summaryrefslogtreecommitdiffstats
path: root/WebCore/page
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/page')
-rw-r--r--WebCore/page/ChromeClient.h13
-rw-r--r--WebCore/page/Console.cpp36
-rw-r--r--WebCore/page/Console.h38
-rw-r--r--WebCore/page/DOMWindow.cpp33
-rw-r--r--WebCore/page/DOMWindow.h7
-rw-r--r--WebCore/page/DOMWindow.idl4
-rw-r--r--WebCore/page/EditorClient.h5
-rw-r--r--WebCore/page/EventHandler.cpp11
-rw-r--r--WebCore/page/EventSource.cpp3
-rw-r--r--WebCore/page/FocusController.cpp428
-rw-r--r--WebCore/page/FocusController.h6
-rw-r--r--WebCore/page/Frame.cpp9
-rw-r--r--WebCore/page/FrameView.cpp33
-rw-r--r--WebCore/page/FrameView.h7
-rw-r--r--WebCore/page/Geolocation.cpp36
-rw-r--r--WebCore/page/Geolocation.h3
-rw-r--r--WebCore/page/Page.cpp19
-rw-r--r--WebCore/page/Page.h7
-rw-r--r--WebCore/page/PerformanceTiming.cpp9
-rw-r--r--WebCore/page/PerformanceTiming.h1
-rw-r--r--WebCore/page/PerformanceTiming.idl1
-rw-r--r--WebCore/page/SecurityOrigin.cpp3
-rw-r--r--WebCore/page/Settings.cpp38
-rw-r--r--WebCore/page/Settings.h26
-rw-r--r--WebCore/page/SpatialNavigation.cpp658
-rw-r--r--WebCore/page/SpatialNavigation.h36
-rw-r--r--WebCore/page/SpeechInputEvent.cpp54
-rw-r--r--WebCore/page/SpeechInputEvent.h59
-rw-r--r--WebCore/page/SpeechInputEvent.idl34
-rw-r--r--WebCore/page/SpeechInputListener.h2
-rw-r--r--WebCore/page/SpeechInputResult.cpp5
-rw-r--r--WebCore/page/SpeechInputResult.h3
-rw-r--r--WebCore/page/SpeechInputResult.idl35
-rw-r--r--WebCore/page/SpeechInputResultList.cpp55
-rw-r--r--WebCore/page/SpeechInputResultList.h57
-rw-r--r--WebCore/page/SpeechInputResultList.idl36
-rw-r--r--WebCore/page/animation/AnimationBase.cpp4
-rw-r--r--WebCore/page/mac/WebCoreFrameView.h2
-rw-r--r--WebCore/page/qt/FrameQt.cpp26
39 files changed, 1195 insertions, 647 deletions
diff --git a/WebCore/page/ChromeClient.h b/WebCore/page/ChromeClient.h
index 0725f46..d224726 100644
--- a/WebCore/page/ChromeClient.h
+++ b/WebCore/page/ChromeClient.h
@@ -236,6 +236,19 @@ namespace WebCore {
// Returns whether or not the client can render the composited layer,
// regardless of the settings.
virtual bool allowsAcceleratedCompositing() const { return true; }
+
+ enum CompositingTrigger {
+ ThreeDTransformTrigger = 1 << 0,
+ VideoTrigger = 1 << 1,
+ PluginTrigger = 1 << 2,
+ CanvasTrigger = 1 << 3,
+ AnimationTrigger = 1 << 4,
+ AllTriggers = 0xFFFFFFFF
+ };
+ typedef unsigned CompositingTriggerFlags;
+
+ // Returns a bitfield indicating conditions that can trigger the compositor.
+ virtual CompositingTriggerFlags allowedCompositingTriggers() const { return static_cast<CompositingTriggerFlags>(AllTriggers); }
#endif
virtual bool supportsFullscreenForNode(const Node*) { return false; }
diff --git a/WebCore/page/Console.cpp b/WebCore/page/Console.cpp
index 34db538..219647d 100644
--- a/WebCore/page/Console.cpp
+++ b/WebCore/page/Console.cpp
@@ -137,7 +137,7 @@ void Console::addMessage(MessageSource source, MessageType type, MessageLevel le
addMessage(source, type, level, message, lineNumber, sourceURL, 0);
}
-void Console::addMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL, PassOwnPtr<ScriptCallStack> callStack)
+void Console::addMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack> callStack)
{
Page* page = this->page();
if (!page)
@@ -162,7 +162,7 @@ void Console::addMessage(MessageSource source, MessageType type, MessageLevel le
printf(" %s\n", message.utf8().data());
}
-void Console::addMessage(MessageType type, MessageLevel level, PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack, bool acceptNoArguments)
+void Console::addMessage(MessageType type, MessageLevel level, PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack, bool acceptNoArguments)
{
Page* page = this->page();
if (!page)
@@ -194,39 +194,39 @@ void Console::addMessage(MessageType type, MessageLevel level, PassOwnPtr<Script
#endif
}
-void Console::debug(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack)
+void Console::debug(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
{
// In Firebug, console.debug has the same behavior as console.log. So we'll do the same.
log(arguments, callStack);
}
-void Console::error(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack)
+void Console::error(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
{
addMessage(LogMessageType, ErrorMessageLevel, arguments, callStack);
}
-void Console::info(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack)
+void Console::info(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
{
log(arguments, callStack);
}
-void Console::log(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack)
+void Console::log(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
{
addMessage(LogMessageType, LogMessageLevel, arguments, callStack);
}
-void Console::dir(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack)
+void Console::dir(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
{
addMessage(ObjectMessageType, LogMessageLevel, arguments, callStack);
}
-void Console::dirxml(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack)
+void Console::dirxml(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
{
// The standard behavior of our console.log will print the DOM tree for nodes.
log(arguments, callStack);
}
-void Console::trace(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack)
+void Console::trace(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
{
addMessage(TraceMessageType, LogMessageLevel, arguments, callStack, true);
@@ -240,7 +240,7 @@ void Console::trace(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCall
}
}
-void Console::assertCondition(bool condition, PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack)
+void Console::assertCondition(bool condition, PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
{
if (condition)
return;
@@ -248,7 +248,7 @@ void Console::assertCondition(bool condition, PassOwnPtr<ScriptArguments> argume
addMessage(AssertMessageType, ErrorMessageLevel, arguments, callStack, true);
}
-void Console::count(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack)
+void Console::count(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
{
#if ENABLE(INSPECTOR)
Page* page = this->page();
@@ -267,7 +267,7 @@ void Console::count(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCall
#endif
}
-void Console::markTimeline(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack>)
+void Console::markTimeline(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack>)
{
#if ENABLE(INSPECTOR)
Page* page = this->page();
@@ -312,7 +312,7 @@ String Console::lastWMLErrorMessage() const
#if ENABLE(JAVASCRIPT_DEBUGGER)
-void Console::profile(const String& title, ScriptState* state, PassOwnPtr<ScriptCallStack> callStack)
+void Console::profile(const String& title, ScriptState* state, PassRefPtr<ScriptCallStack> callStack)
{
Page* page = this->page();
if (!page)
@@ -341,7 +341,7 @@ void Console::profile(const String& title, ScriptState* state, PassOwnPtr<Script
#endif
}
-void Console::profileEnd(const String& title, ScriptState* state, PassOwnPtr<ScriptCallStack> callStack)
+void Console::profileEnd(const String& title, ScriptState* state, PassRefPtr<ScriptCallStack> callStack)
{
Page* page = this->page();
if (!page)
@@ -385,7 +385,7 @@ void Console::time(const String& title)
#endif
}
-void Console::timeEnd(const String& title, PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack> callStack)
+void Console::timeEnd(const String& title, PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack> callStack)
{
#if ENABLE(INSPECTOR)
Page* page = this->page();
@@ -411,7 +411,7 @@ void Console::timeEnd(const String& title, PassOwnPtr<ScriptArguments>, PassOwnP
#endif
}
-void Console::group(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack)
+void Console::group(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
{
#if ENABLE(INSPECTOR)
Page* page = this->page();
@@ -425,7 +425,7 @@ void Console::group(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCall
#endif
}
-void Console::groupCollapsed(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack)
+void Console::groupCollapsed(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
{
#if ENABLE(INSPECTOR)
Page* page = this->page();
@@ -463,7 +463,7 @@ bool Console::shouldCaptureFullStackTrace() const
#endif
}
-void Console::warn(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack)
+void Console::warn(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
{
addMessage(LogMessageType, WarningMessageLevel, arguments, callStack);
}
diff --git a/WebCore/page/Console.h b/WebCore/page/Console.h
index 92fee59..19f1a57 100644
--- a/WebCore/page/Console.h
+++ b/WebCore/page/Console.h
@@ -87,31 +87,31 @@ public:
void disconnectFrame();
void addMessage(MessageSource, MessageType, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL);
- void addMessage(MessageSource, MessageType, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL, PassOwnPtr<ScriptCallStack> callStack);
-
- void debug(PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
- void error(PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
- void info(PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
- void log(PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
- void warn(PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
- void dir(PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
- void dirxml(PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
- void trace(PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
- void assertCondition(bool condition, PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
- void count(PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
- void markTimeline(PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
+ void addMessage(MessageSource, MessageType, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack> callStack);
+
+ void debug(PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
+ void error(PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
+ void info(PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
+ void log(PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
+ void warn(PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
+ void dir(PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
+ void dirxml(PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
+ void trace(PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
+ void assertCondition(bool condition, PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
+ void count(PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
+ void markTimeline(PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
#if ENABLE(WML)
String lastWMLErrorMessage() const;
#endif
#if ENABLE(JAVASCRIPT_DEBUGGER)
const ProfilesArray& profiles() const { return m_profiles; }
- void profile(const String&, ScriptState*, PassOwnPtr<ScriptCallStack>);
- void profileEnd(const String&, ScriptState*, PassOwnPtr<ScriptCallStack>);
+ void profile(const String&, ScriptState*, PassRefPtr<ScriptCallStack>);
+ void profileEnd(const String&, ScriptState*, PassRefPtr<ScriptCallStack>);
#endif
void time(const String&);
- void timeEnd(const String&, PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
- void group(PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
- void groupCollapsed(PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>);
+ void timeEnd(const String&, PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
+ void group(PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
+ void groupCollapsed(PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>);
void groupEnd();
bool shouldCaptureFullStackTrace() const;
@@ -123,7 +123,7 @@ public:
private:
inline Page* page() const;
- void addMessage(MessageType, MessageLevel, PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>, bool acceptNoArguments = false);
+ void addMessage(MessageType, MessageLevel, PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>, bool acceptNoArguments = false);
Console(Frame*);
diff --git a/WebCore/page/DOMWindow.cpp b/WebCore/page/DOMWindow.cpp
index bfb5b4f..fb64a76 100644
--- a/WebCore/page/DOMWindow.cpp
+++ b/WebCore/page/DOMWindow.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -67,7 +68,8 @@
#include "InspectorInstrumentation.h"
#include "KURL.h"
#include "Location.h"
-#include "StyleMedia.h"
+#include "MediaQueryList.h"
+#include "MediaQueryMatcher.h"
#include "MessageEvent.h"
#include "Navigator.h"
#include "NotificationCenter.h"
@@ -83,6 +85,7 @@
#include "Storage.h"
#include "StorageArea.h"
#include "StorageNamespace.h"
+#include "StyleMedia.h"
#include "SuddenTermination.h"
#include "WebKitPoint.h"
#include <algorithm>
@@ -411,6 +414,11 @@ ScriptExecutionContext* DOMWindow::scriptExecutionContext() const
return document();
}
+PassRefPtr<MediaQueryList> DOMWindow::matchMedia(const String& media)
+{
+ return document() ? document()->mediaQueryMatcher()->matchMedia(media) : 0;
+}
+
void DOMWindow::disconnectFrame()
{
m_frame = 0;
@@ -1515,11 +1523,14 @@ bool DOMWindow::removeEventListener(const AtomicString& eventType, EventListener
void DOMWindow::dispatchLoadEvent()
{
- if (DocumentLoader* documentLoader = m_frame ? m_frame->loader()->documentLoader() : 0)
- documentLoader->timing()->loadEventStart = currentTime();
- dispatchEvent(Event::create(eventNames().loadEvent, false, false), document());
- if (DocumentLoader* documentLoader = m_frame ? m_frame->loader()->documentLoader() : 0)
- documentLoader->timing()->loadEventEnd = currentTime();
+ RefPtr<Event> loadEvent(Event::create(eventNames().loadEvent, false, false));
+ // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed while dispatching
+ // the event, so protect it to prevent writing the end time into freed memory.
+ if (RefPtr<DocumentLoader> documentLoader = m_frame ? m_frame->loader()->documentLoader() : 0) {
+ DocumentLoadTiming* timing = documentLoader->timing();
+ dispatchTimedEvent(loadEvent, document(), &timing->loadEventStart, &timing->loadEventEnd);
+ } else
+ dispatchEvent(loadEvent, document());
// For load events, send a separate load event to the enclosing frame only.
// This is a DOM extension and is independent of bubbling/capturing rules of
@@ -1558,6 +1569,16 @@ bool DOMWindow::dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget
return result;
}
+void DOMWindow::dispatchTimedEvent(PassRefPtr<Event> event, Document* target, double* startTime, double* endTime)
+{
+ ASSERT(startTime);
+ ASSERT(endTime);
+ *startTime = currentTime();
+ dispatchEvent(event, target);
+ *endTime = currentTime();
+ ASSERT(*endTime >= *startTime);
+}
+
void DOMWindow::removeAllEventListeners()
{
EventTarget::removeAllEventListeners();
diff --git a/WebCore/page/DOMWindow.h b/WebCore/page/DOMWindow.h
index d87a386..68b21ff 100644
--- a/WebCore/page/DOMWindow.h
+++ b/WebCore/page/DOMWindow.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -58,10 +59,11 @@ namespace WebCore {
class History;
class IDBFactory;
class Location;
- class StyleMedia;
+ class MediaQueryList;
class Navigator;
class Node;
class NotificationCenter;
+ class StyleMedia;
#if ENABLE(WEB_TIMING)
class Performance;
@@ -96,6 +98,8 @@ namespace WebCore {
void clear();
+ PassRefPtr<MediaQueryList> matchMedia(const String&);
+
#if ENABLE(ORIENTATION_EVENTS)
// This is the interface orientation in degrees. Some examples are:
// 0 is straight up; -90 is when the device is rotated 90 clockwise;
@@ -275,6 +279,7 @@ namespace WebCore {
using EventTarget::dispatchEvent;
bool dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget> prpTarget);
void dispatchLoadEvent();
+ void dispatchTimedEvent(PassRefPtr<Event> event, Document* target, double* startTime, double* endTime);
DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
DEFINE_ATTRIBUTE_EVENT_LISTENER(beforeunload);
diff --git a/WebCore/page/DOMWindow.idl b/WebCore/page/DOMWindow.idl
index 6222983..602289b 100644
--- a/WebCore/page/DOMWindow.idl
+++ b/WebCore/page/DOMWindow.idl
@@ -140,6 +140,9 @@ module window {
readonly attribute Document document;
// CSSOM View Module
+ MediaQueryList matchMedia(in DOMString query);
+
+ // styleMedia has been removed from the CSSOM View specification.
readonly attribute StyleMedia styleMedia;
// DOM Level 2 Style Interface
@@ -496,6 +499,7 @@ module window {
attribute [JSCCustomGetter,Conditional=3D_CANVAS|BLOB,EnabledAtRuntime] Int32ArrayConstructor Int32Array; // Usable with new operator
attribute [JSCCustomGetter,Conditional=3D_CANVAS|BLOB,EnabledAtRuntime] Uint32ArrayConstructor Uint32Array; // Usable with new operator
attribute [JSCCustomGetter,Conditional=3D_CANVAS|BLOB,EnabledAtRuntime] Float32ArrayConstructor Float32Array; // Usable with new operator
+ attribute [JSCCustomGetter,Conditional=3D_CANVAS|BLOB,EnabledAtRuntime] DataViewConstructor DataView; // Usable with new operator
attribute EventConstructor Event;
attribute BeforeLoadEventConstructor BeforeLoadEvent;
diff --git a/WebCore/page/EditorClient.h b/WebCore/page/EditorClient.h
index 61bdd41..ba9ceee 100644
--- a/WebCore/page/EditorClient.h
+++ b/WebCore/page/EditorClient.h
@@ -190,7 +190,7 @@ public:
#endif
#if SUPPORT_AUTOCORRECTION_PANEL
- virtual void showCorrectionPanel(CorrectionPanelInfo::PanelType, const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacmentString, Editor*) = 0;
+ virtual void showCorrectionPanel(CorrectionPanelInfo::PanelType, const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacmentString, const Vector<String>& alternativeReplacementStrings, Editor*) = 0;
virtual void dismissCorrectionPanel(CorrectionWasRejectedOrNot) = 0;
virtual bool isShowingCorrectionPanel() = 0;
#endif
@@ -199,7 +199,8 @@ public:
virtual void updateSpellingUIWithMisspelledWord(const String&) = 0;
virtual void showSpellingUI(bool show) = 0;
virtual bool spellingUIIsShowing() = 0;
- virtual void getGuessesForWord(const String&, Vector<String>& guesses) = 0;
+ // For spellcheckers that support multiple languages, it's often important to be able to identify the language in order to provide more accurate correction suggestions. Caller can pass in more text in "context" to aid such spellcheckers on language identification. Noramlly it's the text surrounding the "word" for which we are getting correction suggestions.
+ virtual void getGuessesForWord(const String& word, const String& context, Vector<String>& guesses) = 0;
virtual void willSetInputMethodState() = 0;
virtual void setInputMethodState(bool enabled) = 0;
};
diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp
index 22c2ecc..e044daa 100644
--- a/WebCore/page/EventHandler.cpp
+++ b/WebCore/page/EventHandler.cpp
@@ -1880,9 +1880,10 @@ bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe
// Walk up the render tree to search for a node to focus.
// Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
+ // FIXME: Rework to use shadowParent. No need to traverse with the render tree.
while (renderer) {
node = renderer->node();
- if (node && node->isFocusable()) {
+ if (node && node->isMouseFocusable()) {
// To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
// node on mouse down if it's selected and inside a focused node. It will be
// focused if the user does a mouseup over it, however, because the mouseup
@@ -2028,11 +2029,8 @@ bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
HitTestRequest request(HitTestRequest::Active);
MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
- // Context menu events shouldn't select text in GTK+ applications or in Chromium.
- // FIXME: This should probably be configurable by embedders. Consider making it a WebPreferences setting.
- // See: https://bugs.webkit.org/show_bug.cgi?id=15279
-#if !PLATFORM(GTK) && !PLATFORM(CHROMIUM)
- if (!m_frame->selection()->contains(viewportPos)
+ if (m_frame->editor()->behavior().shouldSelectOnContextualMenuClick()
+ && !m_frame->selection()->contains(viewportPos)
// FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
// If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
// available for text selections. But only if we're above text.
@@ -2040,7 +2038,6 @@ bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
selectClosestWordOrLinkFromMouseEvent(mev);
}
-#endif
swallowEvent = dispatchMouseEvent(eventNames().contextmenuEvent, mev.targetNode(), true, 0, event, false);
diff --git a/WebCore/page/EventSource.cpp b/WebCore/page/EventSource.cpp
index a7c715a..b0b07aa 100644
--- a/WebCore/page/EventSource.cpp
+++ b/WebCore/page/EventSource.cpp
@@ -120,6 +120,9 @@ void EventSource::connect()
void EventSource::endRequest()
{
+ if (!m_requestInFlight)
+ return;
+
m_requestInFlight = false;
if (!m_failSilently)
diff --git a/WebCore/page/FocusController.cpp b/WebCore/page/FocusController.cpp
index 2866019..5418c89 100644
--- a/WebCore/page/FocusController.cpp
+++ b/WebCore/page/FocusController.cpp
@@ -40,11 +40,13 @@
#include "Frame.h"
#include "FrameTree.h"
#include "FrameView.h"
+#include "HitTestResult.h"
#include "HTMLFrameOwnerElement.h"
#include "HTMLNames.h"
#include "KeyboardEvent.h"
#include "Page.h"
#include "Range.h"
+#include "RenderLayer.h"
#include "RenderObject.h"
#include "RenderWidget.h"
#include "SelectionController.h"
@@ -57,6 +59,7 @@ namespace WebCore {
using namespace HTMLNames;
using namespace std;
+static void updateFocusCandidateIfNeeded(FocusDirection direction, const IntRect& startingRect, FocusCandidate& candidate, FocusCandidate& closest);
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.
@@ -289,255 +292,6 @@ bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, Keyb
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) ?
- FocusDirectionBackward : FocusDirectionForward;
- // '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()->firstChild(), 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, focusCandidate);
- 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;
-}
-
-static void updateFocusCandidateInSameContainer(const FocusCandidate& candidate, FocusCandidate& closest)
-{
- if (closest.isNull()) {
- closest = candidate;
- return;
- }
-
- if (candidate.alignment == closest.alignment) {
- if (candidate.distance < closest.distance)
- closest = candidate;
- return;
- }
-
- if (candidate.alignment > closest.alignment)
- closest = candidate;
-}
-
-static void updateFocusCandidateIfCloser(Node* focusedNode, const FocusCandidate& candidate, FocusCandidate& closest)
-{
- // First, check the common case: neither candidate nor closest are
- // inside scrollable content, then no need to care about enclosingScrollableBox
- // heuristics or parent{Distance,Alignment}, but only distance and alignment.
- if (!candidate.inScrollableContainer() && !closest.inScrollableContainer()) {
- updateFocusCandidateInSameContainer(candidate, closest);
- return;
- }
-
- bool sameContainer = candidate.document() == closest.document() && candidate.enclosingScrollableBox == closest.enclosingScrollableBox;
-
- // Second, if candidate and closest are in the same "container" (i.e. {i}frame or any
- // scrollable block element), we can handle them as common case.
- if (sameContainer) {
- updateFocusCandidateInSameContainer(candidate, closest);
- return;
- }
-
- // Last, we are considering moving to a candidate located in a different enclosing
- // scrollable box than closest.
- bool isInInnerDocument = !isInRootDocument(focusedNode);
-
- bool sameContainerAsCandidate = isInInnerDocument ? focusedNode->document() == candidate.document() :
- focusedNode->isDescendantOf(candidate.enclosingScrollableBox);
-
- bool sameContainerAsClosest = isInInnerDocument ? focusedNode->document() == closest.document() :
- focusedNode->isDescendantOf(closest.enclosingScrollableBox);
-
- // sameContainerAsCandidate and sameContainerAsClosest are mutually exclusive.
- ASSERT(!(sameContainerAsCandidate && sameContainerAsClosest));
-
- if (sameContainerAsCandidate) {
- closest = candidate;
- return;
- }
-
- if (sameContainerAsClosest) {
- // Nothing to be done.
- return;
- }
-
- // NOTE: !sameContainerAsCandidate && !sameContainerAsClosest
- // If distance is shorter, and we are talking about scrollable container,
- // lets compare parent distance and alignment before anything.
- if (candidate.distance < closest.distance) {
- if (candidate.alignment >= closest.parentAlignment
- || candidate.parentAlignment == closest.parentAlignment) {
- closest = candidate;
- return;
- }
-
- } else if (candidate.parentDistance < closest.distance) {
- if (candidate.parentAlignment >= closest.alignment) {
- closest = candidate;
- return;
- }
- }
-}
-
-void FocusController::findFocusableNodeInDirection(Node* outer, Node* focusedNode,
- FocusDirection direction, KeyboardEvent* event,
- FocusCandidate& closest, const FocusCandidate& candidateParent)
-{
- ASSERT(outer);
- ASSERT(candidateParent.isNull()
- || candidateParent.node->hasTagName(frameTag)
- || candidateParent.node->hasTagName(iframeTag)
- || isScrollableContainerNode(candidateParent.node));
-
- // Walk all the child nodes and update closest if we find a nearer node.
- Node* node = outer;
- while (node) {
-
- // Inner documents case.
- if (node->isFrameOwnerElement()) {
- deepFindFocusableNodeInDirection(node, focusedNode, direction, event, closest);
-
- // Scrollable block elements (e.g. <div>, etc) case.
- } else if (isScrollableContainerNode(node)) {
- deepFindFocusableNodeInDirection(node, focusedNode, direction, event, closest);
- node = node->traverseNextSibling();
- continue;
-
- } else if (node != focusedNode && node->isKeyboardFocusable(event)) {
- FocusCandidate candidate(node);
-
- // There are two ways to identify we are in a recursive call from deepFindFocusableNodeInDirection
- // (i.e. processing an element in an iframe, frame or a scrollable block element):
-
- // 1) If candidateParent is not null, and it holds the distance and alignment data of the
- // parent container element itself;
- // 2) Parent of outer is <frame> or <iframe>;
- // 3) Parent is any other scrollable block element.
- if (!candidateParent.isNull()) {
- candidate.parentAlignment = candidateParent.alignment;
- candidate.parentDistance = candidateParent.distance;
- candidate.enclosingScrollableBox = candidateParent.node;
-
- } else if (!isInRootDocument(outer)) {
- if (Document* document = static_cast<Document*>(outer->parentNode()))
- candidate.enclosingScrollableBox = static_cast<Node*>(document->ownerElement());
-
- } else if (isScrollableContainerNode(outer->parentNode()))
- candidate.enclosingScrollableBox = outer->parentNode();
-
- // Get distance and alignment from current candidate.
- distanceDataForNode(direction, focusedNode, candidate);
-
- // Bail out if distance is maximum.
- if (candidate.distance == maxDistance()) {
- node = node->traverseNextNode(outer->parentNode());
- continue;
- }
-
- updateFocusCandidateIfCloser(focusedNode, candidate, closest);
- }
-
- node = node->traverseNextNode(outer->parentNode());
- }
-}
-
-void FocusController::deepFindFocusableNodeInDirection(Node* container, Node* focusedNode,
- FocusDirection direction, KeyboardEvent* event,
- FocusCandidate& closest)
-{
- ASSERT(container->hasTagName(frameTag)
- || container->hasTagName(iframeTag)
- || isScrollableContainerNode(container));
-
- // Track if focusedNode is a descendant of the current container node being processed.
- bool descendantOfContainer = false;
- Node* firstChild = 0;
-
- // Iframe or Frame.
- if (container->hasTagName(frameTag) || container->hasTagName(iframeTag)) {
-
- HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(container);
- if (!owner->contentFrame())
- return;
-
- Document* innerDocument = owner->contentFrame()->document();
- if (!innerDocument)
- return;
-
- descendantOfContainer = isNodeDeepDescendantOfDocument(focusedNode, innerDocument);
- firstChild = innerDocument->firstChild();
-
- // Scrollable block elements (e.g. <div>, etc)
- } else if (isScrollableContainerNode(container)) {
-
- firstChild = container->firstChild();
- descendantOfContainer = focusedNode->isDescendantOf(container);
- }
-
- if (descendantOfContainer) {
- findFocusableNodeInDirection(firstChild, focusedNode, direction, event, closest);
- return;
- }
-
- // Check if the current container element itself is a good candidate
- // to move focus to. If it is, then we traverse its inner nodes.
- FocusCandidate candidateParent = FocusCandidate(container);
- distanceDataForNode(direction, focusedNode, candidateParent);
-
- // Bail out if distance is maximum.
- if (candidateParent.distance == maxDistance())
- return;
-
- // FIXME: Consider alignment?
- if (candidateParent.distance < closest.distance)
- findFocusableNodeInDirection(firstChild, focusedNode, direction, event, closest, candidateParent);
-}
-
static bool relinquishesEditingFocus(Node *node)
{
ASSERT(node);
@@ -658,4 +412,180 @@ void FocusController::setActive(bool active)
dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), active);
}
+void updateFocusCandidateIfNeeded(FocusDirection direction, const IntRect& startingRect, FocusCandidate& candidate, FocusCandidate& closest)
+{
+ if (!candidate.node->isElementNode() || !candidate.node->renderer())
+ return;
+
+ // Ignore iframes that don't have a src attribute
+ if (candidate.node->isFrameOwnerElement() && !static_cast<HTMLFrameOwnerElement*>(candidate.node)->contentFrame())
+ return;
+
+ // Ignore off screen child nodes of containers that do not scroll (overflow:hidden)
+ if (candidate.isOffscreen && !canBeScrolledIntoView(direction, candidate))
+ return;
+
+ FocusCandidate current;
+ current.rect = startingRect;
+ distanceDataForNode(direction, current, candidate);
+ if (candidate.distance == maxDistance())
+ return;
+
+ if (candidate.isOffscreenAfterScrolling && candidate.alignment < Full)
+ return;
+
+ if (closest.isNull()) {
+ closest = candidate;
+ return;
+ }
+
+ IntRect intersectionRect = intersection(candidate.rect, closest.rect);
+ if (!intersectionRect.isEmpty()) {
+ // If 2 nodes are intersecting, do hit test to find which node in on top.
+ int x = intersectionRect.x() + intersectionRect.width() / 2;
+ int y = intersectionRect.y() + intersectionRect.height() / 2;
+ HitTestResult result = candidate.node->document()->page()->mainFrame()->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), false, true);
+ if (candidate.node->contains(result.innerNode())) {
+ closest = candidate;
+ return;
+ }
+ if (closest.node->contains(result.innerNode()))
+ return;
+ }
+
+ if (candidate.alignment == closest.alignment) {
+ if (candidate.distance < closest.distance)
+ closest = candidate;
+ return;
+ }
+
+ if (candidate.alignment > closest.alignment)
+ closest = candidate;
+}
+
+void FocusController::findFocusCandidateInContainer(Node* container, const IntRect& startingRect, FocusDirection direction, KeyboardEvent* event, FocusCandidate& closest)
+{
+ ASSERT(container);
+ Node* focusedNode = (focusedFrame() && focusedFrame()->document()) ? focusedFrame()->document()->focusedNode() : 0;
+
+ Node* node = container->firstChild();
+ for (; node; node = (node->isFrameOwnerElement() || canScrollInDirection(direction, node)) ? node->traverseNextSibling(container) : node->traverseNextNode(container)) {
+ if (node == focusedNode)
+ continue;
+
+ if (!node->renderer())
+ continue;
+
+ if (!node->isKeyboardFocusable(event) && !node->isFrameOwnerElement() && !canScrollInDirection(direction, node))
+ continue;
+
+ FocusCandidate candidate(node, direction);
+ candidate.enclosingScrollableBox = container;
+ updateFocusCandidateIfNeeded(direction, startingRect, candidate, closest);
+ }
+}
+
+bool FocusController::advanceFocusDirectionallyInContainer(Node* container, const IntRect& startingRect, FocusDirection direction, KeyboardEvent* event)
+{
+ if (!container || !container->document())
+ return false;
+
+ IntRect newStartingRect = startingRect;
+
+ if (startingRect.isEmpty())
+ newStartingRect = virtualRectForDirection(direction, nodeRectInAbsoluteCoordinates(container));
+
+ // Find the closest node within current container in the direction of the navigation.
+ FocusCandidate focusCandidate;
+ findFocusCandidateInContainer(container, newStartingRect, direction, event, focusCandidate);
+
+ if (focusCandidate.isNull()) {
+ if (canScrollInDirection(direction, container)) {
+ // Nothing to focus, scroll if possible.
+ scrollInDirection(container, direction);
+ return true;
+ }
+ // Return false will cause a re-try, skipping this container.
+ return false;
+ }
+ if (focusCandidate.node->isFrameOwnerElement()) {
+ HTMLFrameOwnerElement* frameElement = static_cast<HTMLFrameOwnerElement*>(focusCandidate.node);
+ // If we have an iframe without the src attribute, it will not have a contentFrame().
+ // We ASSERT here to make sure that
+ // updateFocusCandidateIfNeeded() will never consider such an iframe as a candidate.
+ ASSERT(frameElement->contentFrame());
+
+ if (focusCandidate.isOffscreenAfterScrolling) {
+ scrollInDirection(focusCandidate.node->document(), direction);
+ return true;
+ }
+ // Navigate into a new frame.
+ IntRect rect;
+ Node* focusedNode = focusedOrMainFrame()->document()->focusedNode();
+ if (focusedNode && !hasOffscreenRect(focusedNode))
+ rect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */);
+ frameElement->contentFrame()->document()->updateLayoutIgnorePendingStylesheets();
+ if (!advanceFocusDirectionallyInContainer(frameElement->contentFrame()->document(), rect, direction, event)) {
+ // The new frame had nothing interesting, need to find another candidate.
+ return advanceFocusDirectionallyInContainer(container, nodeRectInAbsoluteCoordinates(focusCandidate.node, true), direction, event);
+ }
+ return true;
+ }
+ if (canScrollInDirection(direction, focusCandidate.node)) {
+ if (focusCandidate.isOffscreenAfterScrolling) {
+ scrollInDirection(focusCandidate.node, direction);
+ return true;
+ }
+ // Navigate into a new scrollable container.
+ IntRect startingRect;
+ Node* focusedNode = focusedOrMainFrame()->document()->focusedNode();
+ if (focusedNode && !hasOffscreenRect(focusedNode))
+ startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true);
+ return advanceFocusDirectionallyInContainer(focusCandidate.node, startingRect, direction, event);
+ }
+ if (focusCandidate.isOffscreenAfterScrolling) {
+ Node* container = focusCandidate.enclosingScrollableBox;
+ scrollInDirection(container, direction);
+ return true;
+ }
+
+ // We found a new focus node, navigate to it.
+ Element* element = toElement(focusCandidate.node);
+ ASSERT(element);
+
+ element->focus(false);
+ return true;
+}
+
+bool FocusController::advanceFocusDirectionally(FocusDirection direction, KeyboardEvent* event)
+{
+ Frame* curFrame = focusedOrMainFrame();
+ ASSERT(curFrame);
+
+ Document* focusedDocument = curFrame->document();
+ if (!focusedDocument)
+ return false;
+
+ Node* focusedNode = focusedDocument->focusedNode();
+ Node* container = focusedDocument;
+
+ // Figure out the starting rect.
+ IntRect startingRect;
+ if (focusedNode && !hasOffscreenRect(focusedNode)) {
+ container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, focusedNode);
+ startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */);
+ }
+
+ bool consumed = false;
+ do {
+ if (container->isDocumentNode())
+ static_cast<Document*>(container)->updateLayoutIgnorePendingStylesheets();
+ consumed = advanceFocusDirectionallyInContainer(container, startingRect, direction, event);
+ startingRect = nodeRectInAbsoluteCoordinates(container, true /* ignore border */);
+ container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, container);
+ } while (!consumed && container);
+
+ return consumed;
+}
+
} // namespace WebCore
diff --git a/WebCore/page/FocusController.h b/WebCore/page/FocusController.h
index 050a08f..be51c77 100644
--- a/WebCore/page/FocusController.h
+++ b/WebCore/page/FocusController.h
@@ -63,10 +63,8 @@ private:
bool advanceFocusDirectionally(FocusDirection, KeyboardEvent*);
bool advanceFocusInDocumentOrder(FocusDirection, KeyboardEvent*, bool initialFocus);
- void findFocusableNodeInDirection(Node* outter, Node*, FocusDirection, KeyboardEvent*,
- FocusCandidate& closestFocusCandidate,
- const FocusCandidate& parentCandidate = FocusCandidate());
- void deepFindFocusableNodeInDirection(Node* container, Node* focused, FocusDirection, KeyboardEvent*, FocusCandidate&);
+ bool advanceFocusDirectionallyInContainer(Node* container, const IntRect& startingRect, FocusDirection, KeyboardEvent*);
+ void findFocusCandidateInContainer(Node* container, const IntRect& startingRect, FocusDirection, KeyboardEvent*, FocusCandidate& closest);
Page* m_page;
RefPtr<Frame> m_focusedFrame;
diff --git a/WebCore/page/Frame.cpp b/WebCore/page/Frame.cpp
index a97fcb5..17062c5 100644
--- a/WebCore/page/Frame.cpp
+++ b/WebCore/page/Frame.cpp
@@ -715,10 +715,11 @@ void Frame::transferChildFrameToNewDocument()
{
ASSERT(m_ownerElement);
Frame* newParent = m_ownerElement->document()->frame();
+ ASSERT(newParent);
bool didTransfer = false;
// Switch page.
- Page* newPage = newParent ? newParent->page() : 0;
+ Page* newPage = newParent->page();
Page* oldPage = m_page;
if (m_page != newPage) {
if (m_page) {
@@ -736,10 +737,8 @@ void Frame::transferChildFrameToNewDocument()
didTransfer = true;
}
- if (newParent) {
- // Update the frame tree.
- didTransfer = newParent->tree()->transferChild(this);
- }
+ // Update the frame tree.
+ didTransfer = newParent->tree()->transferChild(this) || didTransfer;
// Avoid unnecessary calls to client and frame subtree if the frame ended
// up on the same page and under the same parent frame.
diff --git a/WebCore/page/FrameView.cpp b/WebCore/page/FrameView.cpp
index 17ba2bc..d9a7e98 100644
--- a/WebCore/page/FrameView.cpp
+++ b/WebCore/page/FrameView.cpp
@@ -312,7 +312,7 @@ bool FrameView::didFirstLayout() const
void FrameView::invalidateRect(const IntRect& rect)
{
if (!parent()) {
- if (hostWindow())
+ if (hostWindow() && shouldUpdate())
hostWindow()->invalidateContentsAndWindow(rect, false /*immediate*/);
return;
}
@@ -358,17 +358,7 @@ void FrameView::setMarginHeight(int h)
m_margins.setHeight(h);
}
-bool FrameView::delegatesScrolling()
-{
- ASSERT(m_frame);
-
- if (parent())
- return false;
-
- return m_frame->settings() && m_frame->settings()->shouldDelegateScrolling();
-}
-
-bool FrameView::avoidScrollbarCreation()
+bool FrameView::avoidScrollbarCreation() const
{
ASSERT(m_frame);
@@ -454,7 +444,11 @@ void FrameView::adjustViewSize()
if (!root)
return;
- setContentsSize(IntSize(root->rightLayoutOverflow(), root->bottomLayoutOverflow()));
+ IntSize size = IntSize(root->rightLayoutOverflow() - root->leftLayoutOverflow(), root->bottomLayoutOverflow() - root->topLayoutOverflow());
+
+ ScrollView::setScrollOrigin(IntPoint(-root->leftLayoutOverflow(), -root->topLayoutOverflow()), size == contentsSize());
+
+ setContentsSize(size);
}
void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
@@ -1380,7 +1374,7 @@ void FrameView::repaintContentRectangle(const IntRect& r, bool immediate)
return;
}
- if (!immediate && isOffscreen() && !shouldUpdateWhileOffscreen())
+ if (!shouldUpdate(immediate))
return;
#if ENABLE(TILED_BACKING_STORE)
@@ -1454,7 +1448,7 @@ void FrameView::checkStopDelayingDeferredRepaints()
void FrameView::doDeferredRepaints()
{
ASSERT(!m_deferringRepaints);
- if (isOffscreen() && !shouldUpdateWhileOffscreen()) {
+ if (!shouldUpdate()) {
m_repaintRects.clear();
m_repaintCount = 0;
return;
@@ -1700,6 +1694,15 @@ void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
}
+bool FrameView::shouldUpdate(bool immediateRequested) const
+{
+ if (!immediateRequested && isOffscreen() && !shouldUpdateWhileOffscreen())
+ return false;
+ if (!m_frame || !m_frame->document() || m_frame->document()->mayCauseFlashOfUnstyledContent())
+ return false;
+ return true;
+}
+
void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<Node> eventTarget)
{
if (!m_enqueueEvents) {
diff --git a/WebCore/page/FrameView.h b/WebCore/page/FrameView.h
index 87924b2..d56b1ef 100644
--- a/WebCore/page/FrameView.h
+++ b/WebCore/page/FrameView.h
@@ -76,8 +76,7 @@ public:
virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation);
- virtual bool delegatesScrolling();
- virtual bool avoidScrollbarCreation();
+ virtual bool avoidScrollbarCreation() const;
virtual void setContentsSize(const IntSize&);
@@ -140,6 +139,7 @@ public:
bool shouldUpdateWhileOffscreen() const;
void setShouldUpdateWhileOffscreen(bool);
+ bool shouldUpdate(bool = false) const;
void adjustViewSize();
@@ -238,6 +238,8 @@ public:
bool isFrameViewScrollCorner(RenderScrollbarPart* scrollCorner) const { return m_scrollCorner == scrollCorner; }
void invalidateScrollCorner();
+ void calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode);
+
// Normal delay
static void setRepaintThrottlingDeferredRepaintDelay(double p);
// Negative value would mean that first few repaints happen without a delay
@@ -267,7 +269,6 @@ private:
bool hasFixedObjects() const { return m_fixedObjectCount > 0; }
void applyOverflowToViewport(RenderObject*, ScrollbarMode& hMode, ScrollbarMode& vMode);
- void calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode);
void updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow);
diff --git a/WebCore/page/Geolocation.cpp b/WebCore/page/Geolocation.cpp
index 65c8902..cabfdef 100644
--- a/WebCore/page/Geolocation.cpp
+++ b/WebCore/page/Geolocation.cpp
@@ -525,6 +525,30 @@ void Geolocation::cancelAllRequests()
cancelRequests(copy);
}
+void Geolocation::extractNotifiersWithCachedPosition(GeoNotifierVector& notifiers, GeoNotifierVector* cached)
+{
+ GeoNotifierVector nonCached;
+ GeoNotifierVector::iterator end = notifiers.end();
+ for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it) {
+ GeoNotifier* notifier = it->get();
+ if (notifier->m_useCachedPosition) {
+ if (cached)
+ cached->append(notifier);
+ } else
+ nonCached.append(notifier);
+ }
+ notifiers.swap(nonCached);
+}
+
+void Geolocation::copyToSet(const GeoNotifierVector& src, GeoNotifierSet& dest)
+{
+ GeoNotifierVector::const_iterator end = src.end();
+ for (GeoNotifierVector::const_iterator it = src.begin(); it != end; ++it) {
+ GeoNotifier* notifier = it->get();
+ dest.add(notifier);
+ }
+}
+
void Geolocation::handleError(PositionError* error)
{
ASSERT(error);
@@ -538,15 +562,27 @@ void Geolocation::handleError(PositionError* error)
// Clear the lists before we make the callbacks, to avoid clearing notifiers
// added by calls to Geolocation methods from the callbacks, and to prevent
// further callbacks to these notifiers.
+ GeoNotifierVector oneShotsWithCachedPosition;
m_oneShots.clear();
if (error->isFatal())
m_watchers.clear();
+ else {
+ // Don't send non-fatal errors to notifiers due to receive a cached position.
+ extractNotifiersWithCachedPosition(oneShotsCopy, &oneShotsWithCachedPosition);
+ extractNotifiersWithCachedPosition(watchersCopy, 0);
+ }
sendError(oneShotsCopy, error);
sendError(watchersCopy, error);
+ // hasListeners() doesn't distinguish between notifiers due to receive a
+ // cached position and those requiring a fresh position. Perform the check
+ // before restoring the notifiers below.
if (!hasListeners())
stopUpdating();
+
+ // Maintain a reference to the cached notifiers until their timer fires.
+ copyToSet(oneShotsWithCachedPosition, m_oneShots);
}
void Geolocation::requestPermission()
diff --git a/WebCore/page/Geolocation.h b/WebCore/page/Geolocation.h
index a3a79f9..306214b 100644
--- a/WebCore/page/Geolocation.h
+++ b/WebCore/page/Geolocation.h
@@ -133,6 +133,9 @@ private:
void sendError(GeoNotifierVector&, PositionError*);
void sendPosition(GeoNotifierVector&, Geoposition*);
+ static void extractNotifiersWithCachedPosition(GeoNotifierVector& notifiers, GeoNotifierVector* cached);
+ static void copyToSet(const GeoNotifierVector&, GeoNotifierSet&);
+
static void stopTimer(GeoNotifierVector&);
void stopTimersForOneShots();
void stopTimersForWatchers();
diff --git a/WebCore/page/Page.cpp b/WebCore/page/Page.cpp
index 5453e1e..2726142 100644
--- a/WebCore/page/Page.cpp
+++ b/WebCore/page/Page.cpp
@@ -525,25 +525,31 @@ static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap)
{
+ return findString(target, (caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0) | (direction == FindDirectionBackward ? Backwards : 0) | (shouldWrap ? WrapAround : 0));
+}
+
+bool Page::findString(const String& target, FindOptions options)
+{
if (target.isEmpty() || !mainFrame())
return false;
+ bool shouldWrap = options & WrapAround;
Frame* frame = focusController()->focusedOrMainFrame();
Frame* startFrame = frame;
do {
- if (frame->editor()->findString(target, direction == FindDirectionForward, caseSensitivity == TextCaseSensitive, false, true)) {
+ if (frame->editor()->findString(target, (options & ~WrapAround) | StartInSelection)) {
if (frame != startFrame)
startFrame->selection()->clear();
focusController()->setFocusedFrame(frame);
return true;
}
- frame = incrementFrame(frame, direction == FindDirectionForward, shouldWrap);
+ frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
} while (frame && frame != startFrame);
// Search contents of startFrame, on the other side of the selection that we did earlier.
// We cheat a bit and just research with wrap on
if (shouldWrap && !startFrame->selection()->isNone()) {
- bool found = startFrame->editor()->findString(target, direction == FindDirectionForward, caseSensitivity == TextCaseSensitive, true, true);
+ bool found = startFrame->editor()->findString(target, options | WrapAround | StartInSelection);
focusController()->setFocusedFrame(frame);
return found;
}
@@ -553,6 +559,11 @@ bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity,
unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit)
{
+ return markAllMatchesForText(target, caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0, shouldHighlight, limit);
+}
+
+unsigned int Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned limit)
+{
if (target.isEmpty() || !mainFrame())
return 0;
@@ -561,7 +572,7 @@ unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivi
Frame* frame = mainFrame();
do {
frame->editor()->setMarkedTextMatchesAreHighlighted(shouldHighlight);
- matches += frame->editor()->countMatchesForText(target, caseSensitivity == TextCaseSensitive, limit ? (limit - matches) : 0, true);
+ matches += frame->editor()->countMatchesForText(target, options, limit ? (limit - matches) : 0, true);
frame = incrementFrame(frame, true, false);
} while (frame);
diff --git a/WebCore/page/Page.h b/WebCore/page/Page.h
index e074814..a938932 100644
--- a/WebCore/page/Page.h
+++ b/WebCore/page/Page.h
@@ -22,6 +22,7 @@
#define Page_h
#include "FrameLoaderTypes.h"
+#include "FindOptions.h"
#include "PlatformString.h"
#include "ViewportArguments.h"
#include <wtf/Forward.h>
@@ -198,8 +199,12 @@ namespace WebCore {
void setTabKeyCyclesThroughElements(bool b) { m_tabKeyCyclesThroughElements = b; }
bool tabKeyCyclesThroughElements() const { return m_tabKeyCyclesThroughElements; }
+ bool findString(const String&, FindOptions);
+ // FIXME: Switch callers over to the FindOptions version and retire this one.
bool findString(const String&, TextCaseSensitivity, FindDirection, bool shouldWrap);
- unsigned int markAllMatchesForText(const String&, TextCaseSensitivity, bool shouldHighlight, unsigned);
+ unsigned markAllMatchesForText(const String&, FindOptions, bool shouldHighlight, unsigned);
+ // FIXME: Switch callers over to the FindOptions version and retire this one.
+ unsigned markAllMatchesForText(const String&, TextCaseSensitivity, bool shouldHighlight, unsigned);
void unmarkAllTextMatches();
#if PLATFORM(MAC)
diff --git a/WebCore/page/PerformanceTiming.cpp b/WebCore/page/PerformanceTiming.cpp
index 4fc16da..82b7027 100644
--- a/WebCore/page/PerformanceTiming.cpp
+++ b/WebCore/page/PerformanceTiming.cpp
@@ -93,6 +93,15 @@ unsigned long long PerformanceTiming::navigationStart() const
return toIntegerMilliseconds(timing->navigationStart);
}
+unsigned long long PerformanceTiming::unloadEventStart() const
+{
+ DocumentLoadTiming* timing = documentLoadTiming();
+ if (!timing)
+ return 0;
+
+ return toIntegerMilliseconds(timing->unloadEventStart);
+}
+
unsigned long long PerformanceTiming::unloadEventEnd() const
{
DocumentLoadTiming* timing = documentLoadTiming();
diff --git a/WebCore/page/PerformanceTiming.h b/WebCore/page/PerformanceTiming.h
index 5124e2b..3b5e8b4 100644
--- a/WebCore/page/PerformanceTiming.h
+++ b/WebCore/page/PerformanceTiming.h
@@ -52,6 +52,7 @@ public:
void disconnectFrame();
unsigned long long navigationStart() const;
+ unsigned long long unloadEventStart() const;
unsigned long long unloadEventEnd() const;
unsigned long long redirectStart() const;
unsigned long long redirectEnd() const;
diff --git a/WebCore/page/PerformanceTiming.idl b/WebCore/page/PerformanceTiming.idl
index 49442b0..a13b8d7 100644
--- a/WebCore/page/PerformanceTiming.idl
+++ b/WebCore/page/PerformanceTiming.idl
@@ -33,6 +33,7 @@ module window {
// See: http://dev.w3.org/2006/webapi/WebTiming/
interface [Conditional=WEB_TIMING, OmitConstructor] PerformanceTiming {
readonly attribute unsigned long long navigationStart;
+ readonly attribute unsigned long long unloadEventStart;
readonly attribute unsigned long long unloadEventEnd;
readonly attribute unsigned long long redirectStart;
readonly attribute unsigned long long redirectEnd;
diff --git a/WebCore/page/SecurityOrigin.cpp b/WebCore/page/SecurityOrigin.cpp
index 9ad23c6..82af42a 100644
--- a/WebCore/page/SecurityOrigin.cpp
+++ b/WebCore/page/SecurityOrigin.cpp
@@ -275,6 +275,9 @@ bool SecurityOrigin::taintsCanvas(const KURL& url) const
bool SecurityOrigin::canReceiveDragData(const SecurityOrigin* dragInitiator) const
{
+ if (this == dragInitiator)
+ return true;
+
// FIXME: Currently we treat data URLs as having a unique origin, contrary to the
// current (9/19/2009) draft of the HTML5 specification. We still want to allow
// drop across data URLs, so we special case data URLs below. If we change to
diff --git a/WebCore/page/Settings.cpp b/WebCore/page/Settings.cpp
index 069296a..d150033 100644
--- a/WebCore/page/Settings.cpp
+++ b/WebCore/page/Settings.cpp
@@ -110,6 +110,7 @@ Settings::Settings(Page* page)
, m_sessionStorageQuota(StorageMap::noQuota)
#endif
, m_pluginAllowedRunTime(numeric_limits<unsigned>::max())
+ , m_editingBehaviorType(editingBehaviorTypeForPlatform())
, m_isSpatialNavigationEnabled(false)
, m_isJavaEnabled(false)
, m_loadsImagesAutomatically(false)
@@ -126,7 +127,6 @@ Settings::Settings(Page* page)
, m_javaScriptCanOpenWindowsAutomatically(false)
, m_javaScriptCanAccessClipboard(false)
, m_shouldPrintBackgrounds(false)
- , m_shouldDelegateScrolling(false)
, m_textAreasAreResizable(false)
#if ENABLE(DASHBOARD_SUPPORT)
, m_usesDashboardBackwardCompatibilityMode(false)
@@ -154,12 +154,16 @@ Settings::Settings(Page* page)
, m_enforceCSSMIMETypeInNoQuirksMode(true)
, m_usesEncodingDetector(false)
, m_allowScriptsToCloseWindows(false)
- , m_editingBehaviorType(editingBehaviorTypeForPlatform())
// FIXME: This should really be disabled by default as it makes platforms that don't support the feature download files
// they can't use by. Leaving enabled for now to not change existing behavior.
, m_downloadableBinaryFontsEnabled(true)
, m_xssAuditorEnabled(false)
, m_acceleratedCompositingEnabled(true)
+ , m_acceleratedCompositingFor3DTransformsEnabled(true)
+ , m_acceleratedCompositingForVideoEnabled(true)
+ , m_acceleratedCompositingForPluginsEnabled(true)
+ , m_acceleratedCompositingForCanvasEnabled(true)
+ , m_acceleratedCompositingForAnimationEnabled(true)
, m_showDebugBorders(false)
, m_showRepaintCounter(false)
, m_experimentalNotificationsEnabled(false)
@@ -395,11 +399,6 @@ void Settings::setShouldPrintBackgrounds(bool shouldPrintBackgrounds)
m_shouldPrintBackgrounds = shouldPrintBackgrounds;
}
-void Settings::setShouldDelegateScrolling(bool shouldDelegateScrolling)
-{
- m_shouldDelegateScrolling = shouldDelegateScrolling;
-}
-
void Settings::setTextAreasAreResizable(bool textAreasAreResizable)
{
if (m_textAreasAreResizable == textAreasAreResizable)
@@ -792,6 +791,31 @@ void Settings::setAcceleratedCompositingEnabled(bool enabled)
setNeedsRecalcStyleInAllFrames(m_page);
}
+void Settings::setAcceleratedCompositingFor3DTransformsEnabled(bool enabled)
+{
+ m_acceleratedCompositingFor3DTransformsEnabled = enabled;
+}
+
+void Settings::setAcceleratedCompositingForVideoEnabled(bool enabled)
+{
+ m_acceleratedCompositingForVideoEnabled = enabled;
+}
+
+void Settings::setAcceleratedCompositingForPluginsEnabled(bool enabled)
+{
+ m_acceleratedCompositingForPluginsEnabled = enabled;
+}
+
+void Settings::setAcceleratedCompositingForCanvasEnabled(bool enabled)
+{
+ m_acceleratedCompositingForCanvasEnabled = enabled;
+}
+
+void Settings::setAcceleratedCompositingForAnimationEnabled(bool enabled)
+{
+ m_acceleratedCompositingForAnimationEnabled = enabled;
+}
+
void Settings::setShowDebugBorders(bool enabled)
{
if (m_showDebugBorders == enabled)
diff --git a/WebCore/page/Settings.h b/WebCore/page/Settings.h
index 0d5b875..5b42e89 100644
--- a/WebCore/page/Settings.h
+++ b/WebCore/page/Settings.h
@@ -198,9 +198,6 @@ namespace WebCore {
void setShouldPrintBackgrounds(bool);
bool shouldPrintBackgrounds() const { return m_shouldPrintBackgrounds; }
- void setShouldDelegateScrolling(bool);
- bool shouldDelegateScrolling() const { return m_shouldDelegateScrolling; }
-
void setTextAreasAreResizable(bool);
bool textAreasAreResizable() const { return m_textAreasAreResizable; }
@@ -350,6 +347,21 @@ namespace WebCore {
void setAcceleratedCompositingEnabled(bool);
bool acceleratedCompositingEnabled() const { return m_acceleratedCompositingEnabled; }
+ void setAcceleratedCompositingFor3DTransformsEnabled(bool);
+ bool acceleratedCompositingFor3DTransformsEnabled() const { return m_acceleratedCompositingFor3DTransformsEnabled; }
+
+ void setAcceleratedCompositingForVideoEnabled(bool);
+ bool acceleratedCompositingForVideoEnabled() const { return m_acceleratedCompositingForVideoEnabled; }
+
+ void setAcceleratedCompositingForPluginsEnabled(bool);
+ bool acceleratedCompositingForPluginsEnabled() const { return m_acceleratedCompositingForPluginsEnabled; }
+
+ void setAcceleratedCompositingForCanvasEnabled(bool);
+ bool acceleratedCompositingForCanvasEnabled() const { return m_acceleratedCompositingForCanvasEnabled; }
+
+ void setAcceleratedCompositingForAnimationEnabled(bool);
+ bool acceleratedCompositingForAnimationEnabled() const { return m_acceleratedCompositingForAnimationEnabled; }
+
void setShowDebugBorders(bool);
bool showDebugBorders() const { return m_showDebugBorders; }
@@ -473,6 +485,7 @@ namespace WebCore {
unsigned m_sessionStorageQuota;
#endif
unsigned m_pluginAllowedRunTime;
+ unsigned m_editingBehaviorType;
bool m_isSpatialNavigationEnabled : 1;
bool m_isJavaEnabled : 1;
bool m_loadsImagesAutomatically : 1;
@@ -489,7 +502,6 @@ namespace WebCore {
bool m_javaScriptCanOpenWindowsAutomatically : 1;
bool m_javaScriptCanAccessClipboard : 1;
bool m_shouldPrintBackgrounds : 1;
- bool m_shouldDelegateScrolling : 1;
bool m_textAreasAreResizable : 1;
#if ENABLE(DASHBOARD_SUPPORT)
bool m_usesDashboardBackwardCompatibilityMode : 1;
@@ -517,10 +529,14 @@ namespace WebCore {
bool m_enforceCSSMIMETypeInNoQuirksMode : 1;
bool m_usesEncodingDetector : 1;
bool m_allowScriptsToCloseWindows : 1;
- unsigned m_editingBehaviorType : 1;
bool m_downloadableBinaryFontsEnabled : 1;
bool m_xssAuditorEnabled : 1;
bool m_acceleratedCompositingEnabled : 1;
+ bool m_acceleratedCompositingFor3DTransformsEnabled : 1;
+ bool m_acceleratedCompositingForVideoEnabled : 1;
+ bool m_acceleratedCompositingForPluginsEnabled : 1;
+ bool m_acceleratedCompositingForCanvasEnabled : 1;
+ bool m_acceleratedCompositingForAnimationEnabled : 1;
bool m_showDebugBorders : 1;
bool m_showRepaintCounter : 1;
bool m_experimentalNotificationsEnabled : 1;
diff --git a/WebCore/page/SpatialNavigation.cpp b/WebCore/page/SpatialNavigation.cpp
index a42435f..ffc65b4 100644
--- a/WebCore/page/SpatialNavigation.cpp
+++ b/WebCore/page/SpatialNavigation.cpp
@@ -41,103 +41,40 @@
namespace WebCore {
-static long long spatialDistance(FocusDirection, const IntRect&, const IntRect&);
-static IntRect renderRectRelativeToRootDocument(RenderObject*);
-static RectsAlignment alignmentForRects(FocusDirection, const IntRect&, const IntRect&);
+static RectsAlignment alignmentForRects(FocusDirection, const IntRect&, const IntRect&, const IntSize& viewSize);
static bool areRectsFullyAligned(FocusDirection, const IntRect&, const IntRect&);
static bool areRectsPartiallyAligned(FocusDirection, const IntRect&, const IntRect&);
+static bool areRectsMoreThanFullScreenApart(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect, const IntSize& viewSize);
static bool isRectInDirection(FocusDirection, const IntRect&, const IntRect&);
static void deflateIfOverlapped(IntRect&, IntRect&);
-static bool checkNegativeCoordsForNode(Node*, const IntRect&);
-
-bool isSpatialNavigationEnabled(const Frame* frame)
+static IntRect rectToAbsoluteCoordinates(Frame* initialFrame, const IntRect& rect);
+static void entryAndExitPointsForDirection(FocusDirection direction, const IntRect& startingRect, const IntRect& potentialRect, IntPoint& exitPoint, IntPoint& entryPoint);
+
+
+FocusCandidate::FocusCandidate(Node* n, FocusDirection direction)
+ : node(n)
+ , enclosingScrollableBox(0)
+ , distance(maxDistance())
+ , parentDistance(maxDistance())
+ , alignment(None)
+ , parentAlignment(None)
+ , rect(nodeRectInAbsoluteCoordinates(n, true /* ignore border */))
+ , isOffscreen(hasOffscreenRect(n))
+ , isOffscreenAfterScrolling(hasOffscreenRect(n, direction))
{
- return (frame && frame->settings() && frame->settings()->isSpatialNavigationEnabled());
}
-void distanceDataForNode(FocusDirection direction, Node* start, FocusCandidate& candidate)
+bool isSpatialNavigationEnabled(const Frame* frame)
{
- 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);
+ return (frame && frame->settings() && frame->settings()->isSpatialNavigationEnabled());
}
-// FIXME: This function does not behave correctly with transformed frames.
-static IntRect renderRectRelativeToRootDocument(RenderObject* render)
+static RectsAlignment alignmentForRects(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect, const IntSize& viewSize)
{
- ASSERT(render && render->node());
-
- IntRect rect = render->node()->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());
- }
+ // If we found a node in full alignment, but it is too far away, ignore it.
+ if (areRectsMoreThanFullScreenApart(direction, curRect, targetRect, viewSize))
+ return None;
- // Handle nested frames.
- for (Frame* frame = render->document()->frame(); frame; frame = frame->tree()->parent()) {
- if (Element* element = static_cast<Element*>(frame->ownerElement())) {
- do {
- rect.move(element->offsetLeft(), element->offsetTop());
- } while ((element = element->offsetParent()));
- }
- }
-
- return rect;
-}
-
-static RectsAlignment alignmentForRects(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect)
-{
if (areRectsFullyAligned(direction, curRect, targetRect))
return Full;
@@ -277,6 +214,25 @@ static bool areRectsPartiallyAligned(FocusDirection direction, const IntRect& a,
|| (bEnd >= aStart && bEnd <= aEnd));
}
+static bool areRectsMoreThanFullScreenApart(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect, const IntSize& viewSize)
+{
+ ASSERT(isRectInDirection(direction, curRect, targetRect));
+
+ switch (direction) {
+ case FocusDirectionLeft:
+ return curRect.x() - targetRect.right() > viewSize.width();
+ case FocusDirectionRight:
+ return targetRect.x() - curRect.right() > viewSize.width();
+ case FocusDirectionUp:
+ return curRect.y() - targetRect.bottom() > viewSize.height();
+ case FocusDirectionDown:
+ return targetRect.y() - curRect.bottom() > viewSize.height();
+ default:
+ ASSERT_NOT_REACHED();
+ return true;
+ }
+}
+
// Return true if rect |a| is below |b|. False otherwise.
static inline bool below(const IntRect& a, const IntRect& b)
{
@@ -289,143 +245,27 @@ 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();
+ return targetRect.right() <= curRect.x();
case FocusDirectionRight:
- return targetMiddle > curRect.right();
+ return targetRect.x() >= curRect.right();
case FocusDirectionUp:
- return targetMiddle < curRect.y();
+ return targetRect.bottom() <= curRect.y();
case FocusDirectionDown:
- return targetMiddle > curRect.bottom();
+ return targetRect.y() >= curRect.bottom();
default:
ASSERT_NOT_REACHED();
+ return false;
}
-
- 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)
+bool hasOffscreenRect(Node* node, FocusDirection direction)
{
// 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
@@ -435,68 +275,106 @@ bool hasOffscreenRect(Node* node)
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, const FocusCandidate& candidate)
-{
- if (!frame)
- return false;
-
- ScrollDirection scrollDirection;
-
+ // We want to select a node if it is currently off screen, but will be
+ // exposed after we scroll. Adjust the viewport to post-scrolling position.
+ // If the container has overflow:hidden, we cannot scroll, so we do not pass direction
+ // and we do not adjust for scrolling.
switch (direction) {
case FocusDirectionLeft:
- scrollDirection = ScrollLeft;
+ containerViewportRect.setX(containerViewportRect.x() - Scrollbar::pixelsPerLineStep());
+ containerViewportRect.setWidth(containerViewportRect.width() + Scrollbar::pixelsPerLineStep());
break;
case FocusDirectionRight:
- scrollDirection = ScrollRight;
+ containerViewportRect.setWidth(containerViewportRect.width() + Scrollbar::pixelsPerLineStep());
break;
case FocusDirectionUp:
- scrollDirection = ScrollUp;
+ containerViewportRect.setY(containerViewportRect.y() - Scrollbar::pixelsPerLineStep());
+ containerViewportRect.setHeight(containerViewportRect.height() + Scrollbar::pixelsPerLineStep());
break;
case FocusDirectionDown:
- scrollDirection = ScrollDown;
+ containerViewportRect.setHeight(containerViewportRect.height() + Scrollbar::pixelsPerLineStep());
break;
default:
- return false;
+ break;
}
- if (!candidate.isNull() && isScrollableContainerNode(candidate.enclosingScrollableBox))
- return frame->eventHandler()->scrollRecursively(scrollDirection, ScrollByLine, candidate.enclosingScrollableBox);
+ RenderObject* render = node->renderer();
+ if (!render)
+ return true;
+
+ IntRect rect(render->absoluteClippedOverflowRect());
+ if (rect.isEmpty())
+ return true;
- return frame->eventHandler()->scrollRecursively(scrollDirection, ScrollByLine);
+ return !containerViewportRect.intersects(rect);
}
-void scrollIntoView(Element* element)
+bool scrollInDirection(Frame* frame, FocusDirection direction)
{
- // 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.
- IntRect bounds = element->getRect();
- bounds.inflate(fudgeFactor());
- element->renderer()->enclosingLayer()->scrollRectToVisible(bounds);
+ ASSERT(frame && canScrollInDirection(direction, frame->document()));
+
+ if (frame && canScrollInDirection(direction, frame->document())) {
+ int dx = 0;
+ int dy = 0;
+ switch (direction) {
+ case FocusDirectionLeft:
+ dx = - Scrollbar::pixelsPerLineStep();
+ break;
+ case FocusDirectionRight:
+ dx = Scrollbar::pixelsPerLineStep();
+ break;
+ case FocusDirectionUp:
+ dy = - Scrollbar::pixelsPerLineStep();
+ break;
+ case FocusDirectionDown:
+ dy = Scrollbar::pixelsPerLineStep();
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
+ frame->view()->scrollBy(IntSize(dx, dy));
+ return true;
+ }
+ return false;
}
-bool isInRootDocument(Node* node)
+bool scrollInDirection(Node* container, FocusDirection direction)
{
- if (!node)
+ if (container->isDocumentNode())
+ return scrollInDirection(static_cast<Document*>(container)->frame(), direction);
+
+ if (!container->renderBox())
return false;
- Document* rootDocument = node->document()->page()->mainFrame()->document();
- return node->document() == rootDocument;
+ if (container && canScrollInDirection(direction, container)) {
+ int dx = 0;
+ int dy = 0;
+ switch (direction) {
+ case FocusDirectionLeft:
+ dx = - min(Scrollbar::pixelsPerLineStep(), container->renderBox()->scrollLeft());
+ break;
+ case FocusDirectionRight:
+ ASSERT(container->renderBox()->scrollWidth() > (container->renderBox()->scrollLeft() + container->renderBox()->clientWidth()));
+ dx = min(Scrollbar::pixelsPerLineStep(), container->renderBox()->scrollWidth() - (container->renderBox()->scrollLeft() + container->renderBox()->clientWidth()));
+ break;
+ case FocusDirectionUp:
+ dy = - min(Scrollbar::pixelsPerLineStep(), container->renderBox()->scrollTop());
+ break;
+ case FocusDirectionDown:
+ ASSERT(container->renderBox()->scrollHeight() - (container->renderBox()->scrollTop() + container->renderBox()->clientHeight()));
+ dy = min(Scrollbar::pixelsPerLineStep(), container->renderBox()->scrollHeight() - (container->renderBox()->scrollTop() + container->renderBox()->clientHeight()));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
+ container->renderBox()->enclosingLayer()->scrollByRecursively(dx, dy);
+ return true;
+ }
+ return false;
}
static void deflateIfOverlapped(IntRect& a, IntRect& b)
@@ -514,57 +392,281 @@ static void deflateIfOverlapped(IntRect& a, IntRect& b)
b.inflate(deflateFactor);
}
-static bool checkNegativeCoordsForNode(Node* node, const IntRect& curRect)
+bool isScrollableContainerNode(const Node* node)
{
- ASSERT(node || node->renderer());
+ if (!node)
+ return false;
- if (curRect.x() >= 0 && curRect.y() >= 0)
- return true;
+ if (RenderObject* renderer = node->renderer()) {
+ return (renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()
+ && node->hasChildNodes() && !node->isDocumentNode());
+ }
- bool canBeScrolled = false;
+ return false;
+}
- RenderObject* renderer = node->renderer();
- for (; renderer; renderer = renderer->parent()) {
- if (renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()) {
- canBeScrolled = true;
- break;
+Node* scrollableEnclosingBoxOrParentFrameForNodeInDirection(FocusDirection direction, Node* node)
+{
+ ASSERT(node);
+ Node* parent = node;
+ do {
+ if (parent->isDocumentNode())
+ parent = static_cast<Document*>(parent)->document()->frame()->ownerElement();
+ else
+ parent = parent->parentNode();
+ } while (parent && !canScrollInDirection(direction, parent) && !parent->isDocumentNode());
+
+ return parent;
+}
+
+bool canScrollInDirection(FocusDirection direction, const Node* container)
+{
+ ASSERT(container);
+ if (container->isDocumentNode())
+ return canScrollInDirection(direction, static_cast<const Document*>(container)->frame());
+
+ if (!isScrollableContainerNode(container))
+ return false;
+
+ switch (direction) {
+ case FocusDirectionLeft:
+ return (container->renderer()->style()->overflowX() != OHIDDEN && container->renderBox()->scrollLeft() > 0);
+ case FocusDirectionUp:
+ return (container->renderer()->style()->overflowY() != OHIDDEN && container->renderBox()->scrollTop() > 0);
+ case FocusDirectionRight:
+ return (container->renderer()->style()->overflowX() != OHIDDEN && container->renderBox()->scrollLeft() + container->renderBox()->clientWidth() < container->renderBox()->scrollWidth());
+ case FocusDirectionDown:
+ return (container->renderer()->style()->overflowY() != OHIDDEN && container->renderBox()->scrollTop() + container->renderBox()->clientHeight() < container->renderBox()->scrollHeight());
+ default:
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+}
+
+bool canScrollInDirection(FocusDirection direction, const Frame* frame)
+{
+ if (!frame->view())
+ return false;
+ ScrollbarMode verticalMode;
+ ScrollbarMode horizontalMode;
+ frame->view()->calculateScrollbarModesForLayout(horizontalMode, verticalMode);
+ if ((direction == FocusDirectionLeft || direction == FocusDirectionRight) && ScrollbarAlwaysOff == horizontalMode)
+ return false;
+ if ((direction == FocusDirectionUp || direction == FocusDirectionDown) && ScrollbarAlwaysOff == verticalMode)
+ return false;
+ IntSize size = frame->view()->contentsSize();
+ IntSize offset = frame->view()->scrollOffset();
+ IntRect rect = frame->view()->visibleContentRect(true);
+
+ switch (direction) {
+ case FocusDirectionLeft:
+ return offset.width() > 0;
+ case FocusDirectionUp:
+ return offset.height() > 0;
+ case FocusDirectionRight:
+ return rect.width() + offset.width() < size.width();
+ case FocusDirectionDown:
+ return rect.height() + offset.height() < size.height();
+ default:
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+}
+
+static IntRect rectToAbsoluteCoordinates(Frame* initialFrame, const IntRect& initialRect)
+{
+ IntRect rect = initialRect;
+ for (Frame* frame = initialFrame; frame; frame = frame->tree()->parent()) {
+ if (Element* element = static_cast<Element*>(frame->ownerElement())) {
+ do {
+ rect.move(element->offsetLeft(), element->offsetTop());
+ } while ((element = element->offsetParent()));
+ rect.move((-frame->view()->scrollOffset()));
}
}
+ return rect;
+}
- return canBeScrolled;
+IntRect nodeRectInAbsoluteCoordinates(Node* node, bool ignoreBorder)
+{
+ ASSERT(node && node->renderer());
+
+ if (node->isDocumentNode())
+ return frameRectInAbsoluteCoordinates(static_cast<Document*>(node)->frame());
+ IntRect rect = rectToAbsoluteCoordinates(node->document()->frame(), node->getRect());
+
+ // For authors that use border instead of outline in their CSS, we compensate by ignoring the border when calculating
+ // the rect of the focused element.
+ if (ignoreBorder) {
+ rect.move(node->renderer()->style()->borderLeftWidth(), node->renderer()->style()->borderTopWidth());
+ rect.setWidth(rect.width() - node->renderer()->style()->borderLeftWidth() - node->renderer()->style()->borderRightWidth());
+ rect.setHeight(rect.height() - node->renderer()->style()->borderTopWidth() - node->renderer()->style()->borderBottomWidth());
+ }
+ return rect;
}
-bool isScrollableContainerNode(Node* node)
+IntRect frameRectInAbsoluteCoordinates(Frame* frame)
{
- if (!node)
- return false;
+ return rectToAbsoluteCoordinates(frame, frame->view()->visibleContentRect());
+}
- if (RenderObject* renderer = node->renderer()) {
- return (renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()
- && node->hasChildNodes() && !node->isDocumentNode());
+// This method calculates the exitPoint from the startingRect and the entryPoint into the candidate rect.
+// The line between those 2 points is the closest distance between the 2 rects.
+void entryAndExitPointsForDirection(FocusDirection direction, const IntRect& startingRect, const IntRect& potentialRect, IntPoint& exitPoint, IntPoint& entryPoint)
+{
+ switch (direction) {
+ case FocusDirectionLeft:
+ exitPoint.setX(startingRect.x());
+ entryPoint.setX(potentialRect.right());
+ break;
+ case FocusDirectionUp:
+ exitPoint.setY(startingRect.y());
+ entryPoint.setY(potentialRect.bottom());
+ break;
+ case FocusDirectionRight:
+ exitPoint.setX(startingRect.right());
+ entryPoint.setX(potentialRect.x());
+ break;
+ case FocusDirectionDown:
+ exitPoint.setY(startingRect.bottom());
+ entryPoint.setY(potentialRect.y());
+ break;
+ default:
+ ASSERT_NOT_REACHED();
}
- return false;
+ switch (direction) {
+ case FocusDirectionLeft:
+ case FocusDirectionRight:
+ if (below(startingRect, potentialRect)) {
+ exitPoint.setY(startingRect.y());
+ entryPoint.setY(potentialRect.bottom());
+ } else if (below(potentialRect, startingRect)) {
+ exitPoint.setY(startingRect.bottom());
+ entryPoint.setY(potentialRect.y());
+ } else {
+ exitPoint.setY(max(startingRect.y(), potentialRect.y()));
+ entryPoint.setY(exitPoint.y());
+ }
+ break;
+ case FocusDirectionUp:
+ case FocusDirectionDown:
+ if (rightOf(startingRect, potentialRect)) {
+ exitPoint.setX(startingRect.x());
+ entryPoint.setX(potentialRect.right());
+ } else if (rightOf(potentialRect, startingRect)) {
+ exitPoint.setX(startingRect.right());
+ entryPoint.setX(potentialRect.x());
+ } else {
+ exitPoint.setX(max(startingRect.x(), potentialRect.x()));
+ entryPoint.setX(exitPoint.x());
+ }
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
}
-bool isNodeDeepDescendantOfDocument(Node* node, Document* baseDocument)
+void distanceDataForNode(FocusDirection direction, FocusCandidate& current, FocusCandidate& candidate)
{
- if (!node || !baseDocument)
- return false;
+ if (candidate.isNull())
+ return;
+ if (!candidate.node->renderer())
+ return;
+ IntRect nodeRect = candidate.rect;
+ IntRect currentRect = current.rect;
+ deflateIfOverlapped(currentRect, nodeRect);
- bool descendant = baseDocument == node->document();
+ if (!isRectInDirection(direction, currentRect, nodeRect))
+ return;
- Element* currentElement = static_cast<Element*>(node);
- while (!descendant) {
- Element* documentOwner = currentElement->document()->ownerElement();
- if (!documentOwner)
- break;
+ IntPoint exitPoint;
+ IntPoint entryPoint;
+ int sameAxisDistance = 0;
+ int otherAxisDistance = 0;
+ entryAndExitPointsForDirection(direction, currentRect, nodeRect, exitPoint, entryPoint);
+
+ switch (direction) {
+ case FocusDirectionLeft:
+ sameAxisDistance = exitPoint.x() - entryPoint.x();
+ otherAxisDistance = abs(exitPoint.y() - entryPoint.y());
+ break;
+ case FocusDirectionUp:
+ sameAxisDistance = exitPoint.y() - entryPoint.y();
+ otherAxisDistance = abs(exitPoint.x() - entryPoint.x());
+ break;
+ case FocusDirectionRight:
+ sameAxisDistance = entryPoint.x() - exitPoint.x();
+ otherAxisDistance = abs(entryPoint.y() - exitPoint.y());
+ break;
+ case FocusDirectionDown:
+ sameAxisDistance = entryPoint.y() - exitPoint.y();
+ otherAxisDistance = abs(entryPoint.x() - exitPoint.x());
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ return;
+ }
- descendant = documentOwner->document() == baseDocument;
- currentElement = documentOwner;
+ int x = (entryPoint.x() - exitPoint.x()) * (entryPoint.x() - exitPoint.x());
+ int y = (entryPoint.y() - exitPoint.y()) * (entryPoint.y() - exitPoint.y());
+
+ float euclidianDistance = sqrt((x + y) * 1.0f);
+
+ // Loosely based on http://www.w3.org/TR/WICD/#focus-handling
+ // df = dotDist + dx + dy + 2 * (xdisplacement + ydisplacement) - sqrt(Overlap)
+
+ float distance = euclidianDistance + sameAxisDistance + 2 * otherAxisDistance;
+ candidate.distance = roundf(distance);
+ IntSize viewSize = candidate.node->document()->page()->mainFrame()->view()->visibleContentRect().size();
+ candidate.alignment = alignmentForRects(direction, currentRect, nodeRect, viewSize);
+}
+
+bool canBeScrolledIntoView(FocusDirection direction, const FocusCandidate& candidate)
+{
+ ASSERT(candidate.node && candidate.isOffscreen);
+ IntRect candidateRect = candidate.rect;
+ for (Node* parentNode = candidate.node->parentNode(); parentNode; parentNode = parentNode->parentNode()) {
+ IntRect parentRect = nodeRectInAbsoluteCoordinates(parentNode);
+ if (!candidateRect.intersects(parentRect)) {
+ if (((direction == FocusDirectionLeft || direction == FocusDirectionRight) && parentNode->renderer()->style()->overflowX() == OHIDDEN)
+ || ((direction == FocusDirectionUp || direction == FocusDirectionDown) && parentNode->renderer()->style()->overflowY() == OHIDDEN))
+ return false;
+ }
+ if (parentNode == candidate.enclosingScrollableBox)
+ return canScrollInDirection(direction, parentNode);
}
+ return true;
+}
- return descendant;
+// The starting rect is the rect of the focused node, in document coordinates.
+// Compose a virtual starting rect if there is no focused node or if it is off screen.
+// The virtual rect is the edge of the container or frame. We select which
+// edge depending on the direction of the navigation.
+IntRect virtualRectForDirection(FocusDirection direction, const IntRect& startingRect)
+{
+ IntRect virtualStartingRect = startingRect;
+ switch (direction) {
+ case FocusDirectionLeft:
+ virtualStartingRect.setX(virtualStartingRect.right());
+ virtualStartingRect.setWidth(0);
+ break;
+ case FocusDirectionUp:
+ virtualStartingRect.setY(virtualStartingRect.bottom());
+ virtualStartingRect.setHeight(0);
+ break;
+ case FocusDirectionRight:
+ virtualStartingRect.setWidth(0);
+ break;
+ case FocusDirectionDown:
+ virtualStartingRect.setHeight(0);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return virtualStartingRect;
}
+
} // namespace WebCore
diff --git a/WebCore/page/SpatialNavigation.h b/WebCore/page/SpatialNavigation.h
index 45b0155..153d0ac 100644
--- a/WebCore/page/SpatialNavigation.h
+++ b/WebCore/page/SpatialNavigation.h
@@ -22,6 +22,7 @@
#define SpatialNavigation_h
#include "FocusDirection.h"
+#include "IntRect.h"
#include "Node.h"
#include <limits>
@@ -104,19 +105,12 @@ struct FocusCandidate {
, parentDistance(maxDistance())
, alignment(None)
, parentAlignment(None)
+ , isOffscreen(true)
+ , isOffscreenAfterScrolling(true)
{
}
- FocusCandidate(Node* n)
- : node(n)
- , enclosingScrollableBox(0)
- , distance(maxDistance())
- , parentDistance(maxDistance())
- , alignment(None)
- , parentAlignment(None)
- {
- }
-
+ FocusCandidate(Node* n, FocusDirection);
bool isNull() const { return !node; }
bool inScrollableContainer() const { return node && enclosingScrollableBox; }
Document* document() const { return node ? node->document() : 0; }
@@ -127,16 +121,24 @@ struct FocusCandidate {
long long parentDistance;
RectsAlignment alignment;
RectsAlignment parentAlignment;
+ IntRect rect;
+ bool isOffscreen;
+ bool isOffscreenAfterScrolling;
};
-void distanceDataForNode(FocusDirection direction, Node* start, FocusCandidate& candidate);
-bool scrollInDirection(Frame*, FocusDirection, const FocusCandidate& candidate = FocusCandidate());
-void scrollIntoView(Element*);
-bool hasOffscreenRect(Node*);
-bool isInRootDocument(Node*);
-bool isScrollableContainerNode(Node*);
+bool scrollInDirection(Frame*, FocusDirection);
+bool scrollInDirection(Node* container, FocusDirection);
+bool hasOffscreenRect(Node*, FocusDirection direction = FocusDirectionNone);
+bool isScrollableContainerNode(const Node*);
bool isNodeDeepDescendantOfDocument(Node*, Document*);
-
+Node* scrollableEnclosingBoxOrParentFrameForNodeInDirection(FocusDirection, Node* node);
+bool canScrollInDirection(FocusDirection, const Node* container);
+bool canScrollInDirection(FocusDirection, const Frame*);
+IntRect nodeRectInAbsoluteCoordinates(Node*, bool ignoreBorder = false);
+IntRect frameRectInAbsoluteCoordinates(Frame*);
+void distanceDataForNode(FocusDirection, FocusCandidate& current, FocusCandidate& candidate);
+bool canBeScrolledIntoView(FocusDirection, const FocusCandidate&);
+IntRect virtualRectForDirection(FocusDirection, const IntRect& startingRect);
} // namspace WebCore
#endif // SpatialNavigation_h
diff --git a/WebCore/page/SpeechInputEvent.cpp b/WebCore/page/SpeechInputEvent.cpp
new file mode 100644
index 0000000..181322f
--- /dev/null
+++ b/WebCore/page/SpeechInputEvent.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SpeechInputEvent.h"
+
+#if ENABLE(INPUT_SPEECH)
+
+namespace WebCore {
+
+PassRefPtr<SpeechInputEvent> SpeechInputEvent::create(const AtomicString& eventType, const SpeechInputResultArray& results)
+{
+ return adoptRef(new SpeechInputEvent(eventType, results));
+}
+
+SpeechInputEvent::~SpeechInputEvent() {
+}
+
+SpeechInputEvent::SpeechInputEvent(const AtomicString& eventType, const SpeechInputResultArray& results)
+ : Event(eventType, true, false) // Can bubble, not cancelable
+ , m_results(SpeechInputResultList::create(results))
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INPUT_SPEECH)
diff --git a/WebCore/page/SpeechInputEvent.h b/WebCore/page/SpeechInputEvent.h
new file mode 100644
index 0000000..6a39f3c
--- /dev/null
+++ b/WebCore/page/SpeechInputEvent.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SpeechInputEvent_h
+#define SpeechInputEvent_h
+
+#if ENABLE(INPUT_SPEECH)
+
+#include "Event.h"
+#include "SpeechInputResultList.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class SpeechInputEvent : public Event {
+public:
+ static PassRefPtr<SpeechInputEvent> create(const AtomicString& eventType, const SpeechInputResultArray& results);
+ ~SpeechInputEvent();
+
+ virtual bool isSpeechInputEvent() const { return true; }
+
+ SpeechInputResultList* results() const { return m_results.get(); }
+
+private:
+ SpeechInputEvent(const AtomicString& eventType, const SpeechInputResultArray& results);
+
+ RefPtr<SpeechInputResultList> m_results;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INPUT_SPEECH)
+
+#endif // SpeechInputEvent_h
diff --git a/WebCore/page/SpeechInputEvent.idl b/WebCore/page/SpeechInputEvent.idl
new file mode 100644
index 0000000..c461483
--- /dev/null
+++ b/WebCore/page/SpeechInputEvent.idl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module core {
+
+ interface [
+ Conditional=INPUT_SPEECH
+ ] SpeechInputEvent : Event {
+ readonly attribute SpeechInputResultList results;
+ };
+
+}
diff --git a/WebCore/page/SpeechInputListener.h b/WebCore/page/SpeechInputListener.h
index 568b1b7..7415301 100644
--- a/WebCore/page/SpeechInputListener.h
+++ b/WebCore/page/SpeechInputListener.h
@@ -38,8 +38,6 @@
namespace WebCore {
-typedef Vector<RefPtr<SpeechInputResult> > SpeechInputResultArray;
-
// Interface to be implemented by the element which invokes SpeechInput.
class SpeechInputListener {
public:
diff --git a/WebCore/page/SpeechInputResult.cpp b/WebCore/page/SpeechInputResult.cpp
index f5b6972..1c042a0 100644
--- a/WebCore/page/SpeechInputResult.cpp
+++ b/WebCore/page/SpeechInputResult.cpp
@@ -35,6 +35,11 @@ PassRefPtr<SpeechInputResult> SpeechInputResult::create(const String& utterance,
return adoptRef(new SpeechInputResult(utterance, confidence));
}
+PassRefPtr<SpeechInputResult> SpeechInputResult::create(const SpeechInputResult& source)
+{
+ return adoptRef(new SpeechInputResult(source.m_utterance, source.m_confidence));
+}
+
SpeechInputResult::SpeechInputResult(const String& utterance, double confidence)
: m_utterance(utterance)
, m_confidence(confidence)
diff --git a/WebCore/page/SpeechInputResult.h b/WebCore/page/SpeechInputResult.h
index ef9fd10..457f078 100644
--- a/WebCore/page/SpeechInputResult.h
+++ b/WebCore/page/SpeechInputResult.h
@@ -38,6 +38,7 @@ namespace WebCore {
// fields, as received from the embedder.
class SpeechInputResult : public RefCounted<SpeechInputResult> {
public:
+ static PassRefPtr<SpeechInputResult> create(const SpeechInputResult& source);
static PassRefPtr<SpeechInputResult> create(const String& utterance, double confidence);
double confidence() const;
@@ -50,6 +51,8 @@ private:
double m_confidence;
};
+typedef Vector<RefPtr<SpeechInputResult> > SpeechInputResultArray;
+
} // namespace WebCore
#endif // ENABLE(INPUT_SPEECH)
diff --git a/WebCore/page/SpeechInputResult.idl b/WebCore/page/SpeechInputResult.idl
new file mode 100644
index 0000000..f688de4
--- /dev/null
+++ b/WebCore/page/SpeechInputResult.idl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module core {
+
+ interface [
+ Conditional=INPUT_SPEECH
+ ] SpeechInputResult {
+ readonly attribute DOMString utterance;
+ readonly attribute float confidence;
+ };
+
+}
diff --git a/WebCore/page/SpeechInputResultList.cpp b/WebCore/page/SpeechInputResultList.cpp
new file mode 100644
index 0000000..41fd108
--- /dev/null
+++ b/WebCore/page/SpeechInputResultList.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SpeechInputResultList.h"
+
+#if ENABLE(INPUT_SPEECH)
+
+namespace WebCore {
+
+PassRefPtr<SpeechInputResultList> SpeechInputResultList::create(const SpeechInputResultArray& results)
+{
+ return adoptRef(new SpeechInputResultList(results));
+}
+
+SpeechInputResult* SpeechInputResultList::item(unsigned index)
+{
+ return index >= m_results.size() ? 0 : m_results[index].get();
+}
+
+SpeechInputResultList::SpeechInputResultList(const SpeechInputResultArray& results)
+ : m_results(results) // Takes a copy of the array of RefPtrs.
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INPUT_SPEECH)
diff --git a/WebCore/page/SpeechInputResultList.h b/WebCore/page/SpeechInputResultList.h
new file mode 100644
index 0000000..b050630
--- /dev/null
+++ b/WebCore/page/SpeechInputResultList.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SpeechInputResultList_h
+#define SpeechInputResultList_h
+
+#if ENABLE(INPUT_SPEECH)
+
+#include "SpeechInputResult.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class SpeechInputResultList : public RefCounted<SpeechInputResultList> {
+public:
+ static PassRefPtr<SpeechInputResultList> create(const SpeechInputResultArray& results);
+
+ // Methods from the IDL.
+ size_t length() { return m_results.size(); }
+ SpeechInputResult* item(unsigned index);
+
+private:
+ SpeechInputResultList(const SpeechInputResultArray& results);
+
+ SpeechInputResultArray m_results;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INPUT_SPEECH)
+
+#endif // SpeechInputResultList_h
diff --git a/WebCore/page/SpeechInputResultList.idl b/WebCore/page/SpeechInputResultList.idl
new file mode 100644
index 0000000..5a23d4f
--- /dev/null
+++ b/WebCore/page/SpeechInputResultList.idl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module core {
+
+ interface [
+ HasIndexGetter,
+ Conditional=INPUT_SPEECH
+ ] SpeechInputResultList {
+ readonly attribute unsigned long length;
+ SpeechInputResult item(in [IsIndex] unsigned long index);
+ };
+
+}
diff --git a/WebCore/page/animation/AnimationBase.cpp b/WebCore/page/animation/AnimationBase.cpp
index ad5257e..66172f7 100644
--- a/WebCore/page/animation/AnimationBase.cpp
+++ b/WebCore/page/animation/AnimationBase.cpp
@@ -744,7 +744,7 @@ static void addShorthandProperties()
CSSPropertyWebkitTransformOrigin
};
- for (unsigned i = 0; i < sizeof(animatableShorthandProperties) / sizeof(animatableShorthandProperties[0]); ++i) {
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(animatableShorthandProperties); ++i) {
int propertyID = animatableShorthandProperties[i];
CSSPropertyLonghand longhand = longhandForProperty(propertyID);
if (longhand.length() > 0)
@@ -757,7 +757,7 @@ static void addShorthandProperties()
CSSPropertyFontWeight
};
- CSSPropertyLonghand fontLonghand(animatableFontProperties, sizeof(animatableFontProperties) / sizeof(animatableFontProperties[0]));
+ CSSPropertyLonghand fontLonghand(animatableFontProperties, WTF_ARRAY_LENGTH(animatableFontProperties));
addPropertyWrapper(CSSPropertyFont, new ShorthandPropertyWrapper(CSSPropertyFont, fontLonghand));
}
diff --git a/WebCore/page/mac/WebCoreFrameView.h b/WebCore/page/mac/WebCoreFrameView.h
index 977b1a7..b76350d 100644
--- a/WebCore/page/mac/WebCoreFrameView.h
+++ b/WebCore/page/mac/WebCoreFrameView.h
@@ -33,6 +33,8 @@ namespace WebCore {
- (void)setScrollingModes:(WebCore::ScrollbarMode)hMode vertical:(WebCore::ScrollbarMode)vMode andLock:(BOOL)lock;
- (void)scrollingModes:(WebCore::ScrollbarMode*)hMode vertical:(WebCore::ScrollbarMode*)vMode;
- (void)setScrollBarsSuppressed:(BOOL)suppressed repaintOnUnsuppress:(BOOL)repaint;
+- (void)setScrollOrigin:(NSPoint)origin updatePosition:(BOOL)updatePosition;
+- (NSPoint)scrollOrigin;
@end
@protocol WebCoreFrameView
diff --git a/WebCore/page/qt/FrameQt.cpp b/WebCore/page/qt/FrameQt.cpp
index ed75eb8..467592c 100644
--- a/WebCore/page/qt/FrameQt.cpp
+++ b/WebCore/page/qt/FrameQt.cpp
@@ -23,6 +23,9 @@
#include "config.h"
#include "Frame.h"
+#include "FrameView.h"
+#include "Image.h"
+#include "ImageBuffer.h"
#include "NotImplemented.h"
@@ -36,8 +39,27 @@ DragImageRef Frame::nodeImage(Node*)
DragImageRef Frame::dragImageForSelection()
{
- notImplemented();
- return 0;
+ if (!selection()->isRange())
+ return 0;
+
+ m_doc->updateLayout();
+
+ IntRect paintingRect = enclosingIntRect(selection()->bounds());
+ OwnPtr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size()));
+ if (!buffer)
+ return 0;
+
+ GraphicsContext* context = buffer->context();
+ context->translate(-paintingRect.x(), -paintingRect.y());
+ context->clip(FloatRect(0, 0, paintingRect.right(), paintingRect.bottom()));
+
+ PaintBehavior previousPaintBehavior = m_view->paintBehavior();
+ m_view->setPaintBehavior(PaintBehaviorSelectionOnly);
+ m_view->paintContents(context, paintingRect);
+ m_view->setPaintBehavior(previousPaintBehavior);
+
+ RefPtr<Image> image = buffer->copyImage();
+ return createDragImageFromImage(image.get());
}
}