diff options
Diffstat (limited to 'WebCore/page')
68 files changed, 2783 insertions, 537 deletions
diff --git a/WebCore/page/Chrome.cpp b/WebCore/page/Chrome.cpp index cb7f6bf..b3df888 100644 --- a/WebCore/page/Chrome.cpp +++ b/WebCore/page/Chrome.cpp @@ -67,9 +67,19 @@ Chrome::~Chrome() m_client->chromeDestroyed(); } -void Chrome::repaint(const IntRect& windowRect, bool contentChanged, bool immediate, bool repaintContentOnly) +void Chrome::invalidateWindow(const IntRect& updateRect, bool immediate) { - m_client->repaint(windowRect, contentChanged, immediate, repaintContentOnly); + m_client->invalidateWindow(updateRect, immediate); +} + +void Chrome::invalidateContentsAndWindow(const IntRect& updateRect, bool immediate) +{ + m_client->invalidateContentsAndWindow(updateRect, immediate); +} + +void Chrome::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate) +{ + m_client->invalidateContentsForSlowScroll(updateRect, immediate); } void Chrome::scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) @@ -334,7 +344,7 @@ void Chrome::mouseDidMoveOverElement(const HitTestResult& result, unsigned modif if (result.innerNode()) { Document* document = result.innerNode()->document(); if (document && document->isDNSPrefetchEnabled()) - prefetchDNS(result.absoluteLinkURL().host()); + ResourceHandle::prepareForURL(result.absoluteLinkURL()); } m_client->mouseDidMoveOverElement(result, modifierFlags); @@ -417,9 +427,15 @@ void Chrome::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geo m_client->requestGeolocationPermissionForFrame(frame, geolocation); } +<<<<<<< HEAD void Chrome::cancelGeolocationPermissionRequestForFrame(Frame* frame) { m_client->cancelGeolocationPermissionRequestForFrame(frame); +======= +void Chrome::cancelGeolocationPermissionRequestForFrame(Frame* frame, Geolocation* geolocation) +{ + m_client->cancelGeolocationPermissionRequestForFrame(frame, geolocation); +>>>>>>> webkit.org at r58033 } void Chrome::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> fileChooser) @@ -427,9 +443,9 @@ void Chrome::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> fileChooser) m_client->runOpenPanel(frame, fileChooser); } -void Chrome::iconForFiles(const Vector<String>& filenames, PassRefPtr<FileChooser> fileChooser) +void Chrome::chooseIconForFiles(const Vector<String>& filenames, FileChooser* fileChooser) { - m_client->iconForFiles(filenames, fileChooser); + m_client->chooseIconForFiles(filenames, fileChooser); } bool Chrome::setCursor(PlatformCursorHandle cursor) diff --git a/WebCore/page/Chrome.h b/WebCore/page/Chrome.h index 9227f87..ec58de2 100644 --- a/WebCore/page/Chrome.h +++ b/WebCore/page/Chrome.h @@ -60,8 +60,11 @@ namespace WebCore { ChromeClient* client() { return m_client; } // HostWindow methods. - virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false); - virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect); + + virtual void invalidateWindow(const IntRect&, bool); + virtual void invalidateContentsAndWindow(const IntRect&, bool); + virtual void invalidateContentsForSlowScroll(const IntRect&, bool); + virtual void scroll(const IntSize&, const IntRect&, const IntRect&); virtual IntPoint screenToWindow(const IntPoint&) const; virtual IntRect windowToScreen(const IntRect&) const; virtual PlatformPageClient platformPageClient() const; @@ -133,10 +136,14 @@ namespace WebCore { void print(Frame*); void requestGeolocationPermissionForFrame(Frame*, Geolocation*); +<<<<<<< HEAD void cancelGeolocationPermissionRequestForFrame(Frame*); +======= + void cancelGeolocationPermissionRequestForFrame(Frame*, Geolocation*); +>>>>>>> webkit.org at r58033 void runOpenPanel(Frame*, PassRefPtr<FileChooser>); - void iconForFiles(const Vector<String>&, PassRefPtr<FileChooser>); + void chooseIconForFiles(const Vector<String>&, FileChooser*); bool setCursor(PlatformCursorHandle); diff --git a/WebCore/page/ChromeClient.h b/WebCore/page/ChromeClient.h index 1b8b734..e0b70e0 100644 --- a/WebCore/page/ChromeClient.h +++ b/WebCore/page/ChromeClient.h @@ -56,6 +56,7 @@ namespace WebCore { class Widget; struct FrameLoadRequest; + struct ViewportArguments; struct WindowFeatures; #if USE(ACCELERATED_COMPOSITING) @@ -133,8 +134,10 @@ namespace WebCore { virtual IntRect windowResizerRect() const = 0; // Methods used by HostWindow. - virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false) = 0; - virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) = 0; + virtual void invalidateWindow(const IntRect&, bool) = 0; + virtual void invalidateContentsAndWindow(const IntRect&, bool) = 0; + virtual void invalidateContentsForSlowScroll(const IntRect&, bool) = 0; + virtual void scroll(const IntSize&, const IntRect&, const IntRect&) = 0; virtual IntPoint screenToWindow(const IntPoint&) const = 0; virtual IntRect windowToScreen(const IntRect&) const = 0; virtual PlatformPageClient platformPageClient() const = 0; @@ -147,6 +150,8 @@ namespace WebCore { virtual void setToolTip(const String&, TextDirection) = 0; + virtual void didReceiveViewportArguments(Frame*, const ViewportArguments&) const { } + virtual void print(Frame*) = 0; #if ENABLE(DATABASE) @@ -187,12 +192,15 @@ namespace WebCore { // This can be either a synchronous or asynchronous call. The ChromeClient can display UI asking the user for permission // to use Geolocation. virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*) = 0; +<<<<<<< HEAD virtual void cancelGeolocationPermissionRequestForFrame(Frame*) = 0; +======= + virtual void cancelGeolocationPermissionRequestForFrame(Frame*, Geolocation*) = 0; +>>>>>>> webkit.org at r58033 virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>) = 0; // Asynchronous request to load an icon for specified filenames. - // This is called only if Icon::createIconForFiles() returns 0. - virtual void iconForFiles(const Vector<String>&, PassRefPtr<FileChooser>) = 0; + virtual void chooseIconForFiles(const Vector<String>&, FileChooser*) = 0; virtual bool setCursor(PlatformCursorHandle) = 0; @@ -214,6 +222,9 @@ namespace WebCore { // Sets a flag to specify that the view needs to be updated, so we need // to do an eager layout before the drawing. virtual void scheduleCompositingLayerSync() = 0; + // Returns whether or not the client can render the composited layer, + // regardless of the settings. + virtual bool allowsAcceleratedCompositing() const { return true; } #endif virtual bool supportsFullscreenForNode(const Node*) { return false; } @@ -233,6 +244,14 @@ namespace WebCore { virtual void needTouchEvents(bool) = 0; #endif +#if ENABLE(WIDGETS_10_SUPPORT) + virtual bool isWindowed() { return false; } + virtual bool isFloating() { return false; } + virtual bool isFullscreen() { return false; } + virtual bool isMaximized() { return false; } + virtual bool isMinimized() { return false; } +#endif + protected: virtual ~ChromeClient() { } }; diff --git a/WebCore/page/Console.cpp b/WebCore/page/Console.cpp index 99b3106..d5ff7bc 100644 --- a/WebCore/page/Console.cpp +++ b/WebCore/page/Console.cpp @@ -29,7 +29,6 @@ #include "config.h" #include "Console.h" -#include "CString.h" #include "Chrome.h" #include "ChromeClient.h" #include "ConsoleMessage.h" @@ -45,6 +44,7 @@ #include "ScriptProfile.h" #include "ScriptProfiler.h" #include <stdio.h> +#include <wtf/text/CString.h> #include <wtf/UnusedParam.h> namespace WebCore { diff --git a/WebCore/page/Console.idl b/WebCore/page/Console.idl index c08fcc0..b3c0c24 100644 --- a/WebCore/page/Console.idl +++ b/WebCore/page/Console.idl @@ -30,8 +30,7 @@ module window { interface [OmitConstructor] Console { - // Not enabled in V8 because it requires request-reply style. -#if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER && !(defined(V8_BINDING) && V8_BINDING) +#if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER readonly attribute [CustomGetter] Array profiles; #endif diff --git a/WebCore/page/DOMSelection.cpp b/WebCore/page/DOMSelection.cpp index 0d21c56..a583176 100644 --- a/WebCore/page/DOMSelection.cpp +++ b/WebCore/page/DOMSelection.cpp @@ -207,6 +207,10 @@ void DOMSelection::collapse(Node* node, int offset, ExceptionCode& ec) ec = INDEX_SIZE_ERR; return; } + + if (!isValidForPosition(node)) + return; + m_frame->selection()->moveTo(VisiblePosition(node, offset, DOWNSTREAM)); } @@ -244,6 +248,10 @@ void DOMSelection::setBaseAndExtent(Node* baseNode, int baseOffset, Node* extent ec = INDEX_SIZE_ERR; return; } + + if (!isValidForPosition(baseNode) || !isValidForPosition(extentNode)) + return; + VisiblePosition visibleBase = VisiblePosition(baseNode, baseOffset, DOWNSTREAM); VisiblePosition visibleExtent = VisiblePosition(extentNode, extentOffset, DOWNSTREAM); @@ -258,6 +266,10 @@ void DOMSelection::setPosition(Node* node, int offset, ExceptionCode& ec) ec = INDEX_SIZE_ERR; return; } + + if (!isValidForPosition(node)) + return; + m_frame->selection()->moveTo(VisiblePosition(node, offset, DOWNSTREAM)); } @@ -320,14 +332,16 @@ void DOMSelection::extend(Node* node, int offset, ExceptionCode& ec) ec = TYPE_MISMATCH_ERR; return; } + if (offset < 0 || offset > (node->offsetInCharacters() ? caretMaxOffset(node) : (int)node->childNodeCount())) { ec = INDEX_SIZE_ERR; return; } - SelectionController* selection = m_frame->selection(); - selection->expandUsingGranularity(CharacterGranularity); - selection->setExtent(VisiblePosition(node, offset, DOWNSTREAM)); + if (!isValidForPosition(node)) + return; + + m_frame->selection()->setExtent(VisiblePosition(node, offset, DOWNSTREAM)); } PassRefPtr<Range> DOMSelection::getRangeAt(int index, ExceptionCode& ec) @@ -429,7 +443,7 @@ bool DOMSelection::containsNode(const Node* n, bool allowPartial) const SelectionController* selection = m_frame->selection(); - if (!n || selection->isNone()) + if (!n || m_frame->document() != n->document() || selection->isNone()) return false; Node* parentNode = n->parentNode(); @@ -472,4 +486,12 @@ String DOMSelection::toString() return plainText(m_frame->selection()->selection().toNormalizedRange().get()); } +bool DOMSelection::isValidForPosition(Node* node) const +{ + ASSERT(m_frame); + if (!node) + return true; + return node->document() == m_frame->document(); +} + } // namespace WebCore diff --git a/WebCore/page/DOMSelection.h b/WebCore/page/DOMSelection.h index e0fe1e3..0287e44 100644 --- a/WebCore/page/DOMSelection.h +++ b/WebCore/page/DOMSelection.h @@ -96,6 +96,7 @@ namespace WebCore { // Convenience method for accessors, does not NULL check m_frame. const VisibleSelection& visibleSelection() const; + bool isValidForPosition(Node*) const; Frame* m_frame; }; diff --git a/WebCore/page/DOMWindow.cpp b/WebCore/page/DOMWindow.cpp index 6af22c3..c74cfaf 100644 --- a/WebCore/page/DOMWindow.cpp +++ b/WebCore/page/DOMWindow.cpp @@ -26,15 +26,16 @@ #include "config.h" #include "DOMWindow.h" +#include "Base64.h" #include "BarInfo.h" #include "BeforeUnloadEvent.h" #include "CSSComputedStyleDeclaration.h" #include "CSSRuleList.h" #include "CSSStyleSelector.h" -#include "CString.h" #include "Chrome.h" #include "Console.h" #include "Database.h" +#include "DatabaseCallback.h" #include "DOMApplicationCache.h" #include "DOMSelection.h" #include "DOMTimer.h" @@ -52,6 +53,8 @@ #include "FrameView.h" #include "HTMLFrameOwnerElement.h" #include "History.h" +#include "IndexedDatabase.h" +#include "IndexedDatabaseRequest.h" #include "InspectorController.h" #include "InspectorTimelineAgent.h" #include "Location.h" @@ -73,6 +76,7 @@ #include "SuddenTermination.h" #include "WebKitPoint.h" #include <algorithm> +#include <wtf/text/CString.h> #include <wtf/MathExtras.h> using std::min; @@ -466,6 +470,12 @@ void DOMWindow::clear() m_notifications->disconnectFrame(); m_notifications = 0; #endif + +#if ENABLE(INDEXED_DATABASE) + if (m_indexedDatabaseRequest) + m_indexedDatabaseRequest->disconnectFrame(); + m_indexedDatabaseRequest = 0; +#endif } #if ENABLE(ORIENTATION_EVENTS) @@ -573,9 +583,6 @@ Storage* DOMWindow::sessionStorage() const Document* document = this->document(); if (!document) return 0; - - if (!document->securityOrigin()->canAccessStorage()) - return 0; Page* page = document->page(); if (!page) @@ -590,7 +597,7 @@ Storage* DOMWindow::sessionStorage() const return m_sessionStorage.get(); } -Storage* DOMWindow::localStorage() const +Storage* DOMWindow::localStorage(ExceptionCode& ec) const { if (m_localStorage) return m_localStorage.get(); @@ -599,8 +606,10 @@ Storage* DOMWindow::localStorage() const if (!document) return 0; - if (!document->securityOrigin()->canAccessStorage()) + if (!document->securityOrigin()->canAccessLocalStorage()) { + ec = SECURITY_ERR; return 0; + } Page* page = document->page(); if (!page) @@ -644,7 +653,23 @@ NotificationCenter* DOMWindow::webkitNotifications() const #if ENABLE(INDEXED_DATABASE) IndexedDatabaseRequest* DOMWindow::indexedDB() const { - return 0; + if (m_indexedDatabaseRequest) + return m_indexedDatabaseRequest.get(); + + Document* document = this->document(); + if (!document) + return 0; + + // FIXME: See if access is allowed. + + Page* page = document->page(); + if (!page) + return 0; + + // FIXME: See if indexedDatabase access is allowed. + + m_indexedDatabaseRequest = IndexedDatabaseRequest::create(page->group().indexedDatabase(), m_frame); + return m_indexedDatabaseRequest.get(); } #endif @@ -826,6 +851,57 @@ String DOMWindow::prompt(const String& message, const String& defaultValue) return String(); } +static bool isSafeToConvertCharList(const String& string) +{ + for (unsigned i = 0; i < string.length(); i++) { + if (string[i] > 0xFF) + return false; + } + + return true; +} + +String DOMWindow::btoa(const String& stringToEncode, ExceptionCode& ec) +{ + if (stringToEncode.isNull()) + return String(); + + if (!isSafeToConvertCharList(stringToEncode)) { + ec = INVALID_CHARACTER_ERR; + return String(); + } + + Vector<char> in; + in.append(stringToEncode.characters(), stringToEncode.length()); + Vector<char> out; + + base64Encode(in, out); + + return String(out.data(), out.size()); +} + +String DOMWindow::atob(const String& encodedString, ExceptionCode& ec) +{ + if (encodedString.isNull()) + return String(); + + if (!isSafeToConvertCharList(encodedString)) { + ec = INVALID_CHARACTER_ERR; + return String(); + } + + Vector<char> in; + in.append(encodedString.characters(), encodedString.length()); + Vector<char> out; + + if (!base64Decode(in, out)) { + ec = INVALID_CHARACTER_ERR; + return String(); + } + + return String(out.data(), out.size()); +} + bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool /*wholeWord*/, bool /*searchInFrames*/, bool /*showDialog*/) const { if (!m_frame) @@ -1067,24 +1143,20 @@ PassRefPtr<Media> DOMWindow::media() const return m_media.get(); } -PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String&) const +PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String& pseudoElt) const { if (!elt) return 0; - // FIXME: This needs take pseudo elements into account. - return computedStyle(elt); + return computedStyle(elt, false, pseudoElt); } -PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* elt, const String& pseudoElt, bool authorOnly) const +PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* elt, const String&, bool authorOnly) const { if (!m_frame) return 0; Document* doc = m_frame->document(); - - if (!pseudoElt.isEmpty()) - return doc->styleSelector()->pseudoStyleRulesForElement(elt, pseudoElt, authorOnly); return doc->styleSelector()->styleRulesForElement(elt, authorOnly); } @@ -1125,20 +1197,16 @@ double DOMWindow::devicePixelRatio() const } #if ENABLE(DATABASE) -PassRefPtr<Database> DOMWindow::openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode& ec) +PassRefPtr<Database> DOMWindow::openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, ExceptionCode& ec) { - if (!m_frame) - return 0; + RefPtr<Database> database = 0; + if (m_frame && Database::isAvailable() && m_frame->document()->securityOrigin()->canAccessDatabase()) + database = Database::openDatabase(m_frame->document(), name, version, displayName, estimatedSize, creationCallback, ec); - Document* document = m_frame->document(); - if (!document->securityOrigin()->canAccessDatabase()) - return 0; + if (!database && !ec) + ec = SECURITY_ERR; - Settings* settings = m_frame->settings(); - if (!settings || !settings->databasesEnabled()) - return 0; - - return Database::openDatabase(document, name, version, displayName, estimatedSize, ec); + return database; } #endif @@ -1359,20 +1427,21 @@ bool DOMWindow::dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget event->setEventPhase(Event::AT_TARGET); #if ENABLE(INSPECTOR) - InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent(); - bool timelineAgentIsActive = timelineAgent && hasEventListeners(event->type()); - if (timelineAgentIsActive) - timelineAgent->willDispatchEvent(*event); + Page* inspectedPage = InspectorTimelineAgent::instanceCount() && frame() ? frame()->page() : 0; + if (inspectedPage) { + if (InspectorTimelineAgent* timelineAgent = hasEventListeners(event->type()) ? inspectedPage->inspectorTimelineAgent() : 0) + timelineAgent->willDispatchEvent(*event); + else + inspectedPage = 0; + } #endif bool result = fireEventListeners(event.get()); #if ENABLE(INSPECTOR) - if (timelineAgentIsActive) { - timelineAgent = inspectorTimelineAgent(); - if (timelineAgent) + if (inspectedPage) + if (InspectorTimelineAgent* timelineAgent = inspectedPage->inspectorTimelineAgent()) timelineAgent->didDispatchEvent(); - } #endif return result; diff --git a/WebCore/page/DOMWindow.h b/WebCore/page/DOMWindow.h index 4452dbb..c3a781c 100644 --- a/WebCore/page/DOMWindow.h +++ b/WebCore/page/DOMWindow.h @@ -45,6 +45,7 @@ namespace WebCore { class Console; class DOMSelection; class Database; + class DatabaseCallback; class Document; class Element; class Event; @@ -139,6 +140,8 @@ namespace WebCore { void alert(const String& message); bool confirm(const String& message); String prompt(const String& message, const String& defaultValue); + String btoa(const String& stringToEncode, ExceptionCode&); + String atob(const String& encodedString, ExceptionCode&); bool find(const String&, bool caseSensitive, bool backwards, bool wrap, bool wholeWord, bool searchInFrames, bool showDialog) const; @@ -198,13 +201,13 @@ namespace WebCore { #if ENABLE(DATABASE) // HTML 5 client-side database - PassRefPtr<Database> openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode&); + PassRefPtr<Database> openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, ExceptionCode&); #endif #if ENABLE(DOM_STORAGE) // HTML 5 key/value storage Storage* sessionStorage() const; - Storage* localStorage() const; + Storage* localStorage(ExceptionCode&) const; #endif Console* console() const; @@ -398,6 +401,9 @@ namespace WebCore { #if ENABLE(NOTIFICATIONS) mutable RefPtr<NotificationCenter> m_notifications; #endif +#if ENABLE(INDEXED_DATABASE) + mutable RefPtr<IndexedDatabaseRequest> m_indexedDatabaseRequest; +#endif EventTargetData m_eventTargetData; }; diff --git a/WebCore/page/DOMWindow.idl b/WebCore/page/DOMWindow.idl index a4b72d2..018b4de 100644 --- a/WebCore/page/DOMWindow.idl +++ b/WebCore/page/DOMWindow.idl @@ -160,12 +160,13 @@ module window { readonly attribute [EnabledAtRuntime] DOMApplicationCache applicationCache; #endif #if defined(ENABLE_DATABASE) && ENABLE_DATABASE - [EnabledAtRuntime] Database openDatabase(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize) + [EnabledAtRuntime, Custom] Database openDatabase(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize, in DatabaseCallback creationCallback) raises(DOMException); #endif #if defined(ENABLE_DOM_STORAGE) && ENABLE_DOM_STORAGE readonly attribute [EnabledAtRuntime] Storage sessionStorage; - readonly attribute [EnabledAtRuntime] Storage localStorage; + readonly attribute [EnabledAtRuntime] Storage localStorage + getter raises(DOMException); #endif #if defined(ENABLE_NOTIFICATIONS) && ENABLE_NOTIFICATIONS readonly attribute [EnabledAtRuntime] NotificationCenter webkitNotifications; @@ -204,9 +205,9 @@ module window { void clearInterval(in long handle); // Base64 - [Custom] DOMString atob(in DOMString string) + DOMString atob(in [ConvertNullToNullString] DOMString string) raises(DOMException); - [Custom] DOMString btoa(in DOMString string) + DOMString btoa(in [ConvertNullToNullString] DOMString string) raises(DOMException); // Events @@ -293,12 +294,10 @@ module window { #if defined(ENABLE_ORIENTATION_EVENTS) && ENABLE_ORIENTATION_EVENTS attribute EventListener onorientationchange; #endif - #if defined(ENABLE_TOUCH_EVENTS) && ENABLE_TOUCH_EVENTS - attribute [DontEnum] EventListener ontouchstart; - attribute [DontEnum] EventListener ontouchmove; - attribute [DontEnum] EventListener ontouchend; - attribute [DontEnum] EventListener ontouchcancel; - #endif + attribute [DontEnum,Conditional=TOUCH_EVENTS] EventListener ontouchstart; + attribute [DontEnum,Conditional=TOUCH_EVENTS] EventListener ontouchmove; + attribute [DontEnum,Conditional=TOUCH_EVENTS] EventListener ontouchend; + attribute [DontEnum,Conditional=TOUCH_EVENTS] EventListener ontouchcancel; // EventTarget interface [Custom] void addEventListener(in DOMString type, @@ -421,6 +420,9 @@ module window { attribute HTMLParagraphElementConstructor HTMLParagraphElement; attribute HTMLParamElementConstructor HTMLParamElement; attribute HTMLPreElementConstructor HTMLPreElement; +#if defined(ENABLE_PROGRESS_TAG) && ENABLE_PROGRESS_TAG + attribute HTMLProgressElementConstructor HTMLProgressElement; +#endif attribute HTMLQuoteElementConstructor HTMLQuoteElement; attribute HTMLScriptElementConstructor HTMLScriptElement; attribute HTMLSelectElementConstructor HTMLSelectElement; @@ -443,17 +445,17 @@ module window { attribute CanvasRenderingContext2DConstructor CanvasRenderingContext2D; attribute ImageDataConstructor ImageData; - attribute [Conditional=3D_CANVAS] WebGLRenderingContextConstructor WebGLRenderingContext; + attribute [Conditional=3D_CANVAS,EnabledAtRuntime] 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 [JSCCustomGetter,Conditional=3D_CANVAS,EnabledAtRuntime] WebGLArrayBufferConstructor WebGLArrayBuffer; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS,EnabledAtRuntime] WebGLByteArrayConstructor WebGLByteArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS,EnabledAtRuntime] WebGLUnsignedByteArrayConstructor WebGLUnsignedByteArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS,EnabledAtRuntime] WebGLShortArrayConstructor WebGLShortArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS,EnabledAtRuntime] WebGLUnsignedShortArrayConstructor WebGLUnsignedShortArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS,EnabledAtRuntime] WebGLIntArrayConstructor WebGLIntArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS,EnabledAtRuntime] WebGLUnsignedIntArrayConstructor WebGLUnsignedIntArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS,EnabledAtRuntime] WebGLFloatArrayConstructor WebGLFloatArray; // Usable with new operator attribute EventConstructor Event; attribute BeforeLoadEventConstructor BeforeLoadEvent; @@ -709,9 +711,9 @@ module window { #endif #endif -#if defined(ENABLE_TOUCH_EVENTS) && ENABLE_TOUCH_EVENTS - attribute TouchEventConstructor TouchEvent; -#endif + attribute [Conditional=TOUCH_EVENTS] TouchEventConstructor TouchEvent; + + attribute DOMFormDataConstructor FormData; #endif // defined(LANGUAGE_JAVASCRIPT) diff --git a/WebCore/page/DragController.cpp b/WebCore/page/DragController.cpp index 18e3195..f238b27 100644 --- a/WebCore/page/DragController.cpp +++ b/WebCore/page/DragController.cpp @@ -53,6 +53,7 @@ #include "MoveSelectionCommand.h" #include "Node.h" #include "Page.h" +#include "PlatformKeyboardEvent.h" #include "RenderFileUploadControl.h" #include "RenderImage.h" #include "RenderView.h" @@ -70,10 +71,12 @@ namespace WebCore { static PlatformMouseEvent createMouseEvent(DragData* dragData) { - // FIXME: We should fake modifier keys here. + bool shiftKey, ctrlKey, altKey, metaKey; + shiftKey = ctrlKey = altKey = metaKey = false; + PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey); return PlatformMouseEvent(dragData->clientPosition(), dragData->globalPosition(), - LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime()); - + LeftButton, MouseEventMoved, 0, shiftKey, ctrlKey, altKey, + metaKey, currentTime()); } DragController::DragController(Page* page, DragClient* client) @@ -429,10 +432,11 @@ bool DragController::concludeEditDrag(DragData* dragData) m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); if (dragIsMove(innerFrame->selection())) { - bool smartMove = innerFrame->selectionGranularity() == WordGranularity - && innerFrame->editor()->smartInsertDeleteEnabled() - && dragData->canSmartReplace(); - applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartMove)); + // NSTextView behavior is to always smart delete on moving a selection, + // but only to smart insert if the selection granularity is word granularity. + bool smartDelete = innerFrame->editor()->smartInsertDeleteEnabled(); + bool smartInsert = smartDelete && innerFrame->selectionGranularity() == WordGranularity && dragData->canSmartReplace(); + applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartInsert, smartDelete)); } else { if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse, fragment, true, dragData->canSmartReplace(), chosePlainText)); @@ -482,6 +486,25 @@ bool DragController::canProcessDrag(DragData* dragData) return true; } +static DragOperation defaultOperationForDrag(DragOperation srcOpMask) +{ + // This is designed to match IE's operation fallback for the case where + // the page calls preventDefault() in a drag event but doesn't set dropEffect. + if (srcOpMask == DragOperationEvery) + return DragOperationCopy; + if (srcOpMask == DragOperationNone) + return DragOperationNone; + if (srcOpMask & DragOperationMove || srcOpMask & DragOperationGeneric) + return DragOperationMove; + if (srcOpMask & DragOperationCopy) + return DragOperationCopy; + if (srcOpMask & DragOperationLink) + return DragOperationLink; + + // FIXME: Does IE really return "generic" even if no operations were allowed by the source? + return DragOperationGeneric; +} + bool DragController::tryDHTMLDrag(DragData* dragData, DragOperation& operation) { ASSERT(dragData); @@ -503,7 +526,9 @@ bool DragController::tryDHTMLDrag(DragData* dragData, DragOperation& operation) } operation = clipboard->destinationOperation(); - if (!(srcOpMask & operation)) { + if (clipboard->dropEffectIsUninitialized()) + operation = defaultOperationForDrag(srcOpMask); + else if (!(srcOpMask & operation)) { // The element picked an operation which is not supported by the source operation = DragOperationNone; } @@ -512,7 +537,7 @@ bool DragController::tryDHTMLDrag(DragData* dragData, DragOperation& operation) return true; } -bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPoint& framePos) +bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPoint& framePos, Node* node) { ASSERT(frame); ASSERT(frame->settings()); @@ -523,6 +548,8 @@ bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPo HitTestResult mouseDownTarget = HitTestResult(framePos); mouseDownTarget = frame->eventHandler()->hitTestResultAtPoint(framePos, true); + if (node) + mouseDownTarget.setInnerNonSharedNode(node); if (mouseDownTarget.image() && !mouseDownTarget.absoluteImageURL().isEmpty() @@ -532,7 +559,8 @@ bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPo if (!mouseDownTarget.absoluteLinkURL().isEmpty() && m_dragSourceAction & DragSourceActionLink - && mouseDownTarget.isLiveLink()) + && mouseDownTarget.isLiveLink() + && mouseDownTarget.URLElement()->renderer() && mouseDownTarget.URLElement()->renderer()->style()->userDrag() != DRAG_NONE) return true; if (mouseDownTarget.isSelected() @@ -540,7 +568,6 @@ bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPo return true; return false; - } static CachedImage* getCachedImage(Element* element) diff --git a/WebCore/page/DragController.h b/WebCore/page/DragController.h index 3d59ebf..3b2b083 100644 --- a/WebCore/page/DragController.h +++ b/WebCore/page/DragController.h @@ -77,7 +77,7 @@ namespace WebCore { DragDestinationAction dragDestinationAction() const { return m_dragDestinationAction; } DragSourceAction delegateDragSourceAction(const IntPoint& pagePoint); - bool mayStartDragAtEventLocation(const Frame*, const IntPoint& framePos); + bool mayStartDragAtEventLocation(const Frame*, const IntPoint& framePos, Node*); void dragEnded(); void placeDragCaret(const IntPoint&); diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp index a950407..df8759a 100644 --- a/WebCore/page/EventHandler.cpp +++ b/WebCore/page/EventHandler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) * * Redistribution and use in source and binary forms, with or without @@ -57,7 +57,11 @@ #include "Page.h" #include "PlatformKeyboardEvent.h" #include "PlatformWheelEvent.h" +<<<<<<< HEAD #include "PluginView.h" +======= +#include "PluginDocument.h" +>>>>>>> webkit.org at r58033 #include "RenderFrameSet.h" #include "RenderTextControlSingleLine.h" #include "RenderView.h" @@ -66,7 +70,10 @@ #include "SelectionController.h" #include "Settings.h" #include "TextEvent.h" +#include "UserGestureIndicator.h" +#include "WheelEvent.h" #include "htmlediting.h" // for comparePositions() +#include <wtf/CurrentTime.h> #include <wtf/StdLibExtras.h> #if ENABLE(SVG) @@ -110,25 +117,33 @@ 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; +const double fakeMouseMoveInterval = 0.1; + static Frame* subframeForHitTestResult(const MouseEventWithHitTestResults&); -static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDirection, ScrollDirection negativeDirection, PlatformWheelEvent& e, Node* node, Node** stopNode) +static inline bool scrollNode(float delta, WheelEvent::Granularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode) { if (!delta) - return; - + return false; + + if (!node->renderer()) + return false; + // Find the nearest enclosing box. RenderBox* enclosingBox = node->renderer()->enclosingBox(); - if (e.granularity() == ScrollByPageWheelEvent) { - if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, 1, stopNode)) - e.accept(); - return; - } + float absDelta = delta > 0 ? delta : -delta; + + if (granularity == WheelEvent::Page) + return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, absDelta, stopNode); + + if (granularity == WheelEvent::Line) + return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByLine, absDelta, stopNode); - float pixelsToScroll = delta > 0 ? delta : -delta; - if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll, stopNode)) - e.accept(); + if (granularity == WheelEvent::Pixel) + return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, absDelta, stopNode); + + return false; } #if !PLATFORM(MAC) || ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) @@ -166,6 +181,7 @@ EventHandler::EventHandler(Frame* frame) , m_autoscrollInProgress(false) , m_mouseDownMayStartAutoscroll(false) , m_mouseDownWasInSubframe(false) + , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired) #if ENABLE(SVG) , m_svgPan(false) #endif @@ -185,6 +201,7 @@ EventHandler::EventHandler(Frame* frame) EventHandler::~EventHandler() { + ASSERT(!m_fakeMouseMoveEventTimer.isActive()); } #if ENABLE(DRAG_SUPPORT) @@ -198,6 +215,7 @@ EventHandler::EventHandlerDragState& EventHandler::dragState() void EventHandler::clear() { m_hoverTimer.stop(); + m_fakeMouseMoveEventTimer.stop(); m_resizeLayer = 0; m_nodeUnderMouse = 0; m_lastNodeUnderMouse = 0; @@ -233,20 +251,21 @@ void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestRe if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) { VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint())); + TextGranularity granularity = CharacterGranularity; if (pos.isNotNull()) { newSelection = VisibleSelection(pos); newSelection.expandUsingGranularity(WordGranularity); } if (newSelection.isRange()) { - m_frame->setSelectionGranularity(WordGranularity); + granularity = WordGranularity; m_beganSelectingText = true; if (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled()) newSelection.appendTrailingWhitespace(); } if (m_frame->shouldChangeSelection(newSelection)) - m_frame->selection()->setSelection(newSelection); + m_frame->selection()->setSelection(newSelection, granularity); } } @@ -264,13 +283,14 @@ void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHit if (pos.isNotNull() && pos.deepEquivalent().node()->isDescendantOf(URLElement)) newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement); + TextGranularity granularity = CharacterGranularity; if (newSelection.isRange()) { - m_frame->setSelectionGranularity(WordGranularity); + granularity = WordGranularity; m_beganSelectingText = true; } if (m_frame->shouldChangeSelection(newSelection)) - m_frame->selection()->setSelection(newSelection); + m_frame->selection()->setSelection(newSelection, granularity); } } @@ -307,13 +327,15 @@ bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestR newSelection = VisibleSelection(pos); newSelection.expandUsingGranularity(ParagraphGranularity); } + + TextGranularity granularity = CharacterGranularity; if (newSelection.isRange()) { - m_frame->setSelectionGranularity(ParagraphGranularity); + granularity = ParagraphGranularity; m_beganSelectingText = true; } if (m_frame->shouldChangeSelection(newSelection)) - m_frame->selection()->setSelection(newSelection); + m_frame->selection()->setSelection(newSelection, granularity); return true; } @@ -343,8 +365,10 @@ bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR Position pos = visiblePos.deepEquivalent(); VisibleSelection newSelection = m_frame->selection()->selection(); + TextGranularity granularity = CharacterGranularity; + if (extendSelection && newSelection.isCaretOrRange()) { - m_frame->selection()->setLastChangeWasHorizontalExtension(false); + m_frame->selection()->setIsDirectional(false); // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection // was created right-to-left @@ -355,16 +379,17 @@ bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR else newSelection = VisibleSelection(start, pos); - if (m_frame->selectionGranularity() != CharacterGranularity) + if (m_frame->selectionGranularity() != CharacterGranularity) { + granularity = m_frame->selectionGranularity(); newSelection.expandUsingGranularity(m_frame->selectionGranularity()); + } + m_beganSelectingText = true; - } else { + } else newSelection = VisibleSelection(visiblePos); - m_frame->setSelectionGranularity(CharacterGranularity); - } if (m_frame->shouldChangeSelection(newSelection)) - m_frame->selection()->setSelection(newSelection); + m_frame->selection()->setSelection(newSelection, granularity); return true; } @@ -376,6 +401,8 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve dragState().m_dragSrc = 0; #endif + cancelFakeMouseMoveEvent(); + if (ScrollView* scrollView = m_frame->view()) { if (scrollView->isPointInScrollbarCorner(event.event().pos())) return false; @@ -576,8 +603,8 @@ void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint& newSelection.expandUsingGranularity(m_frame->selectionGranularity()); if (m_frame->shouldChangeSelection(newSelection)) { - m_frame->selection()->setLastChangeWasHorizontalExtension(false); - m_frame->selection()->setSelection(newSelection); + m_frame->selection()->setIsDirectional(false); + m_frame->selection()->setSelection(newSelection, m_frame->selectionGranularity()); } } #endif // ENABLE(DRAG_SUPPORT) @@ -1005,8 +1032,8 @@ Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scr if (style && style->cursors()) { const CursorList* cursors = style->cursors(); for (unsigned i = 0; i < cursors->size(); ++i) { - CachedImage* cimage = (*cursors)[i].cursorImage.get(); - IntPoint hotSpot = (*cursors)[i].hotSpot; + const CachedImage* cimage = (*cursors)[i].image(); + IntPoint hotSpot = (*cursors)[i].hotSpot(); if (!cimage) continue; // Limit the size of cursors so that they cannot be used to cover UI elements in chrome. @@ -1151,6 +1178,9 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) { RefPtr<FrameView> protector(m_frame->view()); + UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); + + cancelFakeMouseMoveEvent(); m_mousePressed = true; m_capturesDragging = true; m_currentMousePosition = mouseEvent.pos(); @@ -1185,7 +1215,7 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) if (Page* page = m_frame->page()) { InspectorController* inspector = page->inspectorController(); if (inspector && inspector->enabled() && inspector->searchingForNodeInPage()) { - inspector->handleMousePressOnNode(m_mousePressNode.get()); + inspector->handleMousePress(); invalidateClick(); return true; } @@ -1279,6 +1309,8 @@ bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEv { RefPtr<FrameView> protector(m_frame->view()); + UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); + // We get this instead of a second mouse-up m_mousePressed = false; m_currentMousePosition = mouseEvent.pos(); @@ -1342,6 +1374,8 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi if (m_hoverTimer.isActive()) m_hoverTimer.stop(); + cancelFakeMouseMoveEvent(); + #if ENABLE(SVG) if (m_svgPan) { static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition); @@ -1404,8 +1438,18 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering. if (Page* page = m_frame->page()) { if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !page->mainFrame()->eventHandler()->panScrollInProgress()) { - if (FrameView* view = m_frame->view()) - view->setCursor(selectCursor(mev, scrollbar)); + // Plugins set cursor on their own. The only case WebKit intervenes is resetting cursor to arrow on mouse enter, + // in case the particular plugin doesn't manipulate cursor at all. Thus, even a CSS cursor set on body has no + // effect on plugins (which matches Firefox). + bool overPluginElement = false; + if (mev.targetNode() && mev.targetNode()->isHTMLElement()) { + HTMLElement* el = static_cast<HTMLElement*>(mev.targetNode()); + overPluginElement = el->hasTagName(appletTag) || el->hasTagName(objectTag) || el->hasTagName(embedTag); + } + if (!overPluginElement) { + if (FrameView* view = m_frame->view()) + view->setCursor(selectCursor(mev, scrollbar)); + } } } } @@ -1433,6 +1477,8 @@ void EventHandler::invalidateClick() bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) { RefPtr<FrameView> protector(m_frame->view()); + + UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); #if ENABLE(PAN_SCROLLING) if (mouseEvent.button() == MiddleButton) @@ -1863,21 +1909,6 @@ 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). - 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; - } } if (e.isAccepted()) @@ -1890,6 +1921,25 @@ bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) view->wheelEvent(e); return e.isAccepted(); } + +void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent) +{ + if (!startNode || !wheelEvent) + return; + + Node* stopNode = m_previousWheelScrolledNode.get(); + + // 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). + if (scrollNode(wheelEvent->rawDeltaX(), wheelEvent->granularity(), ScrollLeft, ScrollRight, startNode, &stopNode)) + wheelEvent->setDefaultHandled(); + + if (scrollNode(wheelEvent->rawDeltaY(), wheelEvent->granularity(), ScrollUp, ScrollDown, startNode, &stopNode)) + wheelEvent->setDefaultHandled(); + + if (!m_useLatchedWheelEventNode) + m_previousWheelScrolledNode = stopNode; +} #if ENABLE(CONTEXT_MENUS) bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) @@ -1930,6 +1980,43 @@ void EventHandler::scheduleHoverStateUpdate() m_hoverTimer.startOneShot(0); } +void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad) +{ + FrameView* view = m_frame->view(); + if (!view) + return; + + if (m_mousePressed || !quad.containsPoint(view->windowToContents(m_currentMousePosition))) + return; + + if (!m_fakeMouseMoveEventTimer.isActive()) + m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveInterval); +} + +void EventHandler::cancelFakeMouseMoveEvent() +{ + m_fakeMouseMoveEventTimer.stop(); +} + +void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer) +{ + ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer); + ASSERT(!m_mousePressed); + + FrameView* view = m_frame->view(); + if (!view) + return; + + bool shiftKey; + bool ctrlKey; + bool altKey; + bool metaKey; + PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey); + IntPoint globalPoint = view->contentsToScreen(IntRect(view->windowToContents(m_currentMousePosition), IntSize())).location(); + PlatformMouseEvent fakeMouseMoveEvent(m_currentMousePosition, globalPoint, NoButton, MouseEventMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime()); + mouseMoved(fakeMouseMoveEvent); +} + // Whether or not a mouse down can begin the creation of a selection. Fires the selectStart event. bool EventHandler::canMouseDownStartSelect(Node* node) { @@ -1996,6 +2083,7 @@ static Node* eventTargetNodeForDocument(Document* doc) if (!doc) return 0; Node* node = doc->focusedNode(); +<<<<<<< HEAD #if defined(ANDROID_PLUGINS) if (!node && doc->frame() && doc->frame()->view()) @@ -2003,6 +2091,12 @@ static Node* eventTargetNodeForDocument(Document* doc) ->cursorNodeIsPlugin(); #endif +======= + if (!node && doc->isPluginDocument()) { + PluginDocument* pluginDocument = static_cast<PluginDocument*>(doc); + node = pluginDocument->pluginNode(); + } +>>>>>>> webkit.org at r58033 if (!node && doc->isHTMLDocument()) node = doc->body(); if (!node) @@ -2055,6 +2149,8 @@ bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) if (!node) return false; + UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); + if (FrameView* view = m_frame->view()) view->resetDeferredRepaintDelay(); @@ -2171,10 +2267,15 @@ void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event) return; if (event->keyIdentifier() == "U+0009") defaultTabEventHandler(event); + else { + FocusDirection direction = focusDirectionForKey(event->keyIdentifier()); + if (direction != FocusDirectionNone) + defaultArrowEventHandler(direction, event); + } - // provides KB navigation and selection for enhanced accessibility users - if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled()) - handleKeyboardSelectionMovement(event); + // provides KB navigation and selection for enhanced accessibility users + if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled()) + handleKeyboardSelectionMovement(event); } if (event->type() == eventNames().keypressEvent) { m_frame->editor()->handleKeyboardEvent(event); @@ -2185,6 +2286,27 @@ void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event) } } +FocusDirection EventHandler::focusDirectionForKey(const AtomicString& keyIdentifier) const +{ + DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down")); + DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up")); + DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left")); + DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right")); + + FocusDirection retVal = FocusDirectionNone; + + if (keyIdentifier == Down) + retVal = FocusDirectionDown; + else if (keyIdentifier == Up) + retVal = FocusDirectionUp; + else if (keyIdentifier == Left) + retVal = FocusDirectionLeft; + else if (keyIdentifier == Right) + retVal = FocusDirectionRight; + + return retVal; +} + #if ENABLE(DRAG_SUPPORT) bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const { @@ -2222,7 +2344,7 @@ bool EventHandler::shouldDragAutoNode(Node* node, const IntPoint& point) const if (!node || !m_frame->view()) return false; Page* page = m_frame->page(); - return page && page->dragController()->mayStartDragAtEventLocation(m_frame, point); + return page && page->dragController()->mayStartDragAtEventLocation(m_frame, point, node); } void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation) @@ -2332,7 +2454,7 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event) // FIXME: This doesn't work correctly with transforms. FloatPoint absPos = renderer->localToAbsolute(); IntSize delta = m_mouseDownPos - roundedIntPoint(absPos); - dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), IntPoint() + delta); + dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), toPoint(delta)); } else { // The renderer has disappeared, this can happen if the onStartDrag handler has hidden // the element in some way. In this case we just kill the drag. @@ -2412,8 +2534,7 @@ bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEve return event->defaultHandled(); } - -#if !PLATFORM(MAC) && !PLATFORM(QT) && !PLATFORM(HAIKU) +#if !PLATFORM(MAC) && !PLATFORM(QT) && !PLATFORM(HAIKU) && !PLATFORM(EFL) bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent*) const { return false; @@ -2479,6 +2600,27 @@ void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event) #endif +void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event) +{ + if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey()) + return; + + Page* page = m_frame->page(); + if (!page) + return; + + if (!page->settings() || !page->settings()->isSpatialNavigationEnabled()) + return; + + // Arrows and other possible directional navigation keys can be used in design + // mode editing. + if (m_frame->document()->inDesignMode()) + return; + + if (page->focusController()->advanceFocus(focusDirection, event)) + event->setDefaultHandled(); +} + void EventHandler::defaultTabEventHandler(KeyboardEvent* event) { // We should only advance focus on tabs if no special modifier keys are held down. @@ -2576,6 +2718,11 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) const Vector<PlatformTouchPoint>& points = event.touchPoints(); AtomicString* eventName = 0; +<<<<<<< HEAD +======= + UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); + +>>>>>>> webkit.org at r58033 for (unsigned i = 0; i < points.size(); ++i) { const PlatformTouchPoint& point = points[i]; IntPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos()); @@ -2602,13 +2749,18 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap. unsigned touchPointTargetKey = point.id() + 1; +<<<<<<< HEAD RefPtr<EventTarget> touchTarget; +======= + EventTarget* touchTarget = 0; +>>>>>>> webkit.org at r58033 if (point.state() == PlatformTouchPoint::TouchPressed) { m_originatingTouchPointTargets.set(touchPointTargetKey, target); touchTarget = target; } else if (point.state() == PlatformTouchPoint::TouchReleased || point.state() == PlatformTouchPoint::TouchCancelled) { // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel // we also remove it from the map. +<<<<<<< HEAD touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey); } else touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey); @@ -2617,6 +2769,16 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) continue; RefPtr<Touch> touch = Touch::create(doc->frame(), touchTarget.get(), point.id(), +======= + touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey).get(); + } else + touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey).get(); + + if (!touchTarget) + continue; + + RefPtr<Touch> touch = Touch::create(doc->frame(), touchTarget, point.id(), +>>>>>>> webkit.org at r58033 point.screenPos().x(), point.screenPos().y(), adjustedPageX, adjustedPageY); @@ -2625,6 +2787,7 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) touches->append(touch); // Now build up the correct list for changedTouches. +<<<<<<< HEAD // Note that any touches that are in the TouchStationary state (e.g. if // the user had several points touched but did not move them all) should // only be present in the touches list. They may also be added to the @@ -2632,6 +2795,8 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) // list so we do not handle them explicitly here. // See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion // about the TouchStationary state. +======= +>>>>>>> webkit.org at r58033 if (point.state() == PlatformTouchPoint::TouchReleased) releasedTouches->append(touch); else if (point.state() == PlatformTouchPoint::TouchCancelled) @@ -2694,6 +2859,7 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) RefPtr<TouchList> targetTouches = assembleTargetTouches(changedTouch, touches.get()); +<<<<<<< HEAD #if PLATFORM(ANDROID) if (event.type() == TouchLongPress) { eventName = &eventNames().touchlongpressEvent; @@ -2717,6 +2883,8 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) defaultPrevented |= doubleTapEv->defaultPrevented(); } else { #endif +======= +>>>>>>> webkit.org at r58033 eventName = &eventNames().touchstartEvent; RefPtr<TouchEvent> startEv = TouchEvent::create(touches.get(), targetTouches.get(), pressedTouches.get(), diff --git a/WebCore/page/EventHandler.h b/WebCore/page/EventHandler.h index a268adb..282100d 100644 --- a/WebCore/page/EventHandler.h +++ b/WebCore/page/EventHandler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,6 +27,7 @@ #define EventHandler_h #include "DragActions.h" +#include "FocusDirection.h" #include "PlatformMouseEvent.h" #include "ScrollTypes.h" #include "Timer.h" @@ -49,6 +50,7 @@ class Cursor; class Event; class EventTarget; class FloatPoint; +class FloatQuad; class Frame; class HitTestRequest; class HitTestResult; @@ -67,6 +69,7 @@ class String; class SVGElementInstance; class TextEvent; class TouchEvent; +class WheelEvent; class Widget; #if ENABLE(DRAG_SUPPORT) @@ -100,6 +103,8 @@ public: RenderObject* autoscrollRenderer() const; void updateAutoscrollRenderer(); + void dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad&); + HitTestResult hitTestResultAtPoint(const IntPoint&, bool allowShadowContent, bool ignoreClipping = false, HitTestScrollbars scrollbars = DontHitTestScrollbars); bool mousePressed() const { return m_mousePressed; } @@ -146,6 +151,7 @@ public: bool handleMouseMoveEvent(const PlatformMouseEvent&, HitTestResult* hoveredNode = 0); bool handleMouseReleaseEvent(const PlatformMouseEvent&); bool handleWheelEvent(PlatformWheelEvent&); + void defaultWheelEventHandler(Node*, WheelEvent*); #if ENABLE(CONTEXT_MENUS) bool sendContextMenuEvent(const PlatformMouseEvent&); @@ -263,6 +269,9 @@ private: void setAutoscrollRenderer(RenderObject*); void autoscrollTimerFired(Timer<EventHandler>*); + void fakeMouseMoveEventTimerFired(Timer<EventHandler>*); + void cancelFakeMouseMoveEvent(); + void invalidateClick(); Node* nodeUnderMouse() const; @@ -306,6 +315,7 @@ private: void defaultSpaceEventHandler(KeyboardEvent*); void defaultTabEventHandler(KeyboardEvent*); + void defaultArrowEventHandler(FocusDirection, KeyboardEvent*); #if ENABLE(DRAG_SUPPORT) void allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const; @@ -328,6 +338,8 @@ private: void setFrameWasScrolledByUser(); + FocusDirection focusDirectionForKey(const AtomicString&) const; + bool capturesDragging() const { return m_capturesDragging; } #if PLATFORM(MAC) && defined(__OBJC__) && !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE) @@ -367,6 +379,8 @@ private: bool m_mouseDownMayStartAutoscroll; bool m_mouseDownWasInSubframe; + Timer<EventHandler> m_fakeMouseMoveEventTimer; + #if ENABLE(SVG) bool m_svgPan; RefPtr<SVGElementInstance> m_instanceUnderMouse; diff --git a/WebCore/page/EventSource.cpp b/WebCore/page/EventSource.cpp index 0c79998..9ccccd7 100644 --- a/WebCore/page/EventSource.cpp +++ b/WebCore/page/EventSource.cpp @@ -250,8 +250,10 @@ void EventSource::parseEventStream() void EventSource::parseEventStreamLine(unsigned int bufPos, int fieldLength, int lineLength) { if (!lineLength) { - if (!m_data.isEmpty()) + if (!m_data.isEmpty()) { + m_data.removeLast(); dispatchEvent(createMessageEvent()); + } if (!m_eventName.isEmpty()) m_eventName = ""; } else if (fieldLength) { @@ -269,10 +271,9 @@ void EventSource::parseEventStreamLine(unsigned int bufPos, int fieldLength, int 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); + m_data.append('\n'); } else if (field == "event") m_eventName = valueLength ? String(&m_receiveBuf[bufPos], valueLength) : ""; else if (field == "id") diff --git a/WebCore/page/EventSource.idl b/WebCore/page/EventSource.idl index ec42556..57bd807 100644 --- a/WebCore/page/EventSource.idl +++ b/WebCore/page/EventSource.idl @@ -53,12 +53,12 @@ module window { void close(); // EventTarget interface - [Custom] void addEventListener(in DOMString type, - in EventListener listener, - in boolean useCapture); - [Custom] void removeEventListener(in DOMString type, + [JSCCustom] void addEventListener(in DOMString type, in EventListener listener, in boolean useCapture); + [JSCCustom] 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 bdd3151..e07e2ea 100644 --- a/WebCore/page/FocusController.cpp +++ b/WebCore/page/FocusController.cpp @@ -49,18 +49,26 @@ #include "RenderWidget.h" #include "SelectionController.h" #include "Settings.h" +#include "SpatialNavigation.h" #include "Widget.h" -#include <wtf/Platform.h> namespace WebCore { using namespace HTMLNames; +using namespace std; 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 + + // Do not fire events while modal dialogs are up. See https://bugs.webkit.org/show_bug.cgi?id=33962 + if (Page* page = document->page()) { + if (page->defersLoading()) + return; + } + if (!focused && document->focusedNode()) document->focusedNode()->dispatchBlurEvent(); document->dispatchWindowEvent(Event::create(focused ? eventNames().focusEvent : eventNames().blurEvent, false, false)); @@ -153,6 +161,24 @@ bool FocusController::setInitialFocus(FocusDirection direction, KeyboardEvent* e bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* event, bool initialFocus) { + switch (direction) { + case FocusDirectionForward: + case FocusDirectionBackward: + return advanceFocusInDocumentOrder(direction, event, initialFocus); + case FocusDirectionLeft: + case FocusDirectionRight: + case FocusDirectionUp: + case FocusDirectionDown: + return advanceFocusDirectionally(direction, event); + default: + ASSERT_NOT_REACHED(); + } + + return false; +} + +bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, KeyboardEvent* event, bool initialFocus) +{ Frame* frame = focusedOrMainFrame(); ASSERT(frame); Document* document = frame->document(); @@ -257,6 +283,175 @@ bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* even return true; } +bool FocusController::advanceFocusDirectionally(FocusDirection direction, KeyboardEvent* event) +{ + Frame* frame = focusedOrMainFrame(); + ASSERT(frame); + Document* focusedDocument = frame->document(); + if (!focusedDocument) + return false; + + Node* focusedNode = focusedDocument->focusedNode(); + if (!focusedNode) { + // Just move to the first focusable node. + FocusDirection tabDirection = (direction == FocusDirectionUp || direction == FocusDirectionLeft) ? + FocusDirectionForward : FocusDirectionBackward; + // 'initialFocus' is set to true so the chrome is not focused. + return advanceFocusInDocumentOrder(tabDirection, event, true); + } + + // Move up in the chain of nested frames. + frame = frame->tree()->top(); + + FocusCandidate focusCandidate; + findFocusableNodeInDirection(frame->document(), focusedNode, direction, event, focusCandidate); + + Node* node = focusCandidate.node; + if (!node || !node->isElementNode()) { + // FIXME: May need a way to focus a document here. + Frame* frame = focusedOrMainFrame(); + scrollInDirection(frame, direction); + return false; + } + + // In order to avoid crazy jump between links that are either far away from each other, + // or just not currently visible, lets do a scroll in the given direction and bail out + // if |node| element is not in the viewport. + if (hasOffscreenRect(node)) { + Frame* frame = node->document()->view()->frame(); + scrollInDirection(frame, direction); + return true; + } + + Document* newDocument = node->document(); + + if (newDocument != focusedDocument) { + // Focus is going away from the originally focused document, so clear the focused node. + focusedDocument->setFocusedNode(0); + } + + if (newDocument) + setFocusedFrame(newDocument->frame()); + + Element* element = static_cast<Element*>(node); + ASSERT(element); + + scrollIntoView(element); + element->focus(false); + return true; +} + +// FIXME: Make this method more modular, and simpler to understand and maintain. +static void updateFocusCandidateIfCloser(Node* focusedNode, const FocusCandidate& candidate, FocusCandidate& closest) +{ + bool sameDocument = candidate.document() == closest.document(); + if (sameDocument) { + if (closest.alignment > candidate.alignment + || (closest.parentAlignment && candidate.alignment > closest.parentAlignment)) + return; + } else if (closest.alignment > candidate.alignment + && (closest.parentAlignment && candidate.alignment > closest.parentAlignment)) + return; + + if (candidate.alignment != None + || (closest.parentAlignment >= candidate.alignment + && closest.document() == candidate.document())) { + + // If we are now in an higher precedent case, lets reset the current closest's + // distance so we force it to be bigger than any result we will get from + // spatialDistance(). + if (closest.alignment < candidate.alignment + && closest.parentAlignment < candidate.alignment) + closest.distance = maxDistance(); + } + + // Bail out if candidate's distance is larger than that of the closest candidate. + if (candidate.distance >= closest.distance) + return; + + if (closest.isNull()) { + closest = candidate; + return; + } + + // If the focused node and the candadate are in the same document and current + // closest candidate is not in an {i}frame that is preferable to get focused ... + if (focusedNode->document() == candidate.document() + && candidate.distance < closest.parentDistance) + closest = candidate; + else if (focusedNode->document() != candidate.document()) { + // If the focusedNode is in an inner document and candidate is in a + // different document, we only consider to change focus if there is not + // another already good focusable candidate in the same document as focusedNode. + if (!((isInRootDocument(candidate.node) && !isInRootDocument(focusedNode)) + && focusedNode->document() == closest.document())) + closest = candidate; + } +} + +void FocusController::findFocusableNodeInDirection(Document* document, Node* focusedNode, + FocusDirection direction, KeyboardEvent* event, + FocusCandidate& closestFocusCandidate, + const FocusCandidate& candidateParent) +{ + ASSERT(document); + ASSERT(candidateParent.isNull() || static_cast<HTMLFrameOwnerElement*>(candidateParent.node)); + + // Walk all the child nodes and update closestFocusCandidate if we find a nearer node. + for (Node* candidate = document->firstChild(); candidate; candidate = candidate->traverseNextNode()) { + // Inner documents case. + + if (candidate->isFrameOwnerElement()) + deepFindFocusableNodeInDirection(focusedNode, candidate, direction, event, closestFocusCandidate); + else if (candidate != focusedNode && candidate->isKeyboardFocusable(event)) { + FocusCandidate currentFocusCandidate(candidate); + + // Get distance and alignment from current candidate. + distanceDataForNode(direction, focusedNode, currentFocusCandidate); + + // Bail out if distance is maximum. + if (currentFocusCandidate.distance == maxDistance()) + continue; + + // If candidateParent is not null, it means that we are in a recursive call + // from deepFineFocusableNodeInDirection (i.e. processing an element in an iframe), + // and holds the distance and alignment data of the iframe element itself. + if (!candidateParent.isNull()) { + currentFocusCandidate.parentAlignment = candidateParent.alignment; + currentFocusCandidate.parentDistance = candidateParent.distance; + } + + updateFocusCandidateIfCloser(focusedNode, currentFocusCandidate, closestFocusCandidate); + } + } +} + +void FocusController::deepFindFocusableNodeInDirection(Node* focusedNode, Node* candidate, + FocusDirection direction, KeyboardEvent* event, + FocusCandidate& closestFocusCandidate) +{ + HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(candidate); + if (!owner->contentFrame()) + return; + + Document* innerDocument = owner->contentFrame()->document(); + if (!innerDocument) + return; + + if (innerDocument == focusedNode->document()) + findFocusableNodeInDirection(innerDocument, focusedNode, direction, event, closestFocusCandidate); + else { + // Check if the current {i}frame element itself is a good candidate + // to move focus to. If it is, then we traverse its inner nodes. + FocusCandidate candidateParent = FocusCandidate(candidate); + distanceDataForNode(direction, focusedNode, candidateParent); + + // FIXME: Consider alignment? + if (candidateParent.distance < closestFocusCandidate.distance) + findFocusableNodeInDirection(innerDocument, focusedNode, direction, event, closestFocusCandidate, candidateParent); + } +} + static bool relinquishesEditingFocus(Node *node) { ASSERT(node); diff --git a/WebCore/page/FocusController.h b/WebCore/page/FocusController.h index 32d4060..dfa3780 100644 --- a/WebCore/page/FocusController.h +++ b/WebCore/page/FocusController.h @@ -27,12 +27,14 @@ #define FocusController_h #include "FocusDirection.h" +#include "SpatialNavigation.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> #include <wtf/RefPtr.h> namespace WebCore { +class Document; class Frame; class KeyboardEvent; class Node; @@ -58,6 +60,13 @@ public: bool isFocused() const { return m_isFocused; } private: + bool advanceFocusDirectionally(FocusDirection, KeyboardEvent*); + bool advanceFocusInDocumentOrder(FocusDirection, KeyboardEvent*, bool initialFocus); + + void findFocusableNodeInDirection(Document*, Node*, FocusDirection, KeyboardEvent*, FocusCandidate& closestFocusCandidate, + const FocusCandidate& parentCandidate = FocusCandidate()); + void deepFindFocusableNodeInDirection(Node*, Node*, FocusDirection, KeyboardEvent*, FocusCandidate&); + Page* m_page; RefPtr<Frame> m_focusedFrame; bool m_isActive; diff --git a/WebCore/page/FocusDirection.h b/WebCore/page/FocusDirection.h index 261c745..8a6d51f 100644 --- a/WebCore/page/FocusDirection.h +++ b/WebCore/page/FocusDirection.h @@ -28,8 +28,13 @@ namespace WebCore { enum FocusDirection { - FocusDirectionForward = 0, - FocusDirectionBackward + FocusDirectionNone = 0, + FocusDirectionForward, + FocusDirectionBackward, + FocusDirectionUp, + FocusDirectionDown, + FocusDirectionLeft, + FocusDirectionRight }; } diff --git a/WebCore/page/Frame.cpp b/WebCore/page/Frame.cpp index 87c9733..a8d58fd 100644 --- a/WebCore/page/Frame.cpp +++ b/WebCore/page/Frame.cpp @@ -49,6 +49,7 @@ #include "FrameLoaderClient.h" #include "FrameView.h" #include "GraphicsContext.h" +#include "GraphicsLayer.h" #include "HTMLDocument.h" #include "HTMLFormControlElement.h" #include "HTMLFormElement.h" @@ -84,8 +85,8 @@ #include <wtf/RefCountedLeakCounter.h> #include <wtf/StdLibExtras.h> -#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN)) -#import <Carbon/Carbon.h> +#if USE(ACCELERATED_COMPOSITING) +#include "RenderLayerCompositor.h" #endif #if USE(JSC) @@ -112,6 +113,10 @@ #include "MathMLNames.h" #endif +#if ENABLE(TILED_BACKING_STORE) +#include "TiledBackingStore.h" +#endif + using namespace std; namespace WebCore { @@ -136,7 +141,6 @@ Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* , m_redirectScheduler(this) , m_ownerElement(ownerElement) , m_script(this) - , m_selectionGranularity(CharacterGranularity) , m_selectionController(this) , m_editor(this) , m_eventHandler(this) @@ -175,9 +179,13 @@ Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* XMLNSNames::init(); XMLNames::init(); - if (!ownerElement) + if (!ownerElement) { page->setMainFrame(this); - else { +#if ENABLE(TILED_BACKING_STORE) + // Top level frame only for now. + setTiledBackingStoreEnabled(page->settings()->tiledBackingStoreEnabled()); +#endif + } else { page->incrementFrameCount(); // Make sure we will not end up with two frames referencing the same owner element. ASSERT((!(ownerElement->m_contentFrame)) || (ownerElement->m_contentFrame->ownerElement() != ownerElement)); @@ -265,6 +273,11 @@ void Frame::setView(PassRefPtr<FrameView> view) // Since this part may be getting reused as a result of being // pulled from the back/forward cache, reset this flag. loader()->resetMultipleFormSubmissionProtection(); + +#if ENABLE(TILED_BACKING_STORE) + if (m_view && tiledBackingStore()) + m_view->setPaintsEntireContents(true); +#endif } ScriptController* Frame::script() @@ -285,8 +298,7 @@ void Frame::setDocument(PassRefPtr<Document> newDoc) } m_doc = newDoc; - if (m_doc && selection()->isFocusedAndActive()) - setUseSecureKeyboardEntry(m_doc->useSecureKeyboardEntryWhenActive()); + selection()->updateSecureKeyboardEntryIfActive(); if (m_doc && !m_doc->attached()) m_doc->attach(); @@ -366,12 +378,7 @@ Editor* Frame::editor() const TextGranularity Frame::selectionGranularity() const { - return m_selectionGranularity; -} - -void Frame::setSelectionGranularity(TextGranularity granularity) -{ - m_selectionGranularity = granularity; + return m_selectionController.granularity(); } SelectionController* Frame::dragCaretController() const @@ -657,6 +664,11 @@ void Frame::paintDragCaret(GraphicsContext* p, int tx, int ty, const IntRect& cl ASSERT(dragCaretController->selection().isCaret()); if (dragCaretController->selection().start().node()->document()->frame() == this) dragCaretController->paintCaret(p, tx, ty, clipRect); +#else + UNUSED_PARAM(p); + UNUSED_PARAM(tx); + UNUSED_PARAM(ty); + UNUSED_PARAM(clipRect); #endif } @@ -665,28 +677,24 @@ float Frame::zoomFactor() const return m_zoomFactor; } -bool Frame::isZoomFactorTextOnly() const +ZoomMode Frame::zoomMode() const { - return m_page->settings()->zoomsTextOnly(); + return m_page->settings()->zoomMode(); } bool Frame::shouldApplyTextZoom() const { - if (m_zoomFactor == 1.0f || !isZoomFactorTextOnly()) - return false; - return true; + return m_zoomFactor != 1.0f && zoomMode() == ZoomTextOnly; } bool Frame::shouldApplyPageZoom() const { - if (m_zoomFactor == 1.0f || isZoomFactorTextOnly()) - return false; - return true; + return m_zoomFactor != 1.0f && zoomMode() == ZoomPage; } -void Frame::setZoomFactor(float percent, bool isTextOnly) +void Frame::setZoomFactor(float percent, ZoomMode mode) { - if (m_zoomFactor == percent && isZoomFactorTextOnly() == isTextOnly) + if (m_zoomFactor == percent && zoomMode() == mode) return; #if ENABLE(SVG) @@ -700,7 +708,7 @@ void Frame::setZoomFactor(float percent, bool isTextOnly) } #endif - if (!isTextOnly) { + if (mode == ZoomPage) { // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position. IntPoint scrollPosition = view()->scrollPosition(); float percentDifference = (percent / m_zoomFactor); @@ -708,12 +716,12 @@ void Frame::setZoomFactor(float percent, bool isTextOnly) } m_zoomFactor = percent; - m_page->settings()->setZoomsTextOnly(isTextOnly); + m_page->settings()->setZoomMode(mode); m_doc->recalcStyle(Node::Force); for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) - child->setZoomFactor(m_zoomFactor, isTextOnly); + child->setZoomFactor(m_zoomFactor, mode); if (m_doc->renderer() && m_doc->renderer()->needsLayout() && view()->didFirstLayout()) view()->layout(); @@ -722,7 +730,8 @@ void Frame::setZoomFactor(float percent, bool isTextOnly) void Frame::setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize) { m_doc->setPrinting(printing); - view()->setMediaType(printing ? "print" : "screen"); + view()->adjustMediaTypeForPrinting(printing); + m_doc->updateStyleSelector(); view()->forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, adjustViewSize); @@ -850,43 +859,6 @@ bool Frame::isContentEditable() const return m_doc->inDesignMode(); } -#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN)) -const short enableRomanKeyboardsOnly = -23; -#endif -void Frame::setUseSecureKeyboardEntry(bool enable) -{ -#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(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() -{ - if (selection()->isFocusedAndActive()) - setUseSecureKeyboardEntry(m_doc->useSecureKeyboardEntryWhenActive()); -} - CSSMutableStyleDeclaration *Frame::typingStyle() const { return m_typingStyle.get(); @@ -1423,7 +1395,7 @@ bool Frame::findString(const String& target, bool forward, bool caseFlag, bool w // If we started in the selection and the found range exactly matches the existing selection, find again. // Build a selection with the found range to remove collapsed whitespace. // Compare ranges instead of selection objects to ignore the way that the current selection was made. - if (startInSelection && *VisibleSelection(resultRange.get()).toNormalizedRange() == *selection.toNormalizedRange()) { + if (startInSelection && areRangesEqual(VisibleSelection(resultRange.get()).toNormalizedRange().get(), selection.toNormalizedRange().get())) { searchRange = rangeOfContents(document()); if (forward) setStart(searchRange.get(), selection.visibleEnd()); @@ -1818,7 +1790,8 @@ Document* Frame::documentAtPoint(const IntPoint& point) void Frame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent, const IntSize& fixedLayoutSize, bool useFixedLayout, - ScrollbarMode horizontalScrollbarMode, ScrollbarMode verticalScrollbarMode) + ScrollbarMode horizontalScrollbarMode, bool horizontalLock, + ScrollbarMode verticalScrollbarMode, bool verticalLock) { ASSERT(this); ASSERT(m_page); @@ -1838,7 +1811,7 @@ void Frame::createView(const IntSize& viewportSize, } else frameView = FrameView::create(this); - frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode); + frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock); setView(frameView); @@ -1855,4 +1828,67 @@ void Frame::createView(const IntSize& viewportSize, view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff); } +#if ENABLE(TILED_BACKING_STORE) +void Frame::setTiledBackingStoreEnabled(bool enabled) +{ + if (!enabled) { + m_tiledBackingStore.clear(); + return; + } + if (m_tiledBackingStore) + return; + m_tiledBackingStore.set(new TiledBackingStore(this)); + if (m_view) + m_view->setPaintsEntireContents(true); +} + +void Frame::tiledBackingStorePaintBegin() +{ + if (!m_view) + return; + m_view->layoutIfNeededRecursive(); + m_view->flushDeferredRepaints(); +} + +void Frame::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect) +{ + if (!m_view) + return; + m_view->paintContents(context, rect); +} + +void Frame::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea) +{ + if (!m_page || !m_view) + return; + unsigned size = paintedArea.size(); + // Request repaint from the system + for (int n = 0; n < size; ++n) + m_page->chrome()->invalidateContentsAndWindow(m_view->contentsToWindow(paintedArea[n]), false); +} + +IntRect Frame::tiledBackingStoreContentsRect() +{ + if (!m_view) + return IntRect(); + return IntRect(IntPoint(), m_view->contentsSize()); +} +#endif + +String Frame::layerTreeAsText() const +{ +#if USE(ACCELERATED_COMPOSITING) + if (!contentRenderer()) + return String(); + + GraphicsLayer* rootLayer = contentRenderer()->compositor()->rootPlatformLayer(); + if (!rootLayer) + return String(); + + return rootLayer->layerTreeAsText(); +#else + return String(); +#endif +} + } // namespace WebCore diff --git a/WebCore/page/Frame.h b/WebCore/page/Frame.h index 26d1efa..4a7cdaf 100644 --- a/WebCore/page/Frame.h +++ b/WebCore/page/Frame.h @@ -38,11 +38,16 @@ #include "ScrollBehavior.h" #include "SelectionController.h" #include "UserScriptTypes.h" +#include "ZoomMode.h" #if PLATFORM(WIN) #include "FrameWin.h" #endif +#if ENABLE(TILED_BACKING_STORE) +#include "TiledBackingStoreClient.h" +#endif + #if PLATFORM(MAC) #ifndef __OBJC__ class NSArray; @@ -62,8 +67,14 @@ namespace WebCore { class CSSMutableStyleDeclaration; class HTMLTableCellElement; class RegularExpression; + class RenderPart; + class TiledBackingStore; - class Frame : public RefCounted<Frame> { + class Frame : public RefCounted<Frame> +#if ENABLE(TILED_BACKING_STORE) + , public TiledBackingStoreClient +#endif + { public: static PassRefPtr<Frame> create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client) { @@ -108,9 +119,12 @@ namespace WebCore { void setExcludeFromTextSearch(bool); void createView(const IntSize&, const Color&, bool, const IntSize &, bool, - ScrollbarMode = ScrollbarAuto, ScrollbarMode = ScrollbarAuto); + ScrollbarMode = ScrollbarAuto, bool horizontalLock = false, + ScrollbarMode = ScrollbarAuto, bool verticalLock = false); void injectUserScripts(UserScriptInjectionTime); + + String layerTreeAsText() const; private: void injectUserScriptsForWorld(DOMWrapperWorld*, const UserScriptVector&, UserScriptInjectionTime); @@ -163,15 +177,20 @@ namespace WebCore { return document() ? document()->displayStringModifiedByEncoding(str) : str; } +#if ENABLE(TILED_BACKING_STORE) + TiledBackingStore* tiledBackingStore() const { return m_tiledBackingStore.get(); } + void setTiledBackingStoreEnabled(bool); +#endif + private: void lifeSupportTimerFired(Timer<Frame>*); // === to be moved into FrameView public: - void setZoomFactor(float scale, bool isTextOnly); + void setZoomFactor(float scale, ZoomMode); float zoomFactor() const; - bool isZoomFactorTextOnly() const; + ZoomMode zoomMode() const; bool shouldApplyTextZoom() const; bool shouldApplyPageZoom() const; float pageZoomFactor() const { return shouldApplyPageZoom() ? zoomFactor() : 1.0f; } @@ -232,7 +251,6 @@ namespace WebCore { public: TextGranularity selectionGranularity() const; - void setSelectionGranularity(TextGranularity); bool shouldChangeSelection(const VisibleSelection&) const; bool shouldDeleteSelection(const VisibleSelection&) const; @@ -243,8 +261,6 @@ namespace WebCore { bool isContentEditable() const; // if true, everything in frame is editable - void updateSecureKeyboardEntryIfActive(); - CSSMutableStyleDeclaration* typingStyle() const; void setTypingStyle(CSSMutableStyleDeclaration*); void clearTypingStyle(); @@ -258,8 +274,6 @@ namespace WebCore { void revealSelection(const ScrollAlignment& = ScrollAlignment::alignCenterIfNeeded, bool revealExtent = false); void setSelectionFromNone(); - void setUseSecureKeyboardEntry(bool); - SelectionController* dragCaretController() const; String searchForLabelsAboveCell(RegularExpression*, HTMLTableCellElement*, size_t* resultDistanceFromStartOfCell); @@ -268,6 +282,15 @@ namespace WebCore { VisiblePosition visiblePositionForPoint(const IntPoint& framePoint); Document* documentAtPoint(const IntPoint& windowPoint); + + private: +#if ENABLE(TILED_BACKING_STORE) + // TiledBackingStoreClient interface + virtual void tiledBackingStorePaintBegin(); + virtual void tiledBackingStorePaint(GraphicsContext*, const IntRect&); + virtual void tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea); + virtual IntRect tiledBackingStoreContentsRect(); +#endif #if PLATFORM(MAC) @@ -325,8 +348,6 @@ namespace WebCore { float m_zoomFactor; - TextGranularity m_selectionGranularity; - mutable SelectionController m_selectionController; mutable VisibleSelection m_mark; mutable Editor m_editor; @@ -346,6 +367,10 @@ namespace WebCore { bool m_needsReapplyStyles; bool m_isDisconnected; bool m_excludeFromTextSearch; + +#if ENABLE(TILED_BACKING_STORE) + OwnPtr<TiledBackingStore> m_tiledBackingStore; +#endif }; } // namespace WebCore diff --git a/WebCore/page/FrameTree.cpp b/WebCore/page/FrameTree.cpp index 41caa9c..d6170e1 100644 --- a/WebCore/page/FrameTree.cpp +++ b/WebCore/page/FrameTree.cpp @@ -25,7 +25,6 @@ #include "Page.h" #include "PageGroup.h" #include <stdarg.h> -#include <wtf/Platform.h> #include <wtf/StringExtras.h> #include <wtf/Vector.h> diff --git a/WebCore/page/FrameView.cpp b/WebCore/page/FrameView.cpp index 356ada2..f784c1b 100644 --- a/WebCore/page/FrameView.cpp +++ b/WebCore/page/FrameView.cpp @@ -75,10 +75,16 @@ #include "SVGViewSpec.h" #endif +<<<<<<< HEAD #if PLATFORM(ANDROID) #include "WebCoreFrameBridge.h" #endif +======= +#if ENABLE(TILED_BACKING_STORE) +#include "TiledBackingStore.h" +#endif +>>>>>>> webkit.org at r58033 namespace WebCore { @@ -117,6 +123,7 @@ FrameView::FrameView(Frame* frame) : m_frame(frame) , m_canHaveScrollbars(true) , m_slowRepaintObjectCount(0) + , m_fixedObjectCount(0) , m_layoutTimer(this, &FrameView::layoutTimerFired) , m_layoutRoot(0) , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired) @@ -301,7 +308,7 @@ void FrameView::invalidateRect(const IntRect& rect) { if (!parent()) { if (hostWindow()) - hostWindow()->repaint(rect, true); + hostWindow()->invalidateContentsAndWindow(rect, false /*immediate*/); return; } @@ -330,6 +337,23 @@ void FrameView::setMarginHeight(int h) m_margins.setHeight(h); } +bool FrameView::avoidScrollbarCreation() +{ + ASSERT(m_frame); + + // with frame flattening no subframe can have scrollbars + // but we also cannot turn scrollbars of as we determine + // our flattening policy using that. + + if (!m_frame->ownerElement()) + return false; + + if (!m_frame->settings() || m_frame->settings()->frameFlatteningEnabled()) + return true; + + return false; +} + void FrameView::setCanHaveScrollbars(bool canHaveScrollbars) { m_canHaveScrollbars = canHaveScrollbars; @@ -385,7 +409,7 @@ void FrameView::setContentsSize(const IntSize& size) return; page->chrome()->contentsSizeChanged(frame(), size); //notify only - + m_deferSetNeedsLayouts--; if (!m_deferSetNeedsLayouts) @@ -398,6 +422,7 @@ void FrameView::adjustViewSize() RenderView* root = m_frame->contentRenderer(); if (!root) return; + setContentsSize(IntSize(root->rightLayoutOverflow(), root->bottomLayoutOverflow())); } @@ -628,7 +653,7 @@ void FrameView::layout(bool allowSubtree) RenderObject* rootRenderer = documentElement ? documentElement->renderer() : 0; Node* body = document->body(); if (body && body->renderer()) { - if (body->hasTagName(framesetTag) && !m_frame->settings()->frameSetFlatteningEnabled()) { + if (body->hasTagName(framesetTag) && !m_frame->settings()->frameFlatteningEnabled()) { body->renderer()->setChildNeedsLayout(true); vMode = ScrollbarAlwaysOff; hMode = ScrollbarAlwaysOff; @@ -665,8 +690,9 @@ void FrameView::layout(bool allowSubtree) ScrollbarMode currentVMode = verticalScrollbarMode(); if (m_firstLayout || (hMode != currentHMode || vMode != currentVMode)) { - setScrollbarsSuppressed(true); if (m_firstLayout) { + setScrollbarsSuppressed(true); + m_firstLayout = false; m_firstLayoutCallbackPending = true; m_lastLayoutSize = IntSize(width(), height()); @@ -678,9 +704,11 @@ void FrameView::layout(bool allowSubtree) // Set the initial hMode to AlwaysOff if we're auto. if (hMode == ScrollbarAuto) setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear. - } - setScrollbarModes(hMode, vMode); - setScrollbarsSuppressed(false, true); + + setScrollbarModes(hMode, vMode); + setScrollbarsSuppressed(false, true); + } else + setScrollbarModes(hMode, vMode); } IntSize oldSize = m_size; @@ -728,10 +756,12 @@ void FrameView::layout(bool allowSubtree) // Now update the positions of all layers. beginDeferredRepaints(); + IntPoint cachedOffset; layer->updateLayerPositions((m_doFullRepaint ? RenderLayer::DoFullRepaint : 0) | RenderLayer::CheckForRepaint | RenderLayer::IsCompositingUpdateRoot - | RenderLayer::UpdateCompositingLayers); + | RenderLayer::UpdateCompositingLayers, + subtree ? 0 : &cachedOffset); endDeferredRepaints(); #if USE(ACCELERATED_COMPOSITING) @@ -815,14 +845,27 @@ String FrameView::mediaType() const return m_mediaType; } +void FrameView::adjustMediaTypeForPrinting(bool printing) +{ + if (printing) { + if (m_mediaTypeWhenNotPrinting.isNull()) + m_mediaTypeWhenNotPrinting = mediaType(); + setMediaType("print"); + } else { + if (!m_mediaTypeWhenNotPrinting.isNull()) + setMediaType(m_mediaTypeWhenNotPrinting); + m_mediaTypeWhenNotPrinting = String(); + } +} + bool FrameView::useSlowRepaints() const { - return m_useSlowRepaints || m_slowRepaintObjectCount > 0 || m_isOverlapped || !m_contentIsOpaque; + return m_useSlowRepaints || m_slowRepaintObjectCount > 0 || (platformWidget() && m_fixedObjectCount > 0) || m_isOverlapped || !m_contentIsOpaque; } bool FrameView::useSlowRepaintsIfNotOverlapped() const { - return m_useSlowRepaints || m_slowRepaintObjectCount > 0 || !m_contentIsOpaque; + return m_useSlowRepaints || m_slowRepaintObjectCount > 0 || (platformWidget() && m_fixedObjectCount > 0) || !m_contentIsOpaque; } void FrameView::setUseSlowRepaints() @@ -846,6 +889,17 @@ void FrameView::removeSlowRepaintObject() setCanBlitOnScroll(!useSlowRepaints()); } +void FrameView::addFixedObject() +{ + ++m_fixedObjectCount; +} + +void FrameView::removeFixedObject() +{ + ASSERT(m_fixedObjectCount > 0); + --m_fixedObjectCount; +} + void FrameView::setIsOverlapped(bool isOverlapped) { if (isOverlapped == m_isOverlapped) @@ -982,10 +1036,10 @@ void FrameView::scrollPositionChanged() // For fixed position elements, update widget positions and compositing layers after scrolling, // but only if we're not inside of layout. - // FIXME: we could skip this if we knew the page had no fixed position elements. - if (!m_nestedLayoutCount) { + if (!m_nestedLayoutCount && hasFixedObjects()) { if (RenderView* root = m_frame->contentRenderer()) { root->updateWidgetPositions(); + root->layer()->updateRepaintRectsAfterScroll(); #if USE(ACCELERATED_COMPOSITING) if (root->usesCompositing()) root->compositor()->updateCompositingLayers(CompositingUpdateOnScroll); @@ -1040,6 +1094,12 @@ void FrameView::repaintContentRectangle(const IntRect& r, bool immediate) if (!immediate && isOffscreen() && !shouldUpdateWhileOffscreen()) return; +#if ENABLE(TILED_BACKING_STORE) + if (frame()->tiledBackingStore()) { + frame()->tiledBackingStore()->invalidate(r); + return; + } +#endif ScrollView::repaintContentRectangle(r, immediate); } @@ -1111,8 +1171,15 @@ void FrameView::doDeferredRepaints() return; } unsigned size = m_repaintRects.size(); - for (unsigned i = 0; i < size; i++) + for (unsigned i = 0; i < size; i++) { +#if ENABLE(TILED_BACKING_STORE) + if (frame()->tiledBackingStore()) { + frame()->tiledBackingStore()->invalidate(m_repaintRects[i]); + continue; + } +#endif ScrollView::repaintContentRectangle(m_repaintRects[i], false); + } m_repaintRects.clear(); m_repaintCount = 0; @@ -1182,6 +1249,7 @@ void FrameView::scheduleRelayout() if (!m_frame->document()->shouldScheduleLayout()) return; +<<<<<<< HEAD #if defined(FLATTEN_IFRAME) || defined(FLATTEN_FRAMESET) // This is the Android frame flattening code. The common code below is not // used as frameSetFlatteningEnabled() is false on Android. @@ -1190,9 +1258,14 @@ void FrameView::scheduleRelayout() #endif // When frameset flattening is enabled, the contents of the frame affects layout of the parent frames. +======= + // When frame flattening is enabled, the contents of the frame affects layout of the parent frames. +>>>>>>> webkit.org at r58033 // Also invalidate parent frame starting from the owner element of this frame. - if (m_frame->settings()->frameSetFlatteningEnabled() && m_frame->ownerRenderer()) - m_frame->ownerRenderer()->setNeedsLayout(true, true); + if (m_frame->settings()->frameFlatteningEnabled() && m_frame->ownerRenderer()) { + if (m_frame->ownerElement()->hasTagName(iframeTag) || m_frame->ownerElement()->hasTagName(frameTag)) + m_frame->ownerRenderer()->setNeedsLayout(true, true); + } int delay = m_frame->document()->minimumLayoutDelay(); if (m_layoutTimer.isActive() && m_delayedLayout && !delay) @@ -1403,20 +1476,30 @@ bool FrameView::updateWidgets() if (m_nestedLayoutCount > 1 || !m_widgetUpdateSet || m_widgetUpdateSet->isEmpty()) return true; - Vector<RenderEmbeddedObject*> objectVector; - copyToVector(*m_widgetUpdateSet, objectVector); - size_t size = objectVector.size(); + size_t size = m_widgetUpdateSet->size(); + + Vector<RenderEmbeddedObject*> objects; + objects.reserveCapacity(size); + + RenderEmbeddedObjectSet::const_iterator end = m_widgetUpdateSet->end(); + for (RenderEmbeddedObjectSet::const_iterator it = m_widgetUpdateSet->begin(); it != end; ++it) { + objects.uncheckedAppend(*it); + (*it)->ref(); + } + for (size_t i = 0; i < size; ++i) { - RenderEmbeddedObject* object = objectVector[i]; + RenderEmbeddedObject* object = objects[i]; + + // The object may have been destroyed, but our manual ref() keeps the object from being deleted. object->updateWidget(false); - - // updateWidget() can destroy the RenderPartObject, so we need to make sure it's - // alive by checking if it's still in m_widgetUpdateSet. - if (m_widgetUpdateSet->contains(object)) { - object->updateWidgetPosition(); - m_widgetUpdateSet->remove(object); - } + object->updateWidgetPosition(); + + m_widgetUpdateSet->remove(object); } + + RenderArena* arena = m_frame->document()->renderArena(); + for (size_t i = 0; i < size; ++i) + objects[i]->deref(arena); return m_widgetUpdateSet->isEmpty(); } diff --git a/WebCore/page/FrameView.h b/WebCore/page/FrameView.h index 1d5a312..cbd0cb9 100644 --- a/WebCore/page/FrameView.h +++ b/WebCore/page/FrameView.h @@ -77,6 +77,8 @@ public: virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation); + virtual bool avoidScrollbarCreation(); + virtual void setContentsSize(const IntSize&); void layout(bool allowSubtree = true); @@ -141,6 +143,7 @@ public: String mediaType() const; void setMediaType(const String&); + void adjustMediaTypeForPrinting(bool printing); void setUseSlowRepaints(); void setIsOverlapped(bool); @@ -149,6 +152,9 @@ public: void addSlowRepaintObject(); void removeSlowRepaintObject(); + void addFixedObject(); + void removeFixedObject(); + void beginDeferredRepaints(); void endDeferredRepaints(); void checkStopDelayingDeferredRepaints(); @@ -215,6 +221,8 @@ private: bool useSlowRepaints() const; bool useSlowRepaintsIfNotOverlapped() const; + bool hasFixedObjects() const { return m_fixedObjectCount > 0; } + void applyOverflowToViewport(RenderObject*, ScrollbarMode& hMode, ScrollbarMode& vMode); void updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow); @@ -272,6 +280,7 @@ private: bool m_isOverlapped; bool m_contentIsOpaque; unsigned m_slowRepaintObjectCount; + unsigned m_fixedObjectCount; int m_borderX, m_borderY; @@ -293,7 +302,8 @@ private: float m_lastZoomFactor; String m_mediaType; - + String m_mediaTypeWhenNotPrinting; + unsigned m_enqueueEvents; Vector<ScheduledEvent*> m_scheduledEvents; diff --git a/WebCore/page/Geolocation.cpp b/WebCore/page/Geolocation.cpp index a885062..55fdef5 100644 --- a/WebCore/page/Geolocation.cpp +++ b/WebCore/page/Geolocation.cpp @@ -28,7 +28,10 @@ #include "config.h" #include "Geolocation.h" +#if ENABLE(GEOLOCATION) + #include "Chrome.h" +<<<<<<< HEAD // ANDROID #include "DOMWindow.h" // END ANDROID @@ -41,6 +44,10 @@ #if PLATFORM(ANDROID) #include "PlatformBridge.h" #endif +======= +#include "Frame.h" +#include "Page.h" +>>>>>>> webkit.org at r58033 #include <wtf/CurrentTime.h> #if ENABLE(CLIENT_BASED_GEOLOCATION) @@ -217,7 +224,10 @@ Geolocation::Geolocation(Frame* frame) , m_service(GeolocationService::create(this)) #endif , m_allowGeolocation(Unknown) +<<<<<<< HEAD , m_shouldClearCache(false) +======= +>>>>>>> webkit.org at r58033 , m_positionCache(new GeolocationPositionCache) { if (!m_frame) @@ -241,6 +251,8 @@ Geolocation::~Geolocation() void Geolocation::disconnectFrame() { + if (m_frame && m_frame->page() && m_allowGeolocation == InProgress) + m_frame->page()->chrome()->cancelGeolocationPermissionRequestForFrame(m_frame, this); stopUpdating(); if (m_frame) { if (m_frame->document()) @@ -253,6 +265,8 @@ void Geolocation::disconnectFrame() Geoposition* Geolocation::lastPosition() { + ASSERT(isAllowed()); + #if ENABLE(CLIENT_BASED_GEOLOCATION) if (!m_frame) return 0; @@ -323,6 +337,7 @@ void Geolocation::fatalErrorOccurred(Geolocation::GeoNotifier* notifier) } void Geolocation::requestUsesCachedPosition(GeoNotifier* notifier) +<<<<<<< HEAD { // This is called asynchronously, so the permissions could have been denied // since we last checked in startRequest. @@ -372,14 +387,57 @@ void Geolocation::makeCachedPositionCallbacks() } void Geolocation::requestTimedOut(GeoNotifier* notifier) +======= +>>>>>>> webkit.org at r58033 { - // If this is a one-shot request, stop it. - m_oneShots.remove(notifier); + // This is called asynchronously, so the permissions could have been denied + // since we last checked in startRequest. + if (isDenied()) { + notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage)); + return; + } + + m_requestsAwaitingCachedPosition.add(notifier); + + // If permissions are allowed, make the callback + if (isAllowed()) { + makeCachedPositionCallbacks(); + return; + } + + // Request permissions, which may be synchronous or asynchronous. + requestPermission(); +} + +void Geolocation::makeCachedPositionCallbacks() +{ + // All modifications to m_requestsAwaitingCachedPosition are done + // asynchronously, so we don't need to worry about it being modified from + // the callbacks. + GeoNotifierSet::const_iterator end = m_requestsAwaitingCachedPosition.end(); + for (GeoNotifierSet::const_iterator iter = m_requestsAwaitingCachedPosition.begin(); iter != end; ++iter) { + GeoNotifier* notifier = iter->get(); + notifier->runSuccessCallback(m_positionCache->cachedPosition()); + + // If this is a one-shot request, stop it. Otherwise, if the watch still + // exists, start the service to get updates. + if (m_oneShots.contains(notifier)) + m_oneShots.remove(notifier); + else if (m_watchers.contains(notifier)) { + if (notifier->hasZeroTimeout() || startUpdating(notifier)) + notifier->startTimerIfNeeded(); + else + notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage)); + } + } + + m_requestsAwaitingCachedPosition.clear(); if (!hasListeners()) stopUpdating(); } +<<<<<<< HEAD bool Geolocation::haveSuitableCachedPosition(PositionOptions* options) { if (!m_positionCache->cachedPosition()) @@ -393,27 +451,35 @@ bool Geolocation::haveSuitableCachedPosition(PositionOptions* options) } void Geolocation::clearWatch(int watchId) +======= +void Geolocation::requestTimedOut(GeoNotifier* notifier) +>>>>>>> webkit.org at r58033 { - m_watchers.remove(watchId); - + // If this is a one-shot request, stop it. + m_oneShots.remove(notifier); + if (!hasListeners()) stopUpdating(); } -void Geolocation::suspend() +bool Geolocation::haveSuitableCachedPosition(PositionOptions* options) { -#if !ENABLE(CLIENT_BASED_GEOLOCATION) - if (hasListeners()) - m_service->suspend(); -#endif + if (!m_positionCache->cachedPosition()) + return false; + if (!options->hasMaximumAge()) + return true; + if (!options->maximumAge()) + return false; + DOMTimeStamp currentTimeMillis = currentTime() * 1000.0; + return m_positionCache->cachedPosition()->timestamp() > currentTimeMillis - options->maximumAge(); } -void Geolocation::resume() +void Geolocation::clearWatch(int watchId) { -#if !ENABLE(CLIENT_BASED_GEOLOCATION) - if (hasListeners()) - m_service->resume(); -#endif + m_watchers.remove(watchId); + + if (!hasListeners()) + stopUpdating(); } void Geolocation::setIsAllowed(bool allowed) @@ -557,7 +623,7 @@ void Geolocation::requestPermission() void Geolocation::positionChanged(PassRefPtr<Geoposition> newPosition) { - m_currentPosition = newPosition; + m_positionCache->setCachedPosition(newPosition.get()); m_positionCache->setCachedPosition(m_currentPosition.get()); @@ -578,7 +644,7 @@ void Geolocation::positionChanged(PassRefPtr<Geoposition> newPosition) void Geolocation::makeSuccessCallbacks() { - ASSERT(m_currentPosition); + ASSERT(lastPosition()); ASSERT(isAllowed()); Vector<RefPtr<GeoNotifier> > oneShotsCopy; @@ -592,8 +658,8 @@ void Geolocation::makeSuccessCallbacks() // further callbacks to these notifiers. m_oneShots.clear(); - sendPosition(oneShotsCopy, m_currentPosition.get()); - sendPosition(watchersCopy, m_currentPosition.get()); + sendPosition(oneShotsCopy, lastPosition()); + sendPosition(watchersCopy, lastPosition()); if (!hasListeners()) stopUpdating(); @@ -709,3 +775,19 @@ void Geolocation::handleEvent(ScriptExecutionContext*, Event* event) // END ANDROID } // namespace WebCore + +#else + +namespace WebCore { + +void Geolocation::disconnectFrame() {} + +Geolocation::Geolocation(Frame*) {} + +Geolocation::~Geolocation() {} + +void Geolocation::setIsAllowed(bool) {} + +} + +#endif // ENABLE(GEOLOCATION) diff --git a/WebCore/page/Geolocation.h b/WebCore/page/Geolocation.h index 358e4a3..30db435 100644 --- a/WebCore/page/Geolocation.h +++ b/WebCore/page/Geolocation.h @@ -27,9 +27,12 @@ #ifndef Geolocation_h #define Geolocation_h +<<<<<<< HEAD // ANDROID #include "EventListener.h" // END ANDROID +======= +>>>>>>> webkit.org at r58033 #include "GeolocationPositionCache.h" #include "GeolocationService.h" #include "Geoposition.h" @@ -38,14 +41,6 @@ #include "PositionErrorCallback.h" #include "PositionOptions.h" #include "Timer.h" -#include <wtf/HashMap.h> -#include <wtf/HashSet.h> -#include <wtf/OwnPtr.h> -#include <wtf/PassRefPtr.h> -#include <wtf/Platform.h> -#include <wtf/RefCounted.h> -#include <wtf/RefPtr.h> -#include <wtf/Vector.h> namespace WebCore { @@ -56,35 +51,30 @@ class GeolocationPosition; class GeolocationError; #endif +<<<<<<< HEAD // ANDROID class Geolocation : public EventListener // END ANDROID #if !ENABLE(CLIENT_BASED_GEOLOCATION) +======= +class Geolocation : public RefCounted<Geolocation> +#if !ENABLE(CLIENT_BASED_GEOLOCATION) && ENABLE(GEOLOCATION) +>>>>>>> webkit.org at r58033 , public GeolocationServiceClient #endif { public: static PassRefPtr<Geolocation> create(Frame* frame) { return adoptRef(new Geolocation(frame)); } - virtual ~Geolocation(); + ~Geolocation(); void disconnectFrame(); - Geoposition* lastPosition(); - void getCurrentPosition(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>); int watchPosition(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>); void clearWatch(int watchId); - void suspend(); - void resume(); - void setIsAllowed(bool); - bool isAllowed() const { return m_allowGeolocation == Yes; } - bool isDenied() const { return m_allowGeolocation == No; } - - void setShouldClearCache(bool shouldClearCache) { m_shouldClearCache = shouldClearCache; } - bool shouldClearCache() const { return m_shouldClearCache; } Frame* frame() const { return m_frame; } #if ENABLE(CLIENT_BASED_GEOLOCATION) @@ -95,6 +85,11 @@ public: #endif private: + Geoposition* lastPosition(); + + bool isAllowed() const { return m_allowGeolocation == Yes; } + bool isDenied() const { return m_allowGeolocation == No; } + Geolocation(Frame*); class GeoNotifier : public RefCounted<GeoNotifier> { @@ -155,7 +150,7 @@ private: bool startUpdating(GeoNotifier*); void stopUpdating(); -#if !ENABLE(CLIENT_BASED_GEOLOCATION) +#if !ENABLE(CLIENT_BASED_GEOLOCATION) && ENABLE(GEOLOCATION) // GeolocationServiceClient virtual void geolocationServicePositionChanged(GeolocationService*); virtual void geolocationServiceErrorOccurred(GeolocationService*); @@ -186,7 +181,6 @@ private: RefPtr<GeoNotifier> m_startRequestPermissionNotifier; #endif RefPtr<Geoposition> m_lastPosition; - RefPtr<Geoposition> m_currentPosition; enum { Unknown, @@ -194,9 +188,16 @@ private: Yes, No } m_allowGeolocation; +<<<<<<< HEAD bool m_shouldClearCache; OwnPtr<GeolocationPositionCache> m_positionCache; +======= + +#if ENABLE(GEOLOCATION) + OwnPtr<GeolocationPositionCache> m_positionCache; +#endif +>>>>>>> webkit.org at r58033 GeoNotifierSet m_requestsAwaitingCachedPosition; }; diff --git a/WebCore/page/Geolocation.idl b/WebCore/page/Geolocation.idl index 76056a3..aa5b59f 100644 --- a/WebCore/page/Geolocation.idl +++ b/WebCore/page/Geolocation.idl @@ -25,9 +25,7 @@ module core { - interface [OmitConstructor] Geolocation { - readonly attribute Geoposition lastPosition; - + interface [Conditional=GEOLOCATION, OmitConstructor] Geolocation { [Custom] void getCurrentPosition(in PositionCallback successCallback, in PositionErrorCallback errorCallback, in PositionOptions options); [Custom] long watchPosition(in PositionCallback successCallback, in PositionErrorCallback errorCallback, in PositionOptions options); diff --git a/WebCore/page/GeolocationPositionCache.cpp b/WebCore/page/GeolocationPositionCache.cpp index 5796191..76d2b0b 100644 --- a/WebCore/page/GeolocationPositionCache.cpp +++ b/WebCore/page/GeolocationPositionCache.cpp @@ -26,6 +26,11 @@ #include "config.h" #include "GeolocationPositionCache.h" +<<<<<<< HEAD +======= +#if ENABLE(GEOLOCATION) + +>>>>>>> webkit.org at r58033 #include "Geoposition.h" #include "SQLValue.h" #include "SQLiteDatabase.h" @@ -33,7 +38,10 @@ #include "SQLiteStatement.h" #include "SQLiteTransaction.h" +<<<<<<< HEAD +======= +>>>>>>> webkit.org at r58033 namespace WebCore { static const char* databaseName = "CachedGeoposition.db"; @@ -173,3 +181,8 @@ void GeolocationPositionCache::writeToDB(const Geoposition* position) } } // namespace WebCore +<<<<<<< HEAD +======= + +#endif // ENABLE(GEOLOCATION) +>>>>>>> webkit.org at r58033 diff --git a/WebCore/page/Geoposition.idl b/WebCore/page/Geoposition.idl index 6fa12ff..41a2262 100644 --- a/WebCore/page/Geoposition.idl +++ b/WebCore/page/Geoposition.idl @@ -25,7 +25,7 @@ module core { - interface [OmitConstructor] Geoposition { + interface [Conditional=GEOLOCATION, OmitConstructor] Geoposition { readonly attribute Coordinates coords; readonly attribute DOMTimeStamp timestamp; }; diff --git a/WebCore/page/History.idl b/WebCore/page/History.idl index 3fc2771..d1be5ae 100644 --- a/WebCore/page/History.idl +++ b/WebCore/page/History.idl @@ -41,9 +41,9 @@ module window { [DoNotCheckDomainSecurity] void forward(); [DoNotCheckDomainSecurity] void go(in long distance); - [Custom] void pushState(in any data, in DOMString title, in optional DOMString url) + [Custom, EnabledAtRuntime] 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) + [Custom, EnabledAtRuntime] void replaceState(in any data, in DOMString title, in optional DOMString url) raises(DOMException); }; diff --git a/WebCore/page/Location.cpp b/WebCore/page/Location.cpp index 5adc48d..5754357 100644 --- a/WebCore/page/Location.cpp +++ b/WebCore/page/Location.cpp @@ -82,7 +82,7 @@ String Location::host() const // Note: this is the IE spec. The NS spec swaps the two, it says // "The hostname property is the concatenation of the host and port properties, separated by a colon." const KURL& url = this->url(); - return url.port() ? url.host() + ":" + String::number((static_cast<int>(url.port()))) : url.host(); + return url.port() ? url.host() + ":" + String::number(url.port()) : url.host(); } String Location::hostname() const @@ -99,7 +99,7 @@ String Location::port() const return String(); const KURL& url = this->url(); - return url.port() ? String::number(static_cast<int>(url.port())) : ""; + return url.port() ? String::number(url.port()) : ""; } String Location::pathname() const diff --git a/WebCore/page/OriginAccessEntry.cpp b/WebCore/page/OriginAccessEntry.cpp index 98c280c..7ff67cc 100644 --- a/WebCore/page/OriginAccessEntry.cpp +++ b/WebCore/page/OriginAccessEntry.cpp @@ -40,7 +40,6 @@ OriginAccessEntry::OriginAccessEntry(const String& protocol, const String& host, , 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. diff --git a/WebCore/page/OriginAccessEntry.h b/WebCore/page/OriginAccessEntry.h index 767d75f..7c8d556 100644 --- a/WebCore/page/OriginAccessEntry.h +++ b/WebCore/page/OriginAccessEntry.h @@ -47,15 +47,28 @@ public: // 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; - + + const String& protocol() const { return m_protocol; } + const String& host() const { return m_host; } + SubdomainSetting subdomainSettings() const { return m_subdomainSettings; } + private: String m_protocol; String m_host; SubdomainSetting m_subdomainSettings; bool m_hostIsIPAddress; - }; +inline bool operator==(const OriginAccessEntry& a, const OriginAccessEntry& b) +{ + return equalIgnoringCase(a.protocol(), b.protocol()) && equalIgnoringCase(a.host(), b.host()) && a.subdomainSettings() == b.subdomainSettings(); +} + +inline bool operator!=(const OriginAccessEntry& a, const OriginAccessEntry& b) +{ + return !(a == b); +} + } // namespace WebCore #endif // CrossOriginAccess_h diff --git a/WebCore/page/Page.cpp b/WebCore/page/Page.cpp index d348d73..ee5c052 100644 --- a/WebCore/page/Page.cpp +++ b/WebCore/page/Page.cpp @@ -30,10 +30,10 @@ #include "ContextMenuController.h" #include "DOMWindow.h" #include "DragController.h" -#include "ExceptionCode.h" #include "EditorClient.h" -#include "EventNames.h" #include "Event.h" +#include "EventNames.h" +#include "ExceptionCode.h" #include "FileSystem.h" #include "FocusController.h" #include "Frame.h" @@ -52,12 +52,14 @@ #include "PageGroup.h" #include "PluginData.h" #include "PluginHalter.h" +#include "PluginView.h" #include "ProgressTracker.h" -#include "RenderWidget.h" #include "RenderTheme.h" +#include "RenderWidget.h" #include "ScriptController.h" #include "SelectionController.h" #include "Settings.h" +#include "SharedBuffer.h" #include "StringHash.h" #include "TextResourceDecoder.h" #include "Widget.h" @@ -70,8 +72,8 @@ #include "StorageNamespace.h" #endif -#if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC) -#include "JavaScriptDebugServer.h" +#if ENABLE(JAVASCRIPT_DEBUGGER) +#include "ScriptDebugServer.h" #endif #if ENABLE(WML) @@ -151,9 +153,6 @@ 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) @@ -192,8 +191,8 @@ Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, Edi m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime()); } -#if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC) - JavaScriptDebugServer::shared().pageCreated(this); +#if ENABLE(JAVASCRIPT_DEBUGGER) + ScriptDebugServer::shared().pageCreated(this); #endif #ifndef NDEBUG @@ -212,8 +211,6 @@ Page::~Page() m_editorClient->pageDestroyed(); #if ENABLE(INSPECTOR) - if (m_parentInspectorController) - m_parentInspectorController->pageDestroyed(); m_inspectorController->inspectedPageDestroyed(); #endif @@ -310,7 +307,7 @@ void Page::goToItem(HistoryItem* item, FrameLoadType type) { // Abort any current load unless we're navigating the current document to a new state object HistoryItem* currentItem = m_mainFrame->loader()->history()->currentItem(); - if (!item->stateObject() || !currentItem || item->documentSequenceNumber() != currentItem->documentSequenceNumber()) { + if (!item->stateObject() || !currentItem || item->documentSequenceNumber() != currentItem->documentSequenceNumber() || item == currentItem) { // Define what to do with any open database connections. By default we stop them and terminate the database thread. DatabasePolicy databasePolicy = DatabasePolicyStop; @@ -407,7 +404,7 @@ void Page::refreshPlugins(bool reload) PluginData* Page::pluginData() const { - if (!settings()->arePluginsEnabled()) + if (!mainFrame()->loader()->allowPlugins(NotAboutToInstantiatePlugin)) return 0; if (!m_pluginData) m_pluginData = PluginData::create(this); @@ -725,7 +722,7 @@ void Page::setDebugger(JSC::Debugger* debugger) StorageNamespace* Page::sessionStorage(bool optionalCreate) { if (!m_sessionStorage && optionalCreate) - m_sessionStorage = StorageNamespace::sessionStorageNamespace(this); + m_sessionStorage = StorageNamespace::sessionStorageNamespace(this, m_settings->sessionStorageQuota()); return m_sessionStorage.get(); } @@ -793,6 +790,35 @@ InspectorTimelineAgent* Page::inspectorTimelineAgent() const } #endif +void Page::privateBrowsingStateChanged() +{ + bool privateBrowsingEnabled = m_settings->privateBrowsingEnabled(); + + // Collect the PluginViews in to a vector to ensure that action the plug-in takes + // from below privateBrowsingStateChanged does not affect their lifetime. + + Vector<RefPtr<PluginView>, 32> pluginViews; + for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { + FrameView* view = frame->view(); + if (!view) + return; + + const HashSet<RefPtr<Widget> >* children = view->children(); + ASSERT(children); + + HashSet<RefPtr<Widget> >::const_iterator end = children->end(); + for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) { + Widget* widget = (*it).get(); + if (!widget->isPluginView()) + continue; + pluginViews.append(static_cast<PluginView*>(widget)); + } + } + + for (size_t i = 0; i < pluginViews.size(); i++) + pluginViews[i]->privateBrowsingStateChanged(privateBrowsingEnabled); +} + void Page::pluginAllowedRunTimeChanged() { if (m_pluginHalter) diff --git a/WebCore/page/Page.h b/WebCore/page/Page.h index 04a545c..94e6dd5 100644 --- a/WebCore/page/Page.h +++ b/WebCore/page/Page.h @@ -31,10 +31,6 @@ #include "SchedulePair.h" #endif -#if PLATFORM(WIN) || (PLATFORM(WX) && OS(WINDOWS)) || (PLATFORM(QT) && defined(Q_WS_WIN)) -typedef struct HINSTANCE__* HINSTANCE; -#endif - namespace JSC { class Debugger; } @@ -153,11 +149,6 @@ namespace WebCore { #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; } @@ -197,6 +188,8 @@ namespace WebCore { void userStyleSheetLocationChanged(); const String& userStyleSheet() const; + void privateBrowsingStateChanged(); + void didStartPlugin(HaltablePlugin*); void didStopPlugin(HaltablePlugin*); void pluginAllowedRunTimeChanged(); @@ -205,12 +198,6 @@ namespace WebCore { void setDebugger(JSC::Debugger*); JSC::Debugger* debugger() const { return m_debugger; } -#if PLATFORM(WIN) || (PLATFORM(WX) && OS(WINDOWS)) || (PLATFORM(QT) && defined(Q_WS_WIN)) - // The global DLL or application instance used for all windows. - static void setInstanceHandle(HINSTANCE instanceHandle) { s_instanceHandle = instanceHandle; } - static HINSTANCE instanceHandle() { return s_instanceHandle; } -#endif - static void removeAllVisitedLinks(); static void allVisitedStateChanged(PageGroup*); @@ -294,10 +281,6 @@ namespace WebCore { bool m_javaScriptURLsAreAllowed; -#if ENABLE(INSPECTOR) - InspectorController* m_parentInspectorController; -#endif - String m_userStyleSheetPath; mutable String m_userStyleSheet; mutable bool m_didLoadUserStyleSheet; @@ -320,10 +303,6 @@ namespace WebCore { RefPtr<StorageNamespace> m_sessionStorage; #endif -#if PLATFORM(WIN) || (PLATFORM(WX) && defined(__WXMSW__)) || (PLATFORM(QT) && defined(Q_WS_WIN)) - static HINSTANCE s_instanceHandle; -#endif - #if ENABLE(WML) OwnPtr<WMLPageState> m_wmlPageState; #endif diff --git a/WebCore/page/PageGroup.cpp b/WebCore/page/PageGroup.cpp index f376d52..f6c746d 100644 --- a/WebCore/page/PageGroup.cpp +++ b/WebCore/page/PageGroup.cpp @@ -30,12 +30,10 @@ #include "ChromeClient.h" #include "Document.h" #include "Frame.h" +#include "IndexedDatabase.h" #include "Page.h" #include "Settings.h" - -#if ENABLE(DOM_STORAGE) #include "StorageNamespace.h" -#endif #if PLATFORM(CHROMIUM) #include "ChromiumBridge.h" @@ -191,6 +189,9 @@ StorageNamespace* PageGroup::localStorage() { if (!m_localStorage) { // Need a page in this page group to query the settings for the local storage database path. + // Having these parameters attached to the page settings is unfortunate since these settings are + // not per-page (and, in fact, we simply grab the settings from some page at random), but + // at this point we're stuck with it. Page* page = *m_pages.begin(); const String& path = page->settings()->localStorageDatabasePath(); unsigned quota = page->settings()->localStorageQuota(); @@ -201,6 +202,17 @@ StorageNamespace* PageGroup::localStorage() } #endif +#if ENABLE(INDEXED_DATABASE) +IndexedDatabase* PageGroup::indexedDatabase() +{ + // Do not add page setting based access control here since this object is shared by all pages in + // the group and having per-page controls is misleading. + if (!m_indexedDatabase) + m_indexedDatabase = IndexedDatabase::create(); + return m_indexedDatabase.get(); +} +#endif + void PageGroup::addUserScriptToWorld(DOMWrapperWorld* world, const String& source, const KURL& url, PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist, UserScriptInjectionTime injectionTime) { diff --git a/WebCore/page/PageGroup.h b/WebCore/page/PageGroup.h index 446f0c7..c1d25fa 100644 --- a/WebCore/page/PageGroup.h +++ b/WebCore/page/PageGroup.h @@ -36,6 +36,7 @@ namespace WebCore { class KURL; + class IndexedDatabase; class Page; class StorageNamespace; @@ -69,6 +70,9 @@ namespace WebCore { StorageNamespace* localStorage(); bool hasLocalStorage() { return m_localStorage; } #endif +#if ENABLE(DOM_STORAGE) + IndexedDatabase* indexedDatabase(); +#endif void addUserScriptToWorld(DOMWrapperWorld*, const String& source, const KURL&, PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist, @@ -101,6 +105,9 @@ namespace WebCore { #if ENABLE(DOM_STORAGE) RefPtr<StorageNamespace> m_localStorage; #endif +#if ENABLE(INDEXED_DATABASE) + RefPtr<IndexedDatabase> m_indexedDatabase; +#endif OwnPtr<UserScriptMap> m_userScripts; OwnPtr<UserStyleSheetMap> m_userStyleSheets; diff --git a/WebCore/page/PositionCallback.h b/WebCore/page/PositionCallback.h index 9f36d7a..5b7a202 100644 --- a/WebCore/page/PositionCallback.h +++ b/WebCore/page/PositionCallback.h @@ -26,7 +26,6 @@ #ifndef PositionCallback_h #define PositionCallback_h -#include <wtf/Platform.h> #include <wtf/RefCounted.h> namespace WebCore { diff --git a/WebCore/page/PositionError.idl b/WebCore/page/PositionError.idl index 1f28d95..5870e0d 100644 --- a/WebCore/page/PositionError.idl +++ b/WebCore/page/PositionError.idl @@ -25,7 +25,7 @@ module core { - interface PositionError { + interface [Conditional=GEOLOCATION] PositionError { readonly attribute unsigned short code; readonly attribute DOMString message; diff --git a/WebCore/page/PositionErrorCallback.h b/WebCore/page/PositionErrorCallback.h index c23e883..e784297 100644 --- a/WebCore/page/PositionErrorCallback.h +++ b/WebCore/page/PositionErrorCallback.h @@ -26,7 +26,6 @@ #ifndef PositionErrorCallback_h #define PositionErrorCallback_h -#include <wtf/Platform.h> #include <wtf/RefCounted.h> namespace WebCore { diff --git a/WebCore/page/PrintContext.cpp b/WebCore/page/PrintContext.cpp index 31c8777..e0235de 100644 --- a/WebCore/page/PrintContext.cpp +++ b/WebCore/page/PrintContext.cpp @@ -32,11 +32,13 @@ namespace WebCore { PrintContext::PrintContext(Frame* frame) : m_frame(frame) + , m_isPrinting(false) { } PrintContext::~PrintContext() { + ASSERT(!m_isPrinting); m_pageRects.clear(); } @@ -58,18 +60,18 @@ void PrintContext::computePageRects(const FloatRect& printRect, float headerHeig if (!m_frame->document() || !m_frame->view() || !m_frame->document()->renderer()) return; - RenderView* root = toRenderView(m_frame->document()->renderer()); - - if (!root) { - LOG_ERROR("document to be printed has no renderer"); + if (userScaleFactor <= 0) { + LOG_ERROR("userScaleFactor has bad value %.2f", userScaleFactor); return; } + RenderView* root = toRenderView(m_frame->document()->renderer()); + float ratio = printRect.height() / printRect.width(); float pageWidth = (float)root->rightLayoutOverflow(); float pageHeight = pageWidth * ratio; - outPageHeight = pageHeight; // this is the height of the page adjusted by margins + outPageHeight = pageHeight; // this is the height of the page adjusted by margins pageHeight -= headerHeight + footerHeight; if (pageHeight <= 0) { @@ -77,26 +79,25 @@ void PrintContext::computePageRects(const FloatRect& printRect, float headerHeig return; } - computePageRectsWithPageSize(FloatSize(pageWidth, pageHeight), userScaleFactor); + computePageRectsWithPageSizeInternal(FloatSize(pageWidth / userScaleFactor, pageHeight / userScaleFactor), false); } -void PrintContext::computePageRectsWithPageSize(const FloatSize& pageSizeInPixels, float userScaleFactor) +void PrintContext::computePageRectsWithPageSize(const FloatSize& pageSizeInPixels, bool allowHorizontalMultiPages) { - RenderView* root = toRenderView(m_frame->document()->renderer()); - - if (!root) { - LOG_ERROR("document to be printed has no renderer"); - return; - } + m_pageRects.clear(); + computePageRectsWithPageSizeInternal(pageSizeInPixels, allowHorizontalMultiPages); +} - if (userScaleFactor <= 0) { - LOG_ERROR("userScaleFactor has bad value %.2f", userScaleFactor); +void PrintContext::computePageRectsWithPageSizeInternal(const FloatSize& pageSizeInPixels, bool allowHorizontalMultiPages) +{ + if (!m_frame->document() || !m_frame->view() || !m_frame->document()->renderer()) return; - } + RenderView* root = toRenderView(m_frame->document()->renderer()); - float currPageHeight = pageSizeInPixels.height() / userScaleFactor; - float docHeight = root->layer()->height(); - float currPageWidth = pageSizeInPixels.width() / userScaleFactor; + const float pageWidth = pageSizeInPixels.width(); + const float docWidth = root->layer()->width(); + const float docHeight = root->layer()->height(); + float currPageHeight = pageSizeInPixels.height(); // always return at least one page, since empty files should print a blank page float printedPagesHeight = 0; @@ -104,14 +105,20 @@ void PrintContext::computePageRectsWithPageSize(const FloatSize& pageSizeInPixel float proposedBottom = std::min(docHeight, printedPagesHeight + pageSizeInPixels.height()); m_frame->view()->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight); currPageHeight = max(1.0f, proposedBottom - printedPagesHeight); - - m_pageRects.append(IntRect(0, (int)printedPagesHeight, (int)currPageWidth, (int)currPageHeight)); + if (allowHorizontalMultiPages) { + for (float curWidth = 0; curWidth < docWidth; curWidth += pageWidth) + m_pageRects.append(IntRect(curWidth, (int)printedPagesHeight, (int)pageWidth, (int)currPageHeight)); + } else + m_pageRects.append(IntRect(0, (int)printedPagesHeight, (int)pageWidth, (int)currPageHeight)); printedPagesHeight += currPageHeight; } while (printedPagesHeight < docHeight); } void PrintContext::begin(float width) { + ASSERT(!m_isPrinting); + m_isPrinting = true; + // By imaging to a width a little wider than the available pixels, // thin pages will be scaled down a little, matching the way they // print in IE and Camino. This lets them use fewer sheets than they @@ -148,6 +155,8 @@ void PrintContext::spoolPage(GraphicsContext& ctx, int pageNumber, float width) void PrintContext::end() { + ASSERT(m_isPrinting); + m_isPrinting = false; m_frame->setPrinting(false, 0, 0, true); } @@ -175,17 +184,18 @@ int PrintContext::pageNumberForElement(Element* element, const FloatSize& pageSi FloatRect pageRect(FloatPoint(0, 0), pageSizeInPixels); PrintContext printContext(frame); printContext.begin(pageRect.width()); - printContext.computePageRectsWithPageSize(pageSizeInPixels, 1); + printContext.computePageRectsWithPageSize(pageSizeInPixels, false); int top = box->offsetTop(); int left = box->offsetLeft(); - for (int pageNumber = 0; pageNumber < printContext.pageCount(); pageNumber++) { + int pageNumber = 0; + for (; pageNumber < printContext.pageCount(); pageNumber++) { const IntRect& page = printContext.pageRect(pageNumber); if (page.x() <= left && left < page.right() && page.y() <= top && top < page.bottom()) - return pageNumber; + break; } printContext.end(); - return -1; + return (pageNumber < printContext.pageCount() ? pageNumber : -1); } int PrintContext::numberOfPages(Frame* frame, const FloatSize& pageSizeInPixels) @@ -195,7 +205,7 @@ int PrintContext::numberOfPages(Frame* frame, const FloatSize& pageSizeInPixels) FloatRect pageRect(FloatPoint(0, 0), pageSizeInPixels); PrintContext printContext(frame); printContext.begin(pageRect.width()); - printContext.computePageRectsWithPageSize(pageSizeInPixels, 1); + printContext.computePageRectsWithPageSize(pageSizeInPixels, false); printContext.end(); return printContext.pageCount(); } diff --git a/WebCore/page/PrintContext.h b/WebCore/page/PrintContext.h index ec15b84..1891144 100644 --- a/WebCore/page/PrintContext.h +++ b/WebCore/page/PrintContext.h @@ -42,6 +42,7 @@ public: const Vector<IntRect>& pageRects() const { return m_pageRects; } void computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight); + void computePageRectsWithPageSize(const FloatSize& pageSizeInPixels, bool allowHorizontalMultiPages); // TODO: eliminate width param void begin(float width); @@ -56,10 +57,14 @@ public: static int numberOfPages(Frame*, const FloatSize& pageSizeInPixels); protected: - void computePageRectsWithPageSize(const FloatSize& pageSizeInPixels, float userScaleFactor); - Frame* m_frame; Vector<IntRect> m_pageRects; + +private: + void computePageRectsWithPageSizeInternal(const FloatSize& pageSizeInPixels, bool allowHorizontalMultiPages); + + // Used to prevent misuses of begin() and end() (e.g., call end without begin). + bool m_isPrinting; }; } diff --git a/WebCore/page/SecurityOrigin.cpp b/WebCore/page/SecurityOrigin.cpp index fe6efbd..265c643 100644 --- a/WebCore/page/SecurityOrigin.cpp +++ b/WebCore/page/SecurityOrigin.cpp @@ -29,7 +29,6 @@ #include "config.h" #include "SecurityOrigin.h" -#include "CString.h" #include "Document.h" #include "KURL.h" #include "OriginAccessEntry.h" @@ -65,6 +64,19 @@ static URLSchemesMap& localSchemes() return localSchemes; } +static URLSchemesMap& secureSchemes() +{ + DEFINE_STATIC_LOCAL(URLSchemesMap, secureSchemes, ()); + + if (secureSchemes.isEmpty()) { + secureSchemes.add("https"); + secureSchemes.add("about"); + secureSchemes.add("data"); + } + + return secureSchemes; +} + static URLSchemesMap& schemesWithUniqueOrigins() { DEFINE_STATIC_LOCAL(URLSchemesMap, schemesWithUniqueOrigins, ()); @@ -85,6 +97,7 @@ SecurityOrigin::SecurityOrigin(const KURL& url, SandboxFlags sandboxFlags) , m_isUnique(isSandboxed(SandboxOrigin) || shouldTreatURLSchemeAsNoAccess(m_protocol)) , m_universalAccess(false) , m_domainWasSetInDOM(false) + , m_enforceFilePathSeparation(false) { // These protocols do not create security origins; the owner frame provides the origin if (m_protocol == "about" || m_protocol == "javascript") @@ -99,6 +112,8 @@ SecurityOrigin::SecurityOrigin(const KURL& url, SandboxFlags sandboxFlags) // Directories should never be readable. if (!url.hasPath() || url.path().endsWith("/")) m_isUnique = true; + // Store the path in case we are doing per-file origin checking. + m_filePath = url.path(); } if (isDefaultPortForProtocol(m_port, m_protocol)) @@ -109,12 +124,15 @@ SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) : m_sandboxFlags(other->m_sandboxFlags) , m_protocol(other->m_protocol.threadsafeCopy()) , m_host(other->m_host.threadsafeCopy()) + , m_encodedHost(other->m_encodedHost.threadsafeCopy()) , m_domain(other->m_domain.threadsafeCopy()) + , m_filePath(other->m_filePath.threadsafeCopy()) , m_port(other->m_port) , m_isUnique(other->m_isUnique) , m_universalAccess(other->m_universalAccess) , m_domainWasSetInDOM(other->m_domainWasSetInDOM) , m_canLoadLocalResources(other->m_canLoadLocalResources) + , m_enforceFilePathSeparation(other->m_enforceFilePathSeparation) { } @@ -172,7 +190,7 @@ bool SecurityOrigin::isDomainRelaxationForbiddenForURLScheme(const String& schem } bool SecurityOrigin::canAccess(const SecurityOrigin* other) const -{ +{ if (m_universalAccess) return true; @@ -199,17 +217,31 @@ bool SecurityOrigin::canAccess(const SecurityOrigin* other) const // Opera 9 allows access when only one page has set document.domain, but // this is a security vulnerability. + bool canAccess = false; if (m_protocol == other->m_protocol) { if (!m_domainWasSetInDOM && !other->m_domainWasSetInDOM) { if (m_host == other->m_host && m_port == other->m_port) - return true; + canAccess = true; } else if (m_domainWasSetInDOM && other->m_domainWasSetInDOM) { if (m_domain == other->m_domain) - return true; + canAccess = true; } } - - return false; + + if (canAccess && isLocal()) + canAccess = passesFileCheck(other); + + return canAccess; +} + +bool SecurityOrigin::passesFileCheck(const SecurityOrigin* other) const +{ + ASSERT(isLocal() && other->isLocal()); + + if (!m_enforceFilePathSeparation && !other->m_enforceFilePathSeparation) + return true; + + return (m_filePath == other->m_filePath); } bool SecurityOrigin::canRequest(const KURL& url) const @@ -229,12 +261,8 @@ bool SecurityOrigin::canRequest(const KURL& url) const 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; - } - } + if (isAccessWhiteListed(targetOrigin.get())) + return true; return false; } @@ -256,15 +284,32 @@ bool SecurityOrigin::taintsCanvas(const KURL& url) const return true; } +bool SecurityOrigin::isAccessWhiteListed(const SecurityOrigin* targetOrigin) const +{ + 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::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 we were provided a document, we first check if the access has been white listed. + // Then we let its local file police dictate the result. + // Otherwise we allow local loads only if the supplied referrer is also local. + if (document) { + SecurityOrigin* documentOrigin = document->securityOrigin(); + RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url); + if (documentOrigin->isAccessWhiteListed(targetOrigin.get())) + return true; + return documentOrigin->canLoadLocalResources(); + } if (!referrer.isEmpty()) return shouldTreatURLAsLocal(referrer); return false; @@ -286,9 +331,10 @@ void SecurityOrigin::grantUniversalAccess() m_universalAccess = true; } -void SecurityOrigin::makeUnique() +void SecurityOrigin::enforceFilePathSeparation() { - m_isUnique = true; + ASSERT(isLocal()); + m_enforceFilePathSeparation = true; } bool SecurityOrigin::isLocal() const @@ -314,8 +360,11 @@ String SecurityOrigin::toString() const if (isUnique()) return "null"; - if (m_protocol == "file") - return String("file://"); + if (m_protocol == "file") { + if (m_enforceFilePathSeparation) + return "null"; + return "file://"; + } Vector<UChar> result; result.reserveInitialCapacity(m_protocol.length() + m_host.length() + 10); @@ -368,13 +417,92 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const St // Split out the 3 sections of data String protocol = databaseIdentifier.substring(0, separator1); String host = databaseIdentifier.substring(separator1 + 1, separator2 - separator1 - 1); + + host = decodeURLEscapeSequences(host); return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(port))); } +// The following lower-ASCII characters need escaping to be used in a filename +// across all systems, including Windows: +// - Unprintable ASCII (00-1F) +// - Space (20) +// - Double quote (22) +// - Percent (25) (escaped because it is our escape character) +// - Asterisk (2A) +// - Slash (2F) +// - Colon (3A) +// - Less-than (3C) +// - Greater-than (3E) +// - Question Mark (3F) +// - Backslash (5C) +// - Pipe (7C) +// - Delete (7F) + +static const bool needsEscaping[128] = { + /* 00-07 */ true, true, true, true, true, true, true, true, + /* 08-0F */ true, true, true, true, true, true, true, true, + + /* 10-17 */ true, true, true, true, true, true, true, true, + /* 18-1F */ true, true, true, true, true, true, true, true, + + /* 20-27 */ true, false, true, false, false, true, false, false, + /* 28-2F */ false, false, true, false, false, false, false, true, + + /* 30-37 */ false, false, false, false, false, false, false, false, + /* 38-3F */ false, false, true, false, true, false, true, true, + + /* 40-47 */ false, false, false, false, false, false, false, false, + /* 48-4F */ false, false, false, false, false, false, false, false, + + /* 50-57 */ false, false, false, false, false, false, false, false, + /* 58-5F */ false, false, false, false, true, false, false, false, + + /* 60-67 */ false, false, false, false, false, false, false, false, + /* 68-6F */ false, false, false, false, false, false, false, false, + + /* 70-77 */ false, false, false, false, false, false, false, false, + /* 78-7F */ false, false, false, false, true, false, false, true, +}; + +static inline bool shouldEscapeUChar(UChar c) +{ + return c > 127 ? false : needsEscaping[c]; +} + +static const char hexDigits[17] = "0123456789ABCDEF"; + +static String encodedHost(const String& host) +{ + unsigned length = host.length(); + Vector<UChar, 512> buffer(length * 3 + 1); + UChar* p = buffer.data(); + + const UChar* str = host.characters(); + const UChar* strEnd = str + length; + + while (str < strEnd) { + UChar c = *str++; + if (shouldEscapeUChar(c)) { + *p++ = '%'; + *p++ = hexDigits[(c >> 4) & 0xF]; + *p++ = hexDigits[c & 0xF]; + } else + *p++ = c; + } + + ASSERT(p - buffer.data() <= static_cast<int>(buffer.size())); + + return String(buffer.data(), p - buffer.data()); +} + String SecurityOrigin::databaseIdentifier() const { - DEFINE_STATIC_LOCAL(String, separatorString, (&SeparatorCharacter, 1)); - return m_protocol + separatorString + m_host + separatorString + String::number(m_port); + String separatorString(&SeparatorCharacter, 1); + + if (m_encodedHost.isEmpty()) + m_encodedHost = encodedHost(m_host); + + return m_protocol + separatorString + m_encodedHost + separatorString + String::number(m_port); } bool SecurityOrigin::equal(const SecurityOrigin* other) const @@ -405,6 +533,9 @@ bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const if (m_port != other->m_port) return false; + if (isLocal() && !passesFileCheck(other)) + return false; + return true; } @@ -477,6 +608,16 @@ bool SecurityOrigin::shouldTreatURLSchemeAsNoAccess(const String& scheme) return schemesWithUniqueOrigins().contains(scheme); } +void SecurityOrigin::registerURLSchemeAsSecure(const String& scheme) +{ + secureSchemes().add(scheme); +} + +bool SecurityOrigin::shouldTreatURLSchemeAsSecure(const String& scheme) +{ + return secureSchemes().contains(scheme); +} + bool SecurityOrigin::shouldHideReferrer(const KURL& url, const String& referrer) { bool referrerIsSecureURL = protocolIs(referrer, "https"); @@ -508,7 +649,7 @@ bool SecurityOrigin::allowSubstituteDataAccessToLocal() return localLoadPolicy != SecurityOrigin::AllowLocalLoadsForLocalOnly; } -void SecurityOrigin::whiteListAccessFromOrigin(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains) +void SecurityOrigin::addOriginAccessWhitelistEntry(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains) { ASSERT(isMainThread()); ASSERT(!sourceOrigin.isEmpty()); @@ -516,15 +657,42 @@ void SecurityOrigin::whiteListAccessFromOrigin(const SecurityOrigin& sourceOrigi return; String sourceString = sourceOrigin.toString(); - OriginAccessWhiteList* list = originAccessMap().get(sourceString); - if (!list) { - list = new OriginAccessWhiteList; - originAccessMap().set(sourceString, list); - } + pair<OriginAccessMap::iterator, bool> result = originAccessMap().add(sourceString, 0); + if (result.second) + result.first->second = new OriginAccessWhiteList; + + OriginAccessWhiteList* list = result.first->second; list->append(OriginAccessEntry(destinationProtocol, destinationDomains, allowDestinationSubdomains ? OriginAccessEntry::AllowSubdomains : OriginAccessEntry::DisallowSubdomains)); } -void SecurityOrigin::resetOriginAccessWhiteLists() +void SecurityOrigin::removeOriginAccessWhitelistEntry(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains) +{ + ASSERT(isMainThread()); + ASSERT(!sourceOrigin.isEmpty()); + if (sourceOrigin.isEmpty()) + return; + + String sourceString = sourceOrigin.toString(); + OriginAccessMap& map = originAccessMap(); + OriginAccessMap::iterator it = map.find(sourceString); + if (it == map.end()) + return; + + OriginAccessWhiteList* list = it->second; + size_t index = list->find(OriginAccessEntry(destinationProtocol, destinationDomains, allowDestinationSubdomains ? OriginAccessEntry::AllowSubdomains : OriginAccessEntry::DisallowSubdomains)); + if (index == notFound) + return; + + list->remove(index); + + if (!list->isEmpty()) + return; + + map.remove(it); + delete list; +} + +void SecurityOrigin::resetOriginAccessWhitelists() { ASSERT(isMainThread()); OriginAccessMap& map = originAccessMap(); diff --git a/WebCore/page/SecurityOrigin.h b/WebCore/page/SecurityOrigin.h index c96bb83..d732664 100644 --- a/WebCore/page/SecurityOrigin.h +++ b/WebCore/page/SecurityOrigin.h @@ -117,7 +117,7 @@ public: bool isSandboxed(SandboxFlags mask) const { return m_sandboxFlags & mask; } bool canAccessDatabase() const { return !isUnique(); } - bool canAccessStorage() const { return !isUnique(); } + bool canAccessLocalStorage() const { return !isUnique(); } bool canAccessCookies() const { return !isUnique(); } bool isSecureTransitionTo(const KURL&) const; @@ -138,8 +138,8 @@ public: // addition, the SandboxOrigin flag is inherited by iframes. bool isUnique() const { return m_isUnique; } - // Marks an origin as being unique. - void makeUnique(); + // Marks a file:// origin as being in a domain defined by its path. + void enforceFilePathSeparation(); // Convert this SecurityOrigin into a string. The string // representation of a SecurityOrigin is similar to a URL, except it @@ -174,6 +174,12 @@ public: static bool shouldTreatURLAsLocal(const String&); static bool shouldTreatURLSchemeAsLocal(const String&); + // Secure schemes do not trigger mixed content warnings. For example, + // https and data are secure schemes because they cannot be corrupted by + // active network attackers. + static void registerURLSchemeAsSecure(const String&); + static bool shouldTreatURLSchemeAsSecure(const String&); + static bool shouldHideReferrer(const KURL&, const String& referrer); enum LocalLoadPolicy { @@ -188,22 +194,30 @@ public: static void registerURLSchemeAsNoAccess(const String&); static bool shouldTreatURLSchemeAsNoAccess(const String&); - static void whiteListAccessFromOrigin(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains); - static void resetOriginAccessWhiteLists(); + static void addOriginAccessWhitelistEntry(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains); + static void removeOriginAccessWhitelistEntry(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains); + static void resetOriginAccessWhitelists(); private: SecurityOrigin(const KURL&, SandboxFlags); explicit SecurityOrigin(const SecurityOrigin*); + bool passesFileCheck(const SecurityOrigin* other) const; + + bool isAccessWhiteListed(const SecurityOrigin* targetOrigin) const; + SandboxFlags m_sandboxFlags; String m_protocol; String m_host; + mutable String m_encodedHost; String m_domain; + String m_filePath; unsigned short m_port; bool m_isUnique; bool m_universalAccess; bool m_domainWasSetInDOM; bool m_canLoadLocalResources; + bool m_enforceFilePathSeparation; }; } // namespace WebCore diff --git a/WebCore/page/Settings.cpp b/WebCore/page/Settings.cpp index c59bdd0..e1b848a 100644 --- a/WebCore/page/Settings.cpp +++ b/WebCore/page/Settings.cpp @@ -27,12 +27,14 @@ #include "Settings.h" #include "BackForwardList.h" +#include "Database.h" #include "Frame.h" #include "FrameTree.h" #include "FrameView.h" #include "HistoryItem.h" #include "Page.h" #include "PageCache.h" +#include "StorageMap.h" #include <limits> using namespace std; @@ -74,15 +76,20 @@ Settings::Settings(Page* page) , m_blockNetworkImage(false) #endif , m_maximumDecodedImageSize(numeric_limits<size_t>::max()) +#if ENABLE(DOM_STORAGE) , m_localStorageQuota(5 * 1024 * 1024) // Suggested by the HTML5 spec. + , m_sessionStorageQuota(StorageMap::noQuota) +#endif , m_pluginAllowedRunTime(numeric_limits<unsigned>::max()) + , m_zoomMode(ZoomPage) + , m_isSpatialNavigationEnabled(false) , m_isJavaEnabled(false) , m_loadsImagesAutomatically(false) , m_privateBrowsingEnabled(false) , m_caretBrowsingEnabled(false) , m_areImagesEnabled(true) + , m_isMediaEnabled(true) , m_arePluginsEnabled(false) - , m_databasesEnabled(false) , m_localStorageEnabled(false) , m_isJavaScriptEnabled(false) , m_isWebSecurityEnabled(true) @@ -108,13 +115,12 @@ Settings::Settings(Page* page) , m_authorAndUserStylesEnabled(true) , m_needsSiteSpecificQuirks(false) , m_fontRenderingMode(0) - , m_frameSetFlatteningEnabled(false) + , m_frameFlatteningEnabled(false) , m_webArchiveDebugModeEnabled(false) , m_localFileContentSniffingEnabled(false) , m_inApplicationChromeMode(false) , m_offlineWebApplicationCacheEnabled(false) , m_shouldPaintCustomScrollbars(false) - , m_zoomsTextOnly(false) , m_enforceCSSMIMETypeInStrictMode(true) , m_usesEncodingDetector(false) , m_allowScriptsToCloseWindows(false) @@ -135,11 +141,14 @@ Settings::Settings(Page* page) , m_showRepaintCounter(false) , m_experimentalNotificationsEnabled(false) , m_webGLEnabled(false) - , m_geolocationEnabled(true) , m_loadDeferringEnabled(true) +<<<<<<< HEAD #ifdef ANDROID_PLUGINS , m_pluginsOnDemand(false) #endif +======= + , m_tiledBackingStoreEnabled(false) +>>>>>>> webkit.org at r58033 { // A Frame may not have been created yet, so we initialize the AtomicString // hash before trying to use it. @@ -271,6 +280,11 @@ void Settings::setAllowFileAccessFromFileURLs(bool allowFileAccessFromFileURLs) m_allowFileAccessFromFileURLs = allowFileAccessFromFileURLs; } +void Settings::setSpatialNavigationEnabled(bool isSpatialNavigationEnabled) +{ + m_isSpatialNavigationEnabled = isSpatialNavigationEnabled; +} + void Settings::setJavaEnabled(bool isJavaEnabled) { m_isJavaEnabled = isJavaEnabled; @@ -281,14 +295,14 @@ void Settings::setImagesEnabled(bool areImagesEnabled) m_areImagesEnabled = areImagesEnabled; } -void Settings::setPluginsEnabled(bool arePluginsEnabled) +void Settings::setMediaEnabled(bool isMediaEnabled) { - m_arePluginsEnabled = arePluginsEnabled; + m_isMediaEnabled = isMediaEnabled; } -void Settings::setDatabasesEnabled(bool databasesEnabled) +void Settings::setPluginsEnabled(bool arePluginsEnabled) { - m_databasesEnabled = databasesEnabled; + m_arePluginsEnabled = arePluginsEnabled; } void Settings::setLocalStorageEnabled(bool localStorageEnabled) @@ -296,14 +310,25 @@ void Settings::setLocalStorageEnabled(bool localStorageEnabled) m_localStorageEnabled = localStorageEnabled; } +#if ENABLE(DOM_STORAGE) void Settings::setLocalStorageQuota(unsigned localStorageQuota) { m_localStorageQuota = localStorageQuota; } +void Settings::setSessionStorageQuota(unsigned sessionStorageQuota) +{ + m_sessionStorageQuota = sessionStorageQuota; +} +#endif + void Settings::setPrivateBrowsingEnabled(bool privateBrowsingEnabled) { + if (m_privateBrowsingEnabled == privateBrowsingEnabled) + return; + m_privateBrowsingEnabled = privateBrowsingEnabled; + m_page->privateBrowsingStateChanged(); } void Settings::setJavaScriptCanOpenWindowsAutomatically(bool javaScriptCanOpenWindowsAutomatically) @@ -631,9 +656,9 @@ void Settings::setNeedsSiteSpecificQuirks(bool needsQuirks) m_needsSiteSpecificQuirks = needsQuirks; } -void Settings::setFrameSetFlatteningEnabled(bool frameSetFlatteningEnabled) +void Settings::setFrameFlatteningEnabled(bool frameFlatteningEnabled) { - m_frameSetFlatteningEnabled = frameSetFlatteningEnabled; + m_frameFlatteningEnabled = frameFlatteningEnabled; } void Settings::setWebArchiveDebugModeEnabled(bool enabled) @@ -666,12 +691,12 @@ void Settings::setShouldPaintCustomScrollbars(bool shouldPaintCustomScrollbars) m_shouldPaintCustomScrollbars = shouldPaintCustomScrollbars; } -void Settings::setZoomsTextOnly(bool zoomsTextOnly) +void Settings::setZoomMode(ZoomMode mode) { - if (zoomsTextOnly == m_zoomsTextOnly) + if (mode == m_zoomMode) return; - m_zoomsTextOnly = zoomsTextOnly; + m_zoomMode = mode; setNeedsReapplyStylesInAllFrames(m_page); } @@ -762,14 +787,18 @@ void Settings::setWebGLEnabled(bool enabled) m_webGLEnabled = enabled; } -void Settings::setGeolocationEnabled(bool enabled) +void Settings::setLoadDeferringEnabled(bool enabled) { - m_geolocationEnabled = enabled; + m_loadDeferringEnabled = enabled; } -void Settings::setLoadDeferringEnabled(bool enabled) +void Settings::setTiledBackingStoreEnabled(bool enabled) { - m_loadDeferringEnabled = enabled; + m_tiledBackingStoreEnabled = enabled; +#if ENABLE(TILED_BACKING_STORE) + if (m_page->mainFrame()) + m_page->mainFrame()->setTiledBackingStoreEnabled(enabled); +#endif } } // namespace WebCore diff --git a/WebCore/page/Settings.h b/WebCore/page/Settings.h index 44b4642..6893eae 100644 --- a/WebCore/page/Settings.h +++ b/WebCore/page/Settings.h @@ -30,6 +30,7 @@ #include "AtomicString.h" #include "FontRenderingMode.h" #include "KURL.h" +#include "ZoomMode.h" namespace WebCore { @@ -127,6 +128,9 @@ namespace WebCore { bool blockNetworkImage() const { return m_blockNetworkImage; } #endif void setJavaScriptEnabled(bool); + // Instead of calling isJavaScriptEnabled directly, please consider calling + // ScriptController::canExecuteScripts, which takes things like the + // HTML sandbox attribute into account. bool isJavaScriptEnabled() const { return m_isJavaScriptEnabled; } void setWebSecurityEnabled(bool); @@ -141,15 +145,22 @@ namespace WebCore { void setJavaScriptCanOpenWindowsAutomatically(bool); bool javaScriptCanOpenWindowsAutomatically() const { return m_javaScriptCanOpenWindowsAutomatically; } + void setSpatialNavigationEnabled(bool); + bool isSpatialNavigationEnabled() const { return m_isSpatialNavigationEnabled; } + void setJavaEnabled(bool); bool isJavaEnabled() const { return m_isJavaEnabled; } void setImagesEnabled(bool); bool areImagesEnabled() const { return m_areImagesEnabled; } + void setMediaEnabled(bool); + bool isMediaEnabled() const { return m_isMediaEnabled; } + void setPluginsEnabled(bool); bool arePluginsEnabled() const { return m_arePluginsEnabled; } +<<<<<<< HEAD #ifdef ANDROID_PLUGINS void setPluginsOnDemand(bool onDemand) { m_pluginsOnDemand = onDemand; } bool arePluginsOnDemand() const { return m_pluginsOnDemand; } @@ -158,12 +169,22 @@ namespace WebCore { void setDatabasesEnabled(bool); bool databasesEnabled() const { return m_databasesEnabled; } +======= +>>>>>>> webkit.org at r58033 void setLocalStorageEnabled(bool); bool localStorageEnabled() const { return m_localStorageEnabled; } +#if ENABLE(DOM_STORAGE) void setLocalStorageQuota(unsigned); unsigned localStorageQuota() const { return m_localStorageQuota; } + // Allow clients concerned with memory consumption to set a quota on session storage + // since the memory used won't be released until the Page is destroyed. + // Default is noQuota. + void setSessionStorageQuota(unsigned); + unsigned sessionStorageQuota() const { return m_sessionStorageQuota; } +#endif + void setPrivateBrowsingEnabled(bool); bool privateBrowsingEnabled() const { return m_privateBrowsingEnabled; } @@ -232,8 +253,8 @@ namespace WebCore { void setDeveloperExtrasEnabled(bool); bool developerExtrasEnabled() const { return m_developerExtrasEnabled; } - void setFrameSetFlatteningEnabled(bool); - bool frameSetFlatteningEnabled() const { return m_frameSetFlatteningEnabled; } + void setFrameFlatteningEnabled(bool); + bool frameFlatteningEnabled() const { return m_frameFlatteningEnabled; } #ifdef ANDROID_META_SUPPORT void resetMetadataSettings(); @@ -300,8 +321,8 @@ namespace WebCore { void setShouldPaintCustomScrollbars(bool); bool shouldPaintCustomScrollbars() const { return m_shouldPaintCustomScrollbars; } - void setZoomsTextOnly(bool); - bool zoomsTextOnly() const { return m_zoomsTextOnly; } + void setZoomMode(ZoomMode); + ZoomMode zoomMode() const { return m_zoomMode; } void setEnforceCSSMIMETypeInStrictMode(bool); bool enforceCSSMIMETypeInStrictMode() { return m_enforceCSSMIMETypeInStrictMode; } @@ -350,11 +371,11 @@ namespace WebCore { void setWebGLEnabled(bool); bool webGLEnabled() const { return m_webGLEnabled; } - void setGeolocationEnabled(bool); - bool geolocationEnabled() const { return m_geolocationEnabled; } - void setLoadDeferringEnabled(bool); bool loadDeferringEnabled() const { return m_loadDeferringEnabled; } + + void setTiledBackingStoreEnabled(bool); + bool tiledBackingStoreEnabled() const { return m_tiledBackingStoreEnabled; } private: Page* m_page; @@ -413,15 +434,20 @@ namespace WebCore { bool m_blockNetworkImage : 1; #endif size_t m_maximumDecodedImageSize; +#if ENABLE(DOM_STORAGE) unsigned m_localStorageQuota; + unsigned m_sessionStorageQuota; +#endif unsigned m_pluginAllowedRunTime; + ZoomMode m_zoomMode; + bool m_isSpatialNavigationEnabled : 1; bool m_isJavaEnabled : 1; bool m_loadsImagesAutomatically : 1; bool m_privateBrowsingEnabled : 1; bool m_caretBrowsingEnabled : 1; bool m_areImagesEnabled : 1; + bool m_isMediaEnabled : 1; bool m_arePluginsEnabled : 1; - bool m_databasesEnabled : 1; bool m_localStorageEnabled : 1; bool m_isJavaScriptEnabled : 1; bool m_isWebSecurityEnabled : 1; @@ -447,13 +473,12 @@ namespace WebCore { bool m_authorAndUserStylesEnabled : 1; bool m_needsSiteSpecificQuirks : 1; unsigned m_fontRenderingMode : 1; - bool m_frameSetFlatteningEnabled : 1; + bool m_frameFlatteningEnabled : 1; bool m_webArchiveDebugModeEnabled : 1; bool m_localFileContentSniffingEnabled : 1; bool m_inApplicationChromeMode : 1; bool m_offlineWebApplicationCacheEnabled : 1; bool m_shouldPaintCustomScrollbars : 1; - bool m_zoomsTextOnly : 1; bool m_enforceCSSMIMETypeInStrictMode : 1; bool m_usesEncodingDetector : 1; bool m_allowScriptsToCloseWindows : 1; @@ -465,11 +490,14 @@ namespace WebCore { bool m_showRepaintCounter : 1; bool m_experimentalNotificationsEnabled : 1; bool m_webGLEnabled : 1; - bool m_geolocationEnabled : 1; bool m_loadDeferringEnabled : 1; +<<<<<<< HEAD #ifdef ANDROID_PLUGINS bool m_pluginsOnDemand : 1; #endif +======= + bool m_tiledBackingStoreEnabled : 1; +>>>>>>> webkit.org at r58033 #if USE(SAFARI_THEME) static bool gShouldPaintNativeControls; diff --git a/WebCore/page/SpatialNavigation.cpp b/WebCore/page/SpatialNavigation.cpp new file mode 100644 index 0000000..890eacd --- /dev/null +++ b/WebCore/page/SpatialNavigation.cpp @@ -0,0 +1,530 @@ +/* + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2009 Antonio Gomes <tonikitoo@webkit.org> + * + * 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 "SpatialNavigation.h" + +#include "Frame.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "HTMLFrameOwnerElement.h" +#include "IntRect.h" +#include "Node.h" +#include "Page.h" + +namespace WebCore { + +static long long spatialDistance(FocusDirection, const IntRect&, const IntRect&); +static IntRect renderRectRelativeToRootDocument(RenderObject*); +static RectsAlignment alignmentForRects(FocusDirection, const IntRect&, const IntRect&); +static bool areRectsFullyAligned(FocusDirection, const IntRect&, const IntRect&); +static bool areRectsPartiallyAligned(FocusDirection, const IntRect&, const IntRect&); +static bool isRectInDirection(FocusDirection, const IntRect&, const IntRect&); +static void deflateIfOverlapped(IntRect&, IntRect&); +static bool checkNegativeCoordsForNode(Node*, const IntRect&); + +void distanceDataForNode(FocusDirection direction, Node* start, FocusCandidate& candidate) +{ + RenderObject* startRender = start->renderer(); + if (!startRender) { + candidate.distance = maxDistance(); + return; + } + + RenderObject* destRender = candidate.node->renderer(); + if (!destRender) { + candidate.distance = maxDistance(); + return; + } + + IntRect curRect = renderRectRelativeToRootDocument(startRender); + IntRect targetRect = renderRectRelativeToRootDocument(destRender); + + // The bounding rectangle of two consecutive nodes can overlap. In such cases, + // deflate both. + deflateIfOverlapped(curRect, targetRect); + + // If empty rects or negative width or height, bail out. + if (curRect.isEmpty() || targetRect.isEmpty() + || targetRect.width() <= 0 || targetRect.height() <= 0) { + candidate.distance = maxDistance(); + return; + } + + // Negative coordinates can be used if node is scrolled up offscreen. + if (!checkNegativeCoordsForNode(start, curRect)) { + candidate.distance = maxDistance(); + return; + } + + if (!checkNegativeCoordsForNode(candidate.node, targetRect)) { + candidate.distance = maxDistance(); + return; + } + + if (!isRectInDirection(direction, curRect, targetRect)) { + candidate.distance = maxDistance(); + return; + } + + // The distance between two nodes is not to be considered alone when evaluating/looking + // for the best focus candidate node. Alignment of rects can be also a good point to be + // considered in order to make the algorithm to behavior in a more intuitive way. + candidate.alignment = alignmentForRects(direction, curRect, targetRect); + candidate.distance = spatialDistance(direction, curRect, targetRect); +} + +// FIXME: This function does not behave correctly with transformed frames. +static IntRect renderRectRelativeToRootDocument(RenderObject* render) +{ + ASSERT(render); + + IntRect rect(render->absoluteClippedOverflowRect()); + + if (rect.isEmpty()) { + Element* e = static_cast<Element*>(render->node()); + rect = e->getRect(); + } + + // In cases when the |render|'s associated node is in a scrollable inner + // document, we only consider its scrollOffset if it is not offscreen. + Node* node = render->node(); + Document* mainDocument = node->document()->page()->mainFrame()->document(); + bool considerScrollOffset = !(hasOffscreenRect(node) && node->document() != mainDocument); + + if (considerScrollOffset) { + if (FrameView* frameView = render->node()->document()->view()) + rect.move(-frameView->scrollOffset()); + } + + // Handle nested frames. + for (Frame* frame = render->document()->frame(); frame; frame = frame->tree()->parent()) { + if (HTMLFrameOwnerElement* ownerElement = frame->ownerElement()) + rect.move(ownerElement->offsetLeft(), ownerElement->offsetTop()); + } + + return rect; +} + +static RectsAlignment alignmentForRects(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect) +{ + if (areRectsFullyAligned(direction, curRect, targetRect)) + return Full; + + if (areRectsPartiallyAligned(direction, curRect, targetRect)) + return Partial; + + return None; +} + +static inline bool isHorizontalMove(FocusDirection direction) +{ + return direction == FocusDirectionLeft || direction == FocusDirectionRight; +} + +static inline int start(FocusDirection direction, const IntRect& rect) +{ + return isHorizontalMove(direction) ? rect.y() : rect.x(); +} + +static inline int middle(FocusDirection direction, const IntRect& rect) +{ + IntPoint center(rect.center()); + return isHorizontalMove(direction) ? center.y(): center.x(); +} + +static inline int end(FocusDirection direction, const IntRect& rect) +{ + return isHorizontalMove(direction) ? rect.bottom() : rect.right(); +} + +// This method checks if rects |a| and |b| are fully aligned either vertically or +// horizontally. In general, rects whose central point falls between the top or +// bottom of each other are considered fully aligned. +// Rects that match this criteria are preferable target nodes in move focus changing +// operations. +// * a = Current focused node's rect. +// * b = Focus candidate node's rect. +static bool areRectsFullyAligned(FocusDirection direction, const IntRect& a, const IntRect& b) +{ + int aStart, bStart, aEnd, bEnd; + + switch (direction) { + case FocusDirectionLeft: + aStart = a.x(); + bEnd = b.right(); + break; + case FocusDirectionRight: + aStart = b.x(); + bEnd = a.right(); + break; + case FocusDirectionUp: + aStart = a.y(); + bEnd = b.y(); + break; + case FocusDirectionDown: + aStart = b.y(); + bEnd = a.y(); + break; + default: + ASSERT_NOT_REACHED(); + return false; + } + + if (aStart < bEnd) + return false; + + aStart = start(direction, a); + bStart = start(direction, b); + + int aMiddle = middle(direction, a); + int bMiddle = middle(direction, b); + + aEnd = end(direction, a); + bEnd = end(direction, b); + + // Picture of the totally aligned logic: + // + // Horizontal Vertical Horizontal Vertical + // **************************** ***************************** + // * _ * _ _ _ _ * * _ * _ _ * + // * |_| _ * |_|_|_|_| * * _ |_| * |_|_| * + // * |_|....|_| * . * * |_|....|_| * . * + // * |_| |_| (1) . * * |_| |_| (2) . * + // * |_| * _._ * * |_| * _ _._ _ * + // * * |_|_| * * * |_|_|_|_| * + // * * * * * * + // **************************** ***************************** + + // Horizontal Vertical Horizontal Vertical + // **************************** ***************************** + // * _......_ * _ _ _ _ * * _ * _ _ _ _ * + // * |_| |_| * |_|_|_|_| * * |_| _ * |_|_|_|_| * + // * |_| |_| * . * * |_| |_| * . * + // * |_| (3) . * * |_|....|_| (4) . * + // * * ._ _ * * * _ _. * + // * * |_|_| * * * |_|_| * + // * * * * * * + // **************************** ***************************** + + return ((bMiddle >= aStart && bMiddle <= aEnd) // (1) + || (aMiddle >= bStart && aMiddle <= bEnd) // (2) + || (bStart == aStart) // (3) + || (bEnd == aEnd)); // (4) +} + +// This method checks if |start| and |dest| have a partial intersection, either +// horizontally or vertically. +// * a = Current focused node's rect. +// * b = Focus candidate node's rect. +static bool areRectsPartiallyAligned(FocusDirection direction, const IntRect& a, const IntRect& b) +{ + int aStart = start(direction, a); + int bStart = start(direction, b); + int bMiddle = middle(direction, b); + int aEnd = end(direction, a); + int bEnd = end(direction, b); + + // Picture of the partially aligned logic: + // + // Horizontal Vertical + // ******************************** + // * _ * _ _ _ * + // * |_| * |_|_|_| * + // * |_|.... _ * . . * + // * |_| |_| * . . * + // * |_|....|_| * ._._ _ * + // * |_| * |_|_|_| * + // * |_| * * + // * * * + // ******************************** + // + // ... and variants of the above cases. + return ((bStart >= aStart && bStart <= aEnd) + || (bStart >= aStart && bStart <= aEnd) + || (bEnd >= aStart && bEnd <= aEnd) + || (bMiddle >= aStart && bMiddle <= aEnd) + || (bEnd >= aStart && bEnd <= aEnd)); +} + +// Return true if rect |a| is below |b|. False otherwise. +static inline bool below(const IntRect& a, const IntRect& b) +{ + return a.y() > b.bottom(); +} + +// Return true if rect |a| is on the right of |b|. False otherwise. +static inline bool rightOf(const IntRect& a, const IntRect& b) +{ + return a.x() > b.right(); +} + +// * a = Current focused node's rect. +// * b = Focus candidate node's rect. +static long long spatialDistance(FocusDirection direction, const IntRect& a, const IntRect& b) +{ + int x1 = 0, y1 = 0, x2 = 0, y2 = 0; + + if (direction == FocusDirectionLeft) { + // #1 |--| + // + // #2 |--| |--| + // + // #3 |--| + + x1 = a.x(); + x2 = b.right(); + + if (below(a, b)) { + // #1 The a rect is below b. + y1 = a.y(); + y2 = b.bottom(); + } else if (below(b, a)) { + // #3 The b rect is below a. + y1 = a.bottom(); + y2 = b.y(); + } else { + // #2 Both b and a share some common y's. + y1 = 0; + y2 = 0; + } + } else if (direction == FocusDirectionRight) { + // |--| #1 + // + // |--| |--| #2 + // + // |--| #3 + + x1 = a.right(); + x2 = b.x(); + + if (below(a, b)) { + // #1 The b rect is above a. + y1 = a.y(); + y2 = b.bottom(); + } else if (below(b, a)) { + // #3 The b rect is below a. + y1 = a.bottom(); + y2 = b.y(); + } else { + // #2 Both b and a share some common y's. + y1 = 0; + y2 = 0; + } + } else if (direction == FocusDirectionUp) { + // + // #1 #2 #3 + // + // |--| |--| |--| + // + // |--| + + y1 = a.y(); + y2 = b.bottom(); + + if (rightOf(a, b)) { + // #1 The b rect is to the left of a. + x1 = a.x(); + x2 = b.right(); + } else if (rightOf(b, a)) { + // #3 The b rect is to the right of a. + x1 = a.right(); + x2 = b.x(); + } else { + // #2 Both b and a share some common x's. + x1 = 0; + x2 = 0; + } + } else if (direction == FocusDirectionDown) { + // |--| + // + // |--| |--| |--| + // + // #1 #2 #3 + + y1 = a.bottom(); + y2 = b.y(); + + if (rightOf(a, b)) { + // #1 The b rect is to the left of a. + x1 = a.x(); + x2 = b.right(); + } else if (rightOf(b, a)) { + // #3 The b rect is to the right of a + x1 = a.right(); + x2 = b.x(); + } else { + // #2 Both b and a share some common x's. + x1 = 0; + x2 = 0; + } + } + + long long dx = x1 - x2; + long long dy = y1 - y2; + + long long distance = (dx * dx) + (dy * dy); + + if (distance < 0) + distance *= -1; + + return distance; +} + +static bool isRectInDirection(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect) +{ + IntPoint center(targetRect.center()); + int targetMiddle = isHorizontalMove(direction) ? center.x() : center.y(); + + switch (direction) { + case FocusDirectionLeft: + return targetMiddle < curRect.x(); + case FocusDirectionRight: + return targetMiddle > curRect.right(); + case FocusDirectionUp: + return targetMiddle < curRect.y(); + case FocusDirectionDown: + return targetMiddle > curRect.bottom(); + default: + ASSERT_NOT_REACHED(); + } + + return false; +} + +// Checks if |node| is offscreen the visible area (viewport) of its container +// document. In case it is, one can scroll in direction or take any different +// desired action later on. +bool hasOffscreenRect(Node* node) +{ + // Get the FrameView in which |node| is (which means the current viewport if |node| + // is not in an inner document), so we can check if its content rect is visible + // before we actually move the focus to it. + FrameView* frameView = node->document()->view(); + if (!frameView) + return true; + + IntRect containerViewportRect = frameView->visibleContentRect(); + + RenderObject* render = node->renderer(); + if (!render) + return true; + + IntRect rect(render->absoluteClippedOverflowRect()); + if (rect.isEmpty()) + return true; + + return !containerViewportRect.intersects(rect); +} + +// In a bottom-up way, this method tries to scroll |frame| in a given direction +// |direction|, going up in the frame tree hierarchy in case it does not succeed. +bool scrollInDirection(Frame* frame, FocusDirection direction) +{ + if (!frame) + return false; + + ScrollDirection scrollDirection; + + switch (direction) { + case FocusDirectionLeft: + scrollDirection = ScrollLeft; + break; + case FocusDirectionRight: + scrollDirection = ScrollRight; + break; + case FocusDirectionUp: + scrollDirection = ScrollUp; + break; + case FocusDirectionDown: + scrollDirection = ScrollDown; + break; + default: + return false; + } + + return frame->eventHandler()->scrollRecursively(scrollDirection, ScrollByLine); +} + +void scrollIntoView(Element* element) +{ + // NOTE: Element's scrollIntoView method could had been used here, but + // it is preferable to inflate |element|'s bounding rect a bit before + // scrolling it for accurate reason. + // Element's scrollIntoView method does not provide this flexibility. + static const int fudgeFactor = 2; + IntRect bounds = element->getRect(); + bounds.inflate(fudgeFactor); + element->renderer()->enclosingLayer()->scrollRectToVisible(bounds); +} + +bool isInRootDocument(Node* node) +{ + if (!node) + return false; + + Document* rootDocument = node->document()->page()->mainFrame()->document(); + return node->document() == rootDocument; +} + +static void deflateIfOverlapped(IntRect& a, IntRect& b) +{ + if (!a.intersects(b) || a.contains(b) || b.contains(a)) + return; + + static const int fudgeFactor = -2; + + // Avoid negative width or height values. + if ((a.width() + 2 * fudgeFactor > 0) && (a.height() + 2 * fudgeFactor > 0)) + a.inflate(fudgeFactor); + + if ((b.width() + 2 * fudgeFactor > 0) && (b.height() + 2 * fudgeFactor > 0)) + b.inflate(fudgeFactor); +} + +static bool checkNegativeCoordsForNode(Node* node, const IntRect& curRect) +{ + ASSERT(node || node->renderer()); + + if (curRect.x() > 0 && curRect.y() > 0) + return true; + + bool canBeScrolled = false; + + RenderObject* renderer = node->renderer(); + for (; renderer; renderer = renderer->parent()) { + if (renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()) { + canBeScrolled = true; + break; + } + } + + return canBeScrolled; +} + +} // namespace WebCore diff --git a/WebCore/page/SpatialNavigation.h b/WebCore/page/SpatialNavigation.h new file mode 100644 index 0000000..90ff1cf --- /dev/null +++ b/WebCore/page/SpatialNavigation.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2009 Antonio Gomes <tonikitoo@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef SpatialNavigation_h +#define SpatialNavigation_h + +#include "FocusDirection.h" +#include "Node.h" + +#include <limits> + +namespace WebCore { + +class Element; +class Frame; +class IntRect; +class RenderObject; + +using namespace std; + +inline long long maxDistance() +{ + return numeric_limits<long long>::max(); +} + +// Spatially speaking, two given elements in a web page can be: +// 1) Fully aligned: There is a full intersection between the rects, either +// vertically or horizontally. +// +// * Horizontally * Vertically +// _ +// |_| _ _ _ _ _ _ +// |_|...... _ |_|_|_|_|_|_| +// |_| |_| . . +// |_|......|_| OR . . +// |_| |_| . . +// |_|......|_| _ _ _ _ +// |_| |_|_|_|_| +// +// +// 2) Partially aligned: There is a partial intersection between the rects, either +// vertically or horizontally. +// +// * Horizontally * Vertically +// _ _ _ _ _ _ +// |_| |_|_|_|_|_| +// |_|.... _ OR . . +// |_| |_| . . +// |_|....|_| ._._ _ +// |_| |_|_|_| +// |_| +// +// 3) Or, otherwise, not aligned at all. +// +// * Horizontally * Vertically +// _ _ _ _ _ +// |_| |_|_|_|_| +// |_| . +// |_| . +// . OR . +// _ . ._ _ _ _ _ +// |_| |_|_|_|_|_| +// |_| +// |_| +// +// "Totally Aligned" elements are preferable candidates to move +// focus to over "Partially Aligned" ones, that on its turns are +// more preferable than "Not Aligned". +enum RectsAlignment { + None = 0, + Partial, + Full +}; + +struct FocusCandidate { + FocusCandidate() + : node(0) + , distance(maxDistance()) + , parentDistance(maxDistance()) + , alignment(None) + , parentAlignment(None) + { + } + + FocusCandidate(Node* n) + : node(n) + , distance(maxDistance()) + , parentDistance(maxDistance()) + , alignment(None) + , parentAlignment(None) + { + } + + bool isNull() const { return !node; } + Document* document() const { return node ? node->document() : 0; } + + Node* node; + long long distance; + long long parentDistance; + RectsAlignment alignment; + RectsAlignment parentAlignment; +}; + +void distanceDataForNode(FocusDirection direction, Node* start, FocusCandidate& candidate); +bool scrollInDirection(Frame*, FocusDirection); +void scrollIntoView(Element*); +bool hasOffscreenRect(Node*); +bool isInRootDocument(Node*); + +} // namspace WebCore + +#endif // SpatialNavigation_h diff --git a/WebCore/page/UserContentURLPattern.cpp b/WebCore/page/UserContentURLPattern.cpp index 5f0a311..09eb678 100644 --- a/WebCore/page/UserContentURLPattern.cpp +++ b/WebCore/page/UserContentURLPattern.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -75,28 +75,26 @@ bool UserContentURLPattern::parse(const String& pattern) int pathStartPos = 0; - if (m_scheme == "file") + if (equalIgnoringCase(m_scheme, "file")) pathStartPos = hostStartPos; else { int hostEndPos = pattern.find("/", hostStartPos); if (hostEndPos == -1) return false; - + m_host = pattern.substring(hostStartPos, hostEndPos - hostStartPos); + m_matchSubdomains = false; - // The first component can be '*', which means to match all subdomains. - Vector<String> hostComponents; - m_host.split(".", hostComponents); - if (hostComponents[0] == "*") { - m_matchSubdomains = true; + if (m_host == "*") { + // The pattern can be just '*', which means match all domains. 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 + "."; - } + m_matchSubdomains = true; + } else if (m_host.startsWith("*.")) { + // The first component can be '*', which means to match all subdomains. + m_host = m_host.substring(2); // Length of "*." + m_matchSubdomains = true; } - + // No other '*' can occur in the host. if (m_host.find("*") != -1) return false; @@ -114,10 +112,10 @@ bool UserContentURLPattern::matches(const KURL& test) const if (m_invalid) return false; - if (test.protocol() != m_scheme) + if (!equalIgnoringCase(test.protocol(), m_scheme)) return false; - if (!matchesHost(test)) + if (!equalIgnoringCase(m_scheme, "file") && !matchesHost(test)) return false; return matchesPath(test); @@ -125,7 +123,8 @@ bool UserContentURLPattern::matches(const KURL& test) const bool UserContentURLPattern::matchesHost(const KURL& test) const { - if (test.host() == m_host) + const String& host = test.host(); + if (equalIgnoringCase(host, m_host)) return true; if (!m_matchSubdomains) @@ -136,8 +135,14 @@ bool UserContentURLPattern::matchesHost(const KURL& test) const if (!m_host.length()) return true; - // Check if the test host is a subdomain of our host. - return test.host().endsWith(m_host, false); + // Check if the domain is a subdomain of our host. + if (!host.endsWith(m_host, false)) + return false; + + ASSERT(host.length() > m_host.length()); + + // Check that the character before the suffix is a period. + return host[host.length() - m_host.length() - 1] == '.'; } struct MatchTester diff --git a/WebCore/page/UserContentURLPattern.h b/WebCore/page/UserContentURLPattern.h index 0b1a248..3450ed1 100644 --- a/WebCore/page/UserContentURLPattern.h +++ b/WebCore/page/UserContentURLPattern.h @@ -35,12 +35,16 @@ class KURL; class UserContentURLPattern { public: + UserContentURLPattern() : m_invalid(true), m_matchSubdomains(false) { } + UserContentURLPattern(const String& pattern) : m_matchSubdomains(false) { m_invalid = !parse(pattern); } + bool isValid() const { return !m_invalid; } + bool matches(const KURL&) const; const String& scheme() const { return m_scheme; } diff --git a/WebCore/page/XSSAuditor.cpp b/WebCore/page/XSSAuditor.cpp index b71fa49..9e225ff 100644 --- a/WebCore/page/XSSAuditor.cpp +++ b/WebCore/page/XSSAuditor.cpp @@ -31,7 +31,6 @@ #include <wtf/Vector.h> #include "Console.h" -#include "CString.h" #include "DocumentLoader.h" #include "DOMWindow.h" #include "Frame.h" @@ -41,6 +40,7 @@ #include "ScriptSourceCode.h" #include "Settings.h" #include "TextResourceDecoder.h" +#include <wtf/text/CString.h> using namespace WTF; @@ -70,6 +70,16 @@ static bool isIllegalURICharacter(UChar c) return (c == '\'' || c == '"' || c == '<' || c == '>'); } +String XSSAuditor::CachingURLCanonicalizer::canonicalizeURL(FormData* formData, const TextEncoding& encoding, bool decodeEntities, + bool decodeURLEscapeSequencesTwice) +{ + if (decodeEntities == m_decodeEntities && decodeURLEscapeSequencesTwice == m_decodeURLEscapeSequencesTwice + && encoding == m_encoding && formData == m_formData) + return m_cachedCanonicalizedURL; + m_formData = formData; + return canonicalizeURL(formData->flattenToString(), encoding, decodeEntities, decodeURLEscapeSequencesTwice); +} + String XSSAuditor::CachingURLCanonicalizer::canonicalizeURL(const String& url, const TextEncoding& encoding, bool decodeEntities, bool decodeURLEscapeSequencesTwice) { @@ -82,11 +92,19 @@ String XSSAuditor::CachingURLCanonicalizer::canonicalizeURL(const String& url, c m_encoding = encoding; m_decodeEntities = decodeEntities; m_decodeURLEscapeSequencesTwice = decodeURLEscapeSequencesTwice; + ++m_generation; return m_cachedCanonicalizedURL; } +void XSSAuditor::CachingURLCanonicalizer::clear() +{ + m_formData.clear(); + m_inputURL = String(); +} + XSSAuditor::XSSAuditor(Frame* frame) : m_frame(frame) + , m_generationOfSuffixTree(-1) { } @@ -290,21 +308,15 @@ bool XSSAuditor::isSameOriginResource(const String& url) const return (m_frame->document()->url().host() == resourceURL.host() && resourceURL.query().isEmpty()); } -bool XSSAuditor::shouldFullPageBlockForXSSProtectionHeader() const +XSSProtectionDisposition XSSAuditor::xssProtection() const { - // If we detect an XSS attack and find the HTTP header "X-XSS-Protection: 12" then - // we will stop loading the page as opposed to ignoring the script. The value "12" - // came from a personal communication, see <https://bugs.webkit.org/show_bug.cgi?id=27312> - // for more details. DEFINE_STATIC_LOCAL(String, XSSProtectionHeader, ("X-XSS-Protection")); Frame* frame = m_frame; if (frame->document()->url() == blankURL()) frame = m_frame->tree()->parent(); - // We strip any whitespace characters to conform to the behavior in Internet Explorer. - String xssProtectionValue = frame->loader()->documentLoader()->response().httpHeaderField(XSSProtectionHeader).stripWhiteSpace(); - return (xssProtectionValue.length() >= 2 && xssProtectionValue[0] == '1' && xssProtectionValue[1] == '2'); + return parseXSSProtectionHeader(frame->loader()->documentLoader()->response().httpHeaderField(XSSProtectionHeader)); } bool XSSAuditor::findInRequest(const FindTask& task) const @@ -318,11 +330,24 @@ bool XSSAuditor::findInRequest(const FindTask& task) const result = findInRequest(m_frame, task); blockFrame = m_frame; } - if (result && blockFrame && shouldFullPageBlockForXSSProtectionHeader()) { - blockFrame->loader()->stopAllLoaders(); - blockFrame->redirectScheduler()->scheduleLocationChange(blankURL(), String()); + if (!result) + return false; + + switch (xssProtection()) { + case XSSProtectionDisabled: + return false; + case XSSProtectionEnabled: + break; + case XSSProtectionBlockEnabled: + if (blockFrame) { + blockFrame->loader()->stopAllLoaders(); + blockFrame->redirectScheduler()->scheduleLocationChange(blankURL(), String()); + } + break; + default: + ASSERT_NOT_REACHED(); } - return result; + return true; } bool XSSAuditor::findInRequest(Frame* frame, const FindTask& task) const @@ -341,6 +366,12 @@ bool XSSAuditor::findInRequest(Frame* frame, const FindTask& task) const const bool hasFormData = formDataObj && !formDataObj->isEmpty(); String pageURL = frame->document()->url().string(); + if (!hasFormData) { + // We clear out our form data caches, in case we're holding onto a bunch of memory. + m_formDataCache.clear(); + m_formDataSuffixTree.clear(); + } + String canonicalizedString; if (!hasFormData && task.string.length() > 2 * pageURL.length()) { // Q: Why do we bother to do this check at all? @@ -368,7 +399,7 @@ bool XSSAuditor::findInRequest(Frame* frame, const FindTask& task) const if (!task.context.isEmpty()) canonicalizedString = task.context + canonicalizedString; - String decodedPageURL = m_cache.canonicalizeURL(pageURL, frame->document()->decoder()->encoding(), task.decodeEntities, task.decodeURLEscapeSequencesTwice); + String decodedPageURL = m_pageURLCache.canonicalizeURL(pageURL, frame->document()->decoder()->encoding(), task.decodeEntities, task.decodeURLEscapeSequencesTwice); if (task.allowRequestIfNoIllegalURICharacters && !hasFormData && decodedPageURL.find(&isIllegalURICharacter, 0) == -1) return false; // Injection is impossible because the request does not contain any illegal URI characters. @@ -377,7 +408,17 @@ bool XSSAuditor::findInRequest(Frame* frame, const FindTask& task) const return true; // We've found the string in the GET data. if (hasFormData) { - String decodedFormData = m_cache.canonicalizeURL(formDataObj->flattenToString(), frame->document()->decoder()->encoding(), task.decodeEntities, task.decodeURLEscapeSequencesTwice); + String decodedFormData = m_formDataCache.canonicalizeURL(formDataObj, frame->document()->decoder()->encoding(), task.decodeEntities, task.decodeURLEscapeSequencesTwice); + + if (m_generationOfSuffixTree != m_formDataCache.generation()) { + m_formDataSuffixTree = new SuffixTree<ASCIICodebook>(decodedFormData, 5); + m_generationOfSuffixTree = m_formDataCache.generation(); + } + + // Try a fast-reject via the suffixTree. + if (m_formDataSuffixTree && !m_formDataSuffixTree->mightContain(canonicalizedString)) + return false; + 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 3ad50a1..d2f525d 100644 --- a/WebCore/page/XSSAuditor.h +++ b/WebCore/page/XSSAuditor.h @@ -27,11 +27,14 @@ #ifndef XSSAuditor_h #define XSSAuditor_h +#include "HTTPParsers.h" #include "PlatformString.h" +#include "SuffixTree.h" #include "TextEncoding.h" namespace WebCore { + class FormData; class Frame; class ScriptSourceCode; @@ -105,16 +108,26 @@ namespace WebCore { class CachingURLCanonicalizer { public: - CachingURLCanonicalizer() : m_decodeEntities(false), m_decodeURLEscapeSequencesTwice(false) { } + CachingURLCanonicalizer() : m_decodeEntities(false), m_decodeURLEscapeSequencesTwice(false), m_generation(0) { } + String canonicalizeURL(FormData*, const TextEncoding& encoding, bool decodeEntities, + bool decodeURLEscapeSequencesTwice); String canonicalizeURL(const String& url, const TextEncoding& encoding, bool decodeEntities, bool decodeURLEscapeSequencesTwice); + void clear(); + + int generation() const { return m_generation; } + private: // The parameters we were called with last. String m_inputURL; TextEncoding m_encoding; bool m_decodeEntities; bool m_decodeURLEscapeSequencesTwice; + RefPtr<FormData> m_formData; + + // Incremented every time we see a new URL. + int m_generation; // The cached result. String m_cachedCanonicalizedURL; @@ -144,13 +157,22 @@ namespace WebCore { bool findInRequest(const FindTask&) const; bool findInRequest(Frame*, const FindTask&) const; - bool shouldFullPageBlockForXSSProtectionHeader() const; + XSSProtectionDisposition xssProtection() const; // The frame to audit. Frame* m_frame; // A state store to help us avoid canonicalizing the same URL repeated. - mutable CachingURLCanonicalizer m_cache; + // When a page has form data, we need two caches: one to store the + // canonicalized URL and another to store the cannonicalized form + // data. If we only had one cache, we'd always generate a cache miss + // and load some pages extremely slowly. + // https://bugs.webkit.org/show_bug.cgi?id=35373 + mutable CachingURLCanonicalizer m_pageURLCache; + mutable CachingURLCanonicalizer m_formDataCache; + + mutable OwnPtr<SuffixTree<ASCIICodebook> > m_formDataSuffixTree; + mutable int m_generationOfSuffixTree; }; } // namespace WebCore diff --git a/WebCore/page/ZoomMode.h b/WebCore/page/ZoomMode.h new file mode 100644 index 0000000..3f02184 --- /dev/null +++ b/WebCore/page/ZoomMode.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010 Research in Motion Ltd. http://www.rim.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef ZoomMode_h +#define ZoomMode_h + +namespace WebCore { + +enum ZoomMode { + ZoomPage, + ZoomTextOnly +}; + +} + +#endif diff --git a/WebCore/page/animation/AnimationBase.cpp b/WebCore/page/animation/AnimationBase.cpp index 2a2ab4b..d9282cb 100644 --- a/WebCore/page/animation/AnimationBase.cpp +++ b/WebCore/page/animation/AnimationBase.cpp @@ -33,7 +33,6 @@ #include "CSSMutableStyleDeclaration.h" #include "CSSPropertyLonghand.h" #include "CSSPropertyNames.h" -#include "CString.h" #include "CompositeAnimation.h" #include "Document.h" #include "EventNames.h" @@ -136,9 +135,9 @@ static inline ShadowStyle blendFunc(const AnimationBase* anim, ShadowStyle from, static inline ShadowData* blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress) { ASSERT(from && to); - return new ShadowData(blendFunc(anim, from->x, to->x, progress), blendFunc(anim, from->y, to->y, progress), - blendFunc(anim, from->blur, to->blur, progress), blendFunc(anim, from->spread, to->spread, progress), - blendFunc(anim, from->style, to->style, progress), blendFunc(anim, from->color, to->color, progress)); + return new ShadowData(blendFunc(anim, from->x(), to->x(), progress), blendFunc(anim, from->y(), to->y(), progress), + blendFunc(anim, from->blur(), to->blur(), progress), blendFunc(anim, from->spread(), to->spread(), progress), + blendFunc(anim, from->style(), to->style(), progress), blendFunc(anim, from->color(), to->color(), progress)); } static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress) @@ -297,18 +296,19 @@ public: }; #endif // USE(ACCELERATED_COMPOSITING) -class PropertyWrapperShadow : public PropertyWrapperGetter<ShadowData*> { +class PropertyWrapperShadow : public PropertyWrapperBase { public: - PropertyWrapperShadow(int prop, ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(ShadowData*, bool)) - : PropertyWrapperGetter<ShadowData*>(prop, getter) + PropertyWrapperShadow(int prop, const ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(ShadowData*, bool)) + : PropertyWrapperBase(prop) + , m_getter(getter) , m_setter(setter) { } virtual bool equals(const RenderStyle* a, const RenderStyle* b) const { - ShadowData* shadowA = (a->*m_getter)(); - ShadowData* shadowB = (b->*m_getter)(); + const ShadowData* shadowA = (a->*m_getter)(); + const ShadowData* shadowB = (b->*m_getter)(); while (true) { if (!shadowA && !shadowB) // end of both lists @@ -320,8 +320,8 @@ public: if (*shadowA != *shadowB) return false; - shadowA = shadowA->next; - shadowB = shadowB->next; + shadowA = shadowA->next(); + shadowB = shadowB->next(); } return true; @@ -329,29 +329,30 @@ public: virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const { - ShadowData* shadowA = (a->*m_getter)(); - ShadowData* shadowB = (b->*m_getter)(); + const ShadowData* shadowA = (a->*m_getter)(); + const ShadowData* shadowB = (b->*m_getter)(); ShadowData defaultShadowData(0, 0, 0, 0, Normal, Color::transparent); ShadowData* newShadowData = 0; while (shadowA || shadowB) { - ShadowData* srcShadow = shadowA ? shadowA : &defaultShadowData; - ShadowData* dstShadow = shadowB ? shadowB : &defaultShadowData; + const ShadowData* srcShadow = shadowA ? shadowA : &defaultShadowData; + const ShadowData* dstShadow = shadowB ? shadowB : &defaultShadowData; if (!newShadowData) newShadowData = blendFunc(anim, srcShadow, dstShadow, progress); else - newShadowData->next = blendFunc(anim, srcShadow, dstShadow, progress); + newShadowData->setNext(blendFunc(anim, srcShadow, dstShadow, progress)); - shadowA = shadowA ? shadowA->next : 0; - shadowB = shadowB ? shadowB->next : 0; + shadowA = shadowA ? shadowA->next() : 0; + shadowB = shadowB ? shadowB->next() : 0; } (dst->*m_setter)(newShadowData, false); } private: + const ShadowData* (RenderStyle::*m_getter)() const; void (RenderStyle::*m_setter)(ShadowData*, bool); }; @@ -918,8 +919,8 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // Execute state machine switch (m_animState) { case AnimationStateNew: - ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning || input == AnimationStateInputPlayStatePaused); - if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning) { + ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning || input == AnimationStateInputPlayStatePaused); + if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning) { m_requestedStartTime = beginAnimationUpdateTime(); m_animState = AnimationStateStartWaitTimer; } @@ -1021,6 +1022,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) ASSERT(input == AnimationStateInputEndTimerFired || input == AnimationStateInputPlayStatePaused); if (input == AnimationStateInputEndTimerFired) { + ASSERT(param >= 0); // End timer fired, finish up onAnimationEnd(param); @@ -1028,7 +1030,10 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) m_animState = AnimationStateDone; if (m_object) { - resumeOverriddenAnimations(); + if (m_animation->fillsForwards()) + m_animState = AnimationStateFillingForwards; + else + resumeOverriddenAnimations(); // Fire off another style change so we can set the final value m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node()); @@ -1042,7 +1047,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // |this| may be deleted here break; case AnimationStatePausedWaitTimer: - ASSERT(input == AnimationStateInputPlayStateRunnning); + ASSERT(input == AnimationStateInputPlayStateRunning); ASSERT(paused()); // Update the times m_startTime += beginAnimationUpdateTime() - m_pauseTime; @@ -1058,7 +1063,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) // AnimationStatePausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation. // When the AnimationStateInputStartTimeSet comes in and we were in AnimationStatePausedRun, we will notice // that we have already set the startTime and will ignore it. - ASSERT(input == AnimationStateInputPlayStateRunnning || input == AnimationStateInputStartTimeSet); + ASSERT(input == AnimationStateInputPlayStateRunning || input == AnimationStateInputStartTimeSet); ASSERT(paused()); // If we are paused, but we get the callback that notifies us that an accelerated animation started, @@ -1093,6 +1098,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param) m_fallbackAnimating = !started; } break; + case AnimationStateFillingForwards: case AnimationStateDone: // We're done. Stay in this state until we are deleted break; @@ -1152,14 +1158,14 @@ void AnimationBase::fireAnimationEventsIfNeeded() void AnimationBase::updatePlayState(bool run) { if (paused() == run || isNew()) - updateStateMachine(run ? AnimationStateInputPlayStateRunnning : AnimationStateInputPlayStatePaused, -1); + updateStateMachine(run ? AnimationStateInputPlayStateRunning : AnimationStateInputPlayStatePaused, -1); } double AnimationBase::timeToNextService() { // Returns the time at which next service is required. -1 means no service is required. 0 means // service is required now, and > 0 means service is required that many seconds in the future. - if (paused() || isNew()) + if (paused() || isNew() || m_animState == AnimationStateFillingForwards) return -1; if (m_animState == AnimationStateStartWaitTimer) { @@ -1184,8 +1190,10 @@ double AnimationBase::progress(double scale, double offset, const TimingFunction if (m_animation->iterationCount() > 0) dur *= m_animation->iterationCount(); - if (postActive() || !m_animation->duration() || (m_animation->iterationCount() > 0 && elapsedTime >= dur)) + if (postActive() || !m_animation->duration()) return 1.0; + if (m_animation->iterationCount() > 0 && elapsedTime >= dur) + return (m_animation->iterationCount() % 2) ? 1.0 : 0.0; // Compute the fractional time, taking into account direction. // There is no need to worry about iterations, we assume that we would have diff --git a/WebCore/page/animation/AnimationBase.h b/WebCore/page/animation/AnimationBase.h index c367e0a..a957119 100644 --- a/WebCore/page/animation/AnimationBase.h +++ b/WebCore/page/animation/AnimationBase.h @@ -71,7 +71,8 @@ public: AnimationStatePausedWaitTimer, // in pause mode when animation started AnimationStatePausedWaitResponse, // animation paused when in STARTING state AnimationStatePausedRun, // animation paused when in LOOPING or ENDING state - AnimationStateDone // end timer fired, animation finished and removed + AnimationStateDone, // end timer fired, animation finished and removed + AnimationStateFillingForwards // animation has ended and is retaining its final value }; enum AnimStateInput { @@ -85,7 +86,7 @@ public: AnimationStateInputEndTimerFired, // end timer fired AnimationStateInputPauseOverride, // pause an animation due to override AnimationStateInputResumeOverride, // resume an overridden animation - AnimationStateInputPlayStateRunnning, // play state paused -> running + AnimationStateInputPlayStateRunning, // play state paused -> running AnimationStateInputPlayStatePaused, // play state running -> paused AnimationStateInputEndAnimation // force an end from any state }; diff --git a/WebCore/page/animation/AnimationController.cpp b/WebCore/page/animation/AnimationController.cpp index 422c154..cb609a5 100644 --- a/WebCore/page/animation/AnimationController.cpp +++ b/WebCore/page/animation/AnimationController.cpp @@ -134,6 +134,9 @@ void AnimationControllerPrivate::updateAnimationTimer(bool callSetChanged/* = fa void AnimationControllerPrivate::updateStyleIfNeededDispatcherFired(Timer<AnimationControllerPrivate>*) { + // Protect the frame from getting destroyed in the event handler + RefPtr<Frame> protector = m_frame; + // fire all the events Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = m_eventsToDispatch.end(); for (Vector<EventToDispatch>::const_iterator it = m_eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) { diff --git a/WebCore/page/animation/CompositeAnimation.cpp b/WebCore/page/animation/CompositeAnimation.cpp index 34f03c7..0f238fd 100644 --- a/WebCore/page/animation/CompositeAnimation.cpp +++ b/WebCore/page/animation/CompositeAnimation.cpp @@ -233,7 +233,7 @@ void CompositeAnimation::updateKeyframeAnimations(RenderObject* renderer, Render keyframeAnim->setAnimation(anim); keyframeAnim->setIndex(i); } else if ((anim->duration() || anim->delay()) && anim->iterationCount()) { - keyframeAnim = KeyframeAnimation::create(const_cast<Animation*>(anim), renderer, i, this, currentStyle ? currentStyle : targetStyle); + keyframeAnim = KeyframeAnimation::create(const_cast<Animation*>(anim), renderer, i, this, targetStyle); m_keyframeAnimations.set(keyframeAnim->name().impl(), keyframeAnim); } diff --git a/WebCore/page/animation/KeyframeAnimation.cpp b/WebCore/page/animation/KeyframeAnimation.cpp index c5e3660..4c2cbc8 100644 --- a/WebCore/page/animation/KeyframeAnimation.cpp +++ b/WebCore/page/animation/KeyframeAnimation.cpp @@ -68,6 +68,11 @@ void KeyframeAnimation::getKeyframeAnimationInterval(const RenderStyle*& fromSty double elapsedTime = getElapsedTime(); double t = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1; + + ASSERT(t >= 0); + if (t < 0) + t = 0; + int i = static_cast<int>(t); t -= i; if (m_animation->direction() && (i & 1)) @@ -120,9 +125,11 @@ void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const Render } // If we are waiting for the start timer, we don't want to change the style yet. - // Special case - if the delay time is 0, then we do want to set the first frame of the + // Special case 1 - if the delay time is 0, then we do want to set the first frame of the // animation right away. This avoids a flash when the animation starts. - if (waitingToStart() && m_animation->delay() > 0) + // Special case 2 - if there is a backwards fill mode, then we want to continue + // through to the style blend so that we get the fromStyle. + if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards()) return; // FIXME: we need to be more efficient about determining which keyframes we are animating between. @@ -163,6 +170,11 @@ void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const Render void KeyframeAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle) { + // If we're in the delay phase and we're not backwards filling, tell the caller + // to use the current style. + if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards()) + return; + // Get the from/to styles and progress between const RenderStyle* fromStyle = 0; const RenderStyle* toStyle = 0; @@ -260,7 +272,10 @@ void KeyframeAnimation::onAnimationIteration(double elapsedTime) void KeyframeAnimation::onAnimationEnd(double elapsedTime) { sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime); - endAnimation(); + // End the animation if we don't fill forwards. Forward filling + // animations are ended properly in the class destructor. + if (!m_animation->fillsForwards()) + endAnimation(); } bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime) diff --git a/WebCore/page/brew/EventHandlerBrew.cpp b/WebCore/page/brew/EventHandlerBrew.cpp new file mode 100644 index 0000000..e3b6645 --- /dev/null +++ b/WebCore/page/brew/EventHandlerBrew.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2010 Company 100, Inc. + * Copyright 2009, The Android Open Source Project + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * + * 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 "EventHandler.h" + +#include "ClipboardBrew.h" +#include "EventNames.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameView.h" +#include "HitTestResult.h" +#include "KeyboardEvent.h" +#include "MouseEventWithHitTestResults.h" +#include "NotImplemented.h" +#include "Page.h" +#include "PlatformKeyboardEvent.h" +#include "PlatformWheelEvent.h" +#include "RenderWidget.h" + +namespace WebCore { + +bool EventHandler::tabsToAllControls(KeyboardEvent* event) const +{ + return true; +} + +void EventHandler::focusDocumentView() +{ + Page* page = m_frame->page(); + if (page) + page->focusController()->setFocusedFrame(m_frame); +} + +bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event) +{ + // Figure out which view to send the event to. + RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0; + if (!target || !target->isWidget()) + return false; + return passMouseDownEventToWidget(toRenderWidget(target)->widget()); +} + +bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget) +{ + return passMouseDownEventToWidget(renderWidget->widget()); +} + +// This function is used to route the mouse down event to the native widgets, it seems like a +// work around for the Mac platform which does not support double clicks, but browsers do. +bool EventHandler::passMouseDownEventToWidget(Widget* widget) +{ + notImplemented(); + return false; +} + +bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const +{ + notImplemented(); + return false; +} + +// This function is called for mouse events by FrameView::handleMousePressEvent(). +// It is used to ensure that events are sync'ed correctly between frames. For example +// if the user presses down in one frame and up in another frame, this function will +// returns true, and pass the event to the correct frame. +bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult*) +{ + notImplemented(); + return false; +} + +// This is called to route wheel events to child widgets when they are RenderWidget +// as the parent usually gets wheel event. Don't have a mouse with a wheel to confirm +// the operation of this function. +bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& event, Widget* widget) +{ + notImplemented(); + return false; +} + +bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) +{ + return passSubframeEventToSubframe(mev, subframe); +} + +bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode) +{ + return passSubframeEventToSubframe(mev, subframe, hoveredNode); +} + +bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) +{ + return passSubframeEventToSubframe(mev, subframe); +} + +unsigned EventHandler::accessKeyModifiers() +{ + return PlatformKeyboardEvent::AltKey; +} + +} // namespace WebCore + diff --git a/WebCore/page/chromium/ChromeClientChromium.h b/WebCore/page/chromium/ChromeClientChromium.h index fc42250..e897c15 100644 --- a/WebCore/page/chromium/ChromeClientChromium.h +++ b/WebCore/page/chromium/ChromeClientChromium.h @@ -48,7 +48,10 @@ public: // If handleExternal is true, then drawing and input handling for the // popup will be handled by the external embedder. virtual void popupOpened(PopupContainer* popupContainer, const IntRect& bounds, - bool focusOnShow, bool handleExternal) = 0; + bool handleExternal) = 0; + + // Notifies the client a popup was closed. + virtual void popupClosed(PopupContainer* popupContainer) = 0; // Notifies embedder that the state of an accessibility object has changed. virtual void didChangeAccessibilityObjectState(AccessibilityObject*) = 0; diff --git a/WebCore/page/chromium/DragControllerChromium.cpp b/WebCore/page/chromium/DragControllerChromium.cpp index 7b0958d..de53d19 100644 --- a/WebCore/page/chromium/DragControllerChromium.cpp +++ b/WebCore/page/chromium/DragControllerChromium.cpp @@ -66,7 +66,12 @@ bool DragController::isCopyKeyDown() const IntSize& DragController::maxDragImageSize() { +#if OS(DARWIN) + // Match Safari's drag image size. + static const IntSize maxDragImageSize(400, 400); +#else static const IntSize maxDragImageSize(200, 200); +#endif return maxDragImageSize; } diff --git a/WebCore/page/efl/DragControllerEfl.cpp b/WebCore/page/efl/DragControllerEfl.cpp new file mode 100644 index 0000000..0c5f002 --- /dev/null +++ b/WebCore/page/efl/DragControllerEfl.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2007 Apple Inc. + * Copyright (C) 2009-2010 ProFUSION embedded systems + * Copyright (C) 2009-2010 Samsung Electronics + * 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 "DragController.h" + +#include "DragData.h" +#include "Frame.h" +#include "FrameView.h" +#include "Page.h" + +namespace WebCore { + +const int DragController::LinkDragBorderInset = 2; +const int DragController::MaxOriginalImageArea = 1500 * 1500; +const int DragController::DragIconRightInset = 7; +const int DragController::DragIconBottomInset = 3; + +const float DragController::DragImageAlpha = 0.75f; + +bool DragController::isCopyKeyDown() +{ + return false; +} + +DragOperation DragController::dragOperation(DragData* dragData) +{ + if (dragData->containsURL()) + return DragOperationCopy; + + return DragOperationNone; +} + +const IntSize& DragController::maxDragImageSize() +{ + static const IntSize maxDragImageSize(400, 400); + + return maxDragImageSize; +} + +void DragController::cleanupAfterSystemDrag() +{} + +} diff --git a/WebCore/page/efl/EventHandlerEfl.cpp b/WebCore/page/efl/EventHandlerEfl.cpp new file mode 100644 index 0000000..df5c276 --- /dev/null +++ b/WebCore/page/efl/EventHandlerEfl.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia + * Copyright (C) 2009,2010 ProFUSION embedded systems + * Copyright (C) 2009,2010 Samsung Electronics + * + * 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 "EventHandler.h" + +#include "ClipboardEfl.h" +#include "EventNames.h" +#include "FloatPoint.h" +#include "FocusController.h" +#include "Frame.h" +#include "FrameView.h" +#include "KeyboardEvent.h" +#include "MouseEventWithHitTestResults.h" +#include "NotImplemented.h" +#include "Page.h" +#include "PlatformKeyboardEvent.h" +#include "PlatformWheelEvent.h" +#include "RenderWidget.h" +#include "Scrollbar.h" + +namespace WebCore { + +const double EventHandler::TextDragDelay = 0.0; + +static 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 +{ + return true; +} + +void EventHandler::focusDocumentView() +{ + if (Page* page = m_frame->page()) + page->focusController()->setFocusedFrame(m_frame); +} + +bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event) +{ + RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0; + + if (!target || !target->isWidget()) + return false; + + return passMouseDownEventToWidget(static_cast<RenderWidget*>(target)->widget()); +} + +bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget) +{ + return passMouseDownEventToWidget(renderWidget->widget()); +} + +bool EventHandler::passMouseDownEventToWidget(Widget* widget) +{ + notImplemented(); + return false; +} + +bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const +{ + notImplemented(); + return false; +} + +bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& event, Widget* widget) +{ + ASSERT(widget); + if (!widget->isFrameView()) + return false; + + return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(event); +} + +PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const +{ + return new ClipboardEfl(ClipboardWritable, true); +} + +bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) +{ + subframe->eventHandler()->handleMousePressEvent(mev.event()); + return true; +} + +bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode) +{ + subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode); + return true; +} + +bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) +{ + subframe->eventHandler()->handleMouseReleaseEvent(mev.event()); + return true; +} + +unsigned EventHandler::accessKeyModifiers() +{ + return PlatformKeyboardEvent::AltKey; +} +} diff --git a/WebCore/page/win/PageWin.cpp b/WebCore/page/efl/FrameEfl.cpp index 3ef7728..783df7e 100644 --- a/WebCore/page/win/PageWin.cpp +++ b/WebCore/page/efl/FrameEfl.cpp @@ -1,5 +1,7 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia + * Copyright (C) 2009-2010 ProFUSION embedded systems + * Copyright (C) 2009-2010 Samsung Electronics * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -20,14 +22,20 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" -#include "Page.h" +#include "Frame.h" + +#include "NotImplemented.h" namespace WebCore { -HINSTANCE Page::s_instanceHandle = 0; +DragImageRef Frame::dragImageForSelection() +{ + notImplemented(); + return 0; +} -} // namespace WebCore +} diff --git a/WebCore/page/haiku/EventHandlerHaiku.cpp b/WebCore/page/haiku/EventHandlerHaiku.cpp index 203344e..450414d 100644 --- a/WebCore/page/haiku/EventHandlerHaiku.cpp +++ b/WebCore/page/haiku/EventHandlerHaiku.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2006 Zack Rusin <zack@kde.org> * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> + * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,7 +40,6 @@ #include "NotImplemented.h" #include "Page.h" #include "PlatformKeyboardEvent.h" -#include "PlatformScrollBar.h" #include "PlatformWheelEvent.h" #include "RenderWidget.h" @@ -56,7 +56,7 @@ static bool isKeyboardOptionTab(KeyboardEvent* event) && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent) && event->altKey() - && event->keyIdentifier() == "U+000009"; + && event->keyIdentifier() == "U+0009"; } bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const @@ -74,8 +74,10 @@ bool EventHandler::tabsToAllControls(KeyboardEvent* event) const void EventHandler::focusDocumentView() { BView* view = m_frame->view()->platformWidget(); - if (view) - view->MakeFocus(); + if (view && view->LockLooperWithTimeout(5000) == B_OK) { + view->MakeFocus(true); + view->UnlockLooper(); + } Page* page = m_frame->page(); if (page) @@ -102,18 +104,14 @@ bool EventHandler::passMouseDownEventToWidget(Widget* widget) return false; } -bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const +bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const { - notImplemented(); + // On Haiku, clicks which activate the window in non focus-follows-mouse mode + // are not passed to the window, so any event we generate is not the activation + // event. return false; } -bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult*) -{ - notImplemented(); - return true; -} - bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& event, Widget* widget) { if (!widget->isFrameView()) @@ -129,21 +127,27 @@ PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const 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, HitTestResult* hoveredNode) { - return passSubframeEventToSubframe(mev, subframe, hoveredNode); + subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode); + return true; } bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) { - return passSubframeEventToSubframe(mev, subframe); + subframe->eventHandler()->handleMouseReleaseEvent(mev.event()); + return true; } unsigned EventHandler::accessKeyModifiers() { + // NOTE: On Haiku, the user can choose Alt or Ctrl as access key, but + // the PlatformKeyboardEvent already takes care of this, internally, + // we always use Alt. return PlatformKeyboardEvent::AltKey; } diff --git a/WebCore/page/mac/FrameMac.mm b/WebCore/page/mac/FrameMac.mm index 9e77387..356503f 100644 --- a/WebCore/page/mac/FrameMac.mm +++ b/WebCore/page/mac/FrameMac.mm @@ -416,12 +416,12 @@ NSDictionary* Frame::fontAttributesForSelectionStart() const if (style->color().isValid() && style->color() != Color::black) [result setObject:nsColor(style->color()) forKey:NSForegroundColorAttributeName]; - ShadowData* shadow = style->textShadow(); + const ShadowData* shadow = style->textShadow(); if (shadow) { NSShadow* s = [[NSShadow alloc] init]; - [s setShadowOffset:NSMakeSize(shadow->x, shadow->y)]; - [s setShadowBlurRadius:shadow->blur]; - [s setShadowColor:nsColor(shadow->color)]; + [s setShadowOffset:NSMakeSize(shadow->x(), shadow->y())]; + [s setShadowBlurRadius:shadow->blur()]; + [s setShadowColor:nsColor(shadow->color())]; [result setObject:s forKey:NSShadowAttributeName]; } diff --git a/WebCore/page/mac/WebCoreViewFactory.h b/WebCore/page/mac/WebCoreViewFactory.h index fef856a..db70b6d 100644 --- a/WebCore/page/mac/WebCoreViewFactory.h +++ b/WebCore/page/mac/WebCoreViewFactory.h @@ -142,6 +142,9 @@ - (NSString *)AXMenuListPopupActionVerb; - (NSString *)AXMenuListActionVerb; +- (NSString *)missingPluginText; +- (NSString *)crashedPluginText; + - (NSString *)multipleFileUploadTextForNumberOfFiles:(unsigned)numberOfFiles; // FTP Directory Related - (NSString *)unknownFileSizeText; diff --git a/WebCore/page/qt/EventHandlerQt.cpp b/WebCore/page/qt/EventHandlerQt.cpp index 3425289..d7982fa 100644 --- a/WebCore/page/qt/EventHandlerQt.cpp +++ b/WebCore/page/qt/EventHandlerQt.cpp @@ -132,7 +132,11 @@ bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& unsigned EventHandler::accessKeyModifiers() { - return PlatformKeyboardEvent::CtrlKey; +#if OS(DARWIN) + return PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey; +#else + return PlatformKeyboardEvent::AltKey; +#endif } } |