diff options
Diffstat (limited to 'WebCore/page')
92 files changed, 4770 insertions, 1991 deletions
diff --git a/WebCore/page/Chrome.cpp b/WebCore/page/Chrome.cpp index 5a5670e..0b85535 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); @@ -122,10 +127,17 @@ float Chrome::scaleFactor() return m_client->scaleFactor(); } +#ifdef ANDROID_USER_GESTURE +void Chrome::focus(bool userGesture) const +{ + m_client->focus(userGesture); +} +#else void Chrome::focus() const { m_client->focus(); } +#endif void Chrome::unfocus() const { @@ -142,6 +154,11 @@ void Chrome::takeFocus(FocusDirection direction) const m_client->takeFocus(direction); } +void Chrome::focusedNodeChanged(Node* node) const +{ + m_client->focusedNodeChanged(node); +} + Page* Chrome::createWindow(Frame* frame, const FrameLoadRequest& request, const WindowFeatures& features) const { Page* newPage = m_client->createWindow(frame, request, features); @@ -297,6 +314,16 @@ bool Chrome::shouldInterruptJavaScript() return m_client->shouldInterruptJavaScript(); } +void Chrome::registerProtocolHandler(const String& scheme, const String& baseURL, const String& url, const String& title) +{ + m_client->registerProtocolHandler(scheme, baseURL, url, title); +} + +void Chrome::registerContentHandler(const String& mimeType, const String& baseURL, const String& url, const String& title) +{ + m_client->registerContentHandler(mimeType, baseURL, url, title); +} + IntRect Chrome::windowResizerRect() const { return m_client->windowResizerRect(); @@ -311,8 +338,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) @@ -385,11 +414,6 @@ void Chrome::print(Frame* frame) void Chrome::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation) { - // Defer loads in case the client method runs a new event loop that would - // otherwise cause the load to continue while we're in the middle of executing JavaScript. - PageGroupLoadDeferrer deferrer(m_page, true); - - ASSERT(frame); m_client->requestGeolocationPermissionForFrame(frame, geolocation); } @@ -403,6 +427,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..398548f 100644 --- a/WebCore/page/Chrome.h +++ b/WebCore/page/Chrome.h @@ -42,8 +42,12 @@ namespace WebCore { class Geolocation; class HitTestResult; class IntRect; + class Node; class Page; class String; +#if ENABLE(NOTIFICATIONS) + class NotificationPresenter; +#endif struct FrameLoadRequest; struct WindowFeatures; @@ -60,8 +64,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; @@ -72,12 +77,18 @@ namespace WebCore { float scaleFactor(); +#ifdef ANDROID_USER_GESTURE + void focus(bool userGesture) const; +#else void focus() const; +#endif void unfocus() const; bool canTakeFocus(FocusDirection) const; void takeFocus(FocusDirection) const; + void focusedNodeChanged(Node*) const; + Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&) const; void show() const; @@ -110,6 +121,9 @@ namespace WebCore { void setStatusbarText(Frame*, const String&); bool shouldInterruptJavaScript(); + void registerProtocolHandler(const String& scheme, const String& baseURL, const String& url, const String& title); + void registerContentHandler(const String& mimeType, const String& baseURL, const String& url, const String& title); + IntRect windowResizerRect() const; void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags); @@ -124,10 +138,14 @@ namespace WebCore { bool setCursor(PlatformCursorHandle); -#if PLATFORM(MAC) +#if PLATFORM(MAC) && !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) 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..117953c 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; @@ -73,12 +77,18 @@ namespace WebCore { virtual float scaleFactor() = 0; +#ifdef ANDROID_USER_GESTURE + virtual void focus(bool userGesture) = 0; +#else virtual void focus() = 0; +#endif virtual void unfocus() = 0; virtual bool canTakeFocus(FocusDirection) = 0; virtual void takeFocus(FocusDirection) = 0; + virtual void focusedNodeChanged(Node*) = 0; + // The Frame pointer provides the ChromeClient with context about which // Frame wants to create the new Page. Also, the newly created window // should not be shown to the user until the ChromeClient of the newly @@ -117,6 +127,9 @@ namespace WebCore { virtual bool shouldInterruptJavaScript() = 0; virtual bool tabsToLinks() const = 0; + virtual void registerProtocolHandler(const String&, const String&, const String&, const String&) { } + virtual void registerContentHandler(const String&, const String&, const String&, const String&) { } + virtual IntRect windowResizerRect() const = 0; // Methods used by HostWindow. @@ -124,11 +137,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 +166,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 +184,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 +212,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..b1b091a 100644 --- a/WebCore/page/Console.cpp +++ b/WebCore/page/Console.cpp @@ -46,6 +46,7 @@ #include "ScriptCallStack.h" #include <stdio.h> +#include <wtf/UnusedParam.h> namespace WebCore { @@ -129,6 +130,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 +151,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 +179,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; @@ -183,7 +191,7 @@ void Console::addMessage(MessageType type, MessageLevel level, ScriptCallStack* for (unsigned i = 0; i < lastCaller.argumentCount(); ++i) { String argAsString; - if (lastCaller.argumentAt(i).getString(argAsString)) + if (lastCaller.argumentAt(i).getString(callStack->state(), argAsString)) printf(" %s", argAsString.utf8().data()); } printf("\n"); @@ -240,12 +248,12 @@ void Console::assertCondition(bool condition, ScriptCallStack* callStack) if (condition) return; - // FIXME: <https://bugs.webkit.org/show_bug.cgi?id=19135> It would be nice to prefix assertion failures with a message like "Assertion failed: ". - addMessage(LogMessageType, ErrorMessageLevel, callStack, true); + addMessage(AssertMessageType, ErrorMessageLevel, callStack, true); } void Console::count(ScriptCallStack* callStack) { +#if ENABLE(INSPECTOR) Page* page = this->page(); if (!page) return; @@ -257,6 +265,26 @@ void Console::count(ScriptCallStack* callStack) getFirstArgumentAsString(callStack->state(), lastCaller, title); page->inspectorController()->count(title, lastCaller.lineNumber(), lastCaller.sourceURL().string()); +#else + UNUSED_PARAM(callStack); +#endif +} + +void Console::markTimeline(ScriptCallStack* callStack) +{ +#if ENABLE(INSPECTOR) + Page* page = this->page(); + if (!page) + return; + + const ScriptCallFrame& lastCaller = callStack->at(0); + String message; + getFirstArgumentAsString(callStack->state(), lastCaller, message); + + page->inspectorController()->markTimeline(message); +#else + UNUSED_PARAM(callStack); +#endif } #if ENABLE(WML) @@ -293,19 +321,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 +353,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 +365,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 +386,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 +411,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..ea3a161 100644 --- a/WebCore/page/Console.h +++ b/WebCore/page/Console.h @@ -64,14 +64,16 @@ namespace WebCore { ObjectMessageType, TraceMessageType, StartGroupMessageType, - EndGroupMessageType + EndGroupMessageType, + AssertMessageType }; enum MessageLevel { TipMessageLevel, LogMessageLevel, WarningMessageLevel, - ErrorMessageLevel + ErrorMessageLevel, + DebugMessageLevel }; class Console : public RefCounted<Console> { @@ -93,6 +95,7 @@ namespace WebCore { void trace(ScriptCallStack*); void assertCondition(bool condition, ScriptCallStack*); void count(ScriptCallStack*); + void markTimeline(ScriptCallStack*); #if ENABLE(WML) String lastWMLErrorMessage() const; #endif diff --git a/WebCore/page/Console.idl b/WebCore/page/Console.idl index 0e9f3dc..a31b605 100644 --- a/WebCore/page/Console.idl +++ b/WebCore/page/Console.idl @@ -44,14 +44,15 @@ module window { [CustomArgumentHandling] void trace(); [CustomArgumentHandling, ImplementationFunction=assertCondition] void assert(in boolean condition); [CustomArgumentHandling] void count(); + [CustomArgumentHandling] void markTimeline(); #if defined(ENABLE_WML) && ENABLE_WML [DontEnum] DOMString lastWMLErrorMessage(); #endif -#if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER - [CustomArgumentHandling] void profile(in [ConvertUndefinedOrNullToNullString] DOMString title); - [CustomArgumentHandling] void profileEnd(in [ConvertUndefinedOrNullToNullString] DOMString title); +#if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER || defined(V8_BINDING) && V8_BINDING + [Custom] void profile(in [ConvertUndefinedOrNullToNullString] DOMString title); + [Custom] void profileEnd(in [ConvertUndefinedOrNullToNullString] DOMString title); #endif void time(in [ConvertUndefinedOrNullToNullString] DOMString title); diff --git a/WebCore/page/ContextMenuController.cpp b/WebCore/page/ContextMenuController.cpp index 0ec9d1c..726dee9 100644 --- a/WebCore/page/ContextMenuController.cpp +++ b/WebCore/page/ContextMenuController.cpp @@ -26,9 +26,12 @@ #include "config.h" #include "ContextMenuController.h" +#if ENABLE(CONTEXT_MENUS) + #include "Chrome.h" #include "ContextMenu.h" #include "ContextMenuClient.h" +#include "ContextMenuSelectionHandler.h" #include "Document.h" #include "DocumentFragment.h" #include "DocumentLoader.h" @@ -64,6 +67,7 @@ ContextMenuController::ContextMenuController(Page* page, ContextMenuClient* clie : m_page(page) , m_client(client) , m_contextMenu(0) + , m_selectionHandler(0) { ASSERT_ARG(page, page); ASSERT_ARG(client, client); @@ -77,13 +81,40 @@ ContextMenuController::~ContextMenuController() void ContextMenuController::clearContextMenu() { m_contextMenu.set(0); + if (m_selectionHandler) + m_selectionHandler->contextMenuCleared(); + m_selectionHandler = 0; } void ContextMenuController::handleContextMenuEvent(Event* event) { - ASSERT(event->type() == eventNames().contextmenuEvent); - if (!event->isMouseEvent()) + m_contextMenu.set(createContextMenu(event)); + if (!m_contextMenu) + return; + m_contextMenu->populate(); + showContextMenu(event); +} + +void ContextMenuController::showContextMenu(Event* event, Vector<ContextMenuItem>& items, PassRefPtr<ContextMenuSelectionHandler> selectionHandler) +{ + m_selectionHandler = selectionHandler; + + m_contextMenu.set(createContextMenu(event)); + if (!m_contextMenu) { + clearContextMenu(); return; + } + for (size_t i = 0; i < items.size(); ++i) { + ContextMenuItem& item = items[i]; + m_contextMenu->appendItem(item); + } + showContextMenu(event); +} + +ContextMenu* ContextMenuController::createContextMenu(Event* event) +{ + if (!event->isMouseEvent()) + return 0; MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); HitTestResult result(mouseEvent->absoluteLocation()); @@ -91,16 +122,18 @@ void ContextMenuController::handleContextMenuEvent(Event* event) result = frame->eventHandler()->hitTestResultAtPoint(mouseEvent->absoluteLocation(), false); if (!result.innerNonSharedNode()) - return; + return 0; + return new ContextMenu(result); +} - m_contextMenu.set(new ContextMenu(result)); - m_contextMenu->populate(); +void ContextMenuController::showContextMenu(Event* event) +{ +#if ENABLE(INSPECTOR) if (m_page->inspectorController()->enabled()) m_contextMenu->addInspectElementItem(); - +#endif PlatformMenuDescription customMenu = m_client->getCustomMenuFromDefaultItems(m_contextMenu.get()); m_contextMenu->setPlatformDescription(customMenu); - event->setDefaultHandled(); } @@ -122,6 +155,12 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) return; } + if (item->action() >= ContextMenuItemBaseCustomTag) { + ASSERT(m_selectionHandler); + m_selectionHandler->contextMenuItemSelected(item); + return; + } + HitTestResult result = m_contextMenu->hitTestResult(); Frame* frame = result.innerNonSharedNode()->document()->frame(); if (!frame) @@ -162,10 +201,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(); @@ -211,7 +252,7 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) break; case ContextMenuItemTagOpenLink: if (Frame* targetFrame = result.targetFrame()) - targetFrame->loader()->loadFrameRequest(FrameLoadRequest(ResourceRequest(result.absoluteLinkURL(), frame->loader()->outgoingReferrer())), false, false, 0, 0); + targetFrame->loader()->loadFrameRequest(FrameLoadRequest(ResourceRequest(result.absoluteLinkURL(), frame->loader()->outgoingReferrer())), false, false, 0, 0, SendReferrer); else openNewWindow(result.absoluteLinkURL(), frame); break; @@ -325,13 +366,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/ContextMenuController.h b/WebCore/page/ContextMenuController.h index 38095f6..d51bc70 100644 --- a/WebCore/page/ContextMenuController.h +++ b/WebCore/page/ContextMenuController.h @@ -28,12 +28,16 @@ #include <wtf/Noncopyable.h> #include <wtf/OwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> namespace WebCore { class ContextMenu; class ContextMenuClient; class ContextMenuItem; + class ContextMenuSelectionHandler; class Event; class Page; @@ -48,12 +52,18 @@ namespace WebCore { void clearContextMenu(); void handleContextMenuEvent(Event*); + void showContextMenu(Event*, Vector<ContextMenuItem>&, PassRefPtr<ContextMenuSelectionHandler>); + void contextMenuItemSelected(ContextMenuItem*); private: + ContextMenu* createContextMenu(Event*); + void showContextMenu(Event*); + Page* m_page; ContextMenuClient* m_client; OwnPtr<ContextMenu> m_contextMenu; + RefPtr<ContextMenuSelectionHandler> m_selectionHandler; }; } diff --git a/WebCore/page/ContextMenuSelectionHandler.h b/WebCore/page/ContextMenuSelectionHandler.h new file mode 100644 index 0000000..d5a6631 --- /dev/null +++ b/WebCore/page/ContextMenuSelectionHandler.h @@ -0,0 +1,51 @@ +/* + * 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 ContextMenuSelectionHandler_h +#define ContextMenuSelectionHandler_h + +#include <wtf/RefCounted.h> + +namespace WebCore { + + class ContextMenuItem; + + class ContextMenuSelectionHandler : public RefCounted<ContextMenuSelectionHandler> { + public: + ContextMenuSelectionHandler() { } + virtual ~ContextMenuSelectionHandler() { }; + + virtual void contextMenuItemSelected(ContextMenuItem*) = 0; + virtual void contextMenuCleared() = 0; + }; + +} + +#endif // ContextMenuSelectionHandler_h diff --git a/WebCore/page/Coordinates.h b/WebCore/page/Coordinates.h index 43870a1..50003ce 100644 --- a/WebCore/page/Coordinates.h +++ b/WebCore/page/Coordinates.h @@ -50,7 +50,7 @@ public: bool canProvideAltitudeAccuracy() const { return m_canProvideAltitudeAccuracy; } bool canProvideHeading() const { return m_canProvideHeading; } bool canProvideSpeed() const { return m_canProvideSpeed; } - + 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..8971bb7 100644 --- a/WebCore/page/DOMTimer.cpp +++ b/WebCore/page/DOMTimer.cpp @@ -27,6 +27,7 @@ #include "config.h" #include "DOMTimer.h" +#include "InspectorTimelineAgent.h" #include "ScheduledAction.h" #include "ScriptExecutionContext.h" #include <wtf/HashSet.h> @@ -47,6 +48,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; @@ -84,6 +88,12 @@ int DOMTimer::install(ScriptExecutionContext* context, ScheduledAction* action, // The timer is deleted when context is deleted (DOMTimer::contextDestroyed) or explicitly via DOMTimer::removeById(), // or if it is a one-time timer and it has fired (DOMTimer::fired). DOMTimer* timer = new DOMTimer(context, action, timeout, singleShot); + +#if ENABLE(INSPECTOR) + if (InspectorTimelineAgent* timelineAgent = InspectorTimelineAgent::retrieve(context)) + timelineAgent->didInstallTimer(timer->m_timeoutId, timeout, singleShot); +#endif + return timer->m_timeoutId; } @@ -94,6 +104,12 @@ void DOMTimer::removeById(ScriptExecutionContext* context, int timeoutId) // respectively if (timeoutId <= 0) return; + +#if ENABLE(INSPECTOR) + if (InspectorTimelineAgent* timelineAgent = InspectorTimelineAgent::retrieve(context)) + timelineAgent->didRemoveTimer(timeoutId); +#endif + delete context->findTimeout(timeoutId); } @@ -102,6 +118,11 @@ void DOMTimer::fired() ScriptExecutionContext* context = scriptExecutionContext(); timerNestingLevel = m_nestingLevel; +#if ENABLE(INSPECTOR) + if (InspectorTimelineAgent* timelineAgent = InspectorTimelineAgent::retrieve(context)) + timelineAgent->willFireTimer(m_timeoutId); +#endif + // Simple case for non-one-shot timers. if (isActive()) { if (repeatInterval() && repeatInterval() < s_minTimerInterval) { @@ -112,6 +133,10 @@ void DOMTimer::fired() // No access to member variables after this point, it can delete the timer. m_action->execute(context); +#if ENABLE(INSPECTOR) + if (InspectorTimelineAgent* timelineAgent = InspectorTimelineAgent::retrieve(context)) + timelineAgent->didFireTimer(); +#endif return; } @@ -122,6 +147,10 @@ void DOMTimer::fired() delete this; action->execute(context); +#if ENABLE(INSPECTOR) + if (InspectorTimelineAgent* timelineAgent = InspectorTimelineAgent::retrieve(context)) + timelineAgent->didFireTimer(); +#endif delete action; timerNestingLevel = 0; } @@ -148,7 +177,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 +188,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..460430f 100644 --- a/WebCore/page/DOMTimer.h +++ b/WebCore/page/DOMTimer.h @@ -33,6 +33,7 @@ namespace WebCore { + class InspectorTimelineAgent; class ScheduledAction; class DOMTimer : public TimerBase, public ActiveDOMObject { @@ -66,6 +67,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..757e32f 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" @@ -50,36 +53,28 @@ #include "HTMLFrameOwnerElement.h" #include "History.h" #include "InspectorController.h" +#include "InspectorTimelineAgent.h" #include "Location.h" #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 +82,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 +106,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 +211,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 +238,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 +253,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 +378,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 +458,24 @@ void DOMWindow::clear() m_applicationCache->disconnectFrame(); m_applicationCache = 0; #endif + +#if ENABLE(NOTIFICATIONS) + if (m_notifications) + m_notifications->disconnectFrame(); + 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 +542,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(); } @@ -551,16 +571,18 @@ Storage* DOMWindow::sessionStorage() const Document* document = this->document(); if (!document) return 0; + + if (!document->securityOrigin()->canAccessStorage()) + return 0; Page* page = document->page(); if (!page) return 0; - if (!page->settings()->sessionStorageEnabled()) - 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(); @@ -574,6 +596,9 @@ Storage* DOMWindow::localStorage() const Document* document = this->document(); if (!document) return 0; + + if (!document->securityOrigin()->canAccessStorage()) + return 0; Page* page = document->page(); if (!page) @@ -582,18 +607,47 @@ 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; + + 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 +663,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 +675,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 +696,7 @@ void DOMWindow::postMessageTimerFired(PostMessageTimer* t) } } - ExceptionCode ec = 0; - dispatchEvent(timer->event(document()), ec); + dispatchEvent(timer->event(document())); } DOMSelection* DOMWindow::getSelection() @@ -692,12 +743,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(); } @@ -869,13 +917,6 @@ int DOMWindow::scrollX() const return static_cast<int>(view->scrollX() / m_frame->pageZoomFactor()); } -#ifdef ANDROID_ORIENTATION_SUPPORT -int DOMWindow::orientation() const -{ - return screen()->orientation(); -} -#endif - int DOMWindow::scrollY() const { if (!m_frame) @@ -1074,13 +1115,15 @@ PassRefPtr<Database> DOMWindow::openDatabase(const String& name, const String& v if (!m_frame) return 0; - Document* doc = m_frame->document(); + Document* document = m_frame->document(); + if (!document->securityOrigin()->canAccessDatabase()) + return 0; Settings* settings = m_frame->settings(); if (!settings || !settings->databasesEnabled()) return 0; - return Database::openDatabase(doc, name, version, displayName, estimatedSize, ec); + return Database::openDatabase(document, name, version, displayName, estimatedSize, ec); } #endif @@ -1214,104 +1257,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()); -} - -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); + addUnloadEventListener(this); + else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this)) + addBeforeUnloadEventListener(this); - 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,694 +1299,60 @@ 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); -} +#if ENABLE(INSPECTOR) + if (!frame() || !frame()->page()) + return; -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; - } - } + if (InspectorController* controller = frame()->page()->inspectorController()) + controller->mainResourceFiredLoadEvent(frame()->loader()->documentLoader(), url()); +#endif } -EventListener* DOMWindow::getAttributeEventListener(const AtomicString& eventType) const +#if ENABLE(INSPECTOR) +InspectorTimelineAgent* DOMWindow::inspectorTimelineAgent() { - 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(); - } + if (frame() && frame()->page()) + return frame()->page()->inspectorTimelineAgent(); return 0; } +#endif -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); -} - -EventListener* DOMWindow::onsuspend() const +bool DOMWindow::dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget> prpTarget) { - return getAttributeEventListener(eventNames().suspendEvent); -} + RefPtr<EventTarget> protect = this; + RefPtr<Event> event = prpEvent; -void DOMWindow::setOnsuspend(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().suspendEvent, eventListener); -} + event->setTarget(prpTarget ? prpTarget : this); + event->setCurrentTarget(this); + event->setEventPhase(Event::AT_TARGET); -EventListener* DOMWindow::oninput() const -{ - return getAttributeEventListener(eventNames().inputEvent); -} +#if ENABLE(INSPECTOR) + InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent(); + bool timelineAgentIsActive = timelineAgent && hasEventListeners(event->type()); + if (timelineAgentIsActive) + timelineAgent->willDispatchEvent(*event); +#endif -void DOMWindow::setOninput(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().inputEvent, eventListener); -} + bool result = fireEventListeners(event.get()); -EventListener* DOMWindow::onmessage() const -{ - return getAttributeEventListener(eventNames().messageEvent); -} +#if ENABLE(INSPECTOR) + if (timelineAgentIsActive) { + timelineAgent = inspectorTimelineAgent(); + if (timelineAgent) + timelineAgent->didDispatchEvent(); + } +#endif -void DOMWindow::setOnmessage(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().messageEvent, eventListener); + return result; } -EventListener* DOMWindow::oncontextmenu() const +void DOMWindow::removeAllEventListeners() { - return getAttributeEventListener(eventNames().contextmenuEvent); -} + EventTarget::removeAllEventListeners(); -void DOMWindow::setOncontextmenu(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().contextmenuEvent, eventListener); + removeAllUnloadEventListeners(this); + removeAllBeforeUnloadEventListeners(this); } void DOMWindow::captureEvents() @@ -2022,46 +1365,14 @@ void DOMWindow::releaseEvents() // Not implemented. } -#if ENABLE(TOUCH_EVENTS) // Android -EventListener* DOMWindow::ontouchstart() const -{ - return getAttributeEventListener(eventNames().touchstartEvent); -} - -void DOMWindow::setOntouchstart(PassRefPtr<EventListener> eventListener) +EventTargetData* DOMWindow::eventTargetData() { - setAttributeEventListener(eventNames().touchstartEvent, eventListener); + return &m_eventTargetData; } -EventListener* DOMWindow::ontouchend() const +EventTargetData* DOMWindow::ensureEventTargetData() { - return getAttributeEventListener(eventNames().touchendEvent); + return &m_eventTargetData; } -void DOMWindow::setOntouchend(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().touchendEvent, eventListener); -} - -EventListener* DOMWindow::ontouchmove() const -{ - return getAttributeEventListener(eventNames().touchmoveEvent); -} - -void DOMWindow::setOntouchmove(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().touchmoveEvent, eventListener); -} - -EventListener* DOMWindow::ontouchcancel() const -{ - return getAttributeEventListener(eventNames().touchcancelEvent); -} - -void DOMWindow::setOntouchcancel(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().touchcancelEvent, eventListener); -} -#endif - } // namespace WebCore diff --git a/WebCore/page/DOMWindow.h b/WebCore/page/DOMWindow.h index 12caf7e..5e2d990 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" @@ -51,13 +52,15 @@ namespace WebCore { class FloatRect; class Frame; class History; + class InspectorTimelineAgent; class Location; class Media; - class MessagePort; class Navigator; class Node; + class NotificationCenter; class PostMessageTimer; class ScheduledAction; + class SerializedScriptValue; class Screen; class WebKitPoint; @@ -84,6 +87,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(); } @@ -145,9 +155,6 @@ namespace WebCore { int scrollY() const; int pageXOffset() const { return scrollX(); } int pageYOffset() const { return scrollY(); } -#ifdef ANDROID_ORIENTATION_SUPPORT - int orientation() const; -#endif bool closed() const; @@ -205,7 +212,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,161 +239,95 @@ 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(); - void dispatchUnloadEvent(RegisteredEventListenerVector* = 0); - PassRefPtr<BeforeUnloadEvent> dispatchBeforeUnloadEvent(RegisteredEventListenerVector* = 0); - - // Used for legacy "onEvent" property APIs. - void setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener>); - void clearAttributeEventListener(const AtomicString& eventType); - EventListener* getAttributeEventListener(const AtomicString& eventType) const; - - const RegisteredEventListenerVector& eventListeners() const { return m_eventListeners; } - bool hasEventListener(const AtomicString& eventType); - void removeAllEventListeners(); - - EventListener* onabort() const; - void setOnabort(PassRefPtr<EventListener>); - EventListener* onblur() const; - void setOnblur(PassRefPtr<EventListener>); - EventListener* onchange() const; - void setOnchange(PassRefPtr<EventListener>); - EventListener* onclick() const; - void setOnclick(PassRefPtr<EventListener>); - EventListener* ondblclick() const; - void setOndblclick(PassRefPtr<EventListener>); - EventListener* ondrag() const; - void setOndrag(PassRefPtr<EventListener>); - EventListener* ondragend() const; - void setOndragend(PassRefPtr<EventListener>); - EventListener* ondragenter() const; - void setOndragenter(PassRefPtr<EventListener>); - EventListener* ondragleave() const; - void setOndragleave(PassRefPtr<EventListener>); - EventListener* ondragover() const; - void setOndragover(PassRefPtr<EventListener>); - EventListener* ondragstart() const; - void setOndragstart(PassRefPtr<EventListener>); - EventListener* ondrop() const; - void setOndrop(PassRefPtr<EventListener>); - EventListener* onerror() const; - void setOnerror(PassRefPtr<EventListener>); - EventListener* onfocus() const; - void setOnfocus(PassRefPtr<EventListener>); - EventListener* onkeydown() const; - void setOnkeydown(PassRefPtr<EventListener>); - EventListener* onkeypress() const; - void setOnkeypress(PassRefPtr<EventListener>); - EventListener* onkeyup() const; - void setOnkeyup(PassRefPtr<EventListener>); - EventListener* onload() const; - void setOnload(PassRefPtr<EventListener>); - EventListener* onmousedown() const; - void setOnmousedown(PassRefPtr<EventListener>); - EventListener* onmousemove() const; - void setOnmousemove(PassRefPtr<EventListener>); - EventListener* onmouseout() const; - void setOnmouseout(PassRefPtr<EventListener>); - EventListener* onmouseover() const; - void setOnmouseover(PassRefPtr<EventListener>); - EventListener* onmouseup() const; - void setOnmouseup(PassRefPtr<EventListener>); - EventListener* onmousewheel() const; - void setOnmousewheel(PassRefPtr<EventListener>); - EventListener* onoffline() const; - void setOnoffline(PassRefPtr<EventListener>); - EventListener* ononline() const; - void setOnonline(PassRefPtr<EventListener>); - EventListener* onreset() const; - void setOnreset(PassRefPtr<EventListener>); - EventListener* onresize() const; - void setOnresize(PassRefPtr<EventListener>); - EventListener* onscroll() const; - void setOnscroll(PassRefPtr<EventListener>); - EventListener* onsearch() const; - void setOnsearch(PassRefPtr<EventListener>); - EventListener* onselect() const; - void setOnselect(PassRefPtr<EventListener>); - EventListener* onstorage() const; - void setOnstorage(PassRefPtr<EventListener>); - EventListener* onsubmit() const; - void setOnsubmit(PassRefPtr<EventListener>); - EventListener* onunload() const; - void setOnunload(PassRefPtr<EventListener>); - EventListener* onbeforeunload() const; - void setOnbeforeunload(PassRefPtr<EventListener>); - EventListener* onwebkitanimationstart() const; - void setOnwebkitanimationstart(PassRefPtr<EventListener>); - EventListener* onwebkitanimationiteration() const; - void setOnwebkitanimationiteration(PassRefPtr<EventListener>); - EventListener* onwebkitanimationend() const; - void setOnwebkitanimationend(PassRefPtr<EventListener>); - EventListener* onwebkittransitionend() const; - void setOnwebkittransitionend(PassRefPtr<EventListener>); + + DEFINE_ATTRIBUTE_EVENT_LISTENER(abort); + DEFINE_ATTRIBUTE_EVENT_LISTENER(beforeunload); + DEFINE_ATTRIBUTE_EVENT_LISTENER(blur); + DEFINE_ATTRIBUTE_EVENT_LISTENER(canplay); + DEFINE_ATTRIBUTE_EVENT_LISTENER(canplaythrough); + DEFINE_ATTRIBUTE_EVENT_LISTENER(change); + DEFINE_ATTRIBUTE_EVENT_LISTENER(click); + DEFINE_ATTRIBUTE_EVENT_LISTENER(contextmenu); + 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(durationchange); + DEFINE_ATTRIBUTE_EVENT_LISTENER(emptied); + DEFINE_ATTRIBUTE_EVENT_LISTENER(ended); + DEFINE_ATTRIBUTE_EVENT_LISTENER(error); + DEFINE_ATTRIBUTE_EVENT_LISTENER(focus); + DEFINE_ATTRIBUTE_EVENT_LISTENER(hashchange); + DEFINE_ATTRIBUTE_EVENT_LISTENER(input); + DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid); + DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown); + DEFINE_ATTRIBUTE_EVENT_LISTENER(keypress); + DEFINE_ATTRIBUTE_EVENT_LISTENER(keyup); + DEFINE_ATTRIBUTE_EVENT_LISTENER(load); + DEFINE_ATTRIBUTE_EVENT_LISTENER(loadeddata); + DEFINE_ATTRIBUTE_EVENT_LISTENER(loadedmetadata); + DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart); + DEFINE_ATTRIBUTE_EVENT_LISTENER(message); + 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(pause); + DEFINE_ATTRIBUTE_EVENT_LISTENER(play); + DEFINE_ATTRIBUTE_EVENT_LISTENER(playing); + DEFINE_ATTRIBUTE_EVENT_LISTENER(popstate); + DEFINE_ATTRIBUTE_EVENT_LISTENER(progress); + DEFINE_ATTRIBUTE_EVENT_LISTENER(ratechange); + DEFINE_ATTRIBUTE_EVENT_LISTENER(reset); + DEFINE_ATTRIBUTE_EVENT_LISTENER(resize); + DEFINE_ATTRIBUTE_EVENT_LISTENER(scroll); + DEFINE_ATTRIBUTE_EVENT_LISTENER(search); + DEFINE_ATTRIBUTE_EVENT_LISTENER(seeked); + DEFINE_ATTRIBUTE_EVENT_LISTENER(seeking); + DEFINE_ATTRIBUTE_EVENT_LISTENER(select); + DEFINE_ATTRIBUTE_EVENT_LISTENER(stalled); + DEFINE_ATTRIBUTE_EVENT_LISTENER(storage); + DEFINE_ATTRIBUTE_EVENT_LISTENER(submit); + DEFINE_ATTRIBUTE_EVENT_LISTENER(suspend); + DEFINE_ATTRIBUTE_EVENT_LISTENER(timeupdate); + DEFINE_ATTRIBUTE_EVENT_LISTENER(unload); + DEFINE_ATTRIBUTE_EVENT_LISTENER(volumechange); + DEFINE_ATTRIBUTE_EVENT_LISTENER(waiting); + DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitbeginfullscreen); + DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitendfullscreen); + +#if ENABLE(ORIENTATION_EVENTS) + DEFINE_ATTRIBUTE_EVENT_LISTENER(orientationchange); +#endif + + 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); + #if ENABLE(TOUCH_EVENTS) // Android - EventListener* ontouchstart() const; - void setOntouchstart(PassRefPtr<EventListener>); - EventListener* ontouchend() const; - void setOntouchend(PassRefPtr<EventListener>); - EventListener* ontouchmove() const; - void setOntouchmove(PassRefPtr<EventListener>); - EventListener* ontouchcancel() const; - void setOntouchcancel(PassRefPtr<EventListener>); + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchstart); + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchend); + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchmove); + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchcancel); #endif - - EventListener* oncanplay() const; - void setOncanplay(PassRefPtr<EventListener>); - EventListener* oncanplaythrough() const; - void setOncanplaythrough(PassRefPtr<EventListener>); - EventListener* ondurationchange() const; - void setOndurationchange(PassRefPtr<EventListener>); - EventListener* onemptied() const; - void setOnemptied(PassRefPtr<EventListener>); - EventListener* onended() const; - void setOnended(PassRefPtr<EventListener>); - EventListener* onloadeddata() const; - void setOnloadeddata(PassRefPtr<EventListener>); - EventListener* onloadedmetadata() const; - void setOnloadedmetadata(PassRefPtr<EventListener>); - EventListener* onpause() const; - void setOnpause(PassRefPtr<EventListener>); - EventListener* onplay() const; - void setOnplay(PassRefPtr<EventListener>); - EventListener* onplaying() const; - void setOnplaying(PassRefPtr<EventListener>); - EventListener* onratechange() const; - void setOnratechange(PassRefPtr<EventListener>); - EventListener* onseeked() const; - void setOnseeked(PassRefPtr<EventListener>); - EventListener* onseeking() const; - void setOnseeking(PassRefPtr<EventListener>); - EventListener* ontimeupdate() const; - void setOntimeupdate(PassRefPtr<EventListener>); - EventListener* onvolumechange() const; - void setOnvolumechange(PassRefPtr<EventListener>); - EventListener* onwaiting() const; - void setOnwaiting(PassRefPtr<EventListener>); - EventListener* onloadstart() const; - void setOnloadstart(PassRefPtr<EventListener>); - EventListener* onprogress() const; - void setOnprogress(PassRefPtr<EventListener>); - EventListener* onstalled() const; - void setOnstalled(PassRefPtr<EventListener>); - EventListener* onsuspend() const; - void setOnsuspend(PassRefPtr<EventListener>); - EventListener* oninput() const; - void setOninput(PassRefPtr<EventListener>); - EventListener* onmessage() const; - void setOnmessage(PassRefPtr<EventListener>); - EventListener* oncontextmenu() const; - void setOncontextmenu(PassRefPtr<EventListener>); void captureEvents(); void releaseEvents(); @@ -415,8 +362,9 @@ namespace WebCore { virtual void refEventTarget() { ref(); } virtual void derefEventTarget() { deref(); } - - void dispatchEventWithDocumentAsTarget(PassRefPtr<Event>, RegisteredEventListenerVector* = 0); + virtual EventTargetData* eventTargetData(); + virtual EventTargetData* ensureEventTargetData(); + InspectorTimelineAgent* inspectorTimelineAgent(); RefPtr<SecurityOrigin> m_securityOrigin; KURL m_url; @@ -441,8 +389,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..c4b08c6 100644 --- a/WebCore/page/DOMWindow.idl +++ b/WebCore/page/DOMWindow.idl @@ -31,7 +31,6 @@ module window { CustomDefineSetter, CustomDeleteProperty, CustomGetOwnPropertySlot, - CustomGetPropertyAttributes, CustomGetPropertyNames, CustomLookupGetter, CustomLookupSetter, @@ -39,6 +38,7 @@ module window { CustomNativeConverter, CustomPutFunction, ExtendsDOMGlobalObject, + EventTarget, GenerateNativeConverter, LegacyParent=JSDOMWindowBase ] DOMWindow { @@ -55,7 +55,7 @@ module window { attribute [Replaceable] Navigator clientInformation; attribute [DoNotCheckDomainSecurity, JSCCustom, V8CustomSetter, V8DisallowShadowing] Location location; - attribute [Replaceable, CustomGetter] Event event; + attribute [Replaceable, CustomGetter, V8CustomSetter] Event event; readonly attribute [Custom] Crypto crypto; @@ -74,7 +74,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); @@ -105,9 +105,6 @@ module window { attribute [Replaceable] long scrollY; readonly attribute long pageXOffset; readonly attribute long pageYOffset; -#if defined(ANDROID_ORIENTATION_SUPPORT) - attribute [Replaceable] long orientation; -#endif [RequiresAllArguments] void scrollBy(in long x, in long y); [RequiresAllArguments] void scrollTo(in long x, in long y); @@ -159,22 +156,38 @@ module window { WebKitPoint webkitConvertPointFromNodeToPage(in Node node, in WebKitPoint p); #if defined(ENABLE_OFFLINE_WEB_APPLICATIONS) && ENABLE_OFFLINE_WEB_APPLICATIONS - readonly attribute DOMApplicationCache applicationCache; + readonly attribute [EnabledAtRuntime] DOMApplicationCache applicationCache; #endif #if defined(ENABLE_DATABASE) && ENABLE_DATABASE - Database openDatabase(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize) + [EnabledAtRuntime] Database openDatabase(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize) raises(DOMException); #endif #if defined(ENABLE_DOM_STORAGE) && ENABLE_DOM_STORAGE - readonly attribute Storage sessionStorage; - readonly attribute Storage localStorage; + readonly attribute [EnabledAtRuntime] Storage sessionStorage; + readonly attribute [EnabledAtRuntime] Storage localStorage; +#endif +#if defined(ENABLE_NOTIFICATIONS) && ENABLE_NOTIFICATIONS + readonly attribute [EnabledAtRuntime] 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 +234,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,9 +253,12 @@ 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; + attribute EventListener onpopstate; attribute EventListener onprogress; attribute EventListener onratechange; attribute EventListener onresize; @@ -262,8 +280,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 +293,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, @@ -414,18 +433,31 @@ module window { attribute HTMLUListElementConstructor HTMLUListElement; attribute HTMLCollectionConstructor HTMLCollection; + attribute HTMLAllCollectionConstructor HTMLAllCollection; attribute [CustomGetter] HTMLImageElementConstructor Image; // Usable with new operator attribute [CustomGetter] HTMLOptionElementConstructor Option; // Usable with new operator attribute CanvasRenderingContext2DConstructor CanvasRenderingContext2D; + attribute [Conditional=3D_CANVAS] WebGLRenderingContextConstructor WebGLRenderingContext; attribute TextMetricsConstructor TextMetrics; + attribute [JSCCustomGetter,Conditional=3D_CANVAS] WebGLArrayBufferConstructor WebGLArrayBuffer; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] WebGLByteArrayConstructor WebGLByteArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] WebGLUnsignedByteArrayConstructor WebGLUnsignedByteArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] WebGLShortArrayConstructor WebGLShortArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] WebGLUnsignedShortArrayConstructor WebGLUnsignedShortArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] WebGLIntArrayConstructor WebGLIntArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] WebGLUnsignedIntArrayConstructor WebGLUnsignedIntArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] WebGLFloatArrayConstructor WebGLFloatArray; // 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 +486,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 +501,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; @@ -479,7 +513,11 @@ module window { #endif #if defined(ENABLE_SHARED_WORKERS) && ENABLE_SHARED_WORKERS - attribute [JSCCustomGetter] SharedWorkerConstructor SharedWorker; // Usable with the new operator + attribute [JSCCustomGetter, EnabledAtRuntime] SharedWorkerConstructor SharedWorker; // Usable with the new operator +#endif + +#if defined(ENABLE_WEB_SOCKETS) && ENABLE_WEB_SOCKETS + attribute [JSCCustomGetter,EnabledAtRuntime] WebSocketConstructor WebSocket; // Usable with the new operator #endif attribute PluginConstructor Plugin; @@ -496,11 +534,11 @@ module window { attribute StorageEventConstructor StorageEvent; #endif - attribute [CustomGetter,Conditional=VIDEO] HTMLAudioElementConstructor Audio; // Usable with the new operator - attribute [Conditional=VIDEO] HTMLAudioElementConstructor HTMLAudioElement; - attribute [Conditional=VIDEO] HTMLMediaElementConstructor HTMLMediaElement; - attribute [Conditional=VIDEO] HTMLVideoElementConstructor HTMLVideoElement; - attribute [Conditional=VIDEO] MediaErrorConstructor MediaError; + attribute [CustomGetter, Conditional=VIDEO, EnabledAtRuntime] HTMLAudioElementConstructor Audio; // Usable with the new operator + attribute [Conditional=VIDEO, EnabledAtRuntime] HTMLAudioElementConstructor HTMLAudioElement; + attribute [Conditional=VIDEO, EnabledAtRuntime] HTMLMediaElementConstructor HTMLMediaElement; + attribute [Conditional=VIDEO, EnabledAtRuntime] HTMLVideoElementConstructor HTMLVideoElement; + attribute [Conditional=VIDEO, EnabledAtRuntime] MediaErrorConstructor MediaError; #if defined(ENABLE_XPATH) && ENABLE_XPATH attribute XPathEvaluatorConstructor XPathEvaluator; @@ -533,7 +571,7 @@ module window { attribute SVGFECompositeElementConstructor SVGFECompositeElement; // attribute SVGFEConvolveMatrixElementConstructor SVGFEConvolveMatrixElement; attribute SVGFEDisplacementMapElementConstructor SVGFEDisplacementMapElement; -// attribute SVGFEMorphologyElementConstructor SVGFEMorphologyElement; + attribute SVGFEMorphologyElementConstructor SVGFEMorphologyElement; attribute SVGFETurbulenceElementConstructor SVGFETurbulenceElement; #endif #endif 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/DragController.h b/WebCore/page/DragController.h index 9472589..3d59ebf 100644 --- a/WebCore/page/DragController.h +++ b/WebCore/page/DragController.h @@ -47,7 +47,7 @@ namespace WebCore { class Range; class SelectionController; - class DragController { + class DragController : public Noncopyable { public: DragController(Page*, DragClient*); ~DragController(); diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp index 937f08f..8b6b602 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(); } @@ -134,10 +136,12 @@ inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResu return false; } +#if ENABLE(DRAG_SUPPORT) inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&) { return false; } +#endif #endif @@ -146,7 +150,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 +185,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 +211,17 @@ void EventHandler::clear() m_touch = 0; #endif m_frameSetBeingResized = 0; +#if ENABLE(DRAG_SUPPORT) m_dragTarget = 0; + m_shouldOnlyFireDragOverEvent = false; +#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 +369,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 +385,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 +416,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 +438,7 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve return swallowEvent; } +#if ENABLE(DRAG_SUPPORT) bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event) { if (handleDrag(event)) @@ -442,7 +461,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 +578,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 +606,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 +620,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 +756,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 +765,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 +786,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 +909,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 +942,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 +1145,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 +1171,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 +1180,7 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) return true; } } +#endif Frame* subframe = subframeForHitTestResult(mev); if (subframe && passMousePressEventToSubframe(mev, subframe)) { @@ -1172,7 +1204,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 +1425,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 +1498,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(); @@ -1486,6 +1521,35 @@ bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTa return me->defaultPrevented(); } +bool EventHandler::canHandleDragAndDropForTarget(DragAndDropHandleType type, Node* target, const PlatformMouseEvent& event, Clipboard* clipboard, bool* accepted) +{ + bool canHandle = false; + bool wasAccepted = false; + + if (target->hasTagName(frameTag) || target->hasTagName(iframeTag)) { + Frame* frame = static_cast<HTMLFrameElementBase*>(target)->contentFrame(); + if (frame) { + switch (type) { + case UpdateDragAndDrop: + wasAccepted = frame->eventHandler()->updateDragAndDrop(event, clipboard); + break; + case CancelDragAndDrop: + frame->eventHandler()->cancelDragAndDrop(event, clipboard); + break; + case PerformDragAndDrop: + wasAccepted = frame->eventHandler()->performDragAndDrop(event, clipboard); + break; + } + } + } else + canHandle = true; + + if (accepted) + *accepted = wasAccepted; + + return canHandle; +} + bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard) { bool accept = false; @@ -1507,27 +1571,34 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* // FIXME: this ordering was explicitly chosen to match WinIE. However, // 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); - else - accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget, event, clipboard); + // + // Moreover, this ordering conforms to section 7.9.4 of the HTML 5 spec. <http://dev.w3.org/html5/spec/Overview.html#drag-and-drop-processing-model>. + if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) { + // As per section 7.9.4 of the HTML 5 spec., we must always fire a drag event before firing a dragenter, dragleave, or dragover event. + if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) { + // for now we don't care if event handler cancels default behavior, since there is none + dispatchDragSrcEvent(eventNames().dragEvent, event); + } + 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; - if (frame) - accept = frame->eventHandler()->updateDragAndDrop(event, clipboard); - else - dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard); + if (m_dragTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, m_dragTarget.get(), event, clipboard, &accept)) + dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard); + + if (newTarget) { + // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that + // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function. + m_shouldOnlyFireDragOverEvent = true; } } else { - if (newTarget) { - if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag)) - accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard); - else - accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget, event, clipboard); + if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) { + // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier. + if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) { + // for now we don't care if event handler cancels default behavior, since there is none + dispatchDragSrcEvent(eventNames().dragEvent, event); + } + accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget, event, clipboard); + m_shouldOnlyFireDragOverEvent = false; } } m_dragTarget = newTarget; @@ -1537,13 +1608,10 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard) { - if (m_dragTarget) { - Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag)) - ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0; - if (frame) - frame->eventHandler()->cancelDragAndDrop(event, clipboard); - else - dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard); + if (m_dragTarget && canHandleDragAndDropForTarget(CancelDragAndDrop, m_dragTarget.get(), event, clipboard)) { + if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) + dispatchDragSrcEvent(eventNames().dragEvent, event); + dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard); } clearDragState(); } @@ -1551,14 +1619,8 @@ void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard) { bool accept = false; - if (m_dragTarget) { - Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag)) - ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0; - if (frame) - accept = frame->eventHandler()->performDragAndDrop(event, clipboard); - else - accept = dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard); - } + if (m_dragTarget && canHandleDragAndDropForTarget(PerformDragAndDrop, m_dragTarget.get(), event, clipboard, &accept)) + dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard); clearDragState(); return accept; } @@ -1567,10 +1629,12 @@ void EventHandler::clearDragState() { m_dragTarget = 0; m_capturingMouseEventsNode = 0; + m_shouldOnlyFireDragOverEvent = false; #if PLATFORM(MAC) m_sendingEventToSubview = false; #endif } +#endif // ENABLE(DRAG_SUPPORT) void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n) { @@ -1692,12 +1756,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 +1803,13 @@ bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe return swallowEvent; } +#if !PLATFORM(GTK) && !(PLATFORM(CHROMIUM) && PLATFORM(LINUX)) +bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&) const +{ + return false; +} +#endif + bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) { Document* doc = m_frame->document(); @@ -1749,35 +1823,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 +1872,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 +1900,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 +1931,7 @@ bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) return swallowEvent; } +#endif // ENABLE(CONTEXT_MENUS) void EventHandler::scheduleHoverStateUpdate() { @@ -1868,12 +1951,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 +1965,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 +2194,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,19 +2228,12 @@ 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); } - -void EventHandler::dragSourceMovedTo(const PlatformMouseEvent& event) -{ - if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) - // for now we don't care if event handler cancels default behavior, since there is none - dispatchDragSrcEvent(eventNames().dragEvent, event); -} - + void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation) { if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) { @@ -2280,9 +2359,10 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event) // gather values from DHTML element, if it set any dragState().m_dragClipboard->sourceOperation(srcOp); - // Yuck, dragSourceMovedTo() can be called as a result of kicking off the drag with - // dragImage! Because of that dumb reentrancy, we may think we've not started the - // drag when that happens. So we have to assume it's started before we kick it off. + // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the + // drag with dragImage! Because of that dumb reentrancy, we may think we've not + // started the drag when that happens. So we have to assume it's started before we + // kick it off. dragState().m_dragClipboard->setDragHasStarted(); } } @@ -2308,6 +2388,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 +2420,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,27 +2521,33 @@ 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()); } #if ENABLE(TOUCH_EVENTS) // Android -bool EventHandler::handleTouchEvent(const PlatformTouchEvent& e) +int EventHandler::handleTouchEvent(const PlatformTouchEvent& e) { // only handle the touch event in the top frame handler if (m_frame->tree()->parent(true)) @@ -2468,17 +2555,17 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& e) Document* doc = m_frame->document(); if (!doc) - return false; + return 0; RenderObject* docRenderer = doc->renderer(); if (!docRenderer) - return false; + return 0; if (doc->touchEventListeners().size() == 0) - return false; + return 0; TouchEventType type = e.eventType(); - if (type == TouchEventStart) { + if (type == TouchEventStart || type == TouchEventLongPress || type == TouchEventDoubleTap) { Frame* frame = m_frame; IntPoint vPoint = frame->view()->windowToContents(e.pos()); HitTestRequest request(HitTestRequest::ReadOnly); @@ -2518,13 +2605,13 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& e) if ((type == TouchEventMove) && (e.x() == m_touch->screenX()) && (e.y() == m_touch->screenY())) { // don't trigger the event if it hasn't really moved - return false; + return 0; } IntPoint vPoint = m_touch->frame()->view()->windowToContents(e.pos()); m_touch->updateLocation(e.x(), e.y(), vPoint.x(), vPoint.y()); } else { - return false; + return 0; } RefPtr<TouchList> touchList = TouchList::create(); @@ -2557,15 +2644,30 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& e) m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY()); break; + case TouchEventLongPress: + te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(), + eventNames().touchlongpressEvent, m_touch->frame()->document()->defaultView(), + m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY()); + break; + + case TouchEventDoubleTap: + te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(), + eventNames().touchdoubletapEvent, m_touch->frame()->document()->defaultView(), + m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY()); + break; + default: return false; } ExceptionCode ec = 0; m_touch->target()->dispatchEvent(te.get(), ec); - if (type == TouchEventEnd || type == TouchEventCancel) { + if (type == TouchEventEnd || type == TouchEventCancel) m_touch = 0; - } - return te->defaultPrevented(); + if (type == TouchEventLongPress || type == TouchEventDoubleTap) + return 0; + return (te->defaultPrevented() ? preventTouch : 0) + | (te->longPressPrevented() ? preventLongPress : 0) + | (te->doubleTapPrevented() ? preventDoubleTap : 0); } #endif diff --git a/WebCore/page/EventHandler.h b/WebCore/page/EventHandler.h index 7fe64ad..0da44f2 100644 --- a/WebCore/page/EventHandler.h +++ b/WebCore/page/EventHandler.h @@ -33,7 +33,7 @@ #include <wtf/Forward.h> #include <wtf/RefPtr.h> -#if PLATFORM(MAC) && !defined(__OBJC__) +#if PLATFORM(MAC) && !defined(__OBJC__) && !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) class NSView; #endif @@ -66,13 +66,23 @@ 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 }; +#if ENABLE(TOUCH_EVENTS) // Android +enum TouchResultMask { + preventTouch = 1 << 0, + preventLongPress = 1 << 1, + preventDoubleTap = 1 << 2, +}; +#endif + class EventHandler : public Noncopyable { public: EventHandler(Frame*); @@ -80,7 +90,9 @@ public: void clear(); +#if ENABLE(DRAG_SUPPORT) void updateSelectionForMouseDrag(); +#endif Node* mousePressNode() const; void setMousePressNode(PassRefPtr<Node>); @@ -99,9 +111,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 +127,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; @@ -132,10 +152,13 @@ public: bool handleWheelEvent(PlatformWheelEvent&); #if ENABLE(TOUCH_EVENTS) // Android - bool handleTouchEvent(const PlatformTouchEvent&); + // See TouchResultMask for the return value options + int handleTouchEvent(const PlatformTouchEvent&); #endif +#if ENABLE(CONTEXT_MENUS) bool sendContextMenuEvent(const PlatformMouseEvent&); +#endif void setMouseDownMayStartAutoscroll() { m_mouseDownMayStartAutoscroll = true; } @@ -150,10 +173,11 @@ 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(); @@ -162,7 +186,7 @@ public: void sendResizeEvent(); void sendScrollEvent(); -#if PLATFORM(MAC) && defined(__OBJC__) +#if PLATFORM(MAC) && defined(__OBJC__) && !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) PassRefPtr<KeyboardEvent> currentKeyboardEvent() const; void mouseDown(NSEvent *); @@ -172,7 +196,9 @@ public: bool keyEvent(NSEvent *); bool wheelEvent(NSEvent *); +#if ENABLE(CONTEXT_MENUS) bool sendContextMenuEvent(NSEvent *); +#endif bool eventMayStartDrag(NSEvent *); void sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent); @@ -183,7 +209,14 @@ public: #endif private: - struct EventHandlerDragState { +#if ENABLE(DRAG_SUPPORT) + enum DragAndDropHandleType { + UpdateDragAndDrop, + CancelDragAndDrop, + PerformDragAndDrop + }; + + struct EventHandlerDragState : Noncopyable { RefPtr<Node> m_dragSrc; // element that may be a drag source, for the current mouse gesture bool m_dragSrcIsLink; bool m_dragSrcIsImage; @@ -195,8 +228,11 @@ private: }; static EventHandlerDragState& dragState(); static const double TextDragDelay; + + bool canHandleDragAndDropForTarget(DragAndDropHandleType, Node* target, const PlatformMouseEvent&, Clipboard*, bool* accepted = 0); PassRefPtr<Clipboard> createDraggingClipboard() const; +#endif // ENABLE(DRAG_SUPPORT) bool eventActivatedView(const PlatformMouseEvent&) const; void selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults&); @@ -208,7 +244,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 +259,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 +278,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,22 +312,30 @@ 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; } -#if PLATFORM(MAC) && defined(__OBJC__) +#if PLATFORM(MAC) && defined(__OBJC__) && !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) NSView *mouseDownViewIfStillGood(); PlatformMouseEvent currentPlatformMouseEvent() const; @@ -296,11 +348,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 +393,10 @@ private: RefPtr<Touch> m_touch; #endif +#if ENABLE(DRAG_SUPPORT) RefPtr<Node> m_dragTarget; + bool m_shouldOnlyFireDragOverEvent; +#endif RefPtr<HTMLFrameSetElement> m_frameSetBeingResized; @@ -351,8 +410,10 @@ private: bool m_useLatchedWheelEventNode; RefPtr<Node> m_latchedWheelEventNode; bool m_widgetIsLatched; - -#if PLATFORM(MAC) + + RefPtr<Node> m_previousWheelScrolledNode; + +#if PLATFORM(MAC) && !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) NSView *m_mouseDownView; bool m_sendingEventToSubview; int m_activationEventNumber; 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..c7ff2c9 --- /dev/null +++ b/WebCore/page/EventSource.h @@ -0,0 +1,133 @@ +/* + * 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 "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/FocusController.h b/WebCore/page/FocusController.h index 33debf1..d86408a 100644 --- a/WebCore/page/FocusController.h +++ b/WebCore/page/FocusController.h @@ -28,6 +28,7 @@ #include "FocusDirection.h" #include <wtf/Forward.h> +#include <wtf/Noncopyable.h> #include <wtf/RefPtr.h> namespace WebCore { @@ -37,7 +38,7 @@ namespace WebCore { class Node; class Page; - class FocusController { + class FocusController : public Noncopyable { public: FocusController(Page*); diff --git a/WebCore/page/Frame.cpp b/WebCore/page/Frame.cpp index 78cc25c..7e81b3d 100644 --- a/WebCore/page/Frame.cpp +++ b/WebCore/page/Frame.cpp @@ -25,6 +25,7 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ + #include "config.h" #include "Frame.h" @@ -59,6 +60,7 @@ #include "Navigator.h" #include "NodeList.h" #include "Page.h" +#include "PageGroup.h" #include "RegularExpression.h" #include "RenderPart.h" #include "RenderTableCell.h" @@ -66,9 +68,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" @@ -77,15 +82,15 @@ #include <wtf/RefCountedLeakCounter.h> #include <wtf/StdLibExtras.h> +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) +#import <Carbon/Carbon.h> +#endif + #if USE(JSC) #include "JSDOMWindowShell.h" #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 +106,10 @@ #include "WMLNames.h" #endif +#if ENABLE(MATHML) +#include "MathMLNames.h" +#endif + using namespace std; namespace WebCore { @@ -122,6 +131,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 +141,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 +151,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 +169,10 @@ Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* WMLNames::init(); #endif +#if ENABLE(MATHML) + MathMLNames::init(); +#endif + XMLNames::init(); if (!ownerElement) @@ -192,6 +206,7 @@ Frame::~Frame() if (m_domWindow) m_domWindow->disconnectFrame(); + script()->clearWindowShell(); HashSet<DOMWindow*>::iterator end = m_liveFormerWindows.end(); for (HashSet<DOMWindow*>::iterator it = m_liveFormerWindows.begin(); it != end; ++it) @@ -203,10 +218,6 @@ Frame::~Frame() } ASSERT(!m_lifeSupportTimer.isActive()); - -#if FRAME_LOADS_USER_STYLESHEET - delete m_userStyleSheetLoader; -#endif } void Frame::init() @@ -219,6 +230,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 +242,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 +295,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(Event::create(eventNames().orientationchangeEvent, false, false)); +} +#endif // ENABLE(ORIENTATION_EVENTS) + Settings* Frame::settings() const { return m_page ? m_page->settings() : 0; @@ -829,14 +860,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 +867,38 @@ 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.get(), *it->second, injectionTime); +} + +void Frame::injectUserScriptsForWorld(DOMWrapperWorld* world, 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())) + m_script.evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world); + } +} + bool Frame::shouldChangeSelection(const VisibleSelection& newSelection) const { return shouldChangeSelection(selection()->selection(), newSelection, newSelection.affinity(), false); @@ -867,13 +922,36 @@ bool Frame::isContentEditable() const return m_doc->inDesignMode(); } -#if !PLATFORM(MAC) - -void Frame::setUseSecureKeyboardEntry(bool) +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) +const short enableRomanKeyboardsOnly = -23; +#endif +void Frame::setUseSecureKeyboardEntry(bool enable) { -} - +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) + if (enable == IsSecureEventInputEnabled()) + return; + if (enable) { + EnableSecureEventInput(); +#ifdef BUILDING_ON_TIGER + KeyScript(enableRomanKeyboardsOnly); +#else + // WebKit substitutes nil for input context when in password field, which corresponds to null TSMDocument. So, there is + // no need to call TSMGetActiveDocument(), which may return an incorrect result when selection hasn't been yet updated + // after focusing a node. + CFArrayRef inputSources = TISCreateASCIICapableInputSourceList(); + TSMSetDocumentProperty(0, kTSMDocumentEnabledInputSourcesPropertyTag, sizeof(CFArrayRef), &inputSources); + CFRelease(inputSources); +#endif + } else { + DisableSecureEventInput(); +#ifdef BUILDING_ON_TIGER + KeyScript(smKeyEnableKybds); +#else + TSMRemoveDocumentProperty(0, kTSMDocumentEnabledInputSourcesPropertyTag); #endif + } +#endif +} void Frame::updateSecureKeyboardEntryIfActive() { @@ -1192,7 +1270,7 @@ FloatRect Frame::selectionBounds(bool clipToVisibleContent) const return clipToVisibleContent ? intersection(selectionRect, view->visibleContentRect()) : selectionRect; } -void Frame::selectionTextRects(Vector<FloatRect>& rects, bool clipToVisibleContent) const +void Frame::selectionTextRects(Vector<FloatRect>& rects, SelectionRectRespectTransforms respectTransforms, bool clipToVisibleContent) const { RenderView* root = contentRenderer(); if (!root) @@ -1200,19 +1278,36 @@ void Frame::selectionTextRects(Vector<FloatRect>& rects, bool clipToVisibleConte RefPtr<Range> selectedRange = selection()->toNormalizedRange(); - Vector<IntRect> intRects; - selectedRange->textRects(intRects, true); - - unsigned size = intRects.size(); FloatRect visibleContentRect = m_view->visibleContentRect(); - for (unsigned i = 0; i < size; ++i) - if (clipToVisibleContent) - rects.append(intersection(intRects[i], visibleContentRect)); - else - rects.append(intRects[i]); + + // FIMXE: we are appending empty rects to the list for those that fall outside visibleContentRect. + // We may not want to do that. + if (respectTransforms) { + Vector<FloatQuad> quads; + selectedRange->textQuads(quads, true); + + unsigned size = quads.size(); + for (unsigned i = 0; i < size; ++i) { + IntRect currRect = quads[i].enclosingBoundingBox(); + if (clipToVisibleContent) + rects.append(intersection(currRect, visibleContentRect)); + else + rects.append(currRect); + } + } else { + Vector<IntRect> intRects; + selectedRange->textRects(intRects, true); + + unsigned size = intRects.size(); + for (unsigned i = 0; i < size; ++i) { + if (clipToVisibleContent) + rects.append(intersection(intRects[i], visibleContentRect)); + else + rects.append(intRects[i]); + } + } } - // Scans logically forward from "start", including any child frames static HTMLFormElement *scanForForm(Node *start) { @@ -1559,6 +1654,11 @@ Page* Frame::page() const return m_page; } +void Frame::detachFromPage() +{ + m_page = 0; +} + EventHandler* Frame::eventHandler() const { return &m_eventHandler; @@ -1575,11 +1675,10 @@ void Frame::pageDestroyed() page()->focusController()->setFocusedFrame(0); script()->clearWindowShell(); - script()->clearScriptObjects(); script()->updatePlatformScriptObjects(); - m_page = 0; + detachFromPage(); } void Frame::disconnectOwnerElement() @@ -1609,7 +1708,13 @@ void Frame::focusWindow() // If we're a top level window, bring the window to the front. if (!tree()->parent()) +#ifdef ANDROID_USER_GESTURE + // FrameLoader::isProcessingUserGesture() will be false when a + // different frame tries to focus this frame through javascript. + page()->chrome()->focus(m_loader.isProcessingUserGesture()); +#else page()->chrome()->focus(); +#endif eventHandler()->focusDocumentView(); } @@ -1624,7 +1729,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 +1743,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()); @@ -1649,7 +1755,6 @@ bool Frame::shouldClose(RegisteredEventListenerVector* alternateEventListeners) return chrome->runBeforeUnloadConfirmPanel(text, this); } - void Frame::scheduleClose() { if (!shouldClose()) @@ -1759,7 +1864,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..ca9a6d4 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(DOMWrapperWorld*, 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&); @@ -267,7 +274,8 @@ namespace WebCore { void clearTypingStyle(); FloatRect selectionBounds(bool clipToVisibleContent = true) const; - void selectionTextRects(Vector<FloatRect>&, bool clipToVisibleContent = true) const; + enum SelectionRectRespectTransforms { RespectTransforms = true, IgnoreTransforms = false }; + void selectionTextRects(Vector<FloatRect>&, SelectionRectRespectTransforms respectTransforms, bool clipToVisibleContent = true) const; HTMLFormElement* currentForm() const; @@ -329,6 +337,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 +366,10 @@ namespace WebCore { Timer<Frame> m_lifeSupportTimer; +#if ENABLE(ORIENTATION_EVENTS) + int m_orientation; +#endif + bool m_caretVisible; bool m_caretPaint; @@ -365,11 +378,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..b533bad 100644 --- a/WebCore/page/FrameView.cpp +++ b/WebCore/page/FrameView.cpp @@ -23,6 +23,7 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ + #include "config.h" #include "FrameView.h" @@ -42,14 +43,16 @@ #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" +#include "TextResourceDecoder.h" #include <wtf/CurrentTime.h> #ifdef ANDROID_INSTRUMENT @@ -61,6 +64,21 @@ #include "RenderLayerCompositor.h" #endif +#if ENABLE(SVG) +#include "SVGDocument.h" +#include "SVGLocatable.h" +#include "SVGNames.h" +#include "SVGPreserveAspectRatio.h" +#include "SVGSVGElement.h" +#include "SVGViewElement.h" +#include "SVGViewSpec.h" +#endif + +#if PLATFORM(ANDROID) +#include "WebCoreFrameBridge.h" +#endif + + namespace WebCore { using namespace HTMLNames; @@ -89,20 +107,18 @@ static const double deferredRepaintDelayIncrementDuringLoading = 0; // The maximum number of updateWidgets iterations that should be done before returning. static const unsigned maxUpdateWidgetsIterations = 2; -struct ScheduledEvent { +struct ScheduledEvent : Noncopyable { RefPtr<Event> m_event; RefPtr<Node> m_eventTarget; }; FrameView::FrameView(Frame* frame) : m_frame(frame) - , m_vmode(ScrollbarAuto) - , m_hmode(ScrollbarAuto) + , m_canHaveScrollbars(true) , 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 +131,7 @@ FrameView::FrameView(Frame* frame) , m_shouldUpdateWhileOffscreen(true) , m_deferSetNeedsLayouts(0) , m_setNeedsLayoutWasDeferred(false) + , m_scrollCorner(0) { init(); } @@ -143,9 +160,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); @@ -184,7 +207,7 @@ void FrameView::reset() m_deferredRepaintDelay = initialDeferredRepaintDelayDuringLoading; m_deferredRepaintTimer.stop(); m_lastPaintTime = 0; - m_paintRestriction = PaintRestrictionNone; + m_paintBehavior = PaintBehaviorNormal; m_isPainting = false; m_isVisuallyNonEmpty = false; m_firstVisuallyNonEmptyLayoutCallbackPending = true; @@ -206,7 +229,10 @@ 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); + if (m_canHaveScrollbars) + setScrollbarModes(ScrollbarAuto, ScrollbarAuto); + else + setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); setScrollbarsSuppressed(false); } @@ -237,23 +263,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 +296,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,10 +329,21 @@ void FrameView::setMarginHeight(int h) m_margins.setHeight(h); } -void FrameView::setCanHaveScrollbars(bool canScroll) +void FrameView::setCanHaveScrollbars(bool canHaveScrollbars) +{ + m_canHaveScrollbars = canHaveScrollbars; + ScrollView::setCanHaveScrollbars(canHaveScrollbars); +} + +void FrameView::updateCanHaveScrollbars() { - ScrollView::setCanHaveScrollbars(canScroll); - scrollbarModes(m_hmode, m_vmode); + ScrollbarMode hMode; + ScrollbarMode vMode; + scrollbarModes(hMode, vMode); + if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff) + m_canHaveScrollbars = false; + else + m_canHaveScrollbars = true; } PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation) @@ -355,6 +372,9 @@ PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientatio void FrameView::setContentsSize(const IntSize& size) { + if (size == contentsSize()) + return; + m_deferSetNeedsLayouts++; ScrollView::setContentsSize(size); @@ -377,7 +397,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) @@ -427,7 +447,7 @@ void FrameView::updateCompositingLayers() return; // This call will make sure the cached hasAcceleratedCompositing is updated from the pref - view->compositor()->cacheAcceleratedCompositingEnabledFlag(); + view->compositor()->cacheAcceleratedCompositingFlags(); if (!view->usesCompositing()) return; @@ -470,8 +490,9 @@ bool FrameView::syncCompositingStateRecursive() } } return allSubframesSynced; -#endif // USE(ACCELERATED_COMPOSITING) +#else // USE(ACCELERATED_COMPOSITING) return true; +#endif } void FrameView::didMoveOnscreen() @@ -517,6 +538,11 @@ void FrameView::layout(bool allowSubtree) if (isPainting()) return; +#if ENABLE(INSPECTOR) + if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent()) + timelineAgent->willLayout(); +#endif + if (!allowSubtree && m_layoutRoot) { m_layoutRoot->markContainingBlocksForLayout(false); m_layoutRoot = 0; @@ -573,8 +599,15 @@ void FrameView::layout(bool allowSubtree) m_nestedLayoutCount++; - ScrollbarMode hMode = m_hmode; - ScrollbarMode vMode = m_vmode; + ScrollbarMode hMode; + ScrollbarMode vMode; + if (m_canHaveScrollbars) { + hMode = ScrollbarAuto; + vMode = ScrollbarAuto; + } else { + hMode = ScrollbarAlwaysOff; + vMode = ScrollbarAlwaysOff; + } if (!subtree) { RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0; @@ -663,6 +696,7 @@ void FrameView::layout(bool allowSubtree) beginDeferredRepaints(); layer->updateLayerPositions((m_doFullRepaint ? RenderLayer::DoFullRepaint : 0) | RenderLayer::CheckForRepaint + | RenderLayer::IsCompositingUpdateRoot | RenderLayer::UpdateCompositingLayers); endDeferredRepaints(); @@ -674,7 +708,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 +743,11 @@ void FrameView::layout(bool allowSubtree) ASSERT(m_enqueueEvents); } +#if ENABLE(INSPECTOR) + if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent()) + timelineAgent->didLayout(); +#endif + m_nestedLayoutCount--; } @@ -747,6 +786,11 @@ bool FrameView::useSlowRepaints() const return m_useSlowRepaints || m_slowRepaintObjectCount > 0 || m_isOverlapped || !m_contentIsOpaque; } +bool FrameView::useSlowRepaintsIfNotOverlapped() const +{ + return m_useSlowRepaints || m_slowRepaintObjectCount > 0 || !m_contentIsOpaque; +} + void FrameView::setUseSlowRepaints() { m_useSlowRepaints = true; @@ -791,6 +835,79 @@ void FrameView::restoreScrollbar() setScrollbarsSuppressed(false); } +bool FrameView::scrollToFragment(const KURL& url) +{ + // If our URL has no ref, then we have no place we need to jump to. + // OTOH If CSS target was set previously, we want to set it to 0, recalc + // and possibly repaint because :target pseudo class may have been + // set (see bug 11321). + if (!url.hasFragmentIdentifier() && !m_frame->document()->cssTarget()) + return false; + + String fragmentIdentifier = url.fragmentIdentifier(); + if (scrollToAnchor(fragmentIdentifier)) + return true; + + // Try again after decoding the ref, based on the document's encoding. + if (TextResourceDecoder* decoder = m_frame->document()->decoder()) + return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, decoder->encoding())); + + return false; +} + +bool FrameView::scrollToAnchor(const String& name) +{ + ASSERT(m_frame->document()); + + if (!m_frame->document()->haveStylesheetsLoaded()) { + m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true); + return false; + } + + m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false); + + Element* anchorNode = m_frame->document()->findAnchor(name); + +#if ENABLE(SVG) + if (m_frame->document()->isSVGDocument()) { + if (name.startsWith("xpointer(")) { + // We need to parse the xpointer reference here + } else if (name.startsWith("svgView(")) { + RefPtr<SVGSVGElement> svg = static_cast<SVGDocument*>(m_frame->document())->rootElement(); + if (!svg->currentView()->parseViewSpec(name)) + return false; + svg->setUseCurrentView(true); + } else { + if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) { + RefPtr<SVGViewElement> viewElement = anchorNode->hasTagName(SVGNames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0; + if (viewElement.get()) { + RefPtr<SVGSVGElement> svg = static_cast<SVGSVGElement*>(SVGLocatable::nearestViewportElement(viewElement.get())); + svg->inheritViewAttributes(viewElement.get()); + } + } + } + // FIXME: need to decide which <svg> to focus on, and zoom to that one + // FIXME: need to actually "highlight" the viewTarget(s) + } +#endif + + m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear the current target. + + // Implement the rule that "" and "top" both mean top of page as in other browsers. + if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top"))) + return false; + +#ifdef ANDROID_SCROLL_ON_GOTO_ANCHOR + // TODO(andreip): check with Grace if this is correct. + android::WebFrame::getWebFrame(m_frame.get())->setUserInitiatedClick(true); +#endif + maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document()); +#ifdef ANDROID_SCROLL_ON_GOTO_ANCHOR + android::WebFrame::getWebFrame(m_frame.get())->setUserInitiatedClick(false); +#endif + return true; +} + void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode) { m_maintainScrollPositionAnchor = anchorNode; @@ -825,6 +942,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; @@ -841,13 +974,14 @@ void FrameView::repaintContentRectangle(const IntRect& r, bool immediate) double delay = adjustedDeferredRepaintDelay(); if ((m_deferringRepaints || m_deferredRepaintTimer.isActive() || delay) && !immediate) { - IntRect visibleContent = visibleContentRect(); - visibleContent.intersect(r); + IntRect paintRect = r; + if (!paintsEntireContents()) + paintRect.intersect(visibleContentRect()); #ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS - if (visibleContent.isEmpty()) - ScrollView::platformOffscreenContentRectangle(r); + if (r != paintRect) + ScrollView::platformOffscreenContentRectangle(visibleContentRect(), r); #endif - if (visibleContent.isEmpty()) + if (paintRect.isEmpty()) return; if (m_repaintCount == cRepaintRectUnionThreshold) { IntRect unionedRect; @@ -857,9 +991,9 @@ void FrameView::repaintContentRectangle(const IntRect& r, bool immediate) m_repaintRects.append(unionedRect); } if (m_repaintCount < cRepaintRectUnionThreshold) - m_repaintRects.append(r); + m_repaintRects.append(paintRect); else - m_repaintRects[0].unite(r); + m_repaintRects[0].unite(paintRect); m_repaintCount++; if (!m_deferringRepaints && !m_deferredRepaintTimer.isActive()) @@ -997,7 +1131,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) { @@ -1016,11 +1151,7 @@ void FrameView::scheduleRelayout() m_frame->ownerRenderer()->setNeedsLayoutAndPrefWidthsRecalc(); #endif -#ifdef ANDROID_MOBILE - int delay = m_frame->document()->minimumLayoutDelay() + m_frame->document()->extraLayoutDelay(); -#else int delay = m_frame->document()->minimumLayoutDelay(); -#endif if (m_layoutTimer.isActive() && m_delayedLayout && !delay) unscheduleRelayout(); if (m_layoutTimer.isActive()) @@ -1074,11 +1205,7 @@ void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot) } } } else { -#ifdef ANDROID_MOBILE - int delay = m_frame->document()->minimumLayoutDelay() + m_frame->document()->extraLayoutDelay(); -#else int delay = m_frame->document()->minimumLayoutDelay(); -#endif m_layoutRoot = relayoutRoot; m_delayedLayout = delay != 0; m_layoutTimer.startOneShot(delay * 0.001); @@ -1221,6 +1348,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; } @@ -1386,6 +1516,7 @@ void FrameView::valueChanged(Scrollbar* bar) ScrollView::valueChanged(bar); if (offset != scrollOffset()) frame()->eventHandler()->sendScrollEvent(); + frame()->loader()->client()->didChangeScrollOffset(); } void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) @@ -1427,6 +1558,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 +1649,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 +1679,12 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) { if (!frame()) return; - + +#if ENABLE(INSPECTOR) + if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent()) + timelineAgent->willPaint(rect); +#endif + Document* document = frame()->document(); #ifndef NDEBUG @@ -1479,7 +1695,7 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) fillWithRed = false; // Subframe, don't fill with red. else if (isTransparent()) fillWithRed = false; // Transparent, don't fill with red. - else if (m_paintRestriction == PaintRestrictionSelectionOnly || m_paintRestriction == PaintRestrictionSelectionOnlyBlackText) + else if (m_paintBehavior & PaintBehaviorSelectionOnly) fillWithRed = false; // Selections are transparent, don't fill with red. else if (m_nodeToDraw) fillWithRed = false; // Element images are transparent, don't fill with red. @@ -1487,7 +1703,7 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) fillWithRed = true; if (fillWithRed) - p->fillRect(rect, Color(0xFF, 0, 0)); + p->fillRect(rect, Color(0xFF, 0, 0), DeviceColorSpace); #endif bool isTopLevelPainter = !sCurrentPaintTimeStamp; @@ -1517,9 +1733,15 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) // m_nodeToDraw is used to draw only one element (and its descendants) RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0; - if (m_paintRestriction == PaintRestrictionNone) + + PaintBehavior paintBehavior = m_paintBehavior; + if (paintBehavior == PaintBehaviorNormal) document->invalidateRenderedRectsForMarkersInRect(rect); - contentRenderer->layer()->paint(p, rect, m_paintRestriction, eltRenderer); + + if (document->printing()) + paintBehavior |= PaintBehaviorFlattenCompositingLayers; + + contentRenderer->layer()->paint(p, rect, paintBehavior, eltRenderer); m_isPainting = false; m_lastPaintTime = currentTime(); @@ -1532,11 +1754,16 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) if (isTopLevelPainter) sCurrentPaintTimeStamp = 0; + +#if ENABLE(INSPECTOR) + if (InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent()) + timelineAgent->didPaint(); +#endif } -void FrameView::setPaintRestriction(PaintRestriction pr) +void FrameView::setPaintBehavior(PaintBehavior behavior) { - m_paintRestriction = pr; + m_paintBehavior = behavior; } bool FrameView::isPainting() const @@ -1573,10 +1800,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 +1858,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..11f8843 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; @@ -70,6 +73,7 @@ public: void setMarginHeight(int); virtual void setCanHaveScrollbars(bool); + void updateCanHaveScrollbars(); virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation); @@ -122,8 +126,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 +134,7 @@ public: virtual void scrollRectIntoViewRecursively(const IntRect&); virtual void setScrollPosition(const IntPoint&); + void scrollPositionChanged(); String mediaType() const; void setMediaType(const String&); @@ -167,13 +170,15 @@ public: void removeWidgetToUpdate(RenderPartObject*); virtual void paintContents(GraphicsContext*, const IntRect& damageRect); - void setPaintRestriction(PaintRestriction); + void setPaintBehavior(PaintBehavior); + PaintBehavior paintBehavior() const { return m_paintBehavior; } bool isPainting() const; void setNodeToDraw(Node*); static double currentPaintTimeStamp() { return sCurrentPaintTimeStamp; } // returns 0 if not painting void layoutIfNeededRecursive(); + void flushDeferredRepaints(); void setIsVisuallyNonEmpty() { m_isVisuallyNonEmpty = true; } @@ -182,6 +187,8 @@ public: void adjustPageHeight(float* newBottom, float oldTop, float oldBottom, float bottomLimit); + bool scrollToFragment(const KURL&); + bool scrollToAnchor(const String&); void maintainScrollPositionAtAnchor(Node*); // Methods to convert points and rects between the coordinate space of the renderer, and this view. @@ -190,6 +197,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*); @@ -200,6 +210,7 @@ private: friend class RenderWidget; bool useSlowRepaints() const; + bool useSlowRepaintsIfNotOverlapped() const; void applyOverflowToViewport(RenderObject*, ScrollbarMode& hMode, ScrollbarMode& vMode); @@ -232,7 +243,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 +262,7 @@ private: bool m_doFullRepaint; - ScrollbarMode m_vmode; - ScrollbarMode m_hmode; + bool m_canHaveScrollbars; bool m_useSlowRepaints; bool m_isOverlapped; bool m_contentIsOpaque; @@ -263,7 +282,6 @@ private: bool m_firstLayoutCallbackPending; bool m_firstLayout; - bool m_needToInitScrollbars; bool m_isTransparent; Color m_baseBackgroundColor; IntSize m_lastLayoutSize; @@ -295,15 +313,25 @@ private: bool m_setNeedsLayoutWasDeferred; RefPtr<Node> m_nodeToDraw; - PaintRestriction m_paintRestriction; + PaintBehavior m_paintBehavior; bool m_isPainting; bool m_isVisuallyNonEmpty; 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..5fbad47 100644 --- a/WebCore/page/Geolocation.cpp +++ b/WebCore/page/Geolocation.cpp @@ -28,7 +28,6 @@ #include "Geolocation.h" #include "Chrome.h" -#include "CurrentTime.h" #include "Document.h" #include "DOMWindow.h" #include "EventNames.h" @@ -38,10 +37,11 @@ #include "SQLiteStatement.h" #include "SQLiteTransaction.h" #include "SQLValue.h" +#include <wtf/CurrentTime.h> namespace WebCore { -static const char* permissionDeniedErrorMessage = "User denied Geolocation"; +static const char permissionDeniedErrorMessage[] = "User denied Geolocation"; Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options) : m_geolocation(geolocation) @@ -49,7 +49,6 @@ Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassRefPtr<Posit , m_errorCallback(errorCallback) , m_options(options) , m_timer(this, &Geolocation::GeoNotifier::timerFired) - , m_fatalError(0) { ASSERT(m_geolocation); ASSERT(m_successCallback); @@ -60,10 +59,17 @@ Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassRefPtr<Posit void Geolocation::GeoNotifier::setFatalError(PassRefPtr<PositionError> error) { + // This method is called at most once on a given GeoNotifier object. + ASSERT(!m_fatalError); m_fatalError = error; m_timer.startOneShot(0); } +bool Geolocation::GeoNotifier::hasZeroTimeout() const +{ + return m_options->hasTimeout() && m_options->timeout() == 0; +} + void Geolocation::GeoNotifier::setCachedPosition(Geoposition* cachedPosition) { // We do not take owenership from the caller, but add our own ref count. @@ -81,25 +87,79 @@ void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*) { m_timer.stop(); + // Cache our pointer to the Geolocation object, as this GeoNotifier object + // could be deleted by a call to clearWatch in a callback. + Geolocation* geolocation = m_geolocation; + if (m_fatalError) { if (m_errorCallback) m_errorCallback->handleEvent(m_fatalError.get()); // This will cause this notifier to be deleted. - m_geolocation->fatalErrorOccurred(this); + geolocation->fatalErrorOccurred(this); return; } if (m_cachedPosition) { m_successCallback->handleEvent(m_cachedPosition.get()); - m_geolocation->requestReturnedCachedPosition(this); + // Clear the cached position in case this is a watch request, which + // will continue to run. + m_cachedPosition = 0; + geolocation->requestReturnedCachedPosition(this); return; } if (m_errorCallback) { - RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timed out"); + RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timeout expired"); m_errorCallback->handleEvent(error.get()); } - m_geolocation->requestTimedOut(this); + geolocation->requestTimedOut(this); +} + +void Geolocation::Watchers::set(int id, PassRefPtr<GeoNotifier> prpNotifier) +{ + RefPtr<GeoNotifier> notifier = prpNotifier; + + m_idToNotifierMap.set(id, notifier.get()); + m_notifierToIdMap.set(notifier.release(), id); +} + +void Geolocation::Watchers::remove(int id) +{ + IdToNotifierMap::iterator iter = m_idToNotifierMap.find(id); + if (iter == m_idToNotifierMap.end()) + return; + m_notifierToIdMap.remove(iter->second); + m_idToNotifierMap.remove(iter); +} + +void Geolocation::Watchers::remove(GeoNotifier* notifier) +{ + NotifierToIdMap::iterator iter = m_notifierToIdMap.find(notifier); + if (iter == m_notifierToIdMap.end()) + return; + m_idToNotifierMap.remove(iter->second); + m_notifierToIdMap.remove(iter); +} + +bool Geolocation::Watchers::contains(GeoNotifier* notifier) const +{ + return m_notifierToIdMap.contains(notifier); +} + +void Geolocation::Watchers::clear() +{ + m_idToNotifierMap.clear(); + m_notifierToIdMap.clear(); +} + +bool Geolocation::Watchers::isEmpty() const +{ + return m_idToNotifierMap.isEmpty(); +} + +void Geolocation::Watchers::getNotifiersVector(Vector<RefPtr<GeoNotifier> >& copy) const +{ + copyValuesToVector(m_idToNotifierMap, copy); } static const char* databaseName = "/CachedPosition.db"; @@ -132,7 +192,9 @@ class CachedPositionManager { } static void setDatabasePath(String databasePath) { - s_databaseFile = databasePath + databaseName; + if (!s_databaseFile) + s_databaseFile = new String; + *s_databaseFile = databasePath + databaseName; // If we don't have have a cached position, attempt to read one from the // DB at the new path. if (s_instances && *s_cachedPosition == 0) @@ -143,7 +205,7 @@ class CachedPositionManager { static PassRefPtr<Geoposition> readFromDB() { SQLiteDatabase database; - if (!database.open(s_databaseFile)) + if (!s_databaseFile || !database.open(*s_databaseFile)) return 0; // Create the table here, such that even if we've just created the @@ -184,7 +246,7 @@ class CachedPositionManager { ASSERT(position); SQLiteDatabase database; - if (!database.open(s_databaseFile)) + if (!s_databaseFile || !database.open(*s_databaseFile)) return; SQLiteTransaction transaction(database); @@ -232,16 +294,17 @@ class CachedPositionManager { } static int s_instances; static RefPtr<Geoposition>* s_cachedPosition; - static String s_databaseFile; + static String* s_databaseFile; }; int CachedPositionManager::s_instances = 0; RefPtr<Geoposition>* CachedPositionManager::s_cachedPosition; -String CachedPositionManager::s_databaseFile; +String* CachedPositionManager::s_databaseFile = 0; Geolocation::Geolocation(Frame* frame) - : m_frame(frame) + : EventListener(GeolocationEventListenerType) + , m_frame(frame) , m_service(GeolocationService::create(this)) , m_allowGeolocation(Unknown) , m_shouldClearCache(false) @@ -274,7 +337,7 @@ void Geolocation::disconnectFrame() void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options) { - RefPtr<GeoNotifier> notifier = makeRequest(successCallback, errorCallback, options); + RefPtr<GeoNotifier> notifier = startRequest(successCallback, errorCallback, options); ASSERT(notifier); m_oneShots.add(notifier); @@ -282,24 +345,26 @@ void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallbac int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options) { - RefPtr<GeoNotifier> notifier = makeRequest(successCallback, errorCallback, options); + RefPtr<GeoNotifier> notifier = startRequest(successCallback, errorCallback, options); ASSERT(notifier); - static int sIdentifier = 0; - m_watchers.set(++sIdentifier, notifier); - - return sIdentifier; + static int nextAvailableWatchId = 1; + // In case of overflow, make sure the ID remains positive, but reuse the ID values. + if (nextAvailableWatchId < 1) + nextAvailableWatchId = 1; + m_watchers.set(nextAvailableWatchId, notifier.release()); + return nextAvailableWatchId++; } -PassRefPtr<Geolocation::GeoNotifier> Geolocation::makeRequest(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options) +PassRefPtr<Geolocation::GeoNotifier> Geolocation::startRequest(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options) { RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options); // Check whether permissions have already been denied. Note that if this is the case, // the permission state can not change again in the lifetime of this page. - if (isDenied()) { + if (isDenied()) notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage)); - } else { + else { if (haveSuitableCachedPosition(notifier->m_options.get())) { ASSERT(m_cachedPositionManager->cachedPosition()); if (isAllowed()) @@ -309,10 +374,10 @@ PassRefPtr<Geolocation::GeoNotifier> Geolocation::makeRequest(PassRefPtr<Positio requestPermission(); } } else { - if (m_service->startUpdating(notifier->m_options.get())) + if (notifier->hasZeroTimeout() || m_service->startUpdating(notifier->m_options.get())) notifier->startTimerIfNeeded(); else - notifier->setFatalError(PositionError::create(PositionError::UNKNOWN_ERROR, "Failed to start Geolocation service")); + notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, "Failed to start Geolocation service")); } } @@ -323,12 +388,7 @@ void Geolocation::fatalErrorOccurred(Geolocation::GeoNotifier* notifier) { // This request has failed fatally. Remove it from our lists. m_oneShots.remove(notifier); - for (GeoNotifierMap::iterator iter = m_watchers.begin(); iter != m_watchers.end(); ++iter) { - if (iter->second == notifier) { - m_watchers.remove(iter); - break; - } - } + m_watchers.remove(notifier); if (!hasListeners()) m_service->stopUpdating(); @@ -346,18 +406,17 @@ void Geolocation::requestTimedOut(GeoNotifier* notifier) void Geolocation::requestReturnedCachedPosition(GeoNotifier* notifier) { // If this is a one-shot request, stop it. - if (m_oneShots.contains(notifier)) { - m_oneShots.remove(notifier); - if (!hasListeners()) - m_service->stopUpdating(); - return; - } + m_oneShots.remove(notifier); + if (!hasListeners()) + m_service->stopUpdating(); - // Otherwise, start the service to get updates. - if (m_service->startUpdating(notifier->m_options.get())) - notifier->startTimerIfNeeded(); - else - notifier->setFatalError(PositionError::create(PositionError::UNKNOWN_ERROR, "Failed to start Geolocation service")); + // Otherwise, if the watch still exists, start the service to get updates. + if (m_watchers.contains(notifier)) { + if (notifier->hasZeroTimeout() || m_service->startUpdating(notifier->m_options.get())) + notifier->startTimerIfNeeded(); + else + notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, "Failed to start Geolocation service")); + } } bool Geolocation::haveSuitableCachedPosition(PositionOptions* options) @@ -399,7 +458,7 @@ void Geolocation::setIsAllowed(bool allowed) m_allowGeolocation = allowed ? Yes : No; if (!isAllowed()) { - RefPtr<WebCore::PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage); + RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage); error->setIsFatal(true); handleError(error.get()); return; @@ -412,8 +471,10 @@ void Geolocation::setIsAllowed(bool allowed) makeSuccessCallbacks(); else { GeoNotifierSet::const_iterator end = m_requestsAwaitingCachedPosition.end(); - for (GeoNotifierSet::const_iterator iter = m_requestsAwaitingCachedPosition.begin(); iter != end; ++iter) + for (GeoNotifierSet::const_iterator iter = m_requestsAwaitingCachedPosition.begin(); iter != end; ++iter) { + ASSERT(m_cachedPositionManager->cachedPosition()); (*iter)->setCachedPosition(m_cachedPositionManager->cachedPosition()); + } } m_requestsAwaitingCachedPosition.clear(); } @@ -461,7 +522,7 @@ void Geolocation::stopTimersForOneShots() void Geolocation::stopTimersForWatchers() { Vector<RefPtr<GeoNotifier> > copy; - copyValuesToVector(m_watchers, copy); + m_watchers.getNotifiersVector(copy); stopTimer(copy); } @@ -475,15 +536,16 @@ void Geolocation::stopTimers() void Geolocation::handleError(PositionError* error) { ASSERT(error); - + Vector<RefPtr<GeoNotifier> > oneShotsCopy; copyToVector(m_oneShots, oneShotsCopy); Vector<RefPtr<GeoNotifier> > watchersCopy; - copyValuesToVector(m_watchers, watchersCopy); + m_watchers.getNotifiersVector(watchersCopy); // Clear the lists before we make the callbacks, to avoid clearing notifiers - // 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. m_oneShots.clear(); if (error->isFatal()) m_watchers.clear(); @@ -513,19 +575,20 @@ void Geolocation::requestPermission() page->chrome()->requestGeolocationPermissionForFrame(m_frame, this); } -void Geolocation::geolocationServicePositionChanged(GeolocationService*) +void Geolocation::geolocationServicePositionChanged(GeolocationService* service) { + ASSERT_UNUSED(service, service == m_service); ASSERT(m_service->lastPosition()); m_cachedPositionManager->setCachedPosition(m_service->lastPosition()); // Stop all currently running timers. stopTimers(); - + if (!isAllowed()) { // requestPermission() will ask the chrome for permission. This may be // implemented synchronously or asynchronously. In both cases, - // makeSucessCallbacks() will be called if permission is granted, so + // makeSuccessCallbacks() will be called if permission is granted, so // there's nothing more to do here. requestPermission(); return; @@ -538,15 +601,16 @@ void Geolocation::makeSuccessCallbacks() { ASSERT(m_service->lastPosition()); ASSERT(isAllowed()); - + Vector<RefPtr<GeoNotifier> > oneShotsCopy; copyToVector(m_oneShots, oneShotsCopy); - + Vector<RefPtr<GeoNotifier> > watchersCopy; - copyValuesToVector(m_watchers, watchersCopy); - + m_watchers.getNotifiersVector(watchersCopy); + // Clear the lists before we make the callbacks, to avoid clearing notifiers - // 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. m_oneShots.clear(); sendPosition(oneShotsCopy, m_service->lastPosition()); @@ -560,17 +624,28 @@ void Geolocation::geolocationServiceErrorOccurred(GeolocationService* service) { ASSERT(service->lastError()); + // Note that we do not stop timers here. For one-shots, the request is + // cleared in handleError. For watchers, the spec requires that the timer is + // not cleared. handleError(service->lastError()); } -void Geolocation::handleEvent(Event* event, bool) +bool Geolocation::operator==(const EventListener& listener) { - ASSERT_UNUSED(event, event->type() == eventTypes().unloadEvent); - // Cancel any ongoing requests on page unload. This is required to release - // references to JS callbacks in the page, to allow the frame to be cleaned up - // by WebKit. - m_oneShots.clear(); - m_watchers.clear(); + if (listener.type() != GeolocationEventListenerType) + return false; + const Geolocation* geolocation = static_cast<const Geolocation*>(&listener); + return m_frame == geolocation->m_frame; +} + +void Geolocation::handleEvent(ScriptExecutionContext*, Event* event) +{ + ASSERT_UNUSED(event, event->type() == eventNames().unloadEvent); + // Cancel any ongoing requests on page unload. This is required to release + // references to JS callbacks in the page, to allow the frame to be cleaned up + // by WebKit. + m_oneShots.clear(); + m_watchers.clear(); } void Geolocation::setDatabasePath(String databasePath) diff --git a/WebCore/page/Geolocation.h b/WebCore/page/Geolocation.h index 9b3b43f..fd9d560 100644 --- a/WebCore/page/Geolocation.h +++ b/WebCore/page/Geolocation.h @@ -82,7 +82,8 @@ 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)); } - void setFatalError(PassRefPtr<PositionError> error); + void setFatalError(PassRefPtr<PositionError>); + bool hasZeroTimeout() const; void setCachedPosition(Geoposition* cachedPosition); void startTimerIfNeeded(); void timerFired(Timer<GeoNotifier>*); @@ -96,14 +97,30 @@ private: RefPtr<Geoposition> m_cachedPosition; private: - GeoNotifier(Geolocation* geolocation, PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>); + GeoNotifier(Geolocation*, PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>); + }; + + class Watchers { + public: + void set(int id, PassRefPtr<GeoNotifier>); + void remove(int id); + void remove(GeoNotifier*); + bool contains(GeoNotifier*) const; + void clear(); + bool isEmpty() const; + void getNotifiersVector(Vector<RefPtr<GeoNotifier> >&) const; + private: + typedef HashMap<int, RefPtr<GeoNotifier> > IdToNotifierMap; + typedef HashMap<RefPtr<GeoNotifier>, int> NotifierToIdMap; + IdToNotifierMap m_idToNotifierMap; + NotifierToIdMap m_notifierToIdMap; }; bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); } void sendError(Vector<RefPtr<GeoNotifier> >&, PositionError*); void sendPosition(Vector<RefPtr<GeoNotifier> >&, Geoposition*); - + static void stopTimer(Vector<RefPtr<GeoNotifier> >&); void stopTimersForOneShots(); void stopTimersForWatchers(); @@ -113,25 +130,26 @@ private: void handleError(PositionError*); void requestPermission(); - PassRefPtr<GeoNotifier> makeRequest(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>); // GeolocationServiceClient virtual void geolocationServicePositionChanged(GeolocationService*); virtual void geolocationServiceErrorOccurred(GeolocationService*); + PassRefPtr<GeoNotifier> startRequest(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>); + // EventListener - virtual void handleEvent(Event*, bool isWindowEvent); + virtual bool operator==(const EventListener&); + virtual void handleEvent(ScriptExecutionContext*, Event*); - void fatalErrorOccurred(GeoNotifier* notifier); - void requestTimedOut(GeoNotifier* notifier); - void requestReturnedCachedPosition(GeoNotifier* notifier); + void fatalErrorOccurred(GeoNotifier*); + void requestTimedOut(GeoNotifier*); + void requestReturnedCachedPosition(GeoNotifier*); bool haveSuitableCachedPosition(PositionOptions*); typedef HashSet<RefPtr<GeoNotifier> > GeoNotifierSet; - typedef HashMap<int, RefPtr<GeoNotifier> > GeoNotifierMap; GeoNotifierSet m_oneShots; - GeoNotifierMap m_watchers; + Watchers m_watchers; Frame* m_frame; OwnPtr<GeolocationService> m_service; diff --git a/WebCore/page/Geolocation.idl b/WebCore/page/Geolocation.idl index e9770ad..e125118 100644 --- a/WebCore/page/Geolocation.idl +++ b/WebCore/page/Geolocation.idl @@ -31,6 +31,7 @@ module core { [Custom] void getCurrentPosition(in PositionCallback successCallback, in PositionErrorCallback errorCallback, in PositionOptions options); [Custom] long watchPosition(in PositionCallback successCallback, in PositionErrorCallback errorCallback, in PositionOptions options); + void clearWatch(in long watchId); }; diff --git a/WebCore/page/HaltablePlugin.h b/WebCore/page/HaltablePlugin.h new file mode 100644 index 0000000..0f4aa41 --- /dev/null +++ b/WebCore/page/HaltablePlugin.h @@ -0,0 +1,46 @@ +/* + * 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; + virtual bool isWindowed() const = 0; + virtual String pluginName() const = 0; +}; + +} // namespace WebCore + +#endif // HaltablePlugin_h diff --git a/WebCore/page/History.cpp b/WebCore/page/History.cpp index 2527132..ea9819e 100644 --- a/WebCore/page/History.cpp +++ b/WebCore/page/History.cpp @@ -26,8 +26,12 @@ #include "config.h" #include "History.h" +#include "ExceptionCode.h" #include "Frame.h" #include "FrameLoader.h" +#include "FrameLoaderClient.h" +#include "HistoryItem.h" +#include "Page.h" namespace WebCore { @@ -50,28 +54,72 @@ 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); +} + +KURL History::urlForState(const String& urlString) +{ + KURL baseURL = m_frame->loader()->baseURL(); + if (urlString.isEmpty()) + return baseURL; + + KURL absoluteURL(baseURL, urlString); + if (!absoluteURL.isValid()) + return KURL(); + + if (absoluteURL.string().left(absoluteURL.pathStart()) != baseURL.string().left(baseURL.pathStart())) + return KURL(); + + return absoluteURL; +} + +void History::stateObjectAdded(PassRefPtr<SerializedScriptValue> data, const String& title, const String& urlString, StateObjectType stateObjectType, ExceptionCode& ec) +{ + if (!m_frame) + return; + ASSERT(m_frame->page()); + + KURL fullURL = urlForState(urlString); + if (!fullURL.isValid()) { + ec = SECURITY_ERR; + return; + } + + if (stateObjectType == StateObjectPush) + m_frame->loader()->history()->pushState(data, title, fullURL.string()); + else if (stateObjectType == StateObjectReplace) + m_frame->loader()->history()->replaceState(data, title, fullURL.string()); + + if (!urlString.isEmpty()) { + m_frame->document()->updateURLForPushOrReplaceState(fullURL); + if (stateObjectType == StateObjectPush) + m_frame->loader()->client()->dispatchDidPushStateWithinPage(); + else if (stateObjectType == StateObjectReplace) + m_frame->loader()->client()->dispatchDidReplaceStateWithinPage(); + } } } // namespace WebCore diff --git a/WebCore/page/History.h b/WebCore/page/History.h index f0df2de..66a6a03 100644 --- a/WebCore/page/History.h +++ b/WebCore/page/History.h @@ -26,30 +26,42 @@ #ifndef History_h #define History_h +#include "KURL.h" #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> namespace WebCore { - class Frame; +class Frame; +class SerializedScriptValue; +class String; +typedef int ExceptionCode; - class History : public RefCounted<History> { - public: - static PassRefPtr<History> create(Frame* frame) { return adoptRef(new History(frame)); } - - Frame* frame() const; - void disconnectFrame(); +class History : public RefCounted<History> { +public: + static PassRefPtr<History> create(Frame* frame) { return adoptRef(new History(frame)); } + + Frame* frame() const; + void disconnectFrame(); - unsigned length() const; - void back(); - void forward(); - void go(int distance); + unsigned length() const; + void back(); + void forward(); + void go(int distance); - private: - History(Frame*); - - Frame* m_frame; + enum StateObjectType { + StateObjectPush, + StateObjectReplace }; + void stateObjectAdded(PassRefPtr<SerializedScriptValue>, const String& title, const String& url, StateObjectType, ExceptionCode&); + +private: + History(Frame*); + + KURL urlForState(const String& url); + + Frame* m_frame; +}; } // namespace WebCore diff --git a/WebCore/page/History.idl b/WebCore/page/History.idl index 914d441..3790552 100644 --- a/WebCore/page/History.idl +++ b/WebCore/page/History.idl @@ -39,6 +39,11 @@ module window { [DoNotCheckDomainSecurity] void back(); [DoNotCheckDomainSecurity] void forward(); [DoNotCheckDomainSecurity] void go(in long distance); + + [Custom] void pushState(in any data, in DOMString title, in optional DOMString url) + raises(DOMException); + [Custom] void replaceState(in any data, in DOMString title, in optional DOMString url) + raises(DOMException); }; } diff --git a/WebCore/page/MouseEventWithHitTestResults.h b/WebCore/page/MouseEventWithHitTestResults.h index 7330d93..8c28574 100644 --- a/WebCore/page/MouseEventWithHitTestResults.h +++ b/WebCore/page/MouseEventWithHitTestResults.h @@ -1,4 +1,4 @@ -/* This file is part of the KDE project +/* Copyright (C) 2000 Simon Hausmann <hausmann@kde.org> Copyright (C) 2006 Apple Computer, Inc. diff --git a/WebCore/page/Navigator.cpp b/WebCore/page/Navigator.cpp index 3603b86..a4193fc 100644 --- a/WebCore/page/Navigator.cpp +++ b/WebCore/page/Navigator.cpp @@ -24,18 +24,22 @@ #include "Navigator.h" #include "CookieJar.h" +#include "ExceptionCode.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" #include "Geolocation.h" +#include "KURL.h" #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 +154,110 @@ 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 + +static bool verifyCustomHandlerURL(const String& baseURL, const String& url, ExceptionCode& ec) +{ + // The specification requires that it is a SYNTAX_ERR if the the "%s" token is not present. + static const char token[] = "%s"; + int index = url.find(token); + if (-1 == index) { + ec = SYNTAX_ERR; + return false; + } + + // It is also a SYNTAX_ERR if the custom handler URL, as created by removing + // the "%s" token and prepending the base url, does not resolve. + String newURL = url; + newURL.remove(index, sizeof(token) / sizeof(token[0])); + + KURL base(ParsedURLString, baseURL); + KURL kurl(base, newURL); + + if (kurl.isEmpty() || !kurl.isValid()) { + ec = SYNTAX_ERR; + return false; + } + + return true; +} + +static bool verifyProtocolHandlerScheme(const String& scheme, ExceptionCode& ec) +{ + // It is a SECURITY_ERR for these schemes to be handled by a custom handler. + if (equalIgnoringCase(scheme, "http") || equalIgnoringCase(scheme, "https") || equalIgnoringCase(scheme, "file")) { + ec = SECURITY_ERR; + return false; + } + return true; +} + +void Navigator::registerProtocolHandler(const String& scheme, const String& url, const String& title, ExceptionCode& ec) +{ + if (!verifyProtocolHandlerScheme(scheme, ec)) + return; + + if (!m_frame) + return; + + Document* document = m_frame->document(); + if (!document) + return; + + String baseURL = document->baseURL().baseAsString(); + + if (!verifyCustomHandlerURL(baseURL, url, ec)) + return; + + if (Page* page = m_frame->page()) + page->chrome()->registerProtocolHandler(scheme, baseURL, url, m_frame->displayStringModifiedByEncoding(title)); +} + +static bool verifyProtocolHandlerMimeType(const String& type, ExceptionCode& ec) +{ + // It is a SECURITY_ERR for these mime types to be assigned to a custom + // handler. + if (equalIgnoringCase(type, "text/html") || equalIgnoringCase(type, "text/css") || equalIgnoringCase(type, "application/x-javascript")) { + ec = SECURITY_ERR; + return false; + } + return true; +} + +void Navigator::registerContentHandler(const String& mimeType, const String& url, const String& title, ExceptionCode& ec) +{ + if (!verifyProtocolHandlerMimeType(mimeType, ec)) + return; + + if (!m_frame) + return; + + Document* document = m_frame->document(); + if (!document) + return; + + String baseURL = document->baseURL().baseAsString(); + + if (!verifyCustomHandlerURL(baseURL, url, ec)) + return; + + if (Page* page = m_frame->page()) + page->chrome()->registerContentHandler(mimeType, baseURL, url, m_frame->displayStringModifiedByEncoding(title)); +} + } // namespace WebCore diff --git a/WebCore/page/Navigator.h b/WebCore/page/Navigator.h index d50721e..107082b 100644 --- a/WebCore/page/Navigator.h +++ b/WebCore/page/Navigator.h @@ -34,6 +34,8 @@ namespace WebCore { class PluginArray; class String; + typedef int ExceptionCode; + class Navigator : public NavigatorBase, public RefCounted<Navigator> { public: static PassRefPtr<Navigator> create(Frame* frame) { return adoptRef(new Navigator(frame)); } @@ -55,6 +57,14 @@ 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 + + void registerProtocolHandler(const String& scheme, const String& url, const String& title, ExceptionCode& ec); + void registerContentHandler(const String& mimeType, const String& url, const String& title, ExceptionCode& ec); + private: Navigator(Frame*); Frame* m_frame; diff --git a/WebCore/page/Navigator.idl b/WebCore/page/Navigator.idl index 8048ff3..99b22af 100644 --- a/WebCore/page/Navigator.idl +++ b/WebCore/page/Navigator.idl @@ -42,6 +42,15 @@ module window { #if defined(ENABLE_GEOLOCATION) && ENABLE_GEOLOCATION readonly attribute Geolocation geolocation; #endif + +#if defined(ENABLE_DOM_STORAGE) && ENABLE_DOM_STORAGE + void getStorageUpdates(); +#endif + + void registerProtocolHandler(in DOMString scheme, in DOMString url, in DOMString title) + raises(DomException); + void registerContentHandler(in DOMString mimeType, in DOMString url, in DOMString title) + raises(DomException); }; } 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..c4f33d6 100644 --- a/WebCore/page/Page.cpp +++ b/WebCore/page/Page.cpp @@ -21,6 +21,8 @@ #include "config.h" #include "Page.h" +#include "BackForwardList.h" +#include "Base64.h" #include "CSSStyleSelector.h" #include "Chrome.h" #include "ChromeClient.h" @@ -28,8 +30,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 +44,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 +98,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 +128,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) @@ -124,6 +139,15 @@ Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, Edi , m_customHTMLTokenizerChunkSize(-1) , m_canStartPlugins(true) { +#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,11 @@ Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, Edi ASSERT(!allPages->contains(this)); allPages->add(this); + if (pluginHalterClient) { + m_pluginHalter.set(new PluginHalter(pluginHalterClient)); + m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime()); + } + #if ENABLE(JAVASCRIPT_DEBUGGER) JavaScriptDebugServer::shared().pageCreated(this); #endif @@ -152,9 +181,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 +205,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,23 +242,72 @@ 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 +#if !ASSERT_DISABLED + // If we're navigating to an item with history state for a Document other than the + // current Document, the new Document had better be in the page cache. + if (item->stateObject() && item->document() != m_mainFrame->document()) + ASSERT(item->document()->inPageCache()); +#endif - // Define what to do with any open database connections. By default we stop them and terminate the database thread. - DatabasePolicy databasePolicy = DatabasePolicyStop; + // Abort any current load unless we're navigating the current document to a new state object + if (!item->stateObject() || item->document() != m_mainFrame->document()) { + // Define what to do with any open database connections. By default we stop them and terminate the database thread. + DatabasePolicy databasePolicy = DatabasePolicyStop; #if ENABLE(DATABASE) - // If we're navigating the history via a fragment on the same document, then we do not want to stop databases. - const KURL& currentURL = m_mainFrame->loader()->url(); - const KURL& newURL = item->url(); - - if (newURL.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(currentURL, newURL)) - databasePolicy = DatabasePolicyContinue; + // If we're navigating the history via a fragment on the same document, then we do not want to stop databases. + const KURL& currentURL = m_mainFrame->loader()->url(); + const KURL& newURL = item->url(); + + if (newURL.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(currentURL, newURL)) + databasePolicy = DatabasePolicyContinue; #endif - m_mainFrame->loader()->stopAllLoaders(databasePolicy); - m_mainFrame->loader()->goToItem(item, type); + + m_mainFrame->loader()->stopAllLoaders(databasePolicy); + } + + m_mainFrame->loader()->history()->goToItem(item, type); +} + +int Page::getHistoryLength() +{ + return m_backForwardList->backListCount() + 1; } void Page::setGlobalHistoryItem(HistoryItem* item) @@ -439,26 +529,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(), styleSheetAsUTF8.size()); + } + + 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 +739,29 @@ bool Page::javaScriptURLsAreAllowed() const return m_javaScriptURLsAreAllowed; } +#if ENABLE(INSPECTOR) +InspectorTimelineAgent* Page::inspectorTimelineAgent() const +{ + return m_inspectorController->timelineAgent(); +} +#endif + +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..4886464 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,10 @@ namespace WebCore { void userStyleSheetLocationChanged(); const String& userStyleSheet() const; + void didStartPlugin(HaltablePlugin*); + void didStopPlugin(HaltablePlugin*); + void pluginAllowedRunTimeChanged(); + static void setDebuggerForAllPages(JSC::Debugger*); void setDebugger(JSC::Debugger*); JSC::Debugger* debugger() const { return m_debugger; } @@ -207,15 +232,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 +266,7 @@ namespace WebCore { int m_frameCount; String m_groupName; + bool m_openedByDOM; bool m_tabKeyCyclesThroughElements; bool m_defersLoading; @@ -243,7 +278,9 @@ namespace WebCore { bool m_javaScriptURLsAreAllowed; +#if ENABLE(INSPECTOR) InspectorController* m_parentInspectorController; +#endif String m_userStyleSheetPath; mutable String m_userStyleSheet; @@ -261,6 +298,8 @@ namespace WebCore { bool m_canStartPlugins; HashSet<PluginView*> m_unstartedPlugins; + OwnPtr<PluginHalter> m_pluginHalter; + #if ENABLE(DOM_STORAGE) RefPtr<StorageNamespace> m_sessionStorage; #endif @@ -272,6 +311,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..558c5cb 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,159 @@ 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::addUserScriptToWorld(DOMWrapperWorld* world, const String& source, const KURL& url, PassOwnPtr<Vector<String> > whitelist, + PassOwnPtr<Vector<String> > blacklist, UserScriptInjectionTime injectionTime) +{ + ASSERT_ARG(world, world); + + OwnPtr<UserScript> userScript(new UserScript(source, url, whitelist, blacklist, injectionTime)); + if (!m_userScripts) + m_userScripts.set(new UserScriptMap); + UserScriptVector*& scriptsInWorld = m_userScripts->add(world, 0).first->second; + if (!scriptsInWorld) + scriptsInWorld = new UserScriptVector; + scriptsInWorld->append(userScript.release()); +} + +void PageGroup::addUserStyleSheetToWorld(DOMWrapperWorld* world, const String& source, const KURL& url, PassOwnPtr<Vector<String> > whitelist, + PassOwnPtr<Vector<String> > blacklist) +{ + ASSERT_ARG(world, world); + + OwnPtr<UserStyleSheet> userStyleSheet(new UserStyleSheet(source, url, whitelist, blacklist)); + if (!m_userStyleSheets) + m_userStyleSheets.set(new UserStyleSheetMap); + UserStyleSheetVector*& styleSheetsInWorld = m_userStyleSheets->add(world, 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::removeUserScriptFromWorld(DOMWrapperWorld* world, const KURL& url) +{ + ASSERT_ARG(world, world); + + if (!m_userScripts) + return; + + UserScriptMap::iterator it = m_userScripts->find(world); + if (it == m_userScripts->end()) + return; + + 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()) + return; + + delete it->second; + m_userScripts->remove(it); +} + +void PageGroup::removeUserStyleSheetFromWorld(DOMWrapperWorld* world, const KURL& url) +{ + ASSERT_ARG(world, world); + + if (!m_userStyleSheets) + return; + + UserStyleSheetMap::iterator it = m_userStyleSheets->find(world); + bool sheetsChanged = false; + if (it == m_userStyleSheets->end()) + return; + + 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 (!sheetsChanged) + return; + + if (!stylesheets->isEmpty()) { + delete it->second; + m_userStyleSheets->remove(it); + } + + // 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::removeUserScriptsFromWorld(DOMWrapperWorld* world) +{ + ASSERT_ARG(world, world); + + if (!m_userScripts) + return; + + UserScriptMap::iterator it = m_userScripts->find(world); + if (it == m_userScripts->end()) + return; + + delete it->second; + m_userScripts->remove(it); +} + +void PageGroup::removeUserStyleSheetsFromWorld(DOMWrapperWorld* world) +{ + ASSERT_ARG(world, world); + + if (!m_userStyleSheets) + return; + + UserStyleSheetMap::iterator it = m_userStyleSheets->find(world); + if (it == m_userStyleSheets->end()) + return; + + delete it->second; + m_userStyleSheets->remove(it); + + // 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 8c842b9..446f0c7 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,10 +43,11 @@ namespace WebCore { public: PageGroup(const String& name); PageGroup(Page*); + ~PageGroup(); static PageGroup* pageGroup(const String& groupName); static void closeLocalStorage(); - + const HashSet<Page*>& pages() const { return m_pages; } void addPage(Page*); @@ -64,13 +67,29 @@ namespace WebCore { #if ENABLE(DOM_STORAGE) StorageNamespace* localStorage(); + bool hasLocalStorage() { return m_localStorage; } #endif + void addUserScriptToWorld(DOMWrapperWorld*, const String& source, const KURL&, + PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist, + UserScriptInjectionTime); + void addUserStyleSheetToWorld(DOMWrapperWorld*, const String& source, const KURL&, + PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist); + + void removeUserScriptFromWorld(DOMWrapperWorld*, const KURL&); + void removeUserStyleSheetFromWorld(DOMWrapperWorld*, const KURL&); + + void removeUserScriptsFromWorld(DOMWrapperWorld*); + void removeUserStyleSheetsFromWorld(DOMWrapperWorld*); + + void removeAllUserContent(); + + const UserScriptMap* userScripts() const { return m_userScripts.get(); } + const UserStyleSheetMap* userStyleSheets() const { return m_userStyleSheets.get(); } + private: void addVisitedLink(LinkHash stringHash); -#if ENABLE(DOM_STORAGE) - bool hasLocalStorage() { return m_localStorage; } -#endif + String m_name; HashSet<Page*> m_pages; @@ -82,6 +101,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..c0a6452 --- /dev/null +++ b/WebCore/page/PluginHalter.cpp @@ -0,0 +1,118 @@ +/* + * 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 "PlatformString.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)); + + if (!m_client->enabled()) + return; + + double currentTime = WTF::currentTime(); + + m_plugins.add(obj, currentTime); + + if (m_plugins.size() == 1) + m_oldestStartTime = currentTime; + + startTimerIfNecessary(); +} + +void PluginHalter::didStopPlugin(HaltablePlugin* obj) +{ + if (!m_client->enabled()) + return; + + 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]->isWindowed(), plugins[i]->pluginName())) + 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..af8b31e --- /dev/null +++ b/WebCore/page/PluginHalter.h @@ -0,0 +1,60 @@ +/* + * 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 "PluginHalterClient.h" +#include "Timer.h" +#include <wtf/HashMap.h> +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class HaltablePlugin; + +class PluginHalter : public Noncopyable { +public: + PluginHalter(PluginHalterClient*); + + void didStartPlugin(HaltablePlugin*); + void didStopPlugin(HaltablePlugin*); + + void setPluginAllowedRunTime(unsigned runTime) { m_pluginAllowedRunTime = runTime; } + +private: + void timerFired(Timer<PluginHalter>*); + void startTimerIfNecessary(); + + OwnPtr<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..0251547 --- /dev/null +++ b/WebCore/page/PluginHalterClient.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 PluginHalterClient_h +#define PluginHalterClient_h + +namespace WebCore { + +class Node; +class String; + +class PluginHalterClient { +public: + virtual ~PluginHalterClient() { } + + virtual bool shouldHaltPlugin(Node*, bool isWindowed, const String& pluginName) const = 0; + virtual bool enabled() const = 0; +}; + +} // namespace WebCore + +#endif // PluginHalterClient_h diff --git a/WebCore/page/PositionCallback.h b/WebCore/page/PositionCallback.h index f6bf139..9f36d7a 100644 --- a/WebCore/page/PositionCallback.h +++ b/WebCore/page/PositionCallback.h @@ -36,7 +36,7 @@ namespace WebCore { class PositionCallback : public RefCounted<PositionCallback> { public: virtual ~PositionCallback() { } - virtual void handleEvent(Geoposition* position) = 0; + virtual void handleEvent(Geoposition*) = 0; }; } // namespace WebCore diff --git a/WebCore/page/PositionError.h b/WebCore/page/PositionError.h index c309061..1467170 100644 --- a/WebCore/page/PositionError.h +++ b/WebCore/page/PositionError.h @@ -35,7 +35,6 @@ namespace WebCore { class PositionError : public RefCounted<PositionError> { public: enum ErrorCode { - UNKNOWN_ERROR = 0, PERMISSION_DENIED = 1, POSITION_UNAVAILABLE = 2, TIMEOUT = 3 @@ -46,7 +45,7 @@ public: ErrorCode code() const { return m_code; } const String& message() const { return m_message; } void setIsFatal(bool isFatal) { m_isFatal = isFatal; } - bool isFatal() { return m_isFatal; } + bool isFatal() const { return m_isFatal; } private: PositionError(ErrorCode code, const String& message) diff --git a/WebCore/page/PositionError.idl b/WebCore/page/PositionError.idl index cb2ef5e..91027df 100644 --- a/WebCore/page/PositionError.idl +++ b/WebCore/page/PositionError.idl @@ -31,7 +31,6 @@ module core { readonly attribute unsigned short code; readonly attribute DOMString message; - const unsigned short UNKNOWN_ERROR = 0; const unsigned short PERMISSION_DENIED = 1; const unsigned short POSITION_UNAVAILABLE = 2; const unsigned short TIMEOUT = 3; diff --git a/WebCore/page/PositionOptions.h b/WebCore/page/PositionOptions.h index 5900998..5cb66f7 100644 --- a/WebCore/page/PositionOptions.h +++ b/WebCore/page/PositionOptions.h @@ -33,7 +33,7 @@ namespace WebCore { class PositionOptions : public RefCounted<PositionOptions> { public: - static PassRefPtr<PositionOptions> create() { return adoptRef(new PositionOptions); } + static PassRefPtr<PositionOptions> create() { return adoptRef(new PositionOptions()); } 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/Screen.h b/WebCore/page/Screen.h index 6f34195..2c84abd 100644 --- a/WebCore/page/Screen.h +++ b/WebCore/page/Screen.h @@ -52,9 +52,6 @@ namespace WebCore { unsigned availTop() const; unsigned availHeight() const; unsigned availWidth() const; -#ifdef ANDROID_ORIENTATION_SUPPORT - int orientation() const; -#endif private: Screen(Frame*); diff --git a/WebCore/page/SecurityOrigin.cpp b/WebCore/page/SecurityOrigin.cpp index 14a1b59..f53dbf1 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,26 +75,11 @@ static URLSchemesMap& noAccessSchemes() return noAccessSchemes; } -static bool isDefaultPortForProtocol(unsigned short port, const String& protocol) -{ - if (protocol.isEmpty()) - return false; - - typedef HashMap<String, unsigned> DefaultPortsMap; - DEFINE_STATIC_LOCAL(DefaultPortsMap, defaultPorts, ()); - if (defaultPorts.isEmpty()) { - defaultPorts.set("http", 80); - defaultPorts.set("https", 443); - defaultPorts.set("ftp", 21); - defaultPorts.set("ftps", 990); - } - return defaultPorts.get(protocol) == port; -} - SecurityOrigin::SecurityOrigin(const KURL& url) : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower()) , m_host(url.host().isNull() ? "" : url.host().lower()) , m_port(url.port()) + , m_sandboxFlags(SandboxNone) , m_noAccess(false) , m_universalAccess(false) , m_domainWasSetInDOM(false) @@ -105,16 +97,22 @@ SecurityOrigin::SecurityOrigin(const KURL& url) // By default, only local SecurityOrigins can load local resources. m_canLoadLocalResources = isLocal(); + if (m_canLoadLocalResources) { + // Directories should never be readable. + if (!url.hasPath() || url.path().endsWith("/")) + m_noAccess = true; + } if (isDefaultPortForProtocol(m_port, m_protocol)) m_port = 0; } 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_sandboxFlags(other->m_sandboxFlags) , m_noAccess(other->m_noAccess) , m_universalAccess(other->m_universalAccess) , m_domainWasSetInDOM(other->m_domainWasSetInDOM) @@ -139,7 +137,7 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::createEmpty() return create(KURL()); } -PassRefPtr<SecurityOrigin> SecurityOrigin::copy() +PassRefPtr<SecurityOrigin> SecurityOrigin::threadsafeCopy() { return adoptRef(new SecurityOrigin(this)); } @@ -155,7 +153,7 @@ bool SecurityOrigin::canAccess(const SecurityOrigin* other) const if (m_universalAccess) return true; - if (m_noAccess || other->m_noAccess) + if (m_noAccess || other->m_noAccess || isSandboxed(SandboxOrigin) || other->isSandboxed(SandboxOrigin)) return false; // Here are two cases where we should permit access: @@ -196,14 +194,56 @@ bool SecurityOrigin::canRequest(const KURL& url) const if (m_universalAccess) return true; - if (m_noAccess) + if (m_noAccess || isSandboxed(SandboxOrigin)) return false; RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url); + if (targetOrigin->m_noAccess) + return false; // 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 +253,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; } @@ -242,7 +282,7 @@ String SecurityOrigin::toString() const if (isEmpty()) return "null"; - if (m_noAccess) + if (m_noAccess || isSandboxed(SandboxOrigin)) return "null"; if (m_protocol == "file") @@ -339,13 +379,27 @@ 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 + 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 +420,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 +438,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..af83f02 100644 --- a/WebCore/page/SecurityOrigin.h +++ b/WebCore/page/SecurityOrigin.h @@ -29,14 +29,20 @@ #ifndef SecurityOrigin_h #define SecurityOrigin_h +#include <wtf/HashSet.h> #include <wtf/RefCounted.h> #include <wtf/PassRefPtr.h> #include <wtf/Threading.h> +#include "FrameLoaderTypes.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 +54,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 +78,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 @@ -95,6 +111,13 @@ namespace WebCore { // WARNING: This is an extremely powerful ability. Use with caution! void grantUniversalAccess(); + // Sandboxing status as determined by the frame. + void setSandboxFlags(SandboxFlags flags) { m_sandboxFlags = flags; } + bool isSandboxed(SandboxFlags mask) const { return m_sandboxFlags & mask; } + + bool canAccessDatabase() const { return !isSandboxed(SandboxOrigin); } + bool canAccessStorage() const { return !isSandboxed(SandboxOrigin); } + bool isSecureTransitionTo(const KURL&) const; // The local SecurityOrigin is the most privileged SecurityOrigin. @@ -108,13 +131,18 @@ namespace WebCore { // Convert this SecurityOrigin into a string. The string // representation of a SecurityOrigin is similar to a URL, except it // lacks a path component. The string representation does not encode - // the value of the SecurityOrigin's domain property. The empty - // SecurityOrigin is represented with the string "null". + // the value of the SecurityOrigin's domain property. + // + // When using the string value, it's important to remember that it + // might be "null". This happens when this SecurityOrigin has + // noAccess to other SecurityOrigins. For example, this SecurityOrigin + // might have come from a data URL, the SecurityOrigin might be empty, + // or we might have explicitly decided that we + // shouldTreatURLSchemeAsNoAccess. String toString() const; - // Serialize the security origin for storage in the database. This format is - // deprecated and should be used only for compatibility with old databases; - // use toString() and createFromString() instead. + // Serialize the security origin to a string that could be used as part of + // file names. This format should be used in storage APIs only. String databaseIdentifier() const; // This method checks for equality between SecurityOrigins, not whether @@ -129,12 +157,28 @@ 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(); + private: explicit SecurityOrigin(const KURL&); explicit SecurityOrigin(const SecurityOrigin*); @@ -143,6 +187,7 @@ namespace WebCore { String m_host; String m_domain; unsigned short m_port; + SandboxFlags m_sandboxFlags; bool m_noAccess; bool m_universalAccess; bool m_domainWasSetInDOM; diff --git a/WebCore/page/Settings.cpp b/WebCore/page/Settings.cpp index 9692707..b250e4d 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) @@ -76,7 +82,6 @@ Settings::Settings(Page* page) , m_arePluginsEnabled(false) , m_databasesEnabled(false) , m_localStorageEnabled(false) - , m_sessionStorageEnabled(true) , m_isJavaScriptEnabled(false) , m_isWebSecurityEnabled(true) , m_allowUniversalAccessFromFileURLs(true) @@ -110,7 +115,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,11 +127,16 @@ Settings::Settings(Page* page) , m_downloadableBinaryFontsEnabled(true) , m_xssAuditorEnabled(false) , m_acceleratedCompositingEnabled(true) + , m_showDebugBorders(false) + , m_showRepaintCounter(false) + , m_experimentalNotificationsEnabled(false) + , m_webGLEnabled(false) + , m_geolocationEnabled(true) { // A Frame may not have been created yet, so we initialize the AtomicString // hash before trying to use it. AtomicString::init(); -#ifdef ANDROID_META_SUPPORT +#ifdef ANDROID_META_SUPPORT resetMetadataSettings(); #endif } @@ -267,9 +278,9 @@ void Settings::setLocalStorageEnabled(bool localStorageEnabled) m_localStorageEnabled = localStorageEnabled; } -void Settings::setSessionStorageEnabled(bool sessionStorageEnabled) +void Settings::setLocalStorageQuota(unsigned localStorageQuota) { - m_sessionStorageEnabled = sessionStorageEnabled; + m_localStorageQuota = localStorageQuota; } void Settings::setPrivateBrowsingEnabled(bool privateBrowsingEnabled) @@ -295,7 +306,6 @@ void Settings::setUserStyleSheetLocation(const KURL& userStyleSheetLocation) m_userStyleSheetLocation = userStyleSheetLocation; m_page->userStyleSheetLocationChanged(); - setNeedsReapplyStylesInAllFrames(m_page); } void Settings::setShouldPrintBackgrounds(bool shouldPrintBackgrounds) @@ -427,9 +437,9 @@ void Settings::setMetadataSettings(const String& key, const String& value) int width = value.toInt(); if (width <= 10000) { if (width <= 320) { - // This is a hack to accommodate the pages designed for the - // original iPhone. The new version, since 10/2007, is to - // use device-width which works for both portrait and + // This is a hack to accommodate the pages designed for the + // original iPhone. The new version, since 10/2007, is to + // use device-width which works for both portrait and // landscape modes. m_viewport_width = 0; } else { @@ -485,27 +495,95 @@ void Settings::setMetadataSettings(const String& key, const String& value) } else if (key == "telephone") { if (value == "no") { m_format_detection_telephone = false; - } + } } else if (key == "address") { if (value == "no") { m_format_detection_address = false; - } + } } else if (key == "email") { if (value == "no") { m_format_detection_email = false; - } + } } else if (key == "format-detection") { - // even Apple doc says "format-detection" should be the name of the - // <meta> tag. In the real world, e.g. amazon.com, use + // even Apple doc says "format-detection" should be the name of the + // <meta> tag. In the real world, e.g. amazon.com, use // "format-detection=no" in the "viewport" <meta> tag to disable all // format detection. if (value == "no") { m_format_detection_telephone = false; m_format_detection_address = false; m_format_detection_email = false; - } + } } } + +void Settings::setViewportWidth(int width) +{ + if (width < 0 || width > 10000) + m_viewport_width = -1; + else + m_viewport_width = width; +} + +void Settings::setViewportHeight(int height) +{ + if (height < 0 || height > 10000) + m_viewport_height = -1; + else + m_viewport_height = height; +} + +void Settings::setViewportInitialScale(int scale) +{ + if (scale < 1 || scale > 1000) + m_viewport_initial_scale = 0; + else + m_viewport_initial_scale = scale; +} + +void Settings::setViewportMinimumScale(int scale) +{ + if (scale < 1 || scale > 1000) + m_viewport_minimum_scale = 0; + else + m_viewport_minimum_scale = scale; +} + +void Settings::setViewportMaximumScale(int scale) +{ + if (scale < 1 || scale > 1000) + m_viewport_maximum_scale = 0; + else + m_viewport_maximum_scale = scale; +} + +void Settings::setViewportUserScalable(bool scalable) +{ + m_viewport_user_scalable = scalable; +} + +void Settings::setViewportTargetDensityDpi(int dpi) +{ + if (dpi < 0 || dpi > 400) + m_viewport_target_densitydpi = -1; + else + m_viewport_target_densitydpi = dpi; +} + +void Settings::setFormatDetectionAddress(bool detect) +{ + m_format_detection_address = detect; +} + +void Settings::setFormatDetectionEmail(bool detect) +{ + m_format_detection_email = detect; +} + +void Settings::setFormatDetectionTelephone(bool detect) +{ + m_format_detection_telephone = detect; +} #endif void Settings::setAuthorAndUserStylesEnabled(bool authorAndUserStylesEnabled) @@ -620,4 +698,50 @@ void Settings::setAcceleratedCompositingEnabled(bool enabled) setNeedsReapplyStylesInAllFrames(m_page); } +void Settings::setShowDebugBorders(bool enabled) +{ + if (m_showDebugBorders == enabled) + return; + + m_showDebugBorders = enabled; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setShowRepaintCounter(bool enabled) +{ + if (m_showRepaintCounter == enabled) + return; + + m_showRepaintCounter = enabled; + setNeedsReapplyStylesInAllFrames(m_page); +} + +void Settings::setExperimentalNotificationsEnabled(bool enabled) +{ + m_experimentalNotificationsEnabled = enabled; +} + +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; +} + +void Settings::setGeolocationEnabled(bool enabled) +{ + m_geolocationEnabled = enabled; +} + } // namespace WebCore diff --git a/WebCore/page/Settings.h b/WebCore/page/Settings.h index 162b21d..fbb70b0 100644 --- a/WebCore/page/Settings.h +++ b/WebCore/page/Settings.h @@ -64,7 +64,7 @@ namespace WebCore { // if possible in the future. enum EditingBehavior { EditingMacBehavior, EditingWindowsBehavior }; - class Settings { + class Settings : public Noncopyable { public: Settings(Page*); @@ -92,7 +92,7 @@ namespace WebCore { bool useWideViewport() const { return m_useWideViewport; } void setUseWideViewport(bool use) { m_useWideViewport = use; } #endif - + void setSerifFontFamily(const AtomicString&); const AtomicString& serifFontFamily() const { return m_serifFontFamily; } @@ -148,8 +148,8 @@ namespace WebCore { void setLocalStorageEnabled(bool); bool localStorageEnabled() const { return m_localStorageEnabled; } - 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; } @@ -223,15 +223,34 @@ namespace WebCore { void resetMetadataSettings(); void setMetadataSettings(const String& key, const String& value); + void setViewportWidth(int); int viewportWidth() const { return m_viewport_width; } + + void setViewportHeight(int); int viewportHeight() const { return m_viewport_height; } + + void setViewportInitialScale(int); int viewportInitialScale() const { return m_viewport_initial_scale; } + + void setViewportMinimumScale(int); int viewportMinimumScale() const { return m_viewport_minimum_scale; } + + void setViewportMaximumScale(int); int viewportMaximumScale() const { return m_viewport_maximum_scale; } + + void setViewportUserScalable(bool); bool viewportUserScalable() const { return m_viewport_user_scalable; } + + void setViewportTargetDensityDpi(int); int viewportTargetDensityDpi() const { return m_viewport_target_densitydpi; } + + void setFormatDetectionAddress(bool); bool formatDetectionAddress() const { return m_format_detection_address; } + + void setFormatDetectionEmail(bool); bool formatDetectionEmail() const { return m_format_detection_email; } + + void setFormatDetectionTelephone(bool); bool formatDetectionTelephone() const { return m_format_detection_telephone; } #endif #ifdef ANDROID_MULTIPLE_WINDOWS @@ -295,6 +314,29 @@ namespace WebCore { void setAcceleratedCompositingEnabled(bool); bool acceleratedCompositingEnabled() const { return m_acceleratedCompositingEnabled; } + void setShowDebugBorders(bool); + bool showDebugBorders() const { return m_showDebugBorders; } + + void setShowRepaintCounter(bool); + bool showRepaintCounter() const { return m_showRepaintCounter; } + + 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 setPluginAllowedRunTime(unsigned); + unsigned pluginAllowedRunTime() const { return m_pluginAllowedRunTime; } + + void setWebGLEnabled(bool); + bool webGLEnabled() const { return m_webGLEnabled; } + + void setGeolocationEnabled(bool); + bool geolocationEnabled() const { return m_geolocationEnabled; } + private: Page* m_page; @@ -352,6 +394,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; @@ -359,7 +403,6 @@ namespace WebCore { bool m_arePluginsEnabled : 1; bool m_databasesEnabled : 1; bool m_localStorageEnabled : 1; - bool m_sessionStorageEnabled : 1; bool m_isJavaScriptEnabled : 1; bool m_isWebSecurityEnabled : 1; bool m_allowUniversalAccessFromFileURLs: 1; @@ -396,10 +439,18 @@ namespace WebCore { bool m_downloadableBinaryFontsEnabled : 1; bool m_xssAuditorEnabled : 1; bool m_acceleratedCompositingEnabled : 1; + bool m_showDebugBorders : 1; + bool m_showRepaintCounter : 1; + bool m_experimentalNotificationsEnabled : 1; + bool m_webGLEnabled : 1; + bool m_geolocationEnabled : 1; #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..8b3703f --- /dev/null +++ b/WebCore/page/UserScript.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 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 Noncopyable { +public: + UserScript(const String& source, const KURL& url, + PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist, + UserScriptInjectionTime injectionTime) + : m_source(source) + , m_url(url) + , m_whitelist(whitelist) + , m_blacklist(blacklist) + , 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(); } + UserScriptInjectionTime injectionTime() const { return m_injectionTime; } + +private: + String m_source; + KURL m_url; + OwnPtr<Vector<String> > m_whitelist; + OwnPtr<Vector<String> > m_blacklist; + 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..ad27e79 --- /dev/null +++ b/WebCore/page/UserScriptTypes.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 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 DOMWrapperWorld; +class UserScript; + +typedef Vector<OwnPtr<UserScript> > UserScriptVector; +typedef HashMap<RefPtr<DOMWrapperWorld>, 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..610778f --- /dev/null +++ b/WebCore/page/UserStyleSheet.h @@ -0,0 +1,62 @@ +/* + * 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 Noncopyable { +public: + UserStyleSheet(const String& source, const KURL& url, + PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist) + : m_source(source) + , m_url(url) + , m_whitelist(whitelist) + , m_blacklist(blacklist) + { + } + + 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(); } + +private: + String m_source; + KURL m_url; + OwnPtr<Vector<String> > m_whitelist; + OwnPtr<Vector<String> > m_blacklist; +}; + +} // namespace WebCore + +#endif // UserStyleSheet_h diff --git a/WebCore/page/UserStyleSheetTypes.h b/WebCore/page/UserStyleSheetTypes.h new file mode 100644 index 0000000..ef662f2 --- /dev/null +++ b/WebCore/page/UserStyleSheetTypes.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 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 DOMWrapperWorld; +class UserStyleSheet; + +typedef Vector<OwnPtr<UserStyleSheet> > UserStyleSheetVector; +typedef HashMap<RefPtr<DOMWrapperWorld>, UserStyleSheetVector*> UserStyleSheetMap; + +} // namespace WebCore + +#endif // UserStyleSheetTypes_h diff --git a/WebCore/page/XSSAuditor.cpp b/WebCore/page/XSSAuditor.cpp index 70b691b..72c2591 100644 --- a/WebCore/page/XSSAuditor.cpp +++ b/WebCore/page/XSSAuditor.cpp @@ -48,12 +48,41 @@ 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 the 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, + bool decodeURLEscapeSequencesTwice) +{ + if (decodeEntities == m_decodeEntities && decodeURLEscapeSequencesTwice == m_decodeURLEscapeSequencesTwice + && encoding == m_encoding && url == m_inputURL) + return m_cachedCanonicalizedURL; + + m_cachedCanonicalizedURL = canonicalize(decodeURL(url, encoding, decodeEntities, decodeURLEscapeSequencesTwice)); + m_inputURL = url; + m_encoding = encoding; + m_decodeEntities = decodeEntities; + m_decodeURLEscapeSequencesTwice = decodeURLEscapeSequencesTwice; + return m_cachedCanonicalizedURL; } XSSAuditor::XSSAuditor(Frame* frame) @@ -76,7 +105,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; @@ -89,7 +118,7 @@ bool XSSAuditor::canEvaluateJavaScriptURL(const String& code) const if (!isEnabled()) return true; - if (findInRequest(code)) { + if (findInRequest(code, true, 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 +131,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; @@ -115,6 +144,9 @@ bool XSSAuditor::canLoadExternalScriptFromSrc(const String& context, const Strin if (!isEnabled()) return true; + if (isSameOriginResource(url)) + return true; + if (findInRequest(context + url)) { 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()); @@ -128,8 +160,11 @@ bool XSSAuditor::canLoadObject(const String& url) const if (!isEnabled()) return true; + if (isSameOriginResource(url)) + return true; + if (findInRequest(url)) { - DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request")); + String consoleMessage = String::format("Refused to load an object. URL found within request: \"%s\".\n", url.utf8().data()); m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); return false; } @@ -140,10 +175,12 @@ bool XSSAuditor::canSetBaseElementURL(const String& url) const { if (!isEnabled()) return true; - - KURL baseElementURL(m_frame->document()->url(), url); - if (m_frame->document()->url().host() != baseElementURL.host() && findInRequest(url)) { - DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request")); + + if (isSameOriginResource(url)) + return true; + + if (findInRequest(url)) { + DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to load from document base URL. URL found within request.\n")); m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); return false; } @@ -156,22 +193,30 @@ 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, bool decodeURLEscapeSequencesTwice) { 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 (decodeURLEscapeSequencesTwice) { + result = decodeURLEscapeSequences(result); + utf8Url = result.utf8(); + decodedResult = encoding.decode(utf8Url.data(), utf8Url.length()); + if (!decodedResult.isEmpty()) + result = decodedResult; + } + 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 +231,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 +241,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 +253,62 @@ String XSSAuditor::decodeHTMLEntities(const String& string, bool leaveUndecodabl return String::adopt(result); } -bool XSSAuditor::findInRequest(const String& string, bool decodeHTMLentities) const +bool XSSAuditor::isSameOriginResource(const String& url) const +{ + // If the resource is loaded from the same URL as the enclosing page, it's + // probably not an XSS attack, so we reduce false positives by allowing the + // request. If the resource has a query string, we're more suspicious, + // however, because that's pretty rare and the attacker might be able to + // trick a server-side script into doing something dangerous with the query + // string. + KURL resourceURL(m_frame->document()->url(), url); + return (m_frame->document()->url().host() == resourceURL.host() && resourceURL.query().isEmpty()); +} + +bool XSSAuditor::findInRequest(const String& string, bool decodeEntities, bool allowRequestIfNoIllegalURICharacters, + bool decodeURLEscapeSequencesTwice) 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, decodeURLEscapeSequencesTwice); if (!result) - result = findInRequest(m_frame, string, decodeHTMLentities); + result = findInRequest(m_frame, string, decodeEntities, allowRequestIfNoIllegalURICharacters, decodeURLEscapeSequencesTwice); 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, + bool decodeURLEscapeSequencesTwice) 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 +317,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, decodeURLEscapeSequencesTwice); + + 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 +334,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, decodeURLEscapeSequencesTwice); 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..b64665b 100644 --- a/WebCore/page/XSSAuditor.h +++ b/WebCore/page/XSSAuditor.h @@ -42,14 +42,14 @@ namespace WebCore { // a script is to be allowed or denied based on the content of any // user-submitted data, including: // - // * the query string of the URL. + // * the URL. // * the HTTP-POST data. // // If the source code of a script resembles any user-submitted data then it // is denied execution. // - // When you instantiate the XSSAuditor you must specify the {@link Frame} - // of the page that you wish to audit. + // When you instantiate the XSSAuditor you must specify the Frame of the + // page that you wish to audit. // // Bindings // @@ -59,11 +59,14 @@ namespace WebCore { // JavaScript script is safe to execute before executing it. The following // methods call into XSSAuditor: // - // * ScriptController::evaluate - used to evaluate JavaScript scripts. - // * ScriptController::createInlineEventListener - used to create JavaScript event handlers. - // * HTMLTokenizer::scriptHandler - used to load external JavaScript scripts. + // * ScriptController::evaluateInWorld - used to evaluate JavaScript scripts. + // * ScriptController::executeIfJavaScriptURL - used to evaluate JavaScript URLs. + // * ScriptEventListener::createAttributeEventListener - used to create JavaScript event handlers. + // * HTMLBaseElement::process - used to set the document base URL. + // * HTMLTokenizer::parseTag - used to load external JavaScript scripts. + // * FrameLoader::requestObject - used to load <object>/<embed> elements. // - class XSSAuditor { + class XSSAuditor : public Noncopyable { public: XSSAuditor(Frame*); ~XSSAuditor(); @@ -99,18 +102,40 @@ 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), m_decodeURLEscapeSequencesTwice(false) { } + String canonicalizeURL(const String& url, const TextEncoding& encoding, bool decodeEntities, + bool decodeURLEscapeSequencesTwice); + + private: + // The parameters we were called with last. + String m_inputURL; + TextEncoding m_encoding; + bool m_decodeEntities; + bool m_decodeURLEscapeSequencesTwice; + + // 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, + bool decodeURLEscapeSequencesTwice = false); + static String decodeHTMLEntities(const String&, bool leaveUndecodableEntitiesUntouched = true); - bool findInRequest(Frame*, const String&, bool decodeHTMLentities = true) const; + bool isSameOriginResource(const String& url) const; + bool findInRequest(const String&, bool decodeEntities = true, bool allowRequestIfNoIllegalURICharacters = false, + bool decodeURLEscapeSequencesTwice = false) const; + bool findInRequest(Frame*, const String&, bool decodeEntities = true, bool allowRequestIfNoIllegalURICharacters = false, + bool decodeURLEscapeSequencesTwice = 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/android/DragControllerAndroid.cpp b/WebCore/page/android/DragControllerAndroid.cpp index 99e18a6..b20ab60 100644 --- a/WebCore/page/android/DragControllerAndroid.cpp +++ b/WebCore/page/android/DragControllerAndroid.cpp @@ -28,6 +28,7 @@ #include "DragController.h" #include "DragData.h" +#include "NotImplemented.h" namespace WebCore { @@ -38,13 +39,13 @@ bool DragController::isCopyKeyDown() DragOperation DragController::dragOperation(DragData* dragData) { - //FIXME: This logic is incomplete - ASSERT(0); + // FIXME: This logic is incomplete + notImplemented(); if (dragData->containsURL()) return DragOperationCopy; return DragOperationNone; -} +} void DragController::cleanupAfterSystemDrag() { diff --git a/WebCore/page/android/InspectorControllerAndroid.cpp b/WebCore/page/android/InspectorControllerAndroid.cpp deleted file mode 100644 index 328a6f3..0000000 --- a/WebCore/page/android/InspectorControllerAndroid.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "InspectorController.h" - -#include "InspectorBackend.h" -#include "InspectorClient.h" -#include "InspectorDOMAgent.h" -#include "InspectorFrontend.h" - -#include "Frame.h" -#include "Node.h" -#if USE(JSC) -#include "Profile.h" -#endif -// This stub file was created to avoid building and linking in all the -// Inspector codebase. If you would like to enable the Inspector, do the -// following steps: -// 1. Replace this file in WebCore/Android.mk with the common -// implementation, ie page/InsepctorController.cpp -// 2. Add the JS API files to JavaScriptCore/Android.mk: -// ? API/JSBase.cpp \ -// API/JSCallbackConstructor.cpp \ -// API/JSCallbackFunction.cpp \ -// API/JSCallbackObject.cpp \ -// API/JSClassRef.cpp \ -// API/JSContextRef.cpp \ -// API/JSObjectRef.cpp \ -// API/JSStringRef.cpp \ -// API/JSValueRef.cpp -// 3. Add the following LOCAL_C_INCLUDES to JavaScriptCore/Android.mk: -// ?$(LOCAL_PATH)/API \ -// $(LOCAL_PATH)/ForwardingHeaders \ -// $(LOCAL_PATH)/../../WebKit \ -// 4. Rebuild WebKit -// -// Note, for a functional Inspector, you must implement InspectorClientAndroid. - -namespace WebCore { - -struct InspectorResource : public RefCounted<InspectorResource> { -}; - -#if ENABLE(DATABASE) -struct InspectorDatabaseResource : public RefCounted<InspectorDatabaseResource> { -}; -#endif - -#if ENABLE(DOM_STORAGE) -struct InspectorDOMStorageResource : public RefCounted<InspectorDatabaseResource> { -}; -#endif - -InspectorController::InspectorController(Page*, InspectorClient* client) -{ - m_client = client; -} - -InspectorController::~InspectorController() { m_client->inspectorDestroyed(); } - -void InspectorController::windowScriptObjectAvailable() {} -void InspectorController::didCommitLoad(DocumentLoader*) {} -void InspectorController::identifierForInitialRequest(unsigned long, DocumentLoader*, ResourceRequest const&) {} -void InspectorController::willSendRequest(DocumentLoader*, unsigned long, ResourceRequest&, ResourceResponse const&) {} -void InspectorController::didReceiveResponse(DocumentLoader*, unsigned long, ResourceResponse const&) {} -void InspectorController::didReceiveContentLength(DocumentLoader*, unsigned long, int) {} -void InspectorController::didFinishLoading(DocumentLoader*, unsigned long) {} -void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader*, const CachedResource*) {} -void InspectorController::frameDetachedFromParent(Frame*) {} -void InspectorController::addMessageToConsole(WebCore::MessageSource, WebCore::MessageType, WebCore::MessageLevel, WebCore::String const&, unsigned int, WebCore::String const&) {} -void InspectorController::addMessageToConsole(WebCore::MessageSource, WebCore::MessageType, WebCore::MessageLevel, ScriptCallStack*) {} -#if ENABLE(DATABASE) -void InspectorController::didOpenDatabase(Database*, String const&, String const&, String const&) {} -#endif -#if ENABLE(DOM_STORAGE) - void InspectorController::didUseDOMStorage(StorageArea* storageArea, bool isLocalStorage, Frame* frame) {} -#endif -bool InspectorController::enabled() const { return false; } -void InspectorController::inspect(Node*) {} -bool InspectorController::windowVisible() { return false; } -void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString) {} -void InspectorController::scriptImported(unsigned long identifier, const String& sourceString) {} -void InspectorController::inspectedPageDestroyed() {} - -void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame) {} -void InspectorController::startGroup(MessageSource source, ScriptCallStack* callFrame) {} -void InspectorController::endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL) {} -void InspectorController::startTiming(const String& title) {} -bool InspectorController::stopTiming(const String& title, double& elapsed) { return false; } -void InspectorController::count(const String& title, unsigned lineNumber, const String& sourceID) {} - -void InspectorController::mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags) {} -void InspectorController::handleMousePressOnNode(Node*) {} - -#if ENABLE(JAVASCRIPT_DEBUGGER) -void InspectorController::didPause() {} -#endif - -} // namespace WebCore diff --git a/WebCore/page/animation/AnimationBase.cpp b/WebCore/page/animation/AnimationBase.cpp index 7503f0a..f1ee750 100644 --- a/WebCore/page/animation/AnimationBase.cpp +++ b/WebCore/page/animation/AnimationBase.cpp @@ -190,7 +190,7 @@ class PropertyWrapperBase; static void addShorthandProperties(); static PropertyWrapperBase* wrapperForProperty(int propertyID); -class PropertyWrapperBase { +class PropertyWrapperBase : public Noncopyable { public: PropertyWrapperBase(int prop) : m_prop(prop) @@ -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,125 @@ 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 CSSPropertyWebkitBackgroundSize: + 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 +589,15 @@ 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(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers)); + + gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers)); + gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers)); + gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers)); gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyFontSize, &RenderStyle::fontSize, &RenderStyle::setBlendedFontSize)); gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth)); @@ -496,7 +645,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 +834,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..aa5de2c 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> @@ -53,7 +55,7 @@ AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame) , m_lastStyleAvailableWaiter(0) , m_responseWaiters(0) , m_lastResponseWaiter(0) - , m_waitingForAResponse(false) + , m_waitingForResponse(false) { } @@ -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; } @@ -277,6 +279,19 @@ double AnimationControllerPrivate::beginAnimationUpdateTime() return m_beginAnimationUpdateTime; } +void AnimationControllerPrivate::endAnimationUpdate() +{ + styleAvailable(); + if (!m_waitingForResponse) + startTimeResponse(beginAnimationUpdateTime()); +} + +void AnimationControllerPrivate::receivedStartTimeResponse(double time) +{ + m_waitingForResponse = false; + startTimeResponse(time); +} + PassRefPtr<RenderStyle> AnimationControllerPrivate::getAnimatedStyleForRenderer(RenderObject* renderer) { if (!renderer) @@ -376,7 +391,7 @@ void AnimationControllerPrivate::addToStartTimeResponseWaitList(AnimationBase* a ASSERT(!animation->next()); if (willGetResponse) - m_waitingForAResponse = true; + m_waitingForResponse = true; if (m_responseWaiters) m_lastResponseWaiter->setNext(animation); @@ -406,13 +421,13 @@ void AnimationControllerPrivate::removeFromStartTimeResponseWaitList(AnimationBa } } -void AnimationControllerPrivate::startTimeResponse(double t) +void AnimationControllerPrivate::startTimeResponse(double time) { // Go through list of waiters and send them on their way for (AnimationBase* animation = m_responseWaiters; animation; ) { AnimationBase* nextAnimation = animation->next(); animation->setNext(0); - animation->onAnimationStartResponse(t); + animation->onAnimationStartResponse(time); animation = nextAnimation; } @@ -438,7 +453,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/animation/AnimationControllerPrivate.h b/WebCore/page/animation/AnimationControllerPrivate.h index 359b9b5..7db3803 100644 --- a/WebCore/page/animation/AnimationControllerPrivate.h +++ b/WebCore/page/animation/AnimationControllerPrivate.h @@ -80,18 +80,8 @@ public: double beginAnimationUpdateTime(); void setBeginAnimationUpdateTime(double t) { m_beginAnimationUpdateTime = t; } - void endAnimationUpdate() - { - styleAvailable(); - if (!m_waitingForAResponse) - startTimeResponse(beginAnimationUpdateTime()); - } - - void receivedStartTimeResponse(double t) - { - m_waitingForAResponse = false; - startTimeResponse(t); - } + void endAnimationUpdate(); + void receivedStartTimeResponse(double); void addToStyleAvailableWaitList(AnimationBase*); void removeFromStyleAvailableWaitList(AnimationBase*); @@ -127,7 +117,7 @@ private: AnimationBase* m_responseWaiters; AnimationBase* m_lastResponseWaiter; - bool m_waitingForAResponse; + bool m_waitingForResponse; }; } // namespace WebCore diff --git a/WebCore/page/animation/ImplicitAnimation.cpp b/WebCore/page/animation/ImplicitAnimation.cpp index 8e6349d..50fc781 100644 --- a/WebCore/page/animation/ImplicitAnimation.cpp +++ b/WebCore/page/animation/ImplicitAnimation.cpp @@ -142,10 +142,8 @@ void ImplicitAnimation::onAnimationEnd(double elapsedTime) if (keyframeAnim) keyframeAnim->setUnanimatedStyle(m_toStyle); - if (!sendTransitionEvent(eventNames().webkitTransitionEndEvent, elapsedTime)) { - // We didn't dispatch an event, which would call endAnimation(), so we'll just call it here. - endAnimation(true); - } + sendTransitionEvent(eventNames().webkitTransitionEndEvent, elapsedTime); + endAnimation(true); } bool ImplicitAnimation::sendTransitionEvent(const AtomicString& eventType, double elapsedTime) diff --git a/WebCore/page/animation/KeyframeAnimation.cpp b/WebCore/page/animation/KeyframeAnimation.cpp index 39ae1e7..500bf6f 100644 --- a/WebCore/page/animation/KeyframeAnimation.cpp +++ b/WebCore/page/animation/KeyframeAnimation.cpp @@ -36,6 +36,7 @@ #include "EventNames.h" #include "RenderLayer.h" #include "RenderLayerBacking.h" +#include "RenderStyle.h" #include <wtf/UnusedParam.h> namespace WebCore { @@ -244,10 +245,8 @@ void KeyframeAnimation::onAnimationIteration(double elapsedTime) void KeyframeAnimation::onAnimationEnd(double elapsedTime) { - if (!sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime)) { - // We didn't dispatch an event, which would call endAnimation(), so we'll just call it here. - endAnimation(true); - } + sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime); + endAnimation(true); } bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime) diff --git a/WebCore/page/animation/KeyframeAnimation.h b/WebCore/page/animation/KeyframeAnimation.h index 4905fc3..e3b8f53 100644 --- a/WebCore/page/animation/KeyframeAnimation.h +++ b/WebCore/page/animation/KeyframeAnimation.h @@ -32,10 +32,11 @@ #include "AnimationBase.h" #include "Document.h" #include "KeyframeList.h" -#include "RenderStyle.h" namespace WebCore { +class RenderStyle; + // A KeyframeAnimation tracks the state of an explicit animation // for a single RenderObject. class KeyframeAnimation : public AnimationBase { diff --git a/WebCore/page/chromium/EventHandlerChromium.cpp b/WebCore/page/chromium/EventHandlerChromium.cpp index 467f94e..ac76a29 100644 --- a/WebCore/page/chromium/EventHandlerChromium.cpp +++ b/WebCore/page/chromium/EventHandlerChromium.cpp @@ -154,4 +154,14 @@ unsigned EventHandler::accessKeyModifiers() #endif } +#if PLATFORM(LINUX) +// GTK+ must scroll horizontally if the mouse pointer is on top of the +// horizontal scrollbar while scrolling with the wheel. +// This code comes from gtk/EventHandlerGtk.cpp. +bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult& result) const +{ + return result.scrollbar() && result.scrollbar()->orientation() == HorizontalScrollbar; +} +#endif + } // namespace WebCore 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/ChromeMac.mm b/WebCore/page/mac/ChromeMac.mm index aba3449..14c07de 100644 --- a/WebCore/page/mac/ChromeMac.mm +++ b/WebCore/page/mac/ChromeMac.mm @@ -25,6 +25,8 @@ namespace WebCore { +#if !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) + void Chrome::focusNSView(NSView* view) { BEGIN_BLOCK_OBJC_EXCEPTIONS; @@ -48,4 +50,6 @@ void Chrome::focusNSView(NSView* view) END_BLOCK_OBJC_EXCEPTIONS; } +#endif + } // namespace WebCore diff --git a/WebCore/page/mac/DragControllerMac.mm b/WebCore/page/mac/DragControllerMac.mm index c476df7..adf89fa 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" @@ -41,6 +42,15 @@ const int DragController::DragIconBottomInset = 3; const float DragController::DragImageAlpha = 0.75f; +#if ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) + +DragOperation DragController::dragOperation(DragData*) +{ + return DragOperationNone; +} + +#else + bool DragController::isCopyKeyDown() { return [[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask; @@ -57,7 +67,9 @@ DragOperation DragController::dragOperation(DragData* dragData) return DragOperationCopy; return DragOperationNone; -} +} + +#endif const IntSize& DragController::maxDragImageSize() { @@ -75,4 +87,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..92895d9 100644 --- a/WebCore/page/mac/EventHandlerMac.mm +++ b/WebCore/page/mac/EventHandlerMac.mm @@ -60,7 +60,11 @@ static inline IMP method_setImplementation(Method m, IMP i) namespace WebCore { +#if ENABLE(DRAG_SUPPORT) const double EventHandler::TextDragDelay = 0.15; +#endif + +#if !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) static RetainPtr<NSEvent>& currentNSEventSlot() { @@ -110,7 +114,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(); @@ -134,65 +138,6 @@ PassRefPtr<KeyboardEvent> EventHandler::currentKeyboardEvent() const } } -static inline bool isKeyboardOptionTab(KeyboardEvent* event) -{ - return event - && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent) - && event->altKey() - && event->keyIdentifier() == "U+0009"; -} - -bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const -{ - return isKeyboardOptionTab(event); -} - -bool EventHandler::tabsToAllControls(KeyboardEvent* event) const -{ - Page* page = m_frame->page(); - if (!page) - return false; - - KeyboardUIMode keyboardUIMode = page->chrome()->client()->keyboardUIMode(); - bool handlingOptionTab = isKeyboardOptionTab(event); - - // If tab-to-links is off, option-tab always highlights all controls - if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab) - return true; - - // If system preferences say to include all controls, we always include all controls - if (keyboardUIMode & KeyboardAccessFull) - return true; - - // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab. - if (keyboardUIMode & KeyboardAccessTabsToLinks) - return !handlingOptionTab; - - return handlingOptionTab; -} - -bool EventHandler::needsKeyboardEventDisambiguationQuirks() const -{ - Document* document = m_frame->document(); - - // RSS view needs arrow key keypress events. - if (applicationIsSafari() && document->url().protocolIs("feed") || document->url().protocolIs("feeds")) - return true; - Settings* settings = m_frame->settings(); - if (!settings) - return false; - -#if ENABLE(DASHBOARD_SUPPORT) - if (settings->usesDashboardBackwardCompatibilityMode()) - return true; -#endif - - if (settings->needsKeyboardEventDisambiguationQuirks()) - return true; - - return false; -} - bool EventHandler::keyEvent(NSEvent *event) { BEGIN_BLOCK_OBJC_EXCEPTIONS; @@ -367,11 +312,7 @@ NSView *EventHandler::mouseDownViewIfStillGood() return mouseDownView; } -bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const -{ - return m_activationEventNumber == event.eventNumber(); -} - +#if ENABLE(DRAG_SUPPORT) bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&) { NSView *view = mouseDownViewIfStillGood(); @@ -390,15 +331,7 @@ bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResult return true; } - -PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const -{ - NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard]; - // Must be done before ondragstart adds types and data to the pboard, - // also done for security, as it erases data from the last drag - [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 +363,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 @@ -691,39 +626,172 @@ bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& return passSubframeEventToSubframe(mev, subframe); } -unsigned EventHandler::accessKeyModifiers() -{ - // Control+Option key combinations are usually unused on Mac OS X, but not when VoiceOver is enabled. - // So, we use Control in this case, even though it conflicts with Emacs-style key bindings. - // See <https://bugs.webkit.org/show_bug.cgi?id=21107> for more detail. - if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled()) - return PlatformKeyboardEvent::CtrlKey; - - return PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey; -} - 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) + +bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const +{ + return m_activationEventNumber == event.eventNumber(); +} + +#else // ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) + +bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) +{ + subframe->eventHandler()->handleMousePressEvent(mev.event()); + return true; +} + +bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode) +{ + if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe) + return false; + subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode); + return true; +} + +bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) +{ + subframe->eventHandler()->handleMouseReleaseEvent(mev.event()); + return true; +} + +bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& wheelEvent, Widget* widget) +{ + if (!widget->isFrameView()) + return false; + + return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent); +} + +void EventHandler::focusDocumentView() +{ + Page* page = m_frame->page(); + if (!page) + return; + page->focusController()->setFocusedFrame(m_frame); +} + +bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults&) +{ + notImplemented(); + return false; +} + +bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const +{ + notImplemented(); + return false; +} + +#endif + +#if ENABLE(DRAG_SUPPORT) + +PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const +{ + NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard]; + // Must be done before ondragstart adds types and data to the pboard, + // also done for security, as it erases data from the last drag + [pasteboard declareTypes:[NSArray array] owner:nil]; + return ClipboardMac::create(true, pasteboard, ClipboardWritable, m_frame); +} + +#endif + +static inline bool isKeyboardOptionTab(KeyboardEvent* event) +{ + return event + && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent) + && event->altKey() + && event->keyIdentifier() == "U+0009"; +} + +bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const +{ + return isKeyboardOptionTab(event); +} + +bool EventHandler::tabsToAllControls(KeyboardEvent* event) const +{ + Page* page = m_frame->page(); + if (!page) + return false; + + KeyboardUIMode keyboardUIMode = page->chrome()->client()->keyboardUIMode(); + bool handlingOptionTab = isKeyboardOptionTab(event); + + // If tab-to-links is off, option-tab always highlights all controls + if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab) + return true; + + // If system preferences say to include all controls, we always include all controls + if (keyboardUIMode & KeyboardAccessFull) + return true; + + // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab. + if (keyboardUIMode & KeyboardAccessTabsToLinks) + return !handlingOptionTab; + + return handlingOptionTab; +} + +bool EventHandler::needsKeyboardEventDisambiguationQuirks() const +{ + Document* document = m_frame->document(); + + // RSS view needs arrow key keypress events. + if (applicationIsSafari() && document->url().protocolIs("feed") || document->url().protocolIs("feeds")) + return true; + Settings* settings = m_frame->settings(); + if (!settings) + return false; + +#if ENABLE(DASHBOARD_SUPPORT) + if (settings->usesDashboardBackwardCompatibilityMode()) + return true; +#endif + + if (settings->needsKeyboardEventDisambiguationQuirks()) + return true; + + return false; +} + +unsigned EventHandler::accessKeyModifiers() +{ + // Control+Option key combinations are usually unused on Mac OS X, but not when VoiceOver is enabled. + // So, we use Control in this case, even though it conflicts with Emacs-style key bindings. + // See <https://bugs.webkit.org/show_bug.cgi?id=21107> for more detail. + if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled()) + return PlatformKeyboardEvent::CtrlKey; + + return PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey; } } diff --git a/WebCore/page/mac/FrameMac.mm b/WebCore/page/mac/FrameMac.mm index c656624..fce5704 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" @@ -273,7 +271,9 @@ NSImage* Frame::imageFromRect(NSRect rect) const if (![view respondsToSelector:@selector(drawSingleRect:)]) return nil; - NSImage* resultImage; + PaintBehavior oldPaintBehavior = m_view->paintBehavior(); + m_view->setPaintBehavior(oldPaintBehavior | PaintBehaviorFlattenCompositingLayers); + BEGIN_BLOCK_OBJC_EXCEPTIONS; NSRect bounds = [view bounds]; @@ -284,7 +284,7 @@ NSImage* Frame::imageFromRect(NSRect rect) const rect.size.width = roundf(rect.size.width); rect = [view convertRect:rect fromView:nil]; - resultImage = [[[NSImage alloc] initWithSize:rect.size] autorelease]; + NSImage* resultImage = [[[NSImage alloc] initWithSize:rect.size] autorelease]; if (rect.size.width != 0 && rect.size.height != 0) { [resultImage setFlipped:YES]; @@ -303,19 +303,21 @@ NSImage* Frame::imageFromRect(NSRect rect) const [resultImage setFlipped:NO]; } + m_view->setPaintBehavior(oldPaintBehavior); return resultImage; END_BLOCK_OBJC_EXCEPTIONS; + m_view->setPaintBehavior(oldPaintBehavior); return nil; } NSImage* Frame::selectionImage(bool forceBlackText) const { - m_view->setPaintRestriction(forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly); + m_view->setPaintBehavior(PaintBehaviorSelectionOnly | (forceBlackText ? PaintBehaviorForceBlackText : 0)); m_doc->updateLayout(); NSImage* result = imageFromRect(selectionBounds()); - m_view->setPaintRestriction(PaintRestrictionNone); + m_view->setPaintBehavior(PaintBehaviorNormal); return result; } @@ -461,33 +463,6 @@ NSWritingDirection Frame::baseWritingDirectionForSelectionStart() const return result; } -const short enableRomanKeyboardsOnly = -23; -void Frame::setUseSecureKeyboardEntry(bool enable) -{ - if (enable == IsSecureEventInputEnabled()) - return; - if (enable) { - EnableSecureEventInput(); -#ifdef BUILDING_ON_TIGER - KeyScript(enableRomanKeyboardsOnly); -#else - // WebKit substitutes nil for input context when in password field, which corresponds to null TSMDocument. So, there is - // no need to call TSMGetActiveDocument(), which may return an incorrect result when selection hasn't been yet updated - // after focusing a node. - CFArrayRef inputSources = TISCreateASCIICapableInputSourceList(); - TSMSetDocumentProperty(0, kTSMDocumentEnabledInputSourcesPropertyTag, sizeof(CFArrayRef), &inputSources); - CFRelease(inputSources); -#endif - } else { - DisableSecureEventInput(); -#ifdef BUILDING_ON_TIGER - KeyScript(smKeyEnableKybds); -#else - TSMRemoveDocumentProperty(0, kTSMDocumentEnabledInputSourcesPropertyTag); -#endif - } -} - #if ENABLE(DASHBOARD_SUPPORT) NSMutableDictionary* Frame::dashboardRegionsDictionary() { @@ -533,35 +508,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..43f3f0a 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,17 @@ - (NSString *)mediaElementLoadingStateText; - (NSString *)mediaElementLiveBroadcastStateText; +- (NSString*)localizedMediaControlElementString:(NSString*)name; +- (NSString*)localizedMediaControlElementHelpText:(NSString*)name; +- (NSString*)localizedMediaTimeDescription:(float)time; + +- (NSString *)validationMessageValueMissingText; +- (NSString *)validationMessageTypeMismatchText; +- (NSString *)validationMessagePatternMismatchText; +- (NSString *)validationMessageTooLongText; +- (NSString *)validationMessageRangeUnderflowText; +- (NSString *)validationMessageRangeOverflowText; +- (NSString *)validationMessageStepMismatchText; @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/FrameCGWin.cpp b/WebCore/page/win/FrameCGWin.cpp index 7483627..d9e577b 100644 --- a/WebCore/page/win/FrameCGWin.cpp +++ b/WebCore/page/win/FrameCGWin.cpp @@ -52,6 +52,9 @@ static void drawRectIntoContext(IntRect rect, FrameView* view, GraphicsContext* static HBITMAP imageFromRect(const Frame* frame, IntRect& ir) { + PaintBehavior oldPaintBehavior = frame->view()->paintBehavior(); + frame->view()->setPaintBehavior(oldPaintBehavior | PaintBehaviorFlattenCompositingLayers); + void* bits; HDC hdc = CreateCompatibleDC(0); int w = ir.width(); @@ -74,6 +77,8 @@ static HBITMAP imageFromRect(const Frame* frame, IntRect& ir) SelectObject(hdc, hbmpOld); DeleteDC(hdc); + frame->view()->setPaintBehavior(oldPaintBehavior); + return hbmp; } @@ -81,12 +86,12 @@ HBITMAP imageFromSelection(Frame* frame, bool forceBlackText) { frame->document()->updateLayout(); - frame->view()->setPaintRestriction(forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly); + frame->view()->setPaintBehavior(PaintBehaviorSelectionOnly | (forceBlackText ? PaintBehaviorForceBlackText : 0)); FloatRect fr = frame->selectionBounds(); IntRect ir(static_cast<int>(fr.x()), static_cast<int>(fr.y()), static_cast<int>(fr.width()), static_cast<int>(fr.height())); HBITMAP image = imageFromRect(frame, ir); - frame->view()->setPaintRestriction(PaintRestrictionNone); + frame->view()->setPaintBehavior(PaintBehaviorNormal); return image; } 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; +} + +} |
