summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/page
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/page
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/page')
-rw-r--r--Source/WebCore/page/AbstractView.idl38
-rw-r--r--Source/WebCore/page/BarInfo.cpp84
-rw-r--r--Source/WebCore/page/BarInfo.h60
-rw-r--r--Source/WebCore/page/BarInfo.idl35
-rw-r--r--Source/WebCore/page/Chrome.cpp529
-rw-r--r--Source/WebCore/page/Chrome.h176
-rw-r--r--Source/WebCore/page/ChromeClient.h309
-rw-r--r--Source/WebCore/page/Console.cpp496
-rw-r--r--Source/WebCore/page/Console.h140
-rw-r--r--Source/WebCore/page/Console.idl64
-rw-r--r--Source/WebCore/page/ContextMenuClient.h66
-rw-r--r--Source/WebCore/page/ContextMenuController.cpp1249
-rw-r--r--Source/WebCore/page/ContextMenuController.h90
-rw-r--r--Source/WebCore/page/ContextMenuProvider.h52
-rw-r--r--Source/WebCore/page/Coordinates.h89
-rw-r--r--Source/WebCore/page/Coordinates.idl37
-rw-r--r--Source/WebCore/page/DOMSelection.cpp511
-rw-r--r--Source/WebCore/page/DOMSelection.h104
-rw-r--r--Source/WebCore/page/DOMSelection.idl88
-rw-r--r--Source/WebCore/page/DOMTimer.cpp153
-rw-r--r--Source/WebCore/page/DOMTimer.h66
-rw-r--r--Source/WebCore/page/DOMWindow.cpp1861
-rw-r--r--Source/WebCore/page/DOMWindow.h486
-rw-r--r--Source/WebCore/page/DOMWindow.idl796
-rw-r--r--Source/WebCore/page/DragActions.h66
-rw-r--r--Source/WebCore/page/DragClient.h81
-rw-r--r--Source/WebCore/page/DragController.cpp852
-rw-r--r--Source/WebCore/page/DragController.h130
-rw-r--r--Source/WebCore/page/EditorClient.h212
-rw-r--r--Source/WebCore/page/EventHandler.cpp3140
-rw-r--r--Source/WebCore/page/EventHandler.h444
-rw-r--r--Source/WebCore/page/EventSource.cpp332
-rw-r--r--Source/WebCore/page/EventSource.h130
-rw-r--r--Source/WebCore/page/EventSource.idl69
-rw-r--r--Source/WebCore/page/FocusController.cpp601
-rw-r--r--Source/WebCore/page/FocusController.h78
-rw-r--r--Source/WebCore/page/FocusDirection.h41
-rw-r--r--Source/WebCore/page/Frame.cpp1002
-rw-r--r--Source/WebCore/page/Frame.h368
-rw-r--r--Source/WebCore/page/FrameLoadRequest.h73
-rw-r--r--Source/WebCore/page/FrameTree.cpp337
-rw-r--r--Source/WebCore/page/FrameTree.h92
-rw-r--r--Source/WebCore/page/FrameView.cpp2607
-rw-r--r--Source/WebCore/page/FrameView.h410
-rw-r--r--Source/WebCore/page/Geolocation.cpp777
-rw-r--r--Source/WebCore/page/Geolocation.h217
-rw-r--r--Source/WebCore/page/Geolocation.idl36
-rw-r--r--Source/WebCore/page/GeolocationClient.h56
-rw-r--r--Source/WebCore/page/GeolocationController.cpp123
-rw-r--r--Source/WebCore/page/GeolocationController.h74
-rw-r--r--Source/WebCore/page/GeolocationError.h65
-rw-r--r--Source/WebCore/page/GeolocationPosition.h111
-rw-r--r--Source/WebCore/page/GeolocationPositionCache.cpp261
-rw-r--r--Source/WebCore/page/GeolocationPositionCache.h80
-rw-r--r--Source/WebCore/page/Geoposition.h65
-rw-r--r--Source/WebCore/page/Geoposition.idl32
-rw-r--r--Source/WebCore/page/GroupSettings.cpp53
-rw-r--r--Source/WebCore/page/GroupSettings.h62
-rw-r--r--Source/WebCore/page/HaltablePlugin.h46
-rw-r--r--Source/WebCore/page/History.cpp146
-rw-r--r--Source/WebCore/page/History.h73
-rw-r--r--Source/WebCore/page/History.idl50
-rw-r--r--Source/WebCore/page/Location.cpp276
-rw-r--r--Source/WebCore/page/Location.h88
-rw-r--r--Source/WebCore/page/Location.idl75
-rw-r--r--Source/WebCore/page/MediaCanStartListener.h40
-rw-r--r--Source/WebCore/page/MemoryInfo.cpp51
-rw-r--r--Source/WebCore/page/MemoryInfo.h57
-rw-r--r--Source/WebCore/page/MemoryInfo.idl40
-rw-r--r--Source/WebCore/page/MouseEventWithHitTestResults.cpp66
-rw-r--r--Source/WebCore/page/MouseEventWithHitTestResults.h50
-rw-r--r--Source/WebCore/page/Navigator.cpp212
-rw-r--r--Source/WebCore/page/Navigator.h98
-rw-r--r--Source/WebCore/page/Navigator.idl62
-rw-r--r--Source/WebCore/page/NavigatorBase.cpp129
-rw-r--r--Source/WebCore/page/NavigatorBase.h54
-rw-r--r--Source/WebCore/page/OriginAccessEntry.cpp80
-rw-r--r--Source/WebCore/page/OriginAccessEntry.h74
-rw-r--r--Source/WebCore/page/Page.cpp965
-rw-r--r--Source/WebCore/page/Page.h390
-rw-r--r--Source/WebCore/page/PageGroup.cpp461
-rw-r--r--Source/WebCore/page/PageGroup.h136
-rw-r--r--Source/WebCore/page/PageGroupLoadDeferrer.cpp83
-rw-r--r--Source/WebCore/page/PageGroupLoadDeferrer.h41
-rw-r--r--Source/WebCore/page/Performance.cpp93
-rw-r--r--Source/WebCore/page/Performance.h68
-rw-r--r--Source/WebCore/page/Performance.idl40
-rw-r--r--Source/WebCore/page/PerformanceNavigation.cpp95
-rw-r--r--Source/WebCore/page/PerformanceNavigation.h69
-rw-r--r--Source/WebCore/page/PerformanceNavigation.idl44
-rw-r--r--Source/WebCore/page/PerformanceTiming.cpp403
-rw-r--r--Source/WebCore/page/PerformanceTiming.h91
-rw-r--r--Source/WebCore/page/PerformanceTiming.idl58
-rw-r--r--Source/WebCore/page/PluginHalter.cpp118
-rw-r--r--Source/WebCore/page/PluginHalter.h60
-rw-r--r--Source/WebCore/page/PluginHalterClient.h45
-rw-r--r--Source/WebCore/page/PositionCallback.h45
-rw-r--r--Source/WebCore/page/PositionError.h67
-rw-r--r--Source/WebCore/page/PositionError.idl37
-rw-r--r--Source/WebCore/page/PositionErrorCallback.h45
-rw-r--r--Source/WebCore/page/PositionOptions.h83
-rw-r--r--Source/WebCore/page/PrintContext.cpp304
-rw-r--r--Source/WebCore/page/PrintContext.h80
-rw-r--r--Source/WebCore/page/Screen.cpp112
-rw-r--r--Source/WebCore/page/Screen.h64
-rw-r--r--Source/WebCore/page/Screen.idl43
-rw-r--r--Source/WebCore/page/SecurityOrigin.cpp564
-rw-r--r--Source/WebCore/page/SecurityOrigin.h216
-rw-r--r--Source/WebCore/page/SecurityOriginHash.h81
-rw-r--r--Source/WebCore/page/Settings.cpp884
-rw-r--r--Source/WebCore/page/Settings.h579
-rw-r--r--Source/WebCore/page/SpatialNavigation.cpp713
-rw-r--r--Source/WebCore/page/SpatialNavigation.h154
-rw-r--r--Source/WebCore/page/SpeechInput.cpp116
-rw-r--r--Source/WebCore/page/SpeechInput.h83
-rw-r--r--Source/WebCore/page/SpeechInputClient.h71
-rw-r--r--Source/WebCore/page/SpeechInputEvent.cpp54
-rw-r--r--Source/WebCore/page/SpeechInputEvent.h59
-rw-r--r--Source/WebCore/page/SpeechInputEvent.idl34
-rw-r--r--Source/WebCore/page/SpeechInputListener.h67
-rw-r--r--Source/WebCore/page/SpeechInputResult.cpp61
-rw-r--r--Source/WebCore/page/SpeechInputResult.h60
-rw-r--r--Source/WebCore/page/SpeechInputResult.idl35
-rw-r--r--Source/WebCore/page/SpeechInputResultList.cpp55
-rw-r--r--Source/WebCore/page/SpeechInputResultList.h57
-rw-r--r--Source/WebCore/page/SpeechInputResultList.idl36
-rw-r--r--Source/WebCore/page/SuspendableTimer.cpp83
-rw-r--r--Source/WebCore/page/SuspendableTimer.h60
-rw-r--r--Source/WebCore/page/UserContentTypes.h38
-rw-r--r--Source/WebCore/page/UserContentURLPattern.cpp231
-rw-r--r--Source/WebCore/page/UserContentURLPattern.h76
-rw-r--r--Source/WebCore/page/UserScript.h70
-rw-r--r--Source/WebCore/page/UserScriptTypes.h44
-rw-r--r--Source/WebCore/page/UserStyleSheet.h70
-rw-r--r--Source/WebCore/page/UserStyleSheetTypes.h45
-rw-r--r--Source/WebCore/page/WebKitPoint.h64
-rw-r--r--Source/WebCore/page/WebKitPoint.idl38
-rw-r--r--Source/WebCore/page/WindowFeatures.cpp266
-rw-r--r--Source/WebCore/page/WindowFeatures.h93
-rw-r--r--Source/WebCore/page/WorkerNavigator.cpp51
-rw-r--r--Source/WebCore/page/WorkerNavigator.h56
-rw-r--r--Source/WebCore/page/WorkerNavigator.idl44
-rw-r--r--Source/WebCore/page/XSSAuditor.cpp432
-rw-r--r--Source/WebCore/page/XSSAuditor.h180
-rw-r--r--Source/WebCore/page/android/DragControllerAndroid.cpp62
-rw-r--r--Source/WebCore/page/android/EventHandlerAndroid.cpp124
-rw-r--r--Source/WebCore/page/animation/AnimationBase.cpp1399
-rw-r--r--Source/WebCore/page/animation/AnimationBase.h241
-rw-r--r--Source/WebCore/page/animation/AnimationController.cpp615
-rw-r--r--Source/WebCore/page/animation/AnimationController.h82
-rw-r--r--Source/WebCore/page/animation/AnimationControllerPrivate.h131
-rw-r--r--Source/WebCore/page/animation/CompositeAnimation.cpp563
-rw-r--r--Source/WebCore/page/animation/CompositeAnimation.h107
-rw-r--r--Source/WebCore/page/animation/ImplicitAnimation.cpp303
-rw-r--r--Source/WebCore/page/animation/ImplicitAnimation.h96
-rw-r--r--Source/WebCore/page/animation/KeyframeAnimation.cpp461
-rw-r--r--Source/WebCore/page/animation/KeyframeAnimation.h101
-rw-r--r--Source/WebCore/page/brew/ChromeClientBrew.h51
-rw-r--r--Source/WebCore/page/brew/DragControllerBrew.cpp70
-rw-r--r--Source/WebCore/page/brew/EventHandlerBrew.cpp127
-rw-r--r--Source/WebCore/page/brew/FrameBrew.cpp44
-rw-r--r--Source/WebCore/page/chromium/ChromeClientChromium.h58
-rw-r--r--Source/WebCore/page/chromium/DragControllerChromium.cpp82
-rw-r--r--Source/WebCore/page/chromium/EventHandlerChromium.cpp167
-rw-r--r--Source/WebCore/page/chromium/FrameChromium.cpp118
-rw-r--r--Source/WebCore/page/efl/DragControllerEfl.cpp69
-rw-r--r--Source/WebCore/page/efl/EventHandlerEfl.cpp138
-rw-r--r--Source/WebCore/page/efl/FrameEfl.cpp47
-rw-r--r--Source/WebCore/page/gtk/DragControllerGtk.cpp69
-rw-r--r--Source/WebCore/page/gtk/EventHandlerGtk.cpp134
-rw-r--r--Source/WebCore/page/gtk/FrameGtk.cpp43
-rw-r--r--Source/WebCore/page/haiku/DragControllerHaiku.cpp76
-rw-r--r--Source/WebCore/page/haiku/EventHandlerHaiku.cpp155
-rw-r--r--Source/WebCore/page/haiku/FrameHaiku.cpp48
-rw-r--r--Source/WebCore/page/mac/ChromeMac.mm52
-rw-r--r--Source/WebCore/page/mac/DragControllerMac.mm81
-rw-r--r--Source/WebCore/page/mac/EventHandlerMac.mm790
-rw-r--r--Source/WebCore/page/mac/FrameMac.mm364
-rw-r--r--Source/WebCore/page/mac/PageMac.cpp77
-rw-r--r--Source/WebCore/page/mac/WebCoreFrameView.h42
-rw-r--r--Source/WebCore/page/mac/WebCoreKeyboardUIMode.h40
-rw-r--r--Source/WebCore/page/mac/WebCoreViewFactory.h54
-rw-r--r--Source/WebCore/page/mac/WebCoreViewFactory.m48
-rw-r--r--Source/WebCore/page/qt/DragControllerQt.cpp72
-rw-r--r--Source/WebCore/page/qt/EventHandlerQt.cpp146
-rw-r--r--Source/WebCore/page/qt/FrameQt.cpp66
-rw-r--r--Source/WebCore/page/win/DragControllerWin.cpp69
-rw-r--r--Source/WebCore/page/win/EventHandlerWin.cpp124
-rw-r--r--Source/WebCore/page/win/FrameCGWin.cpp114
-rw-r--r--Source/WebCore/page/win/FrameCairoWin.cpp49
-rw-r--r--Source/WebCore/page/win/FrameWin.cpp56
-rw-r--r--Source/WebCore/page/win/FrameWin.h44
-rw-r--r--Source/WebCore/page/wince/FrameWinCE.cpp165
-rw-r--r--Source/WebCore/page/wx/DragControllerWx.cpp72
-rw-r--r--Source/WebCore/page/wx/EventHandlerWx.cpp127
-rw-r--r--Source/WebCore/page/wx/FrameWx.cpp44
196 files changed, 40960 insertions, 0 deletions
diff --git a/Source/WebCore/page/AbstractView.idl b/Source/WebCore/page/AbstractView.idl
new file mode 100644
index 0000000..6d8232b
--- /dev/null
+++ b/Source/WebCore/page/AbstractView.idl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module views {
+
+ // Introduced in DOM Level 2:
+ interface [
+ ObjCCustomImplementation,
+ OmitConstructor
+ ] AbstractView {
+ readonly attribute Document document;
+ readonly attribute StyleMedia styleMedia;
+ };
+
+}
diff --git a/Source/WebCore/page/BarInfo.cpp b/Source/WebCore/page/BarInfo.cpp
new file mode 100644
index 0000000..b6ab686
--- /dev/null
+++ b/Source/WebCore/page/BarInfo.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "BarInfo.h"
+
+#include "Chrome.h"
+#include "Frame.h"
+#include "Page.h"
+
+namespace WebCore {
+
+BarInfo::BarInfo(Frame* frame, Type type)
+ : m_frame(frame)
+ , m_type(type)
+{
+}
+
+Frame* BarInfo::frame() const
+{
+ return m_frame;
+}
+
+void BarInfo::disconnectFrame()
+{
+ m_frame = 0;
+}
+
+BarInfo::Type BarInfo::type() const
+{
+ return m_type;
+}
+
+bool BarInfo::visible() const
+{
+ if (!m_frame)
+ return false;
+ Page* page = m_frame->page();
+ if (!page)
+ return false;
+
+ switch (m_type) {
+ case Locationbar:
+ case Personalbar:
+ case Toolbar:
+ return page->chrome()->toolbarsVisible();
+ case Menubar:
+ return page->chrome()->menubarVisible();
+ case Scrollbars:
+ return page->chrome()->scrollbarsVisible();
+ case Statusbar:
+ return page->chrome()->statusbarVisible();
+ }
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/BarInfo.h b/Source/WebCore/page/BarInfo.h
new file mode 100644
index 0000000..376b8fc
--- /dev/null
+++ b/Source/WebCore/page/BarInfo.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 BarInfo_h
+#define BarInfo_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class Frame;
+
+ class BarInfo : public RefCounted<BarInfo> {
+ public:
+ enum Type { Locationbar, Menubar, Personalbar, Scrollbars, Statusbar, Toolbar };
+
+ static PassRefPtr<BarInfo> create(Frame* frame, Type type) { return adoptRef(new BarInfo(frame, type)); }
+
+ Frame* frame() const;
+ void disconnectFrame();
+
+ Type type() const;
+
+ bool visible() const;
+
+ private:
+ BarInfo(Frame*, Type);
+ Frame* m_frame;
+ Type m_type;
+ };
+
+} // namespace WebCore
+
+#endif // BarInfo_h
diff --git a/Source/WebCore/page/BarInfo.idl b/Source/WebCore/page/BarInfo.idl
new file mode 100644
index 0000000..2089895
--- /dev/null
+++ b/Source/WebCore/page/BarInfo.idl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module window {
+
+ interface [OmitConstructor] BarInfo {
+ readonly attribute boolean visible;
+ };
+
+}
diff --git a/Source/WebCore/page/Chrome.cpp b/Source/WebCore/page/Chrome.cpp
new file mode 100644
index 0000000..a801065
--- /dev/null
+++ b/Source/WebCore/page/Chrome.cpp
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Chrome.h"
+
+#include "ChromeClient.h"
+#include "DNS.h"
+#include "Document.h"
+#include "FileList.h"
+#include "FloatRect.h"
+#include "Frame.h"
+#include "FrameTree.h"
+#include "Geolocation.h"
+#include "HTMLFormElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "HitTestResult.h"
+#include "InspectorController.h"
+#include "Page.h"
+#include "PageGroupLoadDeferrer.h"
+#include "RenderObject.h"
+#include "ResourceHandle.h"
+#include "ScriptController.h"
+#include "SecurityOrigin.h"
+#include "Settings.h"
+#include "WindowFeatures.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+#if ENABLE(DOM_STORAGE)
+#include "StorageNamespace.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace std;
+
+Chrome::Chrome(Page* page, ChromeClient* client)
+ : m_page(page)
+ , m_client(client)
+{
+ ASSERT(m_client);
+}
+
+Chrome::~Chrome()
+{
+ m_client->chromeDestroyed();
+}
+
+void Chrome::invalidateWindow(const IntRect& updateRect, bool immediate)
+{
+ m_client->invalidateWindow(updateRect, immediate);
+}
+
+void Chrome::invalidateContentsAndWindow(const IntRect& updateRect, bool immediate)
+{
+ m_client->invalidateContentsAndWindow(updateRect, immediate);
+}
+
+void Chrome::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate)
+{
+ m_client->invalidateContentsForSlowScroll(updateRect, immediate);
+}
+
+void Chrome::scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
+{
+ m_client->scroll(scrollDelta, rectToScroll, clipRect);
+}
+
+#if ENABLE(TILED_BACKING_STORE)
+void Chrome::delegatedScrollRequested(const IntSize& scrollDelta)
+{
+ m_client->delegatedScrollRequested(scrollDelta);
+}
+#endif
+
+IntPoint Chrome::screenToWindow(const IntPoint& point) const
+{
+ return m_client->screenToWindow(point);
+}
+
+IntRect Chrome::windowToScreen(const IntRect& rect) const
+{
+ return m_client->windowToScreen(rect);
+}
+
+PlatformPageClient Chrome::platformPageClient() const
+{
+ return m_client->platformPageClient();
+}
+
+void Chrome::contentsSizeChanged(Frame* frame, const IntSize& size) const
+{
+ m_client->contentsSizeChanged(frame, size);
+}
+
+void Chrome::scrollRectIntoView(const IntRect& rect) const
+{
+ // FIXME: The unused ScrollView* argument can and should be removed from ChromeClient::scrollRectIntoView.
+ m_client->scrollRectIntoView(rect, 0);
+}
+
+void Chrome::scrollbarsModeDidChange() const
+{
+ m_client->scrollbarsModeDidChange();
+}
+
+void Chrome::setWindowRect(const FloatRect& rect) const
+{
+ m_client->setWindowRect(rect);
+}
+
+FloatRect Chrome::windowRect() const
+{
+ return m_client->windowRect();
+}
+
+FloatRect Chrome::pageRect() const
+{
+ return m_client->pageRect();
+}
+
+float Chrome::scaleFactor()
+{
+ return m_client->scaleFactor();
+}
+
+void Chrome::focus() const
+{
+ m_client->focus();
+}
+
+void Chrome::unfocus() const
+{
+ m_client->unfocus();
+}
+
+bool Chrome::canTakeFocus(FocusDirection direction) const
+{
+ return m_client->canTakeFocus(direction);
+}
+
+void Chrome::takeFocus(FocusDirection direction) const
+{
+ m_client->takeFocus(direction);
+}
+
+void Chrome::focusedNodeChanged(Node* node) const
+{
+ m_client->focusedNodeChanged(node);
+}
+
+void Chrome::focusedFrameChanged(Frame* frame) const
+{
+ m_client->focusedFrameChanged(frame);
+}
+
+Page* Chrome::createWindow(Frame* frame, const FrameLoadRequest& request, const WindowFeatures& features, const NavigationAction& action) const
+{
+ Page* newPage = m_client->createWindow(frame, request, features, action);
+
+#if ENABLE(DOM_STORAGE)
+ if (newPage) {
+ if (StorageNamespace* oldSessionStorage = m_page->sessionStorage(false))
+ newPage->setSessionStorage(oldSessionStorage->copy());
+ }
+#endif
+
+ return newPage;
+}
+
+void Chrome::show() const
+{
+ m_client->show();
+}
+
+bool Chrome::canRunModal() const
+{
+ return m_client->canRunModal();
+}
+
+bool Chrome::canRunModalNow() const
+{
+ // If loads are blocked, we can't run modal because the contents
+ // of the modal dialog will never show up!
+ return canRunModal() && !ResourceHandle::loadsBlocked();
+}
+
+void Chrome::runModal() const
+{
+ // Defer callbacks in all the other pages in this group, so we don't try to run JavaScript
+ // in a way that could interact with this view.
+ PageGroupLoadDeferrer deferrer(m_page, false);
+
+ TimerBase::fireTimersInNestedEventLoop();
+ m_client->runModal();
+}
+
+void Chrome::setToolbarsVisible(bool b) const
+{
+ m_client->setToolbarsVisible(b);
+}
+
+bool Chrome::toolbarsVisible() const
+{
+ return m_client->toolbarsVisible();
+}
+
+void Chrome::setStatusbarVisible(bool b) const
+{
+ m_client->setStatusbarVisible(b);
+}
+
+bool Chrome::statusbarVisible() const
+{
+ return m_client->statusbarVisible();
+}
+
+void Chrome::setScrollbarsVisible(bool b) const
+{
+ m_client->setScrollbarsVisible(b);
+}
+
+bool Chrome::scrollbarsVisible() const
+{
+ return m_client->scrollbarsVisible();
+}
+
+void Chrome::setMenubarVisible(bool b) const
+{
+ m_client->setMenubarVisible(b);
+}
+
+bool Chrome::menubarVisible() const
+{
+ return m_client->menubarVisible();
+}
+
+void Chrome::setResizable(bool b) const
+{
+ m_client->setResizable(b);
+}
+
+bool Chrome::canRunBeforeUnloadConfirmPanel()
+{
+ return m_client->canRunBeforeUnloadConfirmPanel();
+}
+
+bool Chrome::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
+{
+ // Defer loads in case the client method runs a new event loop that would
+ // otherwise cause the load to continue while we're in the middle of executing JavaScript.
+ PageGroupLoadDeferrer deferrer(m_page, true);
+
+ return m_client->runBeforeUnloadConfirmPanel(message, frame);
+}
+
+void Chrome::closeWindowSoon()
+{
+ m_client->closeWindowSoon();
+}
+
+void Chrome::runJavaScriptAlert(Frame* frame, const String& message)
+{
+ // Defer loads in case the client method runs a new event loop that would
+ // otherwise cause the load to continue while we're in the middle of executing JavaScript.
+ PageGroupLoadDeferrer deferrer(m_page, true);
+
+ ASSERT(frame);
+ m_client->runJavaScriptAlert(frame, frame->displayStringModifiedByEncoding(message));
+}
+
+bool Chrome::runJavaScriptConfirm(Frame* frame, const String& message)
+{
+ // Defer loads in case the client method runs a new event loop that would
+ // otherwise cause the load to continue while we're in the middle of executing JavaScript.
+ PageGroupLoadDeferrer deferrer(m_page, true);
+
+ ASSERT(frame);
+ return m_client->runJavaScriptConfirm(frame, frame->displayStringModifiedByEncoding(message));
+}
+
+bool Chrome::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultValue, String& result)
+{
+ // Defer loads in case the client method runs a new event loop that would
+ // otherwise cause the load to continue while we're in the middle of executing JavaScript.
+ PageGroupLoadDeferrer deferrer(m_page, true);
+
+ ASSERT(frame);
+ bool ok = m_client->runJavaScriptPrompt(frame, frame->displayStringModifiedByEncoding(prompt), frame->displayStringModifiedByEncoding(defaultValue), result);
+
+ if (ok)
+ result = frame->displayStringModifiedByEncoding(result);
+
+ return ok;
+}
+
+void Chrome::setStatusbarText(Frame* frame, const String& status)
+{
+ ASSERT(frame);
+ m_client->setStatusbarText(frame->displayStringModifiedByEncoding(status));
+}
+
+bool Chrome::shouldInterruptJavaScript()
+{
+ // Defer loads in case the client method runs a new event loop that would
+ // otherwise cause the load to continue while we're in the middle of executing JavaScript.
+ PageGroupLoadDeferrer deferrer(m_page, true);
+
+ return m_client->shouldInterruptJavaScript();
+}
+
+IntRect Chrome::windowResizerRect() const
+{
+ return m_client->windowResizerRect();
+}
+
+void Chrome::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags)
+{
+ if (result.innerNode()) {
+ Document* document = result.innerNode()->document();
+ if (document && document->isDNSPrefetchEnabled())
+ ResourceHandle::prepareForURL(result.absoluteLinkURL());
+ }
+ m_client->mouseDidMoveOverElement(result, modifierFlags);
+
+#if ENABLE(INSPECTOR)
+ if (InspectorController* inspector = m_page->inspectorController())
+ inspector->mouseDidMoveOverElement(result, modifierFlags);
+#endif
+}
+
+void Chrome::setToolTip(const HitTestResult& result)
+{
+ // First priority is a potential toolTip representing a spelling or grammar error
+ TextDirection toolTipDirection;
+ String toolTip = result.spellingToolTip(toolTipDirection);
+
+ // Next priority is a toolTip from a URL beneath the mouse (if preference is set to show those).
+ if (toolTip.isEmpty() && m_page->settings()->showsURLsInToolTips()) {
+ if (Node* node = result.innerNonSharedNode()) {
+ // Get tooltip representing form action, if relevant
+ if (node->hasTagName(inputTag)) {
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
+ if (input->isSubmitButton())
+ if (HTMLFormElement* form = input->form()) {
+ toolTip = form->action();
+ if (form->renderer())
+ toolTipDirection = form->renderer()->style()->direction();
+ else
+ toolTipDirection = LTR;
+ }
+ }
+ }
+
+ // Get tooltip representing link's URL
+ if (toolTip.isEmpty()) {
+ // FIXME: Need to pass this URL through userVisibleString once that's in WebCore
+ toolTip = result.absoluteLinkURL().string();
+ // URL always display as LTR.
+ toolTipDirection = LTR;
+ }
+ }
+
+ // Next we'll consider a tooltip for element with "title" attribute
+ if (toolTip.isEmpty())
+ toolTip = result.title(toolTipDirection);
+
+ // Lastly, for <input type="file"> that allow multiple files, we'll consider a tooltip for the selected filenames
+ if (toolTip.isEmpty()) {
+ if (Node* node = result.innerNonSharedNode()) {
+ if (node->hasTagName(inputTag)) {
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
+ if (input->isFileUpload()) {
+ FileList* files = input->files();
+ unsigned listSize = files->length();
+ if (files && listSize > 1) {
+ Vector<UChar> names;
+ for (size_t i = 0; i < listSize; ++i) {
+ append(names, files->item(i)->fileName());
+ if (i != listSize - 1)
+ names.append('\n');
+ }
+ toolTip = String::adopt(names);
+ // filename always display as LTR.
+ toolTipDirection = LTR;
+ }
+ }
+ }
+ }
+ }
+
+ m_client->setToolTip(toolTip, toolTipDirection);
+}
+
+void Chrome::print(Frame* frame)
+{
+ m_client->print(frame);
+}
+
+void Chrome::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation)
+{
+ m_client->requestGeolocationPermissionForFrame(frame, geolocation);
+}
+
+void Chrome::cancelGeolocationPermissionRequestForFrame(Frame* frame, Geolocation* geolocation)
+{
+ m_client->cancelGeolocationPermissionRequestForFrame(frame, geolocation);
+}
+
+void Chrome::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> fileChooser)
+{
+ m_client->runOpenPanel(frame, fileChooser);
+}
+
+void Chrome::chooseIconForFiles(const Vector<String>& filenames, FileChooser* fileChooser)
+{
+ m_client->chooseIconForFiles(filenames, fileChooser);
+}
+
+void Chrome::dispatchViewportDataDidChange(const ViewportArguments& arguments) const
+{
+ m_client->dispatchViewportDataDidChange(arguments);
+}
+
+void Chrome::setCursor(const Cursor& cursor)
+{
+ m_client->setCursor(cursor);
+}
+
+#if ENABLE(NOTIFICATIONS)
+NotificationPresenter* Chrome::notificationPresenter() const
+{
+ return m_client->notificationPresenter();
+}
+#endif
+
+// --------
+
+#if ENABLE(DASHBOARD_SUPPORT)
+void ChromeClient::dashboardRegionsChanged()
+{
+}
+#endif
+
+void ChromeClient::populateVisitedLinks()
+{
+}
+
+FloatRect ChromeClient::customHighlightRect(Node*, const AtomicString&, const FloatRect&)
+{
+ return FloatRect();
+}
+
+void ChromeClient::paintCustomHighlight(Node*, const AtomicString&, const FloatRect&, const FloatRect&, bool, bool)
+{
+}
+
+bool ChromeClient::shouldReplaceWithGeneratedFileForUpload(const String&, String&)
+{
+ return false;
+}
+
+String ChromeClient::generateReplacementFile(const String&)
+{
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+bool ChromeClient::paintCustomScrollbar(GraphicsContext*, const FloatRect&, ScrollbarControlSize,
+ ScrollbarControlState, ScrollbarPart, bool,
+ float, float, ScrollbarControlPartMask)
+{
+ return false;
+}
+
+bool ChromeClient::paintCustomScrollCorner(GraphicsContext*, const FloatRect&)
+{
+ return false;
+}
+
+bool Chrome::selectItemWritingDirectionIsNatural()
+{
+ return m_client->selectItemWritingDirectionIsNatural();
+}
+
+PassRefPtr<PopupMenu> Chrome::createPopupMenu(PopupMenuClient* client) const
+{
+ return m_client->createPopupMenu(client);
+}
+
+PassRefPtr<SearchPopupMenu> Chrome::createSearchPopupMenu(PopupMenuClient* client) const
+{
+ return m_client->createSearchPopupMenu(client);
+}
+
+#if ENABLE(CONTEXT_MENUS)
+void Chrome::showContextMenu()
+{
+ m_client->showContextMenu();
+}
+#endif
+
+bool Chrome::requiresFullscreenForVideoPlayback()
+{
+ return m_client->requiresFullscreenForVideoPlayback();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/Chrome.h b/Source/WebCore/page/Chrome.h
new file mode 100644
index 0000000..93b8c4a
--- /dev/null
+++ b/Source/WebCore/page/Chrome.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef Chrome_h
+#define Chrome_h
+
+#include "Cursor.h"
+#include "FileChooser.h"
+#include "FocusDirection.h"
+#include "HostWindow.h"
+#include "PopupMenu.h"
+#include "SearchPopupMenu.h"
+#include <wtf/Forward.h>
+#include <wtf/RefPtr.h>
+
+#if PLATFORM(MAC)
+#ifndef __OBJC__
+class NSView;
+#endif
+#endif
+
+namespace WebCore {
+
+ class ChromeClient;
+ class ContextMenu;
+ class FloatRect;
+ class Frame;
+ class Geolocation;
+ class HitTestResult;
+ class IntRect;
+ class NavigationAction;
+ class Node;
+ class Page;
+ class PopupMenuClient;
+#if ENABLE(NOTIFICATIONS)
+ class NotificationPresenter;
+#endif
+
+ struct FrameLoadRequest;
+ struct ViewportArguments;
+ struct WindowFeatures;
+
+ class Chrome : public HostWindow {
+ public:
+ Chrome(Page*, ChromeClient*);
+ ~Chrome();
+
+ ChromeClient* client() { return m_client; }
+
+ // HostWindow methods.
+
+ virtual void invalidateWindow(const IntRect&, bool);
+ virtual void invalidateContentsAndWindow(const IntRect&, bool);
+ virtual void invalidateContentsForSlowScroll(const IntRect&, bool);
+ virtual void scroll(const IntSize&, const IntRect&, const IntRect&);
+#if ENABLE(TILED_BACKING_STORE)
+ virtual void delegatedScrollRequested(const IntSize& scrollDelta);
+#endif
+ virtual IntPoint screenToWindow(const IntPoint&) const;
+ virtual IntRect windowToScreen(const IntRect&) const;
+ virtual PlatformPageClient platformPageClient() const;
+ virtual void scrollbarsModeDidChange() const;
+ virtual void setCursor(const Cursor&);
+
+ void scrollRectIntoView(const IntRect&) const;
+
+ void contentsSizeChanged(Frame*, const IntSize&) const;
+
+ void setWindowRect(const FloatRect&) const;
+ FloatRect windowRect() const;
+
+ FloatRect pageRect() const;
+
+ float scaleFactor();
+
+ void focus() const;
+ void unfocus() const;
+
+ bool canTakeFocus(FocusDirection) const;
+ void takeFocus(FocusDirection) const;
+
+ void focusedNodeChanged(Node*) const;
+ void focusedFrameChanged(Frame*) const;
+
+ Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&, const NavigationAction&) const;
+ void show() const;
+
+ bool canRunModal() const;
+ bool canRunModalNow() const;
+ void runModal() const;
+
+ void setToolbarsVisible(bool) const;
+ bool toolbarsVisible() const;
+
+ void setStatusbarVisible(bool) const;
+ bool statusbarVisible() const;
+
+ void setScrollbarsVisible(bool) const;
+ bool scrollbarsVisible() const;
+
+ void setMenubarVisible(bool) const;
+ bool menubarVisible() const;
+
+ void setResizable(bool) const;
+
+ bool canRunBeforeUnloadConfirmPanel();
+ bool runBeforeUnloadConfirmPanel(const String& message, Frame* frame);
+
+ void closeWindowSoon();
+
+ void runJavaScriptAlert(Frame*, const String&);
+ bool runJavaScriptConfirm(Frame*, const String&);
+ bool runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result);
+ void setStatusbarText(Frame*, const String&);
+ bool shouldInterruptJavaScript();
+
+ IntRect windowResizerRect() const;
+
+ void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags);
+
+ void setToolTip(const HitTestResult&);
+
+ void print(Frame*);
+
+ // FIXME: Remove once all ports are using client-based geolocation. https://bugs.webkit.org/show_bug.cgi?id=40373
+ // For client-based geolocation, these two methods have moved to GeolocationClient. https://bugs.webkit.org/show_bug.cgi?id=50061
+ void requestGeolocationPermissionForFrame(Frame*, Geolocation*);
+ void cancelGeolocationPermissionRequestForFrame(Frame*, Geolocation*);
+
+ void runOpenPanel(Frame*, PassRefPtr<FileChooser>);
+ void chooseIconForFiles(const Vector<String>&, FileChooser*);
+
+ void dispatchViewportDataDidChange(const ViewportArguments&) const;
+
+ bool requiresFullscreenForVideoPlayback();
+
+#if PLATFORM(MAC)
+ void focusNSView(NSView*);
+#endif
+
+#if ENABLE(NOTIFICATIONS)
+ NotificationPresenter* notificationPresenter() const;
+#endif
+
+ bool selectItemWritingDirectionIsNatural();
+ PassRefPtr<PopupMenu> createPopupMenu(PopupMenuClient*) const;
+ PassRefPtr<SearchPopupMenu> createSearchPopupMenu(PopupMenuClient*) const;
+
+#if ENABLE(CONTEXT_MENUS)
+ void showContextMenu();
+#endif
+
+ private:
+ Page* m_page;
+ ChromeClient* m_client;
+ };
+}
+
+#endif // Chrome_h
diff --git a/Source/WebCore/page/ChromeClient.h b/Source/WebCore/page/ChromeClient.h
new file mode 100644
index 0000000..0276a14
--- /dev/null
+++ b/Source/WebCore/page/ChromeClient.h
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple, Inc. All rights reserved.
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef ChromeClient_h
+#define ChromeClient_h
+
+#include "AXObjectCache.h"
+#include "Console.h"
+#include "Cursor.h"
+#include "FocusDirection.h"
+#include "GraphicsContext.h"
+#include "HTMLParserQuirks.h"
+#include "HostWindow.h"
+#include "PopupMenu.h"
+#include "PopupMenuClient.h"
+#include "ScrollTypes.h"
+#include "SearchPopupMenu.h"
+#include <wtf/Forward.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(MAC)
+#include "WebCoreKeyboardUIMode.h"
+#endif
+
+#ifndef __OBJC__
+class NSMenu;
+class NSResponder;
+#endif
+
+namespace WebCore {
+
+ class AccessibilityObject;
+ class Element;
+ class FileChooser;
+ class FloatRect;
+ class Frame;
+ class Geolocation;
+ class HTMLParserQuirks;
+ class HitTestResult;
+ class IntRect;
+ class NavigationAction;
+ class Node;
+ class Page;
+ class PopupMenuClient;
+ class SecurityOrigin;
+ class SharedGraphicsContext3D;
+ class Widget;
+
+ struct FrameLoadRequest;
+ struct ViewportArguments;
+ struct WindowFeatures;
+
+#if USE(ACCELERATED_COMPOSITING)
+ class GraphicsLayer;
+#endif
+
+#if ENABLE(NOTIFICATIONS)
+ class NotificationPresenter;
+#endif
+
+ class ChromeClient {
+ public:
+ virtual void chromeDestroyed() = 0;
+
+ virtual void setWindowRect(const FloatRect&) = 0;
+ virtual FloatRect windowRect() = 0;
+
+ virtual FloatRect pageRect() = 0;
+
+ virtual float scaleFactor() = 0;
+
+ virtual void focus() = 0;
+ virtual void unfocus() = 0;
+
+ virtual bool canTakeFocus(FocusDirection) = 0;
+ virtual void takeFocus(FocusDirection) = 0;
+
+ virtual void focusedNodeChanged(Node*) = 0;
+ virtual void focusedFrameChanged(Frame*) = 0;
+
+ // The Frame pointer provides the ChromeClient with context about which
+ // Frame wants to create the new Page. Also, the newly created window
+ // should not be shown to the user until the ChromeClient of the newly
+ // created Page has its show method called.
+ virtual Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&, const NavigationAction&) = 0;
+ virtual void show() = 0;
+
+ virtual bool canRunModal() = 0;
+ virtual void runModal() = 0;
+
+ virtual void setToolbarsVisible(bool) = 0;
+ virtual bool toolbarsVisible() = 0;
+
+ virtual void setStatusbarVisible(bool) = 0;
+ virtual bool statusbarVisible() = 0;
+
+ virtual void setScrollbarsVisible(bool) = 0;
+ virtual bool scrollbarsVisible() = 0;
+
+ virtual void setMenubarVisible(bool) = 0;
+ virtual bool menubarVisible() = 0;
+
+ virtual void setResizable(bool) = 0;
+
+ virtual void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, unsigned int lineNumber, const String& sourceID) = 0;
+
+ virtual bool canRunBeforeUnloadConfirmPanel() = 0;
+ virtual bool runBeforeUnloadConfirmPanel(const String& message, Frame* frame) = 0;
+
+ virtual void closeWindowSoon() = 0;
+
+ virtual void runJavaScriptAlert(Frame*, const String&) = 0;
+ virtual bool runJavaScriptConfirm(Frame*, const String&) = 0;
+ virtual bool runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result) = 0;
+ virtual void setStatusbarText(const String&) = 0;
+ virtual bool shouldInterruptJavaScript() = 0;
+ virtual bool tabsToLinks() const = 0;
+
+ virtual IntRect windowResizerRect() const = 0;
+
+ // Methods used by HostWindow.
+ virtual void invalidateWindow(const IntRect&, bool) = 0;
+ virtual void invalidateContentsAndWindow(const IntRect&, bool) = 0;
+ virtual void invalidateContentsForSlowScroll(const IntRect&, bool) = 0;
+ virtual void scroll(const IntSize&, const IntRect&, const IntRect&) = 0;
+#if ENABLE(TILED_BACKING_STORE)
+ virtual void delegatedScrollRequested(const IntSize&) = 0;
+#endif
+ virtual IntPoint screenToWindow(const IntPoint&) const = 0;
+ virtual IntRect windowToScreen(const IntRect&) const = 0;
+ virtual PlatformPageClient platformPageClient() const = 0;
+ virtual void scrollbarsModeDidChange() const = 0;
+ virtual void setCursor(const Cursor&) = 0;
+ // End methods used by HostWindow.
+
+ virtual void dispatchViewportDataDidChange(const ViewportArguments&) const { }
+
+ virtual void contentsSizeChanged(Frame*, const IntSize&) const = 0;
+ virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const = 0; // Currently only Mac has a non empty implementation.
+
+ virtual bool shouldMissingPluginMessageBeButton() const { return false; }
+ virtual void missingPluginButtonClicked(Element*) const { }
+ virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags) = 0;
+
+ virtual void setToolTip(const String&, TextDirection) = 0;
+
+ virtual void print(Frame*) = 0;
+
+#if ENABLE(DATABASE)
+ virtual void exceededDatabaseQuota(Frame*, const String& databaseName) = 0;
+#endif
+
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ // Callback invoked when the application cache fails to save a cache object
+ // because storing it would grow the database file past its defined maximum
+ // size or past the amount of free space on the device.
+ // The chrome client would need to take some action such as evicting some
+ // old caches.
+ virtual void reachedMaxAppCacheSize(int64_t spaceNeeded) = 0;
+
+ // Callback invoked when the application cache origin quota is reached. This
+ // means that the resources attempting to be cached via the manifest are
+ // more than allowed on this origin. This callback allows the chrome client
+ // to take action, such as prompting the user to ask to increase the quota
+ // for this origin.
+ virtual void reachedApplicationCacheOriginQuota(SecurityOrigin* origin) = 0;
+#endif
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ virtual void dashboardRegionsChanged();
+#endif
+
+#if ENABLE(NOTIFICATIONS)
+ virtual NotificationPresenter* notificationPresenter() const = 0;
+#endif
+
+ virtual void populateVisitedLinks();
+
+ virtual FloatRect customHighlightRect(Node*, const AtomicString& type, const FloatRect& lineRect);
+ virtual void paintCustomHighlight(Node*, const AtomicString& type, const FloatRect& boxRect, const FloatRect& lineRect,
+ bool behindText, bool entireLine);
+
+ virtual bool shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename);
+ virtual String generateReplacementFile(const String& path);
+
+ virtual bool paintCustomScrollbar(GraphicsContext*, const FloatRect&, ScrollbarControlSize,
+ ScrollbarControlState, ScrollbarPart pressedPart, bool vertical,
+ float value, float proportion, ScrollbarControlPartMask);
+ virtual bool paintCustomScrollCorner(GraphicsContext*, const FloatRect&);
+
+ // FIXME: Remove once all ports are using client-based geolocation. https://bugs.webkit.org/show_bug.cgi?id=40373
+ // For client-based geolocation, these two methods have moved to GeolocationClient. https://bugs.webkit.org/show_bug.cgi?id=50061
+ // This can be either a synchronous or asynchronous call. The ChromeClient can display UI asking the user for permission
+ // to use Geolocation.
+ virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*) = 0;
+ virtual void cancelGeolocationPermissionRequestForFrame(Frame*, Geolocation*) = 0;
+
+ virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>) = 0;
+ // Asynchronous request to load an icon for specified filenames.
+ virtual void chooseIconForFiles(const Vector<String>&, FileChooser*) = 0;
+
+ // Notification that the given form element has changed. This function
+ // will be called frequently, so handling should be very fast.
+ virtual void formStateDidChange(const Node*) = 0;
+
+ virtual void formDidFocus(const Node*) { };
+ virtual void formDidBlur(const Node*) { };
+
+ virtual PassOwnPtr<HTMLParserQuirks> createHTMLParserQuirks() = 0;
+
+#if USE(ACCELERATED_COMPOSITING)
+ // Pass 0 as the GraphicsLayer to detatch the root layer.
+ virtual void attachRootGraphicsLayer(Frame*, GraphicsLayer*) = 0;
+ // Sets a flag to specify that the next time content is drawn to the window,
+ // the changes appear on the screen in synchrony with updates to GraphicsLayers.
+ virtual void setNeedsOneShotDrawingSynchronization() = 0;
+ // Sets a flag to specify that the view needs to be updated, so we need
+ // to do an eager layout before the drawing.
+ virtual void scheduleCompositingLayerSync() = 0;
+ // Returns whether or not the client can render the composited layer,
+ // regardless of the settings.
+ virtual bool allowsAcceleratedCompositing() const { return true; }
+
+ 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; }
+ virtual void enterFullscreenForNode(Node*) { }
+ virtual void exitFullscreenForNode(Node*) { }
+ virtual bool requiresFullscreenForVideoPlayback() { return false; }
+
+#if ENABLE(FULLSCREEN_API)
+ virtual bool supportsFullScreenForElement(const Element*) { return false; }
+ virtual void enterFullScreenForElement(Element*) { }
+ virtual void exitFullScreenForElement(Element*) { }
+ virtual void fullScreenRendererChanged(RenderBox*) { }
+#endif
+
+#if ENABLE(TILED_BACKING_STORE)
+ virtual IntRect visibleRectForTiledBackingStore() const { return IntRect(); }
+#endif
+
+#if PLATFORM(MAC)
+ virtual KeyboardUIMode keyboardUIMode() { return KeyboardAccessDefault; }
+
+ virtual NSResponder *firstResponder() { return 0; }
+ virtual void makeFirstResponder(NSResponder *) { }
+
+ virtual void willPopUpMenu(NSMenu *) { }
+#endif
+
+#if PLATFORM(WIN)
+ virtual void setLastSetCursorToCurrentCursor() = 0;
+#endif
+
+#if ENABLE(TOUCH_EVENTS)
+ virtual void needTouchEvents(bool) = 0;
+#endif
+
+ virtual bool selectItemWritingDirectionIsNatural() = 0;
+ virtual PassRefPtr<PopupMenu> createPopupMenu(PopupMenuClient*) const = 0;
+ virtual PassRefPtr<SearchPopupMenu> createSearchPopupMenu(PopupMenuClient*) const = 0;
+
+#if ENABLE(CONTEXT_MENUS)
+ virtual void showContextMenu() = 0;
+#endif
+
+ virtual void postAccessibilityNotification(AccessibilityObject*, AXObjectCache::AXNotification) { }
+
+#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS)
+ virtual void webAppCanBeInstalled() = 0;
+#endif
+
+ protected:
+ virtual ~ChromeClient() { }
+ };
+
+}
+
+#endif // ChromeClient_h
diff --git a/Source/WebCore/page/Console.cpp b/Source/WebCore/page/Console.cpp
new file mode 100644
index 0000000..219647d
--- /dev/null
+++ b/Source/WebCore/page/Console.cpp
@@ -0,0 +1,496 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "Console.h"
+
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "ConsoleMessage.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "InspectorController.h"
+#include "MemoryInfo.h"
+#include "Page.h"
+#include "PageGroup.h"
+#include "PlatformString.h"
+
+#include "ScriptArguments.h"
+#include "ScriptCallStack.h"
+#include "ScriptProfile.h"
+#include "ScriptProfiler.h"
+#include <stdio.h>
+#include <wtf/text/CString.h>
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+Console::Console(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+Frame* Console::frame() const
+{
+ return m_frame;
+}
+
+void Console::disconnectFrame()
+{
+ if (m_memory)
+ m_memory = 0;
+ m_frame = 0;
+}
+
+static void printSourceURLAndLine(const String& sourceURL, unsigned lineNumber)
+{
+ if (!sourceURL.isEmpty()) {
+ if (lineNumber > 0)
+ printf("%s:%d: ", sourceURL.utf8().data(), lineNumber);
+ else
+ printf("%s: ", sourceURL.utf8().data());
+ }
+}
+
+static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel level)
+{
+ const char* sourceString;
+ switch (source) {
+ case HTMLMessageSource:
+ sourceString = "HTML";
+ break;
+ case WMLMessageSource:
+ sourceString = "WML";
+ break;
+ case XMLMessageSource:
+ sourceString = "XML";
+ break;
+ case JSMessageSource:
+ sourceString = "JS";
+ break;
+ case CSSMessageSource:
+ sourceString = "CSS";
+ break;
+ case OtherMessageSource:
+ sourceString = "OTHER";
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ sourceString = "UNKNOWN";
+ break;
+ }
+
+ const char* levelString;
+ switch (level) {
+ case TipMessageLevel:
+ levelString = "TIP";
+ break;
+ case LogMessageLevel:
+ levelString = "LOG";
+ break;
+ case WarningMessageLevel:
+ levelString = "WARN";
+ break;
+ case ErrorMessageLevel:
+ levelString = "ERROR";
+ break;
+ case DebugMessageLevel:
+ levelString = "DEBUG";
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ levelString = "UNKNOWN";
+ break;
+ }
+
+ printf("%s %s:", sourceString, levelString);
+}
+
+void Console::addMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL)
+{
+ 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, PassRefPtr<ScriptCallStack> callStack)
+{
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ if (source == JSMessageSource)
+ page->chrome()->client()->addMessageToConsole(source, type, level, message, lineNumber, sourceURL);
+
+#if ENABLE(INSPECTOR)
+ if (callStack)
+ page->inspectorController()->addMessageToConsole(source, type, level, message, 0, callStack);
+ else
+ page->inspectorController()->addMessageToConsole(source, type, level, message, lineNumber, sourceURL);
+#endif
+
+ if (!Console::shouldPrintExceptions())
+ return;
+
+ printSourceURLAndLine(sourceURL, lineNumber);
+ printMessageSourceAndLevelPrefix(source, level);
+
+ printf(" %s\n", message.utf8().data());
+}
+
+void Console::addMessage(MessageType type, MessageLevel level, PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack, bool acceptNoArguments)
+{
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ const ScriptCallFrame& lastCaller = callStack->at(0);
+
+ if (!acceptNoArguments && !arguments->argumentCount())
+ return;
+
+ if (Console::shouldPrintExceptions()) {
+ printSourceURLAndLine(lastCaller.sourceURL(), 0);
+ printMessageSourceAndLevelPrefix(JSMessageSource, level);
+
+ for (unsigned i = 0; i < arguments->argumentCount(); ++i) {
+ String argAsString;
+ if (arguments->argumentAt(i).getString(arguments->globalState(), argAsString))
+ printf(" %s", argAsString.utf8().data());
+ }
+ printf("\n");
+ }
+
+ String message;
+ if (arguments->getFirstArgumentAsString(message))
+ page->chrome()->client()->addMessageToConsole(JSMessageSource, type, level, message, lastCaller.lineNumber(), lastCaller.sourceURL());
+
+#if ENABLE(INSPECTOR)
+ page->inspectorController()->addMessageToConsole(JSMessageSource, type, level, message, arguments, callStack);
+#endif
+}
+
+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(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
+{
+ addMessage(LogMessageType, ErrorMessageLevel, arguments, callStack);
+}
+
+void Console::info(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
+{
+ log(arguments, callStack);
+}
+
+void Console::log(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
+{
+ addMessage(LogMessageType, LogMessageLevel, arguments, callStack);
+}
+
+void Console::dir(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
+{
+ addMessage(ObjectMessageType, LogMessageLevel, arguments, 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(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
+{
+ addMessage(TraceMessageType, LogMessageLevel, arguments, callStack, true);
+
+ if (!shouldPrintExceptions())
+ return;
+
+ printf("Stack Trace\n");
+ for (unsigned i = 0; i < callStack->size(); ++i) {
+ String functionName = String(callStack->at(i).functionName());
+ printf("\t%s\n", functionName.utf8().data());
+ }
+}
+
+void Console::assertCondition(bool condition, PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
+{
+ if (condition)
+ return;
+
+ addMessage(AssertMessageType, ErrorMessageLevel, arguments, callStack, true);
+}
+
+void Console::count(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
+{
+#if ENABLE(INSPECTOR)
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ const ScriptCallFrame& lastCaller = callStack->at(0);
+ // Follow Firebug's behavior of counting with null and undefined title in
+ // the same bucket as no argument
+ String title;
+ arguments->getFirstArgumentAsString(title);
+
+ page->inspectorController()->count(title, lastCaller.lineNumber(), lastCaller.sourceURL());
+#else
+ UNUSED_PARAM(callStack);
+#endif
+}
+
+void Console::markTimeline(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack>)
+{
+#if ENABLE(INSPECTOR)
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ String message;
+ arguments->getFirstArgumentAsString(message);
+
+ page->inspectorController()->markTimeline(message);
+#else
+ UNUSED_PARAM(arguments);
+#endif
+}
+
+#if ENABLE(WML)
+String Console::lastWMLErrorMessage() const
+{
+#if ENABLE(INSPECTOR)
+ Page* page = this->page();
+ if (!page)
+ return String();
+
+ const Vector<OwnPtr<ConsoleMessage> >& consoleMessages = page->inspectorController()->consoleMessages();
+ if (consoleMessages.isEmpty())
+ return String();
+
+ Vector<OwnPtr<ConsoleMessage> >::const_iterator it = consoleMessages.begin();
+ const Vector<OwnPtr<ConsoleMessage> >::const_iterator end = consoleMessages.end();
+
+ for (; it != end; ++it) {
+ ConsoleMessage* message = it->get();
+ if (message->source() != WMLMessageSource)
+ continue;
+
+ return message->message();
+ }
+#endif
+ return String();
+}
+#endif
+
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+
+void Console::profile(const String& title, ScriptState* state, PassRefPtr<ScriptCallStack> callStack)
+{
+ Page* page = this->page();
+ if (!page)
+ return;
+
+#if ENABLE(INSPECTOR)
+ InspectorController* controller = page->inspectorController();
+ // FIXME: log a console message when profiling is disabled.
+ if (!controller->profilerEnabled())
+ return;
+#endif
+
+ String resolvedTitle = title;
+ if (title.isNull()) // no title so give it the next user initiated profile title.
+#if ENABLE(INSPECTOR)
+ resolvedTitle = controller->getCurrentUserInitiatedProfileName(true);
+#else
+ resolvedTitle = "";
+#endif
+
+ ScriptProfiler::start(state, resolvedTitle);
+
+#if ENABLE(INSPECTOR)
+ const ScriptCallFrame& lastCaller = callStack->at(0);
+ controller->addStartProfilingMessageToConsole(resolvedTitle, lastCaller.lineNumber(), lastCaller.sourceURL());
+#endif
+}
+
+void Console::profileEnd(const String& title, ScriptState* state, PassRefPtr<ScriptCallStack> callStack)
+{
+ Page* page = this->page();
+ if (!page)
+ return;
+
+#if ENABLE(INSPECTOR)
+ InspectorController* controller = page->inspectorController();
+ if (!controller->profilerEnabled())
+ return;
+#endif
+
+ RefPtr<ScriptProfile> profile = ScriptProfiler::stop(state, title);
+ if (!profile)
+ return;
+
+ m_profiles.append(profile);
+
+#if ENABLE(INSPECTOR)
+ const ScriptCallFrame& lastCaller = callStack->at(0);
+ controller->addProfile(profile, lastCaller.lineNumber(), lastCaller.sourceURL());
+#endif
+}
+
+#endif
+
+void Console::time(const String& title)
+{
+#if ENABLE(INSPECTOR)
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ // Follow Firebug's behavior of requiring a title that is not null or
+ // undefined for timing functions
+ if (title.isNull())
+ return;
+
+ page->inspectorController()->startTiming(title);
+#else
+ UNUSED_PARAM(title);
+#endif
+}
+
+void Console::timeEnd(const String& title, PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack> callStack)
+{
+#if ENABLE(INSPECTOR)
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ // Follow Firebug's behavior of requiring a title that is not null or
+ // undefined for timing functions
+ if (title.isNull())
+ return;
+
+ double elapsed;
+ if (!page->inspectorController()->stopTiming(title, elapsed))
+ return;
+
+ String message = title + String::format(": %.0fms", elapsed);
+
+ const ScriptCallFrame& lastCaller = callStack->at(0);
+ page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lastCaller.lineNumber(), lastCaller.sourceURL());
+#else
+ UNUSED_PARAM(title);
+ UNUSED_PARAM(callStack);
+#endif
+}
+
+void Console::group(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
+{
+#if ENABLE(INSPECTOR)
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ page->inspectorController()->startGroup(arguments, callStack);
+#else
+ UNUSED_PARAM(arguments);
+ UNUSED_PARAM(callStack);
+#endif
+}
+
+void Console::groupCollapsed(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
+{
+#if ENABLE(INSPECTOR)
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ page->inspectorController()->startGroup(arguments, callStack, true);
+#else
+ UNUSED_PARAM(arguments);
+ UNUSED_PARAM(callStack);
+#endif
+}
+
+void Console::groupEnd()
+{
+#if ENABLE(INSPECTOR)
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ page->inspectorController()->endGroup(JSMessageSource, 0, String());
+#endif
+}
+
+bool Console::shouldCaptureFullStackTrace() const
+{
+#if ENABLE(INSPECTOR)
+ Page* page = this->page();
+ if (!page)
+ return false;
+
+ return page->inspectorController()->hasFrontend();
+#else
+ return false;
+#endif
+}
+
+void Console::warn(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack)
+{
+ addMessage(LogMessageType, WarningMessageLevel, arguments, callStack);
+}
+
+MemoryInfo* Console::memory() const
+{
+ m_memory = MemoryInfo::create(m_frame);
+ return m_memory.get();
+}
+
+static bool printExceptions = false;
+
+bool Console::shouldPrintExceptions()
+{
+ return printExceptions;
+}
+
+void Console::setShouldPrintExceptions(bool print)
+{
+ printExceptions = print;
+}
+
+Page* Console::page() const
+{
+ if (!m_frame)
+ return 0;
+ return m_frame->page();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/Console.h b/Source/WebCore/page/Console.h
new file mode 100644
index 0000000..dd692a2
--- /dev/null
+++ b/Source/WebCore/page/Console.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 Console_h
+#define Console_h
+
+#include "MemoryInfo.h"
+#include "PlatformString.h"
+#include "ScriptProfile.h"
+#include "ScriptState.h"
+
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class ScriptArguments;
+
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+typedef Vector<RefPtr<ScriptProfile> > ProfilesArray;
+#endif
+
+class Frame;
+class Page;
+class ScriptCallStack;
+
+// Keep in sync with inspector/front-end/Console.js
+enum MessageSource {
+ HTMLMessageSource,
+ WMLMessageSource,
+ XMLMessageSource,
+ JSMessageSource,
+ CSSMessageSource,
+ OtherMessageSource
+};
+
+enum MessageType {
+ LogMessageType,
+ ObjectMessageType,
+ TraceMessageType,
+ StartGroupMessageType,
+ StartGroupCollapsedMessageType,
+ EndGroupMessageType,
+ AssertMessageType,
+ UncaughtExceptionMessageType,
+ NetworkErrorMessageType
+};
+
+enum MessageLevel {
+ TipMessageLevel,
+ LogMessageLevel,
+ WarningMessageLevel,
+ ErrorMessageLevel,
+ DebugMessageLevel
+};
+
+class Console : public RefCounted<Console> {
+public:
+ static PassRefPtr<Console> create(Frame* frame) { return adoptRef(new Console(frame)); }
+
+ Frame* frame() const;
+ 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, 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*, PassRefPtr<ScriptCallStack>);
+ void profileEnd(const String&, ScriptState*, PassRefPtr<ScriptCallStack>);
+#endif
+ void time(const String&);
+ 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;
+
+ static bool shouldPrintExceptions();
+ static void setShouldPrintExceptions(bool);
+
+ MemoryInfo* memory() const;
+
+private:
+ inline Page* page() const;
+ void addMessage(MessageType, MessageLevel, PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>, bool acceptNoArguments = false);
+
+ Console(Frame*);
+
+ Frame* m_frame;
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+ ProfilesArray m_profiles;
+#endif
+ mutable RefPtr<MemoryInfo> m_memory;
+};
+
+} // namespace WebCore
+
+#endif // Console_h
diff --git a/Source/WebCore/page/Console.idl b/Source/WebCore/page/Console.idl
new file mode 100644
index 0000000..503bb91
--- /dev/null
+++ b/Source/WebCore/page/Console.idl
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module window {
+
+ interface [OmitConstructor] Console {
+
+ [CustomArgumentHandling] void debug();
+ [CustomArgumentHandling] void error();
+ [CustomArgumentHandling] void info();
+ [CustomArgumentHandling] void log();
+ [CustomArgumentHandling] void warn();
+ [CustomArgumentHandling] void dir();
+ [CustomArgumentHandling] void dirxml();
+ [V8Custom, CustomArgumentHandling] void trace();
+ [V8Custom, CustomArgumentHandling, ImplementationFunction=assertCondition] void assert(in boolean condition);
+ [CustomArgumentHandling] void count();
+ [CustomArgumentHandling] void markTimeline();
+
+#if defined(ENABLE_WML) && ENABLE_WML
+ [DontEnum] DOMString lastWMLErrorMessage();
+#endif
+
+#if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER
+ readonly attribute [CustomGetter] Array profiles;
+ [Custom] void profile(in DOMString title);
+ [Custom] void profileEnd(in DOMString title);
+#endif
+
+ void time(in [ConvertUndefinedOrNullToNullString] DOMString title);
+ [CustomArgumentHandling] void timeEnd(in [ConvertUndefinedOrNullToNullString] DOMString title);
+ [CustomArgumentHandling] void group();
+ [CustomArgumentHandling] void groupCollapsed();
+ void groupEnd();
+
+ readonly attribute [V8CustomGetter] MemoryInfo memory;
+ };
+
+}
diff --git a/Source/WebCore/page/ContextMenuClient.h b/Source/WebCore/page/ContextMenuClient.h
new file mode 100644
index 0000000..c9389c0
--- /dev/null
+++ b/Source/WebCore/page/ContextMenuClient.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ContextMenuClient_h
+#define ContextMenuClient_h
+
+#include "ContextMenu.h"
+#include "PlatformMenuDescription.h"
+#include <wtf/Forward.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+ class ContextMenuItem;
+ class Frame;
+ class HitTestResult;
+ class KURL;
+
+ class ContextMenuClient {
+ public:
+ virtual ~ContextMenuClient() { }
+ virtual void contextMenuDestroyed() = 0;
+
+#if USE(CROSS_PLATFORM_CONTEXT_MENUS)
+ virtual PassOwnPtr<ContextMenu> customizeMenu(PassOwnPtr<ContextMenu>) = 0;
+#else
+ virtual PlatformMenuDescription getCustomMenuFromDefaultItems(ContextMenu*) = 0;
+#endif
+
+ virtual void contextMenuItemSelected(ContextMenuItem*, const ContextMenu*) = 0;
+
+ virtual void downloadURL(const KURL& url) = 0;
+ virtual void searchWithGoogle(const Frame*) = 0;
+ virtual void lookUpInDictionary(Frame*) = 0;
+ virtual bool isSpeaking() = 0;
+ virtual void speak(const String&) = 0;
+ virtual void stopSpeaking() = 0;
+
+#if PLATFORM(MAC)
+ virtual void searchWithSpotlight() = 0;
+#endif
+ };
+}
+
+#endif
diff --git a/Source/WebCore/page/ContextMenuController.cpp b/Source/WebCore/page/ContextMenuController.cpp
new file mode 100644
index 0000000..ac89db2
--- /dev/null
+++ b/Source/WebCore/page/ContextMenuController.cpp
@@ -0,0 +1,1249 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Igalia S.L
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ContextMenuController.h"
+
+#if ENABLE(CONTEXT_MENUS)
+
+#include "BackForwardController.h"
+#include "Chrome.h"
+#include "ContextMenu.h"
+#include "ContextMenuClient.h"
+#include "ContextMenuItem.h"
+#include "ContextMenuProvider.h"
+#include "Document.h"
+#include "DocumentFragment.h"
+#include "DocumentLoader.h"
+#include "Editor.h"
+#include "EditorClient.h"
+#include "Event.h"
+#include "EventHandler.h"
+#include "EventNames.h"
+#include "FormState.h"
+#include "Frame.h"
+#include "FrameLoadRequest.h"
+#include "FrameLoader.h"
+#include "HTMLFormElement.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "InspectorController.h"
+#include "LocalizedStrings.h"
+#include "MouseEvent.h"
+#include "NavigationAction.h"
+#include "Node.h"
+#include "Page.h"
+#include "RenderLayer.h"
+#include "RenderObject.h"
+#include "ReplaceSelectionCommand.h"
+#include "ResourceRequest.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "TextIterator.h"
+#include "WindowFeatures.h"
+#include "markup.h"
+#include <wtf/unicode/Unicode.h>
+
+using namespace WTF;
+using namespace Unicode;
+
+namespace WebCore {
+
+ContextMenuController::ContextMenuController(Page* page, ContextMenuClient* client)
+ : m_page(page)
+ , m_client(client)
+ , m_contextMenu(0)
+{
+ ASSERT_ARG(page, page);
+ ASSERT_ARG(client, client);
+}
+
+ContextMenuController::~ContextMenuController()
+{
+ m_client->contextMenuDestroyed();
+}
+
+void ContextMenuController::clearContextMenu()
+{
+ m_contextMenu.set(0);
+ if (m_menuProvider)
+ m_menuProvider->contextMenuCleared();
+ m_menuProvider = 0;
+}
+
+void ContextMenuController::handleContextMenuEvent(Event* event)
+{
+ m_contextMenu = createContextMenu(event);
+ if (!m_contextMenu)
+ return;
+
+ populate();
+
+ showContextMenu(event);
+}
+
+void ContextMenuController::showContextMenu(Event* event, PassRefPtr<ContextMenuProvider> menuProvider)
+{
+ m_menuProvider = menuProvider;
+
+ m_contextMenu = createContextMenu(event);
+ if (!m_contextMenu) {
+ clearContextMenu();
+ return;
+ }
+
+ m_menuProvider->populateContextMenu(m_contextMenu.get());
+ showContextMenu(event);
+}
+
+PassOwnPtr<ContextMenu> ContextMenuController::createContextMenu(Event* event)
+{
+ if (!event->isMouseEvent())
+ return 0;
+
+ MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+ HitTestResult result(mouseEvent->absoluteLocation());
+
+ if (Frame* frame = event->target()->toNode()->document()->frame())
+ result = frame->eventHandler()->hitTestResultAtPoint(mouseEvent->absoluteLocation(), false);
+
+ if (!result.innerNonSharedNode())
+ return 0;
+
+ m_hitTestResult = result;
+
+ return new ContextMenu;
+}
+
+void ContextMenuController::showContextMenu(Event* event)
+{
+#if ENABLE(INSPECTOR)
+ if (m_page->inspectorController()->enabled())
+ addInspectElementItem();
+#endif
+
+#if USE(CROSS_PLATFORM_CONTEXT_MENUS)
+ m_contextMenu = m_client->customizeMenu(m_contextMenu.release());
+#else
+ PlatformMenuDescription customMenu = m_client->getCustomMenuFromDefaultItems(m_contextMenu.get());
+ m_contextMenu->setPlatformDescription(customMenu);
+#endif
+ event->setDefaultHandled();
+}
+
+static void openNewWindow(const KURL& urlToLoad, Frame* frame)
+{
+ if (Page* oldPage = frame->page()) {
+ FrameLoadRequest request(frame->document()->securityOrigin(), ResourceRequest(urlToLoad, frame->loader()->outgoingReferrer()));
+ WindowFeatures features;
+ if (Page* newPage = oldPage->chrome()->createWindow(frame, request, features, NavigationAction()))
+ newPage->chrome()->show();
+ }
+}
+
+void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item)
+{
+ ASSERT(item->type() == ActionType || item->type() == CheckableActionType);
+
+ if (item->action() >= ContextMenuItemBaseApplicationTag) {
+ m_client->contextMenuItemSelected(item, m_contextMenu.get());
+ return;
+ }
+
+ if (item->action() >= ContextMenuItemBaseCustomTag) {
+ ASSERT(m_menuProvider);
+ m_menuProvider->contextMenuItemSelected(item);
+ return;
+ }
+
+ Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame();
+ if (!frame)
+ return;
+
+ switch (item->action()) {
+ case ContextMenuItemTagOpenLinkInNewWindow:
+ openNewWindow(m_hitTestResult.absoluteLinkURL(), frame);
+ break;
+ case ContextMenuItemTagDownloadLinkToDisk:
+ // FIXME: Some day we should be able to do this from within WebCore.
+ m_client->downloadURL(m_hitTestResult.absoluteLinkURL());
+ break;
+ case ContextMenuItemTagCopyLinkToClipboard:
+ frame->editor()->copyURL(m_hitTestResult.absoluteLinkURL(), m_hitTestResult.textContent());
+ break;
+ case ContextMenuItemTagOpenImageInNewWindow:
+ openNewWindow(m_hitTestResult.absoluteImageURL(), frame);
+ break;
+ case ContextMenuItemTagDownloadImageToDisk:
+ // FIXME: Some day we should be able to do this from within WebCore.
+ m_client->downloadURL(m_hitTestResult.absoluteImageURL());
+ break;
+ case ContextMenuItemTagCopyImageToClipboard:
+ // FIXME: The Pasteboard class is not written yet
+ // For now, call into the client. This is temporary!
+ frame->editor()->copyImage(m_hitTestResult);
+ break;
+ case ContextMenuItemTagOpenMediaInNewWindow:
+ openNewWindow(m_hitTestResult.absoluteMediaURL(), frame);
+ break;
+ case ContextMenuItemTagCopyMediaLinkToClipboard:
+ frame->editor()->copyURL(m_hitTestResult.absoluteMediaURL(), m_hitTestResult.textContent());
+ break;
+ case ContextMenuItemTagToggleMediaControls:
+ m_hitTestResult.toggleMediaControlsDisplay();
+ break;
+ case ContextMenuItemTagToggleMediaLoop:
+ m_hitTestResult.toggleMediaLoopPlayback();
+ break;
+ case ContextMenuItemTagEnterVideoFullscreen:
+ m_hitTestResult.enterFullscreenForVideo();
+ break;
+ case ContextMenuItemTagMediaPlayPause:
+ m_hitTestResult.toggleMediaPlayState();
+ break;
+ case ContextMenuItemTagMediaMute:
+ m_hitTestResult.toggleMediaMuteState();
+ break;
+ case ContextMenuItemTagOpenFrameInNewWindow: {
+ DocumentLoader* loader = frame->loader()->documentLoader();
+ if (!loader->unreachableURL().isEmpty())
+ openNewWindow(loader->unreachableURL(), frame);
+ else
+ openNewWindow(loader->url(), frame);
+ break;
+ }
+ case ContextMenuItemTagCopy:
+ frame->editor()->copy();
+ break;
+ case ContextMenuItemTagGoBack:
+ if (Page* page = frame->page())
+ page->backForward()->goBackOrForward(-1);
+ break;
+ case ContextMenuItemTagGoForward:
+ if (Page* page = frame->page())
+ page->backForward()->goBackOrForward(1);
+ break;
+ case ContextMenuItemTagStop:
+ frame->loader()->stop();
+ break;
+ case ContextMenuItemTagReload:
+ frame->loader()->reload();
+ break;
+ case ContextMenuItemTagCut:
+ frame->editor()->cut();
+ break;
+ case ContextMenuItemTagPaste:
+ frame->editor()->paste();
+ break;
+#if PLATFORM(GTK)
+ case ContextMenuItemTagDelete:
+ frame->editor()->performDelete();
+ break;
+#endif
+#if PLATFORM(GTK) || PLATFORM(QT)
+ case ContextMenuItemTagSelectAll:
+ frame->editor()->command("SelectAll").execute();
+ break;
+#endif
+ case ContextMenuItemTagSpellingGuess:
+ ASSERT(frame->editor()->selectedText().length());
+ if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toNormalizedRange().get(), EditorInsertActionPasted)) {
+ Document* document = frame->document();
+ RefPtr<ReplaceSelectionCommand> command = ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""), true, false, true);
+ applyCommand(command);
+ frame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
+ }
+ break;
+ case ContextMenuItemTagIgnoreSpelling:
+ frame->editor()->ignoreSpelling();
+ break;
+ case ContextMenuItemTagLearnSpelling:
+ frame->editor()->learnSpelling();
+ break;
+ case ContextMenuItemTagSearchWeb:
+ m_client->searchWithGoogle(frame);
+ break;
+ case ContextMenuItemTagLookUpInDictionary:
+ // FIXME: Some day we may be able to do this from within WebCore.
+ m_client->lookUpInDictionary(frame);
+ break;
+ case ContextMenuItemTagOpenLink:
+ if (Frame* targetFrame = m_hitTestResult.targetFrame())
+ targetFrame->loader()->loadFrameRequest(FrameLoadRequest(frame->document()->securityOrigin(), ResourceRequest(m_hitTestResult.absoluteLinkURL(), frame->loader()->outgoingReferrer())), false, false, 0, 0, SendReferrer);
+ else
+ openNewWindow(m_hitTestResult.absoluteLinkURL(), frame);
+ break;
+ case ContextMenuItemTagBold:
+ frame->editor()->command("ToggleBold").execute();
+ break;
+ case ContextMenuItemTagItalic:
+ frame->editor()->command("ToggleItalic").execute();
+ break;
+ case ContextMenuItemTagUnderline:
+ frame->editor()->toggleUnderline();
+ break;
+ case ContextMenuItemTagOutline:
+ // We actually never enable this because CSS does not have a way to specify an outline font,
+ // which may make this difficult to implement. Maybe a special case of text-shadow?
+ break;
+ case ContextMenuItemTagStartSpeaking: {
+ ExceptionCode ec;
+ RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
+ if (!selectedRange || selectedRange->collapsed(ec)) {
+ Document* document = m_hitTestResult.innerNonSharedNode()->document();
+ selectedRange = document->createRange();
+ selectedRange->selectNode(document->documentElement(), ec);
+ }
+ m_client->speak(plainText(selectedRange.get()));
+ break;
+ }
+ case ContextMenuItemTagStopSpeaking:
+ m_client->stopSpeaking();
+ break;
+ case ContextMenuItemTagDefaultDirection:
+ frame->editor()->setBaseWritingDirection(NaturalWritingDirection);
+ break;
+ case ContextMenuItemTagLeftToRight:
+ frame->editor()->setBaseWritingDirection(LeftToRightWritingDirection);
+ break;
+ case ContextMenuItemTagRightToLeft:
+ frame->editor()->setBaseWritingDirection(RightToLeftWritingDirection);
+ break;
+ case ContextMenuItemTagTextDirectionDefault:
+ frame->editor()->command("MakeTextWritingDirectionNatural").execute();
+ break;
+ case ContextMenuItemTagTextDirectionLeftToRight:
+ frame->editor()->command("MakeTextWritingDirectionLeftToRight").execute();
+ break;
+ case ContextMenuItemTagTextDirectionRightToLeft:
+ frame->editor()->command("MakeTextWritingDirectionRightToLeft").execute();
+ break;
+#if PLATFORM(MAC)
+ case ContextMenuItemTagSearchInSpotlight:
+ m_client->searchWithSpotlight();
+ break;
+#endif
+ case ContextMenuItemTagShowSpellingPanel:
+ frame->editor()->showSpellingGuessPanel();
+ break;
+ case ContextMenuItemTagCheckSpelling:
+ frame->editor()->advanceToNextMisspelling();
+ break;
+ case ContextMenuItemTagCheckSpellingWhileTyping:
+ frame->editor()->toggleContinuousSpellChecking();
+ break;
+#ifndef BUILDING_ON_TIGER
+ case ContextMenuItemTagCheckGrammarWithSpelling:
+ frame->editor()->toggleGrammarChecking();
+ break;
+#endif
+#if PLATFORM(MAC)
+ case ContextMenuItemTagShowFonts:
+ frame->editor()->showFontPanel();
+ break;
+ case ContextMenuItemTagStyles:
+ frame->editor()->showStylesPanel();
+ break;
+ case ContextMenuItemTagShowColors:
+ frame->editor()->showColorPanel();
+ break;
+#endif
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ case ContextMenuItemTagMakeUpperCase:
+ frame->editor()->uppercaseWord();
+ break;
+ case ContextMenuItemTagMakeLowerCase:
+ frame->editor()->lowercaseWord();
+ break;
+ case ContextMenuItemTagCapitalize:
+ frame->editor()->capitalizeWord();
+ break;
+ case ContextMenuItemTagShowSubstitutions:
+ frame->editor()->showSubstitutionsPanel();
+ break;
+ case ContextMenuItemTagSmartCopyPaste:
+ frame->editor()->toggleSmartInsertDelete();
+ break;
+ case ContextMenuItemTagSmartQuotes:
+ frame->editor()->toggleAutomaticQuoteSubstitution();
+ break;
+ case ContextMenuItemTagSmartDashes:
+ frame->editor()->toggleAutomaticDashSubstitution();
+ break;
+ case ContextMenuItemTagSmartLinks:
+ frame->editor()->toggleAutomaticLinkDetection();
+ break;
+ case ContextMenuItemTagTextReplacement:
+ frame->editor()->toggleAutomaticTextReplacement();
+ break;
+ case ContextMenuItemTagCorrectSpellingAutomatically:
+ frame->editor()->toggleAutomaticSpellingCorrection();
+ break;
+ case ContextMenuItemTagChangeBack:
+ frame->editor()->changeBackToReplacedString(m_hitTestResult.replacedString());
+ break;
+#endif
+#if ENABLE(INSPECTOR)
+ case ContextMenuItemTagInspectElement:
+ if (Page* page = frame->page())
+ page->inspectorController()->inspect(m_hitTestResult.innerNonSharedNode());
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+void ContextMenuController::appendItem(ContextMenuItem& menuItem, ContextMenu* parentMenu)
+{
+ checkOrEnableIfNeeded(menuItem);
+ if (parentMenu)
+ parentMenu->appendItem(menuItem);
+}
+
+static PassOwnPtr<ContextMenuItem> separatorItem()
+{
+ return new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String());
+}
+
+void ContextMenuController::createAndAppendFontSubMenu(ContextMenuItem& fontMenuItem)
+{
+ ContextMenu fontMenu;
+
+#if PLATFORM(MAC)
+ ContextMenuItem showFonts(ActionType, ContextMenuItemTagShowFonts, contextMenuItemTagShowFonts());
+#endif
+ ContextMenuItem bold(CheckableActionType, ContextMenuItemTagBold, contextMenuItemTagBold());
+ ContextMenuItem italic(CheckableActionType, ContextMenuItemTagItalic, contextMenuItemTagItalic());
+ ContextMenuItem underline(CheckableActionType, ContextMenuItemTagUnderline, contextMenuItemTagUnderline());
+ ContextMenuItem outline(ActionType, ContextMenuItemTagOutline, contextMenuItemTagOutline());
+#if PLATFORM(MAC)
+ ContextMenuItem styles(ActionType, ContextMenuItemTagStyles, contextMenuItemTagStyles());
+ ContextMenuItem showColors(ActionType, ContextMenuItemTagShowColors, contextMenuItemTagShowColors());
+#endif
+
+#if PLATFORM(MAC)
+ appendItem(showFonts, &fontMenu);
+#endif
+ appendItem(bold, &fontMenu);
+ appendItem(italic, &fontMenu);
+ appendItem(underline, &fontMenu);
+ appendItem(outline, &fontMenu);
+#if PLATFORM(MAC)
+ appendItem(styles, &fontMenu);
+ appendItem(*separatorItem(), &fontMenu);
+ appendItem(showColors, &fontMenu);
+#endif
+
+ fontMenuItem.setSubMenu(&fontMenu);
+}
+
+#if !defined(BUILDING_ON_TIGER)
+
+#if !PLATFORM(GTK)
+
+void ContextMenuController::createAndAppendSpellingAndGrammarSubMenu(ContextMenuItem& spellingAndGrammarMenuItem)
+{
+ ContextMenu spellingAndGrammarMenu;
+
+ ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel,
+ contextMenuItemTagShowSpellingPanel(true));
+ ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling,
+ contextMenuItemTagCheckSpelling());
+ ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping,
+ contextMenuItemTagCheckSpellingWhileTyping());
+ ContextMenuItem grammarWithSpelling(CheckableActionType, ContextMenuItemTagCheckGrammarWithSpelling,
+ contextMenuItemTagCheckGrammarWithSpelling());
+#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
+ ContextMenuItem correctSpelling(CheckableActionType, ContextMenuItemTagCorrectSpellingAutomatically,
+ contextMenuItemTagCorrectSpellingAutomatically());
+#endif
+
+ appendItem(showSpellingPanel, &spellingAndGrammarMenu);
+ appendItem(checkSpelling, &spellingAndGrammarMenu);
+#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
+ appendItem(*separatorItem(), &spellingAndGrammarMenu);
+#endif
+ appendItem(checkAsYouType, &spellingAndGrammarMenu);
+ appendItem(grammarWithSpelling, &spellingAndGrammarMenu);
+#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
+ appendItem(correctSpelling, &spellingAndGrammarMenu);
+#endif
+
+ spellingAndGrammarMenuItem.setSubMenu(&spellingAndGrammarMenu);
+}
+
+#endif // !PLATFORM(GTK)
+
+#else
+
+void ContextMenuController::createAndAppendSpellingAndGrammarSubMenu(ContextMenuItem& spellingAndGrammarMenuItem)
+{
+ ContextMenu spellingMenu;
+
+ ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel,
+ contextMenuItemTagShowSpellingPanel(true));
+ ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling,
+ contextMenuItemTagCheckSpelling());
+ ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping,
+ contextMenuItemTagCheckSpellingWhileTyping());
+
+ appendItem(showSpellingPanel, &spellingMenu);
+ appendItem(checkSpelling, &spellingMenu);
+ appendItem(checkAsYouType, &spellingMenu);
+
+ spellingMenuItem.setSubMenu(&spellingMenu);
+}
+
+#endif
+
+#if PLATFORM(MAC)
+
+void ContextMenuController::createAndAppendSpeechSubMenu(ContextMenuItem& speechMenuItem)
+{
+ ContextMenu speechMenu;
+
+ ContextMenuItem start(ActionType, ContextMenuItemTagStartSpeaking, contextMenuItemTagStartSpeaking());
+ ContextMenuItem stop(ActionType, ContextMenuItemTagStopSpeaking, contextMenuItemTagStopSpeaking());
+
+ appendItem(start, &speechMenu);
+ appendItem(stop, &speechMenu);
+
+ speechMenuItem.setSubMenu(&speechMenu);
+}
+
+#endif
+
+#if !PLATFORM(GTK)
+
+void ContextMenuController::createAndAppendWritingDirectionSubMenu(ContextMenuItem& writingDirectionMenuItem)
+{
+ ContextMenu writingDirectionMenu;
+
+ ContextMenuItem defaultItem(ActionType, ContextMenuItemTagDefaultDirection,
+ contextMenuItemTagDefaultDirection());
+ ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagLeftToRight, contextMenuItemTagLeftToRight());
+ ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagRightToLeft, contextMenuItemTagRightToLeft());
+
+ appendItem(defaultItem, &writingDirectionMenu);
+ appendItem(ltr, &writingDirectionMenu);
+ appendItem(rtl, &writingDirectionMenu);
+
+ writingDirectionMenuItem.setSubMenu(&writingDirectionMenu);
+}
+
+void ContextMenuController::createAndAppendTextDirectionSubMenu(ContextMenuItem& textDirectionMenuItem)
+{
+ ContextMenu textDirectionMenu;
+
+ ContextMenuItem defaultItem(ActionType, ContextMenuItemTagTextDirectionDefault, contextMenuItemTagDefaultDirection());
+ ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagTextDirectionLeftToRight, contextMenuItemTagLeftToRight());
+ ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagTextDirectionRightToLeft, contextMenuItemTagRightToLeft());
+
+ appendItem(defaultItem, &textDirectionMenu);
+ appendItem(ltr, &textDirectionMenu);
+ appendItem(rtl, &textDirectionMenu);
+
+ textDirectionMenuItem.setSubMenu(&textDirectionMenu);
+}
+
+#endif
+
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+
+void ContextMenuController::createAndAppendSubstitutionsSubMenu(ContextMenuItem& substitutionsMenuItem)
+{
+ ContextMenu substitutionsMenu;
+
+ ContextMenuItem showSubstitutions(ActionType, ContextMenuItemTagShowSubstitutions, contextMenuItemTagShowSubstitutions(true));
+ ContextMenuItem smartCopyPaste(CheckableActionType, ContextMenuItemTagSmartCopyPaste, contextMenuItemTagSmartCopyPaste());
+ ContextMenuItem smartQuotes(CheckableActionType, ContextMenuItemTagSmartQuotes, contextMenuItemTagSmartQuotes());
+ ContextMenuItem smartDashes(CheckableActionType, ContextMenuItemTagSmartDashes, contextMenuItemTagSmartDashes());
+ ContextMenuItem smartLinks(CheckableActionType, ContextMenuItemTagSmartLinks, contextMenuItemTagSmartLinks());
+ ContextMenuItem textReplacement(CheckableActionType, ContextMenuItemTagTextReplacement, contextMenuItemTagTextReplacement());
+
+ appendItem(showSubstitutions, &substitutionsMenu);
+ appendItem(*separatorItem(), &substitutionsMenu);
+ appendItem(smartCopyPaste, &substitutionsMenu);
+ appendItem(smartQuotes, &substitutionsMenu);
+ appendItem(smartDashes, &substitutionsMenu);
+ appendItem(smartLinks, &substitutionsMenu);
+ appendItem(textReplacement, &substitutionsMenu);
+
+ substitutionsMenuItem.setSubMenu(&substitutionsMenu);
+}
+
+void ContextMenuController::createAndAppendTransformationsSubMenu(ContextMenuItem& transformationsMenuItem)
+{
+ ContextMenu transformationsMenu;
+
+ ContextMenuItem makeUpperCase(ActionType, ContextMenuItemTagMakeUpperCase, contextMenuItemTagMakeUpperCase());
+ ContextMenuItem makeLowerCase(ActionType, ContextMenuItemTagMakeLowerCase, contextMenuItemTagMakeLowerCase());
+ ContextMenuItem capitalize(ActionType, ContextMenuItemTagCapitalize, contextMenuItemTagCapitalize());
+
+ appendItem(makeUpperCase, &transformationsMenu);
+ appendItem(makeLowerCase, &transformationsMenu);
+ appendItem(capitalize, &transformationsMenu);
+
+ transformationsMenuItem.setSubMenu(&transformationsMenu);
+}
+
+#endif
+
+static bool selectionContainsPossibleWord(Frame* frame)
+{
+ // Current algorithm: look for a character that's not just a separator.
+ for (TextIterator it(frame->selection()->toNormalizedRange().get()); !it.atEnd(); it.advance()) {
+ int length = it.length();
+ const UChar* characters = it.characters();
+ for (int i = 0; i < length; ++i)
+ if (!(category(characters[i]) & (Separator_Space | Separator_Line | Separator_Paragraph)))
+ return true;
+ }
+ return false;
+}
+
+void ContextMenuController::populate()
+{
+ ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink());
+ ContextMenuItem OpenLinkInNewWindowItem(ActionType, ContextMenuItemTagOpenLinkInNewWindow,
+ contextMenuItemTagOpenLinkInNewWindow());
+ ContextMenuItem DownloadFileItem(ActionType, ContextMenuItemTagDownloadLinkToDisk,
+ contextMenuItemTagDownloadLinkToDisk());
+ ContextMenuItem CopyLinkItem(ActionType, ContextMenuItemTagCopyLinkToClipboard,
+ contextMenuItemTagCopyLinkToClipboard());
+ ContextMenuItem OpenImageInNewWindowItem(ActionType, ContextMenuItemTagOpenImageInNewWindow,
+ contextMenuItemTagOpenImageInNewWindow());
+ ContextMenuItem DownloadImageItem(ActionType, ContextMenuItemTagDownloadImageToDisk,
+ contextMenuItemTagDownloadImageToDisk());
+ ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard,
+ contextMenuItemTagCopyImageToClipboard());
+ ContextMenuItem OpenMediaInNewWindowItem(ActionType, ContextMenuItemTagOpenMediaInNewWindow, String());
+ ContextMenuItem CopyMediaLinkItem(ActionType, ContextMenuItemTagCopyMediaLinkToClipboard,
+ String());
+ ContextMenuItem MediaPlayPause(ActionType, ContextMenuItemTagMediaPlayPause,
+ contextMenuItemTagMediaPlay());
+ ContextMenuItem MediaMute(ActionType, ContextMenuItemTagMediaMute,
+ contextMenuItemTagMediaMute());
+ ContextMenuItem ToggleMediaControls(CheckableActionType, ContextMenuItemTagToggleMediaControls,
+ contextMenuItemTagToggleMediaControls());
+ ContextMenuItem ToggleMediaLoop(CheckableActionType, ContextMenuItemTagToggleMediaLoop,
+ contextMenuItemTagToggleMediaLoop());
+ ContextMenuItem EnterVideoFullscreen(ActionType, ContextMenuItemTagEnterVideoFullscreen,
+ contextMenuItemTagEnterVideoFullscreen());
+#if PLATFORM(MAC)
+ ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight,
+ contextMenuItemTagSearchInSpotlight());
+ ContextMenuItem LookInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary,
+ contextMenuItemTagLookUpInDictionary());
+#endif
+#if !PLATFORM(GTK)
+ ContextMenuItem SearchWebItem(ActionType, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb());
+#endif
+ ContextMenuItem CopyItem(ActionType, ContextMenuItemTagCopy, contextMenuItemTagCopy());
+ ContextMenuItem BackItem(ActionType, ContextMenuItemTagGoBack, contextMenuItemTagGoBack());
+ ContextMenuItem ForwardItem(ActionType, ContextMenuItemTagGoForward, contextMenuItemTagGoForward());
+ ContextMenuItem StopItem(ActionType, ContextMenuItemTagStop, contextMenuItemTagStop());
+ ContextMenuItem ReloadItem(ActionType, ContextMenuItemTagReload, contextMenuItemTagReload());
+ ContextMenuItem OpenFrameItem(ActionType, ContextMenuItemTagOpenFrameInNewWindow,
+ contextMenuItemTagOpenFrameInNewWindow());
+ ContextMenuItem NoGuessesItem(ActionType, ContextMenuItemTagNoGuessesFound,
+ contextMenuItemTagNoGuessesFound());
+ ContextMenuItem IgnoreSpellingItem(ActionType, ContextMenuItemTagIgnoreSpelling,
+ contextMenuItemTagIgnoreSpelling());
+ ContextMenuItem LearnSpellingItem(ActionType, ContextMenuItemTagLearnSpelling,
+ contextMenuItemTagLearnSpelling());
+ ContextMenuItem IgnoreGrammarItem(ActionType, ContextMenuItemTagIgnoreGrammar,
+ contextMenuItemTagIgnoreGrammar());
+ ContextMenuItem CutItem(ActionType, ContextMenuItemTagCut, contextMenuItemTagCut());
+ ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste());
+#if PLATFORM(GTK)
+ ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete());
+#endif
+#if PLATFORM(GTK) || PLATFORM(QT)
+ ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll());
+#endif
+
+ Node* node = m_hitTestResult.innerNonSharedNode();
+ if (!node)
+ return;
+#if PLATFORM(GTK)
+ if (!m_hitTestResult.isContentEditable() && (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement()))
+ return;
+#endif
+ Frame* frame = node->document()->frame();
+ if (!frame)
+ return;
+
+ if (!m_hitTestResult.isContentEditable()) {
+ FrameLoader* loader = frame->loader();
+ KURL linkURL = m_hitTestResult.absoluteLinkURL();
+ if (!linkURL.isEmpty()) {
+ if (loader->canHandleRequest(ResourceRequest(linkURL))) {
+ appendItem(OpenLinkItem, m_contextMenu.get());
+ appendItem(OpenLinkInNewWindowItem, m_contextMenu.get());
+ appendItem(DownloadFileItem, m_contextMenu.get());
+ }
+ appendItem(CopyLinkItem, m_contextMenu.get());
+ }
+
+ KURL imageURL = m_hitTestResult.absoluteImageURL();
+ if (!imageURL.isEmpty()) {
+ if (!linkURL.isEmpty())
+ appendItem(*separatorItem(), m_contextMenu.get());
+
+ appendItem(OpenImageInNewWindowItem, m_contextMenu.get());
+ appendItem(DownloadImageItem, m_contextMenu.get());
+ if (imageURL.isLocalFile() || m_hitTestResult.image())
+ appendItem(CopyImageItem, m_contextMenu.get());
+ }
+
+ KURL mediaURL = m_hitTestResult.absoluteMediaURL();
+ if (!mediaURL.isEmpty()) {
+ if (!linkURL.isEmpty() || !imageURL.isEmpty())
+ appendItem(*separatorItem(), m_contextMenu.get());
+
+ appendItem(MediaPlayPause, m_contextMenu.get());
+ appendItem(MediaMute, m_contextMenu.get());
+ appendItem(ToggleMediaControls, m_contextMenu.get());
+ appendItem(ToggleMediaLoop, m_contextMenu.get());
+ appendItem(EnterVideoFullscreen, m_contextMenu.get());
+
+ appendItem(*separatorItem(), m_contextMenu.get());
+ appendItem(CopyMediaLinkItem, m_contextMenu.get());
+ appendItem(OpenMediaInNewWindowItem, m_contextMenu.get());
+ }
+
+ if (imageURL.isEmpty() && linkURL.isEmpty() && mediaURL.isEmpty()) {
+ if (m_hitTestResult.isSelected()) {
+ if (selectionContainsPossibleWord(frame)) {
+#if PLATFORM(MAC)
+ appendItem(SearchSpotlightItem, m_contextMenu.get());
+#endif
+#if !PLATFORM(GTK)
+ appendItem(SearchWebItem, m_contextMenu.get());
+ appendItem(*separatorItem(), m_contextMenu.get());
+#endif
+#if PLATFORM(MAC)
+ appendItem(LookInDictionaryItem, m_contextMenu.get());
+ appendItem(*separatorItem(), m_contextMenu.get());
+#endif
+ }
+ appendItem(CopyItem, m_contextMenu.get());
+#if PLATFORM(MAC)
+ appendItem(*separatorItem(), m_contextMenu.get());
+ ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu());
+ createAndAppendSpeechSubMenu(SpeechMenuItem);
+ appendItem(SpeechMenuItem, m_contextMenu.get());
+#endif
+ } else {
+#if ENABLE(INSPECTOR)
+ if (!(frame->page() && frame->page()->inspectorController()->hasInspectorFrontendClient())) {
+#endif
+ if (frame->page() && frame->page()->backForward()->canGoBackOrForward(-1))
+ appendItem(BackItem, m_contextMenu.get());
+
+ if (frame->page() && frame->page()->backForward()->canGoBackOrForward(1))
+ appendItem(ForwardItem, m_contextMenu.get());
+
+ // use isLoadingInAPISense rather than isLoading because Stop/Reload are
+ // intended to match WebKit's API, not WebCore's internal notion of loading status
+ if (loader->documentLoader()->isLoadingInAPISense())
+ appendItem(StopItem, m_contextMenu.get());
+ else
+ appendItem(ReloadItem, m_contextMenu.get());
+#if ENABLE(INSPECTOR)
+ }
+#endif
+
+ if (frame->page() && frame != frame->page()->mainFrame())
+ appendItem(OpenFrameItem, m_contextMenu.get());
+ }
+ }
+ } else { // Make an editing context menu
+ SelectionController* selection = frame->selection();
+ bool inPasswordField = selection->isInPasswordField();
+ bool spellCheckingEnabled = frame->editor()->isSpellCheckingEnabledFor(node);
+
+ if (!inPasswordField && spellCheckingEnabled) {
+ // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range
+ // is never considered a misspelling and bad grammar at the same time)
+ bool misspelling;
+ bool badGrammar;
+ Vector<String> guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar);
+ if (misspelling || badGrammar) {
+ size_t size = guesses.size();
+ if (size == 0) {
+ // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions
+ // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit)
+ if (misspelling) {
+ appendItem(NoGuessesItem, m_contextMenu.get());
+ appendItem(*separatorItem(), m_contextMenu.get());
+ }
+ } else {
+ for (unsigned i = 0; i < size; i++) {
+ const String &guess = guesses[i];
+ if (!guess.isEmpty()) {
+ ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess);
+ appendItem(item, m_contextMenu.get());
+ }
+ }
+ appendItem(*separatorItem(), m_contextMenu.get());
+ }
+
+ if (misspelling) {
+ appendItem(IgnoreSpellingItem, m_contextMenu.get());
+ appendItem(LearnSpellingItem, m_contextMenu.get());
+ } else
+ appendItem(IgnoreGrammarItem, m_contextMenu.get());
+ appendItem(*separatorItem(), m_contextMenu.get());
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ } else {
+ // If the string was autocorrected, generate a contextual menu item allowing it to be changed back.
+ String replacedString = m_hitTestResult.replacedString();
+ if (!replacedString.isEmpty()) {
+ ContextMenuItem item(ActionType, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString));
+ appendItem(item, m_contextMenu.get());
+ appendItem(*separatorItem(), m_contextMenu.get());
+ }
+#endif
+ }
+ }
+
+ FrameLoader* loader = frame->loader();
+ KURL linkURL = m_hitTestResult.absoluteLinkURL();
+ if (!linkURL.isEmpty()) {
+ if (loader->canHandleRequest(ResourceRequest(linkURL))) {
+ appendItem(OpenLinkItem, m_contextMenu.get());
+ appendItem(OpenLinkInNewWindowItem, m_contextMenu.get());
+ appendItem(DownloadFileItem, m_contextMenu.get());
+ }
+ appendItem(CopyLinkItem, m_contextMenu.get());
+ appendItem(*separatorItem(), m_contextMenu.get());
+ }
+
+ if (m_hitTestResult.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) {
+#if PLATFORM(MAC)
+ appendItem(SearchSpotlightItem, m_contextMenu.get());
+#endif
+#if !PLATFORM(GTK)
+ appendItem(SearchWebItem, m_contextMenu.get());
+ appendItem(*separatorItem(), m_contextMenu.get());
+#endif
+
+#if PLATFORM(MAC)
+ appendItem(LookInDictionaryItem, m_contextMenu.get());
+ appendItem(*separatorItem(), m_contextMenu.get());
+#endif
+ }
+
+ appendItem(CutItem, m_contextMenu.get());
+ appendItem(CopyItem, m_contextMenu.get());
+ appendItem(PasteItem, m_contextMenu.get());
+#if PLATFORM(GTK)
+ appendItem(DeleteItem, m_contextMenu.get());
+ appendItem(*separatorItem(), m_contextMenu.get());
+#endif
+#if PLATFORM(GTK) || PLATFORM(QT)
+ appendItem(SelectAllItem, m_contextMenu.get());
+#endif
+
+ if (!inPasswordField) {
+ appendItem(*separatorItem(), m_contextMenu.get());
+#ifndef BUILDING_ON_TIGER
+#if !PLATFORM(GTK)
+ ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu,
+ contextMenuItemTagSpellingMenu());
+ createAndAppendSpellingAndGrammarSubMenu(SpellingAndGrammarMenuItem);
+ appendItem(SpellingAndGrammarMenuItem, m_contextMenu.get());
+#endif
+#else
+ ContextMenuItem SpellingMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu,
+ contextMenuItemTagSpellingMenu());
+ createAndAppendSpellingSubMenu(SpellingMenuItem);
+ appendItem(SpellingMenuItem, m_contextMenu.get());
+#endif
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ ContextMenuItem substitutionsMenuItem(SubmenuType, ContextMenuItemTagSubstitutionsMenu,
+ contextMenuItemTagSubstitutionsMenu());
+ createAndAppendSubstitutionsSubMenu(substitutionsMenuItem);
+ appendItem(substitutionsMenuItem, m_contextMenu.get());
+ ContextMenuItem transformationsMenuItem(SubmenuType, ContextMenuItemTagTransformationsMenu,
+ contextMenuItemTagTransformationsMenu());
+ createAndAppendTransformationsSubMenu(transformationsMenuItem);
+ appendItem(transformationsMenuItem, m_contextMenu.get());
+#endif
+#if PLATFORM(GTK)
+ bool shouldShowFontMenu = frame->editor()->canEditRichly();
+#else
+ bool shouldShowFontMenu = true;
+#endif
+ if (shouldShowFontMenu) {
+ ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu,
+ contextMenuItemTagFontMenu());
+ createAndAppendFontSubMenu(FontMenuItem);
+ appendItem(FontMenuItem, m_contextMenu.get());
+ }
+#if PLATFORM(MAC)
+ ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu());
+ createAndAppendSpeechSubMenu(SpeechMenuItem);
+ appendItem(SpeechMenuItem, m_contextMenu.get());
+#endif
+#if !PLATFORM(GTK)
+ ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu,
+ contextMenuItemTagWritingDirectionMenu());
+ createAndAppendWritingDirectionSubMenu(WritingDirectionMenuItem);
+ appendItem(WritingDirectionMenuItem, m_contextMenu.get());
+ if (Page* page = frame->page()) {
+ if (Settings* settings = page->settings()) {
+ bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded
+ || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection());
+ if (includeTextDirectionSubmenu) {
+ ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu,
+ contextMenuItemTagTextDirectionMenu());
+ createAndAppendTextDirectionSubMenu(TextDirectionMenuItem);
+ appendItem(TextDirectionMenuItem, m_contextMenu.get());
+ }
+ }
+ }
+#endif
+ }
+ }
+}
+
+#if ENABLE(INSPECTOR)
+void ContextMenuController::addInspectElementItem()
+{
+ Node* node = m_hitTestResult.innerNonSharedNode();
+ if (!node)
+ return;
+
+ Frame* frame = node->document()->frame();
+ if (!frame)
+ return;
+
+ Page* page = frame->page();
+ if (!page)
+ return;
+
+ if (!page->inspectorController())
+ return;
+
+ ContextMenuItem InspectElementItem(ActionType, ContextMenuItemTagInspectElement, contextMenuItemTagInspectElement());
+ appendItem(*separatorItem(), m_contextMenu.get());
+ appendItem(InspectElementItem, m_contextMenu.get());
+}
+#endif // ENABLE(INSPECTOR)
+
+void ContextMenuController::checkOrEnableIfNeeded(ContextMenuItem& item) const
+{
+ if (item.type() == SeparatorType)
+ return;
+
+ Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame();
+ if (!frame)
+ return;
+
+ // Custom items already have proper checked and enabled values.
+ if (ContextMenuItemBaseCustomTag <= item.action() && item.action() <= ContextMenuItemLastCustomTag)
+ return;
+
+ bool shouldEnable = true;
+ bool shouldCheck = false;
+
+ switch (item.action()) {
+ case ContextMenuItemTagCheckSpelling:
+ shouldEnable = frame->editor()->canEdit();
+ break;
+ case ContextMenuItemTagDefaultDirection:
+ shouldCheck = false;
+ shouldEnable = false;
+ break;
+ case ContextMenuItemTagLeftToRight:
+ case ContextMenuItemTagRightToLeft: {
+ ExceptionCode ec = 0;
+ RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
+ String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl";
+ style->setProperty(CSSPropertyDirection, direction, false, ec);
+ shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
+ shouldEnable = true;
+ break;
+ }
+ case ContextMenuItemTagTextDirectionDefault: {
+ Editor::Command command = frame->editor()->command("MakeTextWritingDirectionNatural");
+ shouldCheck = command.state() == TrueTriState;
+ shouldEnable = command.isEnabled();
+ break;
+ }
+ case ContextMenuItemTagTextDirectionLeftToRight: {
+ Editor::Command command = frame->editor()->command("MakeTextWritingDirectionLeftToRight");
+ shouldCheck = command.state() == TrueTriState;
+ shouldEnable = command.isEnabled();
+ break;
+ }
+ case ContextMenuItemTagTextDirectionRightToLeft: {
+ Editor::Command command = frame->editor()->command("MakeTextWritingDirectionRightToLeft");
+ shouldCheck = command.state() == TrueTriState;
+ shouldEnable = command.isEnabled();
+ break;
+ }
+ case ContextMenuItemTagCopy:
+ shouldEnable = frame->editor()->canDHTMLCopy() || frame->editor()->canCopy();
+ break;
+ case ContextMenuItemTagCut:
+ shouldEnable = frame->editor()->canDHTMLCut() || frame->editor()->canCut();
+ break;
+ case ContextMenuItemTagIgnoreSpelling:
+ case ContextMenuItemTagLearnSpelling:
+ shouldEnable = frame->selection()->isRange();
+ break;
+ case ContextMenuItemTagPaste:
+ shouldEnable = frame->editor()->canDHTMLPaste() || frame->editor()->canPaste();
+ break;
+#if PLATFORM(GTK)
+ case ContextMenuItemTagDelete:
+ shouldEnable = frame->editor()->canDelete();
+ break;
+ case ContextMenuItemTagSelectAll:
+ case ContextMenuItemTagInputMethods:
+ case ContextMenuItemTagUnicode:
+ shouldEnable = true;
+ break;
+#endif
+ case ContextMenuItemTagUnderline: {
+ ExceptionCode ec = 0;
+ RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
+ style->setProperty(CSSPropertyWebkitTextDecorationsInEffect, "underline", false, ec);
+ shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
+ shouldEnable = frame->editor()->canEditRichly();
+ break;
+ }
+ case ContextMenuItemTagLookUpInDictionary:
+ shouldEnable = frame->selection()->isRange();
+ break;
+ case ContextMenuItemTagCheckGrammarWithSpelling:
+#ifndef BUILDING_ON_TIGER
+ if (frame->editor()->isGrammarCheckingEnabled())
+ shouldCheck = true;
+ shouldEnable = true;
+#endif
+ break;
+ case ContextMenuItemTagItalic: {
+ ExceptionCode ec = 0;
+ RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
+ style->setProperty(CSSPropertyFontStyle, "italic", false, ec);
+ shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
+ shouldEnable = frame->editor()->canEditRichly();
+ break;
+ }
+ case ContextMenuItemTagBold: {
+ ExceptionCode ec = 0;
+ RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
+ style->setProperty(CSSPropertyFontWeight, "bold", false, ec);
+ shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
+ shouldEnable = frame->editor()->canEditRichly();
+ break;
+ }
+ case ContextMenuItemTagOutline:
+ shouldEnable = false;
+ break;
+ case ContextMenuItemTagShowSpellingPanel:
+#ifndef BUILDING_ON_TIGER
+ if (frame->editor()->spellingPanelIsShowing())
+ item.setTitle(contextMenuItemTagShowSpellingPanel(false));
+ else
+ item.setTitle(contextMenuItemTagShowSpellingPanel(true));
+#endif
+ shouldEnable = frame->editor()->canEdit();
+ break;
+ case ContextMenuItemTagNoGuessesFound:
+ shouldEnable = false;
+ break;
+ case ContextMenuItemTagCheckSpellingWhileTyping:
+ shouldCheck = frame->editor()->isContinuousSpellCheckingEnabled();
+ break;
+#if PLATFORM(MAC)
+ case ContextMenuItemTagSubstitutionsMenu:
+ case ContextMenuItemTagTransformationsMenu:
+ break;
+ case ContextMenuItemTagShowSubstitutions:
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ if (frame->editor()->substitutionsPanelIsShowing())
+ item.setTitle(contextMenuItemTagShowSubstitutions(false));
+ else
+ item.setTitle(contextMenuItemTagShowSubstitutions(true));
+ shouldEnable = frame->editor()->canEdit();
+#endif
+ break;
+ case ContextMenuItemTagMakeUpperCase:
+ case ContextMenuItemTagMakeLowerCase:
+ case ContextMenuItemTagCapitalize:
+ case ContextMenuItemTagChangeBack:
+ shouldEnable = frame->editor()->canEdit();
+ break;
+ case ContextMenuItemTagCorrectSpellingAutomatically:
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ shouldCheck = frame->editor()->isAutomaticSpellingCorrectionEnabled();
+#endif
+ break;
+ case ContextMenuItemTagSmartCopyPaste:
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ shouldCheck = frame->editor()->smartInsertDeleteEnabled();
+#endif
+ break;
+ case ContextMenuItemTagSmartQuotes:
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ shouldCheck = frame->editor()->isAutomaticQuoteSubstitutionEnabled();
+#endif
+ break;
+ case ContextMenuItemTagSmartDashes:
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ shouldCheck = frame->editor()->isAutomaticDashSubstitutionEnabled();
+#endif
+ break;
+ case ContextMenuItemTagSmartLinks:
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ shouldCheck = frame->editor()->isAutomaticLinkDetectionEnabled();
+#endif
+ break;
+ case ContextMenuItemTagTextReplacement:
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ shouldCheck = frame->editor()->isAutomaticTextReplacementEnabled();
+#endif
+ break;
+ case ContextMenuItemTagStopSpeaking:
+ shouldEnable = client() && client()->isSpeaking();
+ break;
+#else // PLATFORM(MAC) ends here
+ case ContextMenuItemTagStopSpeaking:
+ break;
+#endif
+#if PLATFORM(GTK)
+ case ContextMenuItemTagGoBack:
+ shouldEnable = frame->page() && frame->page()->backForward()->canGoBackOrForward(-1);
+ break;
+ case ContextMenuItemTagGoForward:
+ shouldEnable = frame->page() && frame->page()->backForward()->canGoBackOrForward(1);
+ break;
+ case ContextMenuItemTagStop:
+ shouldEnable = frame->loader()->documentLoader()->isLoadingInAPISense();
+ break;
+ case ContextMenuItemTagReload:
+ shouldEnable = !frame->loader()->documentLoader()->isLoadingInAPISense();
+ break;
+ case ContextMenuItemTagFontMenu:
+ shouldEnable = frame->editor()->canEditRichly();
+ break;
+#else
+ case ContextMenuItemTagGoBack:
+ case ContextMenuItemTagGoForward:
+ case ContextMenuItemTagStop:
+ case ContextMenuItemTagReload:
+ case ContextMenuItemTagFontMenu:
+#endif
+ case ContextMenuItemTagNoAction:
+ case ContextMenuItemTagOpenLinkInNewWindow:
+ case ContextMenuItemTagDownloadLinkToDisk:
+ case ContextMenuItemTagCopyLinkToClipboard:
+ case ContextMenuItemTagOpenImageInNewWindow:
+ case ContextMenuItemTagDownloadImageToDisk:
+ case ContextMenuItemTagCopyImageToClipboard:
+ break;
+ case ContextMenuItemTagOpenMediaInNewWindow:
+ if (m_hitTestResult.mediaIsVideo())
+ item.setTitle(contextMenuItemTagOpenVideoInNewWindow());
+ else
+ item.setTitle(contextMenuItemTagOpenAudioInNewWindow());
+ break;
+ case ContextMenuItemTagCopyMediaLinkToClipboard:
+ if (m_hitTestResult.mediaIsVideo())
+ item.setTitle(contextMenuItemTagCopyVideoLinkToClipboard());
+ else
+ item.setTitle(contextMenuItemTagCopyAudioLinkToClipboard());
+ break;
+ case ContextMenuItemTagToggleMediaControls:
+ shouldCheck = m_hitTestResult.mediaControlsEnabled();
+ break;
+ case ContextMenuItemTagToggleMediaLoop:
+ shouldCheck = m_hitTestResult.mediaLoopEnabled();
+ break;
+ case ContextMenuItemTagEnterVideoFullscreen:
+ shouldEnable = m_hitTestResult.mediaSupportsFullscreen();
+ break;
+ case ContextMenuItemTagOpenFrameInNewWindow:
+ case ContextMenuItemTagSpellingGuess:
+ case ContextMenuItemTagOther:
+ case ContextMenuItemTagSearchInSpotlight:
+ case ContextMenuItemTagSearchWeb:
+ case ContextMenuItemTagOpenWithDefaultApplication:
+ case ContextMenuItemPDFActualSize:
+ case ContextMenuItemPDFZoomIn:
+ case ContextMenuItemPDFZoomOut:
+ case ContextMenuItemPDFAutoSize:
+ case ContextMenuItemPDFSinglePage:
+ case ContextMenuItemPDFFacingPages:
+ case ContextMenuItemPDFContinuous:
+ case ContextMenuItemPDFNextPage:
+ case ContextMenuItemPDFPreviousPage:
+ case ContextMenuItemTagOpenLink:
+ case ContextMenuItemTagIgnoreGrammar:
+ case ContextMenuItemTagSpellingMenu:
+ case ContextMenuItemTagShowFonts:
+ case ContextMenuItemTagStyles:
+ case ContextMenuItemTagShowColors:
+ case ContextMenuItemTagSpeechMenu:
+ case ContextMenuItemTagStartSpeaking:
+ case ContextMenuItemTagWritingDirectionMenu:
+ case ContextMenuItemTagTextDirectionMenu:
+ case ContextMenuItemTagPDFSinglePageScrolling:
+ case ContextMenuItemTagPDFFacingPagesScrolling:
+#if ENABLE(INSPECTOR)
+ case ContextMenuItemTagInspectElement:
+#endif
+ case ContextMenuItemBaseCustomTag:
+ case ContextMenuItemCustomTagNoAction:
+ case ContextMenuItemLastCustomTag:
+ case ContextMenuItemBaseApplicationTag:
+ break;
+ case ContextMenuItemTagMediaPlayPause:
+ if (m_hitTestResult.mediaPlaying())
+ item.setTitle(contextMenuItemTagMediaPause());
+ else
+ item.setTitle(contextMenuItemTagMediaPlay());
+ break;
+ case ContextMenuItemTagMediaMute:
+ shouldEnable = m_hitTestResult.mediaHasAudio();
+ shouldCheck = shouldEnable && m_hitTestResult.mediaMuted();
+ break;
+ }
+
+ item.setChecked(shouldCheck);
+ item.setEnabled(shouldEnable);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(CONTEXT_MENUS)
diff --git a/Source/WebCore/page/ContextMenuController.h b/Source/WebCore/page/ContextMenuController.h
new file mode 100644
index 0000000..ab92796
--- /dev/null
+++ b/Source/WebCore/page/ContextMenuController.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ContextMenuController_h
+#define ContextMenuController_h
+
+#include "HitTestResult.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ class ContextMenu;
+ class ContextMenuClient;
+ class ContextMenuItem;
+ class ContextMenuProvider;
+ class Event;
+ class Page;
+
+ class ContextMenuController : public Noncopyable {
+ public:
+ ContextMenuController(Page*, ContextMenuClient*);
+ ~ContextMenuController();
+
+ ContextMenuClient* client() const { return m_client; }
+
+ ContextMenu* contextMenu() const { return m_contextMenu.get(); }
+ void clearContextMenu();
+
+ void handleContextMenuEvent(Event*);
+ void showContextMenu(Event*, PassRefPtr<ContextMenuProvider>);
+
+ void populate();
+ void contextMenuItemSelected(ContextMenuItem*);
+ void addInspectElementItem();
+
+ void checkOrEnableIfNeeded(ContextMenuItem&) const;
+
+ void setHitTestResult(const HitTestResult& result) { m_hitTestResult = result; }
+ const HitTestResult& hitTestResult() { return m_hitTestResult; }
+
+ private:
+ PassOwnPtr<ContextMenu> createContextMenu(Event*);
+ void showContextMenu(Event*);
+
+ void appendItem(ContextMenuItem&, ContextMenu* parentMenu);
+
+ void createAndAppendFontSubMenu(ContextMenuItem&);
+ void createAndAppendSpellingAndGrammarSubMenu(ContextMenuItem&);
+ void createAndAppendSpellingSubMenu(ContextMenuItem&);
+ void createAndAppendSpeechSubMenu(ContextMenuItem& );
+ void createAndAppendWritingDirectionSubMenu(ContextMenuItem&);
+ void createAndAppendTextDirectionSubMenu(ContextMenuItem&);
+ void createAndAppendSubstitutionsSubMenu(ContextMenuItem&);
+ void createAndAppendTransformationsSubMenu(ContextMenuItem&);
+
+ Page* m_page;
+ ContextMenuClient* m_client;
+ OwnPtr<ContextMenu> m_contextMenu;
+ RefPtr<ContextMenuProvider> m_menuProvider;
+ HitTestResult m_hitTestResult;
+ };
+
+}
+
+#endif
diff --git a/Source/WebCore/page/ContextMenuProvider.h b/Source/WebCore/page/ContextMenuProvider.h
new file mode 100644
index 0000000..57598d1
--- /dev/null
+++ b/Source/WebCore/page/ContextMenuProvider.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ContextMenuProvider_h
+#define ContextMenuProvider_h
+
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class ContextMenu;
+class ContextMenuItem;
+
+class ContextMenuProvider : public RefCounted<ContextMenuProvider> {
+public:
+ virtual ~ContextMenuProvider() { };
+
+ virtual void populateContextMenu(ContextMenu*) = 0;
+ virtual void contextMenuItemSelected(ContextMenuItem*) = 0;
+ virtual void contextMenuCleared() = 0;
+};
+
+}
+
+#endif // ContextMenuProvider_h
diff --git a/Source/WebCore/page/Coordinates.h b/Source/WebCore/page/Coordinates.h
new file mode 100644
index 0000000..6365548
--- /dev/null
+++ b/Source/WebCore/page/Coordinates.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Coordinates_h
+#define Coordinates_h
+
+#include "Event.h"
+#include "PlatformString.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class Coordinates : public RefCounted<Coordinates> {
+public:
+ static PassRefPtr<Coordinates> create(double latitude, double longitude, bool providesAltitude, double altitude, double accuracy, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed) { return adoptRef(new Coordinates(latitude, longitude, providesAltitude, altitude, accuracy, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed)); }
+
+ PassRefPtr<Coordinates> threadSafeCopy() const
+ {
+ return Coordinates::create(m_latitude, m_longitude, m_canProvideAltitude, m_altitude, m_accuracy, m_canProvideAltitudeAccuracy, m_altitudeAccuracy, m_canProvideHeading, m_heading, m_canProvideSpeed, m_speed);
+ }
+
+ double latitude() const { return m_latitude; }
+ double longitude() const { return m_longitude; }
+ double altitude() const { return m_altitude; }
+ double accuracy() const { return m_accuracy; }
+ double altitudeAccuracy() const { return m_altitudeAccuracy; }
+ double heading() const { return m_heading; }
+ double speed() const { return m_speed; }
+
+ bool canProvideAltitude() const { return m_canProvideAltitude; }
+ bool canProvideAltitudeAccuracy() const { return m_canProvideAltitudeAccuracy; }
+ bool canProvideHeading() const { return m_canProvideHeading; }
+ bool canProvideSpeed() const { return m_canProvideSpeed; }
+
+private:
+ Coordinates(double latitude, double longitude, bool providesAltitude, double altitude, double accuracy, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed)
+ : m_latitude(latitude)
+ , m_longitude(longitude)
+ , m_altitude(altitude)
+ , m_accuracy(accuracy)
+ , m_altitudeAccuracy(altitudeAccuracy)
+ , m_heading(heading)
+ , m_speed(speed)
+ , m_canProvideAltitude(providesAltitude)
+ , m_canProvideAltitudeAccuracy(providesAltitudeAccuracy)
+ , m_canProvideHeading(providesHeading)
+ , m_canProvideSpeed(providesSpeed)
+ {
+ }
+
+ double m_latitude;
+ double m_longitude;
+ double m_altitude;
+ double m_accuracy;
+ double m_altitudeAccuracy;
+ double m_heading;
+ double m_speed;
+
+ bool m_canProvideAltitude;
+ bool m_canProvideAltitudeAccuracy;
+ bool m_canProvideHeading;
+ bool m_canProvideSpeed;
+};
+
+} // namespace WebCore
+
+#endif // Coordinates_h
diff --git a/Source/WebCore/page/Coordinates.idl b/Source/WebCore/page/Coordinates.idl
new file mode 100644
index 0000000..5a5a141
--- /dev/null
+++ b/Source/WebCore/page/Coordinates.idl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module core {
+
+ interface [OmitConstructor] Coordinates {
+ readonly attribute double latitude;
+ readonly attribute double longitude;
+ readonly attribute [Custom] double altitude;
+ readonly attribute double accuracy;
+ readonly attribute [Custom] double altitudeAccuracy;
+ readonly attribute [Custom] double heading;
+ readonly attribute [Custom] double speed;
+ };
+}
diff --git a/Source/WebCore/page/DOMSelection.cpp b/Source/WebCore/page/DOMSelection.cpp
new file mode 100644
index 0000000..7691da4
--- /dev/null
+++ b/Source/WebCore/page/DOMSelection.cpp
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DOMSelection.h"
+
+#include "ExceptionCode.h"
+#include "Frame.h"
+#include "Node.h"
+#include "PlatformString.h"
+#include "Range.h"
+#include "SelectionController.h"
+#include "TextIterator.h"
+#include "htmlediting.h"
+
+namespace WebCore {
+
+static Node* selectionShadowAncestor(Frame* frame)
+{
+ Node* node = frame->selection()->selection().base().anchorNode();
+ if (!node)
+ return 0;
+ Node* shadowAncestor = node->shadowAncestorNode();
+ if (shadowAncestor == node)
+ return 0;
+ return shadowAncestor;
+}
+
+DOMSelection::DOMSelection(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+Frame* DOMSelection::frame() const
+{
+ return m_frame;
+}
+
+void DOMSelection::disconnectFrame()
+{
+ m_frame = 0;
+}
+
+const VisibleSelection& DOMSelection::visibleSelection() const
+{
+ ASSERT(m_frame);
+ return m_frame->selection()->selection();
+}
+
+static Position anchorPosition(const VisibleSelection& selection)
+{
+ Position anchor = selection.isBaseFirst() ? selection.start() : selection.end();
+ return rangeCompliantEquivalent(anchor);
+}
+
+static Position focusPosition(const VisibleSelection& selection)
+{
+ Position focus = selection.isBaseFirst() ? selection.end() : selection.start();
+ return rangeCompliantEquivalent(focus);
+}
+
+static Position basePosition(const VisibleSelection& selection)
+{
+ return rangeCompliantEquivalent(selection.base());
+}
+
+static Position extentPosition(const VisibleSelection& selection)
+{
+ return rangeCompliantEquivalent(selection.extent());
+}
+
+Node* DOMSelection::anchorNode() const
+{
+ if (!m_frame)
+ return 0;
+ if (Node* shadowAncestor = selectionShadowAncestor(m_frame))
+ return shadowAncestor->parentNodeGuaranteedHostFree();
+ return anchorPosition(visibleSelection()).node();
+}
+
+int DOMSelection::anchorOffset() const
+{
+ if (!m_frame)
+ return 0;
+ if (Node* shadowAncestor = selectionShadowAncestor(m_frame))
+ return shadowAncestor->nodeIndex();
+ return anchorPosition(visibleSelection()).deprecatedEditingOffset();
+}
+
+Node* DOMSelection::focusNode() const
+{
+ if (!m_frame)
+ return 0;
+ if (Node* shadowAncestor = selectionShadowAncestor(m_frame))
+ return shadowAncestor->parentNodeGuaranteedHostFree();
+ return focusPosition(visibleSelection()).node();
+}
+
+int DOMSelection::focusOffset() const
+{
+ if (!m_frame)
+ return 0;
+ if (Node* shadowAncestor = selectionShadowAncestor(m_frame))
+ return shadowAncestor->nodeIndex();
+ return focusPosition(visibleSelection()).deprecatedEditingOffset();
+}
+
+Node* DOMSelection::baseNode() const
+{
+ if (!m_frame)
+ return 0;
+ if (Node* shadowAncestor = selectionShadowAncestor(m_frame))
+ return shadowAncestor->parentNodeGuaranteedHostFree();
+ return basePosition(visibleSelection()).node();
+}
+
+int DOMSelection::baseOffset() const
+{
+ if (!m_frame)
+ return 0;
+ if (Node* shadowAncestor = selectionShadowAncestor(m_frame))
+ return shadowAncestor->nodeIndex();
+ return basePosition(visibleSelection()).deprecatedEditingOffset();
+}
+
+Node* DOMSelection::extentNode() const
+{
+ if (!m_frame)
+ return 0;
+ if (Node* shadowAncestor = selectionShadowAncestor(m_frame))
+ return shadowAncestor->parentNodeGuaranteedHostFree();
+ return extentPosition(visibleSelection()).node();
+}
+
+int DOMSelection::extentOffset() const
+{
+ if (!m_frame)
+ return 0;
+ if (Node* shadowAncestor = selectionShadowAncestor(m_frame))
+ return shadowAncestor->nodeIndex();
+ return extentPosition(visibleSelection()).deprecatedEditingOffset();
+}
+
+bool DOMSelection::isCollapsed() const
+{
+ if (!m_frame || selectionShadowAncestor(m_frame))
+ return true;
+ return !m_frame->selection()->isRange();
+}
+
+String DOMSelection::type() const
+{
+ if (!m_frame)
+ return String();
+
+ SelectionController* selection = m_frame->selection();
+
+ // This is a WebKit DOM extension, incompatible with an IE extension
+ // IE has this same attribute, but returns "none", "text" and "control"
+ // http://msdn.microsoft.com/en-us/library/ms534692(VS.85).aspx
+ if (selection->isNone())
+ return "None";
+ if (selection->isCaret())
+ return "Caret";
+ return "Range";
+}
+
+int DOMSelection::rangeCount() const
+{
+ if (!m_frame)
+ return 0;
+ return m_frame->selection()->isNone() ? 0 : 1;
+}
+
+void DOMSelection::collapse(Node* node, int offset, ExceptionCode& ec)
+{
+ if (!m_frame)
+ return;
+
+ if (offset < 0) {
+ ec = INDEX_SIZE_ERR;
+ return;
+ }
+
+ if (!isValidForPosition(node))
+ return;
+
+ m_frame->selection()->moveTo(VisiblePosition(node, offset, DOWNSTREAM));
+}
+
+void DOMSelection::collapseToEnd(ExceptionCode& ec)
+{
+ if (!m_frame)
+ return;
+
+ const VisibleSelection& selection = m_frame->selection()->selection();
+
+ if (selection.isNone()) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ m_frame->selection()->moveTo(VisiblePosition(selection.end(), DOWNSTREAM));
+}
+
+void DOMSelection::collapseToStart(ExceptionCode& ec)
+{
+ if (!m_frame)
+ return;
+
+ const VisibleSelection& selection = m_frame->selection()->selection();
+
+ if (selection.isNone()) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ m_frame->selection()->moveTo(VisiblePosition(selection.start(), DOWNSTREAM));
+}
+
+void DOMSelection::empty()
+{
+ if (!m_frame)
+ return;
+ m_frame->selection()->clear();
+}
+
+void DOMSelection::setBaseAndExtent(Node* baseNode, int baseOffset, Node* extentNode, int extentOffset, ExceptionCode& ec)
+{
+ if (!m_frame)
+ return;
+
+ if (baseOffset < 0 || extentOffset < 0) {
+ ec = INDEX_SIZE_ERR;
+ return;
+ }
+
+ if (!isValidForPosition(baseNode) || !isValidForPosition(extentNode))
+ return;
+
+ VisiblePosition visibleBase = VisiblePosition(baseNode, baseOffset, DOWNSTREAM);
+ VisiblePosition visibleExtent = VisiblePosition(extentNode, extentOffset, DOWNSTREAM);
+
+ m_frame->selection()->moveTo(visibleBase, visibleExtent);
+}
+
+void DOMSelection::setPosition(Node* node, int offset, ExceptionCode& ec)
+{
+ if (!m_frame)
+ return;
+ if (offset < 0) {
+ ec = INDEX_SIZE_ERR;
+ return;
+ }
+
+ if (!isValidForPosition(node))
+ return;
+
+ m_frame->selection()->moveTo(VisiblePosition(node, offset, DOWNSTREAM));
+}
+
+void DOMSelection::modify(const String& alterString, const String& directionString, const String& granularityString)
+{
+ if (!m_frame)
+ return;
+
+ SelectionController::EAlteration alter;
+ if (equalIgnoringCase(alterString, "extend"))
+ alter = SelectionController::AlterationExtend;
+ else if (equalIgnoringCase(alterString, "move"))
+ alter = SelectionController::AlterationMove;
+ else
+ return;
+
+ SelectionDirection direction;
+ if (equalIgnoringCase(directionString, "forward"))
+ direction = DirectionForward;
+ else if (equalIgnoringCase(directionString, "backward"))
+ direction = DirectionBackward;
+ else if (equalIgnoringCase(directionString, "left"))
+ direction = DirectionLeft;
+ else if (equalIgnoringCase(directionString, "right"))
+ direction = DirectionRight;
+ else
+ return;
+
+ TextGranularity granularity;
+ if (equalIgnoringCase(granularityString, "character"))
+ granularity = CharacterGranularity;
+ else if (equalIgnoringCase(granularityString, "word"))
+ granularity = WordGranularity;
+ else if (equalIgnoringCase(granularityString, "sentence"))
+ granularity = SentenceGranularity;
+ else if (equalIgnoringCase(granularityString, "line"))
+ granularity = LineGranularity;
+ else if (equalIgnoringCase(granularityString, "paragraph"))
+ granularity = ParagraphGranularity;
+ else if (equalIgnoringCase(granularityString, "lineboundary"))
+ granularity = LineBoundary;
+ else if (equalIgnoringCase(granularityString, "sentenceboundary"))
+ granularity = SentenceBoundary;
+ else if (equalIgnoringCase(granularityString, "paragraphboundary"))
+ granularity = ParagraphBoundary;
+ else if (equalIgnoringCase(granularityString, "documentboundary"))
+ granularity = DocumentBoundary;
+ else
+ return;
+
+ m_frame->selection()->modify(alter, direction, granularity, false);
+}
+
+void DOMSelection::extend(Node* node, int offset, ExceptionCode& ec)
+{
+ if (!m_frame)
+ return;
+
+ if (!node) {
+ ec = TYPE_MISMATCH_ERR;
+ return;
+ }
+
+ if (offset < 0 || offset > (node->offsetInCharacters() ? caretMaxOffset(node) : (int)node->childNodeCount())) {
+ ec = INDEX_SIZE_ERR;
+ return;
+ }
+
+ if (!isValidForPosition(node))
+ return;
+
+ m_frame->selection()->setExtent(VisiblePosition(node, offset, DOWNSTREAM));
+}
+
+PassRefPtr<Range> DOMSelection::getRangeAt(int index, ExceptionCode& ec)
+{
+ if (!m_frame)
+ return 0;
+
+ if (index < 0 || index >= rangeCount()) {
+ ec = INDEX_SIZE_ERR;
+ return 0;
+ }
+
+ // If you're hitting this, you've added broken multi-range selection support
+ ASSERT(rangeCount() == 1);
+
+ if (Node* shadowAncestor = selectionShadowAncestor(m_frame)) {
+ ContainerNode* container = shadowAncestor->parentNodeGuaranteedHostFree();
+ int offset = shadowAncestor->nodeIndex();
+ return Range::create(shadowAncestor->document(), container, offset, container, offset);
+ }
+
+ const VisibleSelection& selection = m_frame->selection()->selection();
+ return selection.firstRange();
+}
+
+void DOMSelection::removeAllRanges()
+{
+ if (!m_frame)
+ return;
+ m_frame->selection()->clear();
+}
+
+void DOMSelection::addRange(Range* r)
+{
+ if (!m_frame)
+ return;
+ if (!r)
+ return;
+
+ SelectionController* selection = m_frame->selection();
+
+ if (selection->isNone()) {
+ selection->setSelection(VisibleSelection(r));
+ return;
+ }
+
+ RefPtr<Range> range = selection->selection().toNormalizedRange();
+ ExceptionCode ec = 0;
+ if (r->compareBoundaryPoints(Range::START_TO_START, range.get(), ec) == -1) {
+ // We don't support discontiguous selection. We don't do anything if r and range don't intersect.
+ if (r->compareBoundaryPoints(Range::START_TO_END, range.get(), ec) > -1) {
+ if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), ec) == -1)
+ // The original range and r intersect.
+ selection->setSelection(VisibleSelection(r->startPosition(), range->endPosition(), DOWNSTREAM));
+ else
+ // r contains the original range.
+ selection->setSelection(VisibleSelection(r));
+ }
+ } else {
+ // We don't support discontiguous selection. We don't do anything if r and range don't intersect.
+ if (r->compareBoundaryPoints(Range::END_TO_START, range.get(), ec) < 1) {
+ if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), ec) == -1)
+ // The original range contains r.
+ selection->setSelection(VisibleSelection(range.get()));
+ else
+ // The original range and r intersect.
+ selection->setSelection(VisibleSelection(range->startPosition(), r->endPosition(), DOWNSTREAM));
+ }
+ }
+}
+
+void DOMSelection::deleteFromDocument()
+{
+ if (!m_frame)
+ return;
+
+ SelectionController* selection = m_frame->selection();
+
+ if (selection->isNone())
+ return;
+
+ if (isCollapsed())
+ selection->modify(SelectionController::AlterationExtend, DirectionBackward, CharacterGranularity);
+
+ RefPtr<Range> selectedRange = selection->selection().toNormalizedRange();
+ if (!selectedRange)
+ return;
+
+ ExceptionCode ec = 0;
+ selectedRange->deleteContents(ec);
+ ASSERT(!ec);
+
+ setBaseAndExtent(selectedRange->startContainer(ec), selectedRange->startOffset(ec), selectedRange->startContainer(ec), selectedRange->startOffset(ec), ec);
+ ASSERT(!ec);
+}
+
+bool DOMSelection::containsNode(const Node* n, bool allowPartial) const
+{
+ if (!m_frame)
+ return false;
+
+ SelectionController* selection = m_frame->selection();
+
+ if (!n || m_frame->document() != n->document() || selection->isNone())
+ return false;
+
+ ContainerNode* parentNode = n->parentNode();
+ unsigned nodeIndex = n->nodeIndex();
+ RefPtr<Range> selectedRange = selection->selection().toNormalizedRange();
+
+ if (!parentNode)
+ return false;
+
+ ExceptionCode ec = 0;
+ bool nodeFullySelected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->startContainer(ec), selectedRange->startOffset(ec)) >= 0
+ && Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->endContainer(ec), selectedRange->endOffset(ec)) <= 0;
+ ASSERT(!ec);
+ if (nodeFullySelected)
+ return true;
+
+ bool nodeFullyUnselected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->endContainer(ec), selectedRange->endOffset(ec)) > 0
+ || Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->startContainer(ec), selectedRange->startOffset(ec)) < 0;
+ ASSERT(!ec);
+ if (nodeFullyUnselected)
+ return false;
+
+ return allowPartial || n->isTextNode();
+}
+
+void DOMSelection::selectAllChildren(Node* n, ExceptionCode& ec)
+{
+ if (!n)
+ return;
+
+ // This doesn't (and shouldn't) select text node characters.
+ setBaseAndExtent(n, 0, n, n->childNodeCount(), ec);
+}
+
+String DOMSelection::toString()
+{
+ if (!m_frame)
+ return String();
+
+ return plainText(m_frame->selection()->selection().toNormalizedRange().get());
+}
+
+bool DOMSelection::isValidForPosition(Node* node) const
+{
+ ASSERT(m_frame);
+ if (!node)
+ return true;
+ return node->document() == m_frame->document();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/DOMSelection.h b/Source/WebCore/page/DOMSelection.h
new file mode 100644
index 0000000..b5fd197
--- /dev/null
+++ b/Source/WebCore/page/DOMSelection.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 DOMSelection_h
+#define DOMSelection_h
+
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class Frame;
+ class Range;
+ class Node;
+ class VisibleSelection;
+
+ typedef int ExceptionCode;
+
+ class DOMSelection : public RefCounted<DOMSelection> {
+ public:
+ static PassRefPtr<DOMSelection> create(Frame* frame) { return adoptRef(new DOMSelection(frame)); }
+
+ Frame* frame() const;
+ void disconnectFrame();
+
+ // Safari Selection Object API
+ // These methods return the valid equivalents of internal editing positions.
+ Node* baseNode() const;
+ Node* extentNode() const;
+ int baseOffset() const;
+ int extentOffset() const;
+ String type() const;
+ void setBaseAndExtent(Node* baseNode, int baseOffset, Node* extentNode, int extentOffset, ExceptionCode&);
+ void setPosition(Node*, int offset, ExceptionCode&);
+ void modify(const String& alter, const String& direction, const String& granularity);
+
+ // Mozilla Selection Object API
+ // In Firefox, anchor/focus are the equal to the start/end of the selection,
+ // but reflect the direction in which the selection was made by the user. That does
+ // not mean that they are base/extent, since the base/extent don't reflect
+ // expansion.
+ // These methods return the valid equivalents of internal editing positions.
+ Node* anchorNode() const;
+ int anchorOffset() const;
+ Node* focusNode() const;
+ int focusOffset() const;
+ bool isCollapsed() const;
+ int rangeCount() const;
+ void collapse(Node*, int offset, ExceptionCode&);
+ void collapseToEnd(ExceptionCode&);
+ void collapseToStart(ExceptionCode&);
+ void extend(Node*, int offset, ExceptionCode&);
+ PassRefPtr<Range> getRangeAt(int, ExceptionCode&);
+ void removeAllRanges();
+ void addRange(Range*);
+ void deleteFromDocument();
+ bool containsNode(const Node*, bool partlyContained) const;
+ void selectAllChildren(Node*, ExceptionCode&);
+
+ String toString();
+
+ // Microsoft Selection Object API
+ void empty();
+
+ private:
+ DOMSelection(Frame*);
+
+ // Convenience method for accessors, does not NULL check m_frame.
+ const VisibleSelection& visibleSelection() const;
+
+ bool isValidForPosition(Node*) const;
+ Frame* m_frame;
+ };
+
+} // namespace WebCore
+
+#endif // DOMSelection_h
diff --git a/Source/WebCore/page/DOMSelection.idl b/Source/WebCore/page/DOMSelection.idl
new file mode 100644
index 0000000..ee82823
--- /dev/null
+++ b/Source/WebCore/page/DOMSelection.idl
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module window {
+
+ // This is based off of Mozilla's Selection interface
+ // https://developer.mozilla.org/En/DOM/Selection
+ interface [OmitConstructor] DOMSelection {
+ readonly attribute Node anchorNode;
+ readonly attribute long anchorOffset;
+ readonly attribute Node focusNode;
+ readonly attribute long focusOffset;
+
+ readonly attribute boolean isCollapsed;
+ readonly attribute long rangeCount;
+
+ void collapse(in Node node, in long index)
+ raises(DOMException);
+ void collapseToEnd()
+ raises(DOMException);
+ void collapseToStart()
+ raises(DOMException);
+
+ void deleteFromDocument();
+ boolean containsNode(in Node node, in boolean allowPartial);
+ void selectAllChildren(in Node node)
+ raises(DOMException);
+
+ void extend(in Node node, in long offset)
+ raises(DOMException);
+
+ Range getRangeAt(in long index)
+ raises(DOMException);
+ void removeAllRanges();
+ void addRange(in Range range);
+
+#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
+ [DontEnum] DOMString toString();
+#endif
+
+ // WebKit extensions
+ readonly attribute Node baseNode;
+ readonly attribute long baseOffset;
+ readonly attribute Node extentNode;
+ readonly attribute long extentOffset;
+
+ // WebKit's "type" accessor returns "None", "Range" and "Caret"
+ // IE's type accessor returns "none", "text" and "control"
+ readonly attribute DOMString type;
+
+ void modify(in DOMString alter, in DOMString direction, in DOMString granularity);
+ void setBaseAndExtent(in Node baseNode, in long baseOffset, in Node extentNode, in long extentOffset)
+ raises(DOMException);
+ void setPosition(in Node node, in long offset)
+ raises(DOMException);
+
+ // IE extentions
+ // http://msdn.microsoft.com/en-us/library/ms535869(VS.85).aspx
+ void empty();
+ };
+
+}
diff --git a/Source/WebCore/page/DOMTimer.cpp b/Source/WebCore/page/DOMTimer.cpp
new file mode 100644
index 0000000..57e6512
--- /dev/null
+++ b/Source/WebCore/page/DOMTimer.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "DOMTimer.h"
+
+#include "InspectorInstrumentation.h"
+#include "ScheduledAction.h"
+#include "ScriptExecutionContext.h"
+#include <wtf/HashSet.h>
+#include <wtf/StdLibExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+static const int maxTimerNestingLevel = 5;
+static const double oneMillisecond = 0.001;
+double DOMTimer::s_minTimerInterval = 0.010; // 10 milliseconds
+
+static int timerNestingLevel = 0;
+
+DOMTimer::DOMTimer(ScriptExecutionContext* context, PassOwnPtr<ScheduledAction> action, int timeout, bool singleShot)
+ : SuspendableTimer(context)
+ , m_action(action)
+{
+ static int lastUsedTimeoutId = 0;
+ ++lastUsedTimeoutId;
+ // Avoid wraparound going negative on us.
+ if (lastUsedTimeoutId <= 0)
+ lastUsedTimeoutId = 1;
+ m_timeoutId = lastUsedTimeoutId;
+
+ m_nestingLevel = timerNestingLevel + 1;
+
+ scriptExecutionContext()->addTimeout(m_timeoutId, this);
+
+ double intervalMilliseconds = max(oneMillisecond, timeout * oneMillisecond);
+
+ if (intervalMilliseconds < s_minTimerInterval && m_nestingLevel >= maxTimerNestingLevel)
+ intervalMilliseconds = s_minTimerInterval;
+ if (singleShot)
+ startOneShot(intervalMilliseconds);
+ else
+ startRepeating(intervalMilliseconds);
+}
+
+DOMTimer::~DOMTimer()
+{
+ if (scriptExecutionContext())
+ scriptExecutionContext()->removeTimeout(m_timeoutId);
+}
+
+int DOMTimer::install(ScriptExecutionContext* context, PassOwnPtr<ScheduledAction> action, int timeout, bool singleShot)
+{
+ // DOMTimer constructor links the new timer into a list of ActiveDOMObjects held by the 'context'.
+ // The timer is deleted when context is deleted (DOMTimer::contextDestroyed) or explicitly via DOMTimer::removeById(),
+ // or if it is a one-time timer and it has fired (DOMTimer::fired).
+ DOMTimer* timer = new DOMTimer(context, action, timeout, singleShot);
+
+ InspectorInstrumentation::didInstallTimer(context, timer->m_timeoutId, timeout, singleShot);
+
+ return timer->m_timeoutId;
+}
+
+void DOMTimer::removeById(ScriptExecutionContext* context, int timeoutId)
+{
+ // timeout IDs have to be positive, and 0 and -1 are unsafe to
+ // even look up since they are the empty and deleted value
+ // respectively
+ if (timeoutId <= 0)
+ return;
+
+ InspectorInstrumentation::didRemoveTimer(context, timeoutId);
+
+ delete context->findTimeout(timeoutId);
+}
+
+void DOMTimer::fired()
+{
+ ScriptExecutionContext* context = scriptExecutionContext();
+ timerNestingLevel = m_nestingLevel;
+
+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willFireTimer(context, m_timeoutId);
+
+ // Simple case for non-one-shot timers.
+ if (isActive()) {
+ if (repeatInterval() && repeatInterval() < s_minTimerInterval) {
+ m_nestingLevel++;
+ if (m_nestingLevel >= maxTimerNestingLevel)
+ augmentRepeatInterval(s_minTimerInterval - repeatInterval());
+ }
+
+ // No access to member variables after this point, it can delete the timer.
+ m_action->execute(context);
+
+ InspectorInstrumentation::didFireTimer(cookie);
+
+ return;
+ }
+
+ // Delete timer before executing the action for one-shot timers.
+ OwnPtr<ScheduledAction> action = m_action.release();
+
+ // No access to member variables after this point.
+ delete this;
+
+ action->execute(context);
+
+ InspectorInstrumentation::didFireTimer(cookie);
+
+ timerNestingLevel = 0;
+}
+
+void DOMTimer::contextDestroyed()
+{
+ SuspendableTimer::contextDestroyed();
+ delete this;
+}
+
+void DOMTimer::stop()
+{
+ SuspendableTimer::stop();
+ // Need to release JS objects potentially protected by ScheduledAction
+ // because they can form circular references back to the ScriptExecutionContext
+ // which will cause a memory leak.
+ m_action.clear();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/DOMTimer.h b/Source/WebCore/page/DOMTimer.h
new file mode 100644
index 0000000..4fc6aae
--- /dev/null
+++ b/Source/WebCore/page/DOMTimer.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef DOMTimer_h
+#define DOMTimer_h
+
+#include "ScheduledAction.h"
+#include "SuspendableTimer.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+ class DOMTimer : public SuspendableTimer {
+ public:
+ virtual ~DOMTimer();
+ // Creates a new timer owned by specified ScriptExecutionContext, starts it
+ // and returns its Id.
+ static int install(ScriptExecutionContext*, PassOwnPtr<ScheduledAction>, int timeout, bool singleShot);
+ static void removeById(ScriptExecutionContext*, int timeoutId);
+
+ // ActiveDOMObject
+ virtual void contextDestroyed();
+ virtual void stop();
+
+ // The lowest allowable timer setting (in seconds, 0.001 == 1 ms).
+ static double minTimerInterval() { return s_minTimerInterval; }
+ static void setMinTimerInterval(double value) { s_minTimerInterval = value; }
+
+ private:
+ DOMTimer(ScriptExecutionContext*, PassOwnPtr<ScheduledAction>, int timeout, bool singleShot);
+ virtual void fired();
+
+ int m_timeoutId;
+ int m_nestingLevel;
+ OwnPtr<ScheduledAction> m_action;
+ static double s_minTimerInterval;
+ };
+
+} // namespace WebCore
+
+#endif // DOMTimer_h
+
diff --git a/Source/WebCore/page/DOMWindow.cpp b/Source/WebCore/page/DOMWindow.cpp
new file mode 100644
index 0000000..c2e8c39
--- /dev/null
+++ b/Source/WebCore/page/DOMWindow.cpp
@@ -0,0 +1,1861 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2010 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DOMWindow.h"
+
+#include "AbstractDatabase.h"
+#include "BackForwardController.h"
+#include "BarInfo.h"
+#include "Base64.h"
+#include "BeforeUnloadEvent.h"
+#include "CSSComputedStyleDeclaration.h"
+#include "CSSRuleList.h"
+#include "CSSStyleSelector.h"
+#include "Chrome.h"
+#include "Console.h"
+#include "DOMApplicationCache.h"
+#include "DOMSelection.h"
+#include "DOMSettableTokenList.h"
+#include "DOMStringList.h"
+#include "DOMTimer.h"
+#include "DOMTokenList.h"
+#include "Database.h"
+#include "DatabaseCallback.h"
+#include "DeviceMotionController.h"
+#include "DeviceOrientationController.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Element.h"
+#include "EventException.h"
+#include "EventListener.h"
+#include "EventNames.h"
+#include "ExceptionCode.h"
+#include "FloatRect.h"
+#include "Frame.h"
+#include "FrameLoadRequest.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "HTMLFrameOwnerElement.h"
+#include "History.h"
+#include "IDBFactory.h"
+#include "IDBFactoryBackendInterface.h"
+#include "InspectorController.h"
+#include "InspectorInstrumentation.h"
+#include "KURL.h"
+#include "Location.h"
+#include "MediaQueryList.h"
+#include "MediaQueryMatcher.h"
+#include "MessageEvent.h"
+#include "Navigator.h"
+#include "NotificationCenter.h"
+#include "Page.h"
+#include "PageGroup.h"
+#include "PageTransitionEvent.h"
+#include "Performance.h"
+#include "PlatformScreen.h"
+#include "PlatformString.h"
+#include "Screen.h"
+#include "SecurityOrigin.h"
+#include "SerializedScriptValue.h"
+#include "Settings.h"
+#include "Storage.h"
+#include "StorageArea.h"
+#include "StorageNamespace.h"
+#include "StyleMedia.h"
+#include "SuddenTermination.h"
+#include "WebKitPoint.h"
+#include "WindowFeatures.h"
+#include <algorithm>
+#include <wtf/CurrentTime.h>
+#include <wtf/MathExtras.h>
+#include <wtf/text/StringConcatenate.h>
+
+#if ENABLE(FILE_SYSTEM)
+#include "AsyncFileSystem.h"
+#include "DOMFileSystem.h"
+#include "ErrorCallback.h"
+#include "FileError.h"
+#include "FileSystemCallback.h"
+#include "FileSystemCallbacks.h"
+#include "LocalFileSystem.h"
+#endif
+
+using std::min;
+using std::max;
+
+namespace WebCore {
+
+class PostMessageTimer : public TimerBase {
+public:
+ PostMessageTimer(DOMWindow* window, PassRefPtr<SerializedScriptValue> message, const String& sourceOrigin, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortChannelArray> channels, SecurityOrigin* targetOrigin)
+ : m_window(window)
+ , m_message(message)
+ , m_origin(sourceOrigin)
+ , m_source(source)
+ , m_channels(channels)
+ , m_targetOrigin(targetOrigin)
+ {
+ }
+
+ PassRefPtr<MessageEvent> event(ScriptExecutionContext* context)
+ {
+ OwnPtr<MessagePortArray> messagePorts = MessagePort::entanglePorts(*context, m_channels.release());
+ return MessageEvent::create(messagePorts.release(), m_message, m_origin, "", m_source);
+ }
+ SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); }
+
+private:
+ virtual void fired()
+ {
+ m_window->postMessageTimerFired(this);
+ }
+
+ RefPtr<DOMWindow> m_window;
+ RefPtr<SerializedScriptValue> m_message;
+ String m_origin;
+ RefPtr<DOMWindow> m_source;
+ OwnPtr<MessagePortChannelArray> m_channels;
+ RefPtr<SecurityOrigin> m_targetOrigin;
+};
+
+typedef HashCountedSet<DOMWindow*> DOMWindowSet;
+
+static DOMWindowSet& windowsWithUnloadEventListeners()
+{
+ DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithUnloadEventListeners, ());
+ return windowsWithUnloadEventListeners;
+}
+
+static DOMWindowSet& windowsWithBeforeUnloadEventListeners()
+{
+ DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithBeforeUnloadEventListeners, ());
+ return windowsWithBeforeUnloadEventListeners;
+}
+
+static void addUnloadEventListener(DOMWindow* domWindow)
+{
+ DOMWindowSet& set = windowsWithUnloadEventListeners();
+ if (set.isEmpty())
+ disableSuddenTermination();
+ set.add(domWindow);
+}
+
+static void removeUnloadEventListener(DOMWindow* domWindow)
+{
+ DOMWindowSet& set = windowsWithUnloadEventListeners();
+ DOMWindowSet::iterator it = set.find(domWindow);
+ if (it == set.end())
+ return;
+ set.remove(it);
+ if (set.isEmpty())
+ enableSuddenTermination();
+}
+
+static void removeAllUnloadEventListeners(DOMWindow* domWindow)
+{
+ DOMWindowSet& set = windowsWithUnloadEventListeners();
+ DOMWindowSet::iterator it = set.find(domWindow);
+ if (it == set.end())
+ return;
+ set.removeAll(it);
+ if (set.isEmpty())
+ enableSuddenTermination();
+}
+
+static void addBeforeUnloadEventListener(DOMWindow* domWindow)
+{
+ DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
+ if (set.isEmpty())
+ disableSuddenTermination();
+ set.add(domWindow);
+}
+
+static void removeBeforeUnloadEventListener(DOMWindow* domWindow)
+{
+ DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
+ DOMWindowSet::iterator it = set.find(domWindow);
+ if (it == set.end())
+ return;
+ set.remove(it);
+ if (set.isEmpty())
+ enableSuddenTermination();
+}
+
+static void removeAllBeforeUnloadEventListeners(DOMWindow* domWindow)
+{
+ DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
+ DOMWindowSet::iterator it = set.find(domWindow);
+ if (it == set.end())
+ return;
+ set.removeAll(it);
+ if (set.isEmpty())
+ enableSuddenTermination();
+}
+
+static bool allowsBeforeUnloadListeners(DOMWindow* window)
+{
+ ASSERT_ARG(window, window);
+ Frame* frame = window->frame();
+ if (!frame)
+ return false;
+ Page* page = frame->page();
+ if (!page)
+ return false;
+ return frame == page->mainFrame();
+}
+
+bool DOMWindow::dispatchAllPendingBeforeUnloadEvents()
+{
+ DOMWindowSet& set = windowsWithBeforeUnloadEventListeners();
+ if (set.isEmpty())
+ return true;
+
+ static bool alreadyDispatched = false;
+ ASSERT(!alreadyDispatched);
+ if (alreadyDispatched)
+ return true;
+
+ Vector<RefPtr<DOMWindow> > windows;
+ DOMWindowSet::iterator end = set.end();
+ for (DOMWindowSet::iterator it = set.begin(); it != end; ++it)
+ windows.append(it->first);
+
+ size_t size = windows.size();
+ for (size_t i = 0; i < size; ++i) {
+ DOMWindow* window = windows[i].get();
+ if (!set.contains(window))
+ continue;
+
+ Frame* frame = window->frame();
+ if (!frame)
+ continue;
+
+ if (!frame->loader()->shouldClose())
+ return false;
+ }
+
+ enableSuddenTermination();
+
+ alreadyDispatched = true;
+
+ return true;
+}
+
+unsigned DOMWindow::pendingUnloadEventListeners() const
+{
+ return windowsWithUnloadEventListeners().count(const_cast<DOMWindow*>(this));
+}
+
+void DOMWindow::dispatchAllPendingUnloadEvents()
+{
+ DOMWindowSet& set = windowsWithUnloadEventListeners();
+ if (set.isEmpty())
+ return;
+
+ static bool alreadyDispatched = false;
+ ASSERT(!alreadyDispatched);
+ if (alreadyDispatched)
+ return;
+
+ Vector<RefPtr<DOMWindow> > windows;
+ DOMWindowSet::iterator end = set.end();
+ for (DOMWindowSet::iterator it = set.begin(); it != end; ++it)
+ windows.append(it->first);
+
+ size_t size = windows.size();
+ for (size_t i = 0; i < size; ++i) {
+ DOMWindow* window = windows[i].get();
+ if (!set.contains(window))
+ continue;
+
+ window->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, false), window->document());
+ window->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), window->document());
+ }
+
+ enableSuddenTermination();
+
+ alreadyDispatched = true;
+}
+
+// This function:
+// 1) Validates the pending changes are not changing to NaN
+// 2) Constrains the window rect to no smaller than 100 in each dimension and no
+// bigger than the the float rect's dimensions.
+// 3) Constrain window rect to within the top and left boundaries of the screen rect
+// 4) Constraint the window rect to within the bottom and right boundaries of the
+// screen rect.
+// 5) Translate the window rect coordinates to be within the coordinate space of
+// the screen rect.
+void DOMWindow::adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges)
+{
+ // Make sure we're in a valid state before adjusting dimensions.
+ ASSERT(isfinite(screen.x()));
+ ASSERT(isfinite(screen.y()));
+ ASSERT(isfinite(screen.width()));
+ ASSERT(isfinite(screen.height()));
+ ASSERT(isfinite(window.x()));
+ ASSERT(isfinite(window.y()));
+ ASSERT(isfinite(window.width()));
+ ASSERT(isfinite(window.height()));
+
+ // Update window values if new requested values are not NaN.
+ if (!isnan(pendingChanges.x()))
+ window.setX(pendingChanges.x());
+ if (!isnan(pendingChanges.y()))
+ window.setY(pendingChanges.y());
+ if (!isnan(pendingChanges.width()))
+ window.setWidth(pendingChanges.width());
+ if (!isnan(pendingChanges.height()))
+ window.setHeight(pendingChanges.height());
+
+ // Resize the window to between 100 and the screen width and height.
+ window.setWidth(min(max(100.0f, window.width()), screen.width()));
+ window.setHeight(min(max(100.0f, window.height()), screen.height()));
+
+ // Constrain the window position to the screen.
+ window.setX(max(screen.x(), min(window.x(), screen.right() - window.width())));
+ window.setY(max(screen.y(), min(window.y(), screen.bottom() - window.height())));
+}
+
+// FIXME: We can remove this function once V8 showModalDialog is changed to use DOMWindow.
+void DOMWindow::parseModalDialogFeatures(const String& string, HashMap<String, String>& map)
+{
+ WindowFeatures::parseDialogFeatures(string, map);
+}
+
+bool DOMWindow::allowPopUp(Frame* firstFrame)
+{
+ ASSERT(firstFrame);
+
+ if (ScriptController::processingUserGesture())
+ return true;
+
+ Settings* settings = firstFrame->settings();
+ return settings && settings->javaScriptCanOpenWindowsAutomatically();
+}
+
+bool DOMWindow::allowPopUp()
+{
+ return m_frame && allowPopUp(m_frame);
+}
+
+bool DOMWindow::canShowModalDialog(const Frame* frame)
+{
+ if (!frame)
+ return false;
+ Page* page = frame->page();
+ if (!page)
+ return false;
+ return page->chrome()->canRunModal();
+}
+
+bool DOMWindow::canShowModalDialogNow(const Frame* frame)
+{
+ if (!frame)
+ return false;
+ Page* page = frame->page();
+ if (!page)
+ return false;
+ return page->chrome()->canRunModalNow();
+}
+
+DOMWindow::DOMWindow(Frame* frame)
+ : m_shouldPrintWhenFinishedLoading(false)
+ , m_frame(frame)
+{
+}
+
+DOMWindow::~DOMWindow()
+{
+ if (m_frame)
+ m_frame->clearFormerDOMWindow(this);
+
+ removeAllUnloadEventListeners(this);
+ removeAllBeforeUnloadEventListeners(this);
+}
+
+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;
+ clear();
+}
+
+void DOMWindow::clear()
+{
+ if (m_screen)
+ m_screen->disconnectFrame();
+ m_screen = 0;
+
+ if (m_selection)
+ m_selection->disconnectFrame();
+ m_selection = 0;
+
+ if (m_history)
+ m_history->disconnectFrame();
+ m_history = 0;
+
+ if (m_locationbar)
+ m_locationbar->disconnectFrame();
+ m_locationbar = 0;
+
+ if (m_menubar)
+ m_menubar->disconnectFrame();
+ m_menubar = 0;
+
+ if (m_personalbar)
+ m_personalbar->disconnectFrame();
+ m_personalbar = 0;
+
+ if (m_scrollbars)
+ m_scrollbars->disconnectFrame();
+ m_scrollbars = 0;
+
+ if (m_statusbar)
+ m_statusbar->disconnectFrame();
+ m_statusbar = 0;
+
+ if (m_toolbar)
+ m_toolbar->disconnectFrame();
+ m_toolbar = 0;
+
+ if (m_console)
+ m_console->disconnectFrame();
+ m_console = 0;
+
+ if (m_navigator)
+ m_navigator->disconnectFrame();
+ m_navigator = 0;
+
+#if ENABLE(WEB_TIMING)
+ if (m_performance)
+ m_performance->disconnectFrame();
+ m_performance = 0;
+#endif
+
+ if (m_location)
+ m_location->disconnectFrame();
+ m_location = 0;
+
+ if (m_media)
+ m_media->disconnectFrame();
+ m_media = 0;
+
+#if ENABLE(DOM_STORAGE)
+ if (m_sessionStorage)
+ m_sessionStorage->disconnectFrame();
+ m_sessionStorage = 0;
+
+ if (m_localStorage)
+ m_localStorage->disconnectFrame();
+ m_localStorage = 0;
+#endif
+
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ if (m_applicationCache)
+ m_applicationCache->disconnectFrame();
+ m_applicationCache = 0;
+#endif
+
+#if ENABLE(NOTIFICATIONS)
+ if (m_notifications)
+ m_notifications->disconnectFrame();
+ m_notifications = 0;
+#endif
+
+#if ENABLE(INDEXED_DATABASE)
+ m_idbFactory = 0;
+#endif
+}
+
+#if ENABLE(ORIENTATION_EVENTS)
+int DOMWindow::orientation() const
+{
+ if (!m_frame)
+ return 0;
+
+ return m_frame->orientation();
+}
+#endif
+
+Screen* DOMWindow::screen() const
+{
+ if (!m_screen)
+ m_screen = Screen::create(m_frame);
+ return m_screen.get();
+}
+
+History* DOMWindow::history() const
+{
+ if (!m_history)
+ m_history = History::create(m_frame);
+ return m_history.get();
+}
+
+BarInfo* DOMWindow::locationbar() const
+{
+ if (!m_locationbar)
+ m_locationbar = BarInfo::create(m_frame, BarInfo::Locationbar);
+ return m_locationbar.get();
+}
+
+BarInfo* DOMWindow::menubar() const
+{
+ if (!m_menubar)
+ m_menubar = BarInfo::create(m_frame, BarInfo::Menubar);
+ return m_menubar.get();
+}
+
+BarInfo* DOMWindow::personalbar() const
+{
+ if (!m_personalbar)
+ m_personalbar = BarInfo::create(m_frame, BarInfo::Personalbar);
+ return m_personalbar.get();
+}
+
+BarInfo* DOMWindow::scrollbars() const
+{
+ if (!m_scrollbars)
+ m_scrollbars = BarInfo::create(m_frame, BarInfo::Scrollbars);
+ return m_scrollbars.get();
+}
+
+BarInfo* DOMWindow::statusbar() const
+{
+ if (!m_statusbar)
+ m_statusbar = BarInfo::create(m_frame, BarInfo::Statusbar);
+ return m_statusbar.get();
+}
+
+BarInfo* DOMWindow::toolbar() const
+{
+ if (!m_toolbar)
+ m_toolbar = BarInfo::create(m_frame, BarInfo::Toolbar);
+ return m_toolbar.get();
+}
+
+Console* DOMWindow::console() const
+{
+ if (!m_console)
+ m_console = Console::create(m_frame);
+ return m_console.get();
+}
+
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+DOMApplicationCache* DOMWindow::applicationCache() const
+{
+ if (!m_applicationCache)
+ m_applicationCache = DOMApplicationCache::create(m_frame);
+ return m_applicationCache.get();
+}
+#endif
+
+Navigator* DOMWindow::navigator() const
+{
+ if (!m_navigator)
+ m_navigator = Navigator::create(m_frame);
+ return m_navigator.get();
+}
+
+#if ENABLE(WEB_TIMING)
+Performance* DOMWindow::performance() const
+{
+ if (!m_performance)
+ m_performance = Performance::create(m_frame);
+ return m_performance.get();
+}
+#endif
+
+Location* DOMWindow::location() const
+{
+ if (!m_location)
+ m_location = Location::create(m_frame);
+ return m_location.get();
+}
+
+#if ENABLE(DOM_STORAGE)
+Storage* DOMWindow::sessionStorage(ExceptionCode& ec) const
+{
+ if (m_sessionStorage)
+ return m_sessionStorage.get();
+
+ Document* document = this->document();
+ if (!document)
+ return 0;
+
+ if (!document->securityOrigin()->canAccessLocalStorage()) {
+ ec = SECURITY_ERR;
+ return 0;
+ }
+
+ Page* page = document->page();
+ if (!page)
+ return 0;
+
+ RefPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin());
+#if ENABLE(INSPECTOR)
+ page->inspectorController()->didUseDOMStorage(storageArea.get(), false, m_frame);
+#endif
+
+ m_sessionStorage = Storage::create(m_frame, storageArea.release());
+ return m_sessionStorage.get();
+}
+
+Storage* DOMWindow::localStorage(ExceptionCode& ec) const
+{
+ if (m_localStorage)
+ return m_localStorage.get();
+
+ Document* document = this->document();
+ if (!document)
+ return 0;
+
+ if (!document->securityOrigin()->canAccessLocalStorage()) {
+ ec = SECURITY_ERR;
+ return 0;
+ }
+
+ Page* page = document->page();
+ if (!page)
+ return 0;
+
+ if (!page->settings()->localStorageEnabled())
+ return 0;
+
+ RefPtr<StorageArea> storageArea = page->group().localStorage()->storageArea(document->securityOrigin());
+#if ENABLE(INSPECTOR)
+ page->inspectorController()->didUseDOMStorage(storageArea.get(), true, m_frame);
+#endif
+
+ m_localStorage = Storage::create(m_frame, storageArea.release());
+ return m_localStorage.get();
+}
+#endif
+
+#if ENABLE(NOTIFICATIONS)
+NotificationCenter* DOMWindow::webkitNotifications() const
+{
+ if (m_notifications)
+ return m_notifications.get();
+
+ Document* document = this->document();
+ if (!document)
+ return 0;
+
+ Page* page = document->page();
+ if (!page)
+ return 0;
+
+ NotificationPresenter* provider = page->chrome()->notificationPresenter();
+ if (provider)
+ m_notifications = NotificationCenter::create(document, provider);
+
+ return m_notifications.get();
+}
+#endif
+
+void DOMWindow::pageDestroyed()
+{
+#if ENABLE(NOTIFICATIONS)
+ // Clearing Notifications requests involves accessing the client so it must be done
+ // before the frame is detached.
+ if (m_notifications)
+ m_notifications->disconnectFrame();
+ m_notifications = 0;
+#endif
+}
+
+#if ENABLE(INDEXED_DATABASE)
+IDBFactory* DOMWindow::webkitIndexedDB() const
+{
+ if (m_idbFactory)
+ return m_idbFactory.get();
+
+ Document* document = this->document();
+ if (!document)
+ return 0;
+
+ // FIXME: See if access is allowed.
+
+ Page* page = document->page();
+ if (!page)
+ return 0;
+
+ // FIXME: See if indexedDatabase access is allowed.
+
+ m_idbFactory = IDBFactory::create(page->group().idbFactory());
+ return m_idbFactory.get();
+}
+#endif
+
+#if ENABLE(FILE_SYSTEM)
+void DOMWindow::requestFileSystem(int type, long long size, PassRefPtr<FileSystemCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback)
+{
+ Document* document = this->document();
+ if (!document)
+ return;
+
+ if (!AsyncFileSystem::isAvailable() || !document->securityOrigin()->canAccessFileSystem()) {
+ DOMFileSystem::scheduleCallback(document, errorCallback, FileError::create(FileError::SECURITY_ERR));
+ return;
+ }
+
+ AsyncFileSystem::Type fileSystemType = static_cast<AsyncFileSystem::Type>(type);
+ if (fileSystemType != AsyncFileSystem::Temporary && fileSystemType != AsyncFileSystem::Persistent) {
+ DOMFileSystem::scheduleCallback(document, errorCallback, FileError::create(FileError::INVALID_MODIFICATION_ERR));
+ return;
+ }
+
+ LocalFileSystem::localFileSystem().requestFileSystem(document, fileSystemType, size, FileSystemCallbacks::create(successCallback, errorCallback, document), false);
+}
+
+COMPILE_ASSERT(static_cast<int>(DOMWindow::TEMPORARY) == static_cast<int>(AsyncFileSystem::Temporary), enum_mismatch);
+COMPILE_ASSERT(static_cast<int>(DOMWindow::PERSISTENT) == static_cast<int>(AsyncFileSystem::Persistent), enum_mismatch);
+
+#endif
+
+void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort* port, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec)
+{
+ MessagePortArray ports;
+ if (port)
+ ports.append(port);
+ postMessage(message, &ports, targetOrigin, source, ec);
+}
+
+void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec)
+{
+ if (!m_frame)
+ return;
+
+ // Compute the target origin. We need to do this synchronously in order
+ // to generate the SYNTAX_ERR exception correctly.
+ RefPtr<SecurityOrigin> target;
+ if (targetOrigin != "*") {
+ target = SecurityOrigin::createFromString(targetOrigin);
+ if (target->isEmpty()) {
+ ec = SYNTAX_ERR;
+ return;
+ }
+ }
+
+ OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, ec);
+ if (ec)
+ return;
+
+ // Capture the source of the message. We need to do this synchronously
+ // in order to capture the source of the message correctly.
+ Document* sourceDocument = source->document();
+ if (!sourceDocument)
+ return;
+ String sourceOrigin = sourceDocument->securityOrigin()->toString();
+
+ // Schedule the message.
+ PostMessageTimer* timer = new PostMessageTimer(this, message, sourceOrigin, source, channels.release(), target.get());
+ timer->startOneShot(0);
+}
+
+void DOMWindow::postMessageTimerFired(PostMessageTimer* t)
+{
+ OwnPtr<PostMessageTimer> timer(t);
+
+ if (!document())
+ return;
+
+ if (timer->targetOrigin()) {
+ // Check target origin now since the target document may have changed since the simer was scheduled.
+ if (!timer->targetOrigin()->isSameSchemeHostPort(document()->securityOrigin())) {
+ String message = makeString("Unable to post message to ", timer->targetOrigin()->toString(),
+ ". Recipient has origin ", document()->securityOrigin()->toString(), ".\n");
+ console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 0, String());
+ return;
+ }
+ }
+
+ dispatchEvent(timer->event(document()));
+}
+
+DOMSelection* DOMWindow::getSelection()
+{
+ if (!m_selection)
+ m_selection = DOMSelection::create(m_frame);
+ return m_selection.get();
+}
+
+Element* DOMWindow::frameElement() const
+{
+ if (!m_frame)
+ return 0;
+
+ return m_frame->ownerElement();
+}
+
+void DOMWindow::focus()
+{
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ // If we're a top level window, bring the window to the front.
+ if (m_frame == page->mainFrame())
+ page->chrome()->focus();
+
+ if (!m_frame)
+ return;
+
+ m_frame->eventHandler()->focusDocumentView();
+}
+
+void DOMWindow::blur()
+{
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ if (m_frame != page->mainFrame())
+ return;
+
+ page->chrome()->unfocus();
+}
+
+void DOMWindow::close(ScriptExecutionContext* context)
+{
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ if (m_frame != page->mainFrame())
+ return;
+
+ if (context) {
+ ASSERT(WTF::isMainThread());
+ Frame* activeFrame = static_cast<Document*>(context)->frame();
+ if (!activeFrame)
+ return;
+
+ if (!activeFrame->loader()->shouldAllowNavigation(m_frame))
+ return;
+ }
+
+ Settings* settings = m_frame->settings();
+ bool allowScriptsToCloseWindows = settings && settings->allowScriptsToCloseWindows();
+
+ if (!(page->openedByDOM() || page->backForward()->count() <= 1 || allowScriptsToCloseWindows))
+ return;
+
+ if (!m_frame->loader()->shouldClose())
+ return;
+
+ page->chrome()->closeWindowSoon();
+}
+
+void DOMWindow::print()
+{
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ if (m_frame->loader()->activeDocumentLoader()->isLoading()) {
+ m_shouldPrintWhenFinishedLoading = true;
+ return;
+ }
+ m_shouldPrintWhenFinishedLoading = false;
+ page->chrome()->print(m_frame);
+}
+
+void DOMWindow::stop()
+{
+ if (!m_frame)
+ return;
+
+ // We must check whether the load is complete asynchronously, because we might still be parsing
+ // the document until the callstack unwinds.
+ m_frame->loader()->stopForUserCancel(true);
+}
+
+void DOMWindow::alert(const String& message)
+{
+ if (!m_frame)
+ return;
+
+ m_frame->document()->updateStyleIfNeeded();
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ page->chrome()->runJavaScriptAlert(m_frame, message);
+}
+
+bool DOMWindow::confirm(const String& message)
+{
+ if (!m_frame)
+ return false;
+
+ m_frame->document()->updateStyleIfNeeded();
+
+ Page* page = m_frame->page();
+ if (!page)
+ return false;
+
+ return page->chrome()->runJavaScriptConfirm(m_frame, message);
+}
+
+String DOMWindow::prompt(const String& message, const String& defaultValue)
+{
+ if (!m_frame)
+ return String();
+
+ m_frame->document()->updateStyleIfNeeded();
+
+ Page* page = m_frame->page();
+ if (!page)
+ return String();
+
+ String returnValue;
+ if (page->chrome()->runJavaScriptPrompt(m_frame, message, defaultValue, returnValue))
+ return returnValue;
+
+ return String();
+}
+
+static bool isSafeToConvertCharList(const String& string)
+{
+ for (unsigned i = 0; i < string.length(); i++) {
+ if (string[i] > 0xFF)
+ return false;
+ }
+
+ return true;
+}
+
+String DOMWindow::btoa(const String& stringToEncode, ExceptionCode& ec)
+{
+ if (stringToEncode.isNull())
+ return String();
+
+ if (!isSafeToConvertCharList(stringToEncode)) {
+ ec = INVALID_CHARACTER_ERR;
+ return String();
+ }
+
+ Vector<char> in;
+ in.append(stringToEncode.characters(), stringToEncode.length());
+ Vector<char> out;
+
+ base64Encode(in, out);
+
+ return String(out.data(), out.size());
+}
+
+String DOMWindow::atob(const String& encodedString, ExceptionCode& ec)
+{
+ if (encodedString.isNull())
+ return String();
+
+ if (!isSafeToConvertCharList(encodedString)) {
+ ec = INVALID_CHARACTER_ERR;
+ return String();
+ }
+
+ Vector<char> out;
+ if (!base64Decode(encodedString, out, FailOnInvalidCharacter)) {
+ ec = INVALID_CHARACTER_ERR;
+ return String();
+ }
+
+ return String(out.data(), out.size());
+}
+
+bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool /*wholeWord*/, bool /*searchInFrames*/, bool /*showDialog*/) const
+{
+ if (!m_frame)
+ return false;
+
+ // FIXME (13016): Support wholeWord, searchInFrames and showDialog
+ return m_frame->editor()->findString(string, !backwards, caseSensitive, wrap, false);
+}
+
+bool DOMWindow::offscreenBuffering() const
+{
+ return true;
+}
+
+int DOMWindow::outerHeight() const
+{
+ if (!m_frame)
+ return 0;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return 0;
+
+ return static_cast<int>(page->chrome()->windowRect().height());
+}
+
+int DOMWindow::outerWidth() const
+{
+ if (!m_frame)
+ return 0;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return 0;
+
+ return static_cast<int>(page->chrome()->windowRect().width());
+}
+
+int DOMWindow::innerHeight() const
+{
+ if (!m_frame)
+ return 0;
+
+ FrameView* view = m_frame->view();
+ if (!view)
+ return 0;
+
+#if PLATFORM(ANDROID)
+ return static_cast<int>(view->actualHeight() / m_frame->pageZoomFactor());
+#else
+ return static_cast<int>(view->height() / m_frame->pageZoomFactor());
+#endif
+}
+
+int DOMWindow::innerWidth() const
+{
+ if (!m_frame)
+ return 0;
+
+ FrameView* view = m_frame->view();
+ if (!view)
+ return 0;
+
+#if PLATFORM(ANDROID)
+ return static_cast<int>(view->actualWidth() / m_frame->pageZoomFactor());
+#else
+ return static_cast<int>(view->width() / m_frame->pageZoomFactor());
+#endif
+}
+
+int DOMWindow::screenX() const
+{
+ if (!m_frame)
+ return 0;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return 0;
+
+ return static_cast<int>(page->chrome()->windowRect().x());
+}
+
+int DOMWindow::screenY() const
+{
+ if (!m_frame)
+ return 0;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return 0;
+
+ return static_cast<int>(page->chrome()->windowRect().y());
+}
+
+int DOMWindow::scrollX() const
+{
+ if (!m_frame)
+ return 0;
+
+ FrameView* view = m_frame->view();
+ if (!view)
+ return 0;
+
+ m_frame->document()->updateLayoutIgnorePendingStylesheets();
+
+#if PLATFORM(ANDROID)
+ return static_cast<int>(view->actualScrollX() / m_frame->pageZoomFactor());
+#else
+ return static_cast<int>(view->scrollX() / m_frame->pageZoomFactor());
+#endif
+}
+
+int DOMWindow::scrollY() const
+{
+ if (!m_frame)
+ return 0;
+
+ FrameView* view = m_frame->view();
+ if (!view)
+ return 0;
+
+ m_frame->document()->updateLayoutIgnorePendingStylesheets();
+
+#if PLATFORM(ANDROID)
+ return static_cast<int>(view->actualScrollY() / m_frame->pageZoomFactor());
+#else
+ return static_cast<int>(view->scrollY() / m_frame->pageZoomFactor());
+#endif
+}
+
+bool DOMWindow::closed() const
+{
+ return !m_frame;
+}
+
+unsigned DOMWindow::length() const
+{
+ if (!m_frame)
+ return 0;
+
+ return m_frame->tree()->childCount();
+}
+
+String DOMWindow::name() const
+{
+ if (!m_frame)
+ return String();
+
+ return m_frame->tree()->name();
+}
+
+void DOMWindow::setName(const String& string)
+{
+ if (!m_frame)
+ return;
+
+ m_frame->tree()->setName(string);
+}
+
+void DOMWindow::setStatus(const String& string)
+{
+ m_status = string;
+
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state.
+ page->chrome()->setStatusbarText(m_frame, m_status);
+}
+
+void DOMWindow::setDefaultStatus(const String& string)
+{
+ m_defaultStatus = string;
+
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ ASSERT(m_frame->document()); // Client calls shouldn't be made when the frame is in inconsistent state.
+ page->chrome()->setStatusbarText(m_frame, m_defaultStatus);
+}
+
+DOMWindow* DOMWindow::self() const
+{
+ if (!m_frame)
+ return 0;
+
+ return m_frame->domWindow();
+}
+
+DOMWindow* DOMWindow::opener() const
+{
+ if (!m_frame)
+ return 0;
+
+ Frame* opener = m_frame->loader()->opener();
+ if (!opener)
+ return 0;
+
+ return opener->domWindow();
+}
+
+DOMWindow* DOMWindow::parent() const
+{
+ if (!m_frame)
+ return 0;
+
+ Frame* parent = m_frame->tree()->parent(true);
+ if (parent)
+ return parent->domWindow();
+
+ return m_frame->domWindow();
+}
+
+DOMWindow* DOMWindow::top() const
+{
+ if (!m_frame)
+ return 0;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return 0;
+
+ return m_frame->tree()->top(true)->domWindow();
+}
+
+Document* DOMWindow::document() const
+{
+ // FIXME: This function shouldn't need a frame to work.
+ if (!m_frame)
+ return 0;
+
+ // The m_frame pointer is not zeroed out when the window is put into b/f cache, so it can hold an unrelated document/window pair.
+ // FIXME: We should always zero out the frame pointer on navigation to avoid accidentally accessing the new frame content.
+ if (m_frame->domWindow() != this)
+ return 0;
+
+ ASSERT(m_frame->document());
+ return m_frame->document();
+}
+
+PassRefPtr<StyleMedia> DOMWindow::styleMedia() const
+{
+ if (!m_media)
+ m_media = StyleMedia::create(m_frame);
+ return m_media.get();
+}
+
+PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String& pseudoElt) const
+{
+ if (!elt)
+ return 0;
+
+ return computedStyle(elt, false, pseudoElt);
+}
+
+PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* elt, const String&, bool authorOnly) const
+{
+ if (!m_frame)
+ return 0;
+
+ Settings* settings = m_frame->settings();
+ return m_frame->document()->styleSelector()->styleRulesForElement(elt, authorOnly, false, settings && settings->crossOriginCheckInGetMatchedCSSRulesDisabled() ? AllCSSRules : SameOriginCSSRulesOnly);
+}
+
+PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromNodeToPage(Node* node, const WebKitPoint* p) const
+{
+ if (!node || !p)
+ return 0;
+
+ m_frame->document()->updateLayoutIgnorePendingStylesheets();
+
+ FloatPoint pagePoint(p->x(), p->y());
+ pagePoint = node->convertToPage(pagePoint);
+ return WebKitPoint::create(pagePoint.x(), pagePoint.y());
+}
+
+PassRefPtr<WebKitPoint> DOMWindow::webkitConvertPointFromPageToNode(Node* node, const WebKitPoint* p) const
+{
+ if (!node || !p)
+ return 0;
+
+ m_frame->document()->updateLayoutIgnorePendingStylesheets();
+
+ FloatPoint nodePoint(p->x(), p->y());
+ nodePoint = node->convertFromPage(nodePoint);
+ return WebKitPoint::create(nodePoint.x(), nodePoint.y());
+}
+
+double DOMWindow::devicePixelRatio() const
+{
+ if (!m_frame)
+ return 0.0;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return 0.0;
+
+ return page->chrome()->scaleFactor();
+}
+
+#if ENABLE(DATABASE)
+PassRefPtr<Database> DOMWindow::openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, ExceptionCode& ec)
+{
+ RefPtr<Database> database = 0;
+ if (m_frame && AbstractDatabase::isAvailable() && m_frame->document()->securityOrigin()->canAccessDatabase())
+ database = Database::openDatabase(m_frame->document(), name, version, displayName, estimatedSize, creationCallback, ec);
+
+ if (!database && !ec)
+ ec = SECURITY_ERR;
+
+ return database;
+}
+#endif
+
+void DOMWindow::scrollBy(int x, int y) const
+{
+ if (!m_frame)
+ return;
+
+ m_frame->document()->updateLayoutIgnorePendingStylesheets();
+
+ RefPtr<FrameView> view = m_frame->view();
+ if (!view)
+ return;
+
+ view->scrollBy(IntSize(x, y));
+}
+
+void DOMWindow::scrollTo(int x, int y) const
+{
+ if (!m_frame)
+ return;
+
+ m_frame->document()->updateLayoutIgnorePendingStylesheets();
+
+ FrameView* view = m_frame->view();
+ if (!view)
+ return;
+
+ int zoomedX = static_cast<int>(x * m_frame->pageZoomFactor());
+ int zoomedY = static_cast<int>(y * m_frame->pageZoomFactor());
+ view->setScrollPosition(IntPoint(zoomedX, zoomedY));
+}
+
+void DOMWindow::moveBy(float x, float y) const
+{
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ if (m_frame != page->mainFrame())
+ return;
+
+ FloatRect fr = page->chrome()->windowRect();
+ FloatRect update = fr;
+ update.move(x, y);
+ // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
+ adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
+ page->chrome()->setWindowRect(fr);
+}
+
+void DOMWindow::moveTo(float x, float y) const
+{
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ if (m_frame != page->mainFrame())
+ return;
+
+ FloatRect fr = page->chrome()->windowRect();
+ FloatRect sr = screenAvailableRect(page->mainFrame()->view());
+ fr.setLocation(sr.location());
+ FloatRect update = fr;
+ update.move(x, y);
+ // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
+ adjustWindowRect(sr, fr, update);
+ page->chrome()->setWindowRect(fr);
+}
+
+void DOMWindow::resizeBy(float x, float y) const
+{
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ if (m_frame != page->mainFrame())
+ return;
+
+ FloatRect fr = page->chrome()->windowRect();
+ FloatSize dest = fr.size() + FloatSize(x, y);
+ FloatRect update(fr.location(), dest);
+ adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
+ page->chrome()->setWindowRect(fr);
+}
+
+void DOMWindow::resizeTo(float width, float height) const
+{
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ if (m_frame != page->mainFrame())
+ return;
+
+ FloatRect fr = page->chrome()->windowRect();
+ FloatSize dest = FloatSize(width, height);
+ FloatRect update(fr.location(), dest);
+ adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update);
+ page->chrome()->setWindowRect(fr);
+}
+
+int DOMWindow::setTimeout(PassOwnPtr<ScheduledAction> action, int timeout, ExceptionCode& ec)
+{
+ ScriptExecutionContext* context = scriptExecutionContext();
+ if (!context) {
+ ec = INVALID_ACCESS_ERR;
+ return -1;
+ }
+ return DOMTimer::install(context, action, timeout, true);
+}
+
+void DOMWindow::clearTimeout(int timeoutId)
+{
+ ScriptExecutionContext* context = scriptExecutionContext();
+ if (!context)
+ return;
+ DOMTimer::removeById(context, timeoutId);
+}
+
+int DOMWindow::setInterval(PassOwnPtr<ScheduledAction> action, int timeout, ExceptionCode& ec)
+{
+ ScriptExecutionContext* context = scriptExecutionContext();
+ if (!context) {
+ ec = INVALID_ACCESS_ERR;
+ return -1;
+ }
+ return DOMTimer::install(context, action, timeout, false);
+}
+
+void DOMWindow::clearInterval(int timeoutId)
+{
+ ScriptExecutionContext* context = scriptExecutionContext();
+ if (!context)
+ return;
+ DOMTimer::removeById(context, timeoutId);
+}
+
+bool DOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
+{
+ if (!EventTarget::addEventListener(eventType, listener, useCapture))
+ return false;
+
+ if (Document* document = this->document())
+ document->addListenerTypeIfNeeded(eventType);
+
+ if (eventType == eventNames().unloadEvent)
+ addUnloadEventListener(this);
+ else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this))
+ addBeforeUnloadEventListener(this);
+#if ENABLE(DEVICE_ORIENTATION)
+ else if (eventType == eventNames().devicemotionEvent && frame() && frame()->page() && frame()->page()->deviceMotionController())
+ frame()->page()->deviceMotionController()->addListener(this);
+ else if (eventType == eventNames().deviceorientationEvent && frame() && frame()->page() && frame()->page()->deviceOrientationController())
+ frame()->page()->deviceOrientationController()->addListener(this);
+#endif
+
+ return true;
+}
+
+bool DOMWindow::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
+{
+ if (!EventTarget::removeEventListener(eventType, listener, useCapture))
+ return false;
+
+ if (eventType == eventNames().unloadEvent)
+ removeUnloadEventListener(this);
+ else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this))
+ removeBeforeUnloadEventListener(this);
+#if ENABLE(DEVICE_ORIENTATION)
+ else if (eventType == eventNames().devicemotionEvent && frame() && frame()->page() && frame()->page()->deviceMotionController())
+ frame()->page()->deviceMotionController()->removeListener(this);
+ else if (eventType == eventNames().deviceorientationEvent && frame() && frame()->page() && frame()->page()->deviceOrientationController())
+ frame()->page()->deviceOrientationController()->removeListener(this);
+#endif
+
+ return true;
+}
+
+void DOMWindow::dispatchLoadEvent()
+{
+ 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
+ // the DOM.
+ Element* ownerElement = document()->ownerElement();
+ if (ownerElement) {
+ RefPtr<Event> ownerEvent = Event::create(eventNames().loadEvent, false, false);
+ ownerEvent->setTarget(ownerElement);
+ ownerElement->dispatchGenericEvent(ownerEvent.release());
+ }
+
+#if ENABLE(INSPECTOR)
+ if (!frame() || !frame()->page())
+ return;
+
+ if (InspectorController* controller = frame()->page()->inspectorController())
+ controller->mainResourceFiredLoadEvent(frame()->loader()->documentLoader(), url());
+#endif
+}
+
+bool DOMWindow::dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget> prpTarget)
+{
+ RefPtr<EventTarget> protect = this;
+ RefPtr<Event> event = prpEvent;
+
+ event->setTarget(prpTarget ? prpTarget : this);
+ event->setCurrentTarget(this);
+ event->setEventPhase(Event::AT_TARGET);
+
+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEventOnWindow(frame(), *event, this);
+
+ bool result = fireEventListeners(event.get());
+
+ InspectorInstrumentation::didDispatchEventOnWindow(cookie);
+
+ 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();
+
+#if ENABLE(DEVICE_ORIENTATION)
+ if (frame() && frame()->page() && frame()->page()->deviceMotionController())
+ frame()->page()->deviceMotionController()->removeAllListeners(this);
+ if (frame() && frame()->page() && frame()->page()->deviceOrientationController())
+ frame()->page()->deviceOrientationController()->removeAllListeners(this);
+#endif
+
+ removeAllUnloadEventListeners(this);
+ removeAllBeforeUnloadEventListeners(this);
+}
+
+void DOMWindow::captureEvents()
+{
+ // Not implemented.
+}
+
+void DOMWindow::releaseEvents()
+{
+ // Not implemented.
+}
+
+void DOMWindow::finishedLoading()
+{
+ if (m_shouldPrintWhenFinishedLoading) {
+ m_shouldPrintWhenFinishedLoading = false;
+ print();
+ }
+}
+
+EventTargetData* DOMWindow::eventTargetData()
+{
+ return &m_eventTargetData;
+}
+
+EventTargetData* DOMWindow::ensureEventTargetData()
+{
+ return &m_eventTargetData;
+}
+
+#if ENABLE(BLOB)
+String DOMWindow::createObjectURL(Blob* blob)
+{
+ return scriptExecutionContext()->createPublicBlobURL(blob).string();
+}
+
+void DOMWindow::revokeObjectURL(const String& blobURLString)
+{
+ scriptExecutionContext()->revokePublicBlobURL(KURL(KURL(), blobURLString));
+}
+#endif
+
+<<<<<<< HEAD:WebCore/page/DOMWindow.cpp
+#if ENABLE(DOM_STORAGE) && defined(ANDROID)
+void DOMWindow::clearDOMStorage()
+{
+ if (m_sessionStorage)
+ m_sessionStorage->disconnectFrame();
+ m_sessionStorage = 0;
+
+ if (m_localStorage)
+ m_localStorage->disconnectFrame();
+ m_localStorage = 0;
+}
+#endif
+
+void DOMWindow::setLocation(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow)
+=======
+void DOMWindow::setLocation(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow, SetLocationLocking locking)
+>>>>>>> webkit.org at r75315:Source/WebCore/page/DOMWindow.cpp
+{
+ Frame* activeFrame = activeWindow->frame();
+ if (!activeFrame)
+ return;
+
+ if (!activeFrame->loader()->shouldAllowNavigation(m_frame))
+ return;
+
+ Frame* firstFrame = firstWindow->frame();
+ if (!firstFrame)
+ return;
+
+ KURL completedURL = firstFrame->document()->completeURL(urlString);
+ if (completedURL.isNull())
+ return;
+
+ if (isInsecureScriptAccess(activeWindow, urlString))
+ return;
+
+ // We want a new history item if we are processing a user gesture.
+ m_frame->navigationScheduler()->scheduleLocationChange(activeFrame->document()->securityOrigin(),
+ completedURL, activeFrame->loader()->outgoingReferrer(),
+ locking != LockHistoryBasedOnGestureState || !activeFrame->script()->anyPageIsProcessingUserGesture(),
+ locking != LockHistoryBasedOnGestureState);
+}
+
+void DOMWindow::printErrorMessage(const String& message)
+{
+ if (message.isEmpty())
+ return;
+
+ Settings* settings = m_frame->settings();
+ if (!settings)
+ return;
+ if (settings->privateBrowsingEnabled())
+ return;
+
+ // FIXME: Add arguments so that we can provide a correct source URL and line number.
+ console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String());
+}
+
+String DOMWindow::crossDomainAccessErrorMessage(DOMWindow* activeWindow)
+{
+ const KURL& activeWindowURL = activeWindow->url();
+ if (activeWindowURL.isNull())
+ return String();
+
+ // FIXME: This error message should contain more specifics of why the same origin check has failed.
+ // Perhaps we should involve the security origin object in composing it.
+ // FIXME: This message, and other console messages, have extra newlines. Should remove them.
+ return makeString("Unsafe JavaScript attempt to access frame with URL ", m_url.string(),
+ " from frame with URL ", activeWindowURL.string(), ". Domains, protocols and ports must match.\n");
+}
+
+bool DOMWindow::isInsecureScriptAccess(DOMWindow* activeWindow, const String& urlString)
+{
+ if (!protocolIsJavaScript(urlString))
+ return false;
+
+ // FIXME: Is there some way to eliminate the need for a separate "activeWindow == this" check?
+ if (activeWindow == this)
+ return false;
+
+ // FIXME: The name canAccess seems to be a roundabout way to ask "can execute script".
+ // Can we name the SecurityOrigin function better to make this more clear?
+ if (activeWindow->securityOrigin()->canAccess(securityOrigin()))
+ return false;
+
+ printErrorMessage(crossDomainAccessErrorMessage(activeWindow));
+ return true;
+}
+
+Frame* DOMWindow::createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures& windowFeatures,
+ DOMWindow* activeWindow, Frame* firstFrame, Frame* openerFrame, PrepareDialogFunction function, void* functionContext)
+{
+ Frame* activeFrame = activeWindow->frame();
+
+ // FIXME: It's much better for client API if a new window starts with a URL, here where we
+ // know what URL we are going to open. Unfortunately, this code passes the empty string
+ // for the URL, but there's a reason for that. Before loading we have to set up the opener,
+ // openedByDOM, and dialogArguments values. Also, to decide whether to use the URL we currently
+ // do an isInsecureScriptAccess call using the window we create, which can't be done before
+ // creating it. We'd have to resolve all those issues to pass the URL instead of an empty string.
+
+ // For whatever reason, Firefox uses the first frame to determine the outgoingReferrer. We replicate that behavior here.
+ String referrer = firstFrame->loader()->outgoingReferrer();
+
+ ResourceRequest request(KURL(), referrer);
+ FrameLoader::addHTTPOriginIfNeeded(request, firstFrame->loader()->outgoingOrigin());
+ FrameLoadRequest frameRequest(activeWindow->securityOrigin(), request, frameName);
+
+ // We pass the opener frame for the lookupFrame in case the active frame is different from
+ // the opener frame, and the name references a frame relative to the opener frame.
+ bool created;
+ Frame* newFrame = WebCore::createWindow(activeFrame, openerFrame, frameRequest, windowFeatures, created);
+ if (!newFrame)
+ return 0;
+
+ newFrame->loader()->setOpener(openerFrame);
+ newFrame->page()->setOpenedByDOM();
+
+ if (newFrame->domWindow()->isInsecureScriptAccess(activeWindow, urlString))
+ return newFrame;
+
+ if (function)
+ function(newFrame->domWindow(), functionContext);
+
+ KURL completedURL = urlString.isEmpty() ? KURL(ParsedURLString, "") : firstFrame->document()->completeURL(urlString);
+
+ if (created)
+ newFrame->loader()->changeLocation(activeWindow->securityOrigin(), completedURL, referrer, false, false);
+ else if (!urlString.isEmpty()) {
+ newFrame->navigationScheduler()->scheduleLocationChange(activeWindow->securityOrigin(), completedURL.string(), referrer,
+ !activeFrame->script()->anyPageIsProcessingUserGesture(), false);
+ }
+
+ return newFrame;
+}
+
+PassRefPtr<DOMWindow> DOMWindow::open(const String& urlString, const AtomicString& frameName, const String& windowFeaturesString,
+ DOMWindow* activeWindow, DOMWindow* firstWindow)
+{
+ if (!m_frame)
+ return 0;
+ Frame* activeFrame = activeWindow->frame();
+ if (!activeFrame)
+ return 0;
+ Frame* firstFrame = firstWindow->frame();
+ if (!firstFrame)
+ return 0;
+
+ if (!firstWindow->allowPopUp()) {
+ // Because FrameTree::find() returns true for empty strings, we must check for empty frame names.
+ // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
+ if (frameName.isEmpty() || !m_frame->tree()->find(frameName))
+ return 0;
+ }
+
+ // Get the target frame for the special cases of _top and _parent.
+ // In those cases, we schedule a location change right now and return early.
+ Frame* targetFrame = 0;
+ if (frameName == "_top")
+ targetFrame = m_frame->tree()->top();
+ else if (frameName == "_parent") {
+ if (Frame* parent = m_frame->tree()->parent())
+ targetFrame = parent;
+ else
+ targetFrame = m_frame;
+ }
+ if (targetFrame) {
+ if (!activeFrame->loader()->shouldAllowNavigation(targetFrame))
+ return 0;
+
+ if (isInsecureScriptAccess(activeWindow, urlString))
+ return targetFrame->domWindow();
+
+ if (urlString.isEmpty())
+ return targetFrame->domWindow();
+
+ // For whatever reason, Firefox uses the first window rather than the active window to
+ // determine the outgoing referrer. We replicate that behavior here.
+ targetFrame->navigationScheduler()->scheduleLocationChange(activeFrame->document()->securityOrigin(),
+ firstFrame->document()->completeURL(urlString).string(),
+ firstFrame->loader()->outgoingReferrer(),
+ !activeFrame->script()->anyPageIsProcessingUserGesture(), false);
+
+ return targetFrame->domWindow();
+ }
+
+ WindowFeatures windowFeatures(windowFeaturesString);
+ FloatRect windowRect(windowFeatures.xSet ? windowFeatures.x : 0, windowFeatures.ySet ? windowFeatures.y : 0,
+ windowFeatures.widthSet ? windowFeatures.width : 0, windowFeatures.heightSet ? windowFeatures.height : 0);
+ Page* page = m_frame->page();
+ DOMWindow::adjustWindowRect(screenAvailableRect(page ? page->mainFrame()->view() : 0), windowRect, windowRect);
+ windowFeatures.x = windowRect.x();
+ windowFeatures.y = windowRect.y();
+ windowFeatures.height = windowRect.height();
+ windowFeatures.width = windowRect.width();
+
+ Frame* result = createWindow(urlString, frameName, windowFeatures, activeWindow, firstFrame, m_frame);
+ return result ? result->domWindow() : 0;
+}
+
+void DOMWindow::showModalDialog(const String& urlString, const String& dialogFeaturesString,
+ DOMWindow* activeWindow, DOMWindow* firstWindow, PrepareDialogFunction function, void* functionContext)
+{
+ if (!m_frame)
+ return;
+ Frame* activeFrame = activeWindow->frame();
+ if (!activeFrame)
+ return;
+ Frame* firstFrame = firstWindow->frame();
+ if (!firstFrame)
+ return;
+
+ if (!canShowModalDialogNow(m_frame) || !firstWindow->allowPopUp())
+ return;
+
+ Frame* dialogFrame = createWindow(urlString, emptyAtom, WindowFeatures(dialogFeaturesString, screenAvailableRect(m_frame->view())),
+ activeWindow, firstFrame, m_frame, function, functionContext);
+ if (!dialogFrame)
+ return;
+
+ dialogFrame->page()->chrome()->runModal();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/DOMWindow.h b/Source/WebCore/page/DOMWindow.h
new file mode 100644
index 0000000..8f434d6
--- /dev/null
+++ b/Source/WebCore/page/DOMWindow.h
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2006, 2007, 2009, 2010 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DOMWindow_h
+#define DOMWindow_h
+
+#include "KURL.h"
+#include "MessagePort.h"
+#include "SecurityOrigin.h"
+
+namespace WebCore {
+
+ class BarInfo;
+ class Blob;
+ class CSSRuleList;
+ class CSSStyleDeclaration;
+ class Console;
+ class DOMApplicationCache;
+ class DOMSelection;
+ class Database;
+ class DatabaseCallback;
+ class Document;
+ class Element;
+ class ErrorCallback;
+ class EventListener;
+ class FileSystemCallback;
+ class FloatRect;
+ class History;
+ class IDBFactory;
+ class Location;
+ class MediaQueryList;
+ class Navigator;
+ class Node;
+ class NotificationCenter;
+ class Performance;
+ class PostMessageTimer;
+ class ScheduledAction;
+ class Screen;
+ class SerializedScriptValue;
+ class Storage;
+ class StyleMedia;
+ class WebKitPoint;
+
+ struct WindowFeatures;
+
+ typedef int ExceptionCode;
+
+ enum SetLocationLocking { LockHistoryBasedOnGestureState, LockHistoryAndBackForwardList };
+
+ class DOMWindow : public RefCounted<DOMWindow>, public EventTarget {
+ public:
+ static PassRefPtr<DOMWindow> create(Frame* frame) { return adoptRef(new DOMWindow(frame)); }
+ virtual ~DOMWindow();
+
+ virtual DOMWindow* toDOMWindow() { return this; }
+ virtual ScriptExecutionContext* scriptExecutionContext() const;
+
+ Frame* frame() const { return m_frame; }
+ void disconnectFrame();
+
+ void clear();
+
+ PassRefPtr<MediaQueryList> matchMedia(const String&);
+
+ void setSecurityOrigin(SecurityOrigin* securityOrigin) { m_securityOrigin = securityOrigin; }
+ SecurityOrigin* securityOrigin() const { return m_securityOrigin.get(); }
+
+ void setURL(const KURL& url) { m_url = url; }
+ KURL url() const { return m_url; }
+
+ unsigned pendingUnloadEventListeners() const;
+
+ static bool dispatchAllPendingBeforeUnloadEvents();
+ static void dispatchAllPendingUnloadEvents();
+
+ static void adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges);
+
+ // FIXME: We can remove this function once V8 showModalDialog is changed to use DOMWindow.
+ static void parseModalDialogFeatures(const String&, HashMap<String, String>&);
+
+ bool allowPopUp(); // Call on first window, not target window.
+ static bool allowPopUp(Frame* firstFrame);
+ static bool canShowModalDialog(const Frame*);
+ static bool canShowModalDialogNow(const Frame*);
+
+ // DOM Level 0
+
+ Screen* screen() const;
+ History* history() const;
+ BarInfo* locationbar() const;
+ BarInfo* menubar() const;
+ BarInfo* personalbar() const;
+ BarInfo* scrollbars() const;
+ BarInfo* statusbar() const;
+ BarInfo* toolbar() const;
+ Navigator* navigator() const;
+ Navigator* clientInformation() const { return navigator(); }
+
+ Location* location() const;
+ void setLocation(const String& location, DOMWindow* activeWindow, DOMWindow* firstWindow,
+ SetLocationLocking = LockHistoryBasedOnGestureState);
+
+ DOMSelection* getSelection();
+
+ Element* frameElement() const;
+
+ void focus();
+ void blur();
+ void close(ScriptExecutionContext* = 0);
+ void print();
+ void stop();
+
+ PassRefPtr<DOMWindow> open(const String& urlString, const AtomicString& frameName, const String& windowFeaturesString,
+ DOMWindow* activeWindow, DOMWindow* firstWindow);
+
+ typedef void (*PrepareDialogFunction)(DOMWindow*, void* context);
+ void showModalDialog(const String& urlString, const String& dialogFeaturesString,
+ DOMWindow* activeWindow, DOMWindow* firstWindow, PrepareDialogFunction, void* functionContext);
+
+ void alert(const String& message);
+ bool confirm(const String& message);
+ String prompt(const String& message, const String& defaultValue);
+ String btoa(const String& stringToEncode, ExceptionCode&);
+ String atob(const String& encodedString, ExceptionCode&);
+
+ bool find(const String&, bool caseSensitive, bool backwards, bool wrap, bool wholeWord, bool searchInFrames, bool showDialog) const;
+
+ bool offscreenBuffering() const;
+
+ int outerHeight() const;
+ int outerWidth() const;
+ int innerHeight() const;
+ int innerWidth() const;
+ int screenX() const;
+ int screenY() const;
+ int screenLeft() const { return screenX(); }
+ int screenTop() const { return screenY(); }
+ int scrollX() const;
+ int scrollY() const;
+ int pageXOffset() const { return scrollX(); }
+ int pageYOffset() const { return scrollY(); }
+
+ bool closed() const;
+
+ unsigned length() const;
+
+ String name() const;
+ void setName(const String&);
+
+ String status() const;
+ void setStatus(const String&);
+ String defaultStatus() const;
+ void setDefaultStatus(const String&);
+
+ // This attribute is an alias of defaultStatus and is necessary for legacy uses.
+ String defaultstatus() const { return defaultStatus(); }
+ void setDefaultstatus(const String& status) { setDefaultStatus(status); }
+
+ // Self-referential attributes
+
+ DOMWindow* self() const;
+ DOMWindow* window() const { return self(); }
+ DOMWindow* frames() const { return self(); }
+
+ DOMWindow* opener() const;
+ DOMWindow* parent() const;
+ DOMWindow* top() const;
+
+ // DOM Level 2 AbstractView Interface
+
+ Document* document() const;
+
+ // CSSOM View Module
+
+ PassRefPtr<StyleMedia> styleMedia() const;
+
+ // DOM Level 2 Style Interface
+
+ PassRefPtr<CSSStyleDeclaration> getComputedStyle(Element*, const String& pseudoElt) const;
+
+ // WebKit extensions
+
+ PassRefPtr<CSSRuleList> getMatchedCSSRules(Element*, const String& pseudoElt, bool authorOnly = true) const;
+ double devicePixelRatio() const;
+
+ PassRefPtr<WebKitPoint> webkitConvertPointFromPageToNode(Node*, const WebKitPoint*) const;
+ PassRefPtr<WebKitPoint> webkitConvertPointFromNodeToPage(Node*, const WebKitPoint*) const;
+
+ Console* console() const;
+
+ void printErrorMessage(const String&);
+ String crossDomainAccessErrorMessage(DOMWindow* activeWindow);
+
+ void pageDestroyed();
+
+ void postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray*, const String& targetOrigin, DOMWindow* source, ExceptionCode&);
+ // FIXME: remove this when we update the ObjC bindings (bug #28774).
+ void postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort*, const String& targetOrigin, DOMWindow* source, ExceptionCode&);
+ void postMessageTimerFired(PostMessageTimer*);
+
+ void scrollBy(int x, int y) const;
+ void scrollTo(int x, int y) const;
+ void scroll(int x, int y) const { scrollTo(x, y); }
+
+ void moveBy(float x, float y) const;
+ void moveTo(float x, float y) const;
+
+ void resizeBy(float x, float y) const;
+ void resizeTo(float width, float height) const;
+
+ // Timers
+ int setTimeout(PassOwnPtr<ScheduledAction>, int timeout, ExceptionCode&);
+ void clearTimeout(int timeoutId);
+ int setInterval(PassOwnPtr<ScheduledAction>, int timeout, ExceptionCode&);
+ void clearInterval(int timeoutId);
+
+ // Events
+ // EventTarget API
+ virtual bool addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
+ virtual bool removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture);
+ virtual void removeAllEventListeners();
+
+ 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);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(blur);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(canplay);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(canplaythrough);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(change);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(click);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(contextmenu);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(dblclick);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(drag);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(dragend);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(dragenter);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(dragleave);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(dragover);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(dragstart);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(drop);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(durationchange);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(emptied);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(ended);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(focus);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(hashchange);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(input);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(keypress);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(keyup);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(load);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(loadeddata);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(loadedmetadata);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(message);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(mousedown);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(mousemove);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseout);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseover);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseup);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(mousewheel);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(offline);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(online);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(pagehide);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(pageshow);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(pause);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(play);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(playing);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(popstate);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(progress);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(ratechange);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(reset);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(resize);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(scroll);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(search);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(seeked);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(seeking);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(select);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(stalled);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(storage);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(submit);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(suspend);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(timeupdate);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(unload);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(volumechange);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(waiting);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitbeginfullscreen);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitendfullscreen);
+
+ DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkitanimationstart, webkitAnimationStart);
+ DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkitanimationiteration, webkitAnimationIteration);
+ DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkitanimationend, webkitAnimationEnd);
+ DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkittransitionend, webkitTransitionEnd);
+
+ void captureEvents();
+ void releaseEvents();
+
+ void finishedLoading();
+
+ // These functions are used for GC marking. See JSDOMWindow::markChildren(MarkStack&) in JSDOMWindowCustom.cpp.
+ Screen* optionalScreen() const { return m_screen.get(); }
+ DOMSelection* optionalSelection() const { return m_selection.get(); }
+ History* optionalHistory() const { return m_history.get(); }
+ BarInfo* optionalLocationbar() const { return m_locationbar.get(); }
+ BarInfo* optionalMenubar() const { return m_menubar.get(); }
+ BarInfo* optionalPersonalbar() const { return m_personalbar.get(); }
+ BarInfo* optionalScrollbars() const { return m_scrollbars.get(); }
+ BarInfo* optionalStatusbar() const { return m_statusbar.get(); }
+ BarInfo* optionalToolbar() const { return m_toolbar.get(); }
+ Console* optionalConsole() const { return m_console.get(); }
+ Navigator* optionalNavigator() const { return m_navigator.get(); }
+ Location* optionalLocation() const { return m_location.get(); }
+ StyleMedia* optionalMedia() const { return m_media.get(); }
+
+ using RefCounted<DOMWindow>::ref;
+ using RefCounted<DOMWindow>::deref;
+
+#if ENABLE(BLOB)
+ String createObjectURL(Blob*);
+ void revokeObjectURL(const String&);
+#endif
+
+#if ENABLE(DATABASE)
+ // HTML 5 client-side database
+ PassRefPtr<Database> openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, ExceptionCode&);
+#endif
+
+#if ENABLE(DEVICE_ORIENTATION)
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(devicemotion);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(deviceorientation);
+#endif
+
+#if ENABLE(DOM_STORAGE)
+ // HTML 5 key/value storage
+ Storage* sessionStorage(ExceptionCode&) const;
+ Storage* localStorage(ExceptionCode&) const;
+ Storage* optionalSessionStorage() const { return m_sessionStorage.get(); }
+ Storage* optionalLocalStorage() const { return m_localStorage.get(); }
+#ifdef ANDROID
+ void clearDOMStorage();
+#endif
+#endif
+
+#if ENABLE(FILE_SYSTEM)
+ // They are placed here and in all capital letters so they can be checked against the constants in the
+ // IDL at compile time.
+ enum FileSystemType {
+ TEMPORARY,
+ PERSISTENT,
+ };
+ void requestFileSystem(int type, long long size, PassRefPtr<FileSystemCallback>, PassRefPtr<ErrorCallback>);
+#endif
+
+#if ENABLE(INDEXED_DATABASE)
+ IDBFactory* webkitIndexedDB() const;
+#endif
+
+#if ENABLE(NOTIFICATIONS)
+ NotificationCenter* webkitNotifications() const;
+#endif
+
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ DOMApplicationCache* applicationCache() const;
+ DOMApplicationCache* optionalApplicationCache() const { return m_applicationCache.get(); }
+#endif
+
+#if ENABLE(ORIENTATION_EVENTS)
+ // This is the interface orientation in degrees. Some examples are:
+ // 0 is straight up; -90 is when the device is rotated 90 clockwise;
+ // 90 is when rotated counter clockwise.
+ int orientation() const;
+
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(orientationchange);
+#endif
+
+#if ENABLE(TOUCH_EVENTS)
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(touchstart);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(touchmove);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(touchend);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(touchcancel);
+#endif
+
+#if ENABLE(WEB_TIMING)
+ Performance* performance() const;
+ Performance* optionalPerformance() const { return m_performance.get(); }
+#endif
+
+ private:
+ DOMWindow(Frame*);
+
+ virtual void refEventTarget() { ref(); }
+ virtual void derefEventTarget() { deref(); }
+ virtual EventTargetData* eventTargetData();
+ virtual EventTargetData* ensureEventTargetData();
+
+ static Frame* createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures&,
+ DOMWindow* activeWindow, Frame* firstFrame, Frame* openerFrame,
+ PrepareDialogFunction = 0, void* functionContext = 0);
+ bool isInsecureScriptAccess(DOMWindow* activeWindow, const String& urlString);
+
+ RefPtr<SecurityOrigin> m_securityOrigin;
+ KURL m_url;
+
+ bool m_shouldPrintWhenFinishedLoading;
+ Frame* m_frame;
+ mutable RefPtr<Screen> m_screen;
+ mutable RefPtr<DOMSelection> m_selection;
+ mutable RefPtr<History> m_history;
+ mutable RefPtr<BarInfo> m_locationbar;
+ mutable RefPtr<BarInfo> m_menubar;
+ mutable RefPtr<BarInfo> m_personalbar;
+ mutable RefPtr<BarInfo> m_scrollbars;
+ mutable RefPtr<BarInfo> m_statusbar;
+ mutable RefPtr<BarInfo> m_toolbar;
+ mutable RefPtr<Console> m_console;
+ mutable RefPtr<Navigator> m_navigator;
+ mutable RefPtr<Location> m_location;
+ mutable RefPtr<StyleMedia> m_media;
+
+ EventTargetData m_eventTargetData;
+
+ String m_status;
+ String m_defaultStatus;
+
+#if ENABLE(DOM_STORAGE)
+ mutable RefPtr<Storage> m_sessionStorage;
+ mutable RefPtr<Storage> m_localStorage;
+#endif
+
+#if ENABLE(INDEXED_DATABASE)
+ mutable RefPtr<IDBFactory> m_idbFactory;
+#endif
+
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ mutable RefPtr<DOMApplicationCache> m_applicationCache;
+#endif
+
+#if ENABLE(NOTIFICATIONS)
+ mutable RefPtr<NotificationCenter> m_notifications;
+#endif
+
+#if ENABLE(WEB_TIMING)
+ mutable RefPtr<Performance> m_performance;
+#endif
+ };
+
+ inline String DOMWindow::status() const
+ {
+ return m_status;
+ }
+
+ inline String DOMWindow::defaultStatus() const
+ {
+ return m_defaultStatus;
+ }
+
+} // namespace WebCore
+
+#endif // DOMWindow_h
diff --git a/Source/WebCore/page/DOMWindow.idl b/Source/WebCore/page/DOMWindow.idl
new file mode 100644
index 0000000..5aab15e
--- /dev/null
+++ b/Source/WebCore/page/DOMWindow.idl
@@ -0,0 +1,796 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module window {
+
+ interface [
+ CheckDomainSecurity,
+ CustomDefineGetter,
+ CustomDefineSetter,
+ CustomDeleteProperty,
+ CustomGetOwnPropertySlot,
+ CustomGetPropertyNames,
+ CustomLookupGetter,
+ CustomLookupSetter,
+ CustomMarkFunction,
+ CustomNativeConverter,
+ CustomPutFunction,
+ EventTarget,
+ ExtendsDOMGlobalObject,
+ GenerateNativeConverter,
+ ReplaceableConstructor,
+ LegacyParent=JSDOMWindowBase
+ ] DOMWindow {
+ // DOM Level 0
+ attribute [Replaceable] Screen screen;
+ readonly attribute [DoNotCheckDomainSecurity, JSCCustomGetter] History history;
+ attribute [Replaceable] BarInfo locationbar;
+ attribute [Replaceable] BarInfo menubar;
+ attribute [Replaceable] BarInfo personalbar;
+ attribute [Replaceable] BarInfo scrollbars;
+ attribute [Replaceable] BarInfo statusbar;
+ attribute [Replaceable] BarInfo toolbar;
+ attribute [Replaceable] Navigator navigator;
+ attribute [Replaceable] Navigator clientInformation;
+ attribute [DoNotCheckDomainSecurity, JSCCustom, V8CustomSetter, V8DisallowShadowing, CPPCustom] Location location;
+
+ attribute [Replaceable, CustomGetter, V8CustomSetter] Event event;
+
+ readonly attribute [Custom] Crypto crypto;
+
+ DOMSelection getSelection();
+
+ readonly attribute [CheckNodeSecurity] Element frameElement;
+
+ [DoNotCheckDomainSecurity] void focus();
+ [DoNotCheckDomainSecurity] void blur();
+ [DoNotCheckDomainSecurity, CallWith=ScriptExecutionContext] void close();
+
+ void print();
+ void stop();
+
+ [Custom] DOMWindow open(in DOMString url,
+ in DOMString name,
+ in [Optional] DOMString options);
+
+ [Custom] DOMObject showModalDialog(in DOMString url,
+ in [Optional] DOMObject dialogArgs,
+ in [Optional] DOMString featureArgs);
+
+ void alert(in DOMString message);
+ boolean confirm(in DOMString message);
+ [ConvertNullStringTo=Null] DOMString prompt(in DOMString message,
+ in [ConvertUndefinedOrNullToNullString] DOMString defaultValue);
+
+ boolean find(in DOMString string,
+ in boolean caseSensitive,
+ in boolean backwards,
+ in boolean wrap,
+ in boolean wholeWord,
+ in boolean searchInFrames,
+ in boolean showDialog);
+
+ attribute [Replaceable] boolean offscreenBuffering;
+
+ attribute [Replaceable] long outerHeight;
+ attribute [Replaceable] long outerWidth;
+ attribute [Replaceable] long innerHeight;
+ attribute [Replaceable] long innerWidth;
+ attribute [Replaceable] long screenX;
+ attribute [Replaceable] long screenY;
+ attribute [Replaceable] long screenLeft;
+ attribute [Replaceable] long screenTop;
+ attribute [Replaceable] long scrollX;
+ attribute [Replaceable] long scrollY;
+ readonly attribute long pageXOffset;
+ readonly attribute long pageYOffset;
+
+ [RequiresAllArguments] void scrollBy(in long x, in long y);
+ [RequiresAllArguments] void scrollTo(in long x, in long y);
+ [RequiresAllArguments] void scroll(in long x, in long y);
+ [RequiresAllArguments] void moveBy(in float x, in float y); // FIXME: this should take longs not floats.
+ [RequiresAllArguments] void moveTo(in float x, in float y); // FIXME: this should take longs not floats.
+ [RequiresAllArguments] void resizeBy(in float x, in float y); // FIXME: this should take longs not floats.
+ [RequiresAllArguments] void resizeTo(in float width, in float height); // FIXME: this should take longs not floats.
+
+ readonly attribute [DoNotCheckDomainSecurity] boolean closed;
+
+ attribute [Replaceable, DoNotCheckDomainSecurityOnGet] unsigned long length;
+
+ attribute DOMString name;
+
+ attribute DOMString status;
+ attribute DOMString defaultStatus;
+#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
+ // This attribute is an alias of defaultStatus and is necessary for legacy uses.
+ attribute DOMString defaultstatus;
+#endif
+
+ // Self referential attributes
+ attribute [Replaceable, DoNotCheckDomainSecurityOnGet] DOMWindow self;
+ readonly attribute [DoNotCheckDomainSecurity, V8DisallowShadowing] DOMWindow window;
+ attribute [Replaceable, DoNotCheckDomainSecurityOnGet] DOMWindow frames;
+
+ attribute [Replaceable, DoNotCheckDomainSecurityOnGet, V8CustomSetter] DOMWindow opener;
+ attribute [Replaceable, DoNotCheckDomainSecurityOnGet] DOMWindow parent;
+ attribute [Replaceable, DoNotCheckDomainSecurityOnGet, V8DisallowShadowing, V8ReadOnly] DOMWindow top;
+
+ // DOM Level 2 AbstractView Interface
+ 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
+ CSSStyleDeclaration getComputedStyle(in Element element,
+ in [ConvertUndefinedOrNullToNullString] DOMString pseudoElement);
+
+ // WebKit extensions
+#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
+ CSSRuleList getMatchedCSSRules(in Element element,
+ in DOMString pseudoElement);
+#endif
+
+ attribute [Replaceable] double devicePixelRatio;
+
+ WebKitPoint webkitConvertPointFromPageToNode(in Node node, in WebKitPoint p);
+ WebKitPoint webkitConvertPointFromNodeToPage(in Node node, in WebKitPoint p);
+
+#if defined(ENABLE_OFFLINE_WEB_APPLICATIONS) && ENABLE_OFFLINE_WEB_APPLICATIONS
+ readonly attribute [EnabledAtRuntime] DOMApplicationCache applicationCache;
+#endif
+#if defined(ENABLE_DATABASE) && ENABLE_DATABASE
+ [EnabledAtRuntime, RequiresAllArguments=Raise] Database openDatabase(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize, in [Callback, Optional] DatabaseCallback creationCallback)
+ raises(DOMException);
+#endif
+#if defined(ENABLE_DOM_STORAGE) && ENABLE_DOM_STORAGE
+ readonly attribute [EnabledAtRuntime] Storage sessionStorage
+ getter raises(DOMException);
+ readonly attribute [EnabledAtRuntime] Storage localStorage
+ getter raises(DOMException);
+#endif
+#if defined(ENABLE_NOTIFICATIONS) && ENABLE_NOTIFICATIONS
+ readonly attribute [EnabledAtRuntime] NotificationCenter webkitNotifications;
+#endif
+#if defined(ENABLE_INDEXED_DATABASE) && ENABLE_INDEXED_DATABASE
+ readonly attribute [EnabledAtRuntime] IDBFactory webkitIndexedDB;
+
+ attribute [EnabledAtRuntime] IDBCursorConstructor webkitIDBCursor;
+ attribute [EnabledAtRuntime] IDBDatabaseConstructor webkitIDBDatabase;
+ attribute [EnabledAtRuntime] IDBDatabaseErrorConstructor webkitIDBDatabaseError;
+ attribute [EnabledAtRuntime] IDBDatabaseExceptionConstructor webkitIDBDatabaseException;
+ attribute [EnabledAtRuntime] IDBErrorEventConstructor webkitIDBErrorEvent;
+ attribute [EnabledAtRuntime] IDBEventConstructor webkitIDBEvent;
+ attribute [EnabledAtRuntime] IDBFactoryConstructor webkitIDBFactory;
+ attribute [EnabledAtRuntime] IDBIndexConstructor webkitIDBIndex;
+ attribute [EnabledAtRuntime] IDBKeyRangeConstructor webkitIDBKeyRange;
+ attribute [EnabledAtRuntime] IDBObjectStoreConstructor webkitIDBObjectStore;
+ attribute [EnabledAtRuntime] IDBRequestConstructor webkitIDBRequest;
+ attribute [EnabledAtRuntime] IDBSuccessEventConstructor webkitIDBSuccessEvent;
+ attribute [EnabledAtRuntime] IDBTransactionConstructor webkitIDBTransaction;
+#endif
+#if defined(ENABLE_FILE_SYSTEM) && ENABLE_FILE_SYSTEM
+ const unsigned short TEMPORARY = 0;
+ const unsigned short PERSISTENT = 1;
+ [EnabledAtRuntime=FileSystem] void requestFileSystem(in unsigned short type, in long long size, in [Callback, Optional] FileSystemCallback successCallback, in [Callback, Optional] ErrorCallback errorCallback);
+
+ attribute [EnabledAtRuntime=FileSystem] FlagsConstructor Flags;
+#endif
+
+#if defined(ENABLE_ORIENTATION_EVENTS) && ENABLE_ORIENTATION_EVENTS
+ // This is the interface orientation in degrees. Some examples are:
+ // 0 is straight up; -90 is when the device is rotated 90 clockwise;
+ // 90 is when rotated counter clockwise.
+ readonly attribute long orientation;
+#endif
+
+ attribute [Replaceable] Console console;
+
+ // cross-document messaging
+#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
+ [DoNotCheckDomainSecurity, Custom] void postMessage(in SerializedScriptValue message, in [Optional] Array messagePorts, in DOMString targetOrigin)
+ raises(DOMException);
+#else
+ // There's no good way to expose an array via the ObjC bindings, so for now just allow passing in a single port.
+ [DoNotCheckDomainSecurity, Custom] void postMessage(in SerializedScriptValue message, in [Optional] MessagePort messagePort, in DOMString targetOrigin)
+ raises(DOMException);
+#endif
+
+#if defined(ENABLE_WEB_TIMING) && ENABLE_WEB_TIMING
+ attribute [Replaceable] Performance performance;
+#endif
+
+ // Timers
+ [Custom] long setTimeout(in TimeoutHandler handler, in long timeout);
+ // [Custom] long setTimeout(in TimeoutHandler handler, in long timeout, arguments...);
+ // [Custom] long setTimeout(in DOMString code, in long timeout);
+ void clearTimeout(in long handle);
+ [Custom] long setInterval(in TimeoutHandler handler, in long timeout);
+ // [Custom] long setInterval(in TimeoutHandler handler, in long timeout, arguments...);
+ // [Custom] long setInterval(in DOMString code, in long timeout);
+ void clearInterval(in long handle);
+
+ // Base64
+ DOMString atob(in [ConvertNullToNullString] DOMString string)
+ raises(DOMException);
+ DOMString btoa(in [ConvertNullToNullString] DOMString string)
+ raises(DOMException);
+
+ // Events
+
+ attribute EventListener onabort;
+ attribute EventListener onbeforeunload;
+ attribute EventListener onblur;
+ attribute EventListener oncanplay;
+ attribute EventListener oncanplaythrough;
+ attribute EventListener onchange;
+ attribute EventListener onclick;
+ attribute EventListener oncontextmenu;
+ attribute EventListener ondblclick;
+ attribute EventListener ondrag;
+ attribute EventListener ondragend;
+ attribute EventListener ondragenter;
+ attribute EventListener ondragleave;
+ attribute EventListener ondragover;
+ attribute EventListener ondragstart;
+ attribute EventListener ondrop;
+ attribute EventListener ondurationchange;
+ attribute EventListener onemptied;
+ attribute EventListener onended;
+ attribute EventListener onerror;
+ attribute EventListener onfocus;
+ attribute EventListener onhashchange;
+ attribute EventListener oninput;
+ attribute EventListener oninvalid;
+ attribute EventListener onkeydown;
+ attribute EventListener onkeypress;
+ attribute EventListener onkeyup;
+ attribute EventListener onload;
+ attribute EventListener onloadeddata;
+ attribute EventListener onloadedmetadata;
+ attribute EventListener onloadstart;
+ attribute EventListener onmessage;
+ attribute EventListener onmousedown;
+ attribute EventListener onmousemove;
+ attribute EventListener onmouseout;
+ attribute EventListener onmouseover;
+ attribute EventListener onmouseup;
+ attribute EventListener onmousewheel;
+ attribute EventListener onoffline;
+ attribute EventListener ononline;
+ attribute EventListener onpagehide;
+ attribute EventListener onpageshow;
+ attribute EventListener onpause;
+ attribute EventListener onplay;
+ attribute EventListener onplaying;
+ attribute EventListener onpopstate;
+ attribute EventListener onprogress;
+ attribute EventListener onratechange;
+ attribute EventListener onresize;
+ attribute EventListener onscroll;
+ attribute EventListener onseeked;
+ attribute EventListener onseeking;
+ attribute EventListener onselect;
+ attribute EventListener onstalled;
+ attribute EventListener onstorage;
+ attribute EventListener onsubmit;
+ attribute EventListener onsuspend;
+ attribute EventListener ontimeupdate;
+ attribute EventListener onunload;
+ attribute EventListener onvolumechange;
+ attribute EventListener onwaiting;
+
+ // Not implemented yet.
+ // attribute EventListener onafterprint;
+ // attribute EventListener onbeforeprint;
+ // attribute EventListener onformchange;
+ // attribute EventListener onforminput;
+ // attribute EventListener onreadystatechange;
+ // attribute EventListener onredo;
+ // attribute EventListener onshow;
+ // attribute EventListener onundo;
+
+ // Webkit extensions
+ attribute EventListener onreset;
+ attribute EventListener onsearch;
+ attribute EventListener onwebkitanimationend;
+ attribute EventListener onwebkitanimationiteration;
+ attribute EventListener onwebkitanimationstart;
+ attribute EventListener onwebkittransitionend;
+#if defined(ENABLE_ORIENTATION_EVENTS) && ENABLE_ORIENTATION_EVENTS
+ attribute EventListener onorientationchange;
+#endif
+ attribute [Conditional=TOUCH_EVENTS,EnabledAtRuntime] EventListener ontouchstart;
+ attribute [Conditional=TOUCH_EVENTS,EnabledAtRuntime] EventListener ontouchmove;
+ attribute [Conditional=TOUCH_EVENTS,EnabledAtRuntime] EventListener ontouchend;
+ attribute [Conditional=TOUCH_EVENTS,EnabledAtRuntime] EventListener ontouchcancel;
+
+ attribute [Conditional=DEVICE_ORIENTATION,EnabledAtRuntime] DeviceMotionEventConstructor DeviceMotionEvent;
+ attribute [Conditional=DEVICE_ORIENTATION,EnabledAtRuntime] EventListener ondevicemotion;
+ attribute [Conditional=DEVICE_ORIENTATION,EnabledAtRuntime] DeviceOrientationEventConstructor DeviceOrientationEvent;
+ attribute [Conditional=DEVICE_ORIENTATION,EnabledAtRuntime] EventListener ondeviceorientation;
+
+ // EventTarget interface
+ [Custom] void addEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ [Custom] void removeEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ boolean dispatchEvent(in Event evt)
+ raises(EventException);
+
+ [V8Custom=DOMWindowNOP] void captureEvents(/*in long eventFlags*/);
+ [V8Custom=DOMWindowNOP] void releaseEvents(/*in long eventFlags*/);
+
+#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
+ // Global constructors
+ attribute StyleSheetConstructor StyleSheet;
+ attribute CSSStyleSheetConstructor CSSStyleSheet;
+
+ attribute CSSValueConstructor CSSValue;
+ attribute CSSPrimitiveValueConstructor CSSPrimitiveValue;
+ attribute CSSValueListConstructor CSSValueList;
+ attribute WebKitCSSTransformValueConstructor WebKitCSSTransformValue;
+
+ attribute CSSRuleConstructor CSSRule;
+ attribute CSSCharsetRuleConstructor CSSCharsetRule;
+ attribute CSSFontFaceRuleConstructor CSSFontFaceRule;
+ attribute CSSImportRuleConstructor CSSImportRule;
+ attribute CSSMediaRuleConstructor CSSMediaRule;
+ attribute CSSPageRuleConstructor CSSPageRule;
+ attribute CSSStyleRuleConstructor CSSStyleRule;
+
+ attribute CSSStyleDeclarationConstructor CSSStyleDeclaration;
+ attribute MediaListConstructor MediaList;
+ attribute CounterConstructor Counter;
+ attribute CSSRuleListConstructor CSSRuleList;
+ attribute RectConstructor Rect;
+ attribute RGBColorConstructor RGBColor;
+ attribute StyleSheetListConstructor StyleSheetList;
+
+ // FIXME: Implement the commented-out global constructors for interfaces listed in DOM Level 3 Core specification.
+ attribute DOMCoreExceptionConstructor DOMException;
+ attribute DOMStringListConstructor DOMStringList;
+// attribute NameListConstructor NameList;
+// attribute DOMImplementationListConstructor DOMImplementationList;
+// attribute DOMImplementationSourceConstructor DOMImplementationSource;
+ attribute DOMImplementationConstructor DOMImplementation;
+ attribute DOMSettableTokenListConstructor DOMSettableTokenList;
+ attribute DOMTokenListConstructor DOMTokenList;
+ attribute DocumentFragmentConstructor DocumentFragment;
+ attribute DocumentConstructor Document;
+ attribute NodeConstructor Node;
+ attribute NodeListConstructor NodeList;
+ attribute NamedNodeMapConstructor NamedNodeMap;
+ attribute CharacterDataConstructor CharacterData;
+ attribute AttrConstructor Attr;
+ attribute ElementConstructor Element;
+ attribute TextConstructor Text;
+ attribute CommentConstructor Comment;
+// attribute TypeInfoConstructor TypeInfo;
+// attribute UserDataHandlerConstructor UserDataHandler;
+// attribute DOMErrorConstructor DOMError;
+// attribute DOMErrorHandlerConstructor DOMErrorHandler
+// attribute DOMLocatorConstructor DOMLocator;
+// attribute DOMConfigurationConstructor DOMConfiguration;
+ attribute CDATASectionConstructor CDATASection;
+ attribute DocumentTypeConstructor DocumentType;
+ attribute NotationConstructor Notation;
+ attribute EntityConstructor Entity;
+ attribute EntityReferenceConstructor EntityReference;
+ attribute ProcessingInstructionConstructor ProcessingInstruction;
+
+ attribute HTMLDocumentConstructor HTMLDocument;
+
+ attribute HTMLElementConstructor HTMLElement;
+ attribute HTMLAnchorElementConstructor HTMLAnchorElement;
+ attribute HTMLAppletElementConstructor HTMLAppletElement;
+ attribute HTMLAreaElementConstructor HTMLAreaElement;
+ attribute HTMLBRElementConstructor HTMLBRElement;
+ attribute HTMLBaseElementConstructor HTMLBaseElement;
+ attribute HTMLBaseFontElementConstructor HTMLBaseFontElement;
+ attribute HTMLBlockquoteElementConstructor HTMLBlockquoteElement;
+ attribute HTMLBodyElementConstructor HTMLBodyElement;
+ attribute HTMLButtonElementConstructor HTMLButtonElement;
+ attribute HTMLCanvasElementConstructor HTMLCanvasElement;
+ attribute [Conditional=DATAGRID] HTMLDataGridElementConstructor HTMLDataGridElement;
+ attribute [Conditional=DATAGRID] HTMLDataGridCellElementConstructor HTMLDataGridCellElement;
+ attribute [Conditional=DATAGRID] HTMLDataGridColElementConstructor HTMLDataGridColElement;
+ attribute HTMLDListElementConstructor HTMLDListElement;
+ attribute HTMLDirectoryElementConstructor HTMLDirectoryElement;
+ attribute HTMLDivElementConstructor HTMLDivElement;
+ attribute HTMLEmbedElementConstructor HTMLEmbedElement;
+ attribute HTMLFieldSetElementConstructor HTMLFieldSetElement;
+ attribute HTMLFontElementConstructor HTMLFontElement;
+ attribute HTMLFormElementConstructor HTMLFormElement;
+ attribute HTMLFrameElementConstructor HTMLFrameElement;
+ attribute HTMLFrameSetElementConstructor HTMLFrameSetElement;
+ attribute HTMLHRElementConstructor HTMLHRElement;
+ attribute HTMLHeadElementConstructor HTMLHeadElement;
+ attribute HTMLHeadingElementConstructor HTMLHeadingElement;
+ attribute HTMLHtmlElementConstructor HTMLHtmlElement;
+ attribute HTMLIFrameElementConstructor HTMLIFrameElement;
+ attribute HTMLImageElementConstructor HTMLImageElement;
+ attribute HTMLInputElementConstructor HTMLInputElement;
+ attribute HTMLIsIndexElementConstructor HTMLIsIndexElement;
+ attribute HTMLLIElementConstructor HTMLLIElement;
+ attribute HTMLLabelElementConstructor HTMLLabelElement;
+ attribute HTMLLegendElementConstructor HTMLLegendElement;
+ attribute HTMLLinkElementConstructor HTMLLinkElement;
+ attribute HTMLMapElementConstructor HTMLMapElement;
+ attribute HTMLMarqueeElementConstructor HTMLMarqueeElement;
+ attribute HTMLMenuElementConstructor HTMLMenuElement;
+ attribute HTMLMetaElementConstructor HTMLMetaElement;
+#if defined(ENABLE_METER_TAG) && ENABLE_METER_TAG
+ attribute HTMLMeterElementConstructor HTMLMeterElement;
+#endif
+ attribute HTMLModElementConstructor HTMLModElement;
+ attribute HTMLOListElementConstructor HTMLOListElement;
+ attribute HTMLObjectElementConstructor HTMLObjectElement;
+ attribute HTMLOptGroupElementConstructor HTMLOptGroupElement;
+ attribute HTMLOptionElementConstructor HTMLOptionElement;
+ attribute HTMLOutputElementConstructor HTMLOutputElement;
+ attribute HTMLParagraphElementConstructor HTMLParagraphElement;
+ attribute HTMLParamElementConstructor HTMLParamElement;
+ attribute HTMLPreElementConstructor HTMLPreElement;
+#if defined(ENABLE_PROGRESS_TAG) && ENABLE_PROGRESS_TAG
+ attribute HTMLProgressElementConstructor HTMLProgressElement;
+#endif
+ attribute HTMLQuoteElementConstructor HTMLQuoteElement;
+ attribute HTMLScriptElementConstructor HTMLScriptElement;
+ attribute HTMLSelectElementConstructor HTMLSelectElement;
+ attribute HTMLStyleElementConstructor HTMLStyleElement;
+ attribute HTMLTableCaptionElementConstructor HTMLTableCaptionElement;
+ attribute HTMLTableCellElementConstructor HTMLTableCellElement;
+ attribute HTMLTableColElementConstructor HTMLTableColElement;
+ attribute HTMLTableElementConstructor HTMLTableElement;
+ attribute HTMLTableRowElementConstructor HTMLTableRowElement;
+ attribute HTMLTableSectionElementConstructor HTMLTableSectionElement;
+ attribute HTMLTextAreaElementConstructor HTMLTextAreaElement;
+ attribute HTMLTitleElementConstructor HTMLTitleElement;
+ attribute HTMLUListElementConstructor HTMLUListElement;
+
+ attribute HTMLCollectionConstructor HTMLCollection;
+ attribute HTMLAllCollectionConstructor HTMLAllCollection;
+
+ attribute [CustomGetter] HTMLImageElementConstructor Image; // Usable with new operator
+ attribute [CustomGetter] HTMLOptionElementConstructor Option; // Usable with new operator
+
+ attribute CanvasPatternConstructor CanvasPattern;
+ attribute CanvasGradientConstructor CanvasGradient;
+ attribute CanvasRenderingContext2DConstructor CanvasRenderingContext2D;
+ attribute ImageDataConstructor ImageData;
+ attribute [Conditional=3D_CANVAS,EnabledAtRuntime] WebGLActiveInfoConstructor WebGLActiveInfo;
+ attribute [Conditional=3D_CANVAS,EnabledAtRuntime] WebGLBufferConstructor WebGLBuffer;
+ attribute [Conditional=3D_CANVAS,EnabledAtRuntime] WebGLFramebufferConstructor WebGLFramebuffer;
+ attribute [Conditional=3D_CANVAS,EnabledAtRuntime] WebGLProgramConstructor WebGLProgram;
+ attribute [Conditional=3D_CANVAS,EnabledAtRuntime] WebGLRenderbufferConstructor WebGLRenderbuffer;
+ attribute [Conditional=3D_CANVAS,EnabledAtRuntime] WebGLRenderingContextConstructor WebGLRenderingContext;
+ attribute [Conditional=3D_CANVAS,EnabledAtRuntime] WebGLShaderConstructor WebGLShader;
+ attribute [Conditional=3D_CANVAS,EnabledAtRuntime] WebGLTextureConstructor WebGLTexture;
+ attribute [Conditional=3D_CANVAS,EnabledAtRuntime] WebGLUniformLocationConstructor WebGLUniformLocation;
+ attribute TextMetricsConstructor TextMetrics;
+
+ attribute DOMStringMapConstructor DOMStringMap;
+
+ attribute [JSCCustomGetter,Conditional=3D_CANVAS|BLOB,EnabledAtRuntime] ArrayBufferConstructor ArrayBuffer; // Usable with new operator
+ attribute [JSCCustomGetter,Conditional=3D_CANVAS|BLOB,EnabledAtRuntime] Int8ArrayConstructor Int8Array; // Usable with new operator
+ attribute [JSCCustomGetter,Conditional=3D_CANVAS|BLOB,EnabledAtRuntime] Uint8ArrayConstructor Uint8Array; // Usable with new operator
+ attribute [JSCCustomGetter,Conditional=3D_CANVAS|BLOB,EnabledAtRuntime] Int16ArrayConstructor Int16Array; // Usable with new operator
+ attribute [JSCCustomGetter,Conditional=3D_CANVAS|BLOB,EnabledAtRuntime] Uint16ArrayConstructor Uint16Array; // Usable with new operator
+ 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 [JSCCustomGetter,Conditional=WEB_AUDIO] AudioContextConstructor webkitAudioContext; // Usable with new operator
+ attribute [Conditional=WEB_AUDIO] AudioPannerNodeConstructor webkitAudioPannerNode; // Needed for panning model constants
+
+ attribute EventConstructor Event;
+ attribute BeforeLoadEventConstructor BeforeLoadEvent;
+ attribute HashChangeEventConstructor HashChangeEvent;
+ attribute KeyboardEventConstructor KeyboardEvent;
+ attribute MouseEventConstructor MouseEvent;
+ attribute MutationEventConstructor MutationEvent;
+ attribute OverflowEventConstructor OverflowEvent;
+ attribute PageTransitionEventConstructor PageTransitionEvent;
+ attribute ProgressEventConstructor ProgressEvent;
+ attribute TextEventConstructor TextEvent;
+ attribute UIEventConstructor UIEvent;
+ attribute WebKitAnimationEventConstructor WebKitAnimationEvent;
+ attribute WebKitTransitionEventConstructor WebKitTransitionEvent;
+ attribute WheelEventConstructor WheelEvent;
+ attribute MessageEventConstructor MessageEvent;
+ attribute EventExceptionConstructor EventException;
+
+ attribute WebKitCSSKeyframeRuleConstructor WebKitCSSKeyframeRule;
+ attribute WebKitCSSKeyframesRuleConstructor WebKitCSSKeyframesRule;
+
+ attribute [JSCCustomGetter] WebKitCSSMatrixConstructor WebKitCSSMatrix; // Usable with the new operator
+
+ attribute [JSCCustomGetter] WebKitPointConstructor WebKitPoint; // Usable with new the operator
+
+ attribute ClipboardConstructor Clipboard;
+
+ attribute FileConstructor File;
+ attribute FileListConstructor FileList;
+ attribute BlobConstructor Blob;
+
+ attribute NodeFilterConstructor NodeFilter;
+ attribute RangeConstructor Range;
+ attribute RangeExceptionConstructor RangeException;
+
+#if ENABLE_EVENTSOURCE
+ attribute [JSCCustomGetter] EventSourceConstructor EventSource; // Usable with new the operator
+#endif
+
+ // Mozilla has a separate XMLDocument object for XML documents.
+ // We just use Document for this.
+ attribute DocumentConstructor XMLDocument;
+
+ attribute DOMParserConstructor DOMParser;
+ attribute XMLSerializerConstructor XMLSerializer;
+
+ attribute [JSCCustomGetter] XMLHttpRequestConstructor XMLHttpRequest; // Usable with the new operator
+ attribute XMLHttpRequestUploadConstructor XMLHttpRequestUpload;
+ attribute XMLHttpRequestExceptionConstructor XMLHttpRequestException;
+
+ attribute [JSCCustomGetter,Conditional=XSLT] XSLTProcessorConstructor XSLTProcessor; // Usable with the new operator
+
+#if defined(ENABLE_CHANNEL_MESSAGING) && ENABLE_CHANNEL_MESSAGING
+ attribute MessagePortConstructor MessagePort;
+ attribute [JSCCustomGetter] MessageChannelConstructor MessageChannel; // Usable with the new operator
+#endif
+
+#if defined(ENABLE_WORKERS) && ENABLE_WORKERS
+ attribute [JSCCustomGetter] WorkerConstructor Worker; // Usable with the new operator
+#endif
+
+#if defined(ENABLE_SHARED_WORKERS) && ENABLE_SHARED_WORKERS
+ attribute [JSCCustomGetter, EnabledAtRuntime] SharedWorkerConstructor SharedWorker; // Usable with the new operator
+#endif
+
+#if defined(ENABLE_WEB_SOCKETS) && ENABLE_WEB_SOCKETS
+ attribute [JSCCustomGetter,EnabledAtRuntime] WebSocketConstructor WebSocket; // Usable with the new operator
+#endif
+
+ attribute DOMPluginConstructor Plugin;
+ attribute DOMPluginArrayConstructor PluginArray;
+
+ attribute DOMMimeTypeConstructor MimeType;
+ attribute DOMMimeTypeArrayConstructor MimeTypeArray;
+
+ attribute ClientRectConstructor ClientRect;
+ attribute ClientRectListConstructor ClientRectList;
+
+#if defined(ENABLE_DOM_STORAGE) && ENABLE_DOM_STORAGE
+ attribute StorageConstructor Storage;
+ attribute StorageEventConstructor StorageEvent;
+#endif
+
+ attribute [CustomGetter, Conditional=VIDEO, EnabledAtRuntime] HTMLAudioElementConstructor Audio; // Usable with the new operator
+ attribute [Conditional=VIDEO, EnabledAtRuntime] HTMLAudioElementConstructor HTMLAudioElement;
+ attribute [Conditional=VIDEO, EnabledAtRuntime] HTMLMediaElementConstructor HTMLMediaElement;
+ attribute [Conditional=VIDEO, EnabledAtRuntime] HTMLVideoElementConstructor HTMLVideoElement;
+ attribute [Conditional=VIDEO, EnabledAtRuntime] MediaErrorConstructor MediaError;
+ attribute [Conditional=VIDEO, EnabledAtRuntime] TimeRangesConstructor TimeRanges;
+
+#if defined(ENABLE_XPATH) && ENABLE_XPATH
+ attribute XPathEvaluatorConstructor XPathEvaluator;
+ attribute XPathResultConstructor XPathResult;
+ attribute XPathExceptionConstructor XPathException;
+#endif
+
+#if defined(ENABLE_SVG) && ENABLE_SVG
+ // Expose all implemented SVG 1.1 interfaces, excluding the SVG MI interfaces:
+ // SVGAnimatedPathData, SVGAnimatedPoints, SVGExternalResourcesRequired,
+ // SVGFilterPrimitiveStandardAttributes, SVGFitToViewBox, SVGLangSpace, SVGLocatable
+ // SVGStylable, SVGTests, SVGTransformable, SVGURIReference, SVGZoomAndPan
+ attribute SVGAElementConstructor SVGAElement;
+ attribute SVGAngleConstructor SVGAngle;
+ attribute SVGAnimatedAngleConstructor SVGAnimatedAngle;
+ attribute SVGAnimatedBooleanConstructor SVGAnimatedBoolean;
+ attribute SVGAnimatedEnumerationConstructor SVGAnimatedEnumeration;
+ attribute SVGAnimatedIntegerConstructor SVGAnimatedInteger;
+ attribute SVGAnimatedLengthConstructor SVGAnimatedLength;
+ attribute SVGAnimatedLengthListConstructor SVGAnimatedLengthList;
+ attribute SVGAnimatedNumberConstructor SVGAnimatedNumber;
+ attribute SVGAnimatedNumberListConstructor SVGAnimatedNumberList;
+ attribute SVGAnimatedPreserveAspectRatioConstructor SVGAnimatedPreserveAspectRatio;
+ attribute SVGAnimatedRectConstructor SVGAnimatedRect;
+ attribute SVGAnimatedStringConstructor SVGAnimatedString;
+ attribute SVGAnimatedTransformListConstructor SVGAnimatedTransformList;
+ attribute SVGCircleElementConstructor SVGCircleElement;
+ attribute SVGClipPathElementConstructor SVGClipPathElement;
+ attribute SVGColorConstructor SVGColor;
+ attribute SVGCursorElementConstructor SVGCursorElement;
+// attribute SVGCSSRuleConstructor SVGCSSRule;
+ attribute SVGDefsElementConstructor SVGDefsElement;
+ attribute SVGDescElementConstructor SVGDescElement;
+ attribute SVGDocumentConstructor SVGDocument;
+ attribute SVGElementConstructor SVGElement;
+ attribute SVGElementInstanceConstructor SVGElementInstance;
+ attribute SVGElementInstanceListConstructor SVGElementInstanceList;
+ attribute SVGEllipseElementConstructor SVGEllipseElement;
+ attribute SVGExceptionConstructor SVGException;
+ attribute SVGGElementConstructor SVGGElement;
+ attribute SVGGradientElementConstructor SVGGradientElement;
+ attribute SVGImageElementConstructor SVGImageElement;
+ attribute SVGLengthConstructor SVGLength;
+ attribute SVGLengthListConstructor SVGLengthList;
+ attribute SVGLinearGradientElementConstructor SVGLinearGradientElement;
+ attribute SVGLineElementConstructor SVGLineElement;
+ attribute SVGMarkerElementConstructor SVGMarkerElement;
+ attribute SVGMaskElementConstructor SVGMaskElement;
+ attribute SVGMatrixConstructor SVGMatrix;
+ attribute SVGMetadataElementConstructor SVGMetadataElement;
+ attribute SVGNumberConstructor SVGNumber;
+ attribute SVGNumberListConstructor SVGNumberList;
+ attribute SVGPaintConstructor SVGPaint;
+ attribute SVGPathElementConstructor SVGPathElement;
+ attribute SVGPathSegConstructor SVGPathSeg;
+ attribute SVGPathSegArcAbsConstructor SVGPathSegArcAbs;
+ attribute SVGPathSegArcRelConstructor SVGPathSegArcRel;
+ attribute SVGPathSegClosePathConstructor SVGPathSegClosePath;
+ attribute SVGPathSegCurvetoCubicAbsConstructor SVGPathSegCurvetoCubicAbs;
+ attribute SVGPathSegCurvetoCubicRelConstructor SVGPathSegCurvetoCubicRel;
+ attribute SVGPathSegCurvetoCubicSmoothAbsConstructor SVGPathSegCurvetoCubicSmoothAbs;
+ attribute SVGPathSegCurvetoCubicSmoothRelConstructor SVGPathSegCurvetoCubicSmoothRel;
+ attribute SVGPathSegCurvetoQuadraticAbsConstructor SVGPathSegCurvetoQuadraticAbs;
+ attribute SVGPathSegCurvetoQuadraticRelConstructor SVGPathSegCurvetoQuadraticRel;
+ attribute SVGPathSegCurvetoQuadraticSmoothAbsConstructor SVGPathSegCurvetoQuadraticSmoothAbs;
+ attribute SVGPathSegCurvetoQuadraticSmoothRelConstructor SVGPathSegCurvetoQuadraticSmoothRel;
+ attribute SVGPathSegLinetoAbsConstructor SVGPathSegLinetoAbs;
+ attribute SVGPathSegLinetoHorizontalAbsConstructor SVGPathSegLinetoHorizontalAbs;
+ attribute SVGPathSegLinetoHorizontalRelConstructor SVGPathSegLinetoHorizontalRel;
+ attribute SVGPathSegLinetoRelConstructor SVGPathSegLinetoRel;
+ attribute SVGPathSegLinetoVerticalAbsConstructor SVGPathSegLinetoVerticalAbs;
+ attribute SVGPathSegLinetoVerticalRelConstructor SVGPathSegLinetoVerticalRel;
+ attribute SVGPathSegListConstructor SVGPathSegList;
+ attribute SVGPathSegMovetoAbsConstructor SVGPathSegMovetoAbs;
+ attribute SVGPathSegMovetoRelConstructor SVGPathSegMovetoRel;
+ attribute SVGPatternElementConstructor SVGPatternElement;
+ attribute SVGPointConstructor SVGPoint;
+ attribute SVGPointListConstructor SVGPointList;
+ attribute SVGPolygonElementConstructor SVGPolygonElement;
+ attribute SVGPolylineElementConstructor SVGPolylineElement;
+ attribute SVGPreserveAspectRatioConstructor SVGPreserveAspectRatio;
+ attribute SVGRadialGradientElementConstructor SVGRadialGradientElement;
+ attribute SVGRectConstructor SVGRect;
+ attribute SVGRectElementConstructor SVGRectElement;
+ attribute SVGRenderingIntentConstructor SVGRenderingIntent;
+ attribute SVGScriptElementConstructor SVGScriptElement;
+ attribute SVGStopElementConstructor SVGStopElement;
+ attribute SVGStringListConstructor SVGStringList;
+ attribute SVGStyleElementConstructor SVGStyleElement;
+ attribute SVGSVGElementConstructor SVGSVGElement;
+ attribute SVGSwitchElementConstructor SVGSwitchElement;
+ attribute SVGSymbolElementConstructor SVGSymbolElement;
+ attribute SVGTextContentElementConstructor SVGTextContentElement;
+ attribute SVGTextElementConstructor SVGTextElement;
+ attribute SVGTextPathElementConstructor SVGTextPathElement;
+ attribute SVGTextPositioningElementConstructor SVGTextPositioningElement;
+ attribute SVGTitleElementConstructor SVGTitleElement;
+ attribute SVGTransformConstructor SVGTransform;
+ attribute SVGTransformListConstructor SVGTransformList;
+ attribute SVGTRefElementConstructor SVGTRefElement;
+ attribute SVGTSpanElementConstructor SVGTSpanElement;
+ attribute SVGUnitTypesConstructor SVGUnitTypes;
+ attribute SVGUseElementConstructor SVGUseElement;
+ attribute SVGViewElementConstructor SVGViewElement;
+// attribute SVGViewSpecConstructor SVGViewSpec;
+ attribute SVGZoomEventConstructor SVGZoomEvent;
+
+#if defined(ENABLE_SVG_ANIMATION) && ENABLE_SVG_ANIMATION
+ attribute SVGAnimateColorElementConstructor SVGAnimateColorElement;
+ attribute SVGAnimateElementConstructor SVGAnimateElement;
+// attribute SVGAnimateMotionElementConstructor SVGAnimateMotionElement;
+ attribute SVGAnimateTransformElementConstructor SVGAnimateTransformElement;
+// attribute SVGMPathElementConstructor SVGMPathElement;
+ attribute SVGSetElementConstructor SVGSetElement;
+#endif
+
+#if ENABLE_SVG_FONTS && ENABLE_SVG_FONTS
+// attribute SVGAltGlyphDefElementConstructor SVGAltGlyphDefElement;
+ attribute SVGAltGlyphElementConstructor SVGAltGlyphElement;
+// attribute SVGAltGlyphItemElementConstructor SVGAltGlyphItemElement;
+// attribute SVGDefinitionSrcElementConstructor SVGDefinitionSrcElement;
+ attribute SVGFontElementConstructor SVGFontElement;
+ attribute SVGFontFaceElementConstructor SVGFontFaceElement;
+ attribute SVGFontFaceFormatElementConstructor SVGFontFaceFormatElement;
+ attribute SVGFontFaceNameElementConstructor SVGFontFaceNameElement;
+ attribute SVGFontFaceSrcElementConstructor SVGFontFaceSrcElement;
+ attribute SVGFontFaceUriElementConstructor SVGFontFaceUriElement;
+ attribute SVGGlyphElementConstructor SVGGlyphElement;
+// attribute SVGGlyphRefElementConstructor SVGGlyphRefElement;
+ attribute SVGHKernElementConstructor SVGHKernElement;
+ attribute SVGMissingGlyphElementConstructor SVGMissingGlyphElement;
+ attribute SVGVKernElementConstructor SVGVKernElement;
+#endif
+
+#if defined(ENABLE_SVG_FOREIGN_OBJECT) && ENABLE_SVG_FOREIGN_OBJECT
+ attribute SVGForeignObjectElementConstructor SVGForeignObjectElement;
+#endif
+
+#if defined(ENABLE_FILTERS) && ENABLE_FILTERS
+ attribute SVGComponentTransferFunctionElementConstructor SVGComponentTransferFunctionElement;
+ attribute SVGFEBlendElementConstructor SVGFEBlendElement;
+ attribute SVGFEColorMatrixElementConstructor SVGFEColorMatrixElement;
+ attribute SVGFEComponentTransferElementConstructor SVGFEComponentTransferElement;
+ attribute SVGFECompositeElementConstructor SVGFECompositeElement;
+ attribute SVGFEConvolveMatrixElementConstructor SVGFEConvolveMatrixElement;
+ attribute SVGFEDiffuseLightingElementConstructor SVGFEDiffuseLightingElement;
+ attribute SVGFEDisplacementMapElementConstructor SVGFEDisplacementMapElement;
+ attribute SVGFEDistantLightElementConstructor SVGFEDistantLightElement;
+ attribute SVGFEFloodElementConstructor SVGFEFloodElement;
+ attribute SVGFEFuncAElementConstructor SVGFEFuncAElement;
+ attribute SVGFEFuncBElementConstructor SVGFEFuncBElement;
+ attribute SVGFEFuncGElementConstructor SVGFEFuncGElement;
+ attribute SVGFEFuncRElementConstructor SVGFEFuncRElement;
+ attribute SVGFEGaussianBlurElementConstructor SVGFEGaussianBlurElement;
+ attribute SVGFEImageElementConstructor SVGFEImageElement;
+ attribute SVGFEMergeElementConstructor SVGFEMergeElement;
+ attribute SVGFEMergeNodeElementConstructor SVGFEMergeNodeElement;
+ attribute SVGFEMorphologyElementConstructor SVGFEMorphologyElement;
+ attribute SVGFEOffsetElementConstructor SVGFEOffsetElement;
+ attribute SVGFEPointLightElementConstructor SVGFEPointLightElement;
+ attribute SVGFESpecularLightingElementConstructor SVGFESpecularLightingElement;
+ attribute SVGFESpotLightElementConstructor SVGFESpotLightElement;
+ attribute SVGFETileElementConstructor SVGFETileElement;
+ attribute SVGFETurbulenceElementConstructor SVGFETurbulenceElement;
+ attribute SVGFilterElementConstructor SVGFilterElement;
+#endif
+#endif
+
+ attribute [Conditional=DATABASE] SQLExceptionConstructor SQLException;
+
+ attribute [Conditional=TOUCH_EVENTS] TouchEventConstructor TouchEvent;
+
+ attribute DOMFormDataConstructor FormData;
+
+ attribute [Conditional=BLOB|FILE_SYSTEM] FileErrorConstructor FileError;
+ attribute [Conditional=BLOB] FileReaderConstructor FileReader;
+
+ attribute [Conditional=BLOB] BlobBuilderConstructor BlobBuilder;
+
+#if defined(ENABLE_BLOB) && ENABLE_BLOB
+ [ConvertNullStringTo=Undefined] DOMString createObjectURL(in Blob blob);
+ void revokeObjectURL(in DOMString blobURL);
+#endif
+
+#endif // defined(LANGUAGE_JAVASCRIPT)
+
+#if defined(V8_BINDING) && V8_BINDING
+ // window.toString() requires special handling in V8
+ [V8DoNotCheckSignature, DoNotCheckDomainSecurity, Custom, DontEnum] DOMString toString();
+#endif // defined(V8_BINDING)
+ };
+
+}
+
diff --git a/Source/WebCore/page/DragActions.h b/Source/WebCore/page/DragActions.h
new file mode 100644
index 0000000..37b783b
--- /dev/null
+++ b/Source/WebCore/page/DragActions.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DragActions_h
+#define DragActions_h
+
+#include <limits.h>
+
+namespace WebCore {
+
+ // WebCoreDragDestinationAction should be kept in sync with WebDragDestinationAction
+ typedef enum {
+ DragDestinationActionNone = 0,
+ DragDestinationActionDHTML = 1,
+ DragDestinationActionEdit = 2,
+ DragDestinationActionLoad = 4,
+ DragDestinationActionAny = UINT_MAX
+ } DragDestinationAction;
+
+ // WebCoreDragSourceAction should be kept in sync with WebDragSourceAction
+ typedef enum {
+ DragSourceActionNone = 0,
+ DragSourceActionDHTML = 1,
+ DragSourceActionImage = 2,
+ DragSourceActionLink = 4,
+ DragSourceActionSelection = 8,
+ DragSourceActionAny = UINT_MAX
+ } DragSourceAction;
+
+ //matches NSDragOperation
+ typedef enum {
+ DragOperationNone = 0,
+ DragOperationCopy = 1,
+ DragOperationLink = 2,
+ DragOperationGeneric = 4,
+ DragOperationPrivate = 8,
+ DragOperationMove = 16,
+ DragOperationDelete = 32,
+ DragOperationEvery = UINT_MAX
+ } DragOperation;
+
+}
+
+#endif // !DragActions_h
diff --git a/Source/WebCore/page/DragClient.h b/Source/WebCore/page/DragClient.h
new file mode 100644
index 0000000..4f343a0
--- /dev/null
+++ b/Source/WebCore/page/DragClient.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef DragClient_h
+#define DragClient_h
+
+#include "DragActions.h"
+#include "DragImage.h"
+#include "IntPoint.h"
+
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+@class DOMElement;
+@class NSURL;
+@class NSString;
+@class NSPasteboard;
+#else
+class DOMElement;
+class NSURL;
+class NSString;
+class NSPasteboard;
+#endif
+#endif
+
+namespace WebCore {
+
+ class Clipboard;
+ class DragData;
+ class Frame;
+ class Image;
+ class HTMLImageElement;
+
+ class DragClient {
+ public:
+ virtual void willPerformDragDestinationAction(DragDestinationAction, DragData*) = 0;
+ virtual void willPerformDragSourceAction(DragSourceAction, const IntPoint&, Clipboard*) = 0;
+ virtual DragDestinationAction actionMaskForDrag(DragData*) = 0;
+ //We work in window rather than view coordinates here
+ virtual DragSourceAction dragSourceActionMaskForPoint(const IntPoint& windowPoint) = 0;
+
+ virtual void startDrag(DragImageRef dragImage, const IntPoint& dragImageOrigin, const IntPoint& eventPos, Clipboard*, Frame*, bool linkDrag = false) = 0;
+ virtual DragImageRef createDragImageForLink(KURL&, const String& label, Frame*) = 0;
+
+ virtual void dragControllerDestroyed() = 0;
+#if PLATFORM(MAC)
+ //Mac specific helper functions to allow access to functionality in webkit -- such as
+ //web archives and NSPasteboard extras
+ //not abstract as that would require another #if PLATFORM(MAC) for the SVGImage client empty impl
+ virtual void declareAndWriteDragImage(NSPasteboard*, DOMElement*, NSURL*, NSString*, Frame*) {};
+#endif
+
+ virtual ~DragClient() {};
+ };
+
+}
+
+#endif // !DragClient_h
+
diff --git a/Source/WebCore/page/DragController.cpp b/Source/WebCore/page/DragController.cpp
new file mode 100644
index 0000000..d0e9a8c
--- /dev/null
+++ b/Source/WebCore/page/DragController.cpp
@@ -0,0 +1,852 @@
+/*
+ * Copyright (C) 2007, 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DragController.h"
+
+#if ENABLE(DRAG_SUPPORT)
+#include "CSSStyleDeclaration.h"
+#include "Clipboard.h"
+#include "ClipboardAccessPolicy.h"
+#include "CachedResourceLoader.h"
+#include "Document.h"
+#include "DocumentFragment.h"
+#include "DragActions.h"
+#include "DragClient.h"
+#include "DragData.h"
+#include "Editor.h"
+#include "EditorClient.h"
+#include "Element.h"
+#include "EventHandler.h"
+#include "FloatRect.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "HTMLAnchorElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "Image.h"
+#include "MoveSelectionCommand.h"
+#include "Node.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "RenderFileUploadControl.h"
+#include "RenderImage.h"
+#include "RenderLayer.h"
+#include "RenderView.h"
+#include "ReplaceSelectionCommand.h"
+#include "ResourceRequest.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "Text.h"
+#include "TextEvent.h"
+#include "htmlediting.h"
+#include "markup.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+static PlatformMouseEvent createMouseEvent(DragData* dragData)
+{
+ bool shiftKey, ctrlKey, altKey, metaKey;
+ shiftKey = ctrlKey = altKey = metaKey = false;
+ PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
+ return PlatformMouseEvent(dragData->clientPosition(), dragData->globalPosition(),
+ LeftButton, MouseEventMoved, 0, shiftKey, ctrlKey, altKey,
+ metaKey, currentTime());
+}
+
+DragController::DragController(Page* page, DragClient* client)
+ : m_page(page)
+ , m_client(client)
+ , m_documentUnderMouse(0)
+ , m_dragInitiator(0)
+ , m_dragDestinationAction(DragDestinationActionNone)
+ , m_dragSourceAction(DragSourceActionNone)
+ , m_didInitiateDrag(false)
+ , m_isHandlingDrag(false)
+ , m_sourceDragOperation(DragOperationNone)
+{
+}
+
+DragController::~DragController()
+{
+ m_client->dragControllerDestroyed();
+}
+
+static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragData, RefPtr<Range> context,
+ bool allowPlainText, bool& chosePlainText)
+{
+ ASSERT(dragData);
+ chosePlainText = false;
+
+ Document* document = context->ownerDocument();
+ ASSERT(document);
+ if (document && dragData->containsCompatibleContent()) {
+ if (PassRefPtr<DocumentFragment> fragment = dragData->asFragment(document))
+ return fragment;
+
+ if (dragData->containsURL(DragData::DoNotConvertFilenames)) {
+ String title;
+ String url = dragData->asURL(DragData::DoNotConvertFilenames, &title);
+ if (!url.isEmpty()) {
+ RefPtr<HTMLAnchorElement> anchor = HTMLAnchorElement::create(document);
+ anchor->setHref(url);
+ if (title.isEmpty()) {
+ // Try the plain text first because the url might be normalized or escaped.
+ if (dragData->containsPlainText())
+ title = dragData->asPlainText();
+ if (title.isEmpty())
+ title = url;
+ }
+ RefPtr<Node> anchorText = document->createTextNode(title);
+ ExceptionCode ec;
+ anchor->appendChild(anchorText, ec);
+ RefPtr<DocumentFragment> fragment = document->createDocumentFragment();
+ fragment->appendChild(anchor, ec);
+ return fragment.get();
+ }
+ }
+ }
+ if (allowPlainText && dragData->containsPlainText()) {
+ chosePlainText = true;
+ return createFragmentFromText(context.get(), dragData->asPlainText()).get();
+ }
+
+ return 0;
+}
+
+bool DragController::dragIsMove(SelectionController* selection)
+{
+ return m_documentUnderMouse == m_dragInitiator && selection->isContentEditable() && !isCopyKeyDown();
+}
+
+// FIXME: This method is poorly named. We're just clearing the selection from the document this drag is exiting.
+void DragController::cancelDrag()
+{
+ m_page->dragCaretController()->clear();
+}
+
+void DragController::dragEnded()
+{
+ m_dragInitiator = 0;
+ m_didInitiateDrag = false;
+ m_page->dragCaretController()->clear();
+}
+
+DragOperation DragController::dragEntered(DragData* dragData)
+{
+ return dragEnteredOrUpdated(dragData);
+}
+
+void DragController::dragExited(DragData* dragData)
+{
+ ASSERT(dragData);
+ Frame* mainFrame = m_page->mainFrame();
+
+ if (RefPtr<FrameView> v = mainFrame->view()) {
+ ClipboardAccessPolicy policy = (!m_documentUnderMouse || m_documentUnderMouse->securityOrigin()->isLocal()) ? ClipboardReadable : ClipboardTypesReadable;
+ RefPtr<Clipboard> clipboard = Clipboard::create(policy, dragData, mainFrame);
+ clipboard->setSourceOperation(dragData->draggingSourceOperationMask());
+ mainFrame->eventHandler()->cancelDragAndDrop(createMouseEvent(dragData), clipboard.get());
+ clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security
+ }
+ mouseMovedIntoDocument(0);
+}
+
+DragOperation DragController::dragUpdated(DragData* dragData)
+{
+ return dragEnteredOrUpdated(dragData);
+}
+
+bool DragController::performDrag(DragData* dragData)
+{
+ ASSERT(dragData);
+ m_documentUnderMouse = m_page->mainFrame()->documentAtPoint(dragData->clientPosition());
+ if (m_isHandlingDrag) {
+ ASSERT(m_dragDestinationAction & DragDestinationActionDHTML);
+ m_client->willPerformDragDestinationAction(DragDestinationActionDHTML, dragData);
+ RefPtr<Frame> mainFrame = m_page->mainFrame();
+ if (mainFrame->view()) {
+ // Sending an event can result in the destruction of the view and part.
+ RefPtr<Clipboard> clipboard = Clipboard::create(ClipboardReadable, dragData, mainFrame.get());
+ clipboard->setSourceOperation(dragData->draggingSourceOperationMask());
+ mainFrame->eventHandler()->performDragAndDrop(createMouseEvent(dragData), clipboard.get());
+ clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security
+ }
+ m_documentUnderMouse = 0;
+ return true;
+ }
+
+ if ((m_dragDestinationAction & DragDestinationActionEdit) && concludeEditDrag(dragData)) {
+ m_documentUnderMouse = 0;
+ return true;
+ }
+
+ m_documentUnderMouse = 0;
+
+ if (operationForLoad(dragData) == DragOperationNone)
+ return false;
+
+ m_client->willPerformDragDestinationAction(DragDestinationActionLoad, dragData);
+ m_page->mainFrame()->loader()->load(ResourceRequest(dragData->asURL()), false);
+ return true;
+}
+
+void DragController::mouseMovedIntoDocument(Document* newDocument)
+{
+ if (m_documentUnderMouse == newDocument)
+ return;
+
+ // If we were over another document clear the selection
+ if (m_documentUnderMouse)
+ cancelDrag();
+ m_documentUnderMouse = newDocument;
+}
+
+DragOperation DragController::dragEnteredOrUpdated(DragData* dragData)
+{
+ ASSERT(dragData);
+ ASSERT(m_page->mainFrame()); // It is not possible in Mac WebKit to have a Page without a mainFrame()
+ mouseMovedIntoDocument(m_page->mainFrame()->documentAtPoint(dragData->clientPosition()));
+
+ m_dragDestinationAction = m_client->actionMaskForDrag(dragData);
+ if (m_dragDestinationAction == DragDestinationActionNone) {
+ cancelDrag(); // FIXME: Why not call mouseMovedIntoDocument(0)?
+ return DragOperationNone;
+ }
+
+ DragOperation operation = DragOperationNone;
+ bool handledByDocument = tryDocumentDrag(dragData, m_dragDestinationAction, operation);
+ if (!handledByDocument && (m_dragDestinationAction & DragDestinationActionLoad))
+ return operationForLoad(dragData);
+ return operation;
+}
+
+static HTMLInputElement* asFileInput(Node* node)
+{
+ ASSERT(node);
+
+ // The button for a FILE input is a sub element with no set input type
+ // In order to get around this problem we assume any non-FILE input element
+ // is this internal button, and try querying the shadow parent node.
+ if (node->hasTagName(HTMLNames::inputTag) && node->isShadowRoot() && !static_cast<HTMLInputElement*>(node)->isFileUpload())
+ node = node->shadowHost();
+
+ if (!node || !node->hasTagName(HTMLNames::inputTag))
+ return 0;
+
+ HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node);
+ if (!inputElement->isFileUpload())
+ return 0;
+
+ return inputElement;
+}
+
+// This can return null if an empty document is loaded.
+static Element* elementUnderMouse(Document* documentUnderMouse, const IntPoint& p)
+{
+ Frame* frame = documentUnderMouse->frame();
+ float zoomFactor = frame ? frame->pageZoomFactor() : 1;
+ IntPoint point = roundedIntPoint(FloatPoint(p.x() * zoomFactor, p.y() * zoomFactor));
+
+ HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
+ HitTestResult result(point);
+ documentUnderMouse->renderView()->layer()->hitTest(request, result);
+
+ Node* n = result.innerNode();
+ while (n && !n->isElementNode())
+ n = n->parentNode();
+ if (n)
+ n = n->shadowAncestorNode();
+
+ return static_cast<Element*>(n);
+}
+
+bool DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask, DragOperation& operation)
+{
+ ASSERT(dragData);
+
+ if (!m_documentUnderMouse)
+ return false;
+
+ if (m_dragInitiator && !m_documentUnderMouse->securityOrigin()->canReceiveDragData(m_dragInitiator->securityOrigin()))
+ return false;
+
+ m_isHandlingDrag = false;
+ if (actionMask & DragDestinationActionDHTML) {
+ m_isHandlingDrag = tryDHTMLDrag(dragData, operation);
+ // Do not continue if m_documentUnderMouse has been reset by tryDHTMLDrag.
+ // tryDHTMLDrag fires dragenter event. The event listener that listens
+ // to this event may create a nested message loop (open a modal dialog),
+ // which could process dragleave event and reset m_documentUnderMouse in
+ // dragExited.
+ if (!m_documentUnderMouse)
+ return false;
+ }
+
+ // It's unclear why this check is after tryDHTMLDrag.
+ // We send drag events in tryDHTMLDrag and that may be the reason.
+ RefPtr<FrameView> frameView = m_documentUnderMouse->view();
+ if (!frameView)
+ return false;
+
+ if (m_isHandlingDrag) {
+ m_page->dragCaretController()->clear();
+ return true;
+ } else if ((actionMask & DragDestinationActionEdit) && canProcessDrag(dragData)) {
+ if (dragData->containsColor()) {
+ operation = DragOperationGeneric;
+ return true;
+ }
+
+ IntPoint point = frameView->windowToContents(dragData->clientPosition());
+ Element* element = elementUnderMouse(m_documentUnderMouse.get(), point);
+ if (!element)
+ return false;
+ if (!asFileInput(element)) {
+ VisibleSelection dragCaret = m_documentUnderMouse->frame()->visiblePositionForPoint(point);
+ m_page->dragCaretController()->setSelection(dragCaret);
+ }
+
+ Frame* innerFrame = element->document()->frame();
+ operation = dragIsMove(innerFrame->selection()) ? DragOperationMove : DragOperationCopy;
+ return true;
+ }
+ // If we're not over an editable region, make sure we're clearing any prior drag cursor.
+ m_page->dragCaretController()->clear();
+ return false;
+}
+
+DragSourceAction DragController::delegateDragSourceAction(const IntPoint& windowPoint)
+{
+ m_dragSourceAction = m_client->dragSourceActionMaskForPoint(windowPoint);
+ return m_dragSourceAction;
+}
+
+DragOperation DragController::operationForLoad(DragData* dragData)
+{
+ ASSERT(dragData);
+ Document* doc = m_page->mainFrame()->documentAtPoint(dragData->clientPosition());
+ if (doc && (m_didInitiateDrag || doc->isPluginDocument() || (doc->frame() && doc->frame()->editor()->clientIsEditable())))
+ return DragOperationNone;
+ return dragOperation(dragData);
+}
+
+static bool setSelectionToDragCaret(Frame* frame, VisibleSelection& dragCaret, RefPtr<Range>& range, const IntPoint& point)
+{
+ frame->selection()->setSelection(dragCaret);
+ if (frame->selection()->isNone()) {
+ dragCaret = frame->visiblePositionForPoint(point);
+ frame->selection()->setSelection(dragCaret);
+ range = dragCaret.toNormalizedRange();
+ }
+ return !frame->selection()->isNone() && frame->selection()->isContentEditable();
+}
+
+bool DragController::dispatchTextInputEventFor(Frame* innerFrame, DragData* dragData)
+{
+ VisibleSelection dragCaret(m_page->dragCaretController()->selection());
+ String text = dragCaret.isContentRichlyEditable() ? "" : dragData->asPlainText();
+ Node* target = innerFrame->editor()->findEventTargetFrom(dragCaret);
+ ExceptionCode ec = 0;
+ return target->dispatchEvent(TextEvent::createForDrop(innerFrame->domWindow(), text), ec);
+}
+
+bool DragController::concludeEditDrag(DragData* dragData)
+{
+ ASSERT(dragData);
+ ASSERT(!m_isHandlingDrag);
+
+ if (!m_documentUnderMouse)
+ return false;
+
+ IntPoint point = m_documentUnderMouse->view()->windowToContents(dragData->clientPosition());
+ Element* element = elementUnderMouse(m_documentUnderMouse.get(), point);
+ if (!element)
+ return false;
+ Frame* innerFrame = element->ownerDocument()->frame();
+ ASSERT(innerFrame);
+
+ if (!dispatchTextInputEventFor(innerFrame, dragData))
+ return true;
+
+ if (dragData->containsColor()) {
+ Color color = dragData->asColor();
+ if (!color.isValid())
+ return false;
+ RefPtr<Range> innerRange = innerFrame->selection()->toNormalizedRange();
+ RefPtr<CSSStyleDeclaration> style = m_documentUnderMouse->createCSSStyleDeclaration();
+ ExceptionCode ec;
+ style->setProperty("color", color.name(), ec);
+ if (!innerFrame->editor()->shouldApplyStyle(style.get(), innerRange.get()))
+ return false;
+ m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
+ innerFrame->editor()->applyStyle(style.get(), EditActionSetColor);
+ return true;
+ }
+
+ if (!m_page->dragController()->canProcessDrag(dragData)) {
+ m_page->dragCaretController()->clear();
+ return false;
+ }
+
+ if (HTMLInputElement* fileInput = asFileInput(element)) {
+ if (fileInput->disabled())
+ return false;
+
+ if (!dragData->containsFiles())
+ return false;
+
+ Vector<String> filenames;
+ dragData->asFilenames(filenames);
+ if (filenames.isEmpty())
+ return false;
+
+ // Ugly. For security none of the APIs available to us can set the input value
+ // on file inputs. Even forcing a change in HTMLInputElement doesn't work as
+ // RenderFileUploadControl clears the file when doing updateFromElement().
+ RenderFileUploadControl* renderer = toRenderFileUploadControl(fileInput->renderer());
+ if (!renderer)
+ return false;
+
+ renderer->receiveDroppedFiles(filenames);
+ return true;
+ }
+
+ VisibleSelection dragCaret(m_page->dragCaretController()->selection());
+ m_page->dragCaretController()->clear();
+ RefPtr<Range> range = dragCaret.toNormalizedRange();
+
+ // For range to be null a WebKit client must have done something bad while
+ // manually controlling drag behaviour
+ if (!range)
+ return false;
+ CachedResourceLoader* cachedResourceLoader = range->ownerDocument()->cachedResourceLoader();
+ cachedResourceLoader->setAllowStaleResources(true);
+ if (dragIsMove(innerFrame->selection()) || dragCaret.isContentRichlyEditable()) {
+ bool chosePlainText = false;
+ RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, range, true, chosePlainText);
+ if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, range, EditorInsertActionDropped)) {
+ cachedResourceLoader->setAllowStaleResources(false);
+ return false;
+ }
+
+ m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
+ if (dragIsMove(innerFrame->selection())) {
+ // NSTextView behavior is to always smart delete on moving a selection,
+ // but only to smart insert if the selection granularity is word granularity.
+ bool smartDelete = innerFrame->editor()->smartInsertDeleteEnabled();
+ bool smartInsert = smartDelete && innerFrame->selection()->granularity() == WordGranularity && dragData->canSmartReplace();
+ applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartInsert, smartDelete));
+ } else {
+ if (setSelectionToDragCaret(innerFrame, dragCaret, range, point))
+ applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse.get(), fragment, true, dragData->canSmartReplace(), chosePlainText));
+ }
+ } else {
+ String text = dragData->asPlainText();
+ if (text.isEmpty() || !innerFrame->editor()->shouldInsertText(text, range.get(), EditorInsertActionDropped)) {
+ cachedResourceLoader->setAllowStaleResources(false);
+ return false;
+ }
+
+ m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
+ if (setSelectionToDragCaret(innerFrame, dragCaret, range, point))
+ applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse.get(), createFragmentFromText(range.get(), text), true, false, true));
+ }
+ cachedResourceLoader->setAllowStaleResources(false);
+
+ return true;
+}
+
+bool DragController::canProcessDrag(DragData* dragData)
+{
+ ASSERT(dragData);
+
+ if (!dragData->containsCompatibleContent())
+ return false;
+
+ IntPoint point = m_page->mainFrame()->view()->windowToContents(dragData->clientPosition());
+ HitTestResult result = HitTestResult(point);
+ if (!m_page->mainFrame()->contentRenderer())
+ return false;
+
+ result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, true);
+
+ if (!result.innerNonSharedNode())
+ return false;
+
+ if (dragData->containsFiles() && asFileInput(result.innerNonSharedNode()))
+ return true;
+
+ if (!result.innerNonSharedNode()->isContentEditable())
+ return false;
+
+ if (m_didInitiateDrag && m_documentUnderMouse == m_dragInitiator && result.isSelected())
+ return false;
+
+ return true;
+}
+
+static DragOperation defaultOperationForDrag(DragOperation srcOpMask)
+{
+ // This is designed to match IE's operation fallback for the case where
+ // the page calls preventDefault() in a drag event but doesn't set dropEffect.
+ if (srcOpMask == DragOperationEvery)
+ return DragOperationCopy;
+ if (srcOpMask == DragOperationNone)
+ return DragOperationNone;
+ if (srcOpMask & DragOperationMove || srcOpMask & DragOperationGeneric)
+ return DragOperationMove;
+ if (srcOpMask & DragOperationCopy)
+ return DragOperationCopy;
+ if (srcOpMask & DragOperationLink)
+ return DragOperationLink;
+
+ // FIXME: Does IE really return "generic" even if no operations were allowed by the source?
+ return DragOperationGeneric;
+}
+
+bool DragController::tryDHTMLDrag(DragData* dragData, DragOperation& operation)
+{
+ ASSERT(dragData);
+ ASSERT(m_documentUnderMouse);
+ RefPtr<Frame> mainFrame = m_page->mainFrame();
+ RefPtr<FrameView> viewProtector = mainFrame->view();
+ if (!viewProtector)
+ return false;
+
+ ClipboardAccessPolicy policy = m_documentUnderMouse->securityOrigin()->isLocal() ? ClipboardReadable : ClipboardTypesReadable;
+ RefPtr<Clipboard> clipboard = Clipboard::create(policy, dragData, mainFrame.get());
+ DragOperation srcOpMask = dragData->draggingSourceOperationMask();
+ clipboard->setSourceOperation(srcOpMask);
+
+ PlatformMouseEvent event = createMouseEvent(dragData);
+ if (!mainFrame->eventHandler()->updateDragAndDrop(event, clipboard.get())) {
+ clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security
+ return false;
+ }
+
+ operation = clipboard->destinationOperation();
+ if (clipboard->dropEffectIsUninitialized())
+ operation = defaultOperationForDrag(srcOpMask);
+ else if (!(srcOpMask & operation)) {
+ // The element picked an operation which is not supported by the source
+ operation = DragOperationNone;
+ }
+
+ clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security
+ return true;
+}
+
+bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPoint& framePos, Node* node)
+{
+ ASSERT(frame);
+ ASSERT(frame->settings());
+
+ if (!frame->view() || !frame->contentRenderer())
+ return false;
+
+ HitTestResult mouseDownTarget = HitTestResult(framePos);
+
+ mouseDownTarget = frame->eventHandler()->hitTestResultAtPoint(framePos, true);
+ if (node)
+ mouseDownTarget.setInnerNonSharedNode(node);
+
+ if (mouseDownTarget.image()
+ && !mouseDownTarget.absoluteImageURL().isEmpty()
+ && frame->settings()->loadsImagesAutomatically()
+ && m_dragSourceAction & DragSourceActionImage)
+ return true;
+
+ if (!mouseDownTarget.absoluteLinkURL().isEmpty()
+ && m_dragSourceAction & DragSourceActionLink
+ && mouseDownTarget.isLiveLink()
+ && mouseDownTarget.URLElement()->renderer() && mouseDownTarget.URLElement()->renderer()->style()->userDrag() != DRAG_NONE)
+ return true;
+
+ if (mouseDownTarget.isSelected()
+ && m_dragSourceAction & DragSourceActionSelection)
+ return true;
+
+ return false;
+}
+
+static CachedImage* getCachedImage(Element* element)
+{
+ ASSERT(element);
+ RenderObject* renderer = element->renderer();
+ if (!renderer || !renderer->isImage())
+ return 0;
+ RenderImage* image = toRenderImage(renderer);
+ return image->cachedImage();
+}
+
+static Image* getImage(Element* element)
+{
+ ASSERT(element);
+ CachedImage* cachedImage = getCachedImage(element);
+ return (cachedImage && !cachedImage->errorOccurred()) ?
+ cachedImage->image() : 0;
+}
+
+static void prepareClipboardForImageDrag(Frame* src, Clipboard* clipboard, Element* node, const KURL& linkURL, const KURL& imageURL, const String& label)
+{
+ RefPtr<Range> range = src->document()->createRange();
+ ExceptionCode ec = 0;
+ range->selectNode(node, ec);
+ ASSERT(!ec);
+ src->selection()->setSelection(VisibleSelection(range.get(), DOWNSTREAM));
+ clipboard->declareAndWriteDragImage(node, !linkURL.isEmpty() ? linkURL : imageURL, label, src);
+}
+
+static IntPoint dragLocForDHTMLDrag(const IntPoint& mouseDraggedPoint, const IntPoint& dragOrigin, const IntPoint& dragImageOffset, bool isLinkImage)
+{
+ // dragImageOffset is the cursor position relative to the lower-left corner of the image.
+#if PLATFORM(MAC)
+ // We add in the Y dimension because we are a flipped view, so adding moves the image down.
+ const int yOffset = dragImageOffset.y();
+#else
+ const int yOffset = -dragImageOffset.y();
+#endif
+
+ if (isLinkImage)
+ return IntPoint(mouseDraggedPoint.x() - dragImageOffset.x(), mouseDraggedPoint.y() + yOffset);
+
+ return IntPoint(dragOrigin.x() - dragImageOffset.x(), dragOrigin.y() + yOffset);
+}
+
+static IntPoint dragLocForSelectionDrag(Frame* src)
+{
+ IntRect draggingRect = enclosingIntRect(src->selection()->bounds());
+ int xpos = draggingRect.right();
+ xpos = draggingRect.x() < xpos ? draggingRect.x() : xpos;
+ int ypos = draggingRect.bottom();
+#if PLATFORM(MAC)
+ // Deal with flipped coordinates on Mac
+ ypos = draggingRect.y() > ypos ? draggingRect.y() : ypos;
+#else
+ ypos = draggingRect.y() < ypos ? draggingRect.y() : ypos;
+#endif
+ return IntPoint(xpos, ypos);
+}
+
+bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag)
+{
+ ASSERT(src);
+ ASSERT(clipboard);
+
+ if (!src->view() || !src->contentRenderer())
+ return false;
+
+ HitTestResult dragSource = HitTestResult(dragOrigin);
+ dragSource = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true);
+ KURL linkURL = dragSource.absoluteLinkURL();
+ KURL imageURL = dragSource.absoluteImageURL();
+ bool isSelected = dragSource.isSelected();
+
+ IntPoint mouseDraggedPoint = src->view()->windowToContents(dragEvent.pos());
+
+ m_draggingImageURL = KURL();
+ m_sourceDragOperation = srcOp;
+
+ DragImageRef dragImage = 0;
+ IntPoint dragLoc(0, 0);
+ IntPoint dragImageOffset(0, 0);
+
+ if (isDHTMLDrag)
+ dragImage = clipboard->createDragImage(dragImageOffset);
+ else {
+ // This drag operation is not a DHTML drag and may go outside the WebView.
+ // We provide a default set of allowed drag operations that follows from:
+ // http://trac.webkit.org/browser/trunk/WebKit/mac/WebView/WebHTMLView.mm?rev=48526#L3430
+ m_sourceDragOperation = (DragOperation)(DragOperationGeneric | DragOperationCopy);
+ }
+
+ // We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging.
+ // This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp.
+ if (dragImage) {
+ dragLoc = dragLocForDHTMLDrag(mouseDraggedPoint, dragOrigin, dragImageOffset, !linkURL.isEmpty());
+ m_dragOffset = dragImageOffset;
+ }
+
+ bool startedDrag = true; // optimism - we almost always manage to start the drag
+
+ Node* node = dragSource.innerNonSharedNode();
+
+ Image* image = getImage(static_cast<Element*>(node));
+ if (!imageURL.isEmpty() && node && node->isElementNode() && image
+ && (m_dragSourceAction & DragSourceActionImage)) {
+ // We shouldn't be starting a drag for an image that can't provide an extension.
+ // This is an early detection for problems encountered later upon drop.
+ ASSERT(!image->filenameExtension().isEmpty());
+ Element* element = static_cast<Element*>(node);
+ if (!clipboard->hasData()) {
+ m_draggingImageURL = imageURL;
+ prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, dragSource.altDisplayString());
+ }
+
+ m_client->willPerformDragSourceAction(DragSourceActionImage, dragOrigin, clipboard);
+
+ if (!dragImage) {
+ IntRect imageRect = dragSource.imageRect();
+ imageRect.setLocation(m_page->mainFrame()->view()->windowToContents(src->view()->contentsToWindow(imageRect.location())));
+ doImageDrag(element, dragOrigin, dragSource.imageRect(), clipboard, src, m_dragOffset);
+ } else
+ // DHTML defined drag image
+ doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
+
+ } else if (!linkURL.isEmpty() && (m_dragSourceAction & DragSourceActionLink)) {
+ if (!clipboard->hasData())
+ // Simplify whitespace so the title put on the clipboard resembles what the user sees
+ // on the web page. This includes replacing newlines with spaces.
+ clipboard->writeURL(linkURL, dragSource.textContent().simplifyWhiteSpace(), src);
+
+ if (src->selection()->isCaret() && src->selection()->isContentEditable()) {
+ // a user can initiate a drag on a link without having any text
+ // selected. In this case, we should expand the selection to
+ // the enclosing anchor element
+ Position pos = src->selection()->base();
+ Node* node = enclosingAnchorElement(pos);
+ if (node)
+ src->selection()->setSelection(VisibleSelection::selectionFromContentsOfNode(node));
+ }
+
+ m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard);
+ if (!dragImage) {
+ dragImage = m_client->createDragImageForLink(linkURL, dragSource.textContent(), src);
+ IntSize size = dragImageSize(dragImage);
+ m_dragOffset = IntPoint(-size.width() / 2, -LinkDragBorderInset);
+ dragLoc = IntPoint(mouseDraggedPoint.x() + m_dragOffset.x(), mouseDraggedPoint.y() + m_dragOffset.y());
+ }
+ doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true);
+ } else if (isSelected && (m_dragSourceAction & DragSourceActionSelection)) {
+ if (!clipboard->hasData()) {
+ if (isNodeInTextFormControl(src->selection()->start().node()))
+ clipboard->writePlainText(src->editor()->selectedText());
+ else {
+ RefPtr<Range> selectionRange = src->selection()->toNormalizedRange();
+ ASSERT(selectionRange);
+
+ clipboard->writeRange(selectionRange.get(), src);
+ }
+ }
+ m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard);
+ if (!dragImage) {
+ dragImage = createDragImageForSelection(src);
+ dragLoc = dragLocForSelectionDrag(src);
+ m_dragOffset = IntPoint((int)(dragOrigin.x() - dragLoc.x()), (int)(dragOrigin.y() - dragLoc.y()));
+ }
+ doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
+ } else if (isDHTMLDrag) {
+ ASSERT(m_dragSourceAction & DragSourceActionDHTML);
+ m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard);
+ doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
+ } else {
+ // Only way I know to get here is if to get here is if the original element clicked on in the mousedown is no longer
+ // under the mousedown point, so linkURL, imageURL and isSelected are all false/empty.
+ startedDrag = false;
+ }
+
+ if (dragImage)
+ deleteDragImage(dragImage);
+ return startedDrag;
+}
+
+void DragController::doImageDrag(Element* element, const IntPoint& dragOrigin, const IntRect& rect, Clipboard* clipboard, Frame* frame, IntPoint& dragImageOffset)
+{
+ IntPoint mouseDownPoint = dragOrigin;
+ DragImageRef dragImage;
+ IntPoint origin;
+
+ Image* image = getImage(element);
+ if (image && image->size().height() * image->size().width() <= MaxOriginalImageArea
+ && (dragImage = createDragImageFromImage(image))) {
+ IntSize originalSize = rect.size();
+ origin = rect.location();
+
+ dragImage = fitDragImageToMaxSize(dragImage, rect.size(), maxDragImageSize());
+ dragImage = dissolveDragImageToFraction(dragImage, DragImageAlpha);
+ IntSize newSize = dragImageSize(dragImage);
+
+ // Properly orient the drag image and orient it differently if it's smaller than the original
+ float scale = newSize.width() / (float)originalSize.width();
+ float dx = origin.x() - mouseDownPoint.x();
+ dx *= scale;
+ origin.setX((int)(dx + 0.5));
+#if PLATFORM(MAC)
+ //Compensate for accursed flipped coordinates in cocoa
+ origin.setY(origin.y() + originalSize.height());
+#endif
+ float dy = origin.y() - mouseDownPoint.y();
+ dy *= scale;
+ origin.setY((int)(dy + 0.5));
+ } else {
+ dragImage = createDragImageIconForCachedImage(getCachedImage(element));
+ if (dragImage)
+ origin = IntPoint(DragIconRightInset - dragImageSize(dragImage).width(), DragIconBottomInset);
+ }
+
+ dragImageOffset.setX(mouseDownPoint.x() + origin.x());
+ dragImageOffset.setY(mouseDownPoint.y() + origin.y());
+ doSystemDrag(dragImage, dragImageOffset, dragOrigin, clipboard, frame, false);
+
+ deleteDragImage(dragImage);
+}
+
+void DragController::doSystemDrag(DragImageRef image, const IntPoint& dragLoc, const IntPoint& eventPos, Clipboard* clipboard, Frame* frame, bool forLink)
+{
+ m_didInitiateDrag = true;
+ m_dragInitiator = frame->document();
+ // Protect this frame and view, as a load may occur mid drag and attempt to unload this frame
+ RefPtr<Frame> frameProtector = m_page->mainFrame();
+ RefPtr<FrameView> viewProtector = frameProtector->view();
+ m_client->startDrag(image, viewProtector->windowToContents(frame->view()->contentsToWindow(dragLoc)),
+ viewProtector->windowToContents(frame->view()->contentsToWindow(eventPos)), clipboard, frameProtector.get(), forLink);
+
+ cleanupAfterSystemDrag();
+}
+
+// Manual drag caret manipulation
+void DragController::placeDragCaret(const IntPoint& windowPoint)
+{
+ mouseMovedIntoDocument(m_page->mainFrame()->documentAtPoint(windowPoint));
+ if (!m_documentUnderMouse)
+ return;
+ Frame* frame = m_documentUnderMouse->frame();
+ FrameView* frameView = frame->view();
+ if (!frameView)
+ return;
+ IntPoint framePoint = frameView->windowToContents(windowPoint);
+ VisibleSelection dragCaret(frame->visiblePositionForPoint(framePoint));
+ m_page->dragCaretController()->setSelection(dragCaret);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DRAG_SUPPORT)
diff --git a/Source/WebCore/page/DragController.h b/Source/WebCore/page/DragController.h
new file mode 100644
index 0000000..0e90a52
--- /dev/null
+++ b/Source/WebCore/page/DragController.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DragController_h
+#define DragController_h
+
+#include "DragActions.h"
+#include "DragImage.h"
+#include "IntPoint.h"
+#include "KURL.h"
+
+namespace WebCore {
+
+ class Clipboard;
+ class Document;
+ class DragClient;
+ class DragData;
+ class Element;
+ class Frame;
+ class Image;
+ class IntRect;
+ class Node;
+ class Page;
+ class PlatformMouseEvent;
+ class Range;
+ class SelectionController;
+
+ class DragController : public Noncopyable {
+ public:
+ DragController(Page*, DragClient*);
+ ~DragController();
+ DragClient* client() const { return m_client; }
+
+ DragOperation dragEntered(DragData*);
+ void dragExited(DragData*);
+ DragOperation dragUpdated(DragData*);
+ bool performDrag(DragData*);
+
+ // FIXME: It should be possible to remove a number of these accessors once all
+ // drag logic is in WebCore.
+ void setDidInitiateDrag(bool initiated) { m_didInitiateDrag = initiated; }
+ bool didInitiateDrag() const { return m_didInitiateDrag; }
+ void setIsHandlingDrag(bool handling) { m_isHandlingDrag = handling; }
+ bool isHandlingDrag() const { return m_isHandlingDrag; }
+ DragOperation sourceDragOperation() const { return m_sourceDragOperation; }
+ void setDraggingImageURL(const KURL& url) { m_draggingImageURL = url; }
+ const KURL& draggingImageURL() const { return m_draggingImageURL; }
+ void setDragOffset(const IntPoint& offset) { m_dragOffset = offset; }
+ const IntPoint& dragOffset() const { return m_dragOffset; }
+ DragSourceAction dragSourceAction() const { return m_dragSourceAction; }
+
+ Document* documentUnderMouse() const { return m_documentUnderMouse.get(); }
+ DragDestinationAction dragDestinationAction() const { return m_dragDestinationAction; }
+ DragSourceAction delegateDragSourceAction(const IntPoint& pagePoint);
+
+ bool mayStartDragAtEventLocation(const Frame*, const IntPoint& framePos, Node*);
+ void dragEnded();
+
+ void placeDragCaret(const IntPoint&);
+
+ bool startDrag(Frame* src, Clipboard*, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag);
+ static const IntSize& maxDragImageSize();
+
+ static const int LinkDragBorderInset;
+ static const int MaxOriginalImageArea;
+ static const int DragIconRightInset;
+ static const int DragIconBottomInset;
+ static const float DragImageAlpha;
+
+ private:
+ bool dispatchTextInputEventFor(Frame*, DragData*);
+ bool canProcessDrag(DragData*);
+ bool concludeEditDrag(DragData*);
+ DragOperation dragEnteredOrUpdated(DragData*);
+ DragOperation operationForLoad(DragData*);
+ bool tryDocumentDrag(DragData*, DragDestinationAction, DragOperation&);
+ bool tryDHTMLDrag(DragData*, DragOperation&);
+ DragOperation dragOperation(DragData*);
+ void cancelDrag();
+ bool dragIsMove(SelectionController*);
+ bool isCopyKeyDown();
+
+ void mouseMovedIntoDocument(Document*);
+
+ IntRect selectionDraggingRect(Frame*);
+ bool doDrag(Frame* src, Clipboard* clipboard, DragImageRef dragImage, const KURL& linkURL, const KURL& imageURL, Node* node, IntPoint& dragLoc, IntPoint& dragImageOffset);
+ void doImageDrag(Element*, const IntPoint&, const IntRect&, Clipboard*, Frame*, IntPoint&);
+ void doSystemDrag(DragImageRef, const IntPoint&, const IntPoint&, Clipboard*, Frame*, bool forLink);
+ void cleanupAfterSystemDrag();
+
+ Page* m_page;
+ DragClient* m_client;
+
+ RefPtr<Document> m_documentUnderMouse; // The document the mouse was last dragged over.
+ RefPtr<Document> m_dragInitiator; // The Document (if any) that initiated the drag.
+
+ DragDestinationAction m_dragDestinationAction;
+ DragSourceAction m_dragSourceAction;
+ bool m_didInitiateDrag;
+ bool m_isHandlingDrag;
+ DragOperation m_sourceDragOperation; // Set in startDrag when a drag starts from a mouse down within WebKit
+ IntPoint m_dragOffset;
+ KURL m_draggingImageURL;
+ };
+
+}
+
+#endif
diff --git a/Source/WebCore/page/EditorClient.h b/Source/WebCore/page/EditorClient.h
new file mode 100644
index 0000000..1ec0c7e
--- /dev/null
+++ b/Source/WebCore/page/EditorClient.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef EditorClient_h
+#define EditorClient_h
+
+#include "CorrectionPanelInfo.h"
+#include "EditorInsertAction.h"
+#include "FloatRect.h"
+#include "PlatformString.h"
+#include "TextAffinity.h"
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+@class NSArray;
+@class NSAttributedString;
+@class NSData;
+@class NSPasteboard;
+@class NSString;
+@class NSURL;
+#else
+class NSArray;
+class NSAttributedString;
+class NSData;
+class NSPasteboard;
+class NSString;
+class NSURL;
+#endif
+#endif
+
+namespace WebCore {
+
+class ArchiveResource;
+class CSSStyleDeclaration;
+class DocumentFragment;
+class EditCommand;
+class Editor;
+class Element;
+class Frame;
+class HTMLElement;
+class KeyboardEvent;
+class Node;
+class Range;
+class SpellChecker;
+class VisibleSelection;
+class VisiblePosition;
+
+struct GrammarDetail {
+ int location;
+ int length;
+ Vector<String> guesses;
+ String userDescription;
+};
+
+enum TextCheckingType {
+ TextCheckingTypeSpelling = 1 << 1,
+ TextCheckingTypeGrammar = 1 << 2,
+ TextCheckingTypeLink = 1 << 5,
+ TextCheckingTypeQuote = 1 << 6,
+ TextCheckingTypeDash = 1 << 7,
+ TextCheckingTypeReplacement = 1 << 8,
+ TextCheckingTypeCorrection = 1 << 9
+};
+
+struct TextCheckingResult {
+ TextCheckingType type;
+ int location;
+ int length;
+ Vector<GrammarDetail> details;
+ String replacement;
+};
+
+class EditorClient {
+public:
+ virtual ~EditorClient() { }
+ virtual void pageDestroyed() = 0;
+
+ virtual bool shouldDeleteRange(Range*) = 0;
+ virtual bool shouldShowDeleteInterface(HTMLElement*) = 0;
+ virtual bool smartInsertDeleteEnabled() = 0;
+ virtual bool isSelectTrailingWhitespaceEnabled() = 0;
+ virtual bool isContinuousSpellCheckingEnabled() = 0;
+ virtual void toggleContinuousSpellChecking() = 0;
+ virtual bool isGrammarCheckingEnabled() = 0;
+ virtual void toggleGrammarChecking() = 0;
+ virtual int spellCheckerDocumentTag() = 0;
+
+ virtual bool isEditable() = 0;
+
+ virtual bool shouldBeginEditing(Range*) = 0;
+ virtual bool shouldEndEditing(Range*) = 0;
+ virtual bool shouldInsertNode(Node*, Range*, EditorInsertAction) = 0;
+ virtual bool shouldInsertText(const String&, Range*, EditorInsertAction) = 0;
+ virtual bool shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity, bool stillSelecting) = 0;
+
+ virtual bool shouldApplyStyle(CSSStyleDeclaration*, Range*) = 0;
+// virtual bool shouldChangeTypingStyle(CSSStyleDeclaration* fromStyle, CSSStyleDeclaration* toStyle) = 0;
+// virtual bool doCommandBySelector(SEL selector) = 0;
+ virtual bool shouldMoveRangeAfterDelete(Range*, Range*) = 0;
+
+ virtual void didBeginEditing() = 0;
+ virtual void respondToChangedContents() = 0;
+ virtual void respondToChangedSelection() = 0;
+ virtual void didEndEditing() = 0;
+ virtual void didWriteSelectionToPasteboard() = 0;
+ virtual void didSetSelectionTypesForPasteboard() = 0;
+// virtual void didChangeTypingStyle:(NSNotification *)notification = 0;
+// virtual void didChangeSelection:(NSNotification *)notification = 0;
+// virtual NSUndoManager* undoManager:(WebView *)webView = 0;
+
+ virtual void registerCommandForUndo(PassRefPtr<EditCommand>) = 0;
+ virtual void registerCommandForRedo(PassRefPtr<EditCommand>) = 0;
+ virtual void clearUndoRedoOperations() = 0;
+
+ virtual bool canUndo() const = 0;
+ virtual bool canRedo() const = 0;
+
+ virtual void undo() = 0;
+ virtual void redo() = 0;
+
+ virtual void handleKeyboardEvent(KeyboardEvent*) = 0;
+ virtual void handleInputMethodKeydown(KeyboardEvent*) = 0;
+
+ virtual void textFieldDidBeginEditing(Element*) = 0;
+ virtual void textFieldDidEndEditing(Element*) = 0;
+ virtual void textDidChangeInTextField(Element*) = 0;
+ virtual bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*) = 0;
+ virtual void textWillBeDeletedInTextField(Element*) = 0;
+ virtual void textDidChangeInTextArea(Element*) = 0;
+
+#if PLATFORM(MAC)
+ virtual NSString* userVisibleString(NSURL*) = 0;
+ virtual DocumentFragment* documentFragmentFromAttributedString(NSAttributedString*, Vector< RefPtr<ArchiveResource> >&) = 0;
+ virtual void setInsertionPasteboard(NSPasteboard*) = 0;
+#ifdef BUILDING_ON_TIGER
+ virtual NSArray* pasteboardTypesForSelection(Frame*) = 0;
+#endif
+#endif
+
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ virtual void uppercaseWord() = 0;
+ virtual void lowercaseWord() = 0;
+ virtual void capitalizeWord() = 0;
+ virtual void showSubstitutionsPanel(bool show) = 0;
+ virtual bool substitutionsPanelIsShowing() = 0;
+ virtual void toggleSmartInsertDelete() = 0;
+ virtual bool isAutomaticQuoteSubstitutionEnabled() = 0;
+ virtual void toggleAutomaticQuoteSubstitution() = 0;
+ virtual bool isAutomaticLinkDetectionEnabled() = 0;
+ virtual void toggleAutomaticLinkDetection() = 0;
+ virtual bool isAutomaticDashSubstitutionEnabled() = 0;
+ virtual void toggleAutomaticDashSubstitution() = 0;
+ virtual bool isAutomaticTextReplacementEnabled() = 0;
+ virtual void toggleAutomaticTextReplacement() = 0;
+ virtual bool isAutomaticSpellingCorrectionEnabled() = 0;
+ virtual void toggleAutomaticSpellingCorrection() = 0;
+#endif
+
+ virtual void ignoreWordInSpellDocument(const String&) = 0;
+ virtual void learnWord(const String&) = 0;
+ virtual void checkSpellingOfString(const UChar*, int length, int* misspellingLocation, int* misspellingLength) = 0;
+ virtual String getAutoCorrectSuggestionForMisspelledWord(const String& misspelledWord) = 0;
+ virtual void checkGrammarOfString(const UChar*, int length, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength) = 0;
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ virtual void checkTextOfParagraph(const UChar* text, int length, uint64_t checkingTypes, Vector<TextCheckingResult>& results) = 0;
+#endif
+
+#if SUPPORT_AUTOCORRECTION_PANEL
+ virtual void showCorrectionPanel(CorrectionPanelInfo::PanelType, const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacmentString, const Vector<String>& alternativeReplacementStrings, Editor*) = 0;
+ virtual void dismissCorrectionPanel(ReasonForDismissingCorrectionPanel) = 0;
+ virtual bool isShowingCorrectionPanel() = 0;
+#endif
+
+ virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail& detail) = 0;
+ virtual void updateSpellingUIWithMisspelledWord(const String&) = 0;
+ virtual void showSpellingUI(bool show) = 0;
+ virtual bool spellingUIIsShowing() = 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;
+ virtual void requestCheckingOfString(SpellChecker*, int, const String&) = 0;
+};
+
+}
+
+#endif // EditorClient_h
diff --git a/Source/WebCore/page/EventHandler.cpp b/Source/WebCore/page/EventHandler.cpp
new file mode 100644
index 0000000..ab923ac
--- /dev/null
+++ b/Source/WebCore/page/EventHandler.cpp
@@ -0,0 +1,3140 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "EventHandler.h"
+
+#include "AXObjectCache.h"
+#include "CachedImage.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "Cursor.h"
+#include "Document.h"
+#include "DragController.h"
+#include "Editor.h"
+#include "EventNames.h"
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "HTMLFrameElementBase.h"
+#include "HTMLFrameSetElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "Image.h"
+#include "InspectorController.h"
+#include "KeyboardEvent.h"
+#include "MouseEvent.h"
+#include "MouseEventWithHitTestResults.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "PluginDocument.h"
+#if defined(ANDROID_PLUGINS)
+#include "PluginView.h"
+#endif
+#include "RenderFrameSet.h"
+#include "RenderLayer.h"
+#include "RenderTextControlSingleLine.h"
+#include "RenderView.h"
+#include "RenderWidget.h"
+#include "Scrollbar.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "StyleCachedImage.h"
+#include "TextEvent.h"
+#include "TextIterator.h"
+#include "UserGestureIndicator.h"
+#include "UserTypingGestureIndicator.h"
+#include "WheelEvent.h"
+#include "htmlediting.h" // for comparePositions()
+#include <wtf/CurrentTime.h>
+#include <wtf/StdLibExtras.h>
+
+#if ENABLE(SVG)
+#include "SVGDocument.h"
+#include "SVGElementInstance.h"
+#include "SVGNames.h"
+#include "SVGUseElement.h"
+#endif
+
+#if ENABLE(TOUCH_EVENTS)
+#include "PlatformTouchEvent.h"
+#include "TouchEvent.h"
+#endif
+
+#if defined(ANDROID_PLUGINS)
+#include "WebViewCore.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+#if ENABLE(DRAG_SUPPORT)
+// The link drag hysteresis is much larger than the others because there
+// needs to be enough space to cancel the link press without starting a link drag,
+// and because dragging links is rare.
+const int LinkDragHysteresis = 40;
+const int ImageDragHysteresis = 5;
+const int TextDragHysteresis = 3;
+const int GeneralDragHysteresis = 3;
+#endif // ENABLE(DRAG_SUPPORT)
+
+// Match key code of composition keydown event on windows.
+// IE sends VK_PROCESSKEY which has value 229;
+const int CompositionEventKeyCode = 229;
+
+#if ENABLE(SVG)
+using namespace SVGNames;
+#endif
+
+// When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth
+const double autoscrollInterval = 0.05;
+
+const double fakeMouseMoveInterval = 0.1;
+
+static Frame* subframeForHitTestResult(const MouseEventWithHitTestResults&);
+
+static inline bool scrollNode(float delta, WheelEvent::Granularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode)
+{
+ if (!delta)
+ return false;
+
+ if (!node->renderer())
+ return false;
+
+ // Find the nearest enclosing box.
+ RenderBox* enclosingBox = node->renderer()->enclosingBox();
+
+ float absDelta = delta > 0 ? delta : -delta;
+
+ if (granularity == WheelEvent::Page)
+ return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, absDelta, stopNode);
+
+ if (granularity == WheelEvent::Line)
+ return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByLine, absDelta, stopNode);
+
+ if (granularity == WheelEvent::Pixel)
+ return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, absDelta, stopNode);
+
+ return false;
+}
+
+#if !PLATFORM(MAC)
+
+inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
+{
+ return false;
+}
+
+#if ENABLE(DRAG_SUPPORT)
+inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
+{
+ return false;
+}
+#endif
+
+#endif
+
+EventHandler::EventHandler(Frame* frame)
+ : m_frame(frame)
+ , m_mousePressed(false)
+ , m_capturesDragging(false)
+ , m_mouseDownMayStartSelect(false)
+#if ENABLE(DRAG_SUPPORT)
+ , m_mouseDownMayStartDrag(false)
+#endif
+ , m_mouseDownWasSingleClickInSelection(false)
+ , m_beganSelectingText(false)
+ , m_panScrollInProgress(false)
+ , m_panScrollButtonPressed(false)
+ , m_springLoadedPanScrollInProgress(false)
+ , m_hoverTimer(this, &EventHandler::hoverTimerFired)
+ , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired)
+ , m_autoscrollRenderer(0)
+ , m_autoscrollInProgress(false)
+ , m_mouseDownMayStartAutoscroll(false)
+ , m_mouseDownWasInSubframe(false)
+ , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
+#if ENABLE(SVG)
+ , m_svgPan(false)
+#endif
+ , m_resizeLayer(0)
+ , m_eventHandlerWillResetCapturingMouseEventsNode(0)
+ , m_clickCount(0)
+ , m_mouseDownTimestamp(0)
+ , m_useLatchedWheelEventNode(false)
+ , m_widgetIsLatched(false)
+#if PLATFORM(MAC)
+ , m_mouseDownView(nil)
+ , m_sendingEventToSubview(false)
+ , m_activationEventNumber(0)
+#endif
+#if ENABLE(TOUCH_EVENTS)
+ , m_touchPressed(false)
+#endif
+{
+}
+
+EventHandler::~EventHandler()
+{
+ ASSERT(!m_fakeMouseMoveEventTimer.isActive());
+}
+
+#if ENABLE(DRAG_SUPPORT)
+EventHandler::EventHandlerDragState& EventHandler::dragState()
+{
+ DEFINE_STATIC_LOCAL(EventHandlerDragState, state, ());
+ return state;
+}
+#endif // ENABLE(DRAG_SUPPORT)
+
+void EventHandler::clear()
+{
+ m_hoverTimer.stop();
+ m_fakeMouseMoveEventTimer.stop();
+ m_resizeLayer = 0;
+ m_nodeUnderMouse = 0;
+ m_lastNodeUnderMouse = 0;
+#if ENABLE(SVG)
+ m_instanceUnderMouse = 0;
+ m_lastInstanceUnderMouse = 0;
+#endif
+ m_lastMouseMoveEventSubframe = 0;
+ m_lastScrollbarUnderMouse = 0;
+ m_clickCount = 0;
+ m_clickNode = 0;
+ m_frameSetBeingResized = 0;
+#if ENABLE(DRAG_SUPPORT)
+ m_dragTarget = 0;
+ m_shouldOnlyFireDragOverEvent = false;
+#endif
+ m_currentMousePosition = IntPoint();
+ m_mousePressNode = 0;
+ m_mousePressed = false;
+ m_capturesDragging = false;
+ m_capturingMouseEventsNode = 0;
+ m_latchedWheelEventNode = 0;
+ m_previousWheelScrolledNode = 0;
+#if ENABLE(TOUCH_EVENTS)
+ m_originatingTouchPointTargets.clear();
+#endif
+}
+
+void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
+{
+ Node* innerNode = result.targetNode();
+ VisibleSelection newSelection;
+
+ if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
+ VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
+ TextGranularity granularity = CharacterGranularity;
+ if (pos.isNotNull()) {
+ newSelection = VisibleSelection(pos);
+ newSelection.expandUsingGranularity(WordGranularity);
+ }
+
+ if (newSelection.isRange()) {
+ granularity = WordGranularity;
+ m_beganSelectingText = true;
+ if (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled())
+ newSelection.appendTrailingWhitespace();
+ }
+
+ if (m_frame->selection()->shouldChangeSelection(newSelection))
+ m_frame->selection()->setSelection(newSelection, granularity, MakeNonDirectionalSelection);
+ }
+}
+
+void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
+{
+ if (!result.hitTestResult().isLiveLink())
+ return selectClosestWordFromMouseEvent(result);
+
+ Node* innerNode = result.targetNode();
+
+ if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
+ VisibleSelection newSelection;
+ Element* URLElement = result.hitTestResult().URLElement();
+ VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
+ if (pos.isNotNull() && pos.deepEquivalent().node()->isDescendantOf(URLElement))
+ newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
+
+ TextGranularity granularity = CharacterGranularity;
+ if (newSelection.isRange()) {
+ granularity = WordGranularity;
+ m_beganSelectingText = true;
+ }
+
+ if (m_frame->selection()->shouldChangeSelection(newSelection))
+ m_frame->selection()->setSelection(newSelection, granularity, MakeNonDirectionalSelection);
+ }
+}
+
+bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
+{
+ if (event.event().button() != LeftButton)
+ return false;
+
+ if (m_frame->selection()->isRange())
+ // A double-click when range is already selected
+ // should not change the selection. So, do not call
+ // selectClosestWordFromMouseEvent, but do set
+ // m_beganSelectingText to prevent handleMouseReleaseEvent
+ // from setting caret selection.
+ m_beganSelectingText = true;
+ else
+ selectClosestWordFromMouseEvent(event);
+
+ return true;
+}
+
+bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
+{
+ if (event.event().button() != LeftButton)
+ return false;
+
+ Node* innerNode = event.targetNode();
+ if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
+ return false;
+
+ VisibleSelection newSelection;
+ VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
+ if (pos.isNotNull()) {
+ newSelection = VisibleSelection(pos);
+ newSelection.expandUsingGranularity(ParagraphGranularity);
+ }
+
+ TextGranularity granularity = CharacterGranularity;
+ if (newSelection.isRange()) {
+ granularity = ParagraphGranularity;
+ m_beganSelectingText = true;
+ }
+
+ if (m_frame->selection()->shouldChangeSelection(newSelection))
+ m_frame->selection()->setSelection(newSelection, granularity, MakeNonDirectionalSelection);
+
+ return true;
+}
+
+static int textDistance(const Position& start, const Position& end)
+{
+ RefPtr<Range> range = Range::create(start.node()->document(), start, end);
+ return TextIterator::rangeLength(range.get(), true);
+}
+
+bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
+{
+ Node* innerNode = event.targetNode();
+ if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
+ return false;
+
+ // Extend the selection if the Shift key is down, unless the click is in a link.
+ bool extendSelection = event.event().shiftKey() && !event.isOverLink();
+
+ // Don't restart the selection when the mouse is pressed on an
+ // existing selection so we can allow for text dragging.
+ if (FrameView* view = m_frame->view()) {
+ IntPoint vPoint = view->windowToContents(event.event().pos());
+ if (!extendSelection && m_frame->selection()->contains(vPoint)) {
+ m_mouseDownWasSingleClickInSelection = true;
+ return false;
+ }
+ }
+
+ VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
+ if (visiblePos.isNull())
+ visiblePos = VisiblePosition(innerNode, 0, DOWNSTREAM);
+ Position pos = visiblePos.deepEquivalent();
+
+ VisibleSelection newSelection = m_frame->selection()->selection();
+ TextGranularity granularity = CharacterGranularity;
+
+ if (extendSelection && newSelection.isCaretOrRange()) {
+ m_frame->selection()->setIsDirectional(false);
+
+ ASSERT(m_frame->settings());
+ if (m_frame->settings()->editingBehaviorType() == EditingMacBehavior) {
+ // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
+ // was created right-to-left
+ Position start = newSelection.start();
+ Position end = newSelection.end();
+ int distanceToStart = textDistance(start, pos);
+ int distanceToEnd = textDistance(pos, end);
+ if (distanceToStart <= distanceToEnd)
+ newSelection = VisibleSelection(end, pos);
+ else
+ newSelection = VisibleSelection(start, pos);
+ } else {
+ newSelection.setExtent(pos);
+ }
+
+ if (m_frame->selection()->granularity() != CharacterGranularity) {
+ granularity = m_frame->selection()->granularity();
+ newSelection.expandUsingGranularity(m_frame->selection()->granularity());
+ }
+
+ m_beganSelectingText = true;
+ } else
+ newSelection = VisibleSelection(visiblePos);
+
+ if (m_frame->selection()->shouldChangeSelection(newSelection))
+ m_frame->selection()->setSelection(newSelection, granularity, MakeNonDirectionalSelection);
+
+ return true;
+}
+
+bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
+{
+#if ENABLE(DRAG_SUPPORT)
+ // Reset drag state.
+ dragState().m_dragSrc = 0;
+#endif
+
+ cancelFakeMouseMoveEvent();
+
+ if (ScrollView* scrollView = m_frame->view()) {
+ if (scrollView->isPointInScrollbarCorner(event.event().pos()))
+ return false;
+ }
+
+ bool singleClick = event.event().clickCount() <= 1;
+
+ // If we got the event back, that must mean it wasn't prevented,
+ // so it's allowed to start a drag or selection.
+ m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode());
+
+#if ENABLE(DRAG_SUPPORT)
+ // Careful that the drag starting logic stays in sync with eventMayStartDrag()
+ m_mouseDownMayStartDrag = singleClick;
+#endif
+
+ m_mouseDownWasSingleClickInSelection = false;
+
+ m_mouseDown = event.event();
+
+ if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
+ return true;
+
+#if ENABLE(SVG)
+ if (m_frame->document()->isSVGDocument()
+ && static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) {
+ if (event.event().shiftKey() && singleClick) {
+ m_svgPan = true;
+ static_cast<SVGDocument*>(m_frame->document())->startPan(event.event().pos());
+ return true;
+ }
+ }
+#endif
+
+ // We don't do this at the start of mouse down handling,
+ // because we don't want to do it until we know we didn't hit a widget.
+ if (singleClick)
+ focusDocumentView();
+
+ Node* innerNode = event.targetNode();
+
+ m_mousePressNode = innerNode;
+#if ENABLE(DRAG_SUPPORT)
+ m_dragStartPos = event.event().pos();
+#endif
+
+ bool swallowEvent = false;
+ m_mousePressed = true;
+ m_beganSelectingText = false;
+
+ if (event.event().clickCount() == 2)
+ swallowEvent = handleMousePressEventDoubleClick(event);
+ else if (event.event().clickCount() >= 3)
+ swallowEvent = handleMousePressEventTripleClick(event);
+ else
+ swallowEvent = handleMousePressEventSingleClick(event);
+
+ m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
+ || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled(true));
+
+ return swallowEvent;
+}
+
+// There are two kinds of renderer that can autoscroll.
+static bool canAutoscroll(RenderObject* renderer)
+{
+ if (!renderer->isBox())
+ return false;
+
+ // Check for a box that can be scrolled in its own right.
+ if (toRenderBox(renderer)->canBeScrolledAndHasScrollableArea())
+ return true;
+
+ // Check for a box that represents the top level of a web page.
+ // This can be scrolled by calling Chrome::scrollRectIntoView.
+ // This only has an effect on the Mac platform in applications
+ // that put web views into scrolling containers, such as Mac OS X Mail.
+ // The code for this is in RenderLayer::scrollRectToVisible.
+ if (renderer->node() != renderer->document())
+ return false;
+ Frame* frame = renderer->frame();
+ if (!frame)
+ return false;
+ Page* page = frame->page();
+ return page && page->mainFrame() == frame;
+}
+
+#if ENABLE(DRAG_SUPPORT)
+bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
+{
+ if (handleDrag(event))
+ return true;
+
+ if (!m_mousePressed)
+ return false;
+
+ Node* targetNode = event.targetNode();
+ if (event.event().button() != LeftButton || !targetNode || !targetNode->renderer())
+ return false;
+
+#if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms?
+ ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
+#endif
+
+ m_mouseDownMayStartDrag = false;
+
+ if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) {
+ // Find a renderer that can autoscroll.
+ RenderObject* renderer = targetNode->renderer();
+ while (renderer && !canAutoscroll(renderer)) {
+ if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
+ renderer = renderer->document()->ownerElement()->renderer();
+ else
+ renderer = renderer->parent();
+ }
+
+ if (renderer) {
+ m_autoscrollInProgress = true;
+ handleAutoscroll(renderer);
+ }
+
+ m_mouseDownMayStartAutoscroll = false;
+ }
+
+ updateSelectionForMouseDrag(targetNode, event.localPoint());
+ return true;
+}
+
+bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
+{
+ // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
+ // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
+ // in handleMousePressEvent
+
+ if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer())
+ return false;
+
+ if (event.button() != LeftButton || event.clickCount() != 1)
+ return false;
+
+ bool DHTMLFlag;
+ bool UAFlag;
+ allowDHTMLDrag(DHTMLFlag, UAFlag);
+ if (!DHTMLFlag && !UAFlag)
+ return false;
+
+ FrameView* view = m_frame->view();
+ if (!view)
+ return false;
+
+ HitTestRequest request(HitTestRequest::ReadOnly);
+ HitTestResult result(view->windowToContents(event.pos()));
+ m_frame->contentRenderer()->layer()->hitTest(request, result);
+ bool srcIsDHTML;
+ return result.innerNode() && result.innerNode()->renderer()->draggableNode(DHTMLFlag, UAFlag, result.point().x(), result.point().y(), srcIsDHTML);
+}
+
+void EventHandler::updateSelectionForMouseDrag()
+{
+ FrameView* view = m_frame->view();
+ if (!view)
+ return;
+ RenderView* renderer = m_frame->contentRenderer();
+ if (!renderer)
+ return;
+ RenderLayer* layer = renderer->layer();
+ if (!layer)
+ return;
+
+ HitTestRequest request(HitTestRequest::ReadOnly |
+ HitTestRequest::Active |
+ HitTestRequest::MouseMove);
+ HitTestResult result(view->windowToContents(m_currentMousePosition));
+ layer->hitTest(request, result);
+ updateSelectionForMouseDrag(result.innerNode(), result.localPoint());
+}
+
+void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint& localPoint)
+{
+ if (!m_mouseDownMayStartSelect)
+ return;
+
+ if (!targetNode)
+ return;
+
+ if (!canMouseDragExtendSelect(targetNode))
+ return;
+
+ RenderObject* targetRenderer = targetNode->renderer();
+ if (!targetRenderer)
+ return;
+
+ VisiblePosition targetPosition(targetRenderer->positionForPoint(localPoint));
+
+ // Don't modify the selection if we're not on a node.
+ if (targetPosition.isNull())
+ return;
+
+ // Restart the selection if this is the first mouse move. This work is usually
+ // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
+ VisibleSelection newSelection = m_frame->selection()->selection();
+
+#if ENABLE(SVG)
+ // Special case to limit selection to the containing block for SVG text.
+ // FIXME: Isn't there a better non-SVG-specific way to do this?
+ if (Node* selectionBaseNode = newSelection.base().node())
+ if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
+ if (selectionBaseRenderer->isSVGText())
+ if (targetNode->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
+ return;
+#endif
+
+ if (!m_beganSelectingText) {
+ m_beganSelectingText = true;
+ newSelection = VisibleSelection(targetPosition);
+ }
+
+ newSelection.setExtent(targetPosition);
+ if (m_frame->selection()->granularity() != CharacterGranularity)
+ newSelection.expandUsingGranularity(m_frame->selection()->granularity());
+
+ if (m_frame->selection()->shouldChangeSelection(newSelection)) {
+ m_frame->selection()->setIsDirectional(false);
+ m_frame->selection()->setSelection(newSelection, m_frame->selection()->granularity(), MakeNonDirectionalSelection);
+ }
+}
+#endif // ENABLE(DRAG_SUPPORT)
+
+void EventHandler::lostMouseCapture()
+{
+ m_frame->selection()->setCaretBlinkingSuspended(false);
+}
+
+bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
+{
+ if (eventLoopHandleMouseUp(event))
+ return true;
+
+ // If this was the first click in the window, we don't even want to clear the selection.
+ // This case occurs when the user clicks on a draggable element, since we have to process
+ // the mouse down and drag events to see if we might start a drag. For other first clicks
+ // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
+ // ignored upstream of this layer.
+ return eventActivatedView(event.event());
+}
+
+bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
+{
+ if (m_autoscrollInProgress)
+ stopAutoscrollTimer();
+
+ if (handleMouseUp(event))
+ return true;
+
+ // Used to prevent mouseMoveEvent from initiating a drag before
+ // the mouse is pressed again.
+ m_frame->selection()->setCaretBlinkingSuspended(false);
+ m_mousePressed = false;
+ m_capturesDragging = false;
+#if ENABLE(DRAG_SUPPORT)
+ m_mouseDownMayStartDrag = false;
+#endif
+ m_mouseDownMayStartSelect = false;
+ m_mouseDownMayStartAutoscroll = false;
+ m_mouseDownWasInSubframe = false;
+
+ bool handled = false;
+
+ // Clear the selection if the mouse didn't move after the last mouse
+ // press and it's not a context menu click. We do this so when clicking
+ // on the selection, the selection goes away. However, if we are
+ // editing, place the caret.
+ if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText
+#if ENABLE(DRAG_SUPPORT)
+ && m_dragStartPos == event.event().pos()
+#endif
+ && m_frame->selection()->isRange()
+ && event.event().button() != RightButton) {
+ VisibleSelection newSelection;
+ Node* node = event.targetNode();
+ bool caretBrowsing = m_frame->settings()->caretBrowsingEnabled();
+ if (node && (caretBrowsing || node->isContentEditable()) && node->renderer()) {
+ VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
+ newSelection = VisibleSelection(pos);
+ }
+ if (m_frame->selection()->shouldChangeSelection(newSelection))
+ m_frame->selection()->setSelection(newSelection);
+
+ handled = true;
+ }
+
+ m_frame->selection()->notifyRendererOfSelectionChange(true);
+
+ m_frame->selection()->selectFrameElementInParentIfFullySelected();
+
+ return handled;
+}
+
+void EventHandler::handleAutoscroll(RenderObject* renderer)
+{
+ // We don't want to trigger the autoscroll or the panScroll if it's already active
+ if (m_autoscrollTimer.isActive())
+ return;
+
+ setAutoscrollRenderer(renderer);
+
+#if ENABLE(PAN_SCROLLING)
+ if (m_panScrollInProgress) {
+ m_panScrollStartPos = currentMousePosition();
+ if (FrameView* view = m_frame->view())
+ view->addPanScrollIcon(m_panScrollStartPos);
+ // If we're not in the top frame we notify it that we doing a panScroll.
+ if (Page* page = m_frame->page()) {
+ Frame* mainFrame = page->mainFrame();
+ if (m_frame != mainFrame)
+ mainFrame->eventHandler()->setPanScrollInProgress(true);
+ }
+ }
+#endif
+
+ startAutoscrollTimer();
+}
+
+void EventHandler::autoscrollTimerFired(Timer<EventHandler>*)
+{
+ RenderObject* r = autoscrollRenderer();
+ if (!r || !r->isBox()) {
+ stopAutoscrollTimer();
+ return;
+ }
+
+ if (m_autoscrollInProgress) {
+ if (!m_mousePressed) {
+ stopAutoscrollTimer();
+ return;
+ }
+ toRenderBox(r)->autoscroll();
+ } else {
+ // we verify that the main frame hasn't received the order to stop the panScroll
+ if (Page* page = m_frame->page()) {
+ if (!page->mainFrame()->eventHandler()->panScrollInProgress()) {
+ stopAutoscrollTimer();
+ return;
+ }
+ }
+#if ENABLE(PAN_SCROLLING)
+ updatePanScrollState();
+ toRenderBox(r)->panScroll(m_panScrollStartPos);
+#endif
+ }
+}
+
+#if ENABLE(PAN_SCROLLING)
+
+void EventHandler::startPanScrolling(RenderObject* renderer)
+{
+ m_panScrollInProgress = true;
+ m_panScrollButtonPressed = true;
+ handleAutoscroll(renderer);
+ invalidateClick();
+}
+
+void EventHandler::updatePanScrollState()
+{
+ FrameView* view = m_frame->view();
+ if (!view)
+ return;
+
+ // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll
+ // So we don't want to change the cursor over this area
+ bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - ScrollView::noPanScrollRadius);
+ bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + ScrollView::noPanScrollRadius);
+ bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + ScrollView::noPanScrollRadius);
+ bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - ScrollView::noPanScrollRadius);
+
+ if ((east || west || north || south) && m_panScrollButtonPressed)
+ m_springLoadedPanScrollInProgress = true;
+
+ if (north) {
+ if (east)
+ view->setCursor(northEastPanningCursor());
+ else if (west)
+ view->setCursor(northWestPanningCursor());
+ else
+ view->setCursor(northPanningCursor());
+ } else if (south) {
+ if (east)
+ view->setCursor(southEastPanningCursor());
+ else if (west)
+ view->setCursor(southWestPanningCursor());
+ else
+ view->setCursor(southPanningCursor());
+ } else if (east)
+ view->setCursor(eastPanningCursor());
+ else if (west)
+ view->setCursor(westPanningCursor());
+ else
+ view->setCursor(middlePanningCursor());
+}
+
+#endif // ENABLE(PAN_SCROLLING)
+
+RenderObject* EventHandler::autoscrollRenderer() const
+{
+ return m_autoscrollRenderer;
+}
+
+void EventHandler::updateAutoscrollRenderer()
+{
+ if (!m_autoscrollRenderer)
+ return;
+
+ HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true);
+
+ if (Node* nodeAtPoint = hitTest.innerNode())
+ m_autoscrollRenderer = nodeAtPoint->renderer();
+
+ while (m_autoscrollRenderer && !canAutoscroll(m_autoscrollRenderer))
+ m_autoscrollRenderer = m_autoscrollRenderer->parent();
+}
+
+void EventHandler::setAutoscrollRenderer(RenderObject* renderer)
+{
+ m_autoscrollRenderer = renderer;
+}
+
+#if ENABLE(DRAG_SUPPORT)
+void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const
+{
+ flagDHTML = false;
+ flagUA = false;
+
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ FrameView* view = m_frame->view();
+ if (!view)
+ return;
+
+ unsigned mask = page->dragController()->delegateDragSourceAction(view->contentsToWindow(m_mouseDownPos));
+ flagDHTML = (mask & DragSourceActionDHTML) != DragSourceActionNone;
+ flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection));
+}
+#endif // ENABLE(DRAG_SUPPORT)
+
+HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars, HitTestRequest::HitTestRequestType hitType, const IntSize& padding)
+{
+ HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width());
+ if (!m_frame->contentRenderer())
+ return result;
+ if (ignoreClipping)
+ hitType |= HitTestRequest::IgnoreClipping;
+ m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), result);
+
+ while (true) {
+ Node* n = result.innerNode();
+ if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget())
+ break;
+ RenderWidget* renderWidget = toRenderWidget(n->renderer());
+ Widget* widget = renderWidget->widget();
+ if (!widget || !widget->isFrameView())
+ break;
+ Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame();
+ if (!frame || !frame->contentRenderer())
+ break;
+ FrameView* view = static_cast<FrameView*>(widget);
+ IntPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(),
+ result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop());
+ HitTestResult widgetHitTestResult(widgetPoint, padding.height(), padding.width(), padding.height(), padding.width());
+ frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), widgetHitTestResult);
+ result = widgetHitTestResult;
+
+ if (testScrollbars == ShouldHitTestScrollbars) {
+ Scrollbar* eventScrollbar = view->scrollbarAtPoint(point);
+ if (eventScrollbar)
+ result.setScrollbar(eventScrollbar);
+ }
+ }
+
+ // If our HitTestResult is not visible, then we started hit testing too far down the frame chain.
+ // Another hit test at the main frame level should get us the correct visible result.
+ Frame* resultFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : 0;
+ if (Page* page = m_frame->page()) {
+ Frame* mainFrame = page->mainFrame();
+ if (m_frame != mainFrame && resultFrame && resultFrame != mainFrame && !resultFrame->editor()->insideVisibleArea(result.point())) {
+ FrameView* resultView = resultFrame->view();
+ FrameView* mainView = mainFrame->view();
+ if (resultView && mainView) {
+ IntPoint windowPoint = resultView->contentsToWindow(result.point());
+ IntPoint mainFramePoint = mainView->windowToContents(windowPoint);
+ result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping, testScrollbars, hitType, padding);
+ }
+ }
+ }
+
+ if (!allowShadowContent)
+ result.setToNonShadowAncestor();
+
+ return result;
+}
+
+
+void EventHandler::startAutoscrollTimer()
+{
+ m_autoscrollTimer.startRepeating(autoscrollInterval);
+}
+
+void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
+{
+ if (m_autoscrollInProgress) {
+ if (m_mouseDownWasInSubframe) {
+ if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get()))
+ subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed);
+ return;
+ }
+ }
+
+ if (autoscrollRenderer()) {
+ if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress))
+ toRenderBox(autoscrollRenderer())->stopAutoscroll();
+#if ENABLE(PAN_SCROLLING)
+ if (m_panScrollInProgress) {
+ if (FrameView* view = m_frame->view()) {
+ view->removePanScrollIcon();
+ view->setCursor(pointerCursor());
+ }
+ }
+#endif
+
+ setAutoscrollRenderer(0);
+ }
+
+ m_autoscrollTimer.stop();
+
+ m_panScrollInProgress = false;
+ m_springLoadedPanScrollInProgress = false;
+
+ // If we're not in the top frame we notify it that we are not doing a panScroll any more.
+ if (Page* page = m_frame->page()) {
+ Frame* mainFrame = page->mainFrame();
+ if (m_frame != mainFrame)
+ mainFrame->eventHandler()->setPanScrollInProgress(false);
+ }
+
+ m_autoscrollInProgress = false;
+}
+
+Node* EventHandler::mousePressNode() const
+{
+ return m_mousePressNode.get();
+}
+
+void EventHandler::setMousePressNode(PassRefPtr<Node> node)
+{
+ m_mousePressNode = node;
+}
+
+bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
+{
+ Node* node = startingNode;
+
+ if (!node)
+ node = m_frame->document()->focusedNode();
+
+ if (!node)
+ node = m_mousePressNode.get();
+
+ if (node) {
+ RenderObject* r = node->renderer();
+ if (r && !r->isListBox() && r->enclosingBox()->scroll(direction, granularity)) {
+ setFrameWasScrolledByUser();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
+{
+ Node* node = startingNode;
+
+ if (!node)
+ node = m_frame->document()->focusedNode();
+
+ if (!node)
+ node = m_mousePressNode.get();
+
+ if (node) {
+ RenderObject* r = node->renderer();
+ if (r && !r->isListBox() && r->enclosingBox()->logicalScroll(direction, granularity)) {
+ setFrameWasScrolledByUser();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
+{
+ // The layout needs to be up to date to determine if we can scroll. We may be
+ // here because of an onLoad event, in which case the final layout hasn't been performed yet.
+ m_frame->document()->updateLayoutIgnorePendingStylesheets();
+ if (scrollOverflow(direction, granularity, startingNode))
+ return true;
+ Frame* frame = m_frame;
+ FrameView* view = frame->view();
+ if (view && view->scroll(direction, granularity))
+ return true;
+ frame = frame->tree()->parent();
+ if (!frame)
+ return false;
+ return frame->eventHandler()->scrollRecursively(direction, granularity, m_frame->document()->ownerElement());
+}
+
+bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
+{
+ // The layout needs to be up to date to determine if we can scroll. We may be
+ // here because of an onLoad event, in which case the final layout hasn't been performed yet.
+ m_frame->document()->updateLayoutIgnorePendingStylesheets();
+ if (logicalScrollOverflow(direction, granularity, startingNode))
+ return true;
+ Frame* frame = m_frame;
+ FrameView* view = frame->view();
+
+ bool scrolled = false;
+#if PLATFORM(MAC)
+ // Mac also resets the scroll position in the inline direction.
+ if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument))
+ scrolled = true;
+#endif
+ if (view && view->logicalScroll(direction, granularity))
+ scrolled = true;
+
+ if (scrolled)
+ return true;
+
+ frame = frame->tree()->parent();
+ if (!frame)
+ return false;
+
+ return frame->eventHandler()->logicalScrollRecursively(direction, granularity, m_frame->document()->ownerElement());
+}
+
+IntPoint EventHandler::currentMousePosition() const
+{
+ return m_currentMousePosition;
+}
+
+Frame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
+{
+ if (!hitTestResult.isOverWidget())
+ return 0;
+ return EventHandler::subframeForTargetNode(hitTestResult.targetNode());
+}
+
+Frame* EventHandler::subframeForTargetNode(Node* node)
+{
+ if (!node)
+ return 0;
+
+ RenderObject* renderer = node->renderer();
+ if (!renderer || !renderer->isWidget())
+ return 0;
+
+ Widget* widget = toRenderWidget(renderer)->widget();
+ if (!widget || !widget->isFrameView())
+ return 0;
+
+ return static_cast<FrameView*>(widget)->frame();
+}
+
+static bool isSubmitImage(Node* node)
+{
+ return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->isImageButton();
+}
+
+// Returns true if the node's editable block is not current focused for editing
+static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
+{
+ return frame->selection()->rootEditableElement() != node->rootEditableElement();
+}
+
+Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scrollbar* scrollbar)
+{
+ Node* node = event.targetNode();
+ RenderObject* renderer = node ? node->renderer() : 0;
+ RenderStyle* style = renderer ? renderer->style() : 0;
+
+ bool horizontalText = !style || style->isHorizontalWritingMode();
+ const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
+
+ // During selection, use an I-beam no matter what we're over.
+ // If you're capturing mouse events for a particular node, don't treat this as a selection.
+ if (m_mousePressed && m_mouseDownMayStartSelect && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode)
+ return iBeam;
+
+ if (renderer && renderer->isFrameSet()) {
+ RenderFrameSet* frameSetRenderer = toRenderFrameSet(renderer);
+ if (frameSetRenderer->canResizeRow(event.localPoint()))
+ return rowResizeCursor();
+ if (frameSetRenderer->canResizeColumn(event.localPoint()))
+ return columnResizeCursor();
+ }
+
+ if (style && style->cursors()) {
+ const CursorList* cursors = style->cursors();
+ for (unsigned i = 0; i < cursors->size(); ++i) {
+ const CachedImage* cimage = 0;
+ StyleImage* image = (*cursors)[i].image();
+ if (image && image->isCachedImage())
+ cimage = static_cast<StyleCachedImage*>(image)->cachedImage();
+ if (!cimage)
+ continue;
+ IntPoint hotSpot = (*cursors)[i].hotSpot();
+ // Limit the size of cursors so that they cannot be used to cover UI elements in chrome.
+ IntSize size = cimage->image()->size();
+ if (size.width() > 128 || size.height() > 128)
+ continue;
+ if (cimage->image()->isNull())
+ break;
+ if (!cimage->errorOccurred())
+ return Cursor(cimage->image(), hotSpot);
+ }
+ }
+
+ switch (style ? style->cursor() : CURSOR_AUTO) {
+ case CURSOR_AUTO: {
+ bool editable = (node && node->isContentEditable());
+ bool editableLinkEnabled = false;
+
+ // If the link is editable, then we need to check the settings to see whether or not the link should be followed
+ if (editable) {
+ ASSERT(m_frame->settings());
+ switch (m_frame->settings()->editableLinkBehavior()) {
+ default:
+ case EditableLinkDefaultBehavior:
+ case EditableLinkAlwaysLive:
+ editableLinkEnabled = true;
+ break;
+
+ case EditableLinkNeverLive:
+ editableLinkEnabled = false;
+ break;
+
+ case EditableLinkLiveWhenNotFocused:
+ editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || event.event().shiftKey();
+ break;
+
+ case EditableLinkOnlyLiveWithShiftKey:
+ editableLinkEnabled = event.event().shiftKey();
+ break;
+ }
+ }
+
+ if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled))
+ return handCursor();
+ bool inResizer = false;
+ if (renderer) {
+ if (RenderLayer* layer = renderer->enclosingLayer()) {
+ if (FrameView* view = m_frame->view())
+ inResizer = layer->isPointInResizeControl(view->windowToContents(event.event().pos()));
+ }
+ }
+ if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !scrollbar)
+ return iBeam;
+ return pointerCursor();
+ }
+ case CURSOR_CROSS:
+ return crossCursor();
+ case CURSOR_POINTER:
+ return handCursor();
+ case CURSOR_MOVE:
+ return moveCursor();
+ case CURSOR_ALL_SCROLL:
+ return moveCursor();
+ case CURSOR_E_RESIZE:
+ return eastResizeCursor();
+ case CURSOR_W_RESIZE:
+ return westResizeCursor();
+ case CURSOR_N_RESIZE:
+ return northResizeCursor();
+ case CURSOR_S_RESIZE:
+ return southResizeCursor();
+ case CURSOR_NE_RESIZE:
+ return northEastResizeCursor();
+ case CURSOR_SW_RESIZE:
+ return southWestResizeCursor();
+ case CURSOR_NW_RESIZE:
+ return northWestResizeCursor();
+ case CURSOR_SE_RESIZE:
+ return southEastResizeCursor();
+ case CURSOR_NS_RESIZE:
+ return northSouthResizeCursor();
+ case CURSOR_EW_RESIZE:
+ return eastWestResizeCursor();
+ case CURSOR_NESW_RESIZE:
+ return northEastSouthWestResizeCursor();
+ case CURSOR_NWSE_RESIZE:
+ return northWestSouthEastResizeCursor();
+ case CURSOR_COL_RESIZE:
+ return columnResizeCursor();
+ case CURSOR_ROW_RESIZE:
+ return rowResizeCursor();
+ case CURSOR_TEXT:
+ return iBeamCursor();
+ case CURSOR_WAIT:
+ return waitCursor();
+ case CURSOR_HELP:
+ return helpCursor();
+ case CURSOR_VERTICAL_TEXT:
+ return verticalTextCursor();
+ case CURSOR_CELL:
+ return cellCursor();
+ case CURSOR_CONTEXT_MENU:
+ return contextMenuCursor();
+ case CURSOR_PROGRESS:
+ return progressCursor();
+ case CURSOR_NO_DROP:
+ return noDropCursor();
+ case CURSOR_ALIAS:
+ return aliasCursor();
+ case CURSOR_COPY:
+ return copyCursor();
+ case CURSOR_NONE:
+ return noneCursor();
+ case CURSOR_NOT_ALLOWED:
+ return notAllowedCursor();
+ case CURSOR_DEFAULT:
+ return pointerCursor();
+ case CURSOR_WEBKIT_ZOOM_IN:
+ return zoomInCursor();
+ case CURSOR_WEBKIT_ZOOM_OUT:
+ return zoomOutCursor();
+ case CURSOR_WEBKIT_GRAB:
+ return grabCursor();
+ case CURSOR_WEBKIT_GRABBING:
+ return grabbingCursor();
+ }
+ return pointerCursor();
+}
+
+static IntPoint documentPointForWindowPoint(Frame* frame, const IntPoint& windowPoint)
+{
+ FrameView* view = frame->view();
+ // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
+ // Historically the code would just crash; this is clearly no worse than that.
+ return view ? view->windowToContents(windowPoint) : windowPoint;
+}
+
+bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
+{
+ RefPtr<FrameView> protector(m_frame->view());
+
+ UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+
+ cancelFakeMouseMoveEvent();
+ m_mousePressed = true;
+ m_capturesDragging = true;
+ m_currentMousePosition = mouseEvent.pos();
+ m_mouseDownTimestamp = mouseEvent.timestamp();
+#if ENABLE(DRAG_SUPPORT)
+ m_mouseDownMayStartDrag = false;
+#endif
+ m_mouseDownMayStartSelect = false;
+ m_mouseDownMayStartAutoscroll = false;
+ if (FrameView* view = m_frame->view())
+ m_mouseDownPos = view->windowToContents(mouseEvent.pos());
+ else {
+ invalidateClick();
+ return false;
+ }
+ m_mouseDownWasInSubframe = false;
+
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ // Add IgnoreClipping because fixed position elements are moved only on the
+ // UI thread. Nodes in fixed position elements are clipped out by the view
+ // without IgnoreClipping.
+ HitTestRequest request(HitTestRequest::Active | HitTestRequest::IgnoreClipping);
+#else
+ HitTestRequest request(HitTestRequest::Active);
+#endif
+ // Save the document point we generate in case the window coordinate is invalidated by what happens
+ // when we dispatch the event.
+ IntPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.pos());
+ MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
+
+ if (!mev.targetNode()) {
+ invalidateClick();
+ return false;
+ }
+
+ m_mousePressNode = mev.targetNode();
+
+#if ENABLE(INSPECTOR)
+ if (Page* page = m_frame->page()) {
+ InspectorController* inspector = page->inspectorController();
+ if (inspector && inspector->enabled() && inspector->searchingForNodeInPage()) {
+ inspector->handleMousePress();
+ invalidateClick();
+ return true;
+ }
+ }
+#endif
+
+ Frame* subframe = subframeForHitTestResult(mev);
+ if (subframe && passMousePressEventToSubframe(mev, subframe)) {
+ // Start capturing future events for this frame. We only do this if we didn't clear
+ // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
+ m_capturesDragging = subframe->eventHandler()->capturesDragging();
+ if (m_mousePressed && m_capturesDragging) {
+ m_capturingMouseEventsNode = mev.targetNode();
+ m_eventHandlerWillResetCapturingMouseEventsNode = true;
+ }
+ invalidateClick();
+ return true;
+ }
+
+#if ENABLE(PAN_SCROLLING)
+ Page* page = m_frame->page();
+ if ((page && page->mainFrame()->eventHandler()->panScrollInProgress()) || m_autoscrollInProgress) {
+ stopAutoscrollTimer();
+ invalidateClick();
+ return true;
+ }
+#endif
+
+ m_clickCount = mouseEvent.clickCount();
+ m_clickNode = mev.targetNode();
+
+ if (FrameView* view = m_frame->view()) {
+ RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
+ IntPoint p = view->windowToContents(mouseEvent.pos());
+ if (layer && layer->isPointInResizeControl(p)) {
+ layer->setInResizeMode(true);
+ m_resizeLayer = layer;
+ m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
+ invalidateClick();
+ return true;
+ }
+ }
+
+ m_frame->selection()->setCaretBlinkingSuspended(true);
+
+ bool swallowEvent = dispatchMouseEvent(eventNames().mousedownEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
+ m_capturesDragging = !swallowEvent;
+
+ // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
+ // in case the scrollbar widget was destroyed when the mouse event was handled.
+ if (mev.scrollbar()) {
+ const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
+ HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
+ mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
+ if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
+ m_lastScrollbarUnderMouse = 0;
+ }
+
+ if (swallowEvent) {
+ // scrollbars should get events anyway, even disabled controls might be scrollable
+ Scrollbar* scrollbar = mev.scrollbar();
+
+ updateLastScrollbarUnderMouse(scrollbar, true);
+
+ if (scrollbar)
+ passMousePressEventToScrollbar(mev, scrollbar);
+ } else {
+ // Refetch the event target node if it currently is the shadow node inside an <input> element.
+ // If a mouse event handler changes the input element type to one that has a widget associated,
+ // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
+ // event target node can't still be the shadow node.
+ if (mev.targetNode()->isShadowRoot() && mev.targetNode()->shadowHost()->hasTagName(inputTag)) {
+ HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
+ mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
+ }
+
+ FrameView* view = m_frame->view();
+ Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.pos()) : 0;
+ if (!scrollbar)
+ scrollbar = mev.scrollbar();
+
+ updateLastScrollbarUnderMouse(scrollbar, true);
+
+ if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
+ swallowEvent = true;
+ else
+ swallowEvent = handleMousePressEvent(mev);
+ }
+
+ return swallowEvent;
+}
+
+// This method only exists for platforms that don't know how to deliver
+bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
+{
+ RefPtr<FrameView> protector(m_frame->view());
+
+ UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+
+ // We get this instead of a second mouse-up
+ m_mousePressed = false;
+ m_currentMousePosition = mouseEvent.pos();
+
+ HitTestRequest request(HitTestRequest::Active);
+ MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
+ Frame* subframe = subframeForHitTestResult(mev);
+ if (m_eventHandlerWillResetCapturingMouseEventsNode)
+ m_capturingMouseEventsNode = 0;
+ if (subframe && passMousePressEventToSubframe(mev, subframe))
+ return true;
+
+ m_clickCount = mouseEvent.clickCount();
+ bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
+
+ bool swallowClickEvent = mouseEvent.button() == LeftButton && mev.targetNode() == m_clickNode && dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
+
+ if (m_lastScrollbarUnderMouse)
+ swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp();
+
+ bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mev);
+
+ invalidateClick();
+
+ return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
+}
+
+bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
+{
+ HitTestResult hoveredNode = HitTestResult(IntPoint());
+ bool result = handleMouseMoveEvent(event, &hoveredNode);
+
+ Page* page = m_frame->page();
+ if (!page)
+ return result;
+
+ hoveredNode.setToNonShadowAncestor();
+ page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
+ page->chrome()->setToolTip(hoveredNode);
+ return result;
+}
+
+bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode)
+{
+ // in Radar 3703768 we saw frequent crashes apparently due to the
+ // part being null here, which seems impossible, so check for nil
+ // but also assert so that we can try to figure this out in debug
+ // builds, if it happens.
+ ASSERT(m_frame);
+ if (!m_frame)
+ return false;
+
+ RefPtr<FrameView> protector(m_frame->view());
+ m_currentMousePosition = mouseEvent.pos();
+
+ if (m_hoverTimer.isActive())
+ m_hoverTimer.stop();
+
+ cancelFakeMouseMoveEvent();
+
+#if ENABLE(SVG)
+ if (m_svgPan) {
+ static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition);
+ return true;
+ }
+#endif
+
+ if (m_frameSetBeingResized)
+ return dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
+
+ // Send events right to a scrollbar if the mouse is pressed.
+ if (m_lastScrollbarUnderMouse && m_mousePressed)
+ return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
+
+ // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent
+ // if we are allowed to select.
+ // This means that :hover and :active freeze in the state they were in when the mouse
+ // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
+ HitTestRequest::HitTestRequestType hitType = HitTestRequest::MouseMove;
+ if (m_mousePressed && m_mouseDownMayStartSelect)
+ hitType |= HitTestRequest::ReadOnly;
+ if (m_mousePressed)
+ hitType |= HitTestRequest::Active;
+
+#if ENABLE(TOUCH_EVENTS)
+ // Treat any mouse move events as readonly if the user is currently touching the screen.
+ if (m_touchPressed)
+ hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
+#endif
+ HitTestRequest request(hitType);
+ MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
+ if (hoveredNode)
+ *hoveredNode = mev.hitTestResult();
+
+ Scrollbar* scrollbar = 0;
+
+ if (m_resizeLayer && m_resizeLayer->inResizeMode())
+ m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner);
+ else {
+ if (FrameView* view = m_frame->view())
+ scrollbar = view->scrollbarAtPoint(mouseEvent.pos());
+
+ if (!scrollbar)
+ scrollbar = mev.scrollbar();
+
+ updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
+ }
+
+ bool swallowEvent = false;
+ RefPtr<Frame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
+
+ // We want mouseouts to happen first, from the inside out. First send a move event to the last subframe so that it will fire mouseouts.
+ if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree()->isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
+ passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
+
+ if (newSubframe) {
+ // Update over/out state before passing the event to the subframe.
+ updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true);
+
+ // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
+ // node to be detached from its FrameView, in which case the event should not be passed.
+ if (newSubframe->view())
+ swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
+ } else {
+ if (scrollbar && !m_mousePressed)
+ scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
+ if (Page* page = m_frame->page()) {
+ if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !page->mainFrame()->eventHandler()->panScrollInProgress()) {
+ // Plugins set cursor on their own. The only case WebKit intervenes is resetting cursor to arrow on mouse enter,
+ // in case the particular plugin doesn't manipulate cursor at all. Thus, even a CSS cursor set on body has no
+ // effect on plugins (which matches Firefox).
+ bool overPluginElement = false;
+ if (mev.targetNode() && mev.targetNode()->isHTMLElement()) {
+ HTMLElement* el = static_cast<HTMLElement*>(mev.targetNode());
+ overPluginElement = el->hasTagName(appletTag) || el->hasTagName(objectTag) || el->hasTagName(embedTag);
+ }
+ if (!overPluginElement) {
+ if (FrameView* view = m_frame->view())
+ view->setCursor(selectCursor(mev, scrollbar));
+ }
+ }
+ }
+ }
+
+ m_lastMouseMoveEventSubframe = newSubframe;
+
+ if (swallowEvent)
+ return true;
+
+ swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true);
+#if ENABLE(DRAG_SUPPORT)
+ if (!swallowEvent)
+ swallowEvent = handleMouseDraggedEvent(mev);
+#endif // ENABLE(DRAG_SUPPORT)
+
+ return swallowEvent;
+}
+
+void EventHandler::invalidateClick()
+{
+ m_clickCount = 0;
+ m_clickNode = 0;
+}
+
+bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
+{
+ RefPtr<FrameView> protector(m_frame->view());
+
+ UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+
+#if ENABLE(PAN_SCROLLING)
+ if (mouseEvent.button() == MiddleButton)
+ m_panScrollButtonPressed = false;
+ if (m_springLoadedPanScrollInProgress)
+ stopAutoscrollTimer();
+#endif
+
+ m_mousePressed = false;
+ m_currentMousePosition = mouseEvent.pos();
+
+#if ENABLE(SVG)
+ if (m_svgPan) {
+ m_svgPan = false;
+ static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition);
+ return true;
+ }
+#endif
+
+ if (m_frameSetBeingResized)
+ return dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
+
+ if (m_lastScrollbarUnderMouse) {
+ invalidateClick();
+ return m_lastScrollbarUnderMouse->mouseUp();
+ }
+
+#if ENABLE(COMPOSITED_FIXED_ELEMENTS)
+ // Add IgnoreClipping because fixed position elements are moved only on the
+ // UI thread. Nodes in fixed position elements are clipped out by the view
+ // without IgnoreClipping.
+ HitTestRequest request(HitTestRequest::MouseUp | HitTestRequest::IgnoreClipping);
+#else
+ HitTestRequest request(HitTestRequest::MouseUp);
+#endif
+ MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
+ Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
+ if (m_eventHandlerWillResetCapturingMouseEventsNode)
+ m_capturingMouseEventsNode = 0;
+ if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
+ return true;
+
+ bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
+
+ bool swallowClickEvent = m_clickCount > 0 && mouseEvent.button() == LeftButton && mev.targetNode() == m_clickNode && dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
+
+ if (m_resizeLayer) {
+ m_resizeLayer->setInResizeMode(false);
+ m_resizeLayer = 0;
+ }
+
+ bool swallowMouseReleaseEvent = false;
+ if (!swallowMouseUpEvent)
+ swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
+
+ invalidateClick();
+
+ return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
+}
+
+#if ENABLE(DRAG_SUPPORT)
+bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
+{
+ FrameView* view = m_frame->view();
+
+ // FIXME: We might want to dispatch a dragleave even if the view is gone.
+ if (!view)
+ return false;
+
+ view->resetDeferredRepaintDelay();
+ IntPoint contentsPos = view->windowToContents(event.pos());
+
+ RefPtr<MouseEvent> me = MouseEvent::create(eventType,
+ true, true, m_frame->document()->defaultView(),
+ 0, event.globalX(), event.globalY(), contentsPos.x(), contentsPos.y(),
+ event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
+ 0, 0, clipboard);
+
+ ExceptionCode ec;
+ dragTarget->dispatchEvent(me.get(), ec);
+ return me->defaultPrevented();
+}
+
+bool EventHandler::canHandleDragAndDropForTarget(DragAndDropHandleType type, Node* target, const PlatformMouseEvent& event, Clipboard* clipboard, bool* accepted)
+{
+ bool canHandle = false;
+ bool wasAccepted = false;
+
+ if (target->hasTagName(frameTag) || target->hasTagName(iframeTag)) {
+ Frame* frame = static_cast<HTMLFrameElementBase*>(target)->contentFrame();
+ if (frame) {
+ switch (type) {
+ case UpdateDragAndDrop:
+ wasAccepted = frame->eventHandler()->updateDragAndDrop(event, clipboard);
+ break;
+ case CancelDragAndDrop:
+ frame->eventHandler()->cancelDragAndDrop(event, clipboard);
+ break;
+ case PerformDragAndDrop:
+ wasAccepted = frame->eventHandler()->performDragAndDrop(event, clipboard);
+ break;
+ }
+ }
+ } else
+ canHandle = true;
+
+ if (accepted)
+ *accepted = wasAccepted;
+
+ return canHandle;
+}
+
+bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
+{
+ bool accept = false;
+
+ if (!m_frame->view())
+ return false;
+
+ HitTestRequest request(HitTestRequest::ReadOnly);
+ MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
+
+ // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
+ Node* newTarget = mev.targetNode();
+ if (newTarget && newTarget->isTextNode())
+ newTarget = newTarget->parentNode();
+ if (newTarget)
+ newTarget = newTarget->shadowAncestorNode();
+
+ if (m_dragTarget != newTarget) {
+ // FIXME: this ordering was explicitly chosen to match WinIE. However,
+ // it is sometimes incorrect when dragging within subframes, as seen with
+ // LayoutTests/fast/events/drag-in-frames.html.
+ //
+ // Moreover, this ordering conforms to section 7.9.4 of the HTML 5 spec. <http://dev.w3.org/html5/spec/Overview.html#drag-and-drop-processing-model>.
+ if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) {
+ // As per section 7.9.4 of the HTML 5 spec., we must always fire a drag event before firing a dragenter, dragleave, or dragover event.
+ if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
+ // for now we don't care if event handler cancels default behavior, since there is none
+ dispatchDragSrcEvent(eventNames().dragEvent, event);
+ }
+ accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget, event, clipboard);
+ }
+
+ if (m_dragTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, m_dragTarget.get(), event, clipboard, &accept))
+ dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
+
+ if (newTarget) {
+ // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
+ // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
+ m_shouldOnlyFireDragOverEvent = true;
+ }
+ } else {
+ if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) {
+ // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
+ if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
+ // for now we don't care if event handler cancels default behavior, since there is none
+ dispatchDragSrcEvent(eventNames().dragEvent, event);
+ }
+ accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget, event, clipboard);
+ m_shouldOnlyFireDragOverEvent = false;
+ }
+ }
+ m_dragTarget = newTarget;
+
+ return accept;
+}
+
+void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
+{
+ if (m_dragTarget && canHandleDragAndDropForTarget(CancelDragAndDrop, m_dragTarget.get(), event, clipboard)) {
+ if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML)
+ dispatchDragSrcEvent(eventNames().dragEvent, event);
+ dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
+ }
+ clearDragState();
+}
+
+bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
+{
+ bool accept = false;
+ if (m_dragTarget && canHandleDragAndDropForTarget(PerformDragAndDrop, m_dragTarget.get(), event, clipboard, &accept))
+ dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
+ clearDragState();
+ return accept;
+}
+
+void EventHandler::clearDragState()
+{
+ m_dragTarget = 0;
+ m_capturingMouseEventsNode = 0;
+ m_shouldOnlyFireDragOverEvent = false;
+#if PLATFORM(MAC)
+ m_sendingEventToSubview = false;
+#endif
+}
+#endif // ENABLE(DRAG_SUPPORT)
+
+void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
+{
+ m_capturingMouseEventsNode = n;
+ m_eventHandlerWillResetCapturingMouseEventsNode = false;
+}
+
+MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
+{
+ ASSERT(m_frame);
+ ASSERT(m_frame->document());
+
+ return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.pos()), mev);
+}
+
+#if ENABLE(SVG)
+static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
+{
+ if (!referenceNode || !referenceNode->isSVGElement())
+ return 0;
+
+ Node* shadowTreeElement = referenceNode->shadowTreeRootNode();
+ if (!shadowTreeElement)
+ return 0;
+
+ Element* shadowTreeParentElement = shadowTreeElement->shadowHost();
+ if (!shadowTreeParentElement)
+ return 0;
+
+ ASSERT(shadowTreeParentElement->hasTagName(useTag));
+ return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
+}
+#endif
+
+void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
+{
+ Node* result = targetNode;
+
+ // If we're capturing, we always go right to that node.
+ if (m_capturingMouseEventsNode)
+ result = m_capturingMouseEventsNode.get();
+ else {
+ // If the target node is a text node, dispatch on the parent node - rdar://4196646
+ if (result && result->isTextNode())
+ result = result->parentNode();
+ }
+ m_nodeUnderMouse = result;
+#if ENABLE(SVG)
+ m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result);
+
+ // <use> shadow tree elements may have been recloned, update node under mouse in any case
+ if (m_lastInstanceUnderMouse) {
+ SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement();
+ SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement();
+
+ if (lastCorrespondingElement && lastCorrespondingUseElement) {
+ HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement();
+
+ // Locate the recloned shadow tree element for our corresponding instance
+ HashSet<SVGElementInstance*>::iterator end = instances.end();
+ for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
+ SVGElementInstance* instance = (*it);
+ ASSERT(instance->correspondingElement() == lastCorrespondingElement);
+
+ if (instance == m_lastInstanceUnderMouse)
+ continue;
+
+ if (instance->correspondingUseElement() != lastCorrespondingUseElement)
+ continue;
+
+ SVGElement* shadowTreeElement = instance->shadowTreeElement();
+ if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement)
+ continue;
+
+ m_lastNodeUnderMouse = shadowTreeElement;
+ m_lastInstanceUnderMouse = instance;
+ break;
+ }
+ }
+ }
+#endif
+
+ // Fire mouseout/mouseover if the mouse has shifted to a different node.
+ if (fireMouseOverOut) {
+ if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
+ m_lastNodeUnderMouse = 0;
+ m_lastScrollbarUnderMouse = 0;
+#if ENABLE(SVG)
+ m_lastInstanceUnderMouse = 0;
+#endif
+ }
+
+ if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
+ // send mouseout event to the old node
+ if (m_lastNodeUnderMouse)
+ m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_nodeUnderMouse.get());
+ // send mouseover event to the new node
+ if (m_nodeUnderMouse)
+ m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastNodeUnderMouse.get());
+ }
+ m_lastNodeUnderMouse = m_nodeUnderMouse;
+#if ENABLE(SVG)
+ m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get());
+#endif
+ }
+}
+
+bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
+{
+ if (FrameView* view = m_frame->view())
+ view->resetDeferredRepaintDelay();
+
+ updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
+
+ bool swallowEvent = false;
+
+ if (m_nodeUnderMouse)
+ swallowEvent = m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
+
+ if (!swallowEvent && eventType == eventNames().mousedownEvent) {
+
+ // If clicking on a frame scrollbar, do not mess up with content focus.
+ if (FrameView* view = m_frame->view()) {
+ if (view->scrollbarAtPoint(mouseEvent.pos()))
+ return false;
+ }
+
+ // The layout needs to be up to date to determine if an element is focusable.
+ m_frame->document()->updateLayoutIgnorePendingStylesheets();
+
+ // Blur current focus node when a link/button is clicked; this
+ // is expected by some sites that rely on onChange handlers running
+ // from form fields before the button click is processed.
+ Node* node = m_nodeUnderMouse.get();
+
+ // Walk up the DOM tree to search for a node to focus.
+ while (node) {
+ if (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
+ // will set a selection inside it, which will call setFocuseNodeIfNeeded.
+ ExceptionCode ec = 0;
+ Node* n = node->isShadowRoot() ? node->shadowHost() : node;
+ if (m_frame->selection()->isRange()
+ && m_frame->selection()->toNormalizedRange()->compareNode(n, ec) == Range::NODE_INSIDE
+ && n->isDescendantOf(m_frame->document()->focusedNode()))
+ return false;
+
+ break;
+ }
+ node = node->parentOrHostNode();
+ }
+
+ // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
+ // if the page already set it (e.g., by canceling default behavior).
+ if (Page* page = m_frame->page()) {
+ if (node && node->isMouseFocusable()) {
+ if (!page->focusController()->setFocusedNode(node, m_frame))
+ swallowEvent = true;
+ } else if (!node || !node->focused()) {
+ if (!page->focusController()->setFocusedNode(0, m_frame))
+ swallowEvent = true;
+ }
+ }
+ }
+
+ return swallowEvent;
+}
+
+#if !PLATFORM(GTK) && !(PLATFORM(CHROMIUM) && (OS(LINUX) || OS(FREEBSD)))
+bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&) const
+{
+ return false;
+}
+#endif
+
+bool EventHandler::handleWheelEvent(PlatformWheelEvent& e)
+{
+ Document* doc = m_frame->document();
+
+ RenderObject* docRenderer = doc->renderer();
+ if (!docRenderer)
+ return false;
+
+ RefPtr<FrameView> protector(m_frame->view());
+
+ FrameView* view = m_frame->view();
+ if (!view)
+ return false;
+ setFrameWasScrolledByUser();
+ IntPoint vPoint = view->windowToContents(e.pos());
+
+ Node* node;
+ bool isOverWidget;
+
+ HitTestRequest request(HitTestRequest::ReadOnly);
+ HitTestResult result(vPoint);
+ doc->renderView()->layer()->hitTest(request, result);
+
+ if (m_useLatchedWheelEventNode) {
+ if (!m_latchedWheelEventNode) {
+ m_latchedWheelEventNode = result.innerNode();
+ m_widgetIsLatched = result.isOverWidget();
+ }
+
+ node = m_latchedWheelEventNode.get();
+ isOverWidget = m_widgetIsLatched;
+ } else {
+ if (m_latchedWheelEventNode)
+ m_latchedWheelEventNode = 0;
+ if (m_previousWheelScrolledNode)
+ m_previousWheelScrolledNode = 0;
+
+ node = result.innerNode();
+ isOverWidget = result.isOverWidget();
+ }
+
+ if (shouldTurnVerticalTicksIntoHorizontal(result))
+ e.turnVerticalTicksIntoHorizontal();
+
+ if (node) {
+ // Figure out which view to send the event to.
+ RenderObject* target = node->renderer();
+
+ if (isOverWidget && target && target->isWidget()) {
+ Widget* widget = toRenderWidget(target)->widget();
+ if (widget && passWheelEventToWidget(e, widget)) {
+ e.accept();
+ return true;
+ }
+ }
+
+ node = node->shadowAncestorNode();
+ node->dispatchWheelEvent(e);
+ if (e.isAccepted())
+ return true;
+ }
+
+ if (e.isAccepted())
+ return true;
+
+ view = m_frame->view();
+ if (!view)
+ return false;
+
+ view->wheelEvent(e);
+ return e.isAccepted();
+}
+
+void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
+{
+ if (!startNode || !wheelEvent)
+ return;
+
+ Node* stopNode = m_previousWheelScrolledNode.get();
+
+ // Break up into two scrolls if we need to. Diagonal movement on
+ // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
+ if (scrollNode(wheelEvent->rawDeltaX(), wheelEvent->granularity(), ScrollLeft, ScrollRight, startNode, &stopNode))
+ wheelEvent->setDefaultHandled();
+
+ if (scrollNode(wheelEvent->rawDeltaY(), wheelEvent->granularity(), ScrollUp, ScrollDown, startNode, &stopNode))
+ wheelEvent->setDefaultHandled();
+
+ if (!m_useLatchedWheelEventNode)
+ m_previousWheelScrolledNode = stopNode;
+}
+
+#if ENABLE(CONTEXT_MENUS)
+bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
+{
+ Document* doc = m_frame->document();
+ FrameView* v = m_frame->view();
+ if (!v)
+ return false;
+
+ bool swallowEvent;
+ IntPoint viewportPos = v->windowToContents(event.pos());
+ HitTestRequest request(HitTestRequest::Active);
+ MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
+
+ 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.
+ && (m_frame->selection()->isContentEditable() || (mev.targetNode() && mev.targetNode()->isTextNode()))) {
+ m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
+ selectClosestWordOrLinkFromMouseEvent(mev);
+ }
+
+ swallowEvent = dispatchMouseEvent(eventNames().contextmenuEvent, mev.targetNode(), true, 0, event, false);
+
+ return swallowEvent;
+}
+
+bool EventHandler::sendContextMenuEventForKey()
+{
+ FrameView* view = m_frame->view();
+ if (!view)
+ return false;
+
+ Document* doc = m_frame->document();
+ if (!doc)
+ return false;
+
+ static const int kContextMenuMargin = 1;
+
+#if OS(WINDOWS) && !OS(WINCE)
+ int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
+#else
+ int rightAligned = 0;
+#endif
+ IntPoint location;
+
+ Node* focusedNode = doc->focusedNode();
+ SelectionController* selectionController = m_frame->selection();
+ Position start = selectionController->selection().start();
+
+ if (start.node() && (selectionController->rootEditableElement() || selectionController->isRange())) {
+ RefPtr<Range> selection = selectionController->toNormalizedRange();
+ IntRect firstRect = m_frame->editor()->firstRectForRange(selection.get());
+
+ int x = rightAligned ? firstRect.right() : firstRect.x();
+ location = IntPoint(x, firstRect.bottom());
+ } else if (focusedNode) {
+ RenderBoxModelObject* box = focusedNode->renderBoxModelObject();
+ IntRect clippedRect = box->absoluteClippedOverflowRect();
+ location = clippedRect.bottomLeft();
+ } else {
+ location = IntPoint(
+ rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
+ kContextMenuMargin);
+ }
+
+ m_frame->view()->setCursor(pointerCursor());
+
+ IntPoint position = view->contentsToWindow(location);
+ IntPoint globalPosition = view->contentsToScreen(IntRect(location, IntSize())).location();
+
+ Node* targetNode = doc->focusedNode();
+ if (!targetNode)
+ targetNode = doc;
+
+ // Use the focused node as the target for hover and active.
+ HitTestResult result(position);
+ result.setInnerNode(targetNode);
+ HitTestRequest request(HitTestRequest::Active);
+ doc->renderView()->layer()->updateHoverActiveState(request, result);
+ doc->updateStyleIfNeeded();
+
+ // The contextmenu event is a mouse event even when invoked using the keyboard.
+ // This is required for web compatibility.
+
+#if OS(WINDOWS)
+ MouseEventType eventType = MouseEventReleased;
+#else
+ MouseEventType eventType = MouseEventPressed;
+#endif
+
+ PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
+
+ return dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, mouseEvent, false);
+}
+
+#endif // ENABLE(CONTEXT_MENUS)
+
+void EventHandler::scheduleHoverStateUpdate()
+{
+ if (!m_hoverTimer.isActive())
+ m_hoverTimer.startOneShot(0);
+}
+
+void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
+{
+ FrameView* view = m_frame->view();
+ if (!view)
+ return;
+
+ if (m_mousePressed || !quad.containsPoint(view->windowToContents(m_currentMousePosition)))
+ return;
+
+ if (!m_fakeMouseMoveEventTimer.isActive())
+ m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveInterval);
+}
+
+void EventHandler::cancelFakeMouseMoveEvent()
+{
+ m_fakeMouseMoveEventTimer.stop();
+}
+
+void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
+{
+ ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
+ ASSERT(!m_mousePressed);
+
+ FrameView* view = m_frame->view();
+ if (!view)
+ return;
+
+ bool shiftKey;
+ bool ctrlKey;
+ bool altKey;
+ bool metaKey;
+ PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
+ IntPoint globalPoint = view->contentsToScreen(IntRect(view->windowToContents(m_currentMousePosition), IntSize())).location();
+ PlatformMouseEvent fakeMouseMoveEvent(m_currentMousePosition, globalPoint, NoButton, MouseEventMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
+ mouseMoved(fakeMouseMoveEvent);
+}
+
+// Whether or not a mouse down can begin the creation of a selection. Fires the selectStart event.
+bool EventHandler::canMouseDownStartSelect(Node* node)
+{
+ if (!node || !node->renderer())
+ return true;
+
+ // Some controls and images can't start a select on a mouse down.
+ if (!node->canStartSelection())
+ return false;
+
+ return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
+}
+
+#if ENABLE(DRAG_SUPPORT)
+bool EventHandler::canMouseDragExtendSelect(Node* node)
+{
+ if (!node || !node->renderer())
+ return true;
+
+ return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
+}
+#endif // ENABLE(DRAG_SUPPORT)
+
+void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
+{
+ m_frameSetBeingResized = frameSet;
+}
+
+void EventHandler::resizeLayerDestroyed()
+{
+ ASSERT(m_resizeLayer);
+ m_resizeLayer = 0;
+}
+
+void EventHandler::hoverTimerFired(Timer<EventHandler>*)
+{
+ m_hoverTimer.stop();
+
+ ASSERT(m_frame);
+ ASSERT(m_frame->document());
+
+ if (RenderView* renderer = m_frame->contentRenderer()) {
+ if (FrameView* view = m_frame->view()) {
+ HitTestRequest request(HitTestRequest::MouseMove);
+ HitTestResult result(view->windowToContents(m_currentMousePosition));
+ renderer->layer()->hitTest(request, result);
+ m_frame->document()->updateStyleIfNeeded();
+ }
+ }
+}
+
+static Node* eventTargetNodeForDocument(Document* doc)
+{
+ if (!doc)
+ return 0;
+ Node* node = doc->focusedNode();
+#if defined(ANDROID_PLUGINS)
+ if (!node && doc->frame() && doc->frame()->view())
+ node = android::WebViewCore::getWebViewCore(doc->frame()->view())
+ ->cursorNodeIsPlugin();
+#else
+ if (!node && doc->isPluginDocument()) {
+ PluginDocument* pluginDocument = static_cast<PluginDocument*>(doc);
+ node = pluginDocument->pluginNode();
+ }
+#endif
+ if (!node && doc->isHTMLDocument())
+ node = doc->body();
+ if (!node)
+ node = doc->documentElement();
+ return node;
+}
+
+bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
+{
+ // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
+ // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
+ // lower case variants are present in a document, the correct element is matched based on Shift key state.
+ // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
+ ASSERT(!(accessKeyModifiers() & PlatformKeyboardEvent::ShiftKey));
+ if ((evt.modifiers() & ~PlatformKeyboardEvent::ShiftKey) != accessKeyModifiers())
+ return false;
+ String key = evt.unmodifiedText();
+ Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
+ if (!elem)
+ return false;
+ elem->accessKeyAction(false);
+ return true;
+}
+
+#if !PLATFORM(MAC)
+bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
+{
+ return false;
+}
+#endif
+
+bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
+{
+#if ENABLE(PAN_SCROLLING)
+ if (Page* page = m_frame->page()) {
+ if (page->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) {
+ // If a key is pressed while the autoscroll/panScroll is in progress then we want to stop
+ if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown || initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown)
+ stopAutoscrollTimer();
+
+ // If we were in autoscroll/panscroll mode, we swallow the key event
+ return true;
+ }
+ }
+#endif
+
+ // Check for cases where we are too early for events -- possible unmatched key up
+ // from pressing return in the location bar.
+ RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
+ if (!node)
+ return false;
+
+ UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+ UserTypingGestureIndicator typingGestureIndicator(m_frame);
+
+ if (FrameView* view = m_frame->view())
+ view->resetDeferredRepaintDelay();
+
+ // FIXME: what is this doing here, in keyboard event handler?
+ m_frame->loader()->resetMultipleFormSubmissionProtection();
+
+ // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
+ // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
+ // with access keys. Then we dispatch keydown, but suppress its default handling.
+ // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
+ // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
+ bool matchedAnAccessKey = false;
+ if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown)
+ matchedAnAccessKey = handleAccessKey(initialKeyEvent);
+
+ // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
+ if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp || initialKeyEvent.type() == PlatformKeyboardEvent::Char)
+ return !node->dispatchKeyEvent(initialKeyEvent);
+
+ bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
+
+ ExceptionCode ec;
+ PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
+ if (keyDownEvent.type() != PlatformKeyboardEvent::RawKeyDown)
+ keyDownEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown, backwardCompatibilityMode);
+ RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
+ if (matchedAnAccessKey)
+ keydown->setDefaultPrevented(true);
+ keydown->setTarget(node);
+
+ if (initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown) {
+ node->dispatchEvent(keydown, ec);
+ // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
+ bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
+ return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
+ }
+
+ // Run input method in advance of DOM event handling. This may result in the IM
+ // modifying the page prior the keydown event, but this behaviour is necessary
+ // in order to match IE:
+ // 1. preventing default handling of keydown and keypress events has no effect on IM input;
+ // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
+ m_frame->editor()->handleInputMethodKeydown(keydown.get());
+
+ bool handledByInputMethod = keydown->defaultHandled();
+
+ if (handledByInputMethod) {
+ keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
+ keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
+ keydown->setTarget(node);
+ keydown->setDefaultHandled();
+ }
+
+ node->dispatchEvent(keydown, ec);
+ // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
+ bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
+ bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
+ if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
+ return keydownResult;
+
+ // Focus may have changed during keydown handling, so refetch node.
+ // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
+ if (!keydownResult) {
+ node = eventTargetNodeForDocument(m_frame->document());
+ if (!node)
+ return false;
+ }
+
+ PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
+ keyPressEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::Char, backwardCompatibilityMode);
+ if (keyPressEvent.text().isEmpty())
+ return keydownResult;
+ RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->defaultView());
+ keypress->setTarget(node);
+ if (keydownResult)
+ keypress->setDefaultPrevented(true);
+#if PLATFORM(MAC)
+ keypress->keypressCommands() = keydown->keypressCommands();
+#endif
+ node->dispatchEvent(keypress, ec);
+
+ return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
+}
+
+void EventHandler::handleKeyboardSelectionMovement(KeyboardEvent* event)
+{
+ if (!event)
+ return;
+
+ const String& key = event->keyIdentifier();
+ bool isShifted = event->getModifierState("Shift");
+ bool isOptioned = event->getModifierState("Alt");
+ bool isCommanded = event->getModifierState("Meta");
+
+ if (key == "Up") {
+ m_frame->selection()->modify((isShifted) ? SelectionController::AlterationExtend : SelectionController::AlterationMove, DirectionBackward, (isCommanded) ? DocumentBoundary : LineGranularity, true);
+ event->setDefaultHandled();
+ } else if (key == "Down") {
+ m_frame->selection()->modify((isShifted) ? SelectionController::AlterationExtend : SelectionController::AlterationMove, DirectionForward, (isCommanded) ? DocumentBoundary : LineGranularity, true);
+ event->setDefaultHandled();
+ } else if (key == "Left") {
+ m_frame->selection()->modify((isShifted) ? SelectionController::AlterationExtend : SelectionController::AlterationMove, DirectionLeft, (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity, true);
+ event->setDefaultHandled();
+ } else if (key == "Right") {
+ m_frame->selection()->modify((isShifted) ? SelectionController::AlterationExtend : SelectionController::AlterationMove, DirectionRight, (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity, true);
+ event->setDefaultHandled();
+ }
+}
+
+void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
+{
+ if (event->type() == eventNames().keydownEvent) {
+ m_frame->editor()->handleKeyboardEvent(event);
+ if (event->defaultHandled())
+ return;
+ if (event->keyIdentifier() == "U+0009")
+ defaultTabEventHandler(event);
+ else {
+ FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
+ if (direction != FocusDirectionNone)
+ defaultArrowEventHandler(direction, event);
+ }
+
+ // provides KB navigation and selection for enhanced accessibility users
+ if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
+ handleKeyboardSelectionMovement(event);
+ }
+ if (event->type() == eventNames().keypressEvent) {
+ m_frame->editor()->handleKeyboardEvent(event);
+ if (event->defaultHandled())
+ return;
+ if (event->charCode() == ' ')
+ defaultSpaceEventHandler(event);
+ }
+}
+
+FocusDirection EventHandler::focusDirectionForKey(const AtomicString& keyIdentifier) const
+{
+ DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down"));
+ DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up"));
+ DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left"));
+ DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right"));
+
+ FocusDirection retVal = FocusDirectionNone;
+
+ if (keyIdentifier == Down)
+ retVal = FocusDirectionDown;
+ else if (keyIdentifier == Up)
+ retVal = FocusDirectionUp;
+ else if (keyIdentifier == Left)
+ retVal = FocusDirectionLeft;
+ else if (keyIdentifier == Right)
+ retVal = FocusDirectionRight;
+
+ return retVal;
+}
+
+#if ENABLE(DRAG_SUPPORT)
+bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const
+{
+ IntPoint dragViewportLocation((int)floatDragViewportLocation.x(), (int)floatDragViewportLocation.y());
+ return dragHysteresisExceeded(dragViewportLocation);
+}
+
+bool EventHandler::dragHysteresisExceeded(const IntPoint& dragViewportLocation) const
+{
+ FrameView* view = m_frame->view();
+ if (!view)
+ return false;
+ IntPoint dragLocation = view->windowToContents(dragViewportLocation);
+ IntSize delta = dragLocation - m_mouseDownPos;
+
+ int threshold = GeneralDragHysteresis;
+ if (dragState().m_dragSrcIsImage)
+ threshold = ImageDragHysteresis;
+ else if (dragState().m_dragSrcIsLink)
+ threshold = LinkDragHysteresis;
+ else if (dragState().m_dragSrcInSelection)
+ threshold = TextDragHysteresis;
+
+ return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
+}
+
+void EventHandler::freeClipboard()
+{
+ if (dragState().m_dragClipboard)
+ dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
+}
+
+bool EventHandler::shouldDragAutoNode(Node* node, const IntPoint& point) const
+{
+ if (!node || !m_frame->view())
+ return false;
+ Page* page = m_frame->page();
+ return page && page->dragController()->mayStartDragAtEventLocation(m_frame, point, node);
+}
+
+void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
+{
+ if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
+ dragState().m_dragClipboard->setDestinationOperation(operation);
+ // for now we don't care if event handler cancels default behavior, since there is none
+ dispatchDragSrcEvent(eventNames().dragendEvent, event);
+ }
+ freeClipboard();
+ dragState().m_dragSrc = 0;
+ // In case the drag was ended due to an escape key press we need to ensure
+ // that consecutive mousemove events don't reinitiate the drag and drop.
+ m_mouseDownMayStartDrag = false;
+}
+
+// returns if we should continue "default processing", i.e., whether eventhandler canceled
+bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
+{
+ return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
+}
+
+bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event)
+{
+ if (event.event().button() != LeftButton || event.event().eventType() != MouseEventMoved) {
+ // If we allowed the other side of the bridge to handle a drag
+ // last time, then m_mousePressed might still be set. So we
+ // clear it now to make sure the next move after a drag
+ // doesn't look like a drag.
+ m_mousePressed = false;
+ return false;
+ }
+
+ if (eventLoopHandleMouseDragged(event))
+ return true;
+
+ // Careful that the drag starting logic stays in sync with eventMayStartDrag()
+
+ if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
+ allowDHTMLDrag(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA);
+ if (!dragState().m_dragSrcMayBeDHTML && !dragState().m_dragSrcMayBeUA)
+ m_mouseDownMayStartDrag = false; // no element is draggable
+ }
+
+ if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
+ // try to find an element that wants to be dragged
+ HitTestRequest request(HitTestRequest::ReadOnly);
+ HitTestResult result(m_mouseDownPos);
+ m_frame->contentRenderer()->layer()->hitTest(request, result);
+ Node* node = result.innerNode();
+ if (node && node->renderer())
+ dragState().m_dragSrc = node->renderer()->draggableNode(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA,
+ m_mouseDownPos.x(), m_mouseDownPos.y(), dragState().m_dragSrcIsDHTML);
+ else
+ dragState().m_dragSrc = 0;
+
+ if (!dragState().m_dragSrc)
+ m_mouseDownMayStartDrag = false; // no element is draggable
+ else {
+ // remember some facts about this source, while we have a HitTestResult handy
+ node = result.URLElement();
+ dragState().m_dragSrcIsLink = node && node->isLink();
+
+ node = result.innerNonSharedNode();
+ dragState().m_dragSrcIsImage = node && node->renderer() && node->renderer()->isImage();
+
+ dragState().m_dragSrcInSelection = m_frame->selection()->contains(m_mouseDownPos);
+ }
+ }
+
+ // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
+ // or else we bail on the dragging stuff and allow selection to occur
+ if (m_mouseDownMayStartDrag && !dragState().m_dragSrcIsImage && dragState().m_dragSrcInSelection && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
+ m_mouseDownMayStartDrag = false;
+ dragState().m_dragSrc = 0;
+ // ...but if this was the first click in the window, we don't even want to start selection
+ if (eventActivatedView(event.event()))
+ m_mouseDownMayStartSelect = false;
+ }
+
+ if (!m_mouseDownMayStartDrag)
+ return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
+
+ // We are starting a text/image/url drag, so the cursor should be an arrow
+ if (FrameView* view = m_frame->view()) {
+ // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
+ view->setCursor(pointerCursor());
+ }
+
+ if (!dragHysteresisExceeded(event.event().pos()))
+ return true;
+
+ // Once we're past the hysteresis point, we don't want to treat this gesture as a click
+ invalidateClick();
+
+ DragOperation srcOp = DragOperationNone;
+
+ freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just
+ // to make sure it gets numbified
+ dragState().m_dragClipboard = createDraggingClipboard();
+
+ if (dragState().m_dragSrcMayBeDHTML) {
+ // Check to see if the is a DOM based drag, if it is get the DOM specified drag
+ // image and offset
+ if (dragState().m_dragSrcIsDHTML) {
+ if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
+ // FIXME: This doesn't work correctly with transforms.
+ FloatPoint absPos = renderer->localToAbsolute();
+ IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
+ dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), toPoint(delta));
+ } else {
+ // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
+ // the element in some way. In this case we just kill the drag.
+ m_mouseDownMayStartDrag = false;
+ goto cleanupDrag;
+ }
+ }
+
+ m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
+ && !m_frame->selection()->isInPasswordField();
+
+ // Invalidate clipboard here against anymore pasteboard writing for security. The drag
+ // image can still be changed as we drag, but not the pasteboard data.
+ dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable);
+
+ if (m_mouseDownMayStartDrag) {
+ // gather values from DHTML element, if it set any
+ srcOp = dragState().m_dragClipboard->sourceOperation();
+
+ // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the
+ // drag with dragImage! Because of that dumb reentrancy, we may think we've not
+ // started the drag when that happens. So we have to assume it's started before we
+ // kick it off.
+ dragState().m_dragClipboard->setDragHasStarted();
+ }
+ }
+
+ if (m_mouseDownMayStartDrag) {
+ Page* page = m_frame->page();
+ DragController* dragController = page ? page->dragController() : 0;
+ bool startedDrag = dragController && dragController->startDrag(m_frame, dragState().m_dragClipboard.get(), srcOp, event.event(), m_mouseDownPos, dragState().m_dragSrcIsDHTML);
+ if (!startedDrag && dragState().m_dragSrcMayBeDHTML) {
+ // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
+ dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
+ m_mouseDownMayStartDrag = false;
+ }
+ }
+
+cleanupDrag:
+ if (!m_mouseDownMayStartDrag) {
+ // something failed to start the drag, cleanup
+ freeClipboard();
+ dragState().m_dragSrc = 0;
+ }
+
+ // No more default handling (like selection), whether we're past the hysteresis bounds or not
+ return true;
+}
+#endif // ENABLE(DRAG_SUPPORT)
+
+bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, bool isLineBreak, bool isBackTab)
+{
+ // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
+ // and avoid dispatching text input events from keydown default handlers.
+ ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent);
+ ASSERT(!(isLineBreak && isBackTab));
+
+ if (!m_frame)
+ return false;
+
+ EventTarget* target;
+ if (underlyingEvent)
+ target = underlyingEvent->target();
+ else
+ target = eventTargetNodeForDocument(m_frame->document());
+ if (!target)
+ return false;
+
+ if (FrameView* view = m_frame->view())
+ view->resetDeferredRepaintDelay();
+
+ RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text, TextEvent::selectInputType(isLineBreak, isBackTab));
+ event->setUnderlyingEvent(underlyingEvent);
+
+ ExceptionCode ec;
+ target->dispatchEvent(event, ec);
+ return event->defaultHandled();
+}
+
+#if !PLATFORM(MAC) && !PLATFORM(QT) && !PLATFORM(HAIKU) && !PLATFORM(EFL)
+bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent*) const
+{
+ return false;
+}
+#endif
+
+bool EventHandler::tabsToLinks(KeyboardEvent* event) const
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return false;
+
+ if (page->chrome()->client()->tabsToLinks())
+ return !invertSenseOfTabsToLinks(event);
+
+ return invertSenseOfTabsToLinks(event);
+}
+
+void EventHandler::defaultTextInputEventHandler(TextEvent* event)
+{
+ if (m_frame->editor()->handleTextEvent(event))
+ event->setDefaultHandled();
+}
+
+#if PLATFORM(QT) || PLATFORM(MAC) || PLATFORM(ANDROID)
+
+// These two platforms handle the space event in the platform-specific WebKit code.
+// Eventually it would be good to eliminate that and use the code here instead, but
+// the Qt version is inside an ifdef and the Mac version has some extra behavior
+// so we can't unify everything yet.
+void EventHandler::defaultSpaceEventHandler(KeyboardEvent*)
+{
+}
+
+#else
+
+void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
+{
+ ScrollLogicalDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
+ if (logicalScrollOverflow(direction, ScrollByPage)) {
+ event->setDefaultHandled();
+ return;
+ }
+
+ FrameView* view = m_frame->view();
+ if (!view)
+ return;
+
+ if (view->logicalScroll(direction, ScrollByPage))
+ event->setDefaultHandled();
+}
+
+#endif
+
+void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event)
+{
+ if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ if (!isSpatialNavigationEnabled(m_frame))
+ return;
+
+ // Arrows and other possible directional navigation keys can be used in design
+ // mode editing.
+ if (m_frame->document()->inDesignMode())
+ return;
+
+ if (page->focusController()->advanceFocus(focusDirection, event))
+ event->setDefaultHandled();
+}
+
+void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
+{
+ // We should only advance focus on tabs if no special modifier keys are held down.
+ if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+ if (!page->tabKeyCyclesThroughElements())
+ return;
+
+ FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
+
+ // Tabs can be used in design mode editing.
+ if (m_frame->document()->inDesignMode())
+ return;
+
+ if (page->focusController()->advanceFocus(focusDirection, event))
+ event->setDefaultHandled();
+}
+
+void EventHandler::capsLockStateMayHaveChanged()
+{
+ Document* d = m_frame->document();
+ if (Node* node = d->focusedNode()) {
+ if (RenderObject* r = node->renderer()) {
+ if (r->isTextField())
+ toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
+ }
+ }
+}
+
+void EventHandler::sendResizeEvent()
+{
+ m_frame->document()->dispatchWindowEvent(Event::create(eventNames().resizeEvent, false, false));
+}
+
+void EventHandler::sendScrollEvent()
+{
+ setFrameWasScrolledByUser();
+ if (m_frame->view() && m_frame->document())
+ m_frame->document()->dispatchEvent(Event::create(eventNames().scrollEvent, true, false));
+}
+
+void EventHandler::setFrameWasScrolledByUser()
+{
+ FrameView* v = m_frame->view();
+ if (v)
+ v->setWasScrolledByUser(true);
+}
+
+bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
+{
+ if (!scrollbar || !scrollbar->enabled())
+ return false;
+ setFrameWasScrolledByUser();
+ return scrollbar->mouseDown(mev.event());
+}
+
+// If scrollbar (under mouse) is different from last, send a mouse exited. Set
+// last to scrollbar if setLast is true; else set last to 0.
+void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
+{
+ if (m_lastScrollbarUnderMouse != scrollbar) {
+ // Send mouse exited to the old scrollbar.
+ if (m_lastScrollbarUnderMouse)
+ m_lastScrollbarUnderMouse->mouseExited();
+ m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
+ }
+}
+
+#if ENABLE(TOUCH_EVENTS)
+
+static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
+{
+ switch (state) {
+ case PlatformTouchPoint::TouchReleased:
+ return eventNames().touchendEvent;
+ case PlatformTouchPoint::TouchCancelled:
+ return eventNames().touchcancelEvent;
+ case PlatformTouchPoint::TouchPressed:
+ return eventNames().touchstartEvent;
+ case PlatformTouchPoint::TouchMoved:
+ return eventNames().touchmoveEvent;
+ default:
+ ASSERT_NOT_REACHED();
+ return emptyAtom;
+ }
+}
+
+bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
+{
+ // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes
+ // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
+ // for an overview of how these lists fit together.
+
+ // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event.
+ RefPtr<TouchList> touches = TouchList::create();
+
+ // A different view on the 'touches' list above, filtered and grouped by event target. Used for the
+ // 'targetTouches' list in the JS event.
+ typedef HashMap<EventTarget*, RefPtr<TouchList> > TargetTouchesMap;
+ TargetTouchesMap touchesByTarget;
+
+ // Array of touches per state, used to assemble the 'changedTouches' list in the JS event.
+ typedef HashSet<RefPtr<EventTarget> > EventTargetSet;
+ struct {
+ // The touches corresponding to the particular change state this struct instance represents.
+ RefPtr<TouchList> m_touches;
+ // Set of targets involved in m_touches.
+ EventTargetSet m_targets;
+ } changedTouches[PlatformTouchPoint::TouchStateEnd];
+
+ const Vector<PlatformTouchPoint>& points = event.touchPoints();
+
+ UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+
+ for (unsigned i = 0; i < points.size(); ++i) {
+ const PlatformTouchPoint& point = points[i];
+ PlatformTouchPoint::State pointState = point.state();
+ IntPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
+
+ HitTestRequest::HitTestRequestType hitType = HitTestRequest::Active | HitTestRequest::ReadOnly;
+ // The HitTestRequest types used for mouse events map quite adequately
+ // to touch events. Note that in addition to meaning that the hit test
+ // should affect the active state of the current node if necessary,
+ // HitTestRequest::Active signifies that the hit test is taking place
+ // with the mouse (or finger in this case) being pressed.
+ switch (pointState) {
+ case PlatformTouchPoint::TouchPressed:
+ hitType = HitTestRequest::Active;
+ break;
+ case PlatformTouchPoint::TouchMoved:
+ hitType = HitTestRequest::Active | HitTestRequest::MouseMove | HitTestRequest::ReadOnly;
+ break;
+ case PlatformTouchPoint::TouchReleased:
+ case PlatformTouchPoint::TouchCancelled:
+ hitType = HitTestRequest::MouseUp;
+ break;
+ default:
+ break;
+ }
+
+ HitTestResult result = hitTestResultAtPoint(pagePoint, /*allowShadowContent*/ false, false, DontHitTestScrollbars, hitType);
+ Node* node = result.innerNode();
+ ASSERT(node);
+
+ // Touch events should not go to text nodes
+ if (node->isTextNode())
+ node = node->parentNode();
+
+ Document* doc = node->document();
+ if (!doc)
+ continue;
+ if (!doc->hasListenerType(Document::TOUCH_LISTENER))
+ continue;
+
+ if (m_frame != doc->frame()) {
+ // pagePoint should always be relative to the target elements containing frame.
+ pagePoint = documentPointForWindowPoint(doc->frame(), point.pos());
+ }
+
+ int adjustedPageX = lroundf(pagePoint.x() / m_frame->pageZoomFactor());
+ int adjustedPageY = lroundf(pagePoint.y() / m_frame->pageZoomFactor());
+
+ // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
+ unsigned touchPointTargetKey = point.id() + 1;
+ RefPtr<EventTarget> touchTarget;
+ if (pointState == PlatformTouchPoint::TouchPressed) {
+ m_originatingTouchPointTargets.set(touchPointTargetKey, node);
+ touchTarget = node;
+ } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
+ // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel
+ // we also remove it from the map.
+ touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey);
+ } else
+ touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey);
+
+ if (!touchTarget.get())
+ continue;
+
+ RefPtr<Touch> touch = Touch::create(doc->frame(), touchTarget.get(), point.id(),
+ point.screenPos().x(), point.screenPos().y(),
+ adjustedPageX, adjustedPageY);
+
+ // Ensure this target's touch list exists, even if it ends up empty, so it can always be passed to TouchEvent::Create below.
+ TargetTouchesMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
+ if (targetTouchesIterator == touchesByTarget.end())
+ targetTouchesIterator = touchesByTarget.set(touchTarget.get(), TouchList::create()).first;
+
+ // touches and targetTouches should only contain information about touches still on the screen, so if this point is
+ // released or cancelled it will only appear in the changedTouches list.
+ if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
+ touches->append(touch);
+ targetTouchesIterator->second->append(touch);
+ }
+
+ // Now build up the correct list for changedTouches.
+ // Note that any touches that are in the TouchStationary state (e.g. if
+ // the user had several points touched but did not move them all) should
+ // never be in the changedTouches list so we do not handle them explicitly here.
+ // See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion
+ // about the TouchStationary state.
+ if (pointState != PlatformTouchPoint::TouchStationary) {
+ ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
+ if (!changedTouches[pointState].m_touches)
+ changedTouches[pointState].m_touches = TouchList::create();
+ changedTouches[pointState].m_touches->append(touch);
+ changedTouches[pointState].m_targets.add(touchTarget);
+ }
+ }
+ m_touchPressed = touches->length() > 0;
+
+ // Now iterate the changedTouches list and m_targets within it, sending events to the tagets as required.
+ bool defaultPrevented = false;
+<<<<<<< HEAD:WebCore/page/EventHandler.cpp
+ Touch* changedTouch = 0;
+ EventTarget* touchEventTarget = 0;
+
+ if (cancelTouches->length() > 0) {
+ // We dispatch the event to the target of the touch that caused this touch event to be generated, i.e.
+ // we take it from the list that will be used as the changedTouches property of the event.
+ // The choice to use the touch at index 0 guarantees that there is a target (as we checked the length
+ // above). In the case that there are multiple touches in what becomes the changedTouches list, it is
+ // difficult to say how we should prioritise touches and as such, item 0 is an arbitrary choice.
+ changedTouch = cancelTouches->item(0);
+ ASSERT(changedTouch);
+ touchEventTarget = changedTouch->target();
+ ASSERT(touchEventTarget);
+
+ eventName = &eventNames().touchcancelEvent;
+ RefPtr<TouchEvent> cancelEv =
+ TouchEvent::create(TouchList::create().get(), TouchList::create().get(), cancelTouches.get(),
+ *eventName, touchEventTarget->toNode()->document()->defaultView(),
+ 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(),
+ event.metaKey());
+ ExceptionCode ec = 0;
+ touchEventTarget->dispatchEvent(cancelEv.get(), ec);
+ defaultPrevented |= cancelEv->defaultPrevented();
+ }
+
+ if (releasedTouches->length() > 0) {
+ Touch* changedTouch = releasedTouches->item(0);
+ ASSERT(changedTouch);
+ touchEventTarget = changedTouch->target();
+ ASSERT(touchEventTarget);
+
+ RefPtr<TouchList> targetTouches = assembleTargetTouches(changedTouch, touches.get());
+
+ eventName = &eventNames().touchendEvent;
+ RefPtr<TouchEvent> endEv =
+ TouchEvent::create(touches.get(), targetTouches.get(), releasedTouches.get(),
+ *eventName, touchEventTarget->toNode()->document()->defaultView(),
+ 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(),
+ event.metaKey());
+ ExceptionCode ec = 0;
+ touchEventTarget->dispatchEvent(endEv.get(), ec);
+ defaultPrevented |= endEv->defaultPrevented();
+ }
+ if (pressedTouches->length() > 0) {
+ Touch* changedTouch = pressedTouches->item(0);
+ ASSERT(changedTouch);
+ touchEventTarget = changedTouch->target();
+ ASSERT(touchEventTarget);
+
+ RefPtr<TouchList> targetTouches = assembleTargetTouches(changedTouch, touches.get());
+
+#if PLATFORM(ANDROID)
+ if (event.type() == TouchLongPress) {
+ eventName = &eventNames().touchlongpressEvent;
+ RefPtr<TouchEvent> longpressEv =
+ TouchEvent::create(touches.get(), targetTouches.get(), pressedTouches.get(),
+ *eventName, touchEventTarget->toNode()->document()->defaultView(),
+ 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(),
+ event.metaKey());
+ ExceptionCode ec = 0;
+ touchEventTarget->dispatchEvent(longpressEv.get(), ec);
+ defaultPrevented |= longpressEv->defaultPrevented();
+ } else if (event.type() == TouchDoubleTap) {
+ eventName = &eventNames().touchdoubletapEvent;
+ RefPtr<TouchEvent> doubleTapEv =
+ TouchEvent::create(touches.get(), targetTouches.get(), pressedTouches.get(),
+ *eventName, touchEventTarget->toNode()->document()->defaultView(),
+ 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(),
+ event.metaKey());
+ ExceptionCode ec = 0;
+ touchEventTarget->dispatchEvent(doubleTapEv.get(), ec);
+ defaultPrevented |= doubleTapEv->defaultPrevented();
+ } else {
+#endif
+ eventName = &eventNames().touchstartEvent;
+ RefPtr<TouchEvent> startEv =
+ TouchEvent::create(touches.get(), targetTouches.get(), pressedTouches.get(),
+ *eventName, touchEventTarget->toNode()->document()->defaultView(),
+ 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(),
+ event.metaKey());
+ ExceptionCode ec = 0;
+ touchEventTarget->dispatchEvent(startEv.get(), ec);
+ defaultPrevented |= startEv->defaultPrevented();
+#if PLATFORM(ANDROID)
+ }
+#endif
+ }
+
+ if (movedTouches->length() > 0) {
+ Touch* changedTouch = movedTouches->item(0);
+ ASSERT(changedTouch);
+ touchEventTarget = changedTouch->target();
+ ASSERT(touchEventTarget);
+
+ RefPtr<TouchList> targetTouches = assembleTargetTouches(changedTouch, touches.get());
+
+ eventName = &eventNames().touchmoveEvent;
+ RefPtr<TouchEvent> moveEv =
+ TouchEvent::create(touches.get(), targetTouches.get(), movedTouches.get(),
+ *eventName, touchEventTarget->toNode()->document()->defaultView(),
+ 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(),
+ event.metaKey());
+ ExceptionCode ec = 0;
+ touchEventTarget->dispatchEvent(moveEv.get(), ec);
+ defaultPrevented |= moveEv->defaultPrevented();
+=======
+ RefPtr<TouchList> emptyList = TouchList::create();
+ for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
+ if (!changedTouches[state].m_touches)
+ continue;
+
+ // When sending a touch cancel event, use empty touches and targetTouches lists.
+ bool isTouchCancelEvent = (state == PlatformTouchPoint::TouchCancelled);
+ RefPtr<TouchList>& effectiveTouches(isTouchCancelEvent ? emptyList : touches);
+ const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
+ const EventTargetSet& targetsForState = changedTouches[state].m_targets;
+
+ for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) {
+ EventTarget* touchEventTarget = it->get();
+ RefPtr<TouchList> targetTouches(isTouchCancelEvent ? emptyList : touchesByTarget.get(touchEventTarget));
+ ASSERT(targetTouches);
+
+ RefPtr<TouchEvent> touchEvent =
+ TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(),
+ stateName, touchEventTarget->toNode()->document()->defaultView(),
+ 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey());
+ ExceptionCode ec = 0;
+ touchEventTarget->dispatchEvent(touchEvent.get(), ec);
+ defaultPrevented |= touchEvent->defaultPrevented();
+ }
+>>>>>>> webkit.org at r75315:Source/WebCore/page/EventHandler.cpp
+ }
+
+ return defaultPrevented;
+}
+#endif
+
+}
diff --git a/Source/WebCore/page/EventHandler.h b/Source/WebCore/page/EventHandler.h
new file mode 100644
index 0000000..65695c2
--- /dev/null
+++ b/Source/WebCore/page/EventHandler.h
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2006, 2007, 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef EventHandler_h
+#define EventHandler_h
+
+#include "DragActions.h"
+#include "FocusDirection.h"
+#include "HitTestRequest.h"
+#include "PlatformMouseEvent.h"
+#include "ScrollTypes.h"
+#include "Timer.h"
+#include <wtf/Forward.h>
+#include <wtf/RefPtr.h>
+
+#if PLATFORM(MAC) && !defined(__OBJC__)
+class NSView;
+#endif
+
+#if ENABLE(TOUCH_EVENTS)
+#include <wtf/HashMap.h>
+#endif
+
+namespace WebCore {
+
+class Clipboard;
+class Cursor;
+class Event;
+class EventTarget;
+class FloatPoint;
+class FloatQuad;
+class Frame;
+class HitTestRequest;
+class HitTestResult;
+class HTMLFrameSetElement;
+class KeyboardEvent;
+class MouseEventWithHitTestResults;
+class Node;
+class PlatformKeyboardEvent;
+class PlatformTouchEvent;
+class PlatformWheelEvent;
+class RenderLayer;
+class RenderObject;
+class RenderWidget;
+class Scrollbar;
+class SVGElementInstance;
+class TextEvent;
+class TouchEvent;
+class WheelEvent;
+class Widget;
+
+#if ENABLE(DRAG_SUPPORT)
+extern const int LinkDragHysteresis;
+extern const int ImageDragHysteresis;
+extern const int TextDragHysteresis;
+extern const int GeneralDragHysteresis;
+#endif // ENABLE(DRAG_SUPPORT)
+
+enum HitTestScrollbars { ShouldHitTestScrollbars, DontHitTestScrollbars };
+
+class EventHandler : public Noncopyable {
+public:
+ EventHandler(Frame*);
+ ~EventHandler();
+
+ void clear();
+
+#if ENABLE(DRAG_SUPPORT)
+ void updateSelectionForMouseDrag();
+#endif
+
+ Node* mousePressNode() const;
+ void setMousePressNode(PassRefPtr<Node>);
+
+ void startPanScrolling(RenderObject*);
+ bool panScrollInProgress() { return m_panScrollInProgress; }
+ void setPanScrollInProgress(bool inProgress) { m_panScrollInProgress = inProgress; }
+
+ void stopAutoscrollTimer(bool rendererIsBeingDestroyed = false);
+ RenderObject* autoscrollRenderer() const;
+ void updateAutoscrollRenderer();
+
+ void dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad&);
+
+ HitTestResult hitTestResultAtPoint(const IntPoint&, bool allowShadowContent, bool ignoreClipping = false,
+ HitTestScrollbars scrollbars = DontHitTestScrollbars,
+ HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active,
+ const IntSize& padding = IntSize());
+
+ bool mousePressed() const { return m_mousePressed; }
+ void setMousePressed(bool pressed) { m_mousePressed = pressed; }
+
+ void setCapturingMouseEventsNode(PassRefPtr<Node>); // A caller is responsible for resetting capturing node to 0.
+
+#if ENABLE(DRAG_SUPPORT)
+ bool updateDragAndDrop(const PlatformMouseEvent&, Clipboard*);
+ void cancelDragAndDrop(const PlatformMouseEvent&, Clipboard*);
+ bool performDragAndDrop(const PlatformMouseEvent&, Clipboard*);
+#endif
+
+ void scheduleHoverStateUpdate();
+
+ void setResizingFrameSet(HTMLFrameSetElement*);
+
+ void resizeLayerDestroyed();
+
+ IntPoint currentMousePosition() const;
+
+ void setIgnoreWheelEvents(bool);
+
+ static Frame* subframeForTargetNode(Node*);
+
+ bool scrollOverflow(ScrollDirection, ScrollGranularity, Node* startingNode = 0);
+ bool logicalScrollOverflow(ScrollLogicalDirection, ScrollGranularity, Node* startingNode = 0);
+
+ bool scrollRecursively(ScrollDirection, ScrollGranularity, Node* startingNode = 0);
+ bool logicalScrollRecursively(ScrollLogicalDirection, ScrollGranularity, Node* startingNode = 0);
+
+#if ENABLE(DRAG_SUPPORT)
+ bool shouldDragAutoNode(Node*, const IntPoint&) const; // -webkit-user-drag == auto
+#endif
+
+ bool shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&) const;
+
+ bool tabsToLinks(KeyboardEvent*) const;
+ bool tabsToAllControls(KeyboardEvent*) const;
+
+ bool mouseDownMayStartSelect() const { return m_mouseDownMayStartSelect; }
+
+ bool mouseMoved(const PlatformMouseEvent&);
+
+ void lostMouseCapture();
+
+ bool handleMousePressEvent(const PlatformMouseEvent&);
+ bool handleMouseMoveEvent(const PlatformMouseEvent&, HitTestResult* hoveredNode = 0);
+ bool handleMouseReleaseEvent(const PlatformMouseEvent&);
+ bool handleWheelEvent(PlatformWheelEvent&);
+ void defaultWheelEventHandler(Node*, WheelEvent*);
+
+#if ENABLE(CONTEXT_MENUS)
+ bool sendContextMenuEvent(const PlatformMouseEvent&);
+ bool sendContextMenuEventForKey();
+#endif
+
+ void setMouseDownMayStartAutoscroll() { m_mouseDownMayStartAutoscroll = true; }
+
+ bool needsKeyboardEventDisambiguationQuirks() const;
+
+ static unsigned accessKeyModifiers();
+ bool handleAccessKey(const PlatformKeyboardEvent&);
+ bool keyEvent(const PlatformKeyboardEvent&);
+ void defaultKeyboardEventHandler(KeyboardEvent*);
+
+ bool handleTextInputEvent(const String& text, Event* underlyingEvent = 0,
+ bool isLineBreak = false, bool isBackTab = false);
+ void defaultTextInputEventHandler(TextEvent*);
+
+#if ENABLE(DRAG_SUPPORT)
+ bool eventMayStartDrag(const PlatformMouseEvent&) const;
+
+ void dragSourceEndedAt(const PlatformMouseEvent&, DragOperation);
+#endif
+
+ void focusDocumentView();
+
+ void capsLockStateMayHaveChanged();
+
+ void sendResizeEvent();
+ void sendScrollEvent();
+
+#if PLATFORM(MAC) && defined(__OBJC__)
+ PassRefPtr<KeyboardEvent> currentKeyboardEvent() const;
+
+ void mouseDown(NSEvent *);
+ void mouseDragged(NSEvent *);
+ void mouseUp(NSEvent *);
+ void mouseMoved(NSEvent *);
+ bool keyEvent(NSEvent *);
+ bool wheelEvent(NSEvent *);
+
+#if ENABLE(CONTEXT_MENUS)
+ bool sendContextMenuEvent(NSEvent *);
+#endif
+ bool eventMayStartDrag(NSEvent *);
+
+ void sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent);
+
+ void setActivationEventNumber(int num) { m_activationEventNumber = num; }
+
+ static NSEvent *currentNSEvent();
+#endif
+
+#if ENABLE(TOUCH_EVENTS)
+ bool handleTouchEvent(const PlatformTouchEvent&);
+#endif
+
+private:
+#if ENABLE(DRAG_SUPPORT)
+ enum DragAndDropHandleType {
+ UpdateDragAndDrop,
+ CancelDragAndDrop,
+ PerformDragAndDrop
+ };
+
+ struct EventHandlerDragState : Noncopyable {
+ RefPtr<Node> m_dragSrc; // element that may be a drag source, for the current mouse gesture
+ bool m_dragSrcIsLink;
+ bool m_dragSrcIsImage;
+ bool m_dragSrcInSelection;
+ bool m_dragSrcMayBeDHTML;
+ bool m_dragSrcMayBeUA; // Are DHTML and/or the UserAgent allowed to drag out?
+ bool m_dragSrcIsDHTML;
+ RefPtr<Clipboard> m_dragClipboard; // used on only the source side of dragging
+ };
+ static EventHandlerDragState& dragState();
+ static const double TextDragDelay;
+
+ bool canHandleDragAndDropForTarget(DragAndDropHandleType, Node* target, const PlatformMouseEvent&, Clipboard*, bool* accepted = 0);
+
+ PassRefPtr<Clipboard> createDraggingClipboard() const;
+#endif // ENABLE(DRAG_SUPPORT)
+
+ bool eventActivatedView(const PlatformMouseEvent&) const;
+ void selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults&);
+ void selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults&);
+
+ bool handleMouseDoubleClickEvent(const PlatformMouseEvent&);
+
+ bool handleMousePressEvent(const MouseEventWithHitTestResults&);
+ bool handleMousePressEventSingleClick(const MouseEventWithHitTestResults&);
+ bool handleMousePressEventDoubleClick(const MouseEventWithHitTestResults&);
+ bool handleMousePressEventTripleClick(const MouseEventWithHitTestResults&);
+#if ENABLE(DRAG_SUPPORT)
+ bool handleMouseDraggedEvent(const MouseEventWithHitTestResults&);
+#endif
+ bool handleMouseReleaseEvent(const MouseEventWithHitTestResults&);
+
+ void handleKeyboardSelectionMovement(KeyboardEvent*);
+
+ Cursor selectCursor(const MouseEventWithHitTestResults&, Scrollbar*);
+#if ENABLE(PAN_SCROLLING)
+ void updatePanScrollState();
+#endif
+
+ void hoverTimerFired(Timer<EventHandler>*);
+
+ static bool canMouseDownStartSelect(Node*);
+#if ENABLE(DRAG_SUPPORT)
+ static bool canMouseDragExtendSelect(Node*);
+#endif
+
+ void handleAutoscroll(RenderObject*);
+ void startAutoscrollTimer();
+ void setAutoscrollRenderer(RenderObject*);
+ void autoscrollTimerFired(Timer<EventHandler>*);
+
+ void fakeMouseMoveEventTimerFired(Timer<EventHandler>*);
+ void cancelFakeMouseMoveEvent();
+
+ void invalidateClick();
+
+ Node* nodeUnderMouse() const;
+
+ void updateMouseEventTargetNode(Node*, const PlatformMouseEvent&, bool fireMouseOverOut);
+ void fireMouseOverOut(bool fireMouseOver = true, bool fireMouseOut = true, bool updateLastNodeUnderMouse = true);
+
+ MouseEventWithHitTestResults prepareMouseEvent(const HitTestRequest&, const PlatformMouseEvent&);
+
+ bool dispatchMouseEvent(const AtomicString& eventType, Node* target, bool cancelable, int clickCount, const PlatformMouseEvent&, bool setUnder);
+#if ENABLE(DRAG_SUPPORT)
+ bool dispatchDragEvent(const AtomicString& eventType, Node* target, const PlatformMouseEvent&, Clipboard*);
+
+ void freeClipboard();
+
+ bool handleDrag(const MouseEventWithHitTestResults&);
+#endif
+ bool handleMouseUp(const MouseEventWithHitTestResults&);
+#if ENABLE(DRAG_SUPPORT)
+ void clearDragState();
+
+ bool dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent&);
+
+ bool dragHysteresisExceeded(const FloatPoint&) const;
+ bool dragHysteresisExceeded(const IntPoint&) const;
+#endif // ENABLE(DRAG_SUPPORT)
+
+ bool passMousePressEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe);
+ bool passMouseMoveEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe, HitTestResult* hoveredNode = 0);
+ bool passMouseReleaseEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe);
+
+ bool passSubframeEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe, HitTestResult* hoveredNode = 0);
+
+ bool passMousePressEventToScrollbar(MouseEventWithHitTestResults&, Scrollbar*);
+
+ bool passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults&);
+ bool passWidgetMouseDownEventToWidget(RenderWidget*);
+
+ bool passMouseDownEventToWidget(Widget*);
+ bool passWheelEventToWidget(PlatformWheelEvent&, Widget*);
+
+ void defaultSpaceEventHandler(KeyboardEvent*);
+ void defaultTabEventHandler(KeyboardEvent*);
+ void defaultArrowEventHandler(FocusDirection, KeyboardEvent*);
+
+#if ENABLE(DRAG_SUPPORT)
+ void allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const;
+#endif
+
+ // The following are called at the beginning of handleMouseUp and handleDrag.
+ // If they return true it indicates that they have consumed the event.
+ bool eventLoopHandleMouseUp(const MouseEventWithHitTestResults&);
+#if ENABLE(DRAG_SUPPORT)
+ bool eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&);
+#endif
+
+ bool invertSenseOfTabsToLinks(KeyboardEvent*) const;
+
+#if ENABLE(DRAG_SUPPORT)
+ void updateSelectionForMouseDrag(Node* targetNode, const IntPoint& localPoint);
+#endif
+
+ void updateLastScrollbarUnderMouse(Scrollbar*, bool);
+
+ void setFrameWasScrolledByUser();
+
+ FocusDirection focusDirectionForKey(const AtomicString&) const;
+
+ bool capturesDragging() const { return m_capturesDragging; }
+
+#if PLATFORM(MAC) && defined(__OBJC__)
+ NSView *mouseDownViewIfStillGood();
+
+ PlatformMouseEvent currentPlatformMouseEvent() const;
+#endif
+
+ Frame* m_frame;
+
+ bool m_mousePressed;
+ bool m_capturesDragging;
+ RefPtr<Node> m_mousePressNode;
+
+ bool m_mouseDownMayStartSelect;
+#if ENABLE(DRAG_SUPPORT)
+ bool m_mouseDownMayStartDrag;
+#endif
+ bool m_mouseDownWasSingleClickInSelection;
+ bool m_beganSelectingText;
+
+#if ENABLE(DRAG_SUPPORT)
+ IntPoint m_dragStartPos;
+#endif
+
+ IntPoint m_panScrollStartPos;
+ bool m_panScrollInProgress;
+
+ bool m_panScrollButtonPressed;
+ bool m_springLoadedPanScrollInProgress;
+
+ Timer<EventHandler> m_hoverTimer;
+
+ Timer<EventHandler> m_autoscrollTimer;
+ RenderObject* m_autoscrollRenderer;
+ bool m_autoscrollInProgress;
+ bool m_mouseDownMayStartAutoscroll;
+ bool m_mouseDownWasInSubframe;
+
+ Timer<EventHandler> m_fakeMouseMoveEventTimer;
+
+#if ENABLE(SVG)
+ bool m_svgPan;
+ RefPtr<SVGElementInstance> m_instanceUnderMouse;
+ RefPtr<SVGElementInstance> m_lastInstanceUnderMouse;
+#endif
+
+ RenderLayer* m_resizeLayer;
+
+ RefPtr<Node> m_capturingMouseEventsNode;
+ bool m_eventHandlerWillResetCapturingMouseEventsNode;
+
+ RefPtr<Node> m_nodeUnderMouse;
+ RefPtr<Node> m_lastNodeUnderMouse;
+ RefPtr<Frame> m_lastMouseMoveEventSubframe;
+ RefPtr<Scrollbar> m_lastScrollbarUnderMouse;
+
+ int m_clickCount;
+ RefPtr<Node> m_clickNode;
+
+#if ENABLE(DRAG_SUPPORT)
+ RefPtr<Node> m_dragTarget;
+ bool m_shouldOnlyFireDragOverEvent;
+#endif
+
+ RefPtr<HTMLFrameSetElement> m_frameSetBeingResized;
+
+ IntSize m_offsetFromResizeCorner; // in the coords of m_resizeLayer
+
+ IntPoint m_currentMousePosition;
+ IntPoint m_mouseDownPos; // in our view's coords
+ double m_mouseDownTimestamp;
+ PlatformMouseEvent m_mouseDown;
+
+ bool m_useLatchedWheelEventNode;
+ RefPtr<Node> m_latchedWheelEventNode;
+ bool m_widgetIsLatched;
+
+ RefPtr<Node> m_previousWheelScrolledNode;
+
+#if PLATFORM(MAC)
+ NSView *m_mouseDownView;
+ bool m_sendingEventToSubview;
+ int m_activationEventNumber;
+#endif
+#if ENABLE(TOUCH_EVENTS)
+ typedef HashMap<int, RefPtr<EventTarget> > TouchTargetMap;
+ TouchTargetMap m_originatingTouchPointTargets;
+ bool m_touchPressed;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // EventHandler_h
diff --git a/Source/WebCore/page/EventSource.cpp b/Source/WebCore/page/EventSource.cpp
new file mode 100644
index 0000000..39f15e9
--- /dev/null
+++ b/Source/WebCore/page/EventSource.cpp
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2009 Ericsson AB
+ * All rights reserved.
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of Ericsson nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(EVENTSOURCE)
+
+#include "EventSource.h"
+
+#include "MemoryCache.h"
+#include "DOMWindow.h"
+#include "Event.h"
+#include "EventException.h"
+#include "PlatformString.h"
+#include "MessageEvent.h"
+#include "ResourceError.h"
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+#include "ScriptExecutionContext.h"
+#include "SerializedScriptValue.h"
+#include "TextResourceDecoder.h"
+#include "ThreadableLoader.h"
+
+namespace WebCore {
+
+const unsigned long long EventSource::defaultReconnectDelay = 3000;
+
+inline EventSource::EventSource(const KURL& url, ScriptExecutionContext* context)
+ : ActiveDOMObject(context, this)
+ , m_url(url)
+ , m_state(CONNECTING)
+ , m_decoder(TextResourceDecoder::create("text/plain", "UTF-8"))
+ , m_reconnectTimer(this, &EventSource::reconnectTimerFired)
+ , m_discardTrailingNewline(false)
+ , m_failSilently(false)
+ , m_requestInFlight(false)
+ , m_reconnectDelay(defaultReconnectDelay)
+ , m_origin(context->securityOrigin()->toString())
+{
+}
+
+PassRefPtr<EventSource> EventSource::create(const String& url, ScriptExecutionContext* context, ExceptionCode& ec)
+{
+ if (url.isEmpty()) {
+ ec = SYNTAX_ERR;
+ return 0;
+ }
+
+ KURL fullURL = context->completeURL(url);
+ if (!fullURL.isValid()) {
+ ec = SYNTAX_ERR;
+ return 0;
+ }
+
+ // FIXME: Should support at least some cross-origin requests.
+ if (!context->securityOrigin()->canRequest(fullURL)) {
+ ec = SECURITY_ERR;
+ return 0;
+ }
+
+ RefPtr<EventSource> source = adoptRef(new EventSource(fullURL, context));
+
+ source->setPendingActivity(source.get());
+ source->connect();
+
+ return source.release();
+}
+
+EventSource::~EventSource()
+{
+}
+
+void EventSource::connect()
+{
+ ResourceRequest request(m_url);
+ request.setHTTPMethod("GET");
+ request.setHTTPHeaderField("Accept", "text/event-stream");
+ request.setHTTPHeaderField("Cache-Control", "no-cache");
+ if (!m_lastEventId.isEmpty())
+ request.setHTTPHeaderField("Last-Event-ID", m_lastEventId);
+
+ ThreadableLoaderOptions options;
+ options.sendLoadCallbacks = true;
+ options.sniffContent = false;
+ options.allowCredentials = true;
+
+ m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options);
+
+ m_requestInFlight = true;
+}
+
+void EventSource::endRequest()
+{
+ if (!m_requestInFlight)
+ return;
+
+ m_requestInFlight = false;
+
+ if (!m_failSilently)
+ dispatchEvent(Event::create(eventNames().errorEvent, false, false));
+
+ if (m_state != CLOSED)
+ scheduleReconnect();
+ else
+ unsetPendingActivity(this);
+}
+
+void EventSource::scheduleReconnect()
+{
+ m_state = CONNECTING;
+ m_reconnectTimer.startOneShot(m_reconnectDelay / 1000);
+}
+
+void EventSource::reconnectTimerFired(Timer<EventSource>*)
+{
+ connect();
+}
+
+String EventSource::url() const
+{
+ return m_url.string();
+}
+
+EventSource::State EventSource::readyState() const
+{
+ return m_state;
+}
+
+void EventSource::close()
+{
+ if (m_state == CLOSED)
+ return;
+
+ if (m_reconnectTimer.isActive()) {
+ m_reconnectTimer.stop();
+ unsetPendingActivity(this);
+ }
+
+ m_state = CLOSED;
+ m_failSilently = true;
+
+ if (m_requestInFlight)
+ m_loader->cancel();
+}
+
+ScriptExecutionContext* EventSource::scriptExecutionContext() const
+{
+ return ActiveDOMObject::scriptExecutionContext();
+}
+
+void EventSource::didReceiveResponse(const ResourceResponse& response)
+{
+ int statusCode = response.httpStatusCode();
+ if (statusCode == 200 && response.mimeType() == "text/event-stream") {
+ m_state = OPEN;
+ dispatchEvent(Event::create(eventNames().openEvent, false, false));
+ } else {
+ if (statusCode <= 200 || statusCode > 299)
+ m_state = CLOSED;
+ m_loader->cancel();
+ }
+}
+
+void EventSource::didReceiveData(const char* data, int length)
+{
+ append(m_receiveBuf, m_decoder->decode(data, length));
+ parseEventStream();
+}
+
+void EventSource::didFinishLoading(unsigned long)
+{
+ if (m_receiveBuf.size() > 0 || m_data.size() > 0) {
+ append(m_receiveBuf, "\n\n");
+ parseEventStream();
+ }
+ m_state = CONNECTING;
+ endRequest();
+}
+
+void EventSource::didFail(const ResourceError& error)
+{
+ int canceled = error.isCancellation();
+ if (((m_state == CONNECTING) && !canceled) || ((m_state == OPEN) && canceled))
+ m_state = CLOSED;
+ endRequest();
+}
+
+void EventSource::didFailRedirectCheck()
+{
+ m_state = CLOSED;
+ m_loader->cancel();
+}
+
+void EventSource::parseEventStream()
+{
+ unsigned int bufPos = 0;
+ unsigned int bufSize = m_receiveBuf.size();
+ while (bufPos < bufSize) {
+ if (m_discardTrailingNewline) {
+ if (m_receiveBuf[bufPos] == '\n')
+ bufPos++;
+ m_discardTrailingNewline = false;
+ }
+
+ int lineLength = -1;
+ int fieldLength = -1;
+ for (unsigned int i = bufPos; lineLength < 0 && i < bufSize; i++) {
+ switch (m_receiveBuf[i]) {
+ case ':':
+ if (fieldLength < 0)
+ fieldLength = i - bufPos;
+ break;
+ case '\r':
+ m_discardTrailingNewline = true;
+ case '\n':
+ lineLength = i - bufPos;
+ break;
+ }
+ }
+
+ if (lineLength < 0)
+ break;
+
+ parseEventStreamLine(bufPos, fieldLength, lineLength);
+ bufPos += lineLength + 1;
+ }
+
+ if (bufPos == bufSize)
+ m_receiveBuf.clear();
+ else if (bufPos)
+ m_receiveBuf.remove(0, bufPos);
+}
+
+void EventSource::parseEventStreamLine(unsigned int bufPos, int fieldLength, int lineLength)
+{
+ if (!lineLength) {
+ if (!m_data.isEmpty()) {
+ m_data.removeLast();
+ dispatchEvent(createMessageEvent());
+ }
+ if (!m_eventName.isEmpty())
+ m_eventName = "";
+ } else if (fieldLength) {
+ bool noValue = fieldLength < 0;
+
+ String field(&m_receiveBuf[bufPos], noValue ? lineLength : fieldLength);
+ int step;
+ if (noValue)
+ step = lineLength;
+ else if (m_receiveBuf[bufPos + fieldLength + 1] != ' ')
+ step = fieldLength + 1;
+ else
+ step = fieldLength + 2;
+ bufPos += step;
+ int valueLength = lineLength - step;
+
+ if (field == "data") {
+ if (valueLength)
+ m_data.append(&m_receiveBuf[bufPos], valueLength);
+ m_data.append('\n');
+ } else if (field == "event")
+ m_eventName = valueLength ? String(&m_receiveBuf[bufPos], valueLength) : "";
+ else if (field == "id")
+ m_lastEventId = valueLength ? String(&m_receiveBuf[bufPos], valueLength) : "";
+ else if (field == "retry") {
+ if (!valueLength)
+ m_reconnectDelay = defaultReconnectDelay;
+ else {
+ String value(&m_receiveBuf[bufPos], valueLength);
+ bool ok;
+ unsigned long long retry = value.toUInt64(&ok);
+ if (ok)
+ m_reconnectDelay = retry;
+ }
+ }
+ }
+}
+
+void EventSource::stop()
+{
+ close();
+}
+
+PassRefPtr<MessageEvent> EventSource::createMessageEvent()
+{
+ RefPtr<MessageEvent> event = MessageEvent::create();
+ event->initMessageEvent(m_eventName.isEmpty() ? eventNames().messageEvent : AtomicString(m_eventName), false, false, SerializedScriptValue::create(String::adopt(m_data)), m_origin, m_lastEventId, 0, 0);
+ return event.release();
+}
+
+EventTargetData* EventSource::eventTargetData()
+{
+ return &m_eventTargetData;
+}
+
+EventTargetData* EventSource::ensureEventTargetData()
+{
+ return &m_eventTargetData;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(EVENTSOURCE)
diff --git a/Source/WebCore/page/EventSource.h b/Source/WebCore/page/EventSource.h
new file mode 100644
index 0000000..ffed592
--- /dev/null
+++ b/Source/WebCore/page/EventSource.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2009 Ericsson AB
+ * All rights reserved.
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of Ericsson nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef EventSource_h
+#define EventSource_h
+
+#if ENABLE(EVENTSOURCE)
+
+#include "ActiveDOMObject.h"
+#include "EventTarget.h"
+#include "KURL.h"
+#include "ThreadableLoaderClient.h"
+#include "Timer.h"
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ class MessageEvent;
+ class ResourceResponse;
+ class TextResourceDecoder;
+ class ThreadableLoader;
+
+ class EventSource : public RefCounted<EventSource>, public EventTarget, private ThreadableLoaderClient, public ActiveDOMObject {
+ public:
+ static PassRefPtr<EventSource> create(const String& url, ScriptExecutionContext*, ExceptionCode&);
+ virtual ~EventSource();
+
+ static const unsigned long long defaultReconnectDelay;
+
+ String url() const;
+
+ enum State {
+ CONNECTING = 0,
+ OPEN = 1,
+ CLOSED = 2,
+ };
+
+ State readyState() const;
+
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(open);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(message);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
+
+ void close();
+
+ using RefCounted<EventSource>::ref;
+ using RefCounted<EventSource>::deref;
+
+ virtual EventSource* toEventSource() { return this; }
+ virtual ScriptExecutionContext* scriptExecutionContext() const;
+
+ virtual void stop();
+
+ private:
+ EventSource(const KURL&, ScriptExecutionContext*);
+
+ virtual void refEventTarget() { ref(); }
+ virtual void derefEventTarget() { deref(); }
+ virtual EventTargetData* eventTargetData();
+ virtual EventTargetData* ensureEventTargetData();
+
+ virtual void didReceiveResponse(const ResourceResponse&);
+ virtual void didReceiveData(const char* data, int length);
+ virtual void didFinishLoading(unsigned long);
+ virtual void didFail(const ResourceError&);
+ virtual void didFailRedirectCheck();
+
+ void connect();
+ void endRequest();
+ void scheduleReconnect();
+ void reconnectTimerFired(Timer<EventSource>*);
+ void parseEventStream();
+ void parseEventStreamLine(unsigned int pos, int fieldLength, int lineLength);
+ PassRefPtr<MessageEvent> createMessageEvent();
+
+ KURL m_url;
+ State m_state;
+
+ RefPtr<TextResourceDecoder> m_decoder;
+ RefPtr<ThreadableLoader> m_loader;
+ Timer<EventSource> m_reconnectTimer;
+ Vector<UChar> m_receiveBuf;
+ bool m_discardTrailingNewline;
+ bool m_failSilently;
+ bool m_requestInFlight;
+
+ String m_eventName;
+ Vector<UChar> m_data;
+ String m_lastEventId;
+ unsigned long long m_reconnectDelay;
+ String m_origin;
+
+ EventTargetData m_eventTargetData;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(EVENTSOURCE)
+
+#endif // EventSource_h
diff --git a/Source/WebCore/page/EventSource.idl b/Source/WebCore/page/EventSource.idl
new file mode 100644
index 0000000..9da7017
--- /dev/null
+++ b/Source/WebCore/page/EventSource.idl
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 Ericsson AB. All rights reserved.
+ * Copyright (C) 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of Ericsson nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module window {
+
+ interface [
+ Conditional=EVENTSOURCE,
+ CanBeConstructed,
+ CustomConstructFunction,
+ ConstructorParameters=1,
+ V8CustomConstructor,
+ EventTarget,
+ NoStaticTables
+ ] EventSource {
+
+ readonly attribute DOMString URL;
+
+ // ready state
+ const unsigned short CONNECTING = 0;
+ const unsigned short OPEN = 1;
+ const unsigned short CLOSED = 2;
+ readonly attribute unsigned short readyState;
+
+ // networking
+ attribute EventListener onopen;
+ attribute EventListener onmessage;
+ attribute EventListener onerror;
+ void close();
+
+ // EventTarget interface
+ void addEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ void removeEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ boolean dispatchEvent(in Event evt)
+ raises(EventException);
+
+ };
+}
diff --git a/Source/WebCore/page/FocusController.cpp b/Source/WebCore/page/FocusController.cpp
new file mode 100644
index 0000000..eda1005
--- /dev/null
+++ b/Source/WebCore/page/FocusController.cpp
@@ -0,0 +1,601 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nuanti Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FocusController.h"
+
+#include "AXObjectCache.h"
+#include "Chrome.h"
+#include "Document.h"
+#include "Editor.h"
+#include "EditorClient.h"
+#include "Element.h"
+#include "Event.h"
+#include "EventHandler.h"
+#include "EventNames.h"
+#include "ExceptionCode.h"
+#include "Frame.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "HTMLAreaElement.h"
+#include "HTMLImageElement.h"
+#include "HTMLNames.h"
+#include "HitTestResult.h"
+#include "KeyboardEvent.h"
+#include "Page.h"
+#include "Range.h"
+#include "RenderLayer.h"
+#include "RenderObject.h"
+#include "RenderWidget.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "SpatialNavigation.h"
+#include "Widget.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace std;
+
+static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool focused)
+{
+ // If we have a focused node we should dispatch blur on it before we blur the window.
+ // If we have a focused node we should dispatch focus on it after we focus the window.
+ // https://bugs.webkit.org/show_bug.cgi?id=27105
+
+ // Do not fire events while modal dialogs are up. See https://bugs.webkit.org/show_bug.cgi?id=33962
+ if (Page* page = document->page()) {
+ if (page->defersLoading())
+ return;
+ }
+
+ if (!focused && document->focusedNode())
+ document->focusedNode()->dispatchBlurEvent();
+ document->dispatchWindowEvent(Event::create(focused ? eventNames().focusEvent : eventNames().blurEvent, false, false));
+ if (focused && document->focusedNode())
+ document->focusedNode()->dispatchFocusEvent();
+}
+
+FocusController::FocusController(Page* page)
+ : m_page(page)
+ , m_isActive(false)
+ , m_isFocused(false)
+ , m_isChangingFocusedFrame(false)
+{
+}
+
+void FocusController::setFocusedFrame(PassRefPtr<Frame> frame)
+{
+ ASSERT(!frame || frame->page() == m_page);
+ if (m_focusedFrame == frame || m_isChangingFocusedFrame)
+ return;
+
+ m_isChangingFocusedFrame = true;
+
+ RefPtr<Frame> oldFrame = m_focusedFrame;
+ RefPtr<Frame> newFrame = frame;
+
+ m_focusedFrame = newFrame;
+
+ // Now that the frame is updated, fire events and update the selection focused states of both frames.
+ if (oldFrame && oldFrame->view()) {
+ oldFrame->selection()->setFocused(false);
+ oldFrame->document()->dispatchWindowEvent(Event::create(eventNames().blurEvent, false, false));
+ }
+
+ if (newFrame && newFrame->view() && isFocused()) {
+ newFrame->selection()->setFocused(true);
+ newFrame->document()->dispatchWindowEvent(Event::create(eventNames().focusEvent, false, false));
+ }
+
+ m_page->chrome()->focusedFrameChanged(newFrame.get());
+
+ m_isChangingFocusedFrame = false;
+}
+
+Frame* FocusController::focusedOrMainFrame() const
+{
+ if (Frame* frame = focusedFrame())
+ return frame;
+ return m_page->mainFrame();
+}
+
+void FocusController::setFocused(bool focused)
+{
+ if (isFocused() == focused)
+ return;
+
+ m_isFocused = focused;
+
+ if (!m_isFocused)
+ focusedOrMainFrame()->eventHandler()->stopAutoscrollTimer();
+
+ if (!m_focusedFrame)
+ setFocusedFrame(m_page->mainFrame());
+
+ if (m_focusedFrame->view()) {
+ m_focusedFrame->selection()->setFocused(focused);
+ dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), focused);
+ }
+}
+
+static Node* deepFocusableNode(FocusDirection direction, Node* node, KeyboardEvent* event)
+{
+ // The node we found might be a HTMLFrameOwnerElement, so descend down the frame tree until we find either:
+ // 1) a focusable node, or
+ // 2) the deepest-nested HTMLFrameOwnerElement
+ while (node && node->isFrameOwnerElement()) {
+ HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node);
+ if (!owner->contentFrame())
+ break;
+
+ Document* document = owner->contentFrame()->document();
+
+ node = (direction == FocusDirectionForward)
+ ? document->nextFocusableNode(0, event)
+ : document->previousFocusableNode(0, event);
+ if (!node) {
+ node = owner;
+ break;
+ }
+ }
+
+ return node;
+}
+
+bool FocusController::setInitialFocus(FocusDirection direction, KeyboardEvent* event)
+{
+ return advanceFocus(direction, event, true);
+}
+
+bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* event, bool initialFocus)
+{
+ switch (direction) {
+ case FocusDirectionForward:
+ case FocusDirectionBackward:
+ return advanceFocusInDocumentOrder(direction, event, initialFocus);
+ case FocusDirectionLeft:
+ case FocusDirectionRight:
+ case FocusDirectionUp:
+ case FocusDirectionDown:
+ return advanceFocusDirectionally(direction, event);
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return false;
+}
+
+bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, KeyboardEvent* event, bool initialFocus)
+{
+ Frame* frame = focusedOrMainFrame();
+ ASSERT(frame);
+ Document* document = frame->document();
+
+ Node* currentNode = document->focusedNode();
+ // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself
+ bool caretBrowsing = focusedOrMainFrame()->settings()->caretBrowsingEnabled();
+
+ if (caretBrowsing && !currentNode)
+ currentNode = frame->selection()->start().node();
+
+ document->updateLayoutIgnorePendingStylesheets();
+
+ Node* node = (direction == FocusDirectionForward)
+ ? document->nextFocusableNode(currentNode, event)
+ : document->previousFocusableNode(currentNode, event);
+
+ // If there's no focusable node to advance to, move up the frame tree until we find one.
+ while (!node && frame) {
+ Frame* parentFrame = frame->tree()->parent();
+ if (!parentFrame)
+ break;
+
+ Document* parentDocument = parentFrame->document();
+
+ HTMLFrameOwnerElement* owner = frame->ownerElement();
+ if (!owner)
+ break;
+
+ node = (direction == FocusDirectionForward)
+ ? parentDocument->nextFocusableNode(owner, event)
+ : parentDocument->previousFocusableNode(owner, event);
+
+ frame = parentFrame;
+ }
+
+ node = deepFocusableNode(direction, node, event);
+
+ if (!node) {
+ // We didn't find a node to focus, so we should try to pass focus to Chrome.
+ if (!initialFocus && m_page->chrome()->canTakeFocus(direction)) {
+ document->setFocusedNode(0);
+ setFocusedFrame(0);
+ m_page->chrome()->takeFocus(direction);
+ return true;
+ }
+
+ // Chrome doesn't want focus, so we should wrap focus.
+ Document* d = m_page->mainFrame()->document();
+ node = (direction == FocusDirectionForward)
+ ? d->nextFocusableNode(0, event)
+ : d->previousFocusableNode(0, event);
+
+ node = deepFocusableNode(direction, node, event);
+
+ if (!node)
+ return false;
+ }
+
+ ASSERT(node);
+
+ if (node == document->focusedNode())
+ // Focus wrapped around to the same node.
+ return true;
+
+ if (!node->isElementNode())
+ // FIXME: May need a way to focus a document here.
+ return false;
+
+ if (node->isFrameOwnerElement()) {
+ // We focus frames rather than frame owners.
+ // FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user.
+ HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node);
+ if (!owner->contentFrame())
+ return false;
+
+ document->setFocusedNode(0);
+ setFocusedFrame(owner->contentFrame());
+ return true;
+ }
+
+ // FIXME: It would be nice to just be able to call setFocusedNode(node) here, but we can't do
+ // that because some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in
+ // their focus() methods.
+
+ Document* newDocument = node->document();
+
+ if (newDocument != document)
+ // Focus is going away from this document, so clear the focused node.
+ document->setFocusedNode(0);
+
+ if (newDocument)
+ setFocusedFrame(newDocument->frame());
+
+ if (caretBrowsing) {
+ VisibleSelection newSelection(Position(node, 0), Position(node, 0), DOWNSTREAM);
+ if (frame->selection()->shouldChangeSelection(newSelection))
+ frame->selection()->setSelection(newSelection);
+ }
+
+ static_cast<Element*>(node)->focus(false);
+ return true;
+}
+
+static bool relinquishesEditingFocus(Node *node)
+{
+ ASSERT(node);
+ ASSERT(node->isContentEditable());
+
+ Node* root = node->rootEditableElement();
+ Frame* frame = node->document()->frame();
+ if (!frame || !root)
+ return false;
+
+ return frame->editor()->shouldEndEditing(rangeOfContents(root).get());
+}
+
+static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFrame, Node* newFocusedNode)
+{
+ if (!oldFocusedFrame || !newFocusedFrame)
+ return;
+
+ if (oldFocusedFrame->document() != newFocusedFrame->document())
+ return;
+
+ SelectionController* s = oldFocusedFrame->selection();
+ if (s->isNone())
+ return;
+
+ bool caretBrowsing = oldFocusedFrame->settings()->caretBrowsingEnabled();
+ if (caretBrowsing)
+ return;
+
+ Node* selectionStartNode = s->selection().start().node();
+ if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->shadowAncestorNode() == newFocusedNode)
+ return;
+
+ if (Node* mousePressNode = newFocusedFrame->eventHandler()->mousePressNode()) {
+ if (mousePressNode->renderer() && !mousePressNode->canStartSelection()) {
+ // Don't clear the selection for contentEditable elements, but do clear it for input and textarea. See bug 38696.
+ Node * root = s->rootEditableElement();
+ if (!root)
+ return;
+
+ if (Node* shadowAncestorNode = root->shadowAncestorNode()) {
+ if (!shadowAncestorNode->hasTagName(inputTag) && !shadowAncestorNode->hasTagName(textareaTag))
+ return;
+ }
+ }
+ }
+
+ s->clear();
+}
+
+bool FocusController::setFocusedNode(Node* node, PassRefPtr<Frame> newFocusedFrame)
+{
+ RefPtr<Frame> oldFocusedFrame = focusedFrame();
+ RefPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : 0;
+
+ Node* oldFocusedNode = oldDocument ? oldDocument->focusedNode() : 0;
+ if (oldFocusedNode == node)
+ return true;
+
+ // FIXME: Might want to disable this check for caretBrowsing
+ if (oldFocusedNode && oldFocusedNode->rootEditableElement() == oldFocusedNode && !relinquishesEditingFocus(oldFocusedNode))
+ return false;
+
+ m_page->editorClient()->willSetInputMethodState();
+
+ clearSelectionIfNeeded(oldFocusedFrame.get(), newFocusedFrame.get(), node);
+
+ if (!node) {
+ if (oldDocument)
+ oldDocument->setFocusedNode(0);
+ m_page->editorClient()->setInputMethodState(false);
+ return true;
+ }
+
+ RefPtr<Document> newDocument = node->document();
+
+ if (newDocument && newDocument->focusedNode() == node) {
+ m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod());
+ return true;
+ }
+
+ if (oldDocument && oldDocument != newDocument)
+ oldDocument->setFocusedNode(0);
+
+ setFocusedFrame(newFocusedFrame);
+
+ // Setting the focused node can result in losing our last reft to node when JS event handlers fire.
+ RefPtr<Node> protect = node;
+ if (newDocument) {
+ bool successfullyFocused = newDocument->setFocusedNode(node);
+ if (!successfullyFocused)
+ return false;
+ }
+
+ if (newDocument->focusedNode() == node)
+ m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod());
+
+ return true;
+}
+
+void FocusController::setActive(bool active)
+{
+ if (m_isActive == active)
+ return;
+
+ m_isActive = active;
+
+ if (FrameView* view = m_page->mainFrame()->view()) {
+ if (!view->platformWidget()) {
+ view->updateLayoutAndStyleIfNeededRecursive();
+ view->updateControlTints();
+ }
+ }
+
+ focusedOrMainFrame()->selection()->pageActivationChanged();
+
+ if (m_focusedFrame && isFocused())
+ dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), active);
+}
+
+static void updateFocusCandidateIfNeeded(FocusDirection direction, const IntRect& startingRect, FocusCandidate& candidate, FocusCandidate& closest)
+{
+ ASSERT(candidate.visibleNode->isElementNode());
+ ASSERT(candidate.visibleNode->renderer());
+
+ // Ignore iframes that don't have a src attribute
+ if (frameOwnerElement(candidate) && (!frameOwnerElement(candidate)->contentFrame() || candidate.rect.isEmpty()))
+ 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.visibleNode->document()->page()->mainFrame()->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), false, true);
+ if (candidate.visibleNode->contains(result.innerNode())) {
+ closest = candidate;
+ return;
+ }
+ if (closest.visibleNode->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(node, direction)) ? node->traverseNextSibling(container) : node->traverseNextNode(container)) {
+ if (node == focusedNode)
+ continue;
+
+ if (!node->isElementNode())
+ continue;
+
+ if (!node->isKeyboardFocusable(event) && !node->isFrameOwnerElement() && !canScrollInDirection(node, direction))
+ continue;
+
+ FocusCandidate candidate = FocusCandidate(node, direction);
+ if (candidate.isNull())
+ continue;
+
+ 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()) {
+ // Nothing to focus, scroll if possible.
+ // NOTE: If no scrolling is performed (i.e. scrollInDirection returns false), the
+ // spatial navigation algorithm will skip this container.
+ return scrollInDirection(container, direction);
+ }
+
+ if (HTMLFrameOwnerElement* frameElement = frameOwnerElement(focusCandidate)) {
+ // 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.visibleNode->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.visibleNode, true), direction, event);
+ }
+ return true;
+ }
+
+ if (canScrollInDirection(focusCandidate.visibleNode, direction)) {
+ if (focusCandidate.isOffscreenAfterScrolling) {
+ scrollInDirection(focusCandidate.visibleNode, 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.visibleNode, 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.focusableNode);
+ 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) {
+ if (!hasOffscreenRect(focusedNode)) {
+ container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, focusedNode);
+ startingRect = nodeRectInAbsoluteCoordinates(focusedNode, true /* ignore border */);
+ } else if (focusedNode->hasTagName(areaTag)) {
+ HTMLAreaElement* area = static_cast<HTMLAreaElement*>(focusedNode);
+ container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, area->imageElement());
+ startingRect = virtualRectForAreaElementAndDirection(area, direction);
+ }
+ }
+
+ 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/Source/WebCore/page/FocusController.h b/Source/WebCore/page/FocusController.h
new file mode 100644
index 0000000..be51c77
--- /dev/null
+++ b/Source/WebCore/page/FocusController.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FocusController_h
+#define FocusController_h
+
+#include "FocusDirection.h"
+#include "SpatialNavigation.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class Document;
+class Frame;
+class KeyboardEvent;
+class Node;
+class Page;
+
+class FocusController : public Noncopyable {
+public:
+ FocusController(Page*);
+
+ void setFocusedFrame(PassRefPtr<Frame>);
+ Frame* focusedFrame() const { return m_focusedFrame.get(); }
+ Frame* focusedOrMainFrame() const;
+
+ bool setInitialFocus(FocusDirection, KeyboardEvent*);
+ bool advanceFocus(FocusDirection, KeyboardEvent*, bool initialFocus = false);
+
+ bool setFocusedNode(Node*, PassRefPtr<Frame>);
+
+ void setActive(bool);
+ bool isActive() const { return m_isActive; }
+
+ void setFocused(bool);
+ bool isFocused() const { return m_isFocused; }
+
+private:
+ bool advanceFocusDirectionally(FocusDirection, KeyboardEvent*);
+ bool advanceFocusInDocumentOrder(FocusDirection, KeyboardEvent*, bool initialFocus);
+
+ 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;
+ bool m_isActive;
+ bool m_isFocused;
+ bool m_isChangingFocusedFrame;
+};
+
+} // namespace WebCore
+
+#endif // FocusController_h
diff --git a/Source/WebCore/page/FocusDirection.h b/Source/WebCore/page/FocusDirection.h
new file mode 100644
index 0000000..8a6d51f
--- /dev/null
+++ b/Source/WebCore/page/FocusDirection.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FocusDirection_h
+#define FocusDirection_h
+
+namespace WebCore {
+ enum FocusDirection {
+ FocusDirectionNone = 0,
+ FocusDirectionForward,
+ FocusDirectionBackward,
+ FocusDirectionUp,
+ FocusDirectionDown,
+ FocusDirectionLeft,
+ FocusDirectionRight
+ };
+}
+
+#endif // FocusDirection_h
diff --git a/Source/WebCore/page/Frame.cpp b/Source/WebCore/page/Frame.cpp
new file mode 100644
index 0000000..11a86c6
--- /dev/null
+++ b/Source/WebCore/page/Frame.cpp
@@ -0,0 +1,1002 @@
+/*
+ * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ * 1999 Lars Knoll <knoll@kde.org>
+ * 1999 Antti Koivisto <koivisto@kde.org>
+ * 2000 Simon Hausmann <hausmann@kde.org>
+ * 2000 Stefan Schimanski <1Stein@gmx.de>
+ * 2001 George Staikos <staikos@kde.org>
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Frame.h"
+
+#include "ApplyStyleCommand.h"
+#include "CSSComputedStyleDeclaration.h"
+#include "CSSMutableStyleDeclaration.h"
+#include "CSSProperty.h"
+#include "CSSPropertyNames.h"
+#include "CachedCSSStyleSheet.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "DOMWindow.h"
+#include "CachedResourceLoader.h"
+#include "DocumentType.h"
+#include "EditingText.h"
+#include "EditorClient.h"
+#include "EventNames.h"
+#include "FloatQuad.h"
+#include "FocusController.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "GraphicsLayer.h"
+#include "HTMLDocument.h"
+#include "HTMLFormControlElement.h"
+#include "HTMLFormElement.h"
+#include "HTMLFrameElementBase.h"
+#include "HTMLNames.h"
+#include "HTMLTableCellElement.h"
+#include "HitTestResult.h"
+#include "Logging.h"
+#include "MediaFeatureNames.h"
+#include "Navigator.h"
+#include "NodeList.h"
+#include "Page.h"
+#include "PageGroup.h"
+#include "RegularExpression.h"
+#include "RenderLayer.h"
+#include "RenderPart.h"
+#include "RenderTableCell.h"
+#include "RenderTextControl.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include "ScriptController.h"
+#include "ScriptSourceCode.h"
+#include "Settings.h"
+#include "TextIterator.h"
+#include "TextResourceDecoder.h"
+#include "UserContentURLPattern.h"
+#include "UserTypingGestureIndicator.h"
+#include "XMLNSNames.h"
+#include "XMLNames.h"
+#include "htmlediting.h"
+#include "markup.h"
+#include "npruntime_impl.h"
+#include "visible_units.h"
+#include <wtf/RefCountedLeakCounter.h>
+#include <wtf/StdLibExtras.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "RenderLayerCompositor.h"
+#endif
+
+#if USE(JSC)
+#include "JSDOMWindowShell.h"
+#include "runtime_root.h"
+#endif
+
+#include "MathMLNames.h"
+#include "SVGNames.h"
+#include "XLinkNames.h"
+
+#if ENABLE(SVG)
+#include "SVGDocument.h"
+#include "SVGDocumentExtensions.h"
+#endif
+
+#if ENABLE(TILED_BACKING_STORE)
+#include "TiledBackingStore.h"
+#endif
+
+#if ENABLE(WML)
+#include "WMLNames.h"
+#endif
+
+#if PLATFORM(ANDROID)
+#include "WebViewCore.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+#ifndef NDEBUG
+static WTF::RefCountedLeakCounter frameCounter("Frame");
+#endif
+
+static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
+{
+ if (!ownerElement)
+ return 0;
+ return ownerElement->document()->frame();
+}
+
+static inline float parentPageZoomFactor(Frame* frame)
+{
+ Frame* parent = frame->tree()->parent();
+ if (!parent)
+ return 1;
+ return parent->pageZoomFactor();
+}
+
+static inline float parentTextZoomFactor(Frame* frame)
+{
+ Frame* parent = frame->tree()->parent();
+ if (!parent)
+ return 1;
+ return parent->textZoomFactor();
+}
+
+inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
+ : m_page(page)
+ , m_treeNode(this, parentFromOwnerElement(ownerElement))
+ , m_loader(this, frameLoaderClient)
+ , m_navigationScheduler(this)
+ , m_ownerElement(ownerElement)
+ , m_script(this)
+ , m_editor(this)
+ , m_selectionController(this)
+ , m_eventHandler(this)
+ , m_animationController(this)
+ , m_lifeSupportTimer(this, &Frame::lifeSupportTimerFired)
+ , m_pageZoomFactor(parentPageZoomFactor(this))
+ , m_textZoomFactor(parentTextZoomFactor(this))
+ , m_pageScaleFactor(1)
+#if ENABLE(ORIENTATION_EVENTS)
+ , m_orientation(0)
+#endif
+ , m_inViewSourceMode(false)
+ , m_isDisconnected(false)
+ , m_excludeFromTextSearch(false)
+{
+ ASSERT(page);
+ AtomicString::init();
+ HTMLNames::init();
+ QualifiedName::init();
+ MediaFeatureNames::init();
+ SVGNames::init();
+ XLinkNames::init();
+ MathMLNames::init();
+ XMLNSNames::init();
+ XMLNames::init();
+
+#if ENABLE(WML)
+ WMLNames::init();
+#endif
+
+ if (!ownerElement) {
+#if ENABLE(TILED_BACKING_STORE)
+ // Top level frame only for now.
+ setTiledBackingStoreEnabled(page->settings()->tiledBackingStoreEnabled());
+#endif
+ } else {
+ page->incrementFrameCount();
+
+ // Make sure we will not end up with two frames referencing the same owner element.
+ Frame*& contentFrameSlot = ownerElement->m_contentFrame;
+ ASSERT(!contentFrameSlot || contentFrameSlot->ownerElement() != ownerElement);
+ contentFrameSlot = this;
+ }
+
+#ifndef NDEBUG
+ frameCounter.increment();
+#endif
+}
+
+PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client)
+{
+ RefPtr<Frame> frame = adoptRef(new Frame(page, ownerElement, client));
+ if (!ownerElement)
+ page->setMainFrame(frame);
+ return frame.release();
+}
+
+Frame::~Frame()
+{
+ setView(0);
+ loader()->cancelAndClear();
+
+ // FIXME: We should not be doing all this work inside the destructor
+
+ ASSERT(!m_lifeSupportTimer.isActive());
+
+#ifndef NDEBUG
+ frameCounter.decrement();
+#endif
+
+ disconnectOwnerElement();
+
+ if (m_domWindow)
+ m_domWindow->disconnectFrame();
+ script()->clearWindowShell();
+
+ HashSet<DOMWindow*>::iterator end = m_liveFormerWindows.end();
+ for (HashSet<DOMWindow*>::iterator it = m_liveFormerWindows.begin(); it != end; ++it)
+ (*it)->disconnectFrame();
+
+ HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
+ for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
+ (*it)->frameDestroyed();
+
+ if (m_view) {
+ m_view->hide();
+ m_view->clearFrame();
+ }
+
+ ASSERT(!m_lifeSupportTimer.isActive());
+}
+
+void Frame::addDestructionObserver(FrameDestructionObserver* observer)
+{
+ m_destructionObservers.add(observer);
+}
+
+void Frame::removeDestructionObserver(FrameDestructionObserver* observer)
+{
+ m_destructionObservers.remove(observer);
+}
+
+void Frame::setView(PassRefPtr<FrameView> view)
+{
+ // We the custom scroll bars as early as possible to prevent m_doc->detach()
+ // from messing with the view such that its scroll bars won't be torn down.
+ // FIXME: We should revisit this.
+ if (m_view)
+ m_view->detachCustomScrollbars();
+
+ // Detach the document now, so any onUnload handlers get run - if
+ // we wait until the view is destroyed, then things won't be
+ // hooked up enough for some JavaScript calls to work.
+ if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {
+ // FIXME: We don't call willRemove here. Why is that OK?
+ m_doc->detach();
+ }
+
+ if (m_view)
+ m_view->unscheduleRelayout();
+
+ eventHandler()->clear();
+
+ m_view = view;
+
+ // Only one form submission is allowed per view of a part.
+ // Since this part may be getting reused as a result of being
+ // pulled from the back/forward cache, reset this flag.
+ loader()->resetMultipleFormSubmissionProtection();
+
+#if ENABLE(TILED_BACKING_STORE)
+ if (m_view && tiledBackingStore())
+ m_view->setPaintsEntireContents(true);
+#endif
+}
+
+void Frame::setDocument(PassRefPtr<Document> newDoc)
+{
+ ASSERT(!newDoc || newDoc->frame());
+ if (m_doc && m_doc->attached() && !m_doc->inPageCache()) {
+ // FIXME: We don't call willRemove here. Why is that OK?
+ m_doc->detach();
+ }
+
+ m_doc = newDoc;
+ selection()->updateSecureKeyboardEntryIfActive();
+
+ if (m_doc && !m_doc->attached())
+ m_doc->attach();
+
+ // Update the cached 'document' property, which is now stale.
+ m_script.updateDocument();
+
+ if (m_page)
+ m_page->updateViewportArguments();
+}
+
+#if ENABLE(ORIENTATION_EVENTS)
+void Frame::sendOrientationChangeEvent(int orientation)
+{
+ m_orientation = orientation;
+ if (Document* doc = document())
+ doc->dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, false, false));
+}
+#endif // ENABLE(ORIENTATION_EVENTS)
+
+Settings* Frame::settings() const
+{
+ return m_page ? m_page->settings() : 0;
+}
+
+static RegularExpression* createRegExpForLabels(const Vector<String>& labels)
+{
+ // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
+ // the same across calls. We can't do that.
+
+ DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));
+ String pattern("(");
+ unsigned int numLabels = labels.size();
+ unsigned int i;
+ for (i = 0; i < numLabels; i++) {
+ String label = labels[i];
+
+ bool startsWithWordChar = false;
+ bool endsWithWordChar = false;
+ if (label.length()) {
+ startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;
+ endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;
+ }
+
+ if (i)
+ pattern.append("|");
+ // Search for word boundaries only if label starts/ends with "word characters".
+ // If we always searched for word boundaries, this wouldn't work for languages
+ // such as Japanese.
+ if (startsWithWordChar)
+ pattern.append("\\b");
+ pattern.append(label);
+ if (endsWithWordChar)
+ pattern.append("\\b");
+ }
+ pattern.append(")");
+ return new RegularExpression(pattern, TextCaseInsensitive);
+}
+
+String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell)
+{
+ HTMLTableCellElement* aboveCell = cell->cellAbove();
+ if (aboveCell) {
+ // search within the above cell we found for a match
+ size_t lengthSearched = 0;
+ for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
+ if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
+ // For each text chunk, run the regexp
+ String nodeString = n->nodeValue();
+ int pos = regExp->searchRev(nodeString);
+ if (pos >= 0) {
+ if (resultDistanceFromStartOfCell)
+ *resultDistanceFromStartOfCell = lengthSearched;
+ return nodeString.substring(pos, regExp->matchedLength());
+ }
+ lengthSearched += nodeString.length();
+ }
+ }
+ }
+
+ // Any reason in practice to search all cells in that are above cell?
+ if (resultDistanceFromStartOfCell)
+ *resultDistanceFromStartOfCell = notFound;
+ return String();
+}
+
+String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
+{
+ OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
+ // We stop searching after we've seen this many chars
+ const unsigned int charsSearchedThreshold = 500;
+ // This is the absolute max we search. We allow a little more slop than
+ // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
+ const unsigned int maxCharsSearched = 600;
+ // If the starting element is within a table, the cell that contains it
+ HTMLTableCellElement* startingTableCell = 0;
+ bool searchedCellAbove = false;
+
+ if (resultDistance)
+ *resultDistance = notFound;
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = false;
+
+ // walk backwards in the node tree, until another element, or form, or end of tree
+ int unsigned lengthSearched = 0;
+ Node* n;
+ for (n = element->traversePreviousNode();
+ n && lengthSearched < charsSearchedThreshold;
+ n = n->traversePreviousNode())
+ {
+ if (n->hasTagName(formTag)
+ || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))
+ {
+ // We hit another form element or the start of the form - bail out
+ break;
+ } else if (n->hasTagName(tdTag) && !startingTableCell) {
+ startingTableCell = static_cast<HTMLTableCellElement*>(n);
+ } else if (n->hasTagName(trTag) && startingTableCell) {
+ String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
+ if (!result.isEmpty()) {
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = true;
+ return result;
+ }
+ searchedCellAbove = true;
+ } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
+ // For each text chunk, run the regexp
+ String nodeString = n->nodeValue();
+ // add 100 for slop, to make it more likely that we'll search whole nodes
+ if (lengthSearched + nodeString.length() > maxCharsSearched)
+ nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
+ int pos = regExp->searchRev(nodeString);
+ if (pos >= 0) {
+ if (resultDistance)
+ *resultDistance = lengthSearched;
+ return nodeString.substring(pos, regExp->matchedLength());
+ }
+ lengthSearched += nodeString.length();
+ }
+ }
+
+ // If we started in a cell, but bailed because we found the start of the form or the
+ // previous element, we still might need to search the row above us for a label.
+ if (startingTableCell && !searchedCellAbove) {
+ String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
+ if (!result.isEmpty()) {
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = true;
+ return result;
+ }
+ }
+ return String();
+}
+
+static String matchLabelsAgainstString(const Vector<String>& labels, const String& stringToMatch)
+{
+ if (stringToMatch.isEmpty())
+ return String();
+
+ String mutableStringToMatch = stringToMatch;
+
+ // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
+ replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
+ mutableStringToMatch.replace('_', ' ');
+
+ OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
+ // Use the largest match we can find in the whole string
+ int pos;
+ int length;
+ int bestPos = -1;
+ int bestLength = -1;
+ int start = 0;
+ do {
+ pos = regExp->match(mutableStringToMatch, start);
+ if (pos != -1) {
+ length = regExp->matchedLength();
+ if (length >= bestLength) {
+ bestPos = pos;
+ bestLength = length;
+ }
+ start = pos + 1;
+ }
+ } while (pos != -1);
+
+ if (bestPos != -1)
+ return mutableStringToMatch.substring(bestPos, bestLength);
+ return String();
+}
+
+String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
+{
+ // Match against the name element, then against the id element if no match is found for the name element.
+ // See 7538330 for one popular site that benefits from the id element check.
+ // FIXME: This code is mirrored in FrameMac.mm. It would be nice to make the Mac code call the platform-agnostic
+ // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
+ String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getAttribute(nameAttr));
+ if (!resultFromNameAttribute.isEmpty())
+ return resultFromNameAttribute;
+
+ return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
+}
+
+void Frame::setPrinting(bool printing, const FloatSize& pageSize, float maximumShrinkRatio, AdjustViewSizeOrNot shouldAdjustViewSize)
+{
+ m_doc->setPrinting(printing);
+ view()->adjustMediaTypeForPrinting(printing);
+
+ m_doc->styleSelectorChanged(RecalcStyleImmediately);
+ view()->forceLayoutForPagination(pageSize, maximumShrinkRatio, shouldAdjustViewSize);
+
+ // Subframes of the one we're printing don't lay out to the page size.
+ for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
+ child->setPrinting(printing, IntSize(), 0, shouldAdjustViewSize);
+}
+
+void Frame::injectUserScripts(UserScriptInjectionTime injectionTime)
+{
+ if (!m_page)
+ return;
+
+ if (loader()->stateMachine()->creatingInitialEmptyDocument())
+ return;
+
+ // Walk the hashtable. Inject by world.
+ const UserScriptMap* userScripts = m_page->group().userScripts();
+ if (!userScripts)
+ return;
+ UserScriptMap::const_iterator end = userScripts->end();
+ for (UserScriptMap::const_iterator it = userScripts->begin(); it != end; ++it)
+ injectUserScriptsForWorld(it->first.get(), *it->second, injectionTime);
+}
+
+void Frame::injectUserScriptsForWorld(DOMWrapperWorld* world, const UserScriptVector& userScripts, UserScriptInjectionTime injectionTime)
+{
+ if (userScripts.isEmpty())
+ return;
+
+ Document* doc = document();
+ if (!doc)
+ return;
+
+ Vector<ScriptSourceCode> sourceCode;
+ unsigned count = userScripts.size();
+ for (unsigned i = 0; i < count; ++i) {
+ UserScript* script = userScripts[i].get();
+ if (script->injectedFrames() == InjectInTopFrameOnly && ownerElement())
+ continue;
+
+ if (script->injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(doc->url(), script->whitelist(), script->blacklist()))
+ m_script.evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world);
+ }
+}
+
+bool Frame::isContentEditable() const
+{
+ if (m_editor.clientIsEditable())
+ return true;
+ return m_doc->inDesignMode();
+}
+
+#ifndef NDEBUG
+static HashSet<Frame*>& keepAliveSet()
+{
+ DEFINE_STATIC_LOCAL(HashSet<Frame*>, staticKeepAliveSet, ());
+ return staticKeepAliveSet;
+}
+#endif
+
+void Frame::keepAlive()
+{
+ if (m_lifeSupportTimer.isActive())
+ return;
+#ifndef NDEBUG
+ keepAliveSet().add(this);
+#endif
+ ref();
+ m_lifeSupportTimer.startOneShot(0);
+}
+
+#ifndef NDEBUG
+void Frame::cancelAllKeepAlive()
+{
+ HashSet<Frame*>::iterator end = keepAliveSet().end();
+ for (HashSet<Frame*>::iterator it = keepAliveSet().begin(); it != end; ++it) {
+ Frame* frame = *it;
+ frame->m_lifeSupportTimer.stop();
+ frame->deref();
+ }
+ keepAliveSet().clear();
+}
+#endif
+
+void Frame::lifeSupportTimerFired(Timer<Frame>*)
+{
+#ifndef NDEBUG
+ keepAliveSet().remove(this);
+#endif
+ deref();
+}
+
+void Frame::clearDOMWindow()
+{
+ if (m_domWindow) {
+ m_liveFormerWindows.add(m_domWindow.get());
+ m_domWindow->clear();
+ }
+ m_domWindow = 0;
+}
+
+RenderView* Frame::contentRenderer() const
+{
+ Document* doc = document();
+ if (!doc)
+ return 0;
+ RenderObject* object = doc->renderer();
+ if (!object)
+ return 0;
+ ASSERT(object->isRenderView());
+ return toRenderView(object);
+}
+
+RenderPart* Frame::ownerRenderer() const
+{
+ HTMLFrameOwnerElement* ownerElement = m_ownerElement;
+ if (!ownerElement)
+ return 0;
+ RenderObject* object = ownerElement->renderer();
+ if (!object)
+ return 0;
+ // FIXME: If <object> is ever fixed to disassociate itself from frames
+ // that it has started but canceled, then this can turn into an ASSERT
+ // since m_ownerElement would be 0 when the load is canceled.
+ // https://bugs.webkit.org/show_bug.cgi?id=18585
+ if (!object->isRenderPart())
+ return 0;
+ return toRenderPart(object);
+}
+
+Frame* Frame::frameForWidget(const Widget* widget)
+{
+ ASSERT_ARG(widget, widget);
+
+ if (RenderWidget* renderer = RenderWidget::find(widget))
+ if (Node* node = renderer->node())
+ return node->document()->frame();
+
+ // Assume all widgets are either a FrameView or owned by a RenderWidget.
+ // FIXME: That assumption is not right for scroll bars!
+ ASSERT(widget->isFrameView());
+ return static_cast<const FrameView*>(widget)->frame();
+}
+
+void Frame::clearTimers(FrameView *view, Document *document)
+{
+ if (view) {
+ view->unscheduleRelayout();
+ if (view->frame()) {
+ view->frame()->animation()->suspendAnimationsForDocument(document);
+ view->frame()->eventHandler()->stopAutoscrollTimer();
+ }
+ }
+}
+
+void Frame::clearTimers()
+{
+ clearTimers(m_view.get(), document());
+}
+
+void Frame::setDOMWindow(DOMWindow* domWindow)
+{
+ if (m_domWindow) {
+ m_liveFormerWindows.add(m_domWindow.get());
+ m_domWindow->clear();
+ }
+ m_domWindow = domWindow;
+}
+
+DOMWindow* Frame::domWindow() const
+{
+ if (!m_domWindow)
+ m_domWindow = DOMWindow::create(const_cast<Frame*>(this));
+
+ return m_domWindow.get();
+}
+
+void Frame::clearFormerDOMWindow(DOMWindow* window)
+{
+ m_liveFormerWindows.remove(window);
+}
+
+void Frame::pageDestroyed()
+{
+ if (Frame* parent = tree()->parent())
+ parent->loader()->checkLoadComplete();
+
+ if (m_domWindow)
+ m_domWindow->pageDestroyed();
+
+ // FIXME: It's unclear as to why this is called more than once, but it is,
+ // so page() could be NULL.
+ if (page() && page()->focusController()->focusedFrame() == this)
+ page()->focusController()->setFocusedFrame(0);
+
+ script()->clearWindowShell();
+ script()->clearScriptObjects();
+ script()->updatePlatformScriptObjects();
+
+ detachFromPage();
+}
+
+void Frame::disconnectOwnerElement()
+{
+ if (m_ownerElement) {
+ if (Document* doc = document())
+ doc->clearAXObjectCache();
+ m_ownerElement->m_contentFrame = 0;
+ if (m_page)
+ m_page->decrementFrameCount();
+ }
+ m_ownerElement = 0;
+}
+
+// The frame is moved in DOM, potentially to another page.
+void Frame::transferChildFrameToNewDocument()
+{
+ ASSERT(m_ownerElement);
+ Frame* newParent = m_ownerElement->document()->frame();
+ ASSERT(newParent);
+ bool didTransfer = false;
+
+ // Switch page.
+ Page* newPage = newParent->page();
+ Page* oldPage = m_page;
+ if (m_page != newPage) {
+ if (m_page) {
+ if (m_page->focusController()->focusedFrame() == this)
+ m_page->focusController()->setFocusedFrame(0);
+
+ m_page->decrementFrameCount();
+ }
+
+ m_page = newPage;
+
+ if (newPage)
+ newPage->incrementFrameCount();
+
+ didTransfer = true;
+ }
+
+ // 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.
+ if (didTransfer) {
+ // Let external clients update themselves.
+ loader()->client()->didTransferChildFrameToNewDocument(oldPage);
+
+ // Update resource tracking now that frame could be in a different page.
+ if (oldPage != newPage)
+ loader()->transferLoadingResourcesFromPage(oldPage);
+
+ // Do the same for all the children.
+ for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
+ child->transferChildFrameToNewDocument();
+ }
+}
+
+String Frame::documentTypeString() const
+{
+ if (DocumentType* doctype = document()->doctype())
+ return createMarkup(doctype);
+
+ return String();
+}
+
+VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
+{
+ HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true);
+ Node* node = result.innerNode();
+ if (!node)
+ return VisiblePosition();
+ RenderObject* renderer = node->renderer();
+ if (!renderer)
+ return VisiblePosition();
+ VisiblePosition visiblePos = renderer->positionForPoint(result.localPoint());
+ if (visiblePos.isNull())
+ visiblePos = VisiblePosition(Position(node, 0));
+ return visiblePos;
+}
+
+Document* Frame::documentAtPoint(const IntPoint& point)
+{
+ if (!view())
+ return 0;
+
+ IntPoint pt = view()->windowToContents(point);
+ HitTestResult result = HitTestResult(pt);
+
+ if (contentRenderer())
+ result = eventHandler()->hitTestResultAtPoint(pt, false);
+ return result.innerNode() ? result.innerNode()->document() : 0;
+}
+
+void Frame::createView(const IntSize& viewportSize,
+ const Color& backgroundColor, bool transparent,
+ const IntSize& fixedLayoutSize, bool useFixedLayout,
+ ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
+ ScrollbarMode verticalScrollbarMode, bool verticalLock)
+{
+ ASSERT(this);
+ ASSERT(m_page);
+
+ bool isMainFrame = this == m_page->mainFrame();
+
+ if (isMainFrame && view())
+ view()->setParentVisible(false);
+
+ setView(0);
+
+ RefPtr<FrameView> frameView;
+ if (isMainFrame) {
+ frameView = FrameView::create(this, viewportSize);
+ frameView->setFixedLayoutSize(fixedLayoutSize);
+ frameView->setUseFixedLayout(useFixedLayout);
+ } else
+ frameView = FrameView::create(this);
+
+ frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
+
+ setView(frameView);
+
+ if (backgroundColor.isValid())
+ frameView->updateBackgroundRecursively(backgroundColor, transparent);
+
+ if (isMainFrame)
+ frameView->setParentVisible(true);
+
+ if (ownerRenderer())
+ ownerRenderer()->setWidget(frameView);
+
+ if (HTMLFrameOwnerElement* owner = ownerElement())
+ view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
+}
+
+#if ENABLE(TILED_BACKING_STORE)
+void Frame::setTiledBackingStoreEnabled(bool enabled)
+{
+ if (!enabled) {
+ m_tiledBackingStore.clear();
+ return;
+ }
+ if (m_tiledBackingStore)
+ return;
+ m_tiledBackingStore.set(new TiledBackingStore(this));
+ if (m_view)
+ m_view->setPaintsEntireContents(true);
+}
+
+void Frame::tiledBackingStorePaintBegin()
+{
+ if (!m_view)
+ return;
+ m_view->updateLayoutAndStyleIfNeededRecursive();
+ m_view->flushDeferredRepaints();
+}
+
+void Frame::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!m_view)
+ return;
+ m_view->paintContents(context, rect);
+}
+
+void Frame::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea)
+{
+ if (!m_page || !m_view)
+ return;
+ unsigned size = paintedArea.size();
+ // Request repaint from the system
+ for (int n = 0; n < size; ++n)
+ m_page->chrome()->invalidateContentsAndWindow(m_view->contentsToWindow(paintedArea[n]), false);
+}
+
+IntRect Frame::tiledBackingStoreContentsRect()
+{
+ if (!m_view)
+ return IntRect();
+ return IntRect(IntPoint(), m_view->contentsSize());
+}
+
+IntRect Frame::tiledBackingStoreVisibleRect()
+{
+ if (!m_page)
+ return IntRect();
+ return m_page->chrome()->client()->visibleRectForTiledBackingStore();
+}
+
+Color Frame::tiledBackingStoreBackgroundColor() const
+{
+ if (!m_view)
+ return Color();
+ return m_view->baseBackgroundColor();
+}
+#endif
+
+String Frame::layerTreeAsText() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ document()->updateLayout();
+
+ if (!contentRenderer())
+ return String();
+
+ return contentRenderer()->compositor()->layerTreeAsText();
+#else
+ return String();
+#endif
+}
+
+void Frame::setPageZoomFactor(float factor)
+{
+ setPageAndTextZoomFactors(factor, m_textZoomFactor);
+}
+
+void Frame::setTextZoomFactor(float factor)
+{
+ setPageAndTextZoomFactors(m_pageZoomFactor, factor);
+}
+
+void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
+{
+ if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
+ return;
+
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ Document* document = this->document();
+ if (!document)
+ return;
+
+#if ENABLE(SVG)
+ // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
+ // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
+ if (document->isSVGDocument()) {
+ if (!static_cast<SVGDocument*>(document)->zoomAndPanEnabled())
+ return;
+ if (document->renderer())
+ document->renderer()->setNeedsLayout(true);
+ }
+#endif
+
+ if (m_pageZoomFactor != pageZoomFactor) {
+ if (FrameView* view = this->view()) {
+ // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
+ IntPoint scrollPosition = view->scrollPosition();
+ float percentDifference = (pageZoomFactor / m_pageZoomFactor);
+ view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
+ }
+ }
+
+ m_pageZoomFactor = pageZoomFactor;
+ m_textZoomFactor = textZoomFactor;
+
+ document->recalcStyle(Node::Force);
+
+ for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
+ child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
+
+ if (FrameView* view = this->view()) {
+ if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
+ view->layout();
+ }
+}
+
+void Frame::scalePage(float scale, const IntPoint& origin)
+{
+ Document* document = this->document();
+ if (!document)
+ return;
+
+ m_pageScaleFactor = scale;
+
+ if (document->renderer())
+ document->renderer()->setNeedsLayout(true);
+
+ document->recalcStyle(Node::Force);
+
+ if (FrameView* view = this->view()) {
+ if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
+ view->layout();
+ view->setScrollPosition(origin);
+ }
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/Frame.h b/Source/WebCore/page/Frame.h
new file mode 100644
index 0000000..4928742
--- /dev/null
+++ b/Source/WebCore/page/Frame.h
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ * 1999-2001 Lars Knoll <knoll@kde.org>
+ * 1999-2001 Antti Koivisto <koivisto@kde.org>
+ * 2000-2001 Simon Hausmann <hausmann@kde.org>
+ * 2000-2001 Dirk Mueller <mueller@kde.org>
+ * 2000 Stefan Schimanski <1Stein@gmx.de>
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef Frame_h
+#define Frame_h
+
+#include "AnimationController.h"
+#include "Document.h"
+#include "DragImage.h"
+#include "Editor.h"
+#include "EventHandler.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "SelectionController.h"
+#include "ScriptController.h"
+#include "UserScriptTypes.h"
+
+#if PLATFORM(WIN)
+#include "FrameWin.h"
+#endif
+
+#if ENABLE(TILED_BACKING_STORE)
+#include "TiledBackingStoreClient.h"
+#endif
+
+#if PLATFORM(MAC)
+#ifndef __OBJC__
+class NSArray;
+class NSMutableDictionary;
+class NSString;
+#endif
+#endif
+
+#if PLATFORM(WIN)
+typedef struct HBITMAP__* HBITMAP;
+#endif
+
+namespace WebCore {
+
+ class FrameView;
+ class HTMLTableCellElement;
+ class RegularExpression;
+ class RenderPart;
+ class TiledBackingStore;
+
+#if !ENABLE(TILED_BACKING_STORE)
+ class TiledBackingStoreClient { };
+#endif
+
+ class FrameDestructionObserver {
+ public:
+ virtual ~FrameDestructionObserver() { }
+
+ virtual void frameDestroyed() = 0;
+ };
+
+ class Frame : public RefCounted<Frame>, public TiledBackingStoreClient {
+ public:
+ static PassRefPtr<Frame> create(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*);
+
+ void init();
+ void setView(PassRefPtr<FrameView>);
+ void createView(const IntSize&, const Color&, bool, const IntSize&, bool,
+ ScrollbarMode = ScrollbarAuto, bool horizontalLock = false,
+ ScrollbarMode = ScrollbarAuto, bool verticalLock = false);
+
+ ~Frame();
+
+ void addDestructionObserver(FrameDestructionObserver*);
+ void removeDestructionObserver(FrameDestructionObserver*);
+
+ void detachFromPage();
+ void pageDestroyed();
+ void disconnectOwnerElement();
+
+ Page* page() const;
+ HTMLFrameOwnerElement* ownerElement() const;
+
+ Document* document() const;
+ FrameView* view() const;
+
+ Editor* editor() const;
+ EventHandler* eventHandler() const;
+ FrameLoader* loader() const;
+ NavigationScheduler* navigationScheduler() const;
+ SelectionController* selection() const;
+ FrameTree* tree() const;
+ AnimationController* animation() const;
+ ScriptController* script();
+
+ RenderView* contentRenderer() const; // Root of the render tree for the document contained in this frame.
+ RenderPart* ownerRenderer() const; // Renderer for the element that contains this frame.
+
+ void transferChildFrameToNewDocument();
+
+ // ======== All public functions below this point are candidates to move out of Frame into another class. ========
+
+ bool isDisconnected() const;
+ void setIsDisconnected(bool);
+ bool excludeFromTextSearch() const;
+ void setExcludeFromTextSearch(bool);
+
+ void injectUserScripts(UserScriptInjectionTime);
+
+ String layerTreeAsText() const;
+
+ // Unlike most accessors in this class, domWindow() always creates a new DOMWindow if m_domWindow is null.
+ // Callers that don't need a new DOMWindow to be created should use existingDOMWindow().
+ DOMWindow* domWindow() const;
+ DOMWindow* existingDOMWindow() { return m_domWindow.get(); }
+ void setDOMWindow(DOMWindow*);
+ void clearFormerDOMWindow(DOMWindow*);
+ void clearDOMWindow();
+
+ static Frame* frameForWidget(const Widget*);
+
+ Settings* settings() const; // can be NULL
+
+ enum AdjustViewSizeOrNot { DoNotAdjustViewSize, AdjustViewSize };
+ void setPrinting(bool printing, const FloatSize& pageSize, float maximumShrinkRatio, AdjustViewSizeOrNot);
+
+ bool inViewSourceMode() const;
+ void setInViewSourceMode(bool = true);
+
+ void keepAlive(); // Used to keep the frame alive when running a script that might destroy it.
+ static void cancelAllKeepAlive();
+
+ void setDocument(PassRefPtr<Document>);
+
+ void setPageZoomFactor(float factor);
+ float pageZoomFactor() const { return m_pageZoomFactor; }
+ void setTextZoomFactor(float factor);
+ float textZoomFactor() const { return m_textZoomFactor; }
+ void setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor);
+
+ void scalePage(float scale, const IntPoint& origin);
+ float pageScaleFactor() const { return m_pageScaleFactor; }
+
+#if ENABLE(ORIENTATION_EVENTS)
+ // Orientation is the interface orientation in degrees. Some examples are:
+ // 0 is straight up; -90 is when the device is rotated 90 clockwise;
+ // 90 is when rotated counter clockwise.
+ void sendOrientationChangeEvent(int orientation);
+ int orientation() const { return m_orientation; }
+#endif
+
+ void clearTimers();
+ static void clearTimers(FrameView*, Document*);
+
+ String documentTypeString() const;
+
+ String displayStringModifiedByEncoding(const String& str) const
+ {
+ return document() ? document()->displayStringModifiedByEncoding(str) : str;
+ }
+
+ DragImageRef nodeImage(Node*);
+ DragImageRef dragImageForSelection();
+
+ bool isContentEditable() const; // if true, everything in frame is editable
+
+ VisiblePosition visiblePositionForPoint(const IntPoint& framePoint);
+ Document* documentAtPoint(const IntPoint& windowPoint);
+
+ String searchForLabelsAboveCell(RegularExpression*, HTMLTableCellElement*, size_t* resultDistanceFromStartOfCell);
+ String searchForLabelsBeforeElement(const Vector<String>& labels, Element*, size_t* resultDistance, bool* resultIsInCellAbove);
+ String matchLabelsAgainstElement(const Vector<String>& labels, Element*);
+
+#if PLATFORM(MAC)
+ NSString* searchForLabelsBeforeElement(NSArray* labels, Element*, size_t* resultDistance, bool* resultIsInCellAbove);
+ NSString* matchLabelsAgainstElement(NSArray* labels, Element*);
+
+ NSImage* selectionImage(bool forceBlackText = false) const;
+ NSImage* snapshotDragImage(Node*, NSRect* imageRect, NSRect* elementRect) const;
+ NSImage* imageFromRect(NSRect) const;
+#endif
+
+ // ========
+
+ private:
+ Frame(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*);
+
+ void injectUserScriptsForWorld(DOMWrapperWorld*, const UserScriptVector&, UserScriptInjectionTime);
+ void lifeSupportTimerFired(Timer<Frame>*);
+
+ HashSet<FrameDestructionObserver*> m_destructionObservers;
+
+ Page* m_page;
+ mutable FrameTree m_treeNode;
+ mutable FrameLoader m_loader;
+ mutable NavigationScheduler m_navigationScheduler;
+
+ mutable RefPtr<DOMWindow> m_domWindow;
+ HashSet<DOMWindow*> m_liveFormerWindows;
+
+ HTMLFrameOwnerElement* m_ownerElement;
+ RefPtr<FrameView> m_view;
+ RefPtr<Document> m_doc;
+
+ ScriptController m_script;
+
+ mutable Editor m_editor;
+ mutable SelectionController m_selectionController;
+ mutable EventHandler m_eventHandler;
+ mutable AnimationController m_animationController;
+
+ Timer<Frame> m_lifeSupportTimer;
+
+ float m_pageZoomFactor;
+ float m_textZoomFactor;
+
+ float m_pageScaleFactor;
+
+#if ENABLE(ORIENTATION_EVENTS)
+ int m_orientation;
+#endif
+
+ bool m_inViewSourceMode;
+ bool m_isDisconnected;
+ bool m_excludeFromTextSearch;
+
+#if ENABLE(TILED_BACKING_STORE)
+ // FIXME: The tiled backing store belongs in FrameView, not Frame.
+
+ public:
+ TiledBackingStore* tiledBackingStore() const { return m_tiledBackingStore.get(); }
+ void setTiledBackingStoreEnabled(bool);
+
+ private:
+ // TiledBackingStoreClient interface
+ virtual void tiledBackingStorePaintBegin();
+ virtual void tiledBackingStorePaint(GraphicsContext*, const IntRect&);
+ virtual void tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea);
+ virtual IntRect tiledBackingStoreContentsRect();
+ virtual IntRect tiledBackingStoreVisibleRect();
+ virtual Color tiledBackingStoreBackgroundColor() const;
+
+ OwnPtr<TiledBackingStore> m_tiledBackingStore;
+#endif
+ };
+
+ inline void Frame::init()
+ {
+ m_loader.init();
+ }
+
+ inline FrameLoader* Frame::loader() const
+ {
+ return &m_loader;
+ }
+
+ inline NavigationScheduler* Frame::navigationScheduler() const
+ {
+ return &m_navigationScheduler;
+ }
+
+ inline FrameView* Frame::view() const
+ {
+ return m_view.get();
+ }
+
+ inline ScriptController* Frame::script()
+ {
+ return &m_script;
+ }
+
+ inline Document* Frame::document() const
+ {
+ return m_doc.get();
+ }
+
+ inline SelectionController* Frame::selection() const
+ {
+ return &m_selectionController;
+ }
+
+ inline Editor* Frame::editor() const
+ {
+ return &m_editor;
+ }
+
+ inline AnimationController* Frame::animation() const
+ {
+ return &m_animationController;
+ }
+
+ inline HTMLFrameOwnerElement* Frame::ownerElement() const
+ {
+ return m_ownerElement;
+ }
+
+ inline bool Frame::isDisconnected() const
+ {
+ return m_isDisconnected;
+ }
+
+ inline void Frame::setIsDisconnected(bool isDisconnected)
+ {
+ m_isDisconnected = isDisconnected;
+ }
+
+ inline bool Frame::excludeFromTextSearch() const
+ {
+ return m_excludeFromTextSearch;
+ }
+
+ inline void Frame::setExcludeFromTextSearch(bool exclude)
+ {
+ m_excludeFromTextSearch = exclude;
+ }
+
+ inline bool Frame::inViewSourceMode() const
+ {
+ return m_inViewSourceMode;
+ }
+
+ inline void Frame::setInViewSourceMode(bool mode)
+ {
+ m_inViewSourceMode = mode;
+ }
+
+ inline FrameTree* Frame::tree() const
+ {
+ return &m_treeNode;
+ }
+
+ inline Page* Frame::page() const
+ {
+ return m_page;
+ }
+
+ inline void Frame::detachFromPage()
+ {
+ m_page = 0;
+ }
+
+ inline EventHandler* Frame::eventHandler() const
+ {
+ return &m_eventHandler;
+ }
+
+} // namespace WebCore
+
+#endif // Frame_h
diff --git a/Source/WebCore/page/FrameLoadRequest.h b/Source/WebCore/page/FrameLoadRequest.h
new file mode 100644
index 0000000..aa7e4a8
--- /dev/null
+++ b/Source/WebCore/page/FrameLoadRequest.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2003, 2006, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FrameLoadRequest_h
+#define FrameLoadRequest_h
+
+#include "ResourceRequest.h"
+#include "SecurityOrigin.h"
+
+namespace WebCore {
+
+ struct FrameLoadRequest {
+ public:
+ explicit FrameLoadRequest(PassRefPtr<SecurityOrigin> requester)
+ : m_requester(requester)
+ {
+ }
+
+ FrameLoadRequest(PassRefPtr<SecurityOrigin> requester, const ResourceRequest& resourceRequest)
+ : m_requester(requester)
+ , m_resourceRequest(resourceRequest)
+ {
+ }
+
+ FrameLoadRequest(PassRefPtr<SecurityOrigin> requester, const ResourceRequest& resourceRequest, const String& frameName)
+ : m_requester(requester)
+ , m_resourceRequest(resourceRequest)
+ , m_frameName(frameName)
+ {
+ }
+
+ bool isEmpty() const { return m_resourceRequest.isEmpty(); }
+
+ const SecurityOrigin* requester() const { return m_requester.get(); }
+
+ ResourceRequest& resourceRequest() { return m_resourceRequest; }
+ const ResourceRequest& resourceRequest() const { return m_resourceRequest; }
+
+ const String& frameName() const { return m_frameName; }
+ void setFrameName(const String& frameName) { m_frameName = frameName; }
+
+ private:
+ RefPtr<SecurityOrigin> m_requester;
+ ResourceRequest m_resourceRequest;
+ String m_frameName;
+ };
+
+}
+
+#endif // FrameLoadRequest_h
+
diff --git a/Source/WebCore/page/FrameTree.cpp b/Source/WebCore/page/FrameTree.cpp
new file mode 100644
index 0000000..f3f32ec
--- /dev/null
+++ b/Source/WebCore/page/FrameTree.cpp
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "FrameTree.h"
+
+#include "Frame.h"
+#include "FrameView.h"
+#include "Page.h"
+#include "PageGroup.h"
+#include <stdarg.h>
+#include <wtf/StringExtras.h>
+#include <wtf/Vector.h>
+
+using std::swap;
+
+namespace WebCore {
+
+FrameTree::~FrameTree()
+{
+ for (Frame* child = firstChild(); child; child = child->tree()->nextSibling())
+ child->setView(0);
+}
+
+void FrameTree::setName(const AtomicString& name)
+{
+ m_name = name;
+ if (!parent()) {
+ m_uniqueName = name;
+ return;
+ }
+ m_uniqueName = AtomicString(); // Remove our old frame name so it's not considered in uniqueChildName.
+ m_uniqueName = parent()->tree()->uniqueChildName(name);
+}
+
+void FrameTree::clearName()
+{
+ m_name = AtomicString();
+ m_uniqueName = AtomicString();
+}
+
+Frame* FrameTree::parent(bool checkForDisconnectedFrame) const
+{
+ if (checkForDisconnectedFrame && m_thisFrame->isDisconnected())
+ return 0;
+ return m_parent;
+}
+
+bool FrameTree::transferChild(PassRefPtr<Frame> child)
+{
+ Frame* oldParent = child->tree()->parent();
+ if (oldParent == m_thisFrame)
+ return false; // |child| is already a child of m_thisFrame.
+
+ if (oldParent)
+ oldParent->tree()->removeChild(child.get());
+
+ ASSERT(child->page() == m_thisFrame->page());
+ child->tree()->m_parent = m_thisFrame;
+
+ // We need to ensure that the child still has a unique frame name with respect to its new parent.
+ child->tree()->setName(child->tree()->m_name);
+
+ actuallyAppendChild(child); // Note, on return |child| is null.
+ return true;
+}
+
+void FrameTree::appendChild(PassRefPtr<Frame> child)
+{
+ ASSERT(child->page() == m_thisFrame->page());
+ child->tree()->m_parent = m_thisFrame;
+ actuallyAppendChild(child); // Note, on return |child| is null.
+}
+
+void FrameTree::actuallyAppendChild(PassRefPtr<Frame> child)
+{
+ ASSERT(child->tree()->m_parent == m_thisFrame);
+ Frame* oldLast = m_lastChild;
+ m_lastChild = child.get();
+
+ if (oldLast) {
+ child->tree()->m_previousSibling = oldLast;
+ oldLast->tree()->m_nextSibling = child;
+ } else
+ m_firstChild = child;
+
+ m_childCount++;
+
+ ASSERT(!m_lastChild->tree()->m_nextSibling);
+}
+
+void FrameTree::removeChild(Frame* child)
+{
+ child->tree()->m_parent = 0;
+
+ // Slightly tricky way to prevent deleting the child until we are done with it, w/o
+ // extra refs. These swaps leave the child in a circular list by itself. Clearing its
+ // previous and next will then finally deref it.
+
+ RefPtr<Frame>& newLocationForNext = m_firstChild == child ? m_firstChild : child->tree()->m_previousSibling->tree()->m_nextSibling;
+ Frame*& newLocationForPrevious = m_lastChild == child ? m_lastChild : child->tree()->m_nextSibling->tree()->m_previousSibling;
+ swap(newLocationForNext, child->tree()->m_nextSibling);
+ // For some inexplicable reason, the following line does not compile without the explicit std:: namespace
+ std::swap(newLocationForPrevious, child->tree()->m_previousSibling);
+
+ child->tree()->m_previousSibling = 0;
+ child->tree()->m_nextSibling = 0;
+
+ m_childCount--;
+}
+
+AtomicString FrameTree::uniqueChildName(const AtomicString& requestedName) const
+{
+ if (!requestedName.isEmpty() && !child(requestedName) && requestedName != "_blank")
+ return requestedName;
+
+ // Create a repeatable name for a child about to be added to us. The name must be
+ // unique within the frame tree. The string we generate includes a "path" of names
+ // from the root frame down to us. For this path to be unique, each set of siblings must
+ // contribute a unique name to the path, which can't collide with any HTML-assigned names.
+ // We generate this path component by index in the child list along with an unlikely
+ // frame name that can't be set in HTML because it collides with comment syntax.
+
+ const char framePathPrefix[] = "<!--framePath ";
+ const int framePathPrefixLength = 14;
+ const int framePathSuffixLength = 3;
+
+ // Find the nearest parent that has a frame with a path in it.
+ Vector<Frame*, 16> chain;
+ Frame* frame;
+ for (frame = m_thisFrame; frame; frame = frame->tree()->parent()) {
+ if (frame->tree()->uniqueName().startsWith(framePathPrefix))
+ break;
+ chain.append(frame);
+ }
+ String name;
+ name += framePathPrefix;
+ if (frame)
+ name += frame->tree()->uniqueName().string().substring(framePathPrefixLength,
+ frame->tree()->uniqueName().length() - framePathPrefixLength - framePathSuffixLength);
+ for (int i = chain.size() - 1; i >= 0; --i) {
+ frame = chain[i];
+ name += "/";
+ name += frame->tree()->uniqueName();
+ }
+
+ // Suffix buffer has more than enough space for:
+ // 10 characters before the number
+ // a number (20 digits for the largest 64-bit integer)
+ // 6 characters after the number
+ // trailing null byte
+ // But we still use snprintf just to be extra-safe.
+ char suffix[40];
+ snprintf(suffix, sizeof(suffix), "/<!--frame%u-->-->", childCount());
+
+ name += suffix;
+
+ return AtomicString(name);
+}
+
+Frame* FrameTree::child(unsigned index) const
+{
+ Frame* result = firstChild();
+ for (unsigned i = 0; result && i != index; ++i)
+ result = result->tree()->nextSibling();
+ return result;
+}
+
+Frame* FrameTree::child(const AtomicString& name) const
+{
+ for (Frame* child = firstChild(); child; child = child->tree()->nextSibling())
+ if (child->tree()->uniqueName() == name)
+ return child;
+ return 0;
+}
+
+Frame* FrameTree::find(const AtomicString& name) const
+{
+ if (name == "_self" || name == "_current" || name.isEmpty())
+ return m_thisFrame;
+
+ if (name == "_top")
+ return top();
+
+ if (name == "_parent")
+ return parent() ? parent() : m_thisFrame;
+
+ // Since "_blank" should never be any frame's name, the following just amounts to an optimization.
+ if (name == "_blank")
+ return 0;
+
+ // Search subtree starting with this frame first.
+ for (Frame* frame = m_thisFrame; frame; frame = frame->tree()->traverseNext(m_thisFrame))
+ if (frame->tree()->uniqueName() == name)
+ return frame;
+
+ // Search the entire tree for this page next.
+ Page* page = m_thisFrame->page();
+
+ // The frame could have been detached from the page, so check it.
+ if (!page)
+ return 0;
+
+ for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
+ if (frame->tree()->uniqueName() == name)
+ return frame;
+
+ // Search the entire tree of each of the other pages in this namespace.
+ // FIXME: Is random order OK?
+ const HashSet<Page*>& pages = page->group().pages();
+ HashSet<Page*>::const_iterator end = pages.end();
+ for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) {
+ Page* otherPage = *it;
+ if (otherPage != page) {
+ for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (frame->tree()->uniqueName() == name)
+ return frame;
+ }
+ }
+ }
+
+ return 0;
+}
+
+bool FrameTree::isDescendantOf(const Frame* ancestor) const
+{
+ if (!ancestor)
+ return false;
+
+ if (m_thisFrame->page() != ancestor->page())
+ return false;
+
+ for (Frame* frame = m_thisFrame; frame; frame = frame->tree()->parent())
+ if (frame == ancestor)
+ return true;
+ return false;
+}
+
+Frame* FrameTree::traverseNext(const Frame* stayWithin) const
+{
+ Frame* child = firstChild();
+ if (child) {
+ ASSERT(!stayWithin || child->tree()->isDescendantOf(stayWithin));
+ return child;
+ }
+
+ if (m_thisFrame == stayWithin)
+ return 0;
+
+ Frame* sibling = nextSibling();
+ if (sibling) {
+ ASSERT(!stayWithin || sibling->tree()->isDescendantOf(stayWithin));
+ return sibling;
+ }
+
+ Frame* frame = m_thisFrame;
+ while (!sibling && (!stayWithin || frame->tree()->parent() != stayWithin)) {
+ frame = frame->tree()->parent();
+ if (!frame)
+ return 0;
+ sibling = frame->tree()->nextSibling();
+ }
+
+ if (frame) {
+ ASSERT(!stayWithin || !sibling || sibling->tree()->isDescendantOf(stayWithin));
+ return sibling;
+ }
+
+ return 0;
+}
+
+Frame* FrameTree::traverseNextWithWrap(bool wrap) const
+{
+ if (Frame* result = traverseNext())
+ return result;
+
+ if (wrap)
+ return m_thisFrame->page()->mainFrame();
+
+ return 0;
+}
+
+Frame* FrameTree::traversePreviousWithWrap(bool wrap) const
+{
+ // FIXME: besides the wrap feature, this is just the traversePreviousNode algorithm
+
+ if (Frame* prevSibling = previousSibling())
+ return prevSibling->tree()->deepLastChild();
+ if (Frame* parentFrame = parent())
+ return parentFrame;
+
+ // no siblings, no parent, self==top
+ if (wrap)
+ return deepLastChild();
+
+ // top view is always the last one in this ordering, so prev is nil without wrap
+ return 0;
+}
+
+Frame* FrameTree::deepLastChild() const
+{
+ Frame* result = m_thisFrame;
+ for (Frame* last = lastChild(); last; last = last->tree()->lastChild())
+ result = last;
+
+ return result;
+}
+
+Frame* FrameTree::top(bool checkForDisconnectedFrame) const
+{
+ Frame* frame = m_thisFrame;
+ for (Frame* parent = m_thisFrame; parent; parent = parent->tree()->parent()) {
+ frame = parent;
+ if (checkForDisconnectedFrame && frame->isDisconnected())
+ return frame;
+ }
+ return frame;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/FrameTree.h b/Source/WebCore/page/FrameTree.h
new file mode 100644
index 0000000..94b8d16
--- /dev/null
+++ b/Source/WebCore/page/FrameTree.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef FrameTree_h
+#define FrameTree_h
+
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+ class Frame;
+
+ class FrameTree : public Noncopyable {
+ public:
+ FrameTree(Frame* thisFrame, Frame* parentFrame)
+ : m_thisFrame(thisFrame)
+ , m_parent(parentFrame)
+ , m_previousSibling(0)
+ , m_lastChild(0)
+ , m_childCount(0)
+ {
+ }
+ ~FrameTree();
+
+ const AtomicString& name() const { return m_name; }
+ const AtomicString& uniqueName() const { return m_uniqueName; }
+ void setName(const AtomicString&);
+ void clearName();
+ Frame* parent(bool checkForDisconnectedFrame = false) const;
+ void setParent(Frame* parent) { m_parent = parent; }
+
+ Frame* nextSibling() const { return m_nextSibling.get(); }
+ Frame* previousSibling() const { return m_previousSibling; }
+ Frame* firstChild() const { return m_firstChild.get(); }
+ Frame* lastChild() const { return m_lastChild; }
+ unsigned childCount() const { return m_childCount; }
+
+ bool isDescendantOf(const Frame* ancestor) const;
+ Frame* traverseNext(const Frame* stayWithin = 0) const;
+ Frame* traverseNextWithWrap(bool) const;
+ Frame* traversePreviousWithWrap(bool) const;
+
+ void appendChild(PassRefPtr<Frame>);
+ bool transferChild(PassRefPtr<Frame>);
+ void detachFromParent() { m_parent = 0; }
+ void removeChild(Frame*);
+
+ Frame* child(unsigned index) const;
+ Frame* child(const AtomicString& name) const;
+ Frame* find(const AtomicString& name) const;
+
+ AtomicString uniqueChildName(const AtomicString& requestedName) const;
+
+ Frame* top(bool checkForDisconnectedFrame = false) const;
+
+ private:
+ Frame* deepLastChild() const;
+ void actuallyAppendChild(PassRefPtr<Frame>);
+
+ Frame* m_thisFrame;
+
+ Frame* m_parent;
+ AtomicString m_name; // The actual frame name (may be empty).
+ AtomicString m_uniqueName;
+
+ // FIXME: use ListRefPtr?
+ RefPtr<Frame> m_nextSibling;
+ Frame* m_previousSibling;
+ RefPtr<Frame> m_firstChild;
+ Frame* m_lastChild;
+ unsigned m_childCount;
+ };
+
+} // namespace WebCore
+
+#endif // FrameTree_h
diff --git a/Source/WebCore/page/FrameView.cpp b/Source/WebCore/page/FrameView.cpp
new file mode 100644
index 0000000..926d943
--- /dev/null
+++ b/Source/WebCore/page/FrameView.cpp
@@ -0,0 +1,2607 @@
+/*
+ * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ * 1999 Lars Knoll <knoll@kde.org>
+ * 1999 Antti Koivisto <koivisto@kde.org>
+ * 2000 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "FrameView.h"
+
+#include "AXObjectCache.h"
+#include "CSSStyleSelector.h"
+#include "CachedResourceLoader.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "DocumentMarkerController.h"
+#include "EventHandler.h"
+#include "FloatRect.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "FrameTree.h"
+#include "GraphicsContext.h"
+#include "HTMLDocument.h"
+#include "HTMLFrameElement.h"
+#include "HTMLFrameSetElement.h"
+#include "HTMLNames.h"
+#include "HTMLPlugInImageElement.h"
+#include "InspectorInstrumentation.h"
+#include "OverflowEvent.h"
+#include "RenderEmbeddedObject.h"
+#include "RenderFullScreen.h"
+#include "RenderLayer.h"
+#include "RenderPart.h"
+#include "RenderScrollbar.h"
+#include "RenderScrollbarPart.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include "Settings.h"
+#include "TextResourceDecoder.h"
+#include <wtf/CurrentTime.h>
+
+#ifdef ANDROID_INSTRUMENT
+#include "FrameTree.h"
+#include "TimeCounter.h"
+#endif
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "RenderLayerCompositor.h"
+#endif
+
+#if ENABLE(SVG)
+#include "SVGDocument.h"
+#include "SVGLocatable.h"
+#include "SVGNames.h"
+#include "SVGPreserveAspectRatio.h"
+#include "SVGSVGElement.h"
+#include "SVGViewElement.h"
+#include "SVGViewSpec.h"
+#endif
+
+#if ENABLE(TILED_BACKING_STORE)
+#include "TiledBackingStore.h"
+#endif
+
+#if PLATFORM(ANDROID)
+#include "WebCoreFrameBridge.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+double FrameView::sCurrentPaintTimeStamp = 0.0;
+
+// REPAINT_THROTTLING now chooses default values for throttling parameters.
+// Should be removed when applications start using runtime configuration.
+#if ENABLE(REPAINT_THROTTLING)
+// Normal delay
+double FrameView::s_deferredRepaintDelay = 0.025;
+// Negative value would mean that first few repaints happen without a delay
+double FrameView::s_initialDeferredRepaintDelayDuringLoading = 0;
+// The delay grows on each repaint to this maximum value
+double FrameView::s_maxDeferredRepaintDelayDuringLoading = 2.5;
+// On each repaint the delay increses by this amount
+double FrameView::s_deferredRepaintDelayIncrementDuringLoading = 0.5;
+#else
+// FIXME: Repaint throttling could be good to have on all platform.
+// The balance between CPU use and repaint frequency will need some tuning for desktop.
+// More hooks may be needed to reset the delay on things like GIF and CSS animations.
+double FrameView::s_deferredRepaintDelay = 0;
+double FrameView::s_initialDeferredRepaintDelayDuringLoading = 0;
+double FrameView::s_maxDeferredRepaintDelayDuringLoading = 0;
+double FrameView::s_deferredRepaintDelayIncrementDuringLoading = 0;
+#endif
+
+// The maximum number of updateWidgets iterations that should be done before returning.
+static const unsigned maxUpdateWidgetsIterations = 2;
+
+struct ScheduledEvent : Noncopyable {
+ RefPtr<Event> m_event;
+ RefPtr<Node> m_eventTarget;
+};
+
+FrameView::FrameView(Frame* frame)
+ : m_frame(frame)
+ , m_canHaveScrollbars(true)
+ , m_slowRepaintObjectCount(0)
+ , m_fixedObjectCount(0)
+ , m_layoutTimer(this, &FrameView::layoutTimerFired)
+ , m_layoutRoot(0)
+ , m_hasPendingPostLayoutTasks(false)
+ , m_inSynchronousPostLayout(false)
+ , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
+ , m_isTransparent(false)
+ , m_baseBackgroundColor(Color::white)
+ , m_mediaType("screen")
+ , m_enqueueEvents(0)
+ , m_overflowStatusDirty(true)
+ , m_viewportRenderer(0)
+ , m_wasScrolledByUser(false)
+ , m_inProgrammaticScroll(false)
+ , m_deferredRepaintTimer(this, &FrameView::deferredRepaintTimerFired)
+ , m_shouldUpdateWhileOffscreen(true)
+ , m_deferSetNeedsLayouts(0)
+ , m_setNeedsLayoutWasDeferred(false)
+ , m_scrollCorner(0)
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+ , m_hasOverflowScroll(false)
+#endif
+{
+ init();
+}
+
+PassRefPtr<FrameView> FrameView::create(Frame* frame)
+{
+ RefPtr<FrameView> view = adoptRef(new FrameView(frame));
+ view->show();
+ return view.release();
+}
+
+PassRefPtr<FrameView> FrameView::create(Frame* frame, const IntSize& initialSize)
+{
+ RefPtr<FrameView> view = adoptRef(new FrameView(frame));
+ view->Widget::setFrameRect(IntRect(view->pos(), initialSize));
+ view->show();
+ return view.release();
+}
+
+FrameView::~FrameView()
+{
+ if (m_hasPendingPostLayoutTasks) {
+ m_postLayoutTasksTimer.stop();
+ m_scheduledEvents.clear();
+ m_enqueueEvents = 0;
+ }
+
+ if (AXObjectCache::accessibilityEnabled() && axObjectCache())
+ axObjectCache()->remove(this);
+
+ resetScrollbars();
+
+ // Custom scrollbars should already be destroyed at this point
+ ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
+ ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
+
+ setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
+ setHasVerticalScrollbar(false);
+
+ ASSERT(!m_scrollCorner);
+ ASSERT(m_scheduledEvents.isEmpty());
+ ASSERT(!m_enqueueEvents);
+
+ if (m_frame) {
+ ASSERT(m_frame->view() != this || !m_frame->contentRenderer());
+ RenderPart* renderer = m_frame->ownerRenderer();
+ if (renderer && renderer->widget() == this)
+ renderer->setWidget(0);
+ }
+}
+
+void FrameView::reset()
+{
+ m_useSlowRepaints = false;
+ m_isOverlapped = false;
+ m_contentIsOpaque = false;
+ m_borderX = 30;
+ m_borderY = 30;
+ m_layoutTimer.stop();
+ m_layoutRoot = 0;
+ m_delayedLayout = false;
+ m_doFullRepaint = true;
+ m_layoutSchedulingEnabled = true;
+ m_inLayout = false;
+ m_inSynchronousPostLayout = false;
+ m_hasPendingPostLayoutTasks = false;
+ m_layoutCount = 0;
+ m_nestedLayoutCount = 0;
+ m_postLayoutTasksTimer.stop();
+ m_firstLayout = true;
+ m_firstLayoutCallbackPending = false;
+ m_wasScrolledByUser = false;
+ m_lastLayoutSize = IntSize();
+ m_lastZoomFactor = 1.0f;
+ m_deferringRepaints = 0;
+ m_repaintCount = 0;
+ m_repaintRects.clear();
+ m_deferredRepaintDelay = s_initialDeferredRepaintDelayDuringLoading;
+ m_deferredRepaintTimer.stop();
+ m_lastPaintTime = 0;
+ m_paintBehavior = PaintBehaviorNormal;
+ m_isPainting = false;
+ m_isVisuallyNonEmpty = false;
+ m_firstVisuallyNonEmptyLayoutCallbackPending = true;
+ m_maintainScrollPositionAnchor = 0;
+}
+
+bool FrameView::isFrameView() const
+{
+ return true;
+}
+
+void FrameView::clearFrame()
+{
+ m_frame = 0;
+}
+
+void FrameView::resetScrollbars()
+{
+ // Reset the document's scrollbars back to our defaults before we yield the floor.
+ m_firstLayout = true;
+ setScrollbarsSuppressed(true);
+ if (m_canHaveScrollbars)
+ setScrollbarModes(ScrollbarAuto, ScrollbarAuto);
+ else
+ setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
+ setScrollbarsSuppressed(false);
+}
+
+void FrameView::init()
+{
+ reset();
+
+ m_margins = IntSize(-1, -1); // undefined
+ m_size = IntSize();
+
+ // Propagate the marginwidth/height and scrolling modes to the view.
+ Element* ownerElement = m_frame && m_frame->document() ? m_frame->document()->ownerElement() : 0;
+ if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
+ HTMLFrameElement* frameElt = static_cast<HTMLFrameElement*>(ownerElement);
+ if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
+ setCanHaveScrollbars(false);
+ int marginWidth = frameElt->marginWidth();
+ int marginHeight = frameElt->marginHeight();
+ if (marginWidth != -1)
+ setMarginWidth(marginWidth);
+ if (marginHeight != -1)
+ setMarginHeight(marginHeight);
+ }
+}
+
+void FrameView::detachCustomScrollbars()
+{
+ if (!m_frame)
+ return;
+
+ Scrollbar* horizontalBar = horizontalScrollbar();
+ if (horizontalBar && horizontalBar->isCustomScrollbar())
+ setHasHorizontalScrollbar(false);
+
+ Scrollbar* verticalBar = verticalScrollbar();
+ if (verticalBar && verticalBar->isCustomScrollbar())
+ setHasVerticalScrollbar(false);
+
+ if (m_scrollCorner) {
+ m_scrollCorner->destroy();
+ m_scrollCorner = 0;
+ }
+}
+
+void FrameView::clear()
+{
+ setCanBlitOnScroll(true);
+
+ reset();
+
+ if (m_frame) {
+ if (RenderPart* renderer = m_frame->ownerRenderer())
+ renderer->viewCleared();
+ }
+
+ setScrollbarsSuppressed(true);
+}
+
+bool FrameView::didFirstLayout() const
+{
+ return !m_firstLayout;
+}
+
+void FrameView::invalidateRect(const IntRect& rect)
+{
+ if (!parent()) {
+ if (hostWindow() && shouldUpdate())
+ hostWindow()->invalidateContentsAndWindow(rect, false /*immediate*/);
+ return;
+ }
+
+ if (!m_frame)
+ return;
+
+ RenderPart* renderer = m_frame->ownerRenderer();
+ if (!renderer)
+ return;
+
+ IntRect repaintRect = rect;
+ repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(),
+ renderer->borderTop() + renderer->paddingTop());
+ renderer->repaintRectangle(repaintRect);
+}
+
+void FrameView::setFrameRect(const IntRect& newRect)
+{
+ IntRect oldRect = frameRect();
+ if (newRect == oldRect)
+ return;
+
+ ScrollView::setFrameRect(newRect);
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (RenderView* root = m_frame->contentRenderer()) {
+ if (root->usesCompositing())
+ root->compositor()->frameViewDidChangeSize();
+ }
+#endif
+}
+
+void FrameView::setMarginWidth(int w)
+{
+ // make it update the rendering area when set
+ m_margins.setWidth(w);
+}
+
+void FrameView::setMarginHeight(int h)
+{
+ // make it update the rendering area when set
+ m_margins.setHeight(h);
+}
+
+bool FrameView::avoidScrollbarCreation() const
+{
+ ASSERT(m_frame);
+
+ // with frame flattening no subframe can have scrollbars
+ // but we also cannot turn scrollbars of as we determine
+ // our flattening policy using that.
+
+ if (!m_frame->ownerElement())
+ return false;
+
+ if (!m_frame->settings() || m_frame->settings()->frameFlatteningEnabled())
+ return true;
+
+ return false;
+}
+
+void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
+{
+ m_canHaveScrollbars = canHaveScrollbars;
+ ScrollView::setCanHaveScrollbars(canHaveScrollbars);
+}
+
+void FrameView::updateCanHaveScrollbars()
+{
+ ScrollbarMode hMode;
+ ScrollbarMode vMode;
+ scrollbarModes(hMode, vMode);
+ if (hMode == ScrollbarAlwaysOff && vMode == ScrollbarAlwaysOff)
+ setCanHaveScrollbars(false);
+ else
+ setCanHaveScrollbars(true);
+}
+
+PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
+{
+ // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
+ Document* doc = m_frame->document();
+
+ // Try the <body> element first as a scrollbar source.
+ Element* body = doc ? doc->body() : 0;
+ if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(SCROLLBAR))
+ return RenderScrollbar::createCustomScrollbar(this, orientation, body->renderer()->enclosingBox());
+
+ // If the <body> didn't have a custom style, then the root element might.
+ Element* docElement = doc ? doc->documentElement() : 0;
+ if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(SCROLLBAR))
+ return RenderScrollbar::createCustomScrollbar(this, orientation, docElement->renderBox());
+
+ // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
+ RenderPart* frameRenderer = m_frame->ownerRenderer();
+ if (frameRenderer && frameRenderer->style()->hasPseudoStyle(SCROLLBAR))
+ return RenderScrollbar::createCustomScrollbar(this, orientation, 0, m_frame.get());
+
+ // Nobody set a custom style, so we just use a native scrollbar.
+ return ScrollView::createScrollbar(orientation);
+}
+
+void FrameView::setContentsSize(const IntSize& size)
+{
+ if (size == contentsSize())
+ return;
+
+ m_deferSetNeedsLayouts++;
+
+ ScrollView::setContentsSize(size);
+
+ Page* page = frame() ? frame()->page() : 0;
+ if (!page)
+ return;
+
+ page->chrome()->contentsSizeChanged(frame(), size); //notify only
+
+ m_deferSetNeedsLayouts--;
+
+ if (!m_deferSetNeedsLayouts)
+ m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen.
+}
+
+void FrameView::adjustViewSize()
+{
+ ASSERT(m_frame->view() == this);
+ RenderView* root = m_frame->contentRenderer();
+ if (!root)
+ return;
+
+ IntSize size = IntSize(root->docWidth(), root->docHeight());
+
+ ScrollView::setScrollOrigin(IntPoint(-root->docLeft(), -root->docTop()), size == contentsSize());
+
+ setContentsSize(size);
+}
+
+void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
+{
+ // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
+ // overflow:hidden and overflow:scroll on <body> as applying to the document's
+ // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
+ // use the root element.
+ switch (o->style()->overflowX()) {
+ case OHIDDEN:
+ hMode = ScrollbarAlwaysOff;
+ break;
+ case OSCROLL:
+ hMode = ScrollbarAlwaysOn;
+ break;
+ case OAUTO:
+ hMode = ScrollbarAuto;
+ break;
+ default:
+ // Don't set it at all.
+ ;
+ }
+
+ switch (o->style()->overflowY()) {
+ case OHIDDEN:
+ vMode = ScrollbarAlwaysOff;
+ break;
+ case OSCROLL:
+ vMode = ScrollbarAlwaysOn;
+ break;
+ case OAUTO:
+ vMode = ScrollbarAuto;
+ break;
+ default:
+ // Don't set it at all.
+ ;
+ }
+
+ m_viewportRenderer = o;
+}
+
+void FrameView::calculateScrollbarModesForLayout(ScrollbarMode& hMode, ScrollbarMode& vMode)
+{
+ const HTMLFrameOwnerElement* owner = m_frame->ownerElement();
+ if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
+ hMode = ScrollbarAlwaysOff;
+ vMode = ScrollbarAlwaysOff;
+ return;
+ }
+
+ if (m_canHaveScrollbars) {
+ hMode = ScrollbarAuto;
+ vMode = ScrollbarAuto;
+ } else {
+ hMode = ScrollbarAlwaysOff;
+ vMode = ScrollbarAlwaysOff;
+ }
+
+ if (!m_layoutRoot) {
+ Document* document = m_frame->document();
+ Node* documentElement = document->documentElement();
+ RenderObject* rootRenderer = documentElement ? documentElement->renderer() : 0;
+ Node* body = document->body();
+ if (body && body->renderer()) {
+ if (body->hasTagName(framesetTag) && m_frame->settings() && !m_frame->settings()->frameFlatteningEnabled()) {
+ vMode = ScrollbarAlwaysOff;
+ hMode = ScrollbarAlwaysOff;
+ } else if (body->hasTagName(bodyTag)) {
+ // It's sufficient to just check the X overflow,
+ // since it's illegal to have visible in only one direction.
+ RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer;
+ applyOverflowToViewport(o, hMode, vMode);
+ }
+ } else if (rootRenderer) {
+#if ENABLE(SVG)
+ if (!documentElement->isSVGElement())
+ applyOverflowToViewport(rootRenderer, hMode, vMode);
+#else
+ applyOverflowToViewport(rootRenderer, hMode, vMode);
+#endif
+ }
+ }
+}
+
+#if ENABLE(FULLSCREEN_API) && USE(ACCELERATED_COMPOSITING)
+static bool isDocumentRunningFullScreenAnimation(Document* document)
+{
+ return document->webkitIsFullScreen() && document->fullScreenRenderer() && document->fullScreenRenderer()->isAnimating();
+}
+#endif
+
+#if USE(ACCELERATED_COMPOSITING)
+void FrameView::updateCompositingLayers()
+{
+ RenderView* view = m_frame->contentRenderer();
+ if (!view)
+ return;
+
+ // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
+ view->compositor()->cacheAcceleratedCompositingFlags();
+ view->compositor()->updateCompositingLayers(CompositingUpdateAfterLayoutOrStyleChange);
+
+#if ENABLE(FULLSCREEN_API)
+ Document* document = m_frame->document();
+ if (isDocumentRunningFullScreenAnimation(document))
+ view->compositor()->updateCompositingLayers(CompositingUpdateAfterLayoutOrStyleChange, document->fullScreenRenderer()->layer());
+#endif
+}
+
+void FrameView::setNeedsOneShotDrawingSynchronization()
+{
+ Page* page = frame() ? frame()->page() : 0;
+ if (page)
+ page->chrome()->client()->setNeedsOneShotDrawingSynchronization();
+}
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+bool FrameView::hasCompositedContent() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (RenderView* view = m_frame->contentRenderer())
+ return view->compositor()->inCompositingMode();
+#endif
+ return false;
+}
+
+bool FrameView::hasCompositedContentIncludingDescendants() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ for (Frame* frame = m_frame.get(); frame; frame = frame->tree()->traverseNext(m_frame.get())) {
+ RenderView* renderView = frame->contentRenderer();
+ RenderLayerCompositor* compositor = renderView ? renderView->compositor() : 0;
+ if (compositor) {
+ if (compositor->inCompositingMode())
+ return true;
+
+ if (!RenderLayerCompositor::allowsIndependentlyCompositedIFrames(this))
+ break;
+ }
+ }
+#endif
+ return false;
+}
+
+bool FrameView::hasCompositingAncestor() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ for (Frame* frame = m_frame->tree()->parent(); frame; frame = frame->tree()->parent()) {
+ if (FrameView* view = frame->view()) {
+ if (view->hasCompositedContent())
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+// Sometimes (for plug-ins) we need to eagerly go into compositing mode.
+void FrameView::enterCompositingMode()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (RenderView* view = m_frame->contentRenderer()) {
+ view->compositor()->enableCompositingMode();
+ if (!needsLayout())
+ view->compositor()->scheduleCompositingLayerUpdate();
+ }
+#endif
+}
+
+bool FrameView::isEnclosedInCompositingLayer() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ RenderObject* frameOwnerRenderer = m_frame->ownerRenderer();
+ if (frameOwnerRenderer && frameOwnerRenderer->containerForRepaint())
+ return true;
+
+ if (Frame* parentFrame = m_frame->tree()->parent()) {
+ if (FrameView* parentView = parentFrame->view())
+ return parentView->isEnclosedInCompositingLayer();
+ }
+#endif
+ return false;
+}
+
+bool FrameView::syncCompositingStateRecursive()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ ASSERT(m_frame->view() == this);
+ RenderView* contentRenderer = m_frame->contentRenderer();
+ if (!contentRenderer)
+ return true; // We don't want to keep trying to update layers if we have no renderer.
+
+ // If we sync compositing layers when a layout is pending, we may cause painting of compositing
+ // layer content to occur before layout has happened, which will cause paintContents() to bail.
+ if (needsLayout())
+ return false;
+
+ if (GraphicsLayer* rootLayer = contentRenderer->compositor()->rootPlatformLayer())
+ rootLayer->syncCompositingState();
+
+#if ENABLE(FULLSCREEN_API)
+ // The fullScreenRenderer's graphicsLayer has been re-parented, and the above recursive syncCompositingState
+ // call will not cause the subtree under it to repaint. Explicitly call the syncCompositingState on
+ // the fullScreenRenderer's graphicsLayer here:
+ Document* document = m_frame->document();
+ if (isDocumentRunningFullScreenAnimation(document)) {
+ RenderLayerBacking* backing = document->fullScreenRenderer()->layer()->backing();
+ if (GraphicsLayer* fullScreenLayer = backing->graphicsLayer())
+ fullScreenLayer->syncCompositingState();
+ }
+#endif
+
+ bool allSubframesSynced = true;
+ const HashSet<RefPtr<Widget> >* viewChildren = children();
+ HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end();
+ for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) {
+ Widget* widget = (*current).get();
+ if (widget->isFrameView()) {
+ bool synced = static_cast<FrameView*>(widget)->syncCompositingStateRecursive();
+ allSubframesSynced &= synced;
+ }
+ }
+ return allSubframesSynced;
+#else // USE(ACCELERATED_COMPOSITING)
+ return true;
+#endif
+}
+
+bool FrameView::isSoftwareRenderable() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ RenderView* view = m_frame->contentRenderer();
+ if (!view)
+ return true;
+
+ return !view->compositor()->has3DContent();
+#else
+ return true;
+#endif
+}
+
+void FrameView::didMoveOnscreen()
+{
+ RenderView* view = m_frame->contentRenderer();
+ if (view)
+ view->didMoveOnscreen();
+}
+
+void FrameView::willMoveOffscreen()
+{
+ RenderView* view = m_frame->contentRenderer();
+ if (view)
+ view->willMoveOffscreen();
+}
+
+RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
+{
+ return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot;
+}
+
+void FrameView::layout(bool allowSubtree)
+{
+ if (m_inLayout)
+ return;
+
+ m_layoutTimer.stop();
+ m_delayedLayout = false;
+ m_setNeedsLayoutWasDeferred = false;
+
+ // Protect the view from being deleted during layout (in recalcStyle)
+ RefPtr<FrameView> protector(this);
+
+ if (!m_frame) {
+ // FIXME: Do we need to set m_size.width here?
+ // FIXME: Should we set m_size.height here too?
+ m_size.setWidth(layoutWidth());
+ return;
+ }
+
+ // we shouldn't enter layout() while painting
+ ASSERT(!isPainting());
+ if (isPainting())
+ return;
+
+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(m_frame.get());
+
+ if (!allowSubtree && m_layoutRoot) {
+ m_layoutRoot->markContainingBlocksForLayout(false);
+ m_layoutRoot = 0;
+ }
+
+ ASSERT(m_frame->view() == this);
+
+ Document* document = m_frame->document();
+
+ m_layoutSchedulingEnabled = false;
+
+ if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_hasPendingPostLayoutTasks) {
+ // This is a new top-level layout. If there are any remaining tasks from the previous
+ // layout, finish them now.
+ m_inSynchronousPostLayout = true;
+ m_postLayoutTasksTimer.stop();
+ performPostLayoutTasks();
+ m_inSynchronousPostLayout = false;
+ }
+
+ // Viewport-dependent media queries may cause us to need completely different style information.
+ // Check that here.
+ if (document->styleSelector()->affectedByViewportChange())
+ document->styleSelectorChanged(RecalcStyleImmediately);
+
+ // Always ensure our style info is up-to-date. This can happen in situations where
+ // the layout beats any sort of style recalc update that needs to occur.
+ document->updateStyleIfNeeded();
+
+ bool subtree = m_layoutRoot;
+
+ // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
+ // so there's no point to continuing to layout
+ if (protector->hasOneRef())
+ return;
+
+ RenderObject* root = subtree ? m_layoutRoot : document->renderer();
+ if (!root) {
+ // FIXME: Do we need to set m_size here?
+ m_layoutSchedulingEnabled = true;
+ return;
+ }
+
+#ifdef ANDROID_INSTRUMENT
+ if (!m_frame->tree() || !m_frame->tree()->parent())
+ android::TimeCounter::start(android::TimeCounter::LayoutTimeCounter);
+#endif
+
+ m_nestedLayoutCount++;
+
+ if (!m_layoutRoot) {
+ Document* document = m_frame->document();
+ Node* documentElement = document->documentElement();
+ RenderObject* rootRenderer = documentElement ? documentElement->renderer() : 0;
+ Node* body = document->body();
+ if (body && body->renderer()) {
+ if (body->hasTagName(framesetTag) && m_frame->settings() && !m_frame->settings()->frameFlatteningEnabled()) {
+ body->renderer()->setChildNeedsLayout(true);
+ } else if (body->hasTagName(bodyTag)) {
+ if (!m_firstLayout && m_size.height() != layoutHeight() && body->renderer()->enclosingBox()->stretchesToViewport())
+ body->renderer()->setChildNeedsLayout(true);
+ }
+ } else if (rootRenderer) {
+#if ENABLE(SVG)
+ if (documentElement->isSVGElement()) {
+ if (!m_firstLayout && (m_size.width() != layoutWidth() || m_size.height() != layoutHeight()))
+ rootRenderer->setChildNeedsLayout(true);
+ }
+#endif
+ }
+
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (m_firstLayout && !document->ownerElement())
+ printf("Elapsed time before first layout: %d\n", document->elapsedTime());
+#endif
+ }
+
+ ScrollbarMode hMode;
+ ScrollbarMode vMode;
+ calculateScrollbarModesForLayout(hMode, vMode);
+
+ m_doFullRepaint = !subtree && (m_firstLayout || toRenderView(root)->printing());
+
+ if (!subtree) {
+ // Now set our scrollbar state for the layout.
+ ScrollbarMode currentHMode = horizontalScrollbarMode();
+ ScrollbarMode currentVMode = verticalScrollbarMode();
+
+ if (m_firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
+ if (m_firstLayout) {
+ setScrollbarsSuppressed(true);
+
+ m_firstLayout = false;
+ m_firstLayoutCallbackPending = true;
+ m_lastLayoutSize = IntSize(width(), height());
+ m_lastZoomFactor = root->style()->zoom();
+
+ // Set the initial vMode to AlwaysOn if we're auto.
+ if (vMode == ScrollbarAuto)
+ setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
+ // Set the initial hMode to AlwaysOff if we're auto.
+ if (hMode == ScrollbarAuto)
+ setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
+
+ setScrollbarModes(hMode, vMode);
+ setScrollbarsSuppressed(false, true);
+ } else
+ setScrollbarModes(hMode, vMode);
+ }
+
+ IntSize oldSize = m_size;
+
+ m_size = IntSize(layoutWidth(), layoutHeight());
+
+ if (oldSize != m_size) {
+ m_doFullRepaint = true;
+ if (!m_firstLayout) {
+ RenderBox* rootRenderer = document->documentElement() ? document->documentElement()->renderBox() : 0;
+ RenderBox* bodyRenderer = rootRenderer && document->body() ? document->body()->renderBox() : 0;
+ if (bodyRenderer && bodyRenderer->stretchesToViewport())
+ bodyRenderer->setChildNeedsLayout(true);
+ else if (rootRenderer && rootRenderer->stretchesToViewport())
+ rootRenderer->setChildNeedsLayout(true);
+ }
+ }
+ }
+
+ RenderLayer* layer = root->enclosingLayer();
+
+ pauseScheduledEvents();
+
+ bool disableLayoutState = false;
+ if (subtree) {
+ RenderView* view = root->view();
+ disableLayoutState = view->shouldDisableLayoutStateForSubtree(root);
+ view->pushLayoutState(root);
+ if (disableLayoutState)
+ view->disableLayoutState();
+ }
+
+ m_inLayout = true;
+ beginDeferredRepaints();
+ root->layout();
+ endDeferredRepaints();
+ m_inLayout = false;
+
+ if (subtree) {
+ RenderView* view = root->view();
+ view->popLayoutState(root);
+ if (disableLayoutState)
+ view->enableLayoutState();
+ }
+ m_layoutRoot = 0;
+
+ m_frame->selection()->setCaretRectNeedsUpdate();
+ m_frame->selection()->updateAppearance();
+
+ m_layoutSchedulingEnabled = true;
+
+ if (!subtree && !toRenderView(root)->printing())
+ adjustViewSize();
+
+ // Now update the positions of all layers.
+ beginDeferredRepaints();
+ IntPoint cachedOffset;
+ layer->updateLayerPositions((m_doFullRepaint ? RenderLayer::DoFullRepaint : 0)
+ | RenderLayer::CheckForRepaint
+ | RenderLayer::IsCompositingUpdateRoot
+ | RenderLayer::UpdateCompositingLayers,
+ subtree ? 0 : &cachedOffset);
+ endDeferredRepaints();
+
+#if USE(ACCELERATED_COMPOSITING)
+ updateCompositingLayers();
+#endif
+
+ m_layoutCount++;
+
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
+ if (AXObjectCache::accessibilityEnabled())
+ root->document()->axObjectCache()->postNotification(root, AXObjectCache::AXLayoutComplete, true);
+#endif
+#if ENABLE(DASHBOARD_SUPPORT)
+ updateDashboardRegions();
+#endif
+
+#ifdef ANDROID_INSTRUMENT
+ if (!m_frame->tree()->parent())
+ android::TimeCounter::record(android::TimeCounter::LayoutTimeCounter, __FUNCTION__);
+#endif
+ ASSERT(!root->needsLayout());
+
+ updateCanBlitOnScrollRecursively();
+
+ if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
+ updateOverflowStatus(layoutWidth() < contentsWidth(),
+ layoutHeight() < contentsHeight());
+
+ if (!m_hasPendingPostLayoutTasks) {
+ if (!m_inSynchronousPostLayout) {
+ m_inSynchronousPostLayout = true;
+ // Calls resumeScheduledEvents()
+ performPostLayoutTasks();
+ m_inSynchronousPostLayout = false;
+ }
+
+ if (!m_hasPendingPostLayoutTasks && (needsLayout() || m_inSynchronousPostLayout)) {
+ // If we need layout or are already in a synchronous call to postLayoutTasks(),
+ // defer widget updates and event dispatch until after we return. postLayoutTasks()
+ // can make us need to update again, and we can get stuck in a nasty cycle unless
+ // we call it through the timer here.
+ m_hasPendingPostLayoutTasks = true;
+ m_postLayoutTasksTimer.startOneShot(0);
+ if (needsLayout()) {
+ pauseScheduledEvents();
+ layout();
+ }
+ }
+ } else {
+ resumeScheduledEvents();
+ ASSERT(m_enqueueEvents);
+ }
+
+ InspectorInstrumentation::didLayout(cookie);
+
+ m_nestedLayoutCount--;
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+ // Reset to false each time we layout in case the overflow status changed.
+ bool hasOverflowScroll = false;
+ RenderObject* ownerRenderer = m_frame->ownerRenderer();
+ if (ownerRenderer && ownerRenderer->isRenderIFrame()) {
+ RenderLayer* layer = ownerRenderer->enclosingLayer();
+ if (layer) {
+ // Some sites use tiny iframes for loading so don't composite those.
+ if (canHaveScrollbars() && layoutWidth() > 1 && layoutHeight() > 1)
+ hasOverflowScroll = layoutWidth() < contentsWidth() || layoutHeight() < contentsHeight();
+ }
+ }
+ if (RenderView* view = m_frame->contentRenderer()) {
+ if (hasOverflowScroll != m_hasOverflowScroll) {
+ if (hasOverflowScroll)
+ enterCompositingMode();
+ else
+ // We are leaving overflow mode so we need to update the layer
+ // tree in case that is the reason we were composited.
+ view->compositor()->scheduleCompositingLayerUpdate();
+ }
+ }
+ m_hasOverflowScroll = hasOverflowScroll;
+#endif
+}
+
+void FrameView::addWidgetToUpdate(RenderEmbeddedObject* object)
+{
+ if (!m_widgetUpdateSet)
+ m_widgetUpdateSet.set(new RenderEmbeddedObjectSet);
+
+ m_widgetUpdateSet->add(object);
+}
+
+void FrameView::removeWidgetToUpdate(RenderEmbeddedObject* object)
+{
+ if (!m_widgetUpdateSet)
+ return;
+
+ m_widgetUpdateSet->remove(object);
+}
+
+void FrameView::setMediaType(const String& mediaType)
+{
+ m_mediaType = mediaType;
+}
+
+String FrameView::mediaType() const
+{
+ // See if we have an override type.
+ String overrideType = m_frame->loader()->client()->overrideMediaType();
+ if (!overrideType.isNull())
+ return overrideType;
+ return m_mediaType;
+}
+
+void FrameView::adjustMediaTypeForPrinting(bool printing)
+{
+ if (printing) {
+ if (m_mediaTypeWhenNotPrinting.isNull())
+ m_mediaTypeWhenNotPrinting = mediaType();
+ setMediaType("print");
+ } else {
+ if (!m_mediaTypeWhenNotPrinting.isNull())
+ setMediaType(m_mediaTypeWhenNotPrinting);
+ m_mediaTypeWhenNotPrinting = String();
+ }
+}
+
+bool FrameView::useSlowRepaints() const
+{
+ if (m_useSlowRepaints || m_slowRepaintObjectCount > 0 || (platformWidget() && m_fixedObjectCount > 0) || m_isOverlapped || !m_contentIsOpaque)
+ return true;
+
+ if (Frame* parentFrame = m_frame->tree()->parent()) {
+ if (FrameView* parentView = parentFrame->view())
+ return parentView->useSlowRepaints();
+ }
+
+ return false;
+}
+
+bool FrameView::useSlowRepaintsIfNotOverlapped() const
+{
+ if (m_useSlowRepaints || m_slowRepaintObjectCount > 0 || (platformWidget() && m_fixedObjectCount > 0) || !m_contentIsOpaque)
+ return true;
+
+ if (Frame* parentFrame = m_frame->tree()->parent()) {
+ if (FrameView* parentView = parentFrame->view())
+ return parentView->useSlowRepaintsIfNotOverlapped();
+ }
+
+ return false;
+}
+
+void FrameView::updateCanBlitOnScrollRecursively()
+{
+ for (Frame* frame = m_frame.get(); frame; frame = frame->tree()->traverseNext(m_frame.get())) {
+ if (FrameView* view = frame->view())
+ view->setCanBlitOnScroll(!view->useSlowRepaints());
+ }
+}
+
+void FrameView::setUseSlowRepaints()
+{
+ m_useSlowRepaints = true;
+ updateCanBlitOnScrollRecursively();
+}
+
+void FrameView::addSlowRepaintObject()
+{
+ if (!m_slowRepaintObjectCount)
+ updateCanBlitOnScrollRecursively();
+ m_slowRepaintObjectCount++;
+}
+
+void FrameView::removeSlowRepaintObject()
+{
+ ASSERT(m_slowRepaintObjectCount > 0);
+ m_slowRepaintObjectCount--;
+ if (!m_slowRepaintObjectCount)
+ updateCanBlitOnScrollRecursively();
+}
+
+void FrameView::addFixedObject()
+{
+ if (!m_fixedObjectCount && platformWidget())
+ updateCanBlitOnScrollRecursively();
+ ++m_fixedObjectCount;
+}
+
+void FrameView::removeFixedObject()
+{
+ ASSERT(m_fixedObjectCount > 0);
+ --m_fixedObjectCount;
+ if (!m_fixedObjectCount)
+ updateCanBlitOnScrollRecursively();
+}
+
+#if PLATFORM(ANDROID)
+// When the screen size change, fixed positioned element should be updated.
+void FrameView::updatePositionedObjects()
+{
+ RenderBlock::PositionedObjectsListHashSet* positionedObjects = 0;
+ if (RenderView* root = m_frame->contentRenderer())
+ positionedObjects = root->positionedObjects();
+
+ if (!positionedObjects || positionedObjects->isEmpty())
+ return;
+
+ RenderBlock::PositionedObjectsListHashSet::const_iterator end = positionedObjects->end();
+ for (RenderBlock::PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
+ RenderBox* renderBox = *it;
+ if (renderBox->style()->position() != FixedPosition)
+ continue;
+
+ renderBox->computeLogicalWidth();
+ renderBox->computeLogicalHeight();
+ }
+}
+#endif
+
+bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
+{
+ const size_t fixedObjectThreshold = 5;
+
+ RenderBlock::PositionedObjectsListHashSet* positionedObjects = 0;
+ if (RenderView* root = m_frame->contentRenderer())
+ positionedObjects = root->positionedObjects();
+
+ if (!positionedObjects || positionedObjects->isEmpty()) {
+ hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
+ return true;
+ }
+
+ // Get the rects of the fixed objects visible in the rectToScroll
+ Vector<IntRect, fixedObjectThreshold> subRectToUpdate;
+ bool updateInvalidatedSubRect = true;
+ RenderBlock::PositionedObjectsListHashSet::const_iterator end = positionedObjects->end();
+ for (RenderBlock::PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
+ RenderBox* renderBox = *it;
+ if (renderBox->style()->position() != FixedPosition)
+ continue;
+ IntRect updateRect = renderBox->layer()->repaintRectIncludingDescendants();
+ updateRect = contentsToWindow(updateRect);
+
+ updateRect.intersect(rectToScroll);
+ if (!updateRect.isEmpty()) {
+ if (subRectToUpdate.size() >= fixedObjectThreshold) {
+ updateInvalidatedSubRect = false;
+ break;
+ }
+ subRectToUpdate.append(updateRect);
+ }
+ }
+
+ // Scroll the view
+ if (updateInvalidatedSubRect) {
+ // 1) scroll
+ hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
+
+ // 2) update the area of fixed objects that has been invalidated
+ size_t fixObjectsCount = subRectToUpdate.size();
+ for (size_t i = 0; i < fixObjectsCount; ++i) {
+ IntRect updateRect = subRectToUpdate[i];
+ IntRect scrolledRect = updateRect;
+ scrolledRect.move(scrollDelta);
+ updateRect.unite(scrolledRect);
+ updateRect.intersect(rectToScroll);
+ hostWindow()->invalidateContentsAndWindow(updateRect, false);
+ }
+ return true;
+ }
+
+ // the number of fixed objects exceed the threshold, we cannot use the fast path
+ return false;
+}
+
+void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (RenderPart* frameRenderer = m_frame->ownerRenderer()) {
+ if (frameRenderer->containerForRepaint()) {
+ IntRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(),
+ frameRenderer->borderTop() + frameRenderer->paddingTop(),
+ visibleWidth(), visibleHeight());
+ frameRenderer->repaintRectangle(rect);
+ return;
+ }
+ }
+#endif
+
+ ScrollView::scrollContentsSlowPath(updateRect);
+}
+
+// Note that this gets called at painting time.
+void FrameView::setIsOverlapped(bool isOverlapped)
+{
+ if (isOverlapped == m_isOverlapped)
+ return;
+
+ m_isOverlapped = isOverlapped;
+ updateCanBlitOnScrollRecursively();
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (hasCompositedContentIncludingDescendants()) {
+ // Overlap can affect compositing tests, so if it changes, we need to trigger
+ // a layer update in the parent document.
+ if (Frame* parentFrame = m_frame->tree()->parent()) {
+ if (RenderView* parentView = parentFrame->contentRenderer()) {
+ RenderLayerCompositor* compositor = parentView->compositor();
+ compositor->setCompositingLayersNeedRebuild();
+ compositor->scheduleCompositingLayerUpdate();
+ }
+ }
+
+ if (RenderLayerCompositor::allowsIndependentlyCompositedIFrames(this)) {
+ // We also need to trigger reevaluation for this and all descendant frames,
+ // since a frame uses compositing if any ancestor is compositing.
+ for (Frame* frame = m_frame.get(); frame; frame = frame->tree()->traverseNext(m_frame.get())) {
+ if (RenderView* view = frame->contentRenderer()) {
+ RenderLayerCompositor* compositor = view->compositor();
+ compositor->setCompositingLayersNeedRebuild();
+ compositor->scheduleCompositingLayerUpdate();
+ }
+ }
+ }
+ }
+#endif
+}
+
+bool FrameView::isOverlappedIncludingAncestors() const
+{
+ if (isOverlapped())
+ return true;
+
+ if (Frame* parentFrame = m_frame->tree()->parent()) {
+ if (FrameView* parentView = parentFrame->view()) {
+ if (parentView->isOverlapped())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void FrameView::setContentIsOpaque(bool contentIsOpaque)
+{
+ if (contentIsOpaque == m_contentIsOpaque)
+ return;
+
+ m_contentIsOpaque = contentIsOpaque;
+ updateCanBlitOnScrollRecursively();
+}
+
+void FrameView::restoreScrollbar()
+{
+ setScrollbarsSuppressed(false);
+}
+
+bool FrameView::scrollToFragment(const KURL& url)
+{
+ // If our URL has no ref, then we have no place we need to jump to.
+ // OTOH If CSS target was set previously, we want to set it to 0, recalc
+ // and possibly repaint because :target pseudo class may have been
+ // set (see bug 11321).
+ if (!url.hasFragmentIdentifier() && !m_frame->document()->cssTarget())
+ return false;
+
+ String fragmentIdentifier = url.fragmentIdentifier();
+ if (scrollToAnchor(fragmentIdentifier))
+ return true;
+
+ // Try again after decoding the ref, based on the document's encoding.
+ if (TextResourceDecoder* decoder = m_frame->document()->decoder())
+ return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, decoder->encoding()));
+
+ return false;
+}
+
+bool FrameView::scrollToAnchor(const String& name)
+{
+ ASSERT(m_frame->document());
+
+ if (!m_frame->document()->haveStylesheetsLoaded()) {
+ m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
+ return false;
+ }
+
+ m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
+
+ Element* anchorNode = m_frame->document()->findAnchor(name);
+
+#if ENABLE(SVG)
+ if (m_frame->document()->isSVGDocument()) {
+ if (name.startsWith("xpointer(")) {
+ // We need to parse the xpointer reference here
+ } else if (name.startsWith("svgView(")) {
+ RefPtr<SVGSVGElement> svg = static_cast<SVGDocument*>(m_frame->document())->rootElement();
+ if (!svg->currentView()->parseViewSpec(name))
+ return false;
+ svg->setUseCurrentView(true);
+ } else {
+ if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) {
+ RefPtr<SVGViewElement> viewElement = anchorNode->hasTagName(SVGNames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0;
+ if (viewElement.get()) {
+ SVGElement* element = SVGLocatable::nearestViewportElement(viewElement.get());
+ if (element->hasTagName(SVGNames::svgTag)) {
+ RefPtr<SVGSVGElement> svg = static_cast<SVGSVGElement*>(element);
+ svg->inheritViewAttributes(viewElement.get());
+ }
+ }
+ }
+ }
+ // FIXME: need to decide which <svg> to focus on, and zoom to that one
+ // FIXME: need to actually "highlight" the viewTarget(s)
+ }
+#endif
+
+ m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear the current target.
+
+ // Implement the rule that "" and "top" both mean top of page as in other browsers.
+ if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
+ return false;
+
+ maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document());
+ return true;
+}
+
+void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode)
+{
+ m_maintainScrollPositionAnchor = anchorNode;
+ if (!m_maintainScrollPositionAnchor)
+ return;
+
+ // We need to update the layout before scrolling, otherwise we could
+ // really mess things up if an anchor scroll comes at a bad moment.
+ m_frame->document()->updateStyleIfNeeded();
+ // Only do a layout if changes have occurred that make it necessary.
+ if (m_frame->contentRenderer() && m_frame->contentRenderer()->needsLayout())
+ layout();
+ else
+ scrollToAnchor();
+}
+
+void FrameView::setScrollPosition(const IntPoint& scrollPoint)
+{
+ bool wasInProgrammaticScroll = m_inProgrammaticScroll;
+ m_inProgrammaticScroll = true;
+ m_maintainScrollPositionAnchor = 0;
+ ScrollView::setScrollPosition(scrollPoint);
+ m_inProgrammaticScroll = wasInProgrammaticScroll;
+}
+
+void FrameView::scrollPositionChangedViaPlatformWidget()
+{
+ repaintFixedElementsAfterScrolling();
+ scrollPositionChanged();
+}
+
+void FrameView::scrollPositionChanged()
+{
+ frame()->eventHandler()->sendScrollEvent();
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (RenderView* root = m_frame->contentRenderer()) {
+ if (root->usesCompositing())
+ root->compositor()->frameViewDidScroll(scrollPosition());
+ }
+#endif
+}
+
+void FrameView::repaintFixedElementsAfterScrolling()
+{
+ // For fixed position elements, update widget positions and compositing layers after scrolling,
+ // but only if we're not inside of layout.
+ if (!m_nestedLayoutCount && hasFixedObjects()) {
+ if (RenderView* root = m_frame->contentRenderer()) {
+ root->updateWidgetPositions();
+ root->layer()->updateRepaintRectsAfterScroll();
+#if USE(ACCELERATED_COMPOSITING)
+ root->compositor()->updateCompositingLayers(CompositingUpdateOnScroll);
+#endif
+ }
+ }
+}
+
+HostWindow* FrameView::hostWindow() const
+{
+ Page* page = frame() ? frame()->page() : 0;
+ if (!page)
+ return 0;
+ return page->chrome();
+}
+
+const unsigned cRepaintRectUnionThreshold = 25;
+
+void FrameView::repaintContentRectangle(const IntRect& r, bool immediate)
+{
+ ASSERT(!m_frame->document()->ownerElement());
+
+ double delay = adjustedDeferredRepaintDelay();
+ if ((m_deferringRepaints || m_deferredRepaintTimer.isActive() || delay) && !immediate) {
+ IntRect paintRect = r;
+ if (clipsRepaints() && !paintsEntireContents())
+ paintRect.intersect(visibleContentRect());
+#ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS
+ if (r != paintRect)
+ ScrollView::platformOffscreenContentRectangle(visibleContentRect(), r);
+#endif
+ if (paintRect.isEmpty())
+ return;
+ if (m_repaintCount == cRepaintRectUnionThreshold) {
+ IntRect unionedRect;
+ for (unsigned i = 0; i < cRepaintRectUnionThreshold; ++i)
+ unionedRect.unite(m_repaintRects[i]);
+ m_repaintRects.clear();
+ m_repaintRects.append(unionedRect);
+ }
+ if (m_repaintCount < cRepaintRectUnionThreshold)
+ m_repaintRects.append(paintRect);
+ else
+ m_repaintRects[0].unite(paintRect);
+ m_repaintCount++;
+
+ if (!m_deferringRepaints && !m_deferredRepaintTimer.isActive())
+ m_deferredRepaintTimer.startOneShot(delay);
+ return;
+ }
+
+ if (!shouldUpdate(immediate))
+ return;
+
+#if ENABLE(TILED_BACKING_STORE)
+ if (frame()->tiledBackingStore()) {
+ frame()->tiledBackingStore()->invalidate(r);
+ return;
+ }
+#endif
+ ScrollView::repaintContentRectangle(r, immediate);
+}
+
+void FrameView::visibleContentsResized()
+{
+ // We check to make sure the view is attached to a frame() as this method can
+ // be triggered before the view is attached by Frame::createView(...) setting
+ // various values such as setScrollBarModes(...) for example. An ASSERT is
+ // triggered when a view is layout before being attached to a frame().
+ if (!frame()->view())
+ return;
+
+ if (needsLayout())
+ layout();
+}
+
+void FrameView::beginDeferredRepaints()
+{
+ Page* page = m_frame->page();
+ if (page->mainFrame() != m_frame)
+ return page->mainFrame()->view()->beginDeferredRepaints();
+
+ m_deferringRepaints++;
+}
+
+
+void FrameView::endDeferredRepaints()
+{
+ Page* page = m_frame->page();
+ if (page->mainFrame() != m_frame)
+ return page->mainFrame()->view()->endDeferredRepaints();
+
+ ASSERT(m_deferringRepaints > 0);
+
+ if (--m_deferringRepaints)
+ return;
+
+ if (m_deferredRepaintTimer.isActive())
+ return;
+
+ if (double delay = adjustedDeferredRepaintDelay()) {
+ m_deferredRepaintTimer.startOneShot(delay);
+ return;
+ }
+
+ doDeferredRepaints();
+}
+
+void FrameView::checkStopDelayingDeferredRepaints()
+{
+ if (!m_deferredRepaintTimer.isActive())
+ return;
+
+ Document* document = m_frame->document();
+ if (document && (document->parsing() || document->cachedResourceLoader()->requestCount()))
+ return;
+
+ m_deferredRepaintTimer.stop();
+
+ doDeferredRepaints();
+}
+
+void FrameView::doDeferredRepaints()
+{
+ ASSERT(!m_deferringRepaints);
+ if (!shouldUpdate()) {
+ m_repaintRects.clear();
+ m_repaintCount = 0;
+ return;
+ }
+ unsigned size = m_repaintRects.size();
+ for (unsigned i = 0; i < size; i++) {
+#if ENABLE(TILED_BACKING_STORE)
+ if (frame()->tiledBackingStore()) {
+ frame()->tiledBackingStore()->invalidate(m_repaintRects[i]);
+ continue;
+ }
+#endif
+ ScrollView::repaintContentRectangle(m_repaintRects[i], false);
+ }
+ m_repaintRects.clear();
+ m_repaintCount = 0;
+
+ updateDeferredRepaintDelay();
+}
+
+void FrameView::updateDeferredRepaintDelay()
+{
+ Document* document = m_frame->document();
+ if (!document || (!document->parsing() && !document->cachedResourceLoader()->requestCount())) {
+ m_deferredRepaintDelay = s_deferredRepaintDelay;
+ return;
+ }
+ if (m_deferredRepaintDelay < s_maxDeferredRepaintDelayDuringLoading) {
+ m_deferredRepaintDelay += s_deferredRepaintDelayIncrementDuringLoading;
+ if (m_deferredRepaintDelay > s_maxDeferredRepaintDelayDuringLoading)
+ m_deferredRepaintDelay = s_maxDeferredRepaintDelayDuringLoading;
+ }
+}
+
+void FrameView::resetDeferredRepaintDelay()
+{
+ m_deferredRepaintDelay = 0;
+ if (m_deferredRepaintTimer.isActive()) {
+ m_deferredRepaintTimer.stop();
+ if (!m_deferringRepaints)
+ doDeferredRepaints();
+ }
+}
+
+double FrameView::adjustedDeferredRepaintDelay() const
+{
+ if (!m_deferredRepaintDelay)
+ return 0;
+ double timeSinceLastPaint = currentTime() - m_lastPaintTime;
+ return max(0., m_deferredRepaintDelay - timeSinceLastPaint);
+}
+
+void FrameView::deferredRepaintTimerFired(Timer<FrameView>*)
+{
+ doDeferredRepaints();
+}
+
+void FrameView::layoutTimerFired(Timer<FrameView>*)
+{
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (!m_frame->document()->ownerElement())
+ printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime());
+#endif
+ layout();
+}
+
+void FrameView::scheduleRelayout()
+{
+ // FIXME: We should assert the page is not in the page cache, but that is causing
+ // too many false assertions. See <rdar://problem/7218118>.
+ ASSERT(m_frame->view() == this);
+
+ if (m_layoutRoot) {
+ m_layoutRoot->markContainingBlocksForLayout(false);
+ m_layoutRoot = 0;
+ }
+ if (!m_layoutSchedulingEnabled)
+ return;
+ if (!needsLayout())
+ return;
+ if (!m_frame->document()->shouldScheduleLayout())
+ return;
+
+#ifdef ANDROID_FLATTEN_FRAMESET
+ if (m_frame->ownerRenderer())
+ m_frame->ownerRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
+#endif
+
+ // When frame flattening is enabled, the contents of the frame affects layout of the parent frames.
+ // Also invalidate parent frame starting from the owner element of this frame.
+ if (m_frame->settings() && m_frame->settings()->frameFlatteningEnabled() && m_frame->ownerRenderer()) {
+ if (m_frame->ownerElement()->hasTagName(iframeTag) || m_frame->ownerElement()->hasTagName(frameTag))
+ m_frame->ownerRenderer()->setNeedsLayout(true, true);
+ }
+
+ int delay = m_frame->document()->minimumLayoutDelay();
+ if (m_layoutTimer.isActive() && m_delayedLayout && !delay)
+ unscheduleRelayout();
+ if (m_layoutTimer.isActive())
+ return;
+
+ m_delayedLayout = delay != 0;
+
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (!m_frame->document()->ownerElement())
+ printf("Scheduling layout for %d\n", delay);
+#endif
+
+ m_layoutTimer.startOneShot(delay * 0.001);
+}
+
+static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
+{
+ for (RenderObject* r = descendant; r; r = r->container()) {
+ if (r == ancestor)
+ return true;
+ }
+ return false;
+}
+
+void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot)
+{
+ ASSERT(m_frame->view() == this);
+
+ if (m_frame->contentRenderer() && m_frame->contentRenderer()->needsLayout()) {
+ if (relayoutRoot)
+ relayoutRoot->markContainingBlocksForLayout(false);
+ return;
+ }
+
+ if (layoutPending() || !m_layoutSchedulingEnabled) {
+ if (m_layoutRoot != relayoutRoot) {
+ if (isObjectAncestorContainerOf(m_layoutRoot, relayoutRoot)) {
+ // Keep the current root
+ relayoutRoot->markContainingBlocksForLayout(false, m_layoutRoot);
+ } else if (m_layoutRoot && isObjectAncestorContainerOf(relayoutRoot, m_layoutRoot)) {
+ // Re-root at relayoutRoot
+ m_layoutRoot->markContainingBlocksForLayout(false, relayoutRoot);
+ m_layoutRoot = relayoutRoot;
+ } else {
+ // Just do a full relayout
+ if (m_layoutRoot)
+ m_layoutRoot->markContainingBlocksForLayout(false);
+ m_layoutRoot = 0;
+ relayoutRoot->markContainingBlocksForLayout(false);
+ }
+ }
+ } else if (m_layoutSchedulingEnabled) {
+ int delay = m_frame->document()->minimumLayoutDelay();
+ m_layoutRoot = relayoutRoot;
+ m_delayedLayout = delay != 0;
+ m_layoutTimer.startOneShot(delay * 0.001);
+ }
+}
+
+bool FrameView::layoutPending() const
+{
+ return m_layoutTimer.isActive();
+}
+
+bool FrameView::needsLayout() const
+{
+ // This can return true in cases where the document does not have a body yet.
+ // Document::shouldScheduleLayout takes care of preventing us from scheduling
+ // layout in that case.
+ if (!m_frame)
+ return false;
+ RenderView* root = m_frame->contentRenderer();
+ return layoutPending()
+ || (root && root->needsLayout())
+ || m_layoutRoot
+ || (m_deferSetNeedsLayouts && m_setNeedsLayoutWasDeferred);
+}
+
+void FrameView::setNeedsLayout()
+{
+ if (m_deferSetNeedsLayouts) {
+ m_setNeedsLayoutWasDeferred = true;
+ return;
+ }
+ RenderView* root = m_frame->contentRenderer();
+ if (root)
+ root->setNeedsLayout(true);
+}
+
+void FrameView::unscheduleRelayout()
+{
+ m_postLayoutTasksTimer.stop();
+
+ if (!m_layoutTimer.isActive())
+ return;
+
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (!m_frame->document()->ownerElement())
+ printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime());
+#endif
+
+ m_layoutTimer.stop();
+ m_delayedLayout = false;
+}
+
+bool FrameView::isTransparent() const
+{
+ return m_isTransparent;
+}
+
+void FrameView::setTransparent(bool isTransparent)
+{
+ m_isTransparent = isTransparent;
+}
+
+Color FrameView::baseBackgroundColor() const
+{
+ return m_baseBackgroundColor;
+}
+
+void FrameView::setBaseBackgroundColor(Color bc)
+{
+ if (!bc.isValid())
+ bc = Color::white;
+ m_baseBackgroundColor = bc;
+}
+
+void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
+{
+ for (Frame* frame = m_frame.get(); frame; frame = frame->tree()->traverseNext(m_frame.get())) {
+ if (FrameView* view = frame->view()) {
+ view->setTransparent(transparent);
+ view->setBaseBackgroundColor(backgroundColor);
+ }
+ }
+}
+
+bool FrameView::shouldUpdateWhileOffscreen() const
+{
+ return m_shouldUpdateWhileOffscreen;
+}
+
+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) {
+ ExceptionCode ec = 0;
+ eventTarget->dispatchEvent(event, ec);
+ return;
+ }
+
+ ScheduledEvent* scheduledEvent = new ScheduledEvent;
+ scheduledEvent->m_event = event;
+ scheduledEvent->m_eventTarget = eventTarget;
+ m_scheduledEvents.append(scheduledEvent);
+}
+
+void FrameView::pauseScheduledEvents()
+{
+ ASSERT(m_scheduledEvents.isEmpty() || m_enqueueEvents);
+ m_enqueueEvents++;
+}
+
+void FrameView::resumeScheduledEvents()
+{
+ m_enqueueEvents--;
+ if (!m_enqueueEvents)
+ dispatchScheduledEvents();
+ ASSERT(m_scheduledEvents.isEmpty() || m_enqueueEvents);
+}
+
+void FrameView::scrollToAnchor()
+{
+ RefPtr<Node> anchorNode = m_maintainScrollPositionAnchor;
+ if (!anchorNode)
+ return;
+
+ if (!anchorNode->renderer())
+ return;
+
+ IntRect rect;
+ if (anchorNode != m_frame->document())
+ rect = anchorNode->getRect();
+
+ // Scroll nested layers and frames to reveal the anchor.
+ // Align to the top and to the closest side (this matches other browsers).
+ anchorNode->renderer()->enclosingLayer()->scrollRectToVisible(rect, true, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
+
+ if (AXObjectCache::accessibilityEnabled())
+ m_frame->document()->axObjectCache()->handleScrolledToAnchor(anchorNode.get());
+
+ // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
+ m_maintainScrollPositionAnchor = anchorNode;
+}
+
+void FrameView::updateWidget(RenderEmbeddedObject* object)
+{
+ ASSERT(!object->node() || object->node()->isElementNode());
+ Element* ownerElement = static_cast<Element*>(object->node());
+ // The object may have already been destroyed (thus node cleared),
+ // but FrameView holds a manual ref, so it won't have been deleted.
+ ASSERT(m_widgetUpdateSet->contains(object));
+ if (!ownerElement)
+ return;
+
+ // No need to update if it's already crashed or known to be missing.
+ if (object->pluginCrashedOrWasMissing())
+ return;
+
+ // FIXME: This could turn into a real virtual dispatch if we defined
+ // updateWidget(bool) on HTMLElement.
+ if (ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag))
+ static_cast<HTMLPlugInImageElement*>(ownerElement)->updateWidget(false);
+ // FIXME: It is not clear that Media elements need or want this updateWidget() call.
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ else if (ownerElement->hasTagName(videoTag) || ownerElement->hasTagName(audioTag))
+ static_cast<HTMLMediaElement*>(ownerElement)->updateWidget(false);
+#endif
+ else
+ ASSERT_NOT_REACHED();
+
+ // Caution: it's possible the object was destroyed again, since loading a
+ // plugin may run any arbitrary javascript.
+ object->updateWidgetPosition();
+}
+
+bool FrameView::updateWidgets()
+{
+ if (m_nestedLayoutCount > 1 || !m_widgetUpdateSet || m_widgetUpdateSet->isEmpty())
+ return true;
+
+ size_t size = m_widgetUpdateSet->size();
+
+ Vector<RenderEmbeddedObject*> objects;
+ objects.reserveCapacity(size);
+
+ RenderEmbeddedObjectSet::const_iterator end = m_widgetUpdateSet->end();
+ for (RenderEmbeddedObjectSet::const_iterator it = m_widgetUpdateSet->begin(); it != end; ++it) {
+ objects.uncheckedAppend(*it);
+ (*it)->ref();
+ }
+
+ for (size_t i = 0; i < size; ++i) {
+ RenderEmbeddedObject* object = objects[i];
+ updateWidget(object);
+ m_widgetUpdateSet->remove(object);
+ }
+
+ RenderArena* arena = m_frame->document()->renderArena();
+ for (size_t i = 0; i < size; ++i)
+ objects[i]->deref(arena);
+
+ return m_widgetUpdateSet->isEmpty();
+}
+
+void FrameView::performPostLayoutTasks()
+{
+ m_hasPendingPostLayoutTasks = false;
+
+ if (m_firstLayoutCallbackPending) {
+ m_firstLayoutCallbackPending = false;
+ m_frame->loader()->didFirstLayout();
+ }
+
+ if (m_isVisuallyNonEmpty && m_firstVisuallyNonEmptyLayoutCallbackPending) {
+ m_firstVisuallyNonEmptyLayoutCallbackPending = false;
+ m_frame->loader()->didFirstVisuallyNonEmptyLayout();
+ }
+
+ RenderView* root = m_frame->contentRenderer();
+
+ root->updateWidgetPositions();
+
+ for (unsigned i = 0; i < maxUpdateWidgetsIterations; i++) {
+ if (updateWidgets())
+ break;
+ }
+
+ scrollToAnchor();
+
+ resumeScheduledEvents();
+
+ if (!root->printing()) {
+ IntSize currentSize = IntSize(width(), height());
+ float currentZoomFactor = root->style()->zoom();
+ bool resized = !m_firstLayout && (currentSize != m_lastLayoutSize || currentZoomFactor != m_lastZoomFactor);
+ m_lastLayoutSize = currentSize;
+ m_lastZoomFactor = currentZoomFactor;
+ if (resized)
+ m_frame->eventHandler()->sendResizeEvent();
+ }
+}
+
+void FrameView::postLayoutTimerFired(Timer<FrameView>*)
+{
+ performPostLayoutTasks();
+}
+
+void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
+{
+ if (!m_viewportRenderer)
+ return;
+
+ if (m_overflowStatusDirty) {
+ m_horizontalOverflow = horizontalOverflow;
+ m_verticalOverflow = verticalOverflow;
+ m_overflowStatusDirty = false;
+ return;
+ }
+
+ bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
+ bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
+
+ if (horizontalOverflowChanged || verticalOverflowChanged) {
+ m_horizontalOverflow = horizontalOverflow;
+ m_verticalOverflow = verticalOverflow;
+
+ scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow,
+ verticalOverflowChanged, verticalOverflow),
+ m_viewportRenderer->node());
+ }
+
+}
+
+void FrameView::dispatchScheduledEvents()
+{
+ if (m_scheduledEvents.isEmpty())
+ return;
+
+ Vector<ScheduledEvent*> scheduledEventsCopy = m_scheduledEvents;
+ m_scheduledEvents.clear();
+
+ Vector<ScheduledEvent*>::iterator end = scheduledEventsCopy.end();
+ for (Vector<ScheduledEvent*>::iterator it = scheduledEventsCopy.begin(); it != end; ++it) {
+ ScheduledEvent* scheduledEvent = *it;
+
+ ExceptionCode ec = 0;
+
+ // Only dispatch events to nodes that are in the document
+ if (scheduledEvent->m_eventTarget->inDocument())
+ scheduledEvent->m_eventTarget->dispatchEvent(scheduledEvent->m_event, ec);
+
+ delete scheduledEvent;
+ }
+}
+
+IntRect FrameView::windowClipRect(bool clipToContents) const
+{
+ ASSERT(m_frame->view() == this);
+
+ if (paintsEntireContents())
+ return IntRect(IntPoint(0, 0), contentsSize());
+
+ // Set our clip rect to be our contents.
+ IntRect clipRect = contentsToWindow(visibleContentRect(!clipToContents));
+ if (!m_frame || !m_frame->document() || !m_frame->document()->ownerElement())
+ return clipRect;
+
+ // Take our owner element and get the clip rect from the enclosing layer.
+ Element* elt = m_frame->document()->ownerElement();
+ RenderLayer* layer = elt->renderer()->enclosingLayer();
+ // FIXME: layer should never be null, but sometimes seems to be anyway.
+ if (!layer)
+ return clipRect;
+ FrameView* parentView = elt->document()->view();
+ clipRect.intersect(parentView->windowClipRectForLayer(layer, true));
+ return clipRect;
+}
+
+IntRect FrameView::windowClipRectForLayer(const RenderLayer* layer, bool clipToLayerContents) const
+{
+ // If we have no layer, just return our window clip rect.
+ if (!layer)
+ return windowClipRect();
+
+ // Apply the clip from the layer.
+ IntRect clipRect;
+ if (clipToLayerContents)
+ clipRect = layer->childrenClipRect();
+ else
+ clipRect = layer->selfClipRect();
+ clipRect = contentsToWindow(clipRect);
+ return intersection(clipRect, windowClipRect());
+}
+
+bool FrameView::isActive() const
+{
+ Page* page = frame()->page();
+ return page && page->focusController()->isActive();
+}
+
+void FrameView::valueChanged(Scrollbar* bar)
+{
+ // Figure out if we really moved.
+ IntSize offset = scrollOffset();
+ ScrollView::valueChanged(bar);
+ if (offset != scrollOffset())
+ scrollPositionChanged();
+ frame()->loader()->client()->didChangeScrollOffset();
+}
+
+void FrameView::valueChanged(const IntSize& scrollDelta)
+{
+ ScrollView::valueChanged(scrollDelta);
+ frame()->eventHandler()->sendScrollEvent();
+ frame()->loader()->client()->didChangeScrollOffset();
+}
+
+void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
+{
+ // Add in our offset within the FrameView.
+ IntRect dirtyRect = rect;
+ dirtyRect.move(scrollbar->x(), scrollbar->y());
+ invalidateRect(dirtyRect);
+}
+
+void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const
+{
+ tickmarks = frame()->document()->markers()->renderedRectsForMarkers(DocumentMarker::TextMatch);
+}
+
+IntRect FrameView::windowResizerRect() const
+{
+ Page* page = frame() ? frame()->page() : 0;
+ if (!page)
+ return IntRect();
+ return page->chrome()->windowResizerRect();
+}
+
+#if ENABLE(DASHBOARD_SUPPORT)
+void FrameView::updateDashboardRegions()
+{
+ Document* document = m_frame->document();
+ if (!document->hasDashboardRegions())
+ return;
+ Vector<DashboardRegionValue> newRegions;
+ document->renderBox()->collectDashboardRegions(newRegions);
+ if (newRegions == document->dashboardRegions())
+ return;
+ document->setDashboardRegions(newRegions);
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+ page->chrome()->client()->dashboardRegionsChanged();
+}
+#endif
+
+void FrameView::invalidateScrollCorner()
+{
+ invalidateRect(scrollCornerRect());
+}
+
+void FrameView::updateScrollCorner()
+{
+ RenderObject* renderer = 0;
+ RefPtr<RenderStyle> cornerStyle;
+
+ if (!scrollCornerRect().isEmpty()) {
+ // Try the <body> element first as a scroll corner source.
+ Document* doc = m_frame->document();
+ Element* body = doc ? doc->body() : 0;
+ if (body && body->renderer()) {
+ renderer = body->renderer();
+ cornerStyle = renderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, renderer->style());
+ }
+
+ if (!cornerStyle) {
+ // If the <body> didn't have a custom style, then the root element might.
+ Element* docElement = doc ? doc->documentElement() : 0;
+ if (docElement && docElement->renderer()) {
+ renderer = docElement->renderer();
+ cornerStyle = renderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, renderer->style());
+ }
+ }
+
+ if (!cornerStyle) {
+ // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
+ if (RenderPart* renderer = m_frame->ownerRenderer())
+ cornerStyle = renderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, renderer->style());
+ }
+ }
+
+ if (cornerStyle) {
+ if (!m_scrollCorner)
+ m_scrollCorner = new (renderer->renderArena()) RenderScrollbarPart(renderer->document());
+ m_scrollCorner->setStyle(cornerStyle.release());
+ invalidateRect(scrollCornerRect());
+ } else if (m_scrollCorner) {
+ m_scrollCorner->destroy();
+ m_scrollCorner = 0;
+ }
+}
+
+void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
+{
+ if (context->updatingControlTints()) {
+ updateScrollCorner();
+ return;
+ }
+
+ if (m_scrollCorner) {
+ m_scrollCorner->paintIntoRect(context, cornerRect.x(), cornerRect.y(), cornerRect);
+ return;
+ }
+
+ ScrollView::paintScrollCorner(context, cornerRect);
+}
+
+bool FrameView::hasCustomScrollbars() const
+{
+ const HashSet<RefPtr<Widget> >* viewChildren = children();
+ HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end();
+ for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) {
+ Widget* widget = current->get();
+ if (widget->isFrameView()) {
+ if (static_cast<FrameView*>(widget)->hasCustomScrollbars())
+ return true;
+ } else if (widget->isScrollbar()) {
+ Scrollbar* scrollbar = static_cast<Scrollbar*>(widget);
+ if (scrollbar->isCustomScrollbar())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void FrameView::updateControlTints()
+{
+ // This is called when control tints are changed from aqua/graphite to clear and vice versa.
+ // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
+ // This is only done if the theme supports control tinting. It's up to the theme and platform
+ // to define when controls get the tint and to call this function when that changes.
+
+ // Optimize the common case where we bring a window to the front while it's still empty.
+ if (!m_frame || m_frame->loader()->url().isEmpty())
+ return;
+
+ if ((m_frame->contentRenderer() && m_frame->contentRenderer()->theme()->supportsControlTints()) || hasCustomScrollbars()) {
+ if (needsLayout())
+ layout();
+ PlatformGraphicsContext* const noContext = 0;
+ GraphicsContext context(noContext);
+ context.setUpdatingControlTints(true);
+ if (platformWidget())
+ paintContents(&context, visibleContentRect());
+ else
+ paint(&context, frameRect());
+ }
+}
+
+bool FrameView::wasScrolledByUser() const
+{
+ return m_wasScrolledByUser;
+}
+
+void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
+{
+ if (m_inProgrammaticScroll)
+ return;
+ m_maintainScrollPositionAnchor = 0;
+ m_wasScrolledByUser = wasScrolledByUser;
+}
+
+void FrameView::paintContents(GraphicsContext* p, const IntRect& rect)
+{
+ if (!frame())
+ return;
+
+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willPaint(m_frame.get(), rect);
+
+ Document* document = frame()->document();
+
+#ifndef NDEBUG
+ bool fillWithRed;
+ if (document->printing())
+ fillWithRed = false; // Printing, don't fill with red (can't remember why).
+ else if (document->ownerElement())
+ fillWithRed = false; // Subframe, don't fill with red.
+ else if (isTransparent())
+ fillWithRed = false; // Transparent, don't fill with red.
+ else if (m_paintBehavior & PaintBehaviorSelectionOnly)
+ fillWithRed = false; // Selections are transparent, don't fill with red.
+ else if (m_nodeToDraw)
+ fillWithRed = false; // Element images are transparent, don't fill with red.
+ else
+ fillWithRed = true;
+
+ if (fillWithRed)
+ p->fillRect(rect, Color(0xFF, 0, 0), ColorSpaceDeviceRGB);
+#endif
+
+ bool isTopLevelPainter = !sCurrentPaintTimeStamp;
+ if (isTopLevelPainter)
+ sCurrentPaintTimeStamp = currentTime();
+
+ RenderView* contentRenderer = frame()->contentRenderer();
+ if (!contentRenderer) {
+ LOG_ERROR("called FrameView::paint with nil renderer");
+ return;
+ }
+
+ ASSERT(!needsLayout());
+ if (needsLayout())
+ return;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (!p->paintingDisabled()) {
+ if (GraphicsLayer* rootLayer = contentRenderer->compositor()->rootPlatformLayer())
+ rootLayer->syncCompositingState();
+#if ENABLE(FULLSCREEN_API)
+ // The fullScreenRenderer's graphicsLayer has been re-parented, and the above recursive syncCompositingState
+ // call will not cause the subtree under it to repaint. Explicitly call the syncCompositingState on
+ // the fullScreenRenderer's graphicsLayer here:
+ if (isDocumentRunningFullScreenAnimation(document)) {
+ RenderLayerBacking* backing = document->fullScreenRenderer()->layer()->backing();
+ if (GraphicsLayer* fullScreenLayer = backing->graphicsLayer())
+ fullScreenLayer->syncCompositingState();
+ }
+#endif
+ }
+#endif
+
+ PaintBehavior oldPaintBehavior = m_paintBehavior;
+ if (m_paintBehavior == PaintBehaviorNormal)
+ document->markers()->invalidateRenderedRectsForMarkersInRect(rect);
+
+ if (document->printing())
+ m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
+
+ bool flatteningPaint = m_paintBehavior & PaintBehaviorFlattenCompositingLayers;
+ bool isRootFrame = !document->ownerElement();
+ if (flatteningPaint && isRootFrame)
+ notifyWidgetsInAllFrames(WillPaintFlattened);
+
+ ASSERT(!m_isPainting);
+ m_isPainting = true;
+
+ // m_nodeToDraw is used to draw only one element (and its descendants)
+ RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0;
+
+ contentRenderer->layer()->paint(p, rect, m_paintBehavior, eltRenderer);
+
+ m_isPainting = false;
+
+ if (flatteningPaint && isRootFrame)
+ notifyWidgetsInAllFrames(DidPaintFlattened);
+
+ m_paintBehavior = oldPaintBehavior;
+ m_lastPaintTime = currentTime();
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ // Regions may have changed as a result of the visibility/z-index of element changing.
+ if (document->dashboardRegionsDirty())
+ updateDashboardRegions();
+#endif
+
+ if (isTopLevelPainter)
+ sCurrentPaintTimeStamp = 0;
+
+ InspectorInstrumentation::didPaint(cookie);
+}
+
+void FrameView::setPaintBehavior(PaintBehavior behavior)
+{
+ m_paintBehavior = behavior;
+}
+
+PaintBehavior FrameView::paintBehavior() const
+{
+ return m_paintBehavior;
+}
+
+bool FrameView::isPainting() const
+{
+ return m_isPainting;
+}
+
+void FrameView::setNodeToDraw(Node* node)
+{
+ m_nodeToDraw = node;
+}
+
+void FrameView::updateLayoutAndStyleIfNeededRecursive()
+{
+ // We have to crawl our entire tree looking for any FrameViews that need
+ // layout and make sure they are up to date.
+ // Mac actually tests for intersection with the dirty region and tries not to
+ // update layout for frames that are outside the dirty region. Not only does this seem
+ // pointless (since those frames will have set a zero timer to layout anyway), but
+ // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
+ // region but then become included later by the second frame adding rects to the dirty region
+ // when it lays out.
+
+ m_frame->document()->updateStyleIfNeeded();
+
+ if (needsLayout())
+ layout();
+
+ const HashSet<RefPtr<Widget> >* viewChildren = children();
+ HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end();
+ for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) {
+ Widget* widget = (*current).get();
+ if (widget->isFrameView())
+ static_cast<FrameView*>(widget)->updateLayoutAndStyleIfNeededRecursive();
+ }
+
+ // updateLayoutAndStyleIfNeededRecursive is called when we need to make sure style and layout are up-to-date before
+ // painting, so we need to flush out any deferred repaints too.
+ flushDeferredRepaints();
+}
+
+void FrameView::flushDeferredRepaints()
+{
+ if (!m_deferredRepaintTimer.isActive())
+ return;
+ m_deferredRepaintTimer.stop();
+ doDeferredRepaints();
+}
+
+void FrameView::forceLayout(bool allowSubtree)
+{
+ layout(allowSubtree);
+}
+
+void FrameView::forceLayoutForPagination(const FloatSize& pageSize, float maximumShrinkFactor, Frame::AdjustViewSizeOrNot shouldAdjustViewSize)
+{
+ // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
+ // the state of things before and after the layout
+ RenderView *root = toRenderView(m_frame->document()->renderer());
+ if (root) {
+ int pageW = ceilf(pageSize.width());
+ root->setWidth(pageW);
+ root->setPageLogicalHeight(pageSize.height());
+ root->setNeedsLayoutAndPrefWidthsRecalc();
+ forceLayout();
+
+ // If we don't fit in the given page width, we'll lay out again. If we don't fit in the
+ // page width when shrunk, we will lay out at maximum shrink and clip extra content.
+ // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping
+ // implementation should not do this!
+ int docWidth = root->docWidth();
+ if (docWidth > pageSize.width()) {
+ pageW = std::min<int>(docWidth, ceilf(pageSize.width() * maximumShrinkFactor));
+ if (pageSize.height())
+ root->setPageLogicalHeight(pageW / pageSize.width() * pageSize.height());
+ root->setWidth(pageW);
+ root->setNeedsLayoutAndPrefWidthsRecalc();
+ forceLayout();
+ int docHeight = root->docHeight();
+ root->clearLayoutOverflow();
+ root->addLayoutOverflow(IntRect(0, 0, pageW, docHeight)); // This is how we clip in case we overflow again.
+ }
+ }
+
+ if (shouldAdjustViewSize)
+ adjustViewSize();
+}
+
+void FrameView::adjustPageHeightDeprecated(float *newBottom, float oldTop, float oldBottom, float /*bottomLimit*/)
+{
+ RenderView* root = m_frame->contentRenderer();
+ if (root) {
+ // Use a context with painting disabled.
+ GraphicsContext context((PlatformGraphicsContext*)0);
+ root->setTruncatedAt((int)floorf(oldBottom));
+ IntRect dirtyRect(0, (int)floorf(oldTop), root->rightLayoutOverflow(), (int)ceilf(oldBottom - oldTop));
+ root->setPrintRect(dirtyRect);
+ root->layer()->paint(&context, dirtyRect);
+ *newBottom = root->bestTruncatedAt();
+ if (*newBottom == 0)
+ *newBottom = oldBottom;
+ root->setPrintRect(IntRect());
+ } else
+ *newBottom = oldBottom;
+}
+
+IntRect FrameView::convertFromRenderer(const RenderObject* renderer, const IntRect& rendererRect) const
+{
+ IntRect rect = renderer->localToAbsoluteQuad(FloatRect(rendererRect)).enclosingBoundingBox();
+
+ // Convert from page ("absolute") to FrameView coordinates.
+ rect.move(-scrollX(), -scrollY());
+
+ return rect;
+}
+
+IntRect FrameView::convertToRenderer(const RenderObject* renderer, const IntRect& viewRect) const
+{
+ IntRect rect = viewRect;
+
+ // Convert from FrameView coords into page ("absolute") coordinates.
+ rect.move(scrollX(), scrollY());
+
+ // FIXME: we don't have a way to map an absolute rect down to a local quad, so just
+ // move the rect for now.
+ rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), false, true /* use transforms */)));
+ return rect;
+}
+
+IntPoint FrameView::convertFromRenderer(const RenderObject* renderer, const IntPoint& rendererPoint) const
+{
+ IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, false, true /* use transforms */));
+
+ // Convert from page ("absolute") to FrameView coordinates.
+ point.move(-scrollX(), -scrollY());
+ return point;
+}
+
+IntPoint FrameView::convertToRenderer(const RenderObject* renderer, const IntPoint& viewPoint) const
+{
+ IntPoint point = viewPoint;
+
+ // Convert from FrameView coords into page ("absolute") coordinates.
+ point += IntSize(scrollX(), scrollY());
+
+ return roundedIntPoint(renderer->absoluteToLocal(point, false, true /* use transforms */));
+}
+
+IntRect FrameView::convertToContainingView(const IntRect& localRect) const
+{
+ if (const ScrollView* parentScrollView = parent()) {
+ if (parentScrollView->isFrameView()) {
+ const FrameView* parentView = static_cast<const FrameView*>(parentScrollView);
+ // Get our renderer in the parent view
+ RenderPart* renderer = m_frame->ownerRenderer();
+ if (!renderer)
+ return localRect;
+
+ IntRect rect(localRect);
+ // Add borders and padding??
+ rect.move(renderer->borderLeft() + renderer->paddingLeft(),
+ renderer->borderTop() + renderer->paddingTop());
+ return parentView->convertFromRenderer(renderer, rect);
+ }
+
+ return Widget::convertToContainingView(localRect);
+ }
+
+ return localRect;
+}
+
+IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const
+{
+ if (const ScrollView* parentScrollView = parent()) {
+ if (parentScrollView->isFrameView()) {
+ const FrameView* parentView = static_cast<const FrameView*>(parentScrollView);
+
+ // Get our renderer in the parent view
+ RenderPart* renderer = m_frame->ownerRenderer();
+ if (!renderer)
+ return parentRect;
+
+ IntRect rect = parentView->convertToRenderer(renderer, parentRect);
+ // Subtract borders and padding
+ rect.move(-renderer->borderLeft() - renderer->paddingLeft(),
+ -renderer->borderTop() - renderer->paddingTop());
+ return rect;
+ }
+
+ return Widget::convertFromContainingView(parentRect);
+ }
+
+ return parentRect;
+}
+
+IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const
+{
+ if (const ScrollView* parentScrollView = parent()) {
+ if (parentScrollView->isFrameView()) {
+ const FrameView* parentView = static_cast<const FrameView*>(parentScrollView);
+
+ // Get our renderer in the parent view
+ RenderPart* renderer = m_frame->ownerRenderer();
+ if (!renderer)
+ return localPoint;
+
+ IntPoint point(localPoint);
+
+ // Add borders and padding
+ point.move(renderer->borderLeft() + renderer->paddingLeft(),
+ renderer->borderTop() + renderer->paddingTop());
+ return parentView->convertFromRenderer(renderer, point);
+ }
+
+ return Widget::convertToContainingView(localPoint);
+ }
+
+ return localPoint;
+}
+
+IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const
+{
+ if (const ScrollView* parentScrollView = parent()) {
+ if (parentScrollView->isFrameView()) {
+ const FrameView* parentView = static_cast<const FrameView*>(parentScrollView);
+
+ // Get our renderer in the parent view
+ RenderPart* renderer = m_frame->ownerRenderer();
+ if (!renderer)
+ return parentPoint;
+
+ IntPoint point = parentView->convertToRenderer(renderer, parentPoint);
+ // Subtract borders and padding
+ point.move(-renderer->borderLeft() - renderer->paddingLeft(),
+ -renderer->borderTop() - renderer->paddingTop());
+ return point;
+ }
+
+ return Widget::convertFromContainingView(parentPoint);
+ }
+
+ return parentPoint;
+}
+
+// Normal delay
+void FrameView::setRepaintThrottlingDeferredRepaintDelay(double p)
+{
+ s_deferredRepaintDelay = p;
+}
+
+// Negative value would mean that first few repaints happen without a delay
+void FrameView::setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(double p)
+{
+ s_initialDeferredRepaintDelayDuringLoading = p;
+}
+
+// The delay grows on each repaint to this maximum value
+void FrameView::setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(double p)
+{
+ s_maxDeferredRepaintDelayDuringLoading = p;
+}
+
+// On each repaint the delay increases by this amount
+void FrameView::setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(double p)
+{
+ s_deferredRepaintDelayIncrementDuringLoading = p;
+}
+
+bool FrameView::isVerticalDocument() const
+{
+ if (!m_frame)
+ return true;
+ Document* doc = m_frame->document();
+ if (!doc)
+ return true;
+ RenderObject* renderView = doc->renderer();
+ if (!renderView)
+ return true;
+ return renderView->style()->isHorizontalWritingMode();
+}
+
+bool FrameView::isFlippedDocument() const
+{
+ if (!m_frame)
+ return false;
+ Document* doc = m_frame->document();
+ if (!doc)
+ return false;
+ RenderObject* renderView = doc->renderer();
+ if (!renderView)
+ return false;
+ return renderView->style()->isFlippedBlocksWritingMode();
+}
+
+void FrameView::notifyWidgetsInAllFrames(WidgetNotification notification)
+{
+ for (Frame* frame = m_frame.get(); frame; frame = frame->tree()->traverseNext(m_frame.get())) {
+ if (RenderView* root = frame->contentRenderer())
+ root->notifyWidgets(notification);
+ }
+}
+
+AXObjectCache* FrameView::axObjectCache() const
+{
+ if (frame() && frame()->document() && frame()->document()->axObjectCacheExists())
+ return frame()->document()->axObjectCache();
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/FrameView.h b/Source/WebCore/page/FrameView.h
new file mode 100644
index 0000000..ed45d00
--- /dev/null
+++ b/Source/WebCore/page/FrameView.h
@@ -0,0 +1,410 @@
+/*
+ Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ (C) 1998 Waldo Bastian (bastian@kde.org)
+ (C) 1998, 1999 Torben Weis (weis@kde.org)
+ (C) 1999 Lars Knoll (knoll@kde.org)
+ (C) 1999 Antti Koivisto (koivisto@kde.org)
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef FrameView_h
+#define FrameView_h
+
+#include "Frame.h"
+#include "IntSize.h"
+#include "Page.h"
+#include "RenderObject.h" // For PaintBehavior
+#include "ScrollView.h"
+#include <wtf/Forward.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class Color;
+class Event;
+class FrameViewPrivate;
+class IntRect;
+class Node;
+class PlatformMouseEvent;
+class RenderLayer;
+class RenderObject;
+class RenderEmbeddedObject;
+class RenderScrollbarPart;
+struct ScheduledEvent;
+
+template <typename T> class Timer;
+
+class FrameView : public ScrollView {
+public:
+ friend class RenderView;
+
+ static PassRefPtr<FrameView> create(Frame*);
+ static PassRefPtr<FrameView> create(Frame*, const IntSize& initialSize);
+
+ virtual ~FrameView();
+
+ virtual HostWindow* hostWindow() const;
+
+ virtual void invalidateRect(const IntRect&);
+ virtual void setFrameRect(const IntRect&);
+
+ Frame* frame() const { return m_frame.get(); }
+ void clearFrame();
+
+ int marginWidth() const { return m_margins.width(); } // -1 means default
+ int marginHeight() const { return m_margins.height(); } // -1 means default
+ void setMarginWidth(int);
+ void setMarginHeight(int);
+
+ virtual void setCanHaveScrollbars(bool);
+ void updateCanHaveScrollbars();
+
+ virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation);
+
+ virtual bool avoidScrollbarCreation() const;
+
+ virtual void setContentsSize(const IntSize&);
+
+ void layout(bool allowSubtree = true);
+ bool didFirstLayout() const;
+ void layoutTimerFired(Timer<FrameView>*);
+ void scheduleRelayout();
+ void scheduleRelayoutOfSubtree(RenderObject*);
+ void unscheduleRelayout();
+ bool layoutPending() const;
+ bool isInLayout() const { return m_inLayout; }
+
+ RenderObject* layoutRoot(bool onlyDuringLayout = false) const;
+ int layoutCount() const { return m_layoutCount; }
+
+ bool needsLayout() const;
+ void setNeedsLayout();
+
+ bool needsFullRepaint() const { return m_doFullRepaint; }
+
+#if PLATFORM(ANDROID)
+ void updatePositionedObjects();
+#endif
+
+#if USE(ACCELERATED_COMPOSITING)
+ void updateCompositingLayers();
+
+ // Called when changes to the GraphicsLayer hierarchy have to be synchronized with
+ // content rendered via the normal painting path.
+ void setNeedsOneShotDrawingSynchronization();
+#endif
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+ bool hasOverflowScroll() const { return m_hasOverflowScroll; }
+#endif
+
+ bool hasCompositedContent() const;
+ bool hasCompositedContentIncludingDescendants() const;
+ bool hasCompositingAncestor() const;
+ void enterCompositingMode();
+ bool isEnclosedInCompositingLayer() const;
+
+ // Only used with accelerated compositing, but outside the #ifdef to make linkage easier.
+ // Returns true if the sync was completed.
+ bool syncCompositingStateRecursive();
+
+ // Returns true when a paint with the PaintBehaviorFlattenCompositingLayers flag set gives
+ // a faithful representation of the content.
+ bool isSoftwareRenderable() const;
+
+ void didMoveOnscreen();
+ void willMoveOffscreen();
+
+ void resetScrollbars();
+ void detachCustomScrollbars();
+
+ void clear();
+
+ bool isTransparent() const;
+ void setTransparent(bool isTransparent);
+
+ Color baseBackgroundColor() const;
+ void setBaseBackgroundColor(Color);
+ void updateBackgroundRecursively(const Color&, bool);
+
+ bool shouldUpdateWhileOffscreen() const;
+ void setShouldUpdateWhileOffscreen(bool);
+ bool shouldUpdate(bool = false) const;
+
+ void adjustViewSize();
+
+ virtual IntRect windowClipRect(bool clipToContents = true) const;
+ IntRect windowClipRectForLayer(const RenderLayer*, bool clipToLayerContents) const;
+
+ virtual IntRect windowResizerRect() const;
+
+ void setScrollPosition(const IntPoint&);
+ void scrollPositionChangedViaPlatformWidget();
+ virtual void repaintFixedElementsAfterScrolling();
+
+ String mediaType() const;
+ void setMediaType(const String&);
+ void adjustMediaTypeForPrinting(bool printing);
+
+ void setUseSlowRepaints();
+ void setIsOverlapped(bool);
+ bool isOverlapped() const { return m_isOverlapped; }
+ bool isOverlappedIncludingAncestors() const;
+ void setContentIsOpaque(bool);
+
+ void addSlowRepaintObject();
+ void removeSlowRepaintObject();
+
+ void addFixedObject();
+ void removeFixedObject();
+
+ void beginDeferredRepaints();
+ void endDeferredRepaints();
+ void checkStopDelayingDeferredRepaints();
+ void resetDeferredRepaintDelay();
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ void updateDashboardRegions();
+#endif
+ void updateControlTints();
+
+ void restoreScrollbar();
+
+ void scheduleEvent(PassRefPtr<Event>, PassRefPtr<Node>);
+ void pauseScheduledEvents();
+ void resumeScheduledEvents();
+ void postLayoutTimerFired(Timer<FrameView>*);
+
+ bool wasScrolledByUser() const;
+ void setWasScrolledByUser(bool);
+
+ void addWidgetToUpdate(RenderEmbeddedObject*);
+ void removeWidgetToUpdate(RenderEmbeddedObject*);
+
+ virtual void paintContents(GraphicsContext*, const IntRect& damageRect);
+ void setPaintBehavior(PaintBehavior);
+ PaintBehavior paintBehavior() const;
+ bool isPainting() const;
+ void setNodeToDraw(Node*);
+
+ static double currentPaintTimeStamp() { return sCurrentPaintTimeStamp; } // returns 0 if not painting
+
+ void updateLayoutAndStyleIfNeededRecursive();
+ void flushDeferredRepaints();
+
+ void setIsVisuallyNonEmpty() { m_isVisuallyNonEmpty = true; }
+
+ void forceLayout(bool allowSubtree = false);
+ void forceLayoutForPagination(const FloatSize& pageSize, float maximumShrinkFactor, Frame::AdjustViewSizeOrNot);
+
+ // FIXME: This method is retained because of embedded WebViews in AppKit. When a WebView is embedded inside
+ // some enclosing view with auto-pagination, no call happens to resize the view. The new pagination model
+ // needs the view to resize as a result of the breaks, but that means that the enclosing view has to potentially
+ // resize around that view. Auto-pagination uses the bounds of the actual view that's being printed to determine
+ // the edges of the print operation, so the resize is necessary if the enclosing view's bounds depend on the
+ // web document's bounds.
+ //
+ // This is already a problem if the view needs to be a different size because of printer fonts or because of print stylesheets.
+ // Mail/Dictionary work around this problem by using the _layoutForPrinting SPI
+ // to at least get print stylesheets and printer fonts into play, but since WebKit doesn't know about the page offset or
+ // page size, it can't actually paginate correctly during _layoutForPrinting.
+ //
+ // We can eventually move Mail to a newer SPI that would let them opt in to the layout-time pagination model,
+ // but that doesn't solve the general problem of how other AppKit views could opt in to the better model.
+ //
+ // NO OTHER PLATFORM BESIDES MAC SHOULD USE THIS METHOD.
+ void adjustPageHeightDeprecated(float* newBottom, float oldTop, float oldBottom, float bottomLimit);
+
+ bool scrollToFragment(const KURL&);
+ bool scrollToAnchor(const String&);
+ void maintainScrollPositionAtAnchor(Node*);
+
+ // Methods to convert points and rects between the coordinate space of the renderer, and this view.
+ virtual IntRect convertFromRenderer(const RenderObject*, const IntRect&) const;
+ virtual IntRect convertToRenderer(const RenderObject*, const IntRect&) const;
+ virtual IntPoint convertFromRenderer(const RenderObject*, const IntPoint&) const;
+ virtual IntPoint convertToRenderer(const RenderObject*, const IntPoint&) const;
+
+ bool isFrameViewScrollCorner(RenderScrollbarPart* scrollCorner) const { return m_scrollCorner == scrollCorner; }
+ void invalidateScrollCorner();
+
+ 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
+ static void setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(double p);
+ // The delay grows on each repaint to this maximum value
+ static void setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(double p);
+ // On each repaint the delay increses by this amount
+ static void setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(double p);
+
+protected:
+ virtual bool scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect);
+ virtual void scrollContentsSlowPath(const IntRect& updateRect);
+
+ virtual bool isVerticalDocument() const;
+ virtual bool isFlippedDocument() const;
+
+private:
+ FrameView(Frame*);
+
+ void reset();
+ void init();
+
+ virtual bool isFrameView() const;
+
+ friend class RenderWidget;
+ bool useSlowRepaints() const;
+ bool useSlowRepaintsIfNotOverlapped() const;
+ void updateCanBlitOnScrollRecursively();
+
+ bool hasFixedObjects() const { return m_fixedObjectCount > 0; }
+
+ void applyOverflowToViewport(RenderObject*, ScrollbarMode& hMode, ScrollbarMode& vMode);
+
+ void updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow);
+
+ void dispatchScheduledEvents();
+ void performPostLayoutTasks();
+
+ virtual void repaintContentRectangle(const IntRect&, bool immediate);
+ virtual void contentsResized() { setNeedsLayout(); }
+ virtual void visibleContentsResized();
+
+ // Override ScrollView methods to do point conversion via renderers, in order to
+ // take transforms into account.
+ virtual IntRect convertToContainingView(const IntRect&) const;
+ virtual IntRect convertFromContainingView(const IntRect&) const;
+ virtual IntPoint convertToContainingView(const IntPoint&) const;
+ virtual IntPoint convertFromContainingView(const IntPoint&) const;
+
+ // ScrollBarClient interface
+ virtual void valueChanged(Scrollbar*);
+ virtual void valueChanged(const IntSize&);
+ virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&);
+ virtual bool isActive() const;
+ virtual void getTickmarks(Vector<IntRect>&) const;
+
+ void deferredRepaintTimerFired(Timer<FrameView>*);
+ void doDeferredRepaints();
+ void updateDeferredRepaintDelay();
+ double adjustedDeferredRepaintDelay() const;
+
+ bool updateWidgets();
+ void updateWidget(RenderEmbeddedObject*);
+ void scrollToAnchor();
+ void scrollPositionChanged();
+
+ bool hasCustomScrollbars() const;
+
+ virtual void updateScrollCorner();
+ virtual void paintScrollCorner(GraphicsContext*, const IntRect& cornerRect);
+
+ virtual AXObjectCache* axObjectCache() const;
+ void notifyWidgetsInAllFrames(WidgetNotification);
+
+ static double sCurrentPaintTimeStamp; // used for detecting decoded resource thrash in the cache
+
+ IntSize m_size;
+ IntSize m_margins;
+
+ typedef HashSet<RenderEmbeddedObject*> RenderEmbeddedObjectSet;
+ OwnPtr<RenderEmbeddedObjectSet> m_widgetUpdateSet;
+ RefPtr<Frame> m_frame;
+
+ bool m_doFullRepaint;
+
+ bool m_canHaveScrollbars;
+ bool m_useSlowRepaints;
+ bool m_isOverlapped;
+ bool m_contentIsOpaque;
+ unsigned m_slowRepaintObjectCount;
+ unsigned m_fixedObjectCount;
+
+ int m_borderX;
+ int m_borderY;
+
+ Timer<FrameView> m_layoutTimer;
+ bool m_delayedLayout;
+ RenderObject* m_layoutRoot;
+
+ bool m_layoutSchedulingEnabled;
+ bool m_inLayout;
+ bool m_hasPendingPostLayoutTasks;
+ bool m_inSynchronousPostLayout;
+ int m_layoutCount;
+ unsigned m_nestedLayoutCount;
+ Timer<FrameView> m_postLayoutTasksTimer;
+ bool m_firstLayoutCallbackPending;
+
+ bool m_firstLayout;
+ bool m_isTransparent;
+ Color m_baseBackgroundColor;
+ IntSize m_lastLayoutSize;
+ float m_lastZoomFactor;
+
+ String m_mediaType;
+ String m_mediaTypeWhenNotPrinting;
+
+ unsigned m_enqueueEvents;
+ Vector<ScheduledEvent*> m_scheduledEvents;
+
+ bool m_overflowStatusDirty;
+ bool m_horizontalOverflow;
+ bool m_verticalOverflow;
+ RenderObject* m_viewportRenderer;
+
+ bool m_wasScrolledByUser;
+ bool m_inProgrammaticScroll;
+
+ unsigned m_deferringRepaints;
+ unsigned m_repaintCount;
+ Vector<IntRect> m_repaintRects;
+ Timer<FrameView> m_deferredRepaintTimer;
+ double m_deferredRepaintDelay;
+ double m_lastPaintTime;
+
+ bool m_shouldUpdateWhileOffscreen;
+
+ unsigned m_deferSetNeedsLayouts;
+ bool m_setNeedsLayoutWasDeferred;
+
+ RefPtr<Node> m_nodeToDraw;
+ PaintBehavior m_paintBehavior;
+ bool m_isPainting;
+
+ bool m_isVisuallyNonEmpty;
+ bool m_firstVisuallyNonEmptyLayoutCallbackPending;
+
+ RefPtr<Node> m_maintainScrollPositionAnchor;
+
+ // Renderer to hold our custom scroll corner.
+ RenderScrollbarPart* m_scrollCorner;
+
+ static double s_deferredRepaintDelay;
+ static double s_initialDeferredRepaintDelayDuringLoading;
+ static double s_maxDeferredRepaintDelayDuringLoading;
+ static double s_deferredRepaintDelayIncrementDuringLoading;
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+ bool m_hasOverflowScroll;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // FrameView_h
diff --git a/Source/WebCore/page/Geolocation.cpp b/Source/WebCore/page/Geolocation.cpp
new file mode 100644
index 0000000..354dde3
--- /dev/null
+++ b/Source/WebCore/page/Geolocation.cpp
@@ -0,0 +1,777 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc.
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Geolocation.h"
+
+#if ENABLE(GEOLOCATION)
+
+#include "Chrome.h"
+#include "Frame.h"
+#include "Page.h"
+#if PLATFORM(ANDROID)
+#include "PlatformBridge.h"
+#endif
+#include <wtf/CurrentTime.h>
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+#include "Coordinates.h"
+#include "GeolocationController.h"
+#include "GeolocationError.h"
+#include "GeolocationPosition.h"
+#include "PositionError.h"
+#endif
+
+namespace WebCore {
+
+static const char permissionDeniedErrorMessage[] = "User denied Geolocation";
+static const char failedToStartServiceErrorMessage[] = "Failed to start Geolocation service";
+static const char framelessDocumentErrorMessage[] = "Geolocation cannot be used in frameless documents";
+
+static const int firstAvailableWatchId = 1;
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+
+static PassRefPtr<Geoposition> createGeoposition(GeolocationPosition* position)
+{
+ if (!position)
+ return 0;
+
+ RefPtr<Coordinates> coordinates = Coordinates::create(position->latitude(), position->longitude(), position->canProvideAltitude(), position->altitude(),
+ position->accuracy(), position->canProvideAltitudeAccuracy(), position->altitudeAccuracy(),
+ position->canProvideHeading(), position->heading(), position->canProvideSpeed(), position->speed());
+ return Geoposition::create(coordinates.release(), convertSecondsToDOMTimeStamp(position->timestamp()));
+}
+
+static PassRefPtr<PositionError> createPositionError(GeolocationError* error)
+{
+ PositionError::ErrorCode code = PositionError::POSITION_UNAVAILABLE;
+ switch (error->code()) {
+ case GeolocationError::PermissionDenied:
+ code = PositionError::PERMISSION_DENIED;
+ break;
+ case GeolocationError::PositionUnavailable:
+ code = PositionError::POSITION_UNAVAILABLE;
+ break;
+ }
+
+ return PositionError::create(code, error->message());
+}
+#endif
+
+Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
+ : m_geolocation(geolocation)
+ , m_successCallback(successCallback)
+ , m_errorCallback(errorCallback)
+ , m_options(options)
+ , m_timer(this, &Geolocation::GeoNotifier::timerFired)
+ , m_useCachedPosition(false)
+{
+ ASSERT(m_geolocation);
+ ASSERT(m_successCallback);
+ // If no options were supplied from JS, we should have created a default set
+ // of options in JSGeolocationCustom.cpp.
+ ASSERT(m_options);
+}
+
+void Geolocation::GeoNotifier::setFatalError(PassRefPtr<PositionError> error)
+{
+ // If a fatal error has already been set, stick with it. This makes sure that
+ // when permission is denied, this is the error reported, as required by the
+ // spec.
+ if (m_fatalError)
+ return;
+
+ m_fatalError = error;
+ // An existing timer may not have a zero timeout.
+ m_timer.stop();
+ m_timer.startOneShot(0);
+}
+
+void Geolocation::GeoNotifier::setUseCachedPosition()
+{
+ m_useCachedPosition = true;
+ m_timer.startOneShot(0);
+}
+
+bool Geolocation::GeoNotifier::hasZeroTimeout() const
+{
+ return m_options->hasTimeout() && m_options->timeout() == 0;
+}
+
+void Geolocation::GeoNotifier::runSuccessCallback(Geoposition* position)
+{
+ m_successCallback->handleEvent(position);
+}
+
+void Geolocation::GeoNotifier::startTimerIfNeeded()
+{
+ if (m_options->hasTimeout())
+ m_timer.startOneShot(m_options->timeout() / 1000.0);
+}
+
+void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*)
+{
+ m_timer.stop();
+
+ // Protect this GeoNotifier object, since it
+ // could be deleted by a call to clearWatch in a callback.
+ RefPtr<GeoNotifier> protect(this);
+
+ // Test for fatal error first. This is required for the case where the Frame is
+ // disconnected and requests are cancelled.
+ if (m_fatalError) {
+ if (m_errorCallback)
+ m_errorCallback->handleEvent(m_fatalError.get());
+ // This will cause this notifier to be deleted.
+ m_geolocation->fatalErrorOccurred(this);
+ return;
+ }
+
+ if (m_useCachedPosition) {
+ // Clear the cached position flag in case this is a watch request, which
+ // will continue to run.
+ m_useCachedPosition = false;
+ m_geolocation->requestUsesCachedPosition(this);
+ return;
+ }
+
+ if (m_errorCallback) {
+ RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timeout expired");
+ m_errorCallback->handleEvent(error.get());
+ }
+ m_geolocation->requestTimedOut(this);
+}
+
+void Geolocation::Watchers::set(int id, PassRefPtr<GeoNotifier> prpNotifier)
+{
+ ASSERT(id > 0);
+ RefPtr<GeoNotifier> notifier = prpNotifier;
+
+ m_idToNotifierMap.set(id, notifier.get());
+ m_notifierToIdMap.set(notifier.release(), id);
+}
+
+void Geolocation::Watchers::remove(int id)
+{
+ ASSERT(id > 0);
+ IdToNotifierMap::iterator iter = m_idToNotifierMap.find(id);
+ if (iter == m_idToNotifierMap.end())
+ return;
+ m_notifierToIdMap.remove(iter->second);
+ m_idToNotifierMap.remove(iter);
+}
+
+void Geolocation::Watchers::remove(GeoNotifier* notifier)
+{
+ NotifierToIdMap::iterator iter = m_notifierToIdMap.find(notifier);
+ if (iter == m_notifierToIdMap.end())
+ return;
+ m_idToNotifierMap.remove(iter->second);
+ m_notifierToIdMap.remove(iter);
+}
+
+bool Geolocation::Watchers::contains(GeoNotifier* notifier) const
+{
+ return m_notifierToIdMap.contains(notifier);
+}
+
+void Geolocation::Watchers::clear()
+{
+ m_idToNotifierMap.clear();
+ m_notifierToIdMap.clear();
+}
+
+bool Geolocation::Watchers::isEmpty() const
+{
+ return m_idToNotifierMap.isEmpty();
+}
+
+void Geolocation::Watchers::getNotifiersVector(GeoNotifierVector& copy) const
+{
+ copyValuesToVector(m_idToNotifierMap, copy);
+}
+
+Geolocation::Geolocation(Frame* frame)
+ : m_frame(frame)
+#if !ENABLE(CLIENT_BASED_GEOLOCATION)
+ , m_service(GeolocationService::create(this))
+#endif
+ , m_allowGeolocation(Unknown)
+{
+ if (!m_frame)
+ return;
+ ASSERT(m_frame->document());
+ m_frame->document()->setUsingGeolocation(true);
+}
+
+Geolocation::~Geolocation()
+{
+}
+
+void Geolocation::disconnectFrame()
+{
+ if (m_frame && m_frame->page() && m_allowGeolocation == InProgress) {
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ m_frame->page()->geolocationController()->cancelPermissionRequest(this);
+#else
+ m_frame->page()->chrome()->cancelGeolocationPermissionRequestForFrame(m_frame, this);
+#endif
+ }
+ cancelAllRequests();
+ stopUpdating();
+ if (m_frame && m_frame->document())
+ m_frame->document()->setUsingGeolocation(false);
+ m_frame = 0;
+}
+
+Geoposition* Geolocation::lastPosition()
+{
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ if (!m_frame)
+ return 0;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return 0;
+
+ m_lastPosition = createGeoposition(page->geolocationController()->lastPosition());
+#else
+ m_lastPosition = m_service->lastPosition();
+#endif
+
+ return m_lastPosition.get();
+}
+
+void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
+{
+ if (!m_frame)
+ return;
+
+ RefPtr<GeoNotifier> notifier = startRequest(successCallback, errorCallback, options);
+ ASSERT(notifier);
+
+ m_oneShots.add(notifier);
+}
+
+int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
+{
+ if (!m_frame)
+ return 0;
+
+ RefPtr<GeoNotifier> notifier = startRequest(successCallback, errorCallback, options);
+ ASSERT(notifier);
+
+ static int nextAvailableWatchId = firstAvailableWatchId;
+ // In case of overflow, make sure the ID remains positive, but reuse the ID values.
+ if (nextAvailableWatchId < 1)
+ nextAvailableWatchId = 1;
+ m_watchers.set(nextAvailableWatchId, notifier.release());
+ return nextAvailableWatchId++;
+}
+
+PassRefPtr<Geolocation::GeoNotifier> Geolocation::startRequest(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options)
+{
+ RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options);
+
+ // Check whether permissions have already been denied. Note that if this is the case,
+ // the permission state can not change again in the lifetime of this page.
+ if (isDenied())
+ notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage));
+ else if (haveSuitableCachedPosition(notifier->m_options.get()))
+ notifier->setUseCachedPosition();
+ else if (notifier->hasZeroTimeout())
+ notifier->startTimerIfNeeded();
+#if USE(PREEMPT_GEOLOCATION_PERMISSION)
+ else if (!isAllowed()) {
+ // if we don't yet have permission, request for permission before calling startUpdating()
+ m_pendingForPermissionNotifiers.add(notifier);
+ requestPermission();
+ }
+#endif
+ else if (startUpdating(notifier.get()))
+ notifier->startTimerIfNeeded();
+ else
+ notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage));
+
+ return notifier.release();
+}
+
+void Geolocation::fatalErrorOccurred(Geolocation::GeoNotifier* notifier)
+{
+ // This request has failed fatally. Remove it from our lists.
+ m_oneShots.remove(notifier);
+ m_watchers.remove(notifier);
+
+ if (!hasListeners())
+ stopUpdating();
+}
+
+void Geolocation::requestUsesCachedPosition(GeoNotifier* notifier)
+{
+ // This is called asynchronously, so the permissions could have been denied
+ // since we last checked in startRequest.
+ if (isDenied()) {
+ notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage));
+ return;
+ }
+
+ m_requestsAwaitingCachedPosition.add(notifier);
+
+ // If permissions are allowed, make the callback
+ if (isAllowed()) {
+ makeCachedPositionCallbacks();
+ return;
+ }
+
+ // Request permissions, which may be synchronous or asynchronous.
+ requestPermission();
+}
+
+void Geolocation::makeCachedPositionCallbacks()
+{
+ // All modifications to m_requestsAwaitingCachedPosition are done
+ // asynchronously, so we don't need to worry about it being modified from
+ // the callbacks.
+ GeoNotifierSet::const_iterator end = m_requestsAwaitingCachedPosition.end();
+ for (GeoNotifierSet::const_iterator iter = m_requestsAwaitingCachedPosition.begin(); iter != end; ++iter) {
+ GeoNotifier* notifier = iter->get();
+ notifier->runSuccessCallback(m_positionCache.cachedPosition());
+
+ // If this is a one-shot request, stop it. Otherwise, if the watch still
+ // exists, start the service to get updates.
+ if (m_oneShots.contains(notifier))
+ m_oneShots.remove(notifier);
+ else if (m_watchers.contains(notifier)) {
+ if (notifier->hasZeroTimeout() || startUpdating(notifier))
+ notifier->startTimerIfNeeded();
+ else
+ notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage));
+ }
+ }
+
+ m_requestsAwaitingCachedPosition.clear();
+
+ if (!hasListeners())
+ stopUpdating();
+}
+
+void Geolocation::requestTimedOut(GeoNotifier* notifier)
+{
+ // If this is a one-shot request, stop it.
+ m_oneShots.remove(notifier);
+
+ if (!hasListeners())
+ stopUpdating();
+}
+
+bool Geolocation::haveSuitableCachedPosition(PositionOptions* options)
+{
+ if (!m_positionCache.cachedPosition())
+ return false;
+ if (!options->hasMaximumAge())
+ return true;
+ if (!options->maximumAge())
+ return false;
+ DOMTimeStamp currentTimeMillis = convertSecondsToDOMTimeStamp(currentTime());
+ return m_positionCache.cachedPosition()->timestamp() > currentTimeMillis - options->maximumAge();
+}
+
+void Geolocation::clearWatch(int watchId)
+{
+ if (watchId < firstAvailableWatchId)
+ return;
+
+ m_watchers.remove(watchId);
+
+ if (!hasListeners())
+ stopUpdating();
+}
+
+void Geolocation::suspend()
+{
+#if !ENABLE(CLIENT_BASED_GEOLOCATION)
+ if (hasListeners())
+ m_service->suspend();
+#endif
+}
+
+void Geolocation::resume()
+{
+#if !ENABLE(CLIENT_BASED_GEOLOCATION)
+ if (hasListeners())
+ m_service->resume();
+#endif
+}
+
+void Geolocation::setIsAllowed(bool allowed)
+{
+ // This may be due to either a new position from the service, or a cached
+ // position.
+ m_allowGeolocation = allowed ? Yes : No;
+
+#if USE(PREEMPT_GEOLOCATION_PERMISSION)
+ // Permission request was made during the startRequest process
+ if (!m_pendingForPermissionNotifiers.isEmpty()) {
+ handlePendingPermissionNotifiers();
+ m_pendingForPermissionNotifiers.clear();
+ return;
+ }
+#endif
+
+ if (!isAllowed()) {
+ RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage);
+ error->setIsFatal(true);
+ handleError(error.get());
+ m_requestsAwaitingCachedPosition.clear();
+ return;
+ }
+
+ // If the service has a last position, use it to call back for all requests.
+ // If any of the requests are waiting for permission for a cached position,
+ // the position from the service will be at least as fresh.
+ if (lastPosition())
+ makeSuccessCallbacks();
+ else
+ makeCachedPositionCallbacks();
+}
+
+void Geolocation::sendError(GeoNotifierVector& notifiers, PositionError* error)
+{
+ GeoNotifierVector::const_iterator end = notifiers.end();
+ for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it) {
+ RefPtr<GeoNotifier> notifier = *it;
+
+ if (notifier->m_errorCallback)
+ notifier->m_errorCallback->handleEvent(error);
+ }
+}
+
+void Geolocation::sendPosition(GeoNotifierVector& notifiers, Geoposition* position)
+{
+ GeoNotifierVector::const_iterator end = notifiers.end();
+ for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it) {
+ RefPtr<GeoNotifier> notifier = *it;
+ ASSERT(notifier->m_successCallback);
+
+ notifier->m_successCallback->handleEvent(position);
+ }
+}
+
+void Geolocation::stopTimer(GeoNotifierVector& notifiers)
+{
+ GeoNotifierVector::const_iterator end = notifiers.end();
+ for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it) {
+ RefPtr<GeoNotifier> notifier = *it;
+ notifier->m_timer.stop();
+ }
+}
+
+void Geolocation::stopTimersForOneShots()
+{
+ GeoNotifierVector copy;
+ copyToVector(m_oneShots, copy);
+
+ stopTimer(copy);
+}
+
+void Geolocation::stopTimersForWatchers()
+{
+ GeoNotifierVector copy;
+ m_watchers.getNotifiersVector(copy);
+
+ stopTimer(copy);
+}
+
+void Geolocation::stopTimers()
+{
+ stopTimersForOneShots();
+ stopTimersForWatchers();
+}
+
+void Geolocation::cancelRequests(GeoNotifierVector& notifiers)
+{
+ GeoNotifierVector::const_iterator end = notifiers.end();
+ for (GeoNotifierVector::const_iterator it = notifiers.begin(); it != end; ++it)
+ (*it)->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, framelessDocumentErrorMessage));
+}
+
+void Geolocation::cancelAllRequests()
+{
+ GeoNotifierVector copy;
+ copyToVector(m_oneShots, copy);
+ cancelRequests(copy);
+ m_watchers.getNotifiersVector(copy);
+ 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);
+
+ GeoNotifierVector oneShotsCopy;
+ copyToVector(m_oneShots, oneShotsCopy);
+
+ GeoNotifierVector watchersCopy;
+ m_watchers.getNotifiersVector(watchersCopy);
+
+ // Clear the lists before we make the callbacks, to avoid clearing notifiers
+ // added by calls to Geolocation methods from the callbacks, 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()
+{
+ if (m_allowGeolocation > Unknown)
+ return;
+
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ m_allowGeolocation = InProgress;
+
+ // Ask the embedder: it maintains the geolocation challenge policy itself.
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ page->geolocationController()->requestPermission(this);
+#else
+ page->chrome()->requestGeolocationPermissionForFrame(m_frame, this);
+#endif
+}
+
+void Geolocation::positionChangedInternal()
+{
+ m_positionCache.setCachedPosition(lastPosition());
+
+ // Stop all currently running timers.
+ stopTimers();
+
+ if (!isAllowed()) {
+ // requestPermission() will ask the chrome for permission. This may be
+ // implemented synchronously or asynchronously. In both cases,
+ // makeSuccessCallbacks() will be called if permission is granted, so
+ // there's nothing more to do here.
+ requestPermission();
+ return;
+ }
+
+ makeSuccessCallbacks();
+}
+
+void Geolocation::makeSuccessCallbacks()
+{
+ ASSERT(lastPosition());
+ ASSERT(isAllowed());
+
+ GeoNotifierVector oneShotsCopy;
+ copyToVector(m_oneShots, oneShotsCopy);
+
+ GeoNotifierVector watchersCopy;
+ m_watchers.getNotifiersVector(watchersCopy);
+
+ // Clear the lists before we make the callbacks, to avoid clearing notifiers
+ // added by calls to Geolocation methods from the callbacks, and to prevent
+ // further callbacks to these notifiers.
+ m_oneShots.clear();
+
+ sendPosition(oneShotsCopy, lastPosition());
+ sendPosition(watchersCopy, lastPosition());
+
+ if (!hasListeners())
+ stopUpdating();
+}
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+
+void Geolocation::positionChanged()
+{
+ positionChangedInternal();
+}
+
+void Geolocation::setError(GeolocationError* error)
+{
+ RefPtr<PositionError> positionError = createPositionError(error);
+ handleError(positionError.get());
+}
+
+#else
+
+void Geolocation::geolocationServicePositionChanged(GeolocationService* service)
+{
+ ASSERT_UNUSED(service, service == m_service);
+ ASSERT(m_service->lastPosition());
+
+ positionChangedInternal();
+}
+
+void Geolocation::geolocationServiceErrorOccurred(GeolocationService* service)
+{
+ ASSERT(service->lastError());
+
+ // Note that we do not stop timers here. For one-shots, the request is
+ // cleared in handleError. For watchers, the spec requires that the timer is
+ // not cleared.
+ handleError(service->lastError());
+}
+
+#endif
+
+bool Geolocation::startUpdating(GeoNotifier* notifier)
+{
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ if (!m_frame)
+ return false;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return false;
+
+ page->geolocationController()->addObserver(this, notifier->m_options->enableHighAccuracy());
+ return true;
+#else
+#if PLATFORM(ANDROID)
+ // TODO: Upstream to webkit.org. See https://bugs.webkit.org/show_bug.cgi?id=34082
+ // Note that the correct fix is to use a 'paused' flag in WebCore, rather
+ // than calling into PlatformBridge.
+ if (!m_frame)
+ return false;
+ FrameView* view = m_frame->view();
+ if (!view)
+ return false;
+ return m_service->startUpdating(notifier->m_options.get(), PlatformBridge::isWebViewPaused(view));
+#else
+ return m_service->startUpdating(notifier->m_options.get());
+#endif
+#endif
+}
+
+void Geolocation::stopUpdating()
+{
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ page->geolocationController()->removeObserver(this);
+#else
+ m_service->stopUpdating();
+#endif
+
+}
+
+#if USE(PREEMPT_GEOLOCATION_PERMISSION)
+void Geolocation::handlePendingPermissionNotifiers()
+{
+ // While we iterate through the list, we need not worry about list being modified as the permission
+ // is already set to Yes/No and no new listeners will be added to the pending list
+ GeoNotifierSet::const_iterator end = m_pendingForPermissionNotifiers.end();
+ for (GeoNotifierSet::const_iterator iter = m_pendingForPermissionNotifiers.begin(); iter != end; ++iter) {
+ GeoNotifier* notifier = iter->get();
+
+ if (isAllowed()) {
+ // start all pending notification requests as permission granted.
+ // The notifier is always ref'ed by m_oneShots or m_watchers.
+ if (startUpdating(notifier))
+ notifier->startTimerIfNeeded();
+ else
+ notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage));
+ } else
+ notifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage));
+ }
+}
+#endif
+
+} // namespace WebCore
+
+#else
+
+namespace WebCore {
+
+void Geolocation::clearWatch(int) {}
+
+void Geolocation::disconnectFrame() {}
+
+Geolocation::Geolocation(Frame*) {}
+
+Geolocation::~Geolocation() {}
+
+void Geolocation::setIsAllowed(bool) {}
+
+}
+
+#endif // ENABLE(GEOLOCATION)
diff --git a/Source/WebCore/page/Geolocation.h b/Source/WebCore/page/Geolocation.h
new file mode 100644
index 0000000..d53c827
--- /dev/null
+++ b/Source/WebCore/page/Geolocation.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Geolocation_h
+#define Geolocation_h
+
+#include "GeolocationPositionCache.h"
+#include "Geoposition.h"
+#include "PositionCallback.h"
+#include "PositionError.h"
+#include "PositionErrorCallback.h"
+#include "PositionOptions.h"
+#include "Timer.h"
+
+#if !ENABLE(CLIENT_BASED_GEOLOCATION)
+#include "GeolocationService.h"
+#endif
+
+namespace WebCore {
+
+class Frame;
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+class GeolocationPosition;
+class GeolocationError;
+#endif
+
+class Geolocation : public RefCounted<Geolocation>
+#if !ENABLE(CLIENT_BASED_GEOLOCATION) && ENABLE(GEOLOCATION)
+ , public GeolocationServiceClient
+#endif
+{
+public:
+ static PassRefPtr<Geolocation> create(Frame* frame) { return adoptRef(new Geolocation(frame)); }
+
+ ~Geolocation();
+
+ void disconnectFrame();
+
+ void getCurrentPosition(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
+ int watchPosition(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
+ void clearWatch(int watchId);
+
+ // These methods are used by Android.
+ void suspend();
+ void resume();
+
+ void setIsAllowed(bool);
+ Frame* frame() const { return m_frame; }
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ void positionChanged();
+ void setError(GeolocationError*);
+#else
+ GeolocationService* getGeolocationService() const { return m_service.get(); }
+#endif
+
+private:
+ Geoposition* lastPosition();
+
+ bool isAllowed() const { return m_allowGeolocation == Yes; }
+ bool isDenied() const { return m_allowGeolocation == No; }
+
+ Geolocation(Frame*);
+
+ class GeoNotifier : public RefCounted<GeoNotifier> {
+ public:
+ static PassRefPtr<GeoNotifier> create(Geolocation* geolocation, PassRefPtr<PositionCallback> positionCallback, PassRefPtr<PositionErrorCallback> positionErrorCallback, PassRefPtr<PositionOptions> options) { return adoptRef(new GeoNotifier(geolocation, positionCallback, positionErrorCallback, options)); }
+
+ void setFatalError(PassRefPtr<PositionError>);
+ bool hasZeroTimeout() const;
+ void setUseCachedPosition();
+ void runSuccessCallback(Geoposition*);
+ void startTimerIfNeeded();
+ void timerFired(Timer<GeoNotifier>*);
+
+ Geolocation* m_geolocation;
+ RefPtr<PositionCallback> m_successCallback;
+ RefPtr<PositionErrorCallback> m_errorCallback;
+ RefPtr<PositionOptions> m_options;
+ Timer<GeoNotifier> m_timer;
+ RefPtr<PositionError> m_fatalError;
+ bool m_useCachedPosition;
+
+ private:
+ GeoNotifier(Geolocation*, PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
+ };
+
+ typedef Vector<RefPtr<GeoNotifier> > GeoNotifierVector;
+ typedef HashSet<RefPtr<GeoNotifier> > GeoNotifierSet;
+
+ class Watchers {
+ public:
+ void set(int id, PassRefPtr<GeoNotifier>);
+ void remove(int id);
+ void remove(GeoNotifier*);
+ bool contains(GeoNotifier*) const;
+ void clear();
+ bool isEmpty() const;
+ void getNotifiersVector(GeoNotifierVector&) const;
+ private:
+ typedef HashMap<int, RefPtr<GeoNotifier> > IdToNotifierMap;
+ typedef HashMap<RefPtr<GeoNotifier>, int> NotifierToIdMap;
+ IdToNotifierMap m_idToNotifierMap;
+ NotifierToIdMap m_notifierToIdMap;
+ };
+
+ class PositionCacheWrapper {
+ public:
+ PositionCacheWrapper()
+ : m_cache(GeolocationPositionCache::instance())
+ {
+ m_cache->addUser();
+ }
+ ~PositionCacheWrapper()
+ {
+ m_cache->removeUser();
+ }
+ void setCachedPosition(Geoposition* cachedPosition) { m_cache->setCachedPosition(cachedPosition); }
+ Geoposition* cachedPosition() { return m_cache->cachedPosition(); }
+ private:
+ GeolocationPositionCache* m_cache;
+ };
+
+ bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); }
+
+ 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();
+ void stopTimers();
+
+ void cancelRequests(GeoNotifierVector&);
+ void cancelAllRequests();
+
+ void positionChangedInternal();
+ void makeSuccessCallbacks();
+ void handleError(PositionError*);
+
+ void requestPermission();
+
+ bool startUpdating(GeoNotifier*);
+ void stopUpdating();
+
+#if USE(PREEMPT_GEOLOCATION_PERMISSION)
+ void handlePendingPermissionNotifiers();
+#endif
+
+#if !ENABLE(CLIENT_BASED_GEOLOCATION) && ENABLE(GEOLOCATION)
+ // GeolocationServiceClient
+ virtual void geolocationServicePositionChanged(GeolocationService*);
+ virtual void geolocationServiceErrorOccurred(GeolocationService*);
+#endif
+
+ PassRefPtr<GeoNotifier> startRequest(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>);
+
+ void fatalErrorOccurred(GeoNotifier*);
+ void requestTimedOut(GeoNotifier*);
+ void requestUsesCachedPosition(GeoNotifier*);
+ bool haveSuitableCachedPosition(PositionOptions*);
+ void makeCachedPositionCallbacks();
+
+ GeoNotifierSet m_oneShots;
+ Watchers m_watchers;
+ Frame* m_frame;
+#if !ENABLE(CLIENT_BASED_GEOLOCATION)
+ OwnPtr<GeolocationService> m_service;
+#endif
+#if USE(PREEMPT_GEOLOCATION_PERMISSION)
+ GeoNotifierSet m_pendingForPermissionNotifiers;
+#endif
+ RefPtr<Geoposition> m_lastPosition;
+
+ enum {
+ Unknown,
+ InProgress,
+ Yes,
+ No
+ } m_allowGeolocation;
+
+#if ENABLE(GEOLOCATION)
+ PositionCacheWrapper m_positionCache;
+#endif
+ GeoNotifierSet m_requestsAwaitingCachedPosition;
+};
+
+} // namespace WebCore
+
+#endif // Geolocation_h
diff --git a/Source/WebCore/page/Geolocation.idl b/Source/WebCore/page/Geolocation.idl
new file mode 100644
index 0000000..aa5b59f
--- /dev/null
+++ b/Source/WebCore/page/Geolocation.idl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module core {
+
+ interface [Conditional=GEOLOCATION, OmitConstructor] Geolocation {
+ [Custom] void getCurrentPosition(in PositionCallback successCallback, in PositionErrorCallback errorCallback, in PositionOptions options);
+
+ [Custom] long watchPosition(in PositionCallback successCallback, in PositionErrorCallback errorCallback, in PositionOptions options);
+
+ void clearWatch(in long watchId);
+ };
+
+}
diff --git a/Source/WebCore/page/GeolocationClient.h b/Source/WebCore/page/GeolocationClient.h
new file mode 100644
index 0000000..44cb909
--- /dev/null
+++ b/Source/WebCore/page/GeolocationClient.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 GeolocationClient_h
+#define GeolocationClient_h
+
+namespace WebCore {
+
+class Geolocation;
+class GeolocationPosition;
+
+class GeolocationClient {
+public:
+ virtual void geolocationDestroyed() = 0;
+
+ virtual void startUpdating() = 0;
+ virtual void stopUpdating() = 0;
+ // FIXME: The V2 Geolocation specification proposes that this property is
+ // renamed. See http://www.w3.org/2008/geolocation/track/issues/6
+ // We should update WebKit to reflect this if and when the V2 specification
+ // is published.
+ virtual void setEnableHighAccuracy(bool) = 0;
+ virtual GeolocationPosition* lastPosition() = 0;
+
+ virtual void requestPermission(Geolocation*) = 0;
+ virtual void cancelPermissionRequest(Geolocation*) = 0;
+
+protected:
+ virtual ~GeolocationClient() { }
+};
+
+} // namespace WebCore
+
+#endif // GeolocationClient_h
diff --git a/Source/WebCore/page/GeolocationController.cpp b/Source/WebCore/page/GeolocationController.cpp
new file mode 100644
index 0000000..28d522d
--- /dev/null
+++ b/Source/WebCore/page/GeolocationController.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "GeolocationController.h"
+#include "GeolocationPosition.h"
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+
+#include "GeolocationClient.h"
+
+namespace WebCore {
+
+GeolocationController::GeolocationController(Page* page, GeolocationClient* client)
+ : m_page(page)
+ , m_client(client)
+{
+}
+
+GeolocationController::~GeolocationController()
+{
+ if (m_client)
+ m_client->geolocationDestroyed();
+}
+
+void GeolocationController::addObserver(Geolocation* observer, bool enableHighAccuracy)
+{
+ // This may be called multiple times with the same observer, though removeObserver()
+ // is called only once with each.
+ bool wasEmpty = m_observers.isEmpty();
+ m_observers.add(observer);
+ if (enableHighAccuracy)
+ m_highAccuracyObservers.add(observer);
+
+ if (m_client) {
+ if (enableHighAccuracy)
+ m_client->setEnableHighAccuracy(true);
+ if (wasEmpty)
+ m_client->startUpdating();
+ }
+}
+
+void GeolocationController::removeObserver(Geolocation* observer)
+{
+ if (!m_observers.contains(observer))
+ return;
+
+ m_observers.remove(observer);
+ m_highAccuracyObservers.remove(observer);
+
+ if (m_client) {
+ if (m_observers.isEmpty())
+ m_client->stopUpdating();
+ else if (m_highAccuracyObservers.isEmpty())
+ m_client->setEnableHighAccuracy(false);
+ }
+}
+
+void GeolocationController::requestPermission(Geolocation* geolocation)
+{
+ if (m_client)
+ m_client->requestPermission(geolocation);
+}
+
+void GeolocationController::cancelPermissionRequest(Geolocation* geolocation)
+{
+ if (m_client)
+ m_client->cancelPermissionRequest(geolocation);
+}
+
+void GeolocationController::positionChanged(GeolocationPosition* position)
+{
+ m_lastPosition = position;
+ Vector<RefPtr<Geolocation> > observersVector;
+ copyToVector(m_observers, observersVector);
+ for (size_t i = 0; i < observersVector.size(); ++i)
+ observersVector[i]->positionChanged();
+}
+
+void GeolocationController::errorOccurred(GeolocationError* error)
+{
+ Vector<RefPtr<Geolocation> > observersVector;
+ copyToVector(m_observers, observersVector);
+ for (size_t i = 0; i < observersVector.size(); ++i)
+ observersVector[i]->setError(error);
+}
+
+GeolocationPosition* GeolocationController::lastPosition()
+{
+ if (m_lastPosition.get())
+ return m_lastPosition.get();
+
+ if (!m_client)
+ return 0;
+
+ return m_client->lastPosition();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(CLIENT_BASED_GEOLOCATION)
diff --git a/Source/WebCore/page/GeolocationController.h b/Source/WebCore/page/GeolocationController.h
new file mode 100644
index 0000000..7db1951
--- /dev/null
+++ b/Source/WebCore/page/GeolocationController.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 GeolocationController_h
+#define GeolocationController_h
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+
+#include "Geolocation.h"
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class GeolocationClient;
+class GeolocationError;
+class GeolocationPosition;
+class Page;
+
+class GeolocationController : public Noncopyable {
+public:
+ GeolocationController(Page*, GeolocationClient*);
+ ~GeolocationController();
+
+ void addObserver(Geolocation*, bool enableHighAccuracy);
+ void removeObserver(Geolocation*);
+
+ void requestPermission(Geolocation*);
+ void cancelPermissionRequest(Geolocation*);
+
+ void positionChanged(GeolocationPosition*);
+ void errorOccurred(GeolocationError*);
+
+ GeolocationPosition* lastPosition();
+
+private:
+ Page* m_page;
+ GeolocationClient* m_client;
+
+ RefPtr<GeolocationPosition> m_lastPosition;
+ typedef HashSet<RefPtr<Geolocation> > ObserversSet;
+ // All observers; both those requesting high accuracy and those not.
+ ObserversSet m_observers;
+ ObserversSet m_highAccuracyObservers;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(CLIENT_BASED_GEOLOCATION)
+
+#endif // GeolocationController_h
diff --git a/Source/WebCore/page/GeolocationError.h b/Source/WebCore/page/GeolocationError.h
new file mode 100644
index 0000000..2a3bad4
--- /dev/null
+++ b/Source/WebCore/page/GeolocationError.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 GeolocationError_h
+#define GeolocationError_h
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class GeolocationError : public RefCounted<GeolocationError> {
+public:
+ enum ErrorCode {
+ PermissionDenied,
+ PositionUnavailable
+ };
+
+ static PassRefPtr<GeolocationError> create(ErrorCode code, const String& message) { return adoptRef(new GeolocationError(code, message)); }
+
+ ErrorCode code() const { return m_code; }
+ const String& message() const { return m_message; }
+
+private:
+ GeolocationError(ErrorCode code, const String& message)
+ : m_code(code)
+ , m_message(message)
+ {
+ }
+
+ ErrorCode m_code;
+ String m_message;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(CLIENT_BASED_GEOLOCATION)
+
+#endif // GeolocationError_h
diff --git a/Source/WebCore/page/GeolocationPosition.h b/Source/WebCore/page/GeolocationPosition.h
new file mode 100644
index 0000000..9f25b11
--- /dev/null
+++ b/Source/WebCore/page/GeolocationPosition.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 GeolocationPosition_h
+#define GeolocationPosition_h
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class GeolocationPosition : public RefCounted<GeolocationPosition> {
+public:
+ static PassRefPtr<GeolocationPosition> create(double timestamp, double latitude, double longitude, double accuracy) { return adoptRef(new GeolocationPosition(timestamp, latitude, longitude, accuracy)); }
+
+ static PassRefPtr<GeolocationPosition> create(double timestamp, double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed) { return adoptRef(new GeolocationPosition(timestamp, latitude, longitude, accuracy, providesAltitude, altitude, providesAltitudeAccuracy, altitudeAccuracy, providesHeading, heading, providesSpeed, speed)); }
+
+ double timestamp() const { return m_timestamp; }
+
+ double latitude() const { return m_latitude; }
+ double longitude() const { return m_longitude; }
+ double accuracy() const { return m_accuracy; }
+ double altitude() const { return m_altitude; }
+ double altitudeAccuracy() const { return m_altitudeAccuracy; }
+ double heading() const { return m_heading; }
+ double speed() const { return m_speed; }
+
+ bool canProvideAltitude() const { return m_canProvideAltitude; }
+ bool canProvideAltitudeAccuracy() const { return m_canProvideAltitudeAccuracy; }
+ bool canProvideHeading() const { return m_canProvideHeading; }
+ bool canProvideSpeed() const { return m_canProvideSpeed; }
+
+private:
+ GeolocationPosition(double timestamp, double latitude, double longitude, double accuracy)
+ : m_timestamp(timestamp)
+ , m_latitude(latitude)
+ , m_longitude(longitude)
+ , m_accuracy(accuracy)
+ , m_altitude(0)
+ , m_altitudeAccuracy(0)
+ , m_heading(0)
+ , m_speed(0)
+ , m_canProvideAltitude(false)
+ , m_canProvideAltitudeAccuracy(false)
+ , m_canProvideHeading(false)
+ , m_canProvideSpeed(false)
+ {
+ }
+
+ GeolocationPosition(double timestamp, double latitude, double longitude, double accuracy, bool providesAltitude, double altitude, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed)
+ : m_timestamp(timestamp)
+ , m_latitude(latitude)
+ , m_longitude(longitude)
+ , m_accuracy(accuracy)
+ , m_altitude(altitude)
+ , m_altitudeAccuracy(altitudeAccuracy)
+ , m_heading(heading)
+ , m_speed(speed)
+ , m_canProvideAltitude(providesAltitude)
+ , m_canProvideAltitudeAccuracy(providesAltitudeAccuracy)
+ , m_canProvideHeading(providesHeading)
+ , m_canProvideSpeed(providesSpeed)
+ {
+ }
+
+ double m_timestamp;
+
+ double m_latitude;
+ double m_longitude;
+ double m_accuracy;
+ double m_altitude;
+ double m_altitudeAccuracy;
+ double m_heading;
+ double m_speed;
+
+ bool m_canProvideAltitude;
+ bool m_canProvideAltitudeAccuracy;
+ bool m_canProvideHeading;
+ bool m_canProvideSpeed;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(CLIENT_BASED_GEOLOCATION)
+
+#endif // GeolocationPosition_h
diff --git a/Source/WebCore/page/GeolocationPositionCache.cpp b/Source/WebCore/page/GeolocationPositionCache.cpp
new file mode 100644
index 0000000..5a0f42d
--- /dev/null
+++ b/Source/WebCore/page/GeolocationPositionCache.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 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 "GeolocationPositionCache.h"
+
+#if ENABLE(GEOLOCATION)
+
+#include "CrossThreadTask.h"
+#include "Geoposition.h"
+#include "SQLValue.h"
+#include "SQLiteDatabase.h"
+#include "SQLiteFileSystem.h"
+#include "SQLiteStatement.h"
+#include "SQLiteTransaction.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Threading.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+static int numUsers = 0;
+
+GeolocationPositionCache* GeolocationPositionCache::instance()
+{
+ DEFINE_STATIC_LOCAL(GeolocationPositionCache*, instance, (0));
+ if (!instance)
+ instance = new GeolocationPositionCache();
+ return instance;
+}
+
+GeolocationPositionCache::GeolocationPositionCache()
+ : m_threadId(0)
+{
+}
+
+void GeolocationPositionCache::addUser()
+{
+ ASSERT(numUsers >= 0);
+ MutexLocker databaseLock(m_databaseFileMutex);
+ if (!numUsers && !m_threadId && !m_databaseFile.isNull()) {
+ startBackgroundThread();
+ MutexLocker lock(m_cachedPositionMutex);
+ if (!m_cachedPosition)
+ triggerReadFromDatabase();
+ }
+ ++numUsers;
+}
+
+void GeolocationPositionCache::removeUser()
+{
+ MutexLocker lock(m_cachedPositionMutex);
+ --numUsers;
+ ASSERT(numUsers >= 0);
+ if (!numUsers && m_cachedPosition && m_threadId)
+ triggerWriteToDatabase();
+}
+
+void GeolocationPositionCache::setDatabasePath(const String& path)
+{
+ static const char* databaseName = "CachedGeoposition.db";
+ String newFile = SQLiteFileSystem::appendDatabaseFileNameToPath(path, databaseName);
+ MutexLocker lock(m_databaseFileMutex);
+ if (m_databaseFile != newFile) {
+ m_databaseFile = newFile;
+ if (numUsers && !m_threadId) {
+ startBackgroundThread();
+ if (!m_cachedPosition)
+ triggerReadFromDatabase();
+ }
+ }
+}
+
+void GeolocationPositionCache::setCachedPosition(Geoposition* cachedPosition)
+{
+ MutexLocker lock(m_cachedPositionMutex);
+ m_cachedPosition = cachedPosition;
+}
+
+Geoposition* GeolocationPositionCache::cachedPosition()
+{
+ MutexLocker lock(m_cachedPositionMutex);
+ return m_cachedPosition.get();
+}
+
+void GeolocationPositionCache::startBackgroundThread()
+{
+ // FIXME: Consider sharing this thread with other background tasks.
+ m_threadId = createThread(threadEntryPoint, this, "WebCore: Geolocation cache");
+}
+
+void* GeolocationPositionCache::threadEntryPoint(void* object)
+{
+ static_cast<GeolocationPositionCache*>(object)->threadEntryPointImpl();
+ return 0;
+}
+
+void GeolocationPositionCache::threadEntryPointImpl()
+{
+ while (OwnPtr<ScriptExecutionContext::Task> task = m_queue.waitForMessage()) {
+ // We don't need a ScriptExecutionContext in the callback, so pass 0 here.
+ task->performTask(0);
+ }
+}
+
+void GeolocationPositionCache::triggerReadFromDatabase()
+{
+ m_queue.append(createCallbackTask(&GeolocationPositionCache::readFromDatabase, this));
+}
+
+void GeolocationPositionCache::readFromDatabase(ScriptExecutionContext*, GeolocationPositionCache* cache)
+{
+ cache->readFromDatabaseImpl();
+}
+
+void GeolocationPositionCache::readFromDatabaseImpl()
+{
+ SQLiteDatabase database;
+ {
+ MutexLocker lock(m_databaseFileMutex);
+ if (!database.open(m_databaseFile))
+ return;
+ }
+
+ // Create the table here, such that even if we've just created the
+ // DB, the commands below should succeed.
+ if (!database.executeCommand("CREATE TABLE IF NOT EXISTS CachedPosition ("
+ "latitude REAL NOT NULL, "
+ "longitude REAL NOT NULL, "
+ "altitude REAL, "
+ "accuracy REAL NOT NULL, "
+ "altitudeAccuracy REAL, "
+ "heading REAL, "
+ "speed REAL, "
+ "timestamp INTEGER NOT NULL)"))
+ return;
+
+ SQLiteStatement statement(database, "SELECT * FROM CachedPosition");
+ if (statement.prepare() != SQLResultOk)
+ return;
+
+ if (statement.step() != SQLResultRow)
+ return;
+
+ bool providesAltitude = statement.getColumnValue(2).type() != SQLValue::NullValue;
+ bool providesAltitudeAccuracy = statement.getColumnValue(4).type() != SQLValue::NullValue;
+ bool providesHeading = statement.getColumnValue(5).type() != SQLValue::NullValue;
+ bool providesSpeed = statement.getColumnValue(6).type() != SQLValue::NullValue;
+ RefPtr<Coordinates> coordinates = Coordinates::create(statement.getColumnDouble(0), // latitude
+ statement.getColumnDouble(1), // longitude
+ providesAltitude, statement.getColumnDouble(2), // altitude
+ statement.getColumnDouble(3), // accuracy
+ providesAltitudeAccuracy, statement.getColumnDouble(4), // altitudeAccuracy
+ providesHeading, statement.getColumnDouble(5), // heading
+ providesSpeed, statement.getColumnDouble(6)); // speed
+ DOMTimeStamp timestamp = statement.getColumnInt64(7); // timestamp
+
+ // A position may have been set since we called triggerReadFromDatabase().
+ MutexLocker lock(m_cachedPositionMutex);
+ if (m_cachedPosition)
+ return;
+ m_cachedPosition = Geoposition::create(coordinates.release(), timestamp);
+}
+
+void GeolocationPositionCache::triggerWriteToDatabase()
+{
+ m_queue.append(createCallbackTask(writeToDatabase, this));
+}
+
+void GeolocationPositionCache::writeToDatabase(ScriptExecutionContext*, GeolocationPositionCache* cache)
+{
+ cache->writeToDatabaseImpl();
+}
+
+void GeolocationPositionCache::writeToDatabaseImpl()
+{
+ SQLiteDatabase database;
+ {
+ MutexLocker lock(m_databaseFileMutex);
+ if (!database.open(m_databaseFile))
+ return;
+ }
+
+ RefPtr<Geoposition> cachedPosition;
+ {
+ MutexLocker lock(m_cachedPositionMutex);
+ if (m_cachedPosition)
+ cachedPosition = m_cachedPosition->threadSafeCopy();
+ }
+
+ SQLiteTransaction transaction(database);
+
+ if (!database.executeCommand("DELETE FROM CachedPosition"))
+ return;
+
+ SQLiteStatement statement(database, "INSERT INTO CachedPosition ("
+ "latitude, "
+ "longitude, "
+ "altitude, "
+ "accuracy, "
+ "altitudeAccuracy, "
+ "heading, "
+ "speed, "
+ "timestamp) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
+ if (statement.prepare() != SQLResultOk)
+ return;
+
+ statement.bindDouble(1, cachedPosition->coords()->latitude());
+ statement.bindDouble(2, cachedPosition->coords()->longitude());
+ if (cachedPosition->coords()->canProvideAltitude())
+ statement.bindDouble(3, cachedPosition->coords()->altitude());
+ else
+ statement.bindNull(3);
+ statement.bindDouble(4, cachedPosition->coords()->accuracy());
+ if (cachedPosition->coords()->canProvideAltitudeAccuracy())
+ statement.bindDouble(5, cachedPosition->coords()->altitudeAccuracy());
+ else
+ statement.bindNull(5);
+ if (cachedPosition->coords()->canProvideHeading())
+ statement.bindDouble(6, cachedPosition->coords()->heading());
+ else
+ statement.bindNull(6);
+ if (cachedPosition->coords()->canProvideSpeed())
+ statement.bindDouble(7, cachedPosition->coords()->speed());
+ else
+ statement.bindNull(7);
+ statement.bindInt64(8, cachedPosition->timestamp());
+
+ if (!statement.executeCommand())
+ return;
+
+ transaction.commit();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(GEOLOCATION)
diff --git a/Source/WebCore/page/GeolocationPositionCache.h b/Source/WebCore/page/GeolocationPositionCache.h
new file mode 100644
index 0000000..1398850
--- /dev/null
+++ b/Source/WebCore/page/GeolocationPositionCache.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 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 GeolocationPositionCache_h
+#define GeolocationPositionCache_h
+
+#include "PlatformString.h"
+#include "ScriptExecutionContext.h"
+
+#include <wtf/Forward.h>
+#include <wtf/MessageQueue.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class Geoposition;
+
+// Maintains a cached position for Geolocation. Takes care of writing and
+// reading the position to a database on a background thread. The Geolocation
+// spec does not require a cached position to be maintained, so we take a
+// best-effort approach where we do not wait for database reads or writes.
+class GeolocationPositionCache {
+public:
+ static GeolocationPositionCache* instance();
+
+ void addUser();
+ void removeUser();
+
+ void setDatabasePath(const String&);
+ void setCachedPosition(Geoposition*);
+ Geoposition* cachedPosition();
+
+private:
+ GeolocationPositionCache();
+
+ void startBackgroundThread();
+ static void* threadEntryPoint(void* object);
+ void threadEntryPointImpl();
+
+ void triggerReadFromDatabase();
+ static void readFromDatabase(ScriptExecutionContext*, GeolocationPositionCache*);
+ void readFromDatabaseImpl();
+ void triggerWriteToDatabase();
+ static void writeToDatabase(ScriptExecutionContext*, GeolocationPositionCache*);
+ void writeToDatabaseImpl();
+
+ RefPtr<Geoposition> m_cachedPosition;
+ Mutex m_cachedPositionMutex;
+ ThreadIdentifier m_threadId;
+ MessageQueue<ScriptExecutionContext::Task> m_queue;
+ String m_databaseFile;
+ Mutex m_databaseFileMutex;
+};
+
+} // namespace WebCore
+
+#endif // GeolocationPositionCache_h
diff --git a/Source/WebCore/page/Geoposition.h b/Source/WebCore/page/Geoposition.h
new file mode 100644
index 0000000..83d865a
--- /dev/null
+++ b/Source/WebCore/page/Geoposition.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Geoposition_h
+#define Geoposition_h
+
+#include "Coordinates.h"
+#include "Event.h"
+#include "PlatformString.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class Geoposition : public RefCounted<Geoposition> {
+public:
+ static PassRefPtr<Geoposition> create(PassRefPtr<Coordinates> coordinates, DOMTimeStamp timestamp)
+ {
+ return adoptRef(new Geoposition(coordinates, timestamp));
+ }
+
+ PassRefPtr<Geoposition> threadSafeCopy() const
+ {
+ return Geoposition::create(m_coordinates->threadSafeCopy(), m_timestamp);
+ }
+
+ DOMTimeStamp timestamp() const { return m_timestamp; }
+ Coordinates* coords() const { return m_coordinates.get(); }
+
+private:
+ Geoposition(PassRefPtr<Coordinates> coordinates, DOMTimeStamp timestamp)
+ : m_coordinates(coordinates)
+ , m_timestamp(timestamp)
+ {
+ ASSERT(m_coordinates);
+ }
+
+ RefPtr<Coordinates> m_coordinates;
+ DOMTimeStamp m_timestamp;
+};
+
+} // namespace WebCore
+
+#endif // Geoposition_h
diff --git a/Source/WebCore/page/Geoposition.idl b/Source/WebCore/page/Geoposition.idl
new file mode 100644
index 0000000..41a2262
--- /dev/null
+++ b/Source/WebCore/page/Geoposition.idl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module core {
+
+ interface [Conditional=GEOLOCATION, OmitConstructor] Geoposition {
+ readonly attribute Coordinates coords;
+ readonly attribute DOMTimeStamp timestamp;
+ };
+}
diff --git a/Source/WebCore/page/GroupSettings.cpp b/Source/WebCore/page/GroupSettings.cpp
new file mode 100644
index 0000000..0762861
--- /dev/null
+++ b/Source/WebCore/page/GroupSettings.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 "GroupSettings.h"
+
+namespace WebCore {
+
+GroupSettings::GroupSettings()
+ : m_localStorageQuotaBytes(5 * 1024 * 1024) // Suggested by the HTML5 spec.
+ , m_indexedDBQuotaBytes(5 * 1024 * 1024)
+{
+}
+
+void GroupSettings::setLocalStorageQuotaBytes(unsigned quota)
+{
+ m_localStorageQuotaBytes = quota;
+}
+
+void GroupSettings::setIndexedDBDatabasePath(const String& path)
+{
+ m_indexedDBDatabasePath = path;
+}
+
+void GroupSettings::setIndexedDBQuotaBytes(int64_t quota)
+{
+ m_indexedDBQuotaBytes = quota;
+}
+
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/GroupSettings.h b/Source/WebCore/page/GroupSettings.h
new file mode 100644
index 0000000..fb6f6b5
--- /dev/null
+++ b/Source/WebCore/page/GroupSettings.h
@@ -0,0 +1,62 @@
+/*
+ * 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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 GroupSettings_h
+#define GroupSettings_h
+
+#include "PlatformString.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class PageGroup;
+
+class GroupSettings : public Noncopyable {
+public:
+ static PassOwnPtr<GroupSettings> create()
+ {
+ return adoptPtr(new GroupSettings());
+ }
+
+ void setLocalStorageQuotaBytes(unsigned);
+ unsigned localStorageQuotaBytes() const { return m_localStorageQuotaBytes; }
+
+ void setIndexedDBQuotaBytes(int64_t);
+ int64_t indexedDBQuotaBytes() const { return m_indexedDBQuotaBytes; }
+
+ void setIndexedDBDatabasePath(const String&);
+ const String& indexedDBDatabasePath() const { return m_indexedDBDatabasePath; }
+
+private:
+ GroupSettings();
+
+ unsigned m_localStorageQuotaBytes;
+ String m_indexedDBDatabasePath;
+ int64_t m_indexedDBQuotaBytes;
+};
+
+} // namespace WebCore
+
+#endif // GroupSettings_h
diff --git a/Source/WebCore/page/HaltablePlugin.h b/Source/WebCore/page/HaltablePlugin.h
new file mode 100644
index 0000000..0f4aa41
--- /dev/null
+++ b/Source/WebCore/page/HaltablePlugin.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HaltablePlugin_h
+#define HaltablePlugin_h
+
+namespace WebCore {
+
+class Node;
+
+class HaltablePlugin {
+public:
+ virtual ~HaltablePlugin() { }
+
+ virtual void halt() = 0;
+ virtual void restart() = 0;
+ virtual Node* node() const = 0;
+ virtual bool isWindowed() const = 0;
+ virtual String pluginName() const = 0;
+};
+
+} // namespace WebCore
+
+#endif // HaltablePlugin_h
diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp
new file mode 100644
index 0000000..abbf9ec
--- /dev/null
+++ b/Source/WebCore/page/History.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "History.h"
+
+#include "BackForwardController.h"
+#include "Document.h"
+#include "ExceptionCode.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "HistoryItem.h"
+#include "Page.h"
+
+namespace WebCore {
+
+History::History(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+Frame* History::frame() const
+{
+ return m_frame;
+}
+
+void History::disconnectFrame()
+{
+ m_frame = 0;
+}
+
+unsigned History::length() const
+{
+ if (!m_frame)
+ return 0;
+ if (!m_frame->page())
+ return 0;
+ return m_frame->page()->backForward()->count();
+}
+
+void History::back()
+{
+ go(-1);
+}
+
+void History::back(ScriptExecutionContext* context)
+{
+ go(context, -1);
+}
+
+void History::forward()
+{
+ go(1);
+}
+
+void History::forward(ScriptExecutionContext* context)
+{
+ go(context, 1);
+}
+
+void History::go(int distance)
+{
+ if (!m_frame)
+ return;
+<<<<<<< HEAD:WebCore/page/History.cpp
+=======
+
+>>>>>>> webkit.org at r75315:Source/WebCore/page/History.cpp
+ m_frame->navigationScheduler()->scheduleHistoryNavigation(distance);
+}
+
+void History::go(ScriptExecutionContext* context, int distance)
+{
+ if (!m_frame)
+ return;
+
+ ASSERT(WTF::isMainThread());
+ Frame* activeFrame = static_cast<Document*>(context)->frame();
+ if (!activeFrame)
+ return;
+
+ if (!activeFrame->loader()->shouldAllowNavigation(m_frame))
+ return;
+
+ m_frame->navigationScheduler()->scheduleHistoryNavigation(distance);
+}
+
+KURL History::urlForState(const String& urlString)
+{
+ KURL baseURL = m_frame->loader()->baseURL();
+ if (urlString.isEmpty())
+ return baseURL;
+
+ return KURL(baseURL, urlString);
+}
+
+void History::stateObjectAdded(PassRefPtr<SerializedScriptValue> data, const String& title, const String& urlString, StateObjectType stateObjectType, ExceptionCode& ec)
+{
+ if (!m_frame || !m_frame->page())
+ return;
+
+ KURL fullURL = urlForState(urlString);
+ RefPtr<SecurityOrigin> origin = SecurityOrigin::create(fullURL);
+ if (!fullURL.isValid() || !m_frame->document()->securityOrigin()->isSameSchemeHostPort(origin.get())) {
+ ec = SECURITY_ERR;
+ return;
+ }
+
+ if (stateObjectType == StateObjectPush)
+ m_frame->loader()->history()->pushState(data, title, fullURL.string());
+ else if (stateObjectType == StateObjectReplace)
+ m_frame->loader()->history()->replaceState(data, title, fullURL.string());
+
+ if (!urlString.isEmpty())
+ m_frame->document()->updateURLForPushOrReplaceState(fullURL);
+
+ if (stateObjectType == StateObjectPush)
+ m_frame->loader()->client()->dispatchDidPushStateWithinPage();
+ else if (stateObjectType == StateObjectReplace)
+ m_frame->loader()->client()->dispatchDidReplaceStateWithinPage();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/History.h b/Source/WebCore/page/History.h
new file mode 100644
index 0000000..9ec1914
--- /dev/null
+++ b/Source/WebCore/page/History.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef History_h
+#define History_h
+
+#include "KURL.h"
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class Frame;
+class ScriptExecutionContext;
+class SerializedScriptValue;
+typedef int ExceptionCode;
+
+class History : public RefCounted<History> {
+public:
+ static PassRefPtr<History> create(Frame* frame) { return adoptRef(new History(frame)); }
+
+ Frame* frame() const;
+ void disconnectFrame();
+
+ unsigned length() const;
+ void back();
+ void forward();
+ void go(int distance);
+
+ void back(ScriptExecutionContext*);
+ void forward(ScriptExecutionContext*);
+ void go(ScriptExecutionContext*, int distance);
+
+ enum StateObjectType {
+ StateObjectPush,
+ StateObjectReplace
+ };
+ void stateObjectAdded(PassRefPtr<SerializedScriptValue>, const String& title, const String& url, StateObjectType, ExceptionCode&);
+
+private:
+ History(Frame*);
+
+ KURL urlForState(const String& url);
+
+ Frame* m_frame;
+};
+
+} // namespace WebCore
+
+#endif // History_h
diff --git a/Source/WebCore/page/History.idl b/Source/WebCore/page/History.idl
new file mode 100644
index 0000000..d8eac60
--- /dev/null
+++ b/Source/WebCore/page/History.idl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module window {
+
+ interface [
+#if defined(V8_BINDING) && V8_BINDING
+ CheckDomainSecurity,
+#endif
+ DelegatingGetOwnPropertySlot,
+ DelegatingPutFunction,
+ CustomDeleteProperty,
+ CustomGetPropertyNames,
+ OmitConstructor
+ ] History {
+ readonly attribute unsigned long length;
+
+ [DoNotCheckDomainSecurity, CallWith=ScriptExecutionContext] void back();
+ [DoNotCheckDomainSecurity, CallWith=ScriptExecutionContext] void forward();
+ [DoNotCheckDomainSecurity, CallWith=ScriptExecutionContext] void go(in long distance);
+
+ [Custom, EnabledAtRuntime] void pushState(in any data, in DOMString title, in optional DOMString url)
+ raises(DOMException);
+ [Custom, EnabledAtRuntime] void replaceState(in any data, in DOMString title, in optional DOMString url)
+ raises(DOMException);
+ };
+
+}
diff --git a/Source/WebCore/page/Location.cpp b/Source/WebCore/page/Location.cpp
new file mode 100644
index 0000000..be185f9
--- /dev/null
+++ b/Source/WebCore/page/Location.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2008, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "Location.h"
+
+#include "DOMWindow.h"
+#include "ExceptionCode.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "KURL.h"
+
+namespace WebCore {
+
+Location::Location(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+void Location::disconnectFrame()
+{
+ m_frame = 0;
+}
+
+inline const KURL& Location::url() const
+{
+ ASSERT(m_frame);
+
+ const KURL& url = m_frame->loader()->url();
+ if (!url.isValid())
+ return blankURL(); // Use "about:blank" while the page is still loading (before we have a frame).
+
+ return url;
+}
+
+String Location::href() const
+{
+ if (!m_frame)
+ return String();
+
+ const KURL& url = this->url();
+ return url.hasPath() ? url.prettyURL() : url.prettyURL() + "/";
+}
+
+String Location::protocol() const
+{
+ if (!m_frame)
+ return String();
+
+ return url().protocol() + ":";
+}
+
+String Location::host() const
+{
+ if (!m_frame)
+ return String();
+
+ // Note: this is the IE spec. The NS spec swaps the two, it says
+ // "The hostname property is the concatenation of the host and port properties, separated by a colon."
+ const KURL& url = this->url();
+ return url.port() ? url.host() + ":" + String::number(url.port()) : url.host();
+}
+
+String Location::hostname() const
+{
+ if (!m_frame)
+ return String();
+
+ return url().host();
+}
+
+String Location::port() const
+{
+ if (!m_frame)
+ return String();
+
+ const KURL& url = this->url();
+ return url.port() ? String::number(url.port()) : "";
+}
+
+String Location::pathname() const
+{
+ if (!m_frame)
+ return String();
+
+ const KURL& url = this->url();
+ return url.path().isEmpty() ? "/" : url.path();
+}
+
+String Location::search() const
+{
+ if (!m_frame)
+ return String();
+
+ const KURL& url = this->url();
+ return url.query().isEmpty() ? "" : "?" + url.query();
+}
+
+String Location::origin() const
+{
+ if (!m_frame)
+ return String();
+ return SecurityOrigin::create(url())->toString();
+}
+
+String Location::hash() const
+{
+ if (!m_frame)
+ return String();
+
+ const String& fragmentIdentifier = url().fragmentIdentifier();
+ return fragmentIdentifier.isEmpty() ? "" : "#" + fragmentIdentifier;
+}
+
+String Location::getParameter(const String& name) const
+{
+ if (!m_frame)
+ return String();
+
+ ParsedURLParameters parameters;
+ url().copyParsedQueryTo(parameters);
+ return parameters.get(name);
+}
+
+String Location::toString() const
+{
+ if (!m_frame)
+ return String();
+
+ const KURL& url = this->url();
+ return url.hasPath() ? url.prettyURL() : url.prettyURL() + "/";
+}
+
+void Location::setHref(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow)
+{
+ if (!m_frame)
+ return;
+ m_frame->domWindow()->setLocation(urlString, activeWindow, firstWindow);
+}
+
+void Location::setProtocol(const String& protocol, DOMWindow* activeWindow, DOMWindow* firstWindow, ExceptionCode& ec)
+{
+ if (!m_frame)
+ return;
+ KURL url = m_frame->loader()->url();
+ if (!url.setProtocol(protocol)) {
+ ec = SYNTAX_ERR;
+ return;
+ }
+ m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
+}
+
+void Location::setHost(const String& host, DOMWindow* activeWindow, DOMWindow* firstWindow)
+{
+ if (!m_frame)
+ return;
+ KURL url = m_frame->loader()->url();
+ url.setHostAndPort(host);
+ m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
+}
+
+void Location::setHostname(const String& hostname, DOMWindow* activeWindow, DOMWindow* firstWindow)
+{
+ if (!m_frame)
+ return;
+ KURL url = m_frame->loader()->url();
+ url.setHost(hostname);
+ m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
+}
+
+void Location::setPort(const String& portString, DOMWindow* activeWindow, DOMWindow* firstWindow)
+{
+ if (!m_frame)
+ return;
+ KURL url = m_frame->loader()->url();
+ int port = portString.toInt();
+ if (port < 0 || port > 0xFFFF)
+ url.removePort();
+ else
+ url.setPort(port);
+ m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
+}
+
+void Location::setPathname(const String& pathname, DOMWindow* activeWindow, DOMWindow* firstWindow)
+{
+ if (!m_frame)
+ return;
+ KURL url = m_frame->loader()->url();
+ url.setPath(pathname);
+ m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
+}
+
+void Location::setSearch(const String& search, DOMWindow* activeWindow, DOMWindow* firstWindow)
+{
+ if (!m_frame)
+ return;
+ KURL url = m_frame->loader()->url();
+ url.setQuery(search);
+ m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
+}
+
+void Location::setHash(const String& hash, DOMWindow* activeWindow, DOMWindow* firstWindow)
+{
+ if (!m_frame)
+ return;
+ KURL url = m_frame->loader()->url();
+ String oldFragmentIdentifier = url.fragmentIdentifier();
+ String newFragmentIdentifier = hash;
+ if (hash[0] == '#')
+ newFragmentIdentifier = hash.substring(1);
+ url.setFragmentIdentifier(newFragmentIdentifier);
+ // Note that by parsing the URL and *then* comparing fragments, we are
+ // comparing fragments post-canonicalization, and so this handles the
+ // cases where fragment identifiers are ignored or invalid.
+ if (equalIgnoringNullity(oldFragmentIdentifier, url.fragmentIdentifier()))
+ return;
+ m_frame->domWindow()->setLocation(url.string(), activeWindow, firstWindow);
+}
+
+void Location::assign(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow)
+{
+ if (!m_frame)
+ return;
+ m_frame->domWindow()->setLocation(urlString, activeWindow, firstWindow);
+}
+
+void Location::replace(const String& urlString, DOMWindow* activeWindow, DOMWindow* firstWindow)
+{
+ if (!m_frame)
+ return;
+ m_frame->domWindow()->setLocation(urlString, activeWindow, firstWindow, LockHistoryAndBackForwardList);
+}
+
+void Location::reload(DOMWindow* activeWindow)
+{
+ if (!m_frame)
+ return;
+ // FIXME: It's not clear this cross-origin security check is valuable.
+ // We allow one page to change the location of another. Why block attempts to reload?
+ // Other location operations simply block use of JavaScript URLs cross origin.
+ DOMWindow* targetWindow = m_frame->domWindow();
+ if (!activeWindow->securityOrigin()->canAccess(targetWindow->securityOrigin())) {
+ targetWindow->printErrorMessage(targetWindow->crossDomainAccessErrorMessage(activeWindow));
+ return;
+ }
+ if (protocolIsJavaScript(m_frame->loader()->url()))
+ return;
+ m_frame->navigationScheduler()->scheduleRefresh();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/Location.h b/Source/WebCore/page/Location.h
new file mode 100644
index 0000000..1b68cee
--- /dev/null
+++ b/Source/WebCore/page/Location.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2008, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 Location_h
+#define Location_h
+
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class DOMWindow;
+class Frame;
+class KURL;
+
+typedef int ExceptionCode;
+
+class Location : public RefCounted<Location> {
+public:
+ static PassRefPtr<Location> create(Frame* frame) { return adoptRef(new Location(frame)); }
+
+ Frame* frame() const { return m_frame; }
+ void disconnectFrame();
+
+ void setHref(const String&, DOMWindow* activeWindow, DOMWindow* firstWindow);
+ String href() const;
+
+ void assign(const String&, DOMWindow* activeWindow, DOMWindow* firstWindow);
+ void replace(const String&, DOMWindow* activeWindow, DOMWindow* firstWindow);
+ void reload(DOMWindow* activeWindow);
+
+ void setProtocol(const String&, DOMWindow* activeWindow, DOMWindow* firstWindow, ExceptionCode&);
+ String protocol() const;
+ void setHost(const String&, DOMWindow* activeWindow, DOMWindow* firstWindow);
+ String host() const;
+ void setHostname(const String&, DOMWindow* activeWindow, DOMWindow* firstWindow);
+ String hostname() const;
+ void setPort(const String&, DOMWindow* activeWindow, DOMWindow* firstWindow);
+ String port() const;
+ void setPathname(const String&, DOMWindow* activeWindow, DOMWindow* firstWindow);
+ String pathname() const;
+ void setSearch(const String&, DOMWindow* activeWindow, DOMWindow* firstWindow);
+ String search() const;
+ void setHash(const String&, DOMWindow* activeWindow, DOMWindow* firstWindow);
+ String hash() const;
+ String origin() const;
+
+ String toString() const;
+
+ String getParameter(const String&) const;
+
+private:
+ Location(Frame*);
+
+ const KURL& url() const;
+
+ Frame* m_frame;
+};
+
+} // namespace WebCore
+
+#endif // Location_h
diff --git a/Source/WebCore/page/Location.idl b/Source/WebCore/page/Location.idl
new file mode 100644
index 0000000..76340d9
--- /dev/null
+++ b/Source/WebCore/page/Location.idl
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module window {
+
+ interface [
+#if defined(V8_BINDING) && V8_BINDING
+ CheckDomainSecurity,
+#endif
+ DelegatingGetOwnPropertySlot,
+ DelegatingPutFunction,
+ CustomDeleteProperty,
+ CustomGetPropertyNames,
+ CustomDefineGetter,
+ DelegatingPrototypePutFunction,
+ CustomPrototypeDefineGetter,
+ OmitConstructor
+ ] Location {
+#if !defined(LANGUAGE_CPP) || !LANGUAGE_CPP
+ attribute [DoNotCheckDomainSecurityOnSet, CustomSetter, V8DisallowShadowing] DOMString href;
+#endif
+
+ [Custom, V8OnInstance] void assign(in DOMString url);
+ [Custom, V8OnInstance] void replace(in DOMString url);
+ [Custom, V8OnInstance] void reload();
+
+ // URI decomposition attributes
+#if !defined(LANGUAGE_CPP) || !LANGUAGE_CPP
+ attribute [CustomSetter] DOMString protocol;
+ attribute [CustomSetter] DOMString host;
+ attribute [CustomSetter] DOMString hostname;
+ attribute [CustomSetter] DOMString port;
+ attribute [CustomSetter] DOMString pathname;
+ attribute [CustomSetter] DOMString search;
+ attribute [CustomSetter] DOMString hash;
+
+ readonly attribute DOMString origin;
+#endif
+
+ DOMString getParameter(in DOMString name);
+
+#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
+ [DontEnum, Custom, V8OnInstance, V8ReadOnly] DOMString toString();
+#endif
+#if defined(V8_BINDING) && V8_BINDING
+ [DontEnum, Custom, V8OnInstance, V8ReadOnly] DOMObject valueOf();
+#endif
+ };
+
+}
diff --git a/Source/WebCore/page/MediaCanStartListener.h b/Source/WebCore/page/MediaCanStartListener.h
new file mode 100644
index 0000000..317babf
--- /dev/null
+++ b/Source/WebCore/page/MediaCanStartListener.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaCanStartListener_h
+#define MediaCanStartListener_h
+
+namespace WebCore {
+
+class MediaCanStartListener {
+public:
+ virtual void mediaCanStart() = 0;
+protected:
+ virtual ~MediaCanStartListener() { }
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/page/MemoryInfo.cpp b/Source/WebCore/page/MemoryInfo.cpp
new file mode 100644
index 0000000..c2247b9
--- /dev/null
+++ b/Source/WebCore/page/MemoryInfo.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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 "MemoryInfo.h"
+
+#include "Frame.h"
+#include "ScriptGCEvent.h"
+#include "Settings.h"
+
+namespace WebCore {
+
+MemoryInfo::MemoryInfo(Frame* frame)
+ : m_totalJSHeapSize(0),
+ m_usedJSHeapSize(0)
+{
+ if (frame && frame->settings() && frame->settings()->memoryInfoEnabled()) {
+#if ENABLE(INSPECTOR)
+ ScriptGCEvent::getHeapSize(m_usedJSHeapSize, m_totalJSHeapSize);
+#endif
+ }
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/MemoryInfo.h b/Source/WebCore/page/MemoryInfo.h
new file mode 100644
index 0000000..615e952
--- /dev/null
+++ b/Source/WebCore/page/MemoryInfo.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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MemoryInfo_h
+#define MemoryInfo_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class Frame;
+
+class MemoryInfo : public RefCounted<MemoryInfo> {
+public:
+ static PassRefPtr<MemoryInfo> create(Frame* frame) { return adoptRef(new MemoryInfo(frame)); }
+
+ size_t totalJSHeapSize() const { return m_totalJSHeapSize; }
+ size_t usedJSHeapSize() const { return m_usedJSHeapSize; }
+
+private:
+ MemoryInfo(Frame*);
+
+ size_t m_totalJSHeapSize;
+ size_t m_usedJSHeapSize;
+};
+
+} // namespace WebCore
+
+#endif // MemoryInfo_h
diff --git a/Source/WebCore/page/MemoryInfo.idl b/Source/WebCore/page/MemoryInfo.idl
new file mode 100644
index 0000000..59b0081
--- /dev/null
+++ b/Source/WebCore/page/MemoryInfo.idl
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+module window {
+
+ interface [OmitConstructor] MemoryInfo {
+
+ readonly attribute unsigned long totalJSHeapSize;
+ readonly attribute unsigned long usedJSHeapSize;
+
+ };
+
+}
diff --git a/Source/WebCore/page/MouseEventWithHitTestResults.cpp b/Source/WebCore/page/MouseEventWithHitTestResults.cpp
new file mode 100644
index 0000000..042269c
--- /dev/null
+++ b/Source/WebCore/page/MouseEventWithHitTestResults.cpp
@@ -0,0 +1,66 @@
+/*
+ Copyright (C) 2006 Apple Computer, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "MouseEventWithHitTestResults.h"
+
+#include "Element.h"
+#include "Node.h"
+
+// Would TargetedMouseEvent be a better name?
+
+namespace WebCore {
+
+MouseEventWithHitTestResults::MouseEventWithHitTestResults(const PlatformMouseEvent& event, const HitTestResult& hitTestResult)
+ : m_event(event)
+ , m_hitTestResult(hitTestResult)
+{
+}
+
+Node* MouseEventWithHitTestResults::targetNode() const
+{
+ Node* node = m_hitTestResult.innerNode();
+ if (!node)
+ return 0;
+ if (node->inDocument())
+ return node;
+
+ Element* element = node->parentElement();
+ if (element && element->inDocument())
+ return element;
+
+ return node;
+}
+
+const IntPoint MouseEventWithHitTestResults::localPoint() const
+{
+ return m_hitTestResult.localPoint();
+}
+
+Scrollbar* MouseEventWithHitTestResults::scrollbar() const
+{
+ return m_hitTestResult.scrollbar();
+}
+
+bool MouseEventWithHitTestResults::isOverLink() const
+{
+ return m_hitTestResult.URLElement() && m_hitTestResult.URLElement()->isLink();
+}
+
+}
diff --git a/Source/WebCore/page/MouseEventWithHitTestResults.h b/Source/WebCore/page/MouseEventWithHitTestResults.h
new file mode 100644
index 0000000..8c28574
--- /dev/null
+++ b/Source/WebCore/page/MouseEventWithHitTestResults.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2000 Simon Hausmann <hausmann@kde.org>
+ Copyright (C) 2006 Apple Computer, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MouseEventWithHitTestResults_h
+#define MouseEventWithHitTestResults_h
+
+#include "HitTestResult.h"
+#include "PlatformMouseEvent.h"
+
+namespace WebCore {
+
+class Scrollbar;
+
+class MouseEventWithHitTestResults {
+public:
+ MouseEventWithHitTestResults(const PlatformMouseEvent&, const HitTestResult&);
+
+ const PlatformMouseEvent& event() const { return m_event; }
+ const HitTestResult& hitTestResult() const { return m_hitTestResult; }
+ Node* targetNode() const;
+ const IntPoint localPoint() const;
+ Scrollbar* scrollbar() const;
+ bool isOverLink() const;
+ bool isOverWidget() const { return m_hitTestResult.isOverWidget(); }
+
+private:
+ PlatformMouseEvent m_event;
+ HitTestResult m_hitTestResult;
+};
+
+} // namespace WebCore
+
+#endif // MouseEventWithHitTestResults_h
diff --git a/Source/WebCore/page/Navigator.cpp b/Source/WebCore/page/Navigator.cpp
new file mode 100644
index 0000000..5390fc9
--- /dev/null
+++ b/Source/WebCore/page/Navigator.cpp
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2000 Harri Porten (porten@kde.org)
+ * Copyright (c) 2000 Daniel Molkentin (molkentin@kde.org)
+ * Copyright (c) 2000 Stefan Schimanski (schimmi@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "Navigator.h"
+
+#include "Chrome.h"
+#include "CookieJar.h"
+#include "DOMMimeTypeArray.h"
+#include "DOMPluginArray.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "Geolocation.h"
+#include "Language.h"
+#include "Page.h"
+#include "PageGroup.h"
+#include "PlatformString.h"
+#include "PluginData.h"
+#include "ScriptController.h"
+#include "Settings.h"
+#include "StorageNamespace.h"
+
+#if PLATFORM(ANDROID)
+#include "ApplicationInstalledCallback.h"
+#include "Connection.h"
+#include "PackageNotifier.h"
+#endif
+
+namespace WebCore {
+
+Navigator::Navigator(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+Navigator::~Navigator()
+{
+ disconnectFrame();
+}
+
+void Navigator::disconnectFrame()
+{
+ if (m_plugins) {
+ m_plugins->disconnectFrame();
+ m_plugins = 0;
+ }
+ if (m_mimeTypes) {
+ m_mimeTypes->disconnectFrame();
+ m_mimeTypes = 0;
+ }
+ if (m_geolocation) {
+ m_geolocation->disconnectFrame();
+ m_geolocation = 0;
+ }
+ m_frame = 0;
+}
+
+// If this function returns true, we need to hide the substring "4." that would otherwise
+// appear in the appVersion string. This is to avoid problems with old versions of a
+// library called OpenCube QuickMenu, which as of this writing is still being used on
+// sites such as nwa.com -- the library thinks Safari is Netscape 4 if we don't do this!
+static bool shouldHideFourDot(Frame* frame)
+{
+ const String* sourceURL = frame->script()->sourceURL();
+ if (!sourceURL)
+ return false;
+ if (!(sourceURL->endsWith("/dqm_script.js") || sourceURL->endsWith("/dqm_loader.js") || sourceURL->endsWith("/tdqm_loader.js")))
+ return false;
+ Settings* settings = frame->settings();
+ if (!settings)
+ return false;
+ return settings->needsSiteSpecificQuirks();
+}
+
+String Navigator::appVersion() const
+{
+ if (!m_frame)
+ return String();
+ String appVersion = NavigatorBase::appVersion();
+ if (shouldHideFourDot(m_frame))
+ appVersion.replace("4.", "4_");
+ return appVersion;
+}
+
+String Navigator::language() const
+{
+ return defaultLanguage();
+}
+
+String Navigator::userAgent() const
+{
+ if (!m_frame)
+ return String();
+
+ // If the frame is already detached, FrameLoader::userAgent may malfunction, because it calls a client method
+ // that uses frame's WebView (at least, in Mac WebKit).
+ if (!m_frame->page())
+ return String();
+
+ return m_frame->loader()->userAgent(m_frame->document()->url());
+}
+
+DOMPluginArray* Navigator::plugins() const
+{
+ if (!m_plugins)
+ m_plugins = DOMPluginArray::create(m_frame);
+ return m_plugins.get();
+}
+
+DOMMimeTypeArray* Navigator::mimeTypes() const
+{
+ if (!m_mimeTypes)
+ m_mimeTypes = DOMMimeTypeArray::create(m_frame);
+ return m_mimeTypes.get();
+}
+
+bool Navigator::cookieEnabled() const
+{
+ if (!m_frame)
+ return false;
+
+ if (m_frame->page() && !m_frame->page()->cookieEnabled())
+ return false;
+
+ return cookiesEnabled(m_frame->document());
+}
+
+bool Navigator::javaEnabled() const
+{
+ if (!m_frame || !m_frame->settings())
+ return false;
+
+ return m_frame->settings()->isJavaEnabled();
+}
+
+Geolocation* Navigator::geolocation() const
+{
+ if (!m_geolocation)
+ m_geolocation = Geolocation::create(m_frame);
+ return m_geolocation.get();
+}
+
+#if PLATFORM(ANDROID)
+Connection* Navigator::connection() const
+{
+ if (!m_connection)
+ m_connection = Connection::create();
+ return m_connection.get();
+}
+#endif
+
+#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+
+bool Navigator::isApplicationInstalled(const String& name, PassRefPtr<ApplicationInstalledCallback> callback)
+{
+ if (m_applicationInstalledCallback)
+ return false;
+
+ m_applicationInstalledCallback = callback;
+ m_applicationNameQuery = name;
+
+ packageNotifier().requestPackageResult();
+
+ return true;
+}
+
+void Navigator::onPackageResult()
+{
+ if (m_applicationInstalledCallback) {
+ m_applicationInstalledCallback->handleEvent(packageNotifier().isPackageInstalled(m_applicationNameQuery));
+ m_applicationInstalledCallback = 0;
+ }
+}
+#endif
+
+#if ENABLE(DOM_STORAGE)
+void Navigator::getStorageUpdates()
+{
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ StorageNamespace* localStorage = page->group().localStorage();
+ if (localStorage)
+ localStorage->unlock();
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/Navigator.h b/Source/WebCore/page/Navigator.h
new file mode 100644
index 0000000..e0801fe
--- /dev/null
+++ b/Source/WebCore/page/Navigator.h
@@ -0,0 +1,98 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef Navigator_h
+#define Navigator_h
+
+#include "NavigatorBase.h"
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+#include "PlatformString.h"
+#endif
+
+namespace WebCore {
+
+class DOMMimeTypeArray;
+class DOMPluginArray;
+class Frame;
+class Geolocation;
+class PluginData;
+#if PLATFORM(ANDROID)
+class ApplicationInstalledCallback;
+class Connection;
+#endif
+
+class Navigator : public NavigatorBase, public RefCounted<Navigator> {
+public:
+ static PassRefPtr<Navigator> create(Frame* frame) { return adoptRef(new Navigator(frame)); }
+ virtual ~Navigator();
+
+ void disconnectFrame();
+ Frame* frame() const { return m_frame; }
+
+ String appVersion() const;
+ String language() const;
+ DOMPluginArray* plugins() const;
+ DOMMimeTypeArray* mimeTypes() const;
+ bool cookieEnabled() const;
+ bool javaEnabled() const;
+
+ virtual String userAgent() const;
+
+ Geolocation* geolocation() const;
+ // This is used for GC marking.
+ Geolocation* optionalGeolocation() const { return m_geolocation.get(); }
+
+#if PLATFORM(ANDROID)
+ Connection* connection() const;
+#endif
+
+#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+ bool isApplicationInstalled(const String& name, PassRefPtr<ApplicationInstalledCallback> callback);
+ void onPackageResult();
+#endif
+
+#if ENABLE(DOM_STORAGE)
+ // Relinquishes the storage lock, if one exists.
+ void getStorageUpdates();
+#endif
+
+private:
+ Navigator(Frame*);
+ Frame* m_frame;
+ mutable RefPtr<DOMPluginArray> m_plugins;
+ mutable RefPtr<DOMMimeTypeArray> m_mimeTypes;
+ mutable RefPtr<Geolocation> m_geolocation;
+#if PLATFORM(ANDROID)
+ mutable RefPtr<Connection> m_connection;
+#endif
+
+#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+ RefPtr<ApplicationInstalledCallback> m_applicationInstalledCallback;
+ String m_applicationNameQuery;
+#endif
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/page/Navigator.idl b/Source/WebCore/page/Navigator.idl
new file mode 100644
index 0000000..5699d86
--- /dev/null
+++ b/Source/WebCore/page/Navigator.idl
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+module window {
+
+ interface [
+ CustomMarkFunction,
+ OmitConstructor
+ ] Navigator {
+ readonly attribute DOMString appCodeName;
+ readonly attribute DOMString appName;
+ readonly attribute DOMString appVersion;
+ readonly attribute DOMString language;
+ readonly attribute DOMString userAgent;
+ readonly attribute DOMString platform;
+ readonly attribute DOMPluginArray plugins;
+ readonly attribute DOMMimeTypeArray mimeTypes;
+ readonly attribute DOMString product;
+ readonly attribute DOMString productSub;
+ readonly attribute DOMString vendor;
+ readonly attribute DOMString vendorSub;
+ readonly attribute boolean cookieEnabled;
+ boolean javaEnabled();
+
+ readonly attribute boolean onLine;
+
+#if defined(ENABLE_CONNECTION) && ENABLE_CONNECTION
+ // ANDROID-only for now, upstreaming in progress.
+ readonly attribute Connection connection;
+#endif
+
+#if defined(ENABLE_APPLICATION_INSTALLED) && ENABLE_APPLICATION_INSTALLED
+ // ANDROID-only for now.
+ [Custom] void isApplicationInstalled(in DOMString applicationName, in ApplicationInstalledCallback callback);
+#endif
+
+#if defined(ENABLE_GEOLOCATION) && ENABLE_GEOLOCATION
+ readonly attribute [EnabledAtRuntime] Geolocation geolocation;
+#endif
+
+#if defined(ENABLE_DOM_STORAGE) && ENABLE_DOM_STORAGE
+ void getStorageUpdates();
+#endif
+ };
+
+}
diff --git a/Source/WebCore/page/NavigatorBase.cpp b/Source/WebCore/page/NavigatorBase.cpp
new file mode 100644
index 0000000..ca51a29
--- /dev/null
+++ b/Source/WebCore/page/NavigatorBase.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "NavigatorBase.h"
+
+#include "NetworkStateNotifier.h"
+#include "PlatformString.h"
+#if OS(LINUX)
+#include "sys/utsname.h"
+#include <wtf/StdLibExtras.h>
+#endif
+
+#ifndef WEBCORE_NAVIGATOR_PLATFORM
+#if OS(MAC_OS_X) && (CPU(PPC) || CPU(PPC64))
+#define WEBCORE_NAVIGATOR_PLATFORM "MacPPC"
+#elif OS(MAC_OS_X) && (CPU(X86) || CPU(X86_64))
+#define WEBCORE_NAVIGATOR_PLATFORM "MacIntel"
+#elif OS(WINDOWS)
+#define WEBCORE_NAVIGATOR_PLATFORM "Win32"
+#elif OS(SYMBIAN)
+#define WEBCORE_NAVIGATOR_PLATFORM "Symbian"
+#else
+#define WEBCORE_NAVIGATOR_PLATFORM ""
+#endif
+#endif // ifndef WEBCORE_NAVIGATOR_PLATFORM
+
+#ifndef WEBCORE_NAVIGATOR_PRODUCT
+#define WEBCORE_NAVIGATOR_PRODUCT "Gecko"
+#endif // ifndef WEBCORE_NAVIGATOR_PRODUCT
+
+#ifndef WEBCORE_NAVIGATOR_PRODUCT_SUB
+#define WEBCORE_NAVIGATOR_PRODUCT_SUB "20030107"
+#endif // ifndef WEBCORE_NAVIGATOR_PRODUCT_SUB
+
+#ifndef WEBCORE_NAVIGATOR_VENDOR
+#define WEBCORE_NAVIGATOR_VENDOR "Apple Computer, Inc."
+#endif // ifndef WEBCORE_NAVIGATOR_VENDOR
+
+#ifndef WEBCORE_NAVIGATOR_VENDOR_SUB
+#define WEBCORE_NAVIGATOR_VENDOR_SUB ""
+#endif // ifndef WEBCORE_NAVIGATOR_VENDOR_SUB
+
+
+namespace WebCore {
+
+NavigatorBase::~NavigatorBase()
+{
+}
+
+String NavigatorBase::appName() const
+{
+ return "Netscape";
+}
+
+String NavigatorBase::appVersion() const
+{
+ // Version is everything in the user agent string past the "Mozilla/" prefix.
+ const String& agent = userAgent();
+ return agent.substring(agent.find('/') + 1);
+}
+
+String NavigatorBase::platform() const
+{
+#if OS(LINUX)
+ if (String("") != WEBCORE_NAVIGATOR_PLATFORM)
+ return WEBCORE_NAVIGATOR_PLATFORM;
+ struct utsname osname;
+ DEFINE_STATIC_LOCAL(String, platformName, (uname(&osname) >= 0 ? String(osname.sysname) + String(" ") + String(osname.machine) : ""));
+ return platformName;
+#else
+ return WEBCORE_NAVIGATOR_PLATFORM;
+#endif
+}
+
+String NavigatorBase::appCodeName() const
+{
+ return "Mozilla";
+}
+
+String NavigatorBase::product() const
+{
+ return WEBCORE_NAVIGATOR_PRODUCT;
+}
+
+String NavigatorBase::productSub() const
+{
+ return WEBCORE_NAVIGATOR_PRODUCT_SUB;
+}
+
+String NavigatorBase::vendor() const
+{
+ return WEBCORE_NAVIGATOR_VENDOR;
+}
+
+String NavigatorBase::vendorSub() const
+{
+ return WEBCORE_NAVIGATOR_VENDOR_SUB;
+}
+
+bool NavigatorBase::onLine() const
+{
+ return networkStateNotifier().onLine();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/NavigatorBase.h b/Source/WebCore/page/NavigatorBase.h
new file mode 100644
index 0000000..8f576e3
--- /dev/null
+++ b/Source/WebCore/page/NavigatorBase.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef NavigatorBase_h
+#define NavigatorBase_h
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+ class NavigatorBase {
+ public:
+ String appName() const;
+ String appVersion() const;
+ virtual String userAgent() const = 0;
+ String platform() const;
+
+ String appCodeName() const;
+ String product() const;
+ String productSub() const;
+ String vendor() const;
+ String vendorSub() const;
+
+ bool onLine() const;
+
+ protected:
+ virtual ~NavigatorBase();
+ };
+
+} // namespace WebCore
+
+#endif // NavigatorBase_h
diff --git a/Source/WebCore/page/OriginAccessEntry.cpp b/Source/WebCore/page/OriginAccessEntry.cpp
new file mode 100644
index 0000000..7ff67cc
--- /dev/null
+++ b/Source/WebCore/page/OriginAccessEntry.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "OriginAccessEntry.h"
+
+#include "SecurityOrigin.h"
+
+namespace WebCore {
+
+OriginAccessEntry::OriginAccessEntry(const String& protocol, const String& host, SubdomainSetting subdomainSetting)
+ : m_protocol(protocol.lower())
+ , m_host(host.lower())
+ , m_subdomainSettings(subdomainSetting)
+{
+ ASSERT(subdomainSetting == AllowSubdomains || subdomainSetting == DisallowSubdomains);
+
+ // Assume that any host that ends with a digit is trying to be an IP address.
+ m_hostIsIPAddress = !m_host.isEmpty() && isASCIIDigit(m_host[m_host.length() - 1]);
+}
+
+bool OriginAccessEntry::matchesOrigin(const SecurityOrigin& origin) const
+{
+ ASSERT(origin.host() == origin.host().lower());
+ ASSERT(origin.protocol() == origin.protocol().lower());
+
+ if (m_protocol != origin.protocol())
+ return false;
+
+ // Special case: Include subdomains and empty host means "all hosts, including ip addresses".
+ if (m_subdomainSettings == AllowSubdomains && m_host.isEmpty())
+ return true;
+
+ // Exact match.
+ if (m_host == origin.host())
+ return true;
+
+ // Otherwise we can only match if we're matching subdomains.
+ if (m_subdomainSettings == DisallowSubdomains)
+ return false;
+
+ // Don't try to do subdomain matching on IP addresses.
+ if (m_hostIsIPAddress)
+ return false;
+
+ // Match subdomains.
+ if (origin.host().length() > m_host.length() && origin.host()[origin.host().length() - m_host.length() - 1] == '.' && origin.host().endsWith(m_host))
+ return true;
+
+ return false;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/OriginAccessEntry.h b/Source/WebCore/page/OriginAccessEntry.h
new file mode 100644
index 0000000..67e39fe
--- /dev/null
+++ b/Source/WebCore/page/OriginAccessEntry.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OriginAccessEntry_h
+#define OriginAccessEntry_h
+
+#include "PlatformString.h"
+
+namespace WebCore {
+
+class SecurityOrigin;
+
+class OriginAccessEntry {
+public:
+ enum SubdomainSetting {
+ AllowSubdomains,
+ DisallowSubdomains
+ };
+
+ // If host is empty string and SubdomainSetting is AllowSubdomains, the entry will match all domains in the specified protocol.
+ OriginAccessEntry(const String& protocol, const String& host, SubdomainSetting);
+ bool matchesOrigin(const SecurityOrigin&) const;
+
+ const String& protocol() const { return m_protocol; }
+ const String& host() const { return m_host; }
+ SubdomainSetting subdomainSettings() const { return m_subdomainSettings; }
+
+private:
+ String m_protocol;
+ String m_host;
+ SubdomainSetting m_subdomainSettings;
+ bool m_hostIsIPAddress;
+};
+
+inline bool operator==(const OriginAccessEntry& a, const OriginAccessEntry& b)
+{
+ return equalIgnoringCase(a.protocol(), b.protocol()) && equalIgnoringCase(a.host(), b.host()) && a.subdomainSettings() == b.subdomainSettings();
+}
+
+inline bool operator!=(const OriginAccessEntry& a, const OriginAccessEntry& b)
+{
+ return !(a == b);
+}
+
+} // namespace WebCore
+
+#endif // OriginAccessEntry_h
diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp
new file mode 100644
index 0000000..5b87051
--- /dev/null
+++ b/Source/WebCore/page/Page.cpp
@@ -0,0 +1,965 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Page.h"
+
+#include "BackForwardController.h"
+#include "BackForwardList.h"
+#include "Base64.h"
+#include "CSSStyleSelector.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "ContextMenuClient.h"
+#include "ContextMenuController.h"
+#include "DOMWindow.h"
+#include "DeviceMotionController.h"
+#include "DeviceOrientationController.h"
+#include "DocumentMarkerController.h"
+#include "DragController.h"
+#include "EditorClient.h"
+#include "Event.h"
+#include "EventNames.h"
+#include "ExceptionCode.h"
+#include "FileSystem.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "HTMLElement.h"
+#include "HistoryItem.h"
+#include "InspectorController.h"
+#include "Logging.h"
+#include "MediaCanStartListener.h"
+#include "Navigator.h"
+#include "NetworkStateNotifier.h"
+#include "PageGroup.h"
+#include "PluginData.h"
+#include "PluginHalter.h"
+#include "PluginView.h"
+#include "PluginViewBase.h"
+#include "ProgressTracker.h"
+#include "RenderTheme.h"
+#include "RenderWidget.h"
+#include "RuntimeEnabledFeatures.h"
+#include "ScriptController.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "SharedBuffer.h"
+#include "SpeechInput.h"
+#include "SpeechInputClient.h"
+#include "TextResourceDecoder.h"
+#include "Widget.h"
+#include <wtf/HashMap.h>
+#include <wtf/RefCountedLeakCounter.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringHash.h>
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+#include "SharedGraphicsContext3D.h"
+#endif
+
+#if ENABLE(DOM_STORAGE)
+#include "StorageArea.h"
+#include "StorageNamespace.h"
+#endif
+
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+#include "ScriptDebugServer.h"
+#endif
+
+#if ENABLE(WML)
+#include "WMLPageState.h"
+#endif
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+#include "GeolocationController.h"
+#endif
+
+#if ENABLE(INSPECTOR) && ENABLE(OFFLINE_WEB_APPLICATIONS)
+#include "InspectorApplicationCacheAgent.h"
+#endif
+
+#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+#include "PackageNotifier.h"
+#endif
+
+namespace WebCore {
+
+static HashSet<Page*>* allPages;
+
+#ifndef NDEBUG
+static WTF::RefCountedLeakCounter pageCounter("Page");
+#endif
+
+static void networkStateChanged()
+{
+ Vector<RefPtr<Frame> > frames;
+
+#if ENABLE(INSPECTOR) && ENABLE(OFFLINE_WEB_APPLICATIONS)
+ bool isNowOnline = networkStateNotifier().onLine();
+#endif
+
+ // Get all the frames of all the pages in all the page groups
+ HashSet<Page*>::iterator end = allPages->end();
+ for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
+ for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frames.append(frame);
+#if ENABLE(INSPECTOR) && ENABLE(OFFLINE_WEB_APPLICATIONS)
+ if (InspectorApplicationCacheAgent* applicationCacheAgent = (*it)->inspectorController()->applicationCacheAgent())
+ applicationCacheAgent->updateNetworkState(isNowOnline);
+#endif
+ }
+
+ AtomicString eventName = networkStateNotifier().onLine() ? eventNames().onlineEvent : eventNames().offlineEvent;
+ for (unsigned i = 0; i < frames.size(); i++)
+ frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false));
+}
+
+#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+static void onPackageResultAvailable()
+{
+ HashSet<Page*>::iterator end = allPages->end();
+ for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
+ for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frame->domWindow()->navigator()->onPackageResult();
+ }
+}
+#endif
+
+Page::Page(const PageClients& pageClients)
+ : m_chrome(adoptPtr(new Chrome(this, pageClients.chromeClient)))
+ , m_dragCaretController(adoptPtr(new SelectionController(0, true)))
+#if ENABLE(DRAG_SUPPORT)
+ , m_dragController(adoptPtr(new DragController(this, pageClients.dragClient)))
+#endif
+ , m_focusController(adoptPtr(new FocusController(this)))
+#if ENABLE(CONTEXT_MENUS)
+ , m_contextMenuController(adoptPtr(new ContextMenuController(this, pageClients.contextMenuClient)))
+#endif
+#if ENABLE(INSPECTOR)
+ , m_inspectorController(adoptPtr(new InspectorController(this, pageClients.inspectorClient)))
+#endif
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ , m_geolocationController(adoptPtr(new GeolocationController(this, pageClients.geolocationClient)))
+#endif
+#if ENABLE(DEVICE_ORIENTATION)
+ , m_deviceMotionController(RuntimeEnabledFeatures::deviceMotionEnabled() ? new DeviceMotionController(pageClients.deviceMotionClient) : 0)
+ , m_deviceOrientationController(RuntimeEnabledFeatures::deviceOrientationEnabled() ? new DeviceOrientationController(this, pageClients.deviceOrientationClient) : 0)
+#endif
+#if ENABLE(INPUT_SPEECH)
+ , m_speechInputClient(pageClients.speechInputClient)
+#endif
+ , m_settings(adoptPtr(new Settings(this)))
+ , m_progress(adoptPtr(new ProgressTracker))
+ , m_backForwardController(adoptPtr(new BackForwardController(this, pageClients.backForwardClient)))
+ , m_theme(RenderTheme::themeForPage(this))
+ , m_editorClient(pageClients.editorClient)
+ , m_frameCount(0)
+ , m_openedByDOM(false)
+ , m_tabKeyCyclesThroughElements(true)
+ , m_defersLoading(false)
+ , m_inLowQualityInterpolationMode(false)
+ , m_cookieEnabled(true)
+ , m_areMemoryCacheClientCallsEnabled(true)
+ , m_mediaVolume(1)
+ , m_javaScriptURLsAreAllowed(true)
+ , m_didLoadUserStyleSheet(false)
+ , m_userStyleSheetModificationTime(0)
+ , m_group(0)
+ , m_debugger(0)
+ , m_customHTMLTokenizerTimeDelay(-1)
+ , m_customHTMLTokenizerChunkSize(-1)
+ , m_canStartMedia(true)
+ , m_viewMode(ViewModeWindowed)
+{
+ if (!allPages) {
+ allPages = new HashSet<Page*>;
+
+ networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged);
+#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
+ packageNotifier().setOnResultAvailable(onPackageResultAvailable);
+#endif
+ }
+
+ ASSERT(!allPages->contains(this));
+ allPages->add(this);
+
+ if (pageClients.pluginHalterClient) {
+ m_pluginHalter.set(new PluginHalter(pageClients.pluginHalterClient));
+ m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime());
+ }
+
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+ ScriptDebugServer::shared().pageCreated(this);
+#endif
+
+#ifndef NDEBUG
+ pageCounter.increment();
+#endif
+}
+
+Page::~Page()
+{
+ m_mainFrame->setView(0);
+ setGroupName(String());
+ allPages->remove(this);
+
+ for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frame->pageDestroyed();
+
+ m_editorClient->pageDestroyed();
+
+#if ENABLE(INSPECTOR)
+ m_inspectorController->inspectedPageDestroyed();
+#endif
+
+ backForward()->close();
+
+#ifndef NDEBUG
+ pageCounter.decrement();
+
+ // Cancel keepAlive timers, to ensure we release all Frames before exiting.
+ // It's safe to do this because we prohibit closing a Page while JavaScript
+ // is executing.
+ Frame::cancelAllKeepAlive();
+#endif
+}
+
+struct ViewModeInfo {
+ const char* name;
+ Page::ViewMode type;
+};
+static const int viewModeMapSize = 5;
+static ViewModeInfo viewModeMap[viewModeMapSize] = {
+ {"windowed", Page::ViewModeWindowed},
+ {"floating", Page::ViewModeFloating},
+ {"fullscreen", Page::ViewModeFullscreen},
+ {"maximized", Page::ViewModeMaximized},
+ {"minimized", Page::ViewModeMinimized}
+};
+
+Page::ViewMode Page::stringToViewMode(const String& text)
+{
+ for (int i = 0; i < viewModeMapSize; ++i) {
+ if (text == viewModeMap[i].name)
+ return viewModeMap[i].type;
+ }
+ return Page::ViewModeInvalid;
+}
+
+void Page::setViewMode(ViewMode viewMode)
+{
+ if (viewMode == m_viewMode || viewMode == ViewModeInvalid)
+ return;
+
+ m_viewMode = viewMode;
+
+ if (!m_mainFrame)
+ return;
+
+ if (m_mainFrame->view())
+ m_mainFrame->view()->forceLayout();
+
+ if (m_mainFrame->document())
+ m_mainFrame->document()->styleSelectorChanged(RecalcStyleImmediately);
+}
+
+void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
+{
+ ASSERT(!m_mainFrame); // Should only be called during initialization
+ m_mainFrame = mainFrame;
+}
+
+bool Page::openedByDOM() const
+{
+ return m_openedByDOM;
+}
+
+void Page::setOpenedByDOM()
+{
+ m_openedByDOM = true;
+}
+
+BackForwardList* Page::backForwardList() const
+{
+ return m_backForwardController->client();
+}
+
+bool Page::goBack()
+{
+ HistoryItem* item = backForward()->backItem();
+
+ if (item) {
+ goToItem(item, FrameLoadTypeBack);
+ return true;
+ }
+ return false;
+}
+
+bool Page::goForward()
+{
+ HistoryItem* item = backForward()->forwardItem();
+
+ if (item) {
+ goToItem(item, FrameLoadTypeForward);
+ return true;
+ }
+ return false;
+}
+
+bool Page::canGoBackOrForward(int distance) const
+{
+ if (distance == 0)
+ return true;
+ if (distance > 0 && distance <= backForward()->forwardCount())
+ return true;
+ if (distance < 0 && -distance <= backForward()->backCount())
+ return true;
+ return false;
+}
+
+void Page::goBackOrForward(int distance)
+{
+ if (distance == 0)
+ return;
+
+ HistoryItem* item = backForward()->itemAtIndex(distance);
+ if (!item) {
+ if (distance > 0) {
+ if (int forwardCount = backForward()->forwardCount())
+ item = backForward()->itemAtIndex(forwardCount);
+ } else {
+ if (int backCount = backForward()->backCount())
+ item = backForward()->itemAtIndex(-backCount);
+ }
+ }
+
+ ASSERT(item);
+ if (!item)
+ return;
+
+ goToItem(item, FrameLoadTypeIndexedBackForward);
+}
+
+void Page::goToItem(HistoryItem* item, FrameLoadType type)
+{
+ if (defersLoading())
+ return;
+
+ // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
+ // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
+ RefPtr<HistoryItem> protector(item);
+
+ // Abort any current load unless we're navigating the current document to a new state object
+ HistoryItem* currentItem = m_mainFrame->loader()->history()->currentItem();
+ if (!item->stateObject() || !currentItem || item->documentSequenceNumber() != currentItem->documentSequenceNumber() || item == currentItem) {
+ // Define what to do with any open database connections. By default we stop them and terminate the database thread.
+ DatabasePolicy databasePolicy = DatabasePolicyStop;
+
+#if ENABLE(DATABASE)
+ // If we're navigating the history via a fragment on the same document, then we do not want to stop databases.
+ const KURL& currentURL = m_mainFrame->loader()->url();
+ const KURL& newURL = item->url();
+
+ if (newURL.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(currentURL, newURL))
+ databasePolicy = DatabasePolicyContinue;
+#endif
+
+ m_mainFrame->loader()->stopAllLoaders(databasePolicy);
+ }
+
+ m_mainFrame->loader()->history()->goToItem(item, type);
+}
+
+int Page::getHistoryLength()
+{
+ return backForward()->backCount() + 1 + backForward()->forwardCount();
+}
+
+void Page::setGlobalHistoryItem(HistoryItem* item)
+{
+ m_globalHistoryItem = item;
+}
+
+void Page::setGroupName(const String& name)
+{
+ if (m_group && !m_group->name().isEmpty()) {
+ ASSERT(m_group != m_singlePageGroup.get());
+ ASSERT(!m_singlePageGroup);
+ m_group->removePage(this);
+ }
+
+ if (name.isEmpty())
+ m_group = m_singlePageGroup.get();
+ else {
+ m_singlePageGroup.clear();
+ m_group = PageGroup::pageGroup(name);
+ m_group->addPage(this);
+ }
+}
+
+const String& Page::groupName() const
+{
+ DEFINE_STATIC_LOCAL(String, nullString, ());
+ return m_group ? m_group->name() : nullString;
+}
+
+void Page::initGroup()
+{
+ ASSERT(!m_singlePageGroup);
+ ASSERT(!m_group);
+ m_singlePageGroup.set(new PageGroup(this));
+ m_group = m_singlePageGroup.get();
+}
+
+void Page::scheduleForcedStyleRecalcForAllPages()
+{
+ if (!allPages)
+ return;
+ HashSet<Page*>::iterator end = allPages->end();
+ for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
+ for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frame->document()->scheduleForcedStyleRecalc();
+}
+
+void Page::updateViewportArguments()
+{
+ if (!mainFrame() || !mainFrame()->document() || mainFrame()->document()->viewportArguments() == m_viewportArguments)
+ return;
+
+ m_viewportArguments = mainFrame()->document()->viewportArguments();
+ chrome()->dispatchViewportDataDidChange(m_viewportArguments);
+}
+
+void Page::refreshPlugins(bool reload)
+{
+ if (!allPages)
+ return;
+
+ PluginData::refresh();
+
+ Vector<RefPtr<Frame> > framesNeedingReload;
+
+ HashSet<Page*>::iterator end = allPages->end();
+ for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
+ Page* page = *it;
+
+ // Clear out the page's plug-in data.
+ if (page->m_pluginData)
+ page->m_pluginData = 0;
+
+ if (!reload)
+ continue;
+
+ for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (frame->loader()->subframeLoader()->containsPlugins())
+ framesNeedingReload.append(frame);
+ }
+ }
+
+ for (size_t i = 0; i < framesNeedingReload.size(); ++i)
+ framesNeedingReload[i]->loader()->reload();
+}
+
+PluginData* Page::pluginData() const
+{
+ if (!mainFrame()->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
+ return 0;
+ if (!m_pluginData)
+ m_pluginData = PluginData::create(this);
+ return m_pluginData.get();
+}
+
+inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
+{
+ for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
+ return listener;
+ }
+ return 0;
+}
+
+void Page::setCanStartMedia(bool canStartMedia)
+{
+ if (m_canStartMedia == canStartMedia)
+ return;
+
+ m_canStartMedia = canStartMedia;
+
+ while (m_canStartMedia) {
+ MediaCanStartListener* listener = takeAnyMediaCanStartListener();
+ if (!listener)
+ break;
+ listener->mediaCanStart();
+ }
+}
+
+static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
+{
+ return forward
+ ? curr->tree()->traverseNextWithWrap(wrapFlag)
+ : curr->tree()->traversePreviousWithWrap(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, (options & ~WrapAround) | StartInSelection)) {
+ if (frame != startFrame)
+ startFrame->selection()->clear();
+ focusController()->setFocusedFrame(frame);
+ return true;
+ }
+ 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, options | WrapAround | StartInSelection);
+ focusController()->setFocusedFrame(frame);
+ return found;
+ }
+
+ return false;
+}
+
+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;
+
+ unsigned matches = 0;
+
+ Frame* frame = mainFrame();
+ do {
+ frame->editor()->setMarkedTextMatchesAreHighlighted(shouldHighlight);
+ matches += frame->editor()->countMatchesForText(target, options, limit ? (limit - matches) : 0, true);
+ frame = incrementFrame(frame, true, false);
+ } while (frame);
+
+ return matches;
+}
+
+void Page::unmarkAllTextMatches()
+{
+ if (!mainFrame())
+ return;
+
+ Frame* frame = mainFrame();
+ do {
+ frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
+ frame = incrementFrame(frame, true, false);
+ } while (frame);
+}
+
+const VisibleSelection& Page::selection() const
+{
+ return focusController()->focusedOrMainFrame()->selection()->selection();
+}
+
+void Page::setDefersLoading(bool defers)
+{
+ if (!m_settings->loadDeferringEnabled())
+ return;
+
+ if (defers == m_defersLoading)
+ return;
+
+ m_defersLoading = defers;
+ for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frame->loader()->setDefersLoading(defers);
+}
+
+void Page::clearUndoRedoOperations()
+{
+ m_editorClient->clearUndoRedoOperations();
+}
+
+bool Page::inLowQualityImageInterpolationMode() const
+{
+ return m_inLowQualityInterpolationMode;
+}
+
+void Page::setInLowQualityImageInterpolationMode(bool mode)
+{
+ m_inLowQualityInterpolationMode = mode;
+}
+
+void Page::setMediaVolume(float volume)
+{
+ if (volume < 0 || volume > 1)
+ return;
+
+ if (m_mediaVolume == volume)
+ return;
+
+ m_mediaVolume = volume;
+ for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ frame->document()->mediaVolumeDidChange();
+ }
+}
+
+void Page::didMoveOnscreen()
+{
+ for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (frame->view())
+ frame->view()->didMoveOnscreen();
+ }
+}
+
+void Page::willMoveOffscreen()
+{
+ for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (frame->view())
+ frame->view()->willMoveOffscreen();
+ }
+}
+
+void Page::userStyleSheetLocationChanged()
+{
+ // FIXME: Eventually we will move to a model of just being handed the sheet
+ // text instead of loading the URL ourselves.
+ KURL url = m_settings->userStyleSheetLocation();
+ if (url.isLocalFile())
+ m_userStyleSheetPath = url.fileSystemPath();
+ else
+ m_userStyleSheetPath = String();
+
+ m_didLoadUserStyleSheet = false;
+ m_userStyleSheet = String();
+ m_userStyleSheetModificationTime = 0;
+
+ // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
+ // synchronously and avoid using a loader.
+ if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
+ m_didLoadUserStyleSheet = true;
+
+ Vector<char> styleSheetAsUTF8;
+ if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, IgnoreWhitespace))
+ m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
+ }
+
+ for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (frame->document())
+ frame->document()->updatePageUserSheet();
+ }
+}
+
+const String& Page::userStyleSheet() const
+{
+ if (m_userStyleSheetPath.isEmpty())
+ return m_userStyleSheet;
+
+ time_t modTime;
+ if (!getFileModificationTime(m_userStyleSheetPath, modTime)) {
+ // The stylesheet either doesn't exist, was just deleted, or is
+ // otherwise unreadable. If we've read the stylesheet before, we should
+ // throw away that data now as it no longer represents what's on disk.
+ m_userStyleSheet = String();
+ return m_userStyleSheet;
+ }
+
+ // If the stylesheet hasn't changed since the last time we read it, we can
+ // just return the old data.
+ if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime)
+ return m_userStyleSheet;
+
+ m_didLoadUserStyleSheet = true;
+ m_userStyleSheet = String();
+ m_userStyleSheetModificationTime = modTime;
+
+ // FIXME: It would be better to load this asynchronously to avoid blocking
+ // the process, but we will first need to create an asynchronous loading
+ // mechanism that is not tied to a particular Frame. We will also have to
+ // determine what our behavior should be before the stylesheet is loaded
+ // and what should happen when it finishes loading, especially with respect
+ // to when the load event fires, when Document::close is called, and when
+ // layout/paint are allowed to happen.
+ RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
+ if (!data)
+ return m_userStyleSheet;
+
+ RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css");
+ m_userStyleSheet = decoder->decode(data->data(), data->size());
+ m_userStyleSheet += decoder->flush();
+
+ return m_userStyleSheet;
+}
+
+void Page::removeAllVisitedLinks()
+{
+ if (!allPages)
+ return;
+ HashSet<PageGroup*> groups;
+ HashSet<Page*>::iterator pagesEnd = allPages->end();
+ for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
+ if (PageGroup* group = (*it)->groupPtr())
+ groups.add(group);
+ }
+ HashSet<PageGroup*>::iterator groupsEnd = groups.end();
+ for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it)
+ (*it)->removeVisitedLinks();
+}
+
+void Page::allVisitedStateChanged(PageGroup* group)
+{
+ ASSERT(group);
+ if (!allPages)
+ return;
+
+ HashSet<Page*>::iterator pagesEnd = allPages->end();
+ for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
+ Page* page = *it;
+ if (page->m_group != group)
+ continue;
+ for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
+ if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
+ styleSelector->allVisitedStateChanged();
+ }
+ }
+}
+
+void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash)
+{
+ ASSERT(group);
+ if (!allPages)
+ return;
+
+ HashSet<Page*>::iterator pagesEnd = allPages->end();
+ for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
+ Page* page = *it;
+ if (page->m_group != group)
+ continue;
+ for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
+ if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
+ styleSelector->visitedStateChanged(visitedLinkHash);
+ }
+ }
+}
+
+void Page::setDebuggerForAllPages(JSC::Debugger* debugger)
+{
+ ASSERT(allPages);
+
+ HashSet<Page*>::iterator end = allPages->end();
+ for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
+ (*it)->setDebugger(debugger);
+}
+
+void Page::setDebugger(JSC::Debugger* debugger)
+{
+ if (m_debugger == debugger)
+ return;
+
+ m_debugger = debugger;
+
+ for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext())
+ frame->script()->attachDebugger(m_debugger);
+}
+
+SharedGraphicsContext3D* Page::sharedGraphicsContext3D()
+{
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ if (!m_sharedGraphicsContext3D)
+ m_sharedGraphicsContext3D = SharedGraphicsContext3D::create(chrome());
+
+ return m_sharedGraphicsContext3D.get();
+#else
+ return 0;
+#endif
+}
+
+#if ENABLE(DOM_STORAGE)
+StorageNamespace* Page::sessionStorage(bool optionalCreate)
+{
+ if (!m_sessionStorage && optionalCreate)
+ m_sessionStorage = StorageNamespace::sessionStorageNamespace(this, m_settings->sessionStorageQuota());
+
+ return m_sessionStorage.get();
+}
+
+void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage)
+{
+ m_sessionStorage = newStorage;
+}
+#endif
+
+#if ENABLE(WML)
+WMLPageState* Page::wmlPageState()
+{
+ if (!m_wmlPageState)
+ m_wmlPageState.set(new WMLPageState(this));
+ return m_wmlPageState.get();
+}
+#endif
+
+void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay)
+{
+ if (customHTMLTokenizerTimeDelay < 0) {
+ m_customHTMLTokenizerTimeDelay = -1;
+ return;
+ }
+ m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay;
+}
+
+void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize)
+{
+ if (customHTMLTokenizerChunkSize < 0) {
+ m_customHTMLTokenizerChunkSize = -1;
+ return;
+ }
+ m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize;
+}
+
+void Page::setMemoryCacheClientCallsEnabled(bool enabled)
+{
+ if (m_areMemoryCacheClientCallsEnabled == enabled)
+ return;
+
+ m_areMemoryCacheClientCallsEnabled = enabled;
+ if (!enabled)
+ return;
+
+ for (RefPtr<Frame> frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frame->loader()->tellClientAboutPastMemoryCacheLoads();
+}
+
+void Page::setJavaScriptURLsAreAllowed(bool areAllowed)
+{
+ m_javaScriptURLsAreAllowed = areAllowed;
+}
+
+bool Page::javaScriptURLsAreAllowed() const
+{
+ return m_javaScriptURLsAreAllowed;
+}
+
+#if ENABLE(INPUT_SPEECH)
+SpeechInput* Page::speechInput()
+{
+ ASSERT(m_speechInputClient);
+ if (!m_speechInput.get())
+ m_speechInput.set(new SpeechInput(m_speechInputClient));
+ return m_speechInput.get();
+}
+#endif
+
+void Page::dnsPrefetchingStateChanged()
+{
+ for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frame->document()->initDNSPrefetch();
+}
+
+void Page::privateBrowsingStateChanged()
+{
+ bool privateBrowsingEnabled = m_settings->privateBrowsingEnabled();
+
+ // Collect the PluginViews in to a vector to ensure that action the plug-in takes
+ // from below privateBrowsingStateChanged does not affect their lifetime.
+ Vector<RefPtr<PluginViewBase>, 32> pluginViewBases;
+ for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ FrameView* view = frame->view();
+ if (!view)
+ return;
+
+ const HashSet<RefPtr<Widget> >* children = view->children();
+ ASSERT(children);
+
+ HashSet<RefPtr<Widget> >::const_iterator end = children->end();
+ for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) {
+ Widget* widget = (*it).get();
+ if (widget->isPluginViewBase())
+ pluginViewBases.append(static_cast<PluginViewBase*>(widget));
+ }
+ }
+
+ for (size_t i = 0; i < pluginViewBases.size(); ++i)
+ pluginViewBases[i]->privateBrowsingStateChanged(privateBrowsingEnabled);
+}
+
+void Page::pluginAllowedRunTimeChanged()
+{
+ if (m_pluginHalter)
+ m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime());
+}
+
+void Page::didStartPlugin(HaltablePlugin* obj)
+{
+ if (m_pluginHalter)
+ m_pluginHalter->didStartPlugin(obj);
+}
+
+void Page::didStopPlugin(HaltablePlugin* obj)
+{
+ if (m_pluginHalter)
+ m_pluginHalter->didStopPlugin(obj);
+}
+
+#if !ASSERT_DISABLED
+void Page::checkFrameCountConsistency() const
+{
+ ASSERT(m_frameCount >= 0);
+
+ int frameCount = 0;
+ for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
+ ++frameCount;
+
+ ASSERT(m_frameCount + 1 == frameCount);
+}
+#endif
+
+Page::PageClients::PageClients()
+ : chromeClient(0)
+ , contextMenuClient(0)
+ , editorClient(0)
+ , dragClient(0)
+ , inspectorClient(0)
+ , pluginHalterClient(0)
+ , geolocationClient(0)
+ , deviceMotionClient(0)
+ , deviceOrientationClient(0)
+ , speechInputClient(0)
+{
+}
+
+Page::PageClients::~PageClients()
+{
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/Page.h b/Source/WebCore/page/Page.h
new file mode 100644
index 0000000..7413bb6
--- /dev/null
+++ b/Source/WebCore/page/Page.h
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef Page_h
+#define Page_h
+
+#include "FrameLoaderTypes.h"
+#include "FindOptions.h"
+#include "PlatformString.h"
+#include "ViewportArguments.h"
+#include <wtf/Forward.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+
+#if PLATFORM(MAC)
+#include "SchedulePair.h"
+#endif
+
+namespace JSC {
+ class Debugger;
+}
+
+namespace WebCore {
+
+ class BackForwardController;
+ class BackForwardList;
+ class Chrome;
+ class ChromeClient;
+ class ContextMenuClient;
+ class ContextMenuController;
+ class DeviceMotionClient;
+ class DeviceMotionController;
+ class DeviceOrientationClient;
+ class DeviceOrientationController;
+ class Document;
+ class DragClient;
+ class DragController;
+ class EditorClient;
+ class FocusController;
+ class Frame;
+ class GeolocationClient;
+ class GeolocationController;
+ class HaltablePlugin;
+ class HistoryItem;
+ class InspectorClient;
+ class InspectorController;
+ class MediaCanStartListener;
+ class Node;
+ class PageGroup;
+ class PluginData;
+ class PluginHalter;
+ class PluginHalterClient;
+ class ProgressTracker;
+ class RenderTheme;
+ class VisibleSelection;
+ class SelectionController;
+ class Settings;
+ class SharedGraphicsContext3D;
+ class SpeechInput;
+ class SpeechInputClient;
+
+#if ENABLE(DOM_STORAGE)
+ class StorageNamespace;
+#endif
+#if ENABLE(NOTIFICATIONS)
+ class NotificationPresenter;
+#endif
+#if ENABLE(WML)
+ class WMLPageState;
+#endif
+
+ typedef uint64_t LinkHash;
+
+ enum FindDirection { FindDirectionForward, FindDirectionBackward };
+
+ class Page : public Noncopyable {
+ public:
+ static void scheduleForcedStyleRecalcForAllPages();
+
+ // It is up to the platform to ensure that non-null clients are provided where required.
+ struct PageClients : Noncopyable {
+ PageClients();
+ ~PageClients();
+
+ ChromeClient* chromeClient;
+ ContextMenuClient* contextMenuClient;
+ EditorClient* editorClient;
+ DragClient* dragClient;
+ InspectorClient* inspectorClient;
+ PluginHalterClient* pluginHalterClient;
+ GeolocationClient* geolocationClient;
+ DeviceMotionClient* deviceMotionClient;
+ DeviceOrientationClient* deviceOrientationClient;
+ RefPtr<BackForwardList> backForwardClient;
+ SpeechInputClient* speechInputClient;
+ };
+
+ Page(const PageClients&);
+ ~Page();
+
+ RenderTheme* theme() const { return m_theme.get(); };
+
+ ViewportArguments viewportArguments() const { return m_viewportArguments; }
+ void updateViewportArguments();
+
+ static void refreshPlugins(bool reload);
+ PluginData* pluginData() const;
+
+ void setCanStartMedia(bool);
+ bool canStartMedia() const { return m_canStartMedia; }
+
+ EditorClient* editorClient() const { return m_editorClient; }
+
+ void setMainFrame(PassRefPtr<Frame>);
+ Frame* mainFrame() const { return m_mainFrame.get(); }
+
+ bool openedByDOM() const;
+ void setOpenedByDOM();
+
+ // DEPRECATED. Use backForward() instead of the following 6 functions.
+ BackForwardList* backForwardList() const;
+ bool goBack();
+ bool goForward();
+ bool canGoBackOrForward(int distance) const;
+ void goBackOrForward(int distance);
+ int getHistoryLength();
+
+ void goToItem(HistoryItem*, FrameLoadType);
+
+ HistoryItem* globalHistoryItem() const { return m_globalHistoryItem.get(); }
+ void setGlobalHistoryItem(HistoryItem*);
+
+ void setGroupName(const String&);
+ const String& groupName() const;
+
+ PageGroup& group() { if (!m_group) initGroup(); return *m_group; }
+ PageGroup* groupPtr() { return m_group; } // can return 0
+
+ void incrementFrameCount() { ++m_frameCount; }
+ void decrementFrameCount() { ASSERT(m_frameCount); --m_frameCount; }
+ int frameCount() const { checkFrameCountConsistency(); return m_frameCount; }
+
+ Chrome* chrome() const { return m_chrome.get(); }
+ SelectionController* dragCaretController() const { return m_dragCaretController.get(); }
+#if ENABLE(DRAG_SUPPORT)
+ DragController* dragController() const { return m_dragController.get(); }
+#endif
+ FocusController* focusController() const { return m_focusController.get(); }
+#if ENABLE(CONTEXT_MENUS)
+ ContextMenuController* contextMenuController() const { return m_contextMenuController.get(); }
+#endif
+#if ENABLE(INSPECTOR)
+ InspectorController* inspectorController() const { return m_inspectorController.get(); }
+#endif
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ GeolocationController* geolocationController() const { return m_geolocationController.get(); }
+#endif
+#if ENABLE(DEVICE_ORIENTATION)
+ DeviceMotionController* deviceMotionController() const { return m_deviceMotionController.get(); }
+ DeviceOrientationController* deviceOrientationController() const { return m_deviceOrientationController.get(); }
+#endif
+#if ENABLE(INPUT_SPEECH)
+ SpeechInput* speechInput();
+#endif
+ Settings* settings() const { return m_settings.get(); }
+ ProgressTracker* progress() const { return m_progress.get(); }
+ BackForwardController* backForward() const { return m_backForwardController.get(); }
+
+ enum ViewMode {
+ ViewModeInvalid,
+ ViewModeWindowed,
+ ViewModeFloating,
+ ViewModeFullscreen,
+ ViewModeMaximized,
+ ViewModeMinimized
+ };
+ static ViewMode stringToViewMode(const String&);
+
+ ViewMode viewMode() const { return m_viewMode; }
+ void setViewMode(ViewMode);
+
+ 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 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)
+ void addSchedulePair(PassRefPtr<SchedulePair>);
+ void removeSchedulePair(PassRefPtr<SchedulePair>);
+ SchedulePairHashSet* scheduledRunLoopPairs() { return m_scheduledRunLoopPairs.get(); }
+
+ OwnPtr<SchedulePairHashSet> m_scheduledRunLoopPairs;
+#endif
+
+ const VisibleSelection& selection() const;
+
+ void setDefersLoading(bool);
+ bool defersLoading() const { return m_defersLoading; }
+
+ void clearUndoRedoOperations();
+
+ bool inLowQualityImageInterpolationMode() const;
+ void setInLowQualityImageInterpolationMode(bool = true);
+
+ bool cookieEnabled() const { return m_cookieEnabled; }
+ void setCookieEnabled(bool enabled) { m_cookieEnabled = enabled; }
+
+ float mediaVolume() const { return m_mediaVolume; }
+ void setMediaVolume(float volume);
+
+ // Notifications when the Page starts and stops being presented via a native window.
+ void didMoveOnscreen();
+ void willMoveOffscreen();
+
+ void userStyleSheetLocationChanged();
+ const String& userStyleSheet() const;
+
+ void dnsPrefetchingStateChanged();
+ void privateBrowsingStateChanged();
+
+ void didStartPlugin(HaltablePlugin*);
+ void didStopPlugin(HaltablePlugin*);
+ void pluginAllowedRunTimeChanged();
+
+ static void setDebuggerForAllPages(JSC::Debugger*);
+ void setDebugger(JSC::Debugger*);
+ JSC::Debugger* debugger() const { return m_debugger; }
+
+ static void removeAllVisitedLinks();
+
+ static void allVisitedStateChanged(PageGroup*);
+ static void visitedStateChanged(PageGroup*, LinkHash visitedHash);
+
+ SharedGraphicsContext3D* sharedGraphicsContext3D();
+
+#if ENABLE(DOM_STORAGE)
+ StorageNamespace* sessionStorage(bool optionalCreate = true);
+ void setSessionStorage(PassRefPtr<StorageNamespace>);
+#endif
+
+#if ENABLE(WML)
+ WMLPageState* wmlPageState();
+#endif
+
+ void setCustomHTMLTokenizerTimeDelay(double);
+ bool hasCustomHTMLTokenizerTimeDelay() const { return m_customHTMLTokenizerTimeDelay != -1; }
+ double customHTMLTokenizerTimeDelay() const { ASSERT(m_customHTMLTokenizerTimeDelay != -1); return m_customHTMLTokenizerTimeDelay; }
+
+ void setCustomHTMLTokenizerChunkSize(int);
+ bool hasCustomHTMLTokenizerChunkSize() const { return m_customHTMLTokenizerChunkSize != -1; }
+ int customHTMLTokenizerChunkSize() const { ASSERT(m_customHTMLTokenizerChunkSize != -1); return m_customHTMLTokenizerChunkSize; }
+
+ void setMemoryCacheClientCallsEnabled(bool);
+ bool areMemoryCacheClientCallsEnabled() const { return m_areMemoryCacheClientCallsEnabled; }
+
+ void setJavaScriptURLsAreAllowed(bool);
+ bool javaScriptURLsAreAllowed() const;
+
+ // Don't allow more than a certain number of frames in a page.
+ // This seems like a reasonable upper bound, and otherwise mutually
+ // recursive frameset pages can quickly bring the program to its knees
+ // with exponential growth in the number of frames.
+ static const int maxNumberOfFrames = 1000;
+ private:
+ void initGroup();
+
+#if ASSERT_DISABLED
+ void checkFrameCountConsistency() const { }
+#else
+ void checkFrameCountConsistency() const;
+#endif
+
+ MediaCanStartListener* takeAnyMediaCanStartListener();
+
+ OwnPtr<Chrome> m_chrome;
+ OwnPtr<SelectionController> m_dragCaretController;
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ RefPtr<SharedGraphicsContext3D> m_sharedGraphicsContext3D;
+#endif
+
+#if ENABLE(DRAG_SUPPORT)
+ OwnPtr<DragController> m_dragController;
+#endif
+ OwnPtr<FocusController> m_focusController;
+#if ENABLE(CONTEXT_MENUS)
+ OwnPtr<ContextMenuController> m_contextMenuController;
+#endif
+#if ENABLE(INSPECTOR)
+ OwnPtr<InspectorController> m_inspectorController;
+#endif
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ OwnPtr<GeolocationController> m_geolocationController;
+#endif
+#if ENABLE(DEVICE_ORIENTATION)
+ OwnPtr<DeviceMotionController> m_deviceMotionController;
+ OwnPtr<DeviceOrientationController> m_deviceOrientationController;
+#endif
+#if ENABLE(INPUT_SPEECH)
+ SpeechInputClient* m_speechInputClient;
+ OwnPtr<SpeechInput> m_speechInput;
+#endif
+ OwnPtr<Settings> m_settings;
+ OwnPtr<ProgressTracker> m_progress;
+
+ OwnPtr<BackForwardController> m_backForwardController;
+ RefPtr<Frame> m_mainFrame;
+
+ RefPtr<HistoryItem> m_globalHistoryItem;
+
+ mutable RefPtr<PluginData> m_pluginData;
+
+ RefPtr<RenderTheme> m_theme;
+
+ EditorClient* m_editorClient;
+
+ int m_frameCount;
+ String m_groupName;
+ bool m_openedByDOM;
+
+ bool m_tabKeyCyclesThroughElements;
+ bool m_defersLoading;
+
+ bool m_inLowQualityInterpolationMode;
+ bool m_cookieEnabled;
+ bool m_areMemoryCacheClientCallsEnabled;
+ float m_mediaVolume;
+
+ bool m_javaScriptURLsAreAllowed;
+
+ String m_userStyleSheetPath;
+ mutable String m_userStyleSheet;
+ mutable bool m_didLoadUserStyleSheet;
+ mutable time_t m_userStyleSheetModificationTime;
+
+ OwnPtr<PageGroup> m_singlePageGroup;
+ PageGroup* m_group;
+
+ JSC::Debugger* m_debugger;
+
+ double m_customHTMLTokenizerTimeDelay;
+ int m_customHTMLTokenizerChunkSize;
+
+ bool m_canStartMedia;
+
+ OwnPtr<PluginHalter> m_pluginHalter;
+
+#if ENABLE(DOM_STORAGE)
+ RefPtr<StorageNamespace> m_sessionStorage;
+#endif
+
+#if ENABLE(WML)
+ OwnPtr<WMLPageState> m_wmlPageState;
+#endif
+
+#if ENABLE(NOTIFICATIONS)
+ NotificationPresenter* m_notificationPresenter;
+#endif
+
+ ViewMode m_viewMode;
+
+ ViewportArguments m_viewportArguments;
+ };
+
+} // namespace WebCore
+
+#endif // Page_h
diff --git a/Source/WebCore/page/PageGroup.cpp b/Source/WebCore/page/PageGroup.cpp
new file mode 100644
index 0000000..746cd04
--- /dev/null
+++ b/Source/WebCore/page/PageGroup.cpp
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PageGroup.h"
+
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "Document.h"
+#include "Frame.h"
+#include "GroupSettings.h"
+#include "IDBFactoryBackendInterface.h"
+#include "Page.h"
+#include "Settings.h"
+#include "StorageNamespace.h"
+
+#if PLATFORM(CHROMIUM)
+#include "ChromiumBridge.h"
+#endif
+
+#ifdef ANDROID
+#include "DOMWindow.h"
+#include "FileSystem.h"
+#endif
+
+namespace WebCore {
+
+static unsigned getUniqueIdentifier()
+{
+ static unsigned currentIdentifier = 0;
+ return ++currentIdentifier;
+}
+
+// --------
+
+static bool shouldTrackVisitedLinks = false;
+
+PageGroup::PageGroup(const String& name)
+ : m_name(name)
+ , m_visitedLinksPopulated(false)
+ , m_identifier(getUniqueIdentifier())
+ , m_groupSettings(GroupSettings::create())
+{
+}
+
+PageGroup::PageGroup(Page* page)
+ : m_visitedLinksPopulated(false)
+ , m_identifier(getUniqueIdentifier())
+ , m_groupSettings(GroupSettings::create())
+{
+ ASSERT(page);
+ addPage(page);
+}
+
+PageGroup::~PageGroup()
+{
+ removeAllUserContent();
+}
+
+typedef HashMap<String, PageGroup*> PageGroupMap;
+static PageGroupMap* pageGroups = 0;
+
+PageGroup* PageGroup::pageGroup(const String& groupName)
+{
+ ASSERT(!groupName.isEmpty());
+
+ if (!pageGroups)
+ pageGroups = new PageGroupMap;
+
+ pair<PageGroupMap::iterator, bool> result = pageGroups->add(groupName, 0);
+
+ if (result.second) {
+ ASSERT(!result.first->second);
+ result.first->second = new PageGroup(groupName);
+ }
+
+ ASSERT(result.first->second);
+ return result.first->second;
+}
+
+void PageGroup::closeLocalStorage()
+{
+#if ENABLE(DOM_STORAGE)
+ if (!pageGroups)
+ return;
+
+ PageGroupMap::iterator end = pageGroups->end();
+
+ for (PageGroupMap::iterator it = pageGroups->begin(); it != end; ++it) {
+ if (it->second->hasLocalStorage())
+ it->second->localStorage()->close();
+ }
+#endif
+}
+
+#if ENABLE(DOM_STORAGE) && defined(ANDROID)
+void PageGroup::clearDomStorage()
+{
+ if (!pageGroups)
+ return;
+
+
+ PageGroupMap::iterator end = pageGroups->end();
+
+ for (PageGroupMap::iterator it = pageGroups->begin(); it != end; ++it) {
+ String basePath = "";
+
+ // This is being called as a result of the user explicitly
+ // asking to clear all stored data (e.g. through a settings
+ // dialog. We need a page in the page group to fire a
+ // StorageEvent. There isn't really a correct page to use
+ // as the source (as the clear request hasn't come from a
+ // particular page). One thing we should ensure though is that
+ // we don't try to clear a private browsing mode page as that has no concept
+ // of DOM storage..
+
+ HashSet<Page*> pages = it->second->pages();
+ HashSet<Page*>::iterator pagesEnd = pages.end();
+ Page* page = 0;
+ for(HashSet<Page*>::iterator pit = pages.begin(); pit != pagesEnd; ++pit) {
+ Page* p = *pit;
+
+ // Grab the storage location from an arbitrary page. This is set
+ // to the same value on all private browsing and "normal" pages,
+ // so we can get it from anything.
+ if (basePath.isEmpty())
+ basePath = p->settings()->localStorageDatabasePath();
+
+ // DOM storage is disabled in private browsing pages, so nothing to do if
+ // this is such a page.
+ if (p->settings()->privateBrowsingEnabled())
+ continue;
+
+ // Clear session storage.
+ StorageNamespace* sessionStorage = p->sessionStorage(false);
+ if (sessionStorage)
+ sessionStorage->clear(p);
+
+ // Save this page so we can clear local storage.
+ page = p;
+ }
+
+ // If page is still null at this point, then the only pages that are
+ // open are private browsing pages. Hence no pages are currently using local
+ // storage, so we don't need a page pointer to send any events and the
+ // clear function will handle a 0 input.
+ it->second->localStorage()->clear(page);
+ it->second->localStorage()->close();
+
+ // Closing the storage areas will stop the background thread and so
+ // we need to remove the local storage ref here so that next time
+ // we come to a site that uses it the thread will get started again.
+ it->second->removeLocalStorage();
+
+ // At this point, active local and session storage have been cleared and the
+ // StorageAreas for this PageGroup closed. The final sync will have taken
+ // place. All that is left is to purge the database files.
+ if (!basePath.isEmpty()) {
+ Vector<String> files = listDirectory(basePath, "*.localstorage");
+ Vector<String>::iterator filesEnd = files.end();
+ for (Vector<String>::iterator it = files.begin(); it != filesEnd; ++it)
+ deleteFile(*it);
+ }
+ }
+}
+
+void PageGroup::removeLocalStorage()
+{
+ HashSet<Page*> pages = this->pages();
+ HashSet<Page*>::iterator pagesEnd = pages.end();
+ for(HashSet<Page*>::iterator pit = pages.begin(); pit != pagesEnd; ++pit) {
+ Page* p = *pit;
+ for (Frame* frame = p->mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frame->document()->domWindow()->clearDOMStorage();
+ }
+
+ m_localStorage = 0;
+}
+#endif
+
+void PageGroup::addPage(Page* page)
+{
+ ASSERT(page);
+ ASSERT(!m_pages.contains(page));
+ m_pages.add(page);
+}
+
+void PageGroup::removePage(Page* page)
+{
+ ASSERT(page);
+ ASSERT(m_pages.contains(page));
+ m_pages.remove(page);
+}
+
+bool PageGroup::isLinkVisited(LinkHash visitedLinkHash)
+{
+#if PLATFORM(CHROMIUM)
+ // Use Chromium's built-in visited link database.
+ return ChromiumBridge::isLinkVisited(visitedLinkHash);
+#else
+ if (!m_visitedLinksPopulated) {
+ m_visitedLinksPopulated = true;
+ ASSERT(!m_pages.isEmpty());
+ (*m_pages.begin())->chrome()->client()->populateVisitedLinks();
+ }
+ return m_visitedLinkHashes.contains(visitedLinkHash);
+#endif
+}
+
+void PageGroup::addVisitedLinkHash(LinkHash hash)
+{
+ if (shouldTrackVisitedLinks)
+ addVisitedLink(hash);
+}
+
+inline void PageGroup::addVisitedLink(LinkHash hash)
+{
+ ASSERT(shouldTrackVisitedLinks);
+#if !PLATFORM(CHROMIUM)
+ if (!m_visitedLinkHashes.add(hash).second)
+ return;
+#endif
+ Page::visitedStateChanged(this, hash);
+}
+
+void PageGroup::addVisitedLink(const KURL& url)
+{
+ if (!shouldTrackVisitedLinks)
+ return;
+ ASSERT(!url.isEmpty());
+ addVisitedLink(visitedLinkHash(url.string().characters(), url.string().length()));
+}
+
+void PageGroup::addVisitedLink(const UChar* characters, size_t length)
+{
+ if (!shouldTrackVisitedLinks)
+ return;
+ addVisitedLink(visitedLinkHash(characters, length));
+}
+
+void PageGroup::removeVisitedLinks()
+{
+ m_visitedLinksPopulated = false;
+ if (m_visitedLinkHashes.isEmpty())
+ return;
+ m_visitedLinkHashes.clear();
+ Page::allVisitedStateChanged(this);
+}
+
+void PageGroup::removeAllVisitedLinks()
+{
+ Page::removeAllVisitedLinks();
+}
+
+void PageGroup::setShouldTrackVisitedLinks(bool shouldTrack)
+{
+ if (shouldTrackVisitedLinks == shouldTrack)
+ return;
+ shouldTrackVisitedLinks = shouldTrack;
+ if (!shouldTrackVisitedLinks)
+ removeAllVisitedLinks();
+}
+
+#if ENABLE(DOM_STORAGE)
+StorageNamespace* PageGroup::localStorage()
+{
+ if (!m_localStorage) {
+ // Need a page in this page group to query the settings for the local storage database path.
+ // Having these parameters attached to the page settings is unfortunate since these settings are
+ // not per-page (and, in fact, we simply grab the settings from some page at random), but
+ // at this point we're stuck with it.
+ Page* page = *m_pages.begin();
+ const String& path = page->settings()->localStorageDatabasePath();
+ unsigned quota = m_groupSettings->localStorageQuotaBytes();
+ m_localStorage = StorageNamespace::localStorageNamespace(path, quota);
+ }
+
+ return m_localStorage.get();
+}
+#endif
+
+#if ENABLE(INDEXED_DATABASE)
+IDBFactoryBackendInterface* PageGroup::idbFactory()
+{
+ // Do not add page setting based access control here since this object is shared by all pages in
+ // the group and having per-page controls is misleading.
+ if (!m_factoryBackend)
+ m_factoryBackend = IDBFactoryBackendInterface::create();
+ return m_factoryBackend.get();
+}
+#endif
+
+void PageGroup::addUserScriptToWorld(DOMWrapperWorld* world, const String& source, const KURL& url,
+ PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist,
+ UserScriptInjectionTime injectionTime, UserContentInjectedFrames injectedFrames)
+{
+ ASSERT_ARG(world, world);
+
+ OwnPtr<UserScript> userScript(new UserScript(source, url, whitelist, blacklist, injectionTime, injectedFrames));
+ if (!m_userScripts)
+ m_userScripts.set(new UserScriptMap);
+ UserScriptVector*& scriptsInWorld = m_userScripts->add(world, 0).first->second;
+ if (!scriptsInWorld)
+ scriptsInWorld = new UserScriptVector;
+ scriptsInWorld->append(userScript.release());
+}
+
+void PageGroup::addUserStyleSheetToWorld(DOMWrapperWorld* world, const String& source, const KURL& url,
+ PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist,
+ UserContentInjectedFrames injectedFrames,
+ UserStyleLevel level,
+ UserStyleInjectionTime injectionTime)
+{
+ ASSERT_ARG(world, world);
+
+ OwnPtr<UserStyleSheet> userStyleSheet(new UserStyleSheet(source, url, whitelist, blacklist, injectedFrames, level));
+ if (!m_userStyleSheets)
+ m_userStyleSheets.set(new UserStyleSheetMap);
+ UserStyleSheetVector*& styleSheetsInWorld = m_userStyleSheets->add(world, 0).first->second;
+ if (!styleSheetsInWorld)
+ styleSheetsInWorld = new UserStyleSheetVector;
+ styleSheetsInWorld->append(userStyleSheet.release());
+
+ if (injectionTime == InjectInExistingDocuments)
+ resetUserStyleCacheInAllFrames();
+}
+
+void PageGroup::removeUserScriptFromWorld(DOMWrapperWorld* world, const KURL& url)
+{
+ ASSERT_ARG(world, world);
+
+ if (!m_userScripts)
+ return;
+
+ UserScriptMap::iterator it = m_userScripts->find(world);
+ if (it == m_userScripts->end())
+ return;
+
+ UserScriptVector* scripts = it->second;
+ for (int i = scripts->size() - 1; i >= 0; --i) {
+ if (scripts->at(i)->url() == url)
+ scripts->remove(i);
+ }
+
+ if (!scripts->isEmpty())
+ return;
+
+ delete it->second;
+ m_userScripts->remove(it);
+}
+
+void PageGroup::removeUserStyleSheetFromWorld(DOMWrapperWorld* world, const KURL& url)
+{
+ ASSERT_ARG(world, world);
+
+ if (!m_userStyleSheets)
+ return;
+
+ UserStyleSheetMap::iterator it = m_userStyleSheets->find(world);
+ bool sheetsChanged = false;
+ if (it == m_userStyleSheets->end())
+ return;
+
+ UserStyleSheetVector* stylesheets = it->second;
+ for (int i = stylesheets->size() - 1; i >= 0; --i) {
+ if (stylesheets->at(i)->url() == url) {
+ stylesheets->remove(i);
+ sheetsChanged = true;
+ }
+ }
+
+ if (!sheetsChanged)
+ return;
+
+ if (!stylesheets->isEmpty()) {
+ delete it->second;
+ m_userStyleSheets->remove(it);
+ }
+
+ resetUserStyleCacheInAllFrames();
+}
+
+void PageGroup::removeUserScriptsFromWorld(DOMWrapperWorld* world)
+{
+ ASSERT_ARG(world, world);
+
+ if (!m_userScripts)
+ return;
+
+ UserScriptMap::iterator it = m_userScripts->find(world);
+ if (it == m_userScripts->end())
+ return;
+
+ delete it->second;
+ m_userScripts->remove(it);
+}
+
+void PageGroup::removeUserStyleSheetsFromWorld(DOMWrapperWorld* world)
+{
+ ASSERT_ARG(world, world);
+
+ if (!m_userStyleSheets)
+ return;
+
+ UserStyleSheetMap::iterator it = m_userStyleSheets->find(world);
+ if (it == m_userStyleSheets->end())
+ return;
+
+ delete it->second;
+ m_userStyleSheets->remove(it);
+
+ resetUserStyleCacheInAllFrames();
+}
+
+void PageGroup::removeAllUserContent()
+{
+ if (m_userScripts) {
+ deleteAllValues(*m_userScripts);
+ m_userScripts.clear();
+ }
+
+ if (m_userStyleSheets) {
+ deleteAllValues(*m_userStyleSheets);
+ m_userStyleSheets.clear();
+ resetUserStyleCacheInAllFrames();
+ }
+}
+
+void PageGroup::resetUserStyleCacheInAllFrames()
+{
+ // Clear our cached sheets and have them just reparse.
+ HashSet<Page*>::const_iterator end = m_pages.end();
+ for (HashSet<Page*>::const_iterator it = m_pages.begin(); it != end; ++it) {
+ for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frame->document()->updatePageGroupUserSheets();
+ }
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/PageGroup.h b/Source/WebCore/page/PageGroup.h
new file mode 100644
index 0000000..0c4b26f
--- /dev/null
+++ b/Source/WebCore/page/PageGroup.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PageGroup_h
+#define PageGroup_h
+
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include "LinkHash.h"
+#include "UserScript.h"
+#include "UserStyleSheet.h"
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+ class KURL;
+ class GroupSettings;
+ class IDBFactoryBackendInterface;
+ class Page;
+ class StorageNamespace;
+
+ class PageGroup : public Noncopyable {
+ public:
+ PageGroup(const String& name);
+ PageGroup(Page*);
+ ~PageGroup();
+
+ static PageGroup* pageGroup(const String& groupName);
+ static void closeLocalStorage();
+
+#if ENABLE(DOM_STORAGE) && defined(ANDROID)
+ static void clearDomStorage();
+#endif
+
+ const HashSet<Page*>& pages() const { return m_pages; }
+
+ void addPage(Page*);
+ void removePage(Page*);
+
+ bool isLinkVisited(LinkHash);
+
+ void addVisitedLink(const KURL&);
+ void addVisitedLink(const UChar*, size_t);
+ void addVisitedLinkHash(LinkHash);
+ void removeVisitedLinks();
+
+ static void setShouldTrackVisitedLinks(bool);
+ static void removeAllVisitedLinks();
+
+ const String& name() { return m_name; }
+ unsigned identifier() { return m_identifier; }
+
+#if ENABLE(DOM_STORAGE)
+ StorageNamespace* localStorage();
+ bool hasLocalStorage() { return m_localStorage; }
+#endif
+#if ENABLE(INDEXED_DATABASE)
+ IDBFactoryBackendInterface* idbFactory();
+ bool hasIDBFactory() { return m_factoryBackend; }
+#endif
+
+ void addUserScriptToWorld(DOMWrapperWorld*, const String& source, const KURL&,
+ PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist,
+ UserScriptInjectionTime, UserContentInjectedFrames);
+ void addUserStyleSheetToWorld(DOMWrapperWorld*, const String& source, const KURL&,
+ PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist,
+ UserContentInjectedFrames,
+ UserStyleLevel level = UserStyleUserLevel,
+ UserStyleInjectionTime injectionTime = InjectInExistingDocuments);
+ void removeUserScriptFromWorld(DOMWrapperWorld*, const KURL&);
+ void removeUserStyleSheetFromWorld(DOMWrapperWorld*, const KURL&);
+
+ void removeUserScriptsFromWorld(DOMWrapperWorld*);
+ void removeUserStyleSheetsFromWorld(DOMWrapperWorld*);
+
+ void removeAllUserContent();
+
+ const UserScriptMap* userScripts() const { return m_userScripts.get(); }
+ const UserStyleSheetMap* userStyleSheets() const { return m_userStyleSheets.get(); }
+
+ GroupSettings* groupSettings() const { return m_groupSettings.get(); }
+
+ private:
+ void addVisitedLink(LinkHash stringHash);
+ void resetUserStyleCacheInAllFrames();
+
+#if ENABLE(DOM_STORAGE) && defined(ANDROID)
+ void removeLocalStorage();
+#endif
+
+ String m_name;
+
+ HashSet<Page*> m_pages;
+
+ HashSet<LinkHash, LinkHashHash> m_visitedLinkHashes;
+ bool m_visitedLinksPopulated;
+
+ unsigned m_identifier;
+#if ENABLE(DOM_STORAGE)
+ RefPtr<StorageNamespace> m_localStorage;
+#endif
+#if ENABLE(INDEXED_DATABASE)
+ RefPtr<IDBFactoryBackendInterface> m_factoryBackend;
+#endif
+
+ OwnPtr<UserScriptMap> m_userScripts;
+ OwnPtr<UserStyleSheetMap> m_userStyleSheets;
+
+ OwnPtr<GroupSettings> m_groupSettings;
+ };
+
+} // namespace WebCore
+
+#endif // PageGroup_h
diff --git a/Source/WebCore/page/PageGroupLoadDeferrer.cpp b/Source/WebCore/page/PageGroupLoadDeferrer.cpp
new file mode 100644
index 0000000..781bc34
--- /dev/null
+++ b/Source/WebCore/page/PageGroupLoadDeferrer.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "PageGroupLoadDeferrer.h"
+
+#include "AsyncScriptRunner.h"
+#include "DocumentParser.h"
+#include "Frame.h"
+#include "Page.h"
+#include "PageGroup.h"
+#include <wtf/HashSet.h>
+
+namespace WebCore {
+
+using namespace std;
+
+PageGroupLoadDeferrer::PageGroupLoadDeferrer(Page* page, bool deferSelf)
+{
+ const HashSet<Page*>& pages = page->group().pages();
+
+ HashSet<Page*>::const_iterator end = pages.end();
+ for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) {
+ Page* otherPage = *it;
+ if ((deferSelf || otherPage != page)) {
+ if (!otherPage->defersLoading()) {
+ m_deferredFrames.append(otherPage->mainFrame());
+
+ // This code is not logically part of load deferring, but we do not want JS code executed beneath modal
+ // windows or sheets, which is exactly when PageGroupLoadDeferrer is used.
+ // NOTE: if PageGroupLoadDeferrer is ever used for tasks other than showing a modal window or sheet,
+ // the constructor will need to take a ActiveDOMObject::ReasonForSuspension.
+ for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ frame->document()->suspendActiveDOMObjects(ActiveDOMObject::WillShowDialog);
+ frame->document()->asyncScriptRunner()->suspend();
+ if (DocumentParser* parser = frame->document()->parser())
+ parser->suspendScheduledTasks();
+ }
+ }
+ }
+ }
+
+ size_t count = m_deferredFrames.size();
+ for (size_t i = 0; i < count; ++i)
+ if (Page* page = m_deferredFrames[i]->page())
+ page->setDefersLoading(true);
+}
+
+PageGroupLoadDeferrer::~PageGroupLoadDeferrer()
+{
+ for (size_t i = 0; i < m_deferredFrames.size(); ++i) {
+ if (Page* page = m_deferredFrames[i]->page()) {
+ page->setDefersLoading(false);
+
+ for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ frame->document()->resumeActiveDOMObjects();
+ frame->document()->asyncScriptRunner()->resume();
+ if (DocumentParser* parser = frame->document()->parser())
+ parser->resumeScheduledTasks();
+ }
+ }
+ }
+}
+
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/PageGroupLoadDeferrer.h b/Source/WebCore/page/PageGroupLoadDeferrer.h
new file mode 100644
index 0000000..d443ebd
--- /dev/null
+++ b/Source/WebCore/page/PageGroupLoadDeferrer.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PageGroupLoadDeferrer_h
+#define PageGroupLoadDeferrer_h
+
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ class Frame;
+ class Page;
+
+ class PageGroupLoadDeferrer : public Noncopyable {
+ public:
+ PageGroupLoadDeferrer(Page*, bool deferSelf);
+ ~PageGroupLoadDeferrer();
+
+ private:
+ Vector<RefPtr<Frame>, 16> m_deferredFrames;
+ };
+}
+
+#endif // PageGroupLoadDeferrer_h
diff --git a/Source/WebCore/page/Performance.cpp b/Source/WebCore/page/Performance.cpp
new file mode 100644
index 0000000..4e130ea
--- /dev/null
+++ b/Source/WebCore/page/Performance.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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 "Performance.h"
+
+#include "MemoryInfo.h"
+#include "PerformanceNavigation.h"
+#include "PerformanceTiming.h"
+
+#if ENABLE(WEB_TIMING)
+
+#include "Frame.h"
+
+namespace WebCore {
+
+Performance::Performance(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+Frame* Performance::frame() const
+{
+ return m_frame;
+}
+
+void Performance::disconnectFrame()
+{
+ if (m_memory)
+ m_memory = 0;
+ if (m_navigation) {
+ m_navigation->disconnectFrame();
+ m_navigation = 0;
+ }
+ if (m_timing) {
+ m_timing->disconnectFrame();
+ m_timing = 0;
+ }
+ m_frame = 0;
+}
+
+MemoryInfo* Performance::memory() const
+{
+ m_memory = MemoryInfo::create(m_frame);
+ return m_memory.get();
+}
+
+PerformanceNavigation* Performance::navigation() const
+{
+ if (!m_navigation)
+ m_navigation = PerformanceNavigation::create(m_frame);
+
+ return m_navigation.get();
+}
+
+PerformanceTiming* Performance::timing() const
+{
+ if (!m_timing)
+ m_timing = PerformanceTiming::create(m_frame);
+
+ return m_timing.get();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_TIMING)
diff --git a/Source/WebCore/page/Performance.h b/Source/WebCore/page/Performance.h
new file mode 100644
index 0000000..be9e124
--- /dev/null
+++ b/Source/WebCore/page/Performance.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#ifndef Performance_h
+#define Performance_h
+
+#if ENABLE(WEB_TIMING)
+
+#include "MemoryInfo.h"
+#include "PerformanceNavigation.h"
+#include "PerformanceTiming.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class Performance : public RefCounted<Performance> {
+public:
+ static PassRefPtr<Performance> create(Frame* frame) { return adoptRef(new Performance(frame)); }
+
+ Frame* frame() const;
+ void disconnectFrame();
+
+ MemoryInfo* memory() const;
+ PerformanceNavigation* navigation() const;
+ PerformanceTiming* timing() const;
+
+private:
+ Performance(Frame*);
+
+ mutable RefPtr<MemoryInfo> m_memory;
+ mutable RefPtr<PerformanceNavigation> m_navigation;
+ mutable RefPtr<PerformanceTiming> m_timing;
+ Frame* m_frame;
+};
+
+}
+
+#endif // !ENABLE(WEB_TIMING)
+#endif // !defined(Performance_h)
diff --git a/Source/WebCore/page/Performance.idl b/Source/WebCore/page/Performance.idl
new file mode 100644
index 0000000..e5a8dcf
--- /dev/null
+++ b/Source/WebCore/page/Performance.idl
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+module window {
+
+ // See: http://dev.w3.org/2006/webapi/WebTiming/
+ interface [Conditional=WEB_TIMING, OmitConstructor] Performance {
+ readonly attribute PerformanceNavigation navigation;
+ readonly attribute PerformanceTiming timing;
+ readonly attribute [V8CustomGetter] MemoryInfo memory;
+ };
+
+}
diff --git a/Source/WebCore/page/PerformanceNavigation.cpp b/Source/WebCore/page/PerformanceNavigation.cpp
new file mode 100644
index 0000000..a46639a
--- /dev/null
+++ b/Source/WebCore/page/PerformanceNavigation.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 "PerformanceNavigation.h"
+
+#if ENABLE(WEB_TIMING)
+
+#include "DocumentLoader.h"
+#include "Frame.h"
+#include "FrameLoaderTypes.h"
+
+namespace WebCore {
+
+PerformanceNavigation::PerformanceNavigation(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+Frame* PerformanceNavigation::frame() const
+{
+ return m_frame;
+}
+
+void PerformanceNavigation::disconnectFrame()
+{
+ m_frame = 0;
+}
+
+unsigned short PerformanceNavigation::type() const
+{
+ if (!m_frame)
+ return TYPE_NAVIGATE;
+
+ DocumentLoader* documentLoader = m_frame->loader()->documentLoader();
+ if (!documentLoader)
+ return TYPE_NAVIGATE;
+
+ WebCore::NavigationType navigationType = documentLoader->triggeringAction().type();
+ switch (navigationType) {
+ case NavigationTypeReload:
+ return TYPE_RELOAD;
+ case NavigationTypeBackForward:
+ return TYPE_BACK_FORWARD;
+ default:
+ return TYPE_NAVIGATE;
+ }
+}
+
+unsigned short PerformanceNavigation::redirectCount() const
+{
+ if (!m_frame)
+ return 0;
+
+ DocumentLoader* loader = m_frame->loader()->documentLoader();
+ if (!loader)
+ return 0;
+
+ DocumentLoadTiming* timing = loader->timing();
+ if (timing->hasCrossOriginRedirect)
+ return 0;
+
+ return timing->redirectCount;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_TIMING)
diff --git a/Source/WebCore/page/PerformanceNavigation.h b/Source/WebCore/page/PerformanceNavigation.h
new file mode 100644
index 0000000..bdf6eaa
--- /dev/null
+++ b/Source/WebCore/page/PerformanceNavigation.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#ifndef PerformanceNavigation_h
+#define PerformanceNavigation_h
+
+#if ENABLE(WEB_TIMING)
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class Frame;
+
+class PerformanceNavigation : public RefCounted<PerformanceNavigation> {
+public:
+ static PassRefPtr<PerformanceNavigation> create(Frame* frame) { return adoptRef(new PerformanceNavigation(frame)); }
+
+ Frame* frame() const;
+ void disconnectFrame();
+
+ enum PerformanceNavigationType {
+ TYPE_NAVIGATE,
+ TYPE_RELOAD,
+ TYPE_BACK_FORWARD,
+ TYPE_RESERVED = 255
+ };
+
+ unsigned short type() const;
+ unsigned short redirectCount() const;
+
+private:
+ PerformanceNavigation(Frame*);
+
+ Frame* m_frame;
+};
+
+}
+
+#endif // !ENABLE(WEB_TIMING)
+#endif // !defined(PerformanceNavigation_h)
diff --git a/Source/WebCore/page/PerformanceNavigation.idl b/Source/WebCore/page/PerformanceNavigation.idl
new file mode 100644
index 0000000..d16bcba
--- /dev/null
+++ b/Source/WebCore/page/PerformanceNavigation.idl
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+module window {
+
+ // See: http://www.w3.org/TR/navigation-timing/
+ interface [Conditional=WEB_TIMING, OmitConstructor] PerformanceNavigation {
+ const unsigned short TYPE_NAVIGATE = 0;
+ const unsigned short TYPE_RELOAD = 1;
+ const unsigned short TYPE_BACK_FORWARD = 2;
+ const unsigned short TYPE_RESERVED = 255;
+ readonly attribute unsigned short type;
+
+ readonly attribute unsigned short redirectCount;
+ };
+
+}
diff --git a/Source/WebCore/page/PerformanceTiming.cpp b/Source/WebCore/page/PerformanceTiming.cpp
new file mode 100644
index 0000000..fb8bfb7
--- /dev/null
+++ b/Source/WebCore/page/PerformanceTiming.cpp
@@ -0,0 +1,403 @@
+/*
+ * 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 "PerformanceTiming.h"
+
+#if ENABLE(WEB_TIMING)
+
+#include "DocumentLoadTiming.h"
+#include "DocumentLoader.h"
+#include "DocumentTiming.h"
+#include "Frame.h"
+#include "ResourceLoadTiming.h"
+#include "ResourceResponse.h"
+#include <wtf/CurrentTime.h>
+
+namespace WebCore {
+
+static unsigned long long toIntegerMilliseconds(double seconds)
+{
+ ASSERT(seconds >= 0);
+ return static_cast<unsigned long long>(seconds * 1000.0);
+}
+
+static double getPossiblySkewedTimeInKnownRange(double skewedTime, double lowerBound, double upperBound)
+{
+#if PLATFORM(CHROMIUM)
+ // The chromium port's currentTime() implementation only syncs with the
+ // system clock every 60 seconds. So it is possible for timing marks
+ // collected in different threads or processes to have a small skew.
+ // FIXME: It may be possible to add a currentTimeFromSystemTime() method
+ // that eliminates the skew.
+ if (skewedTime <= lowerBound)
+ return lowerBound;
+
+ if (upperBound <= 0.0)
+ upperBound = currentTime();
+
+ if (skewedTime >= upperBound)
+ return upperBound;
+#else
+ ASSERT_UNUSED(lowerBound, skewedTime >= lowerBound);
+ ASSERT_UNUSED(upperBound, skewedTime <= upperBound);
+#endif
+
+ return skewedTime;
+}
+
+PerformanceTiming::PerformanceTiming(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+Frame* PerformanceTiming::frame() const
+{
+ return m_frame;
+}
+
+void PerformanceTiming::disconnectFrame()
+{
+ m_frame = 0;
+}
+
+unsigned long long PerformanceTiming::navigationStart() const
+{
+ DocumentLoadTiming* timing = documentLoadTiming();
+ if (!timing)
+ return 0;
+
+ return toIntegerMilliseconds(timing->navigationStart);
+}
+
+unsigned long long PerformanceTiming::unloadEventStart() const
+{
+ DocumentLoadTiming* timing = documentLoadTiming();
+ if (!timing)
+ return 0;
+
+ if (!timing->hasSameOriginAsPreviousDocument)
+ return 0;
+
+ return toIntegerMilliseconds(timing->unloadEventStart);
+}
+
+unsigned long long PerformanceTiming::unloadEventEnd() const
+{
+ DocumentLoadTiming* timing = documentLoadTiming();
+ if (!timing)
+ return 0;
+
+ if (!timing->hasSameOriginAsPreviousDocument)
+ return 0;
+
+ return toIntegerMilliseconds(timing->unloadEventEnd);
+}
+
+unsigned long long PerformanceTiming::redirectStart() const
+{
+ DocumentLoadTiming* timing = documentLoadTiming();
+ if (!timing)
+ return 0;
+
+ if (timing->hasCrossOriginRedirect)
+ return 0;
+
+ return toIntegerMilliseconds(timing->redirectStart);
+}
+
+unsigned long long PerformanceTiming::redirectEnd() const
+{
+ DocumentLoadTiming* timing = documentLoadTiming();
+ if (!timing)
+ return 0;
+
+ if (timing->hasCrossOriginRedirect)
+ return 0;
+
+ return toIntegerMilliseconds(timing->redirectEnd);
+}
+
+unsigned long long PerformanceTiming::fetchStart() const
+{
+ DocumentLoadTiming* timing = documentLoadTiming();
+ if (!timing)
+ return 0;
+
+ return toIntegerMilliseconds(timing->fetchStart);
+}
+
+unsigned long long PerformanceTiming::domainLookupStart() const
+{
+ ResourceLoadTiming* timing = resourceLoadTiming();
+ if (!timing)
+ return 0;
+
+ // This will be -1 when a DNS request is not performed.
+ // Rather than exposing a special value that indicates no DNS, we "backfill" with fetchStart.
+ int dnsStart = timing->dnsStart;
+ if (dnsStart < 0)
+ return fetchStart();
+
+ return resourceLoadTimeRelativeToAbsolute(dnsStart);
+}
+
+unsigned long long PerformanceTiming::domainLookupEnd() const
+{
+ ResourceLoadTiming* timing = resourceLoadTiming();
+ if (!timing)
+ return 0;
+
+ // This will be -1 when a DNS request is not performed.
+ // Rather than exposing a special value that indicates no DNS, we "backfill" with domainLookupStart.
+ int dnsEnd = timing->dnsEnd;
+ if (dnsEnd < 0)
+ return domainLookupStart();
+
+ return resourceLoadTimeRelativeToAbsolute(dnsEnd);
+}
+
+unsigned long long PerformanceTiming::connectStart() const
+{
+ DocumentLoader* loader = documentLoader();
+ if (!loader)
+ return 0;
+
+ ResourceLoadTiming* timing = loader->response().resourceLoadTiming();
+ if (!timing)
+ return 0;
+
+ // connectStart will be -1 when a network request is not made.
+ // Rather than exposing a special value that indicates no new connection, we "backfill" with domainLookupEnd.
+ int connectStart = timing->connectStart;
+ if (connectStart < 0 || loader->response().connectionReused())
+ return domainLookupEnd();
+
+ // ResourceLoadTiming's connect phase includes DNS, however Navigation Timing's
+ // connect phase should not. So if there is DNS time, trim it from the start.
+ if (timing->dnsEnd >= 0 && timing->dnsEnd > connectStart)
+ connectStart = timing->dnsEnd;
+
+ return resourceLoadTimeRelativeToAbsolute(connectStart);
+}
+
+unsigned long long PerformanceTiming::connectEnd() const
+{
+ DocumentLoader* loader = documentLoader();
+ if (!loader)
+ return 0;
+
+ ResourceLoadTiming* timing = loader->response().resourceLoadTiming();
+ if (!timing)
+ return 0;
+
+ // connectEnd will be -1 when a network request is not made.
+ // Rather than exposing a special value that indicates no new connection, we "backfill" with connectStart.
+ int connectEnd = timing->connectEnd;
+ if (connectEnd < 0 || loader->response().connectionReused())
+ return connectStart();
+
+ return resourceLoadTimeRelativeToAbsolute(connectEnd);
+}
+
+unsigned long long PerformanceTiming::sslHandshakeStart() const
+{
+ DocumentLoader* loader = documentLoader();
+ if (!loader)
+ return 0;
+
+ ResourceLoadTiming* timing = loader->response().resourceLoadTiming();
+ if (!timing)
+ return 0;
+
+ int sslStart = timing->sslStart;
+ if (sslStart < 0)
+ return 0;
+
+ return resourceLoadTimeRelativeToAbsolute(sslStart);
+}
+
+unsigned long long PerformanceTiming::requestStart() const
+{
+ ResourceLoadTiming* timing = resourceLoadTiming();
+ if (!timing)
+ return 0;
+
+ ASSERT(timing->sendStart >= 0);
+ return resourceLoadTimeRelativeToAbsolute(timing->sendStart);
+}
+
+unsigned long long PerformanceTiming::responseStart() const
+{
+ ResourceLoadTiming* timing = resourceLoadTiming();
+ if (!timing)
+ return 0;
+
+ // FIXME: Response start needs to be the time of the first received byte.
+ // However, the ResourceLoadTiming API currently only supports the time
+ // the last header byte was received. For many responses with reasonable
+ // sized cookies, the HTTP headers fit into a single packet so this time
+ // is basically equivalent. But for some responses, particularly those with
+ // headers larger than a single packet, this time will be too late.
+ ASSERT(timing->receiveHeadersEnd >= 0);
+ return resourceLoadTimeRelativeToAbsolute(timing->receiveHeadersEnd);
+}
+
+unsigned long long PerformanceTiming::responseEnd() const
+{
+ DocumentLoadTiming* timing = documentLoadTiming();
+ if (!timing)
+ return 0;
+
+ return toIntegerMilliseconds(timing->responseEnd);
+}
+
+unsigned long long PerformanceTiming::domLoading() const
+{
+ const DocumentTiming* timing = documentTiming();
+ if (!timing)
+ return 0;
+
+ return toIntegerMilliseconds(timing->domLoading);
+}
+
+unsigned long long PerformanceTiming::domInteractive() const
+{
+ const DocumentTiming* timing = documentTiming();
+ if (!timing)
+ return 0;
+
+ return toIntegerMilliseconds(timing->domInteractive);
+}
+
+unsigned long long PerformanceTiming::domContentLoadedEventStart() const
+{
+ const DocumentTiming* timing = documentTiming();
+ if (!timing)
+ return 0;
+
+ return toIntegerMilliseconds(timing->domContentLoadedEventStart);
+}
+
+unsigned long long PerformanceTiming::domContentLoadedEventEnd() const
+{
+ const DocumentTiming* timing = documentTiming();
+ if (!timing)
+ return 0;
+
+ return toIntegerMilliseconds(timing->domContentLoadedEventEnd);
+}
+
+unsigned long long PerformanceTiming::domComplete() const
+{
+ const DocumentTiming* timing = documentTiming();
+ if (!timing)
+ return 0;
+
+ return toIntegerMilliseconds(timing->domComplete);
+}
+
+unsigned long long PerformanceTiming::loadEventStart() const
+{
+ DocumentLoadTiming* timing = documentLoadTiming();
+ if (!timing)
+ return 0;
+
+ return toIntegerMilliseconds(timing->loadEventStart);
+}
+
+unsigned long long PerformanceTiming::loadEventEnd() const
+{
+ DocumentLoadTiming* timing = documentLoadTiming();
+ if (!timing)
+ return 0;
+
+ return toIntegerMilliseconds(timing->loadEventEnd);
+}
+
+DocumentLoader* PerformanceTiming::documentLoader() const
+{
+ if (!m_frame)
+ return 0;
+
+ return m_frame->loader()->documentLoader();
+}
+
+const DocumentTiming* PerformanceTiming::documentTiming() const
+{
+ if (!m_frame)
+ return 0;
+
+ Document* document = m_frame->document();
+ if (!document)
+ return 0;
+
+ return document->timing();
+}
+
+DocumentLoadTiming* PerformanceTiming::documentLoadTiming() const
+{
+ DocumentLoader* loader = documentLoader();
+ if (!loader)
+ return 0;
+
+ return loader->timing();
+}
+
+ResourceLoadTiming* PerformanceTiming::resourceLoadTiming() const
+{
+ DocumentLoader* loader = documentLoader();
+ if (!loader)
+ return 0;
+
+ return loader->response().resourceLoadTiming();
+}
+
+unsigned long long PerformanceTiming::resourceLoadTimeRelativeToAbsolute(int relativeSeconds) const
+{
+ ASSERT(relativeSeconds >= 0);
+ ResourceLoadTiming* resourceTiming = resourceLoadTiming();
+ ASSERT(resourceTiming);
+ DocumentLoadTiming* documentTiming = documentLoadTiming();
+ ASSERT(documentTiming);
+
+ // The ResourceLoadTiming API's requestTime is the base time to which all
+ // other marks are relative. So to get an absolute time, we must add it to
+ // the relative marks.
+ //
+ // Since ResourceLoadTimings came from the network platform layer, we must
+ // check them for skew because they may be from another thread/process.
+ double baseTime = getPossiblySkewedTimeInKnownRange(resourceTiming->requestTime, documentTiming->fetchStart, documentTiming->responseEnd);
+ return toIntegerMilliseconds(baseTime) + relativeSeconds;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_TIMING)
diff --git a/Source/WebCore/page/PerformanceTiming.h b/Source/WebCore/page/PerformanceTiming.h
new file mode 100644
index 0000000..9c35672
--- /dev/null
+++ b/Source/WebCore/page/PerformanceTiming.h
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#ifndef PerformanceTiming_h
+#define PerformanceTiming_h
+
+#if ENABLE(WEB_TIMING)
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+struct DocumentLoadTiming;
+class DocumentLoader;
+struct DocumentTiming;
+class Frame;
+class ResourceLoadTiming;
+
+class PerformanceTiming : public RefCounted<PerformanceTiming> {
+public:
+ static PassRefPtr<PerformanceTiming> create(Frame* frame) { return adoptRef(new PerformanceTiming(frame)); }
+
+ Frame* frame() const;
+ 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;
+ unsigned long long fetchStart() const;
+ unsigned long long domainLookupStart() const;
+ unsigned long long domainLookupEnd() const;
+ unsigned long long connectStart() const;
+ unsigned long long connectEnd() const;
+ unsigned long long sslHandshakeStart() const;
+ unsigned long long requestStart() const;
+ unsigned long long responseStart() const;
+ unsigned long long responseEnd() const;
+ unsigned long long domLoading() const;
+ unsigned long long domInteractive() const;
+ unsigned long long domContentLoadedEventStart() const;
+ unsigned long long domContentLoadedEventEnd() const;
+ unsigned long long domComplete() const;
+ unsigned long long loadEventStart() const;
+ unsigned long long loadEventEnd() const;
+
+private:
+ PerformanceTiming(Frame*);
+
+ const DocumentTiming* documentTiming() const;
+ DocumentLoader* documentLoader() const;
+ DocumentLoadTiming* documentLoadTiming() const;
+ ResourceLoadTiming* resourceLoadTiming() const;
+ unsigned long long resourceLoadTimeRelativeToAbsolute(int) const;
+
+ Frame* m_frame;
+};
+
+}
+
+#endif // !ENABLE(WEB_TIMING)
+#endif // !defined(PerformanceTiming_h)
diff --git a/Source/WebCore/page/PerformanceTiming.idl b/Source/WebCore/page/PerformanceTiming.idl
new file mode 100644
index 0000000..a0f08e2
--- /dev/null
+++ b/Source/WebCore/page/PerformanceTiming.idl
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+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;
+ readonly attribute unsigned long long fetchStart;
+ readonly attribute unsigned long long domainLookupStart;
+ readonly attribute unsigned long long domainLookupEnd;
+ readonly attribute unsigned long long connectStart;
+ readonly attribute unsigned long long connectEnd;
+ readonly attribute unsigned long long sslHandshakeStart;
+ readonly attribute unsigned long long requestStart;
+ readonly attribute unsigned long long responseStart;
+ readonly attribute unsigned long long responseEnd;
+ readonly attribute unsigned long long domLoading;
+ readonly attribute unsigned long long domInteractive;
+ readonly attribute unsigned long long domContentLoadedEventStart;
+ readonly attribute unsigned long long domContentLoadedEventEnd;
+ readonly attribute unsigned long long domComplete;
+ readonly attribute unsigned long long loadEventStart;
+ readonly attribute unsigned long long loadEventEnd;
+ };
+
+}
diff --git a/Source/WebCore/page/PluginHalter.cpp b/Source/WebCore/page/PluginHalter.cpp
new file mode 100644
index 0000000..c0a6452
--- /dev/null
+++ b/Source/WebCore/page/PluginHalter.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "PluginHalter.h"
+
+#include "HaltablePlugin.h"
+#include "PlatformString.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+namespace WebCore {
+
+PluginHalter::PluginHalter(PluginHalterClient* client)
+ : m_client(client)
+ , m_timer(this, &PluginHalter::timerFired)
+ , m_pluginAllowedRunTime(numeric_limits<unsigned>::max())
+{
+ ASSERT_ARG(client, client);
+}
+
+void PluginHalter::didStartPlugin(HaltablePlugin* obj)
+{
+ ASSERT_ARG(obj, obj);
+ ASSERT_ARG(obj, !m_plugins.contains(obj));
+
+ if (!m_client->enabled())
+ return;
+
+ double currentTime = WTF::currentTime();
+
+ m_plugins.add(obj, currentTime);
+
+ if (m_plugins.size() == 1)
+ m_oldestStartTime = currentTime;
+
+ startTimerIfNecessary();
+}
+
+void PluginHalter::didStopPlugin(HaltablePlugin* obj)
+{
+ if (!m_client->enabled())
+ return;
+
+ m_plugins.remove(obj);
+}
+
+void PluginHalter::timerFired(Timer<PluginHalter>*)
+{
+ if (m_plugins.isEmpty())
+ return;
+
+ Vector<HaltablePlugin*> plugins;
+ copyKeysToVector(m_plugins, plugins);
+
+ // Plug-ins older than this are candidates to be halted.
+ double pluginCutOffTime = WTF::currentTime() - m_pluginAllowedRunTime;
+
+ m_oldestStartTime = numeric_limits<double>::max();
+
+ for (size_t i = 0; i < plugins.size(); ++i) {
+ double thisStartTime = m_plugins.get(plugins[i]);
+ if (thisStartTime > pluginCutOffTime) {
+ // This plug-in is too young to be halted. We find the oldest
+ // plug-in that is not old enough to be halted and use it to set
+ // the timer's next fire time.
+ if (thisStartTime < m_oldestStartTime)
+ m_oldestStartTime = thisStartTime;
+ continue;
+ }
+
+ if (m_client->shouldHaltPlugin(plugins[i]->node(), plugins[i]->isWindowed(), plugins[i]->pluginName()))
+ plugins[i]->halt();
+
+ m_plugins.remove(plugins[i]);
+ }
+
+ startTimerIfNecessary();
+}
+
+void PluginHalter::startTimerIfNecessary()
+{
+ if (m_timer.isActive())
+ return;
+
+ if (m_plugins.isEmpty())
+ return;
+
+ double nextFireInterval = static_cast<double>(m_pluginAllowedRunTime) - (currentTime() - m_oldestStartTime);
+ m_timer.startOneShot(nextFireInterval < 0 ? 0 : nextFireInterval);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/PluginHalter.h b/Source/WebCore/page/PluginHalter.h
new file mode 100644
index 0000000..af8b31e
--- /dev/null
+++ b/Source/WebCore/page/PluginHalter.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PluginHalter_h
+#define PluginHalter_h
+
+#include "PluginHalterClient.h"
+#include "Timer.h"
+#include <wtf/HashMap.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class HaltablePlugin;
+
+class PluginHalter : public Noncopyable {
+public:
+ PluginHalter(PluginHalterClient*);
+
+ void didStartPlugin(HaltablePlugin*);
+ void didStopPlugin(HaltablePlugin*);
+
+ void setPluginAllowedRunTime(unsigned runTime) { m_pluginAllowedRunTime = runTime; }
+
+private:
+ void timerFired(Timer<PluginHalter>*);
+ void startTimerIfNecessary();
+
+ OwnPtr<PluginHalterClient> m_client;
+ Timer<PluginHalter> m_timer;
+ unsigned m_pluginAllowedRunTime;
+ double m_oldestStartTime;
+ HashMap<HaltablePlugin*, double> m_plugins;
+};
+
+} // namespace WebCore
+
+#endif // PluginHalter_h
diff --git a/Source/WebCore/page/PluginHalterClient.h b/Source/WebCore/page/PluginHalterClient.h
new file mode 100644
index 0000000..12d37cc
--- /dev/null
+++ b/Source/WebCore/page/PluginHalterClient.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PluginHalterClient_h
+#define PluginHalterClient_h
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class Node;
+
+class PluginHalterClient {
+public:
+ virtual ~PluginHalterClient() { }
+
+ virtual bool shouldHaltPlugin(Node*, bool isWindowed, const String& pluginName) const = 0;
+ virtual bool enabled() const = 0;
+};
+
+} // namespace WebCore
+
+#endif // PluginHalterClient_h
diff --git a/Source/WebCore/page/PositionCallback.h b/Source/WebCore/page/PositionCallback.h
new file mode 100644
index 0000000..5511d3e
--- /dev/null
+++ b/Source/WebCore/page/PositionCallback.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PositionCallback_h
+#define PositionCallback_h
+
+#include "ActiveDOMObject.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class Geoposition;
+
+ class PositionCallback : public RefCounted<PositionCallback>, public ActiveDOMObject {
+ public:
+ PositionCallback(ScriptExecutionContext* context) : ActiveDOMObject(context, this) { }
+ virtual ~PositionCallback() { }
+ virtual void handleEvent(Geoposition*) = 0;
+ };
+
+} // namespace WebCore
+
+#endif // PositionCallback_h
diff --git a/Source/WebCore/page/PositionError.h b/Source/WebCore/page/PositionError.h
new file mode 100644
index 0000000..1467170
--- /dev/null
+++ b/Source/WebCore/page/PositionError.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PositionError_h
+#define PositionError_h
+
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class PositionError : public RefCounted<PositionError> {
+public:
+ enum ErrorCode {
+ PERMISSION_DENIED = 1,
+ POSITION_UNAVAILABLE = 2,
+ TIMEOUT = 3
+ };
+
+ static PassRefPtr<PositionError> create(ErrorCode code, const String& message) { return adoptRef(new PositionError(code, message)); }
+
+ ErrorCode code() const { return m_code; }
+ const String& message() const { return m_message; }
+ void setIsFatal(bool isFatal) { m_isFatal = isFatal; }
+ bool isFatal() const { return m_isFatal; }
+
+private:
+ PositionError(ErrorCode code, const String& message)
+ : m_code(code)
+ , m_message(message)
+ , m_isFatal(false)
+ {
+ }
+
+ ErrorCode m_code;
+ String m_message;
+ // Whether the error is fatal, such that no request can ever obtain a good
+ // position fix in the future.
+ bool m_isFatal;
+};
+
+} // namespace WebCore
+
+#endif // PositionError_h
diff --git a/Source/WebCore/page/PositionError.idl b/Source/WebCore/page/PositionError.idl
new file mode 100644
index 0000000..5870e0d
--- /dev/null
+++ b/Source/WebCore/page/PositionError.idl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module core {
+
+ interface [Conditional=GEOLOCATION] PositionError {
+ readonly attribute unsigned short code;
+ readonly attribute DOMString message;
+
+ const unsigned short PERMISSION_DENIED = 1;
+ const unsigned short POSITION_UNAVAILABLE = 2;
+ const unsigned short TIMEOUT = 3;
+ };
+
+}
diff --git a/Source/WebCore/page/PositionErrorCallback.h b/Source/WebCore/page/PositionErrorCallback.h
new file mode 100644
index 0000000..a65e350
--- /dev/null
+++ b/Source/WebCore/page/PositionErrorCallback.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PositionErrorCallback_h
+#define PositionErrorCallback_h
+
+#include "ActiveDOMObject.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class PositionError;
+
+ class PositionErrorCallback : public RefCounted<PositionErrorCallback>, public ActiveDOMObject {
+ public:
+ PositionErrorCallback(ScriptExecutionContext* context) : ActiveDOMObject(context, this) { }
+ virtual ~PositionErrorCallback() { }
+ virtual void handleEvent(PositionError*) = 0;
+ };
+
+} // namespace WebCore
+
+#endif // PositionErrorCallback_h
diff --git a/Source/WebCore/page/PositionOptions.h b/Source/WebCore/page/PositionOptions.h
new file mode 100644
index 0000000..5cb66f7
--- /dev/null
+++ b/Source/WebCore/page/PositionOptions.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PositionOptions_h
+#define PositionOptions_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class PositionOptions : public RefCounted<PositionOptions> {
+public:
+ static PassRefPtr<PositionOptions> create() { return adoptRef(new PositionOptions()); }
+
+ bool enableHighAccuracy() const { return m_highAccuracy; }
+ void setEnableHighAccuracy(bool enable) { m_highAccuracy = enable; }
+ bool hasTimeout() const { return m_hasTimeout; }
+ int timeout() const
+ {
+ ASSERT(hasTimeout());
+ return m_timeout;
+ }
+ void setTimeout(int timeout)
+ {
+ ASSERT(timeout >= 0);
+ m_hasTimeout = true;
+ m_timeout = timeout;
+ }
+ bool hasMaximumAge() const { return m_hasMaximumAge; }
+ int maximumAge() const
+ {
+ ASSERT(hasMaximumAge());
+ return m_maximumAge;
+ }
+ void clearMaximumAge() { m_hasMaximumAge = false; }
+ void setMaximumAge(int age)
+ {
+ ASSERT(age >= 0);
+ m_hasMaximumAge = true;
+ m_maximumAge = age;
+ }
+
+private:
+ PositionOptions()
+ : m_highAccuracy(false)
+ , m_hasTimeout(false)
+ {
+ setMaximumAge(0);
+ }
+
+ bool m_highAccuracy;
+ bool m_hasTimeout;
+ int m_timeout;
+ bool m_hasMaximumAge;
+ int m_maximumAge;
+};
+
+} // namespace WebCore
+
+#endif // PositionOptions_h
diff --git a/Source/WebCore/page/PrintContext.cpp b/Source/WebCore/page/PrintContext.cpp
new file mode 100644
index 0000000..f051ead
--- /dev/null
+++ b/Source/WebCore/page/PrintContext.cpp
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2007 Apple Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "PrintContext.h"
+
+#include "GraphicsContext.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "RenderLayer.h"
+#include "RenderView.h"
+#include <wtf/text/StringConcatenate.h>
+
+using namespace WebCore;
+
+namespace WebCore {
+
+PrintContext::PrintContext(Frame* frame)
+ : m_frame(frame)
+ , m_isPrinting(false)
+{
+}
+
+PrintContext::~PrintContext()
+{
+ if (m_isPrinting)
+ end();
+ m_pageRects.clear();
+}
+
+int PrintContext::pageCount() const
+{
+ return m_pageRects.size();
+}
+
+const IntRect& PrintContext::pageRect(int pageNumber) const
+{
+ return m_pageRects[pageNumber];
+}
+
+void PrintContext::computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight)
+{
+ m_pageRects.clear();
+ outPageHeight = 0;
+
+ if (!m_frame->document() || !m_frame->view() || !m_frame->document()->renderer())
+ return;
+
+ if (userScaleFactor <= 0) {
+ LOG_ERROR("userScaleFactor has bad value %.2f", userScaleFactor);
+ return;
+ }
+
+ RenderView* view = toRenderView(m_frame->document()->renderer());
+
+ float ratio = printRect.height() / printRect.width();
+
+ float pageWidth = view->docWidth();
+ float pageHeight = pageWidth * ratio;
+ outPageHeight = pageHeight; // this is the height of the page adjusted by margins
+ pageHeight -= headerHeight + footerHeight;
+
+ if (pageHeight <= 0) {
+ LOG_ERROR("pageHeight has bad value %.2f", pageHeight);
+ return;
+ }
+
+ computePageRectsWithPageSizeInternal(FloatSize(pageWidth / userScaleFactor, pageHeight / userScaleFactor), false);
+}
+
+void PrintContext::computePageRectsWithPageSize(const FloatSize& pageSizeInPixels, bool allowHorizontalMultiPages)
+{
+ m_pageRects.clear();
+ computePageRectsWithPageSizeInternal(pageSizeInPixels, allowHorizontalMultiPages);
+}
+
+void PrintContext::computePageRectsWithPageSizeInternal(const FloatSize& pageSizeInPixels, bool allowHorizontalMultiPages)
+{
+ if (!m_frame->document() || !m_frame->view() || !m_frame->document()->renderer())
+ return;
+
+ RenderView* view = toRenderView(m_frame->document()->renderer());
+
+ IntRect docRect = view->documentRect();
+
+ int pageWidth = pageSizeInPixels.width();
+ int pageHeight = pageSizeInPixels.height();
+
+ unsigned pageCount = ceilf((float)docRect.height() / pageHeight);
+ for (unsigned i = 0; i < pageCount; ++i) {
+ if (allowHorizontalMultiPages) {
+ for (int currentX = docRect.x(); currentX < docRect.right(); currentX += pageWidth)
+ m_pageRects.append(IntRect(currentX, docRect.y() + i * pageHeight, pageWidth, pageHeight));
+ } else
+ m_pageRects.append(IntRect(docRect.x(), docRect.y() + i * pageHeight, pageWidth, pageHeight));
+ }
+}
+
+void PrintContext::begin(float width, float height)
+{
+ ASSERT(!m_isPrinting);
+ m_isPrinting = true;
+
+ // By imaging to a width a little wider than the available pixels,
+ // thin pages will be scaled down a little, matching the way they
+ // print in IE and Camino. This lets them use fewer sheets than they
+ // would otherwise, which is presumably why other browsers do this.
+ // Wide pages will be scaled down more than this.
+ const float PrintingMinimumShrinkFactor = 1.25f;
+
+ // This number determines how small we are willing to reduce the page content
+ // in order to accommodate the widest line. If the page would have to be
+ // reduced smaller to make the widest line fit, we just clip instead (this
+ // behavior matches MacIE and Mozilla, at least)
+ const float PrintingMaximumShrinkFactor = 2.0f;
+
+ float minLayoutWidth = width * PrintingMinimumShrinkFactor;
+ float minLayoutHeight = height * PrintingMinimumShrinkFactor;
+
+ // FIXME: This will modify the rendering of the on-screen frame.
+ // Could lead to flicker during printing.
+ m_frame->setPrinting(true, FloatSize(minLayoutWidth, minLayoutHeight), PrintingMaximumShrinkFactor / PrintingMinimumShrinkFactor, Frame::AdjustViewSize);
+}
+
+void PrintContext::spoolPage(GraphicsContext& ctx, int pageNumber, float width)
+{
+ IntRect pageRect = m_pageRects[pageNumber];
+ float scale = width / pageRect.width();
+
+ ctx.save();
+ ctx.scale(FloatSize(scale, scale));
+ ctx.translate(-pageRect.x(), -pageRect.y());
+ ctx.clip(pageRect);
+ m_frame->view()->paintContents(&ctx, pageRect);
+ ctx.restore();
+}
+
+void PrintContext::end()
+{
+ ASSERT(m_isPrinting);
+ m_isPrinting = false;
+ m_frame->setPrinting(false, FloatSize(), 0, Frame::AdjustViewSize);
+}
+
+static RenderBoxModelObject* enclosingBoxModelObject(RenderObject* object)
+{
+
+ while (object && !object->isBoxModelObject())
+ object = object->parent();
+ if (!object)
+ return 0;
+ return toRenderBoxModelObject(object);
+}
+
+int PrintContext::pageNumberForElement(Element* element, const FloatSize& pageSizeInPixels)
+{
+ // Make sure the element is not freed during the layout.
+ RefPtr<Element> elementRef(element);
+ element->document()->updateLayout();
+
+ RenderBoxModelObject* box = enclosingBoxModelObject(element->renderer());
+ if (!box)
+ return -1;
+
+ Frame* frame = element->document()->frame();
+ FloatRect pageRect(FloatPoint(0, 0), pageSizeInPixels);
+ PrintContext printContext(frame);
+ printContext.begin(pageRect.width(), pageRect.height());
+ FloatSize scaledPageSize = pageSizeInPixels;
+ scaledPageSize.scale(frame->view()->contentsSize().width() / pageRect.width());
+ printContext.computePageRectsWithPageSize(scaledPageSize, false);
+
+ int top = box->offsetTop();
+ int left = box->offsetLeft();
+ int pageNumber = 0;
+ for (; pageNumber < printContext.pageCount(); pageNumber++) {
+ const IntRect& page = printContext.pageRect(pageNumber);
+ if (page.x() <= left && left < page.right() && page.y() <= top && top < page.bottom())
+ return pageNumber;
+ }
+ return -1;
+}
+
+String PrintContext::pageProperty(Frame* frame, const char* propertyName, int pageNumber)
+{
+ Document* document = frame->document();
+ PrintContext printContext(frame);
+ printContext.begin(800); // Any width is OK here.
+ document->updateLayout();
+ RefPtr<RenderStyle> style = document->styleForPage(pageNumber);
+
+ // Implement formatters for properties we care about.
+ if (!strcmp(propertyName, "margin-left")) {
+ if (style->marginLeft().isAuto())
+ return String("auto");
+ return String::number(style->marginLeft().rawValue());
+ }
+ if (!strcmp(propertyName, "line-height"))
+ return String::number(style->lineHeight().rawValue());
+ if (!strcmp(propertyName, "font-size"))
+ return String::number(style->fontDescription().computedPixelSize());
+ if (!strcmp(propertyName, "font-family"))
+ return style->fontDescription().family().family().string();
+ if (!strcmp(propertyName, "size"))
+ return makeString(String::number(style->pageSize().width().rawValue()), ' ', String::number(style->pageSize().height().rawValue()));
+
+ return makeString("pageProperty() unimplemented for: ", propertyName);
+}
+
+bool PrintContext::isPageBoxVisible(Frame* frame, int pageNumber)
+{
+ return frame->document()->isPageBoxVisible(pageNumber);
+}
+
+String PrintContext::pageSizeAndMarginsInPixels(Frame* frame, int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft)
+{
+ IntSize pageSize(width, height);
+ frame->document()->pageSizeAndMarginsInPixels(pageNumber, pageSize, marginTop, marginRight, marginBottom, marginLeft);
+
+ // We don't have a makeString() function that takes up to 12 arguments, if this is a hot function, we can provide one.
+ return makeString('(', String::number(pageSize.width()), ", ", String::number(pageSize.height()), ") ") +
+ makeString(String::number(marginTop), ' ', String::number(marginRight), ' ', String::number(marginBottom), ' ', String::number(marginLeft));
+}
+
+int PrintContext::numberOfPages(Frame* frame, const FloatSize& pageSizeInPixels)
+{
+ frame->document()->updateLayout();
+
+ FloatRect pageRect(FloatPoint(0, 0), pageSizeInPixels);
+ PrintContext printContext(frame);
+ printContext.begin(pageRect.width(), pageRect.height());
+ // Account for shrink-to-fit.
+ FloatSize scaledPageSize = pageSizeInPixels;
+ scaledPageSize.scale(frame->view()->contentsSize().width() / pageRect.width());
+ printContext.computePageRectsWithPageSize(scaledPageSize, false);
+ return printContext.pageCount();
+}
+
+void PrintContext::spoolAllPagesWithBoundaries(Frame* frame, GraphicsContext& graphicsContext, const FloatSize& pageSizeInPixels)
+{
+ if (!frame->document() || !frame->view() || !frame->document()->renderer())
+ return;
+
+ frame->document()->updateLayout();
+
+ PrintContext printContext(frame);
+ printContext.begin(pageSizeInPixels.width(), pageSizeInPixels.height());
+
+ float pageHeight;
+ printContext.computePageRects(FloatRect(FloatPoint(0, 0), pageSizeInPixels), 0, 0, 1, pageHeight);
+
+ const float pageWidth = pageSizeInPixels.width();
+ const Vector<IntRect>& pageRects = printContext.pageRects();
+ int totalHeight = pageRects.size() * (pageSizeInPixels.height() + 1) - 1;
+
+ // Fill the whole background by white.
+ graphicsContext.setFillColor(Color(255, 255, 255), ColorSpaceDeviceRGB);
+ graphicsContext.fillRect(FloatRect(0, 0, pageWidth, totalHeight));
+
+ graphicsContext.save();
+ graphicsContext.translate(0, totalHeight);
+ graphicsContext.scale(FloatSize(1, -1));
+
+ int currentHeight = 0;
+ for (size_t pageIndex = 0; pageIndex < pageRects.size(); pageIndex++) {
+ // Draw a line for a page boundary if this isn't the first page.
+ if (pageIndex > 0) {
+ graphicsContext.save();
+ graphicsContext.setStrokeColor(Color(0, 0, 255), ColorSpaceDeviceRGB);
+ graphicsContext.setFillColor(Color(0, 0, 255), ColorSpaceDeviceRGB);
+ graphicsContext.drawLine(IntPoint(0, currentHeight),
+ IntPoint(pageWidth, currentHeight));
+ graphicsContext.restore();
+ }
+
+ graphicsContext.save();
+ graphicsContext.translate(0, currentHeight);
+ printContext.spoolPage(graphicsContext, pageIndex, pageWidth);
+ graphicsContext.restore();
+
+ currentHeight += pageSizeInPixels.height() + 1;
+ }
+
+ graphicsContext.restore();
+}
+
+}
diff --git a/Source/WebCore/page/PrintContext.h b/Source/WebCore/page/PrintContext.h
new file mode 100644
index 0000000..ceda892
--- /dev/null
+++ b/Source/WebCore/page/PrintContext.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2007 Apple Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PrintContext_h
+#define PrintContext_h
+
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Element;
+class Frame;
+class FloatRect;
+class FloatSize;
+class GraphicsContext;
+class IntRect;
+
+class PrintContext {
+public:
+ PrintContext(Frame*);
+ ~PrintContext();
+
+ int pageCount() const;
+ const IntRect& pageRect(int pageNumber) const;
+ const Vector<IntRect>& pageRects() const { return m_pageRects; }
+
+ void computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight);
+ void computePageRectsWithPageSize(const FloatSize& pageSizeInPixels, bool allowHorizontalMultiPages);
+
+ // TODO: eliminate width param
+ void begin(float width, float height = 0);
+
+ // TODO: eliminate width param
+ void spoolPage(GraphicsContext& ctx, int pageNumber, float width);
+
+ void end();
+
+ // Used by layout tests.
+ static int pageNumberForElement(Element*, const FloatSize& pageSizeInPixels);
+ static String pageProperty(Frame* frame, const char* propertyName, int pageNumber);
+ static bool isPageBoxVisible(Frame* frame, int pageNumber);
+ static String pageSizeAndMarginsInPixels(Frame* frame, int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft);
+ static int numberOfPages(Frame*, const FloatSize& pageSizeInPixels);
+ // Draw all pages into a graphics context with lines which mean page boundaries.
+ // The height of the graphics context should be
+ // (pageSizeInPixels.height() + 1) * number-of-pages - 1
+ static void spoolAllPagesWithBoundaries(Frame*, GraphicsContext&, const FloatSize& pageSizeInPixels);
+
+protected:
+ Frame* m_frame;
+ Vector<IntRect> m_pageRects;
+
+private:
+ void computePageRectsWithPageSizeInternal(const FloatSize& pageSizeInPixels, bool allowHorizontalMultiPages);
+
+ // Used to prevent misuses of begin() and end() (e.g., call end without begin).
+ bool m_isPrinting;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/page/Screen.cpp b/Source/WebCore/page/Screen.cpp
new file mode 100644
index 0000000..bddc030
--- /dev/null
+++ b/Source/WebCore/page/Screen.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "Screen.h"
+
+#include "FloatRect.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "PlatformScreen.h"
+#include "Widget.h"
+
+namespace WebCore {
+
+Screen::Screen(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+Frame* Screen::frame() const
+{
+ return m_frame;
+}
+
+void Screen::disconnectFrame()
+{
+ m_frame = 0;
+}
+
+unsigned Screen::height() const
+{
+ if (!m_frame)
+ return 0;
+ return static_cast<unsigned>(screenRect(m_frame->view()).height());
+}
+
+unsigned Screen::width() const
+{
+ if (!m_frame)
+ return 0;
+ return static_cast<unsigned>(screenRect(m_frame->view()).width());
+}
+
+unsigned Screen::colorDepth() const
+{
+ if (!m_frame)
+ return 0;
+ return static_cast<unsigned>(screenDepth(m_frame->view()));
+}
+
+unsigned Screen::pixelDepth() const
+{
+ if (!m_frame)
+ return 0;
+ return static_cast<unsigned>(screenDepth(m_frame->view()));
+}
+
+int Screen::availLeft() const
+{
+ if (!m_frame)
+ return 0;
+ return static_cast<int>(screenAvailableRect(m_frame->view()).x());
+}
+
+int Screen::availTop() const
+{
+ if (!m_frame)
+ return 0;
+ return static_cast<int>(screenAvailableRect(m_frame->view()).y());
+}
+
+unsigned Screen::availHeight() const
+{
+ if (!m_frame)
+ return 0;
+ return static_cast<unsigned>(screenAvailableRect(m_frame->view()).height());
+}
+
+unsigned Screen::availWidth() const
+{
+ if (!m_frame)
+ return 0;
+ return static_cast<unsigned>(screenAvailableRect(m_frame->view()).width());
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/Screen.h b/Source/WebCore/page/Screen.h
new file mode 100644
index 0000000..5716d46
--- /dev/null
+++ b/Source/WebCore/page/Screen.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 Screen_h
+#define Screen_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class Frame;
+
+ class Screen : public RefCounted<Screen> {
+ public:
+ static PassRefPtr<Screen> create(Frame *frame) { return adoptRef(new Screen(frame)); }
+
+ Frame* frame() const;
+ void disconnectFrame();
+
+ unsigned height() const;
+ unsigned width() const;
+ unsigned colorDepth() const;
+ unsigned pixelDepth() const;
+ int availLeft() const;
+ int availTop() const;
+ unsigned availHeight() const;
+ unsigned availWidth() const;
+
+ private:
+ Screen(Frame*);
+
+ Frame* m_frame;
+ };
+
+} // namespace WebCore
+
+#endif // Screen_h
diff --git a/Source/WebCore/page/Screen.idl b/Source/WebCore/page/Screen.idl
new file mode 100644
index 0000000..50f87ee
--- /dev/null
+++ b/Source/WebCore/page/Screen.idl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+module window {
+
+ interface [OmitConstructor] Screen {
+ readonly attribute unsigned long height;
+ readonly attribute unsigned long width;
+ readonly attribute unsigned long colorDepth;
+ readonly attribute unsigned long pixelDepth;
+ readonly attribute long availLeft;
+ readonly attribute long availTop;
+ readonly attribute unsigned long availHeight;
+ readonly attribute unsigned long availWidth;
+ };
+
+}
diff --git a/Source/WebCore/page/SecurityOrigin.cpp b/Source/WebCore/page/SecurityOrigin.cpp
new file mode 100644
index 0000000..16de640
--- /dev/null
+++ b/Source/WebCore/page/SecurityOrigin.cpp
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "SecurityOrigin.h"
+
+#include "BlobURL.h"
+#include "Document.h"
+#include "FileSystem.h"
+#include "KURL.h"
+#include "OriginAccessEntry.h"
+#include "SchemeRegistry.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+static SecurityOrigin::LocalLoadPolicy localLoadPolicy = SecurityOrigin::AllowLocalLoadsForLocalOnly;
+const int MaxAllowedPort = 65535;
+
+typedef Vector<OriginAccessEntry> OriginAccessWhiteList;
+typedef HashMap<String, OriginAccessWhiteList*> OriginAccessMap;
+
+static OriginAccessMap& originAccessMap()
+{
+ DEFINE_STATIC_LOCAL(OriginAccessMap, originAccessMap, ());
+ return originAccessMap;
+}
+
+static bool schemeRequiresAuthority(const String& scheme)
+{
+ DEFINE_STATIC_LOCAL(URLSchemesMap, schemes, ());
+
+ if (schemes.isEmpty()) {
+ schemes.add("http");
+ schemes.add("https");
+ schemes.add("ftp");
+ }
+
+ return schemes.contains(scheme);
+}
+
+
+SecurityOrigin::SecurityOrigin(const KURL& url, SandboxFlags sandboxFlags)
+ : m_sandboxFlags(sandboxFlags)
+ , m_protocol(url.protocol().isNull() ? "" : url.protocol().lower())
+ , m_host(url.host().isNull() ? "" : url.host().lower())
+ , m_port(url.port())
+ , m_isUnique(isSandboxed(SandboxOrigin) || SchemeRegistry::shouldTreatURLSchemeAsNoAccess(m_protocol))
+ , m_universalAccess(false)
+ , m_domainWasSetInDOM(false)
+ , m_enforceFilePathSeparation(false)
+{
+ // These protocols do not create security origins; the owner frame provides the origin
+ if (m_protocol == "about" || m_protocol == "javascript")
+ m_protocol = "";
+
+ // For edge case URLs that were probably misparsed, make sure that the origin is unique.
+ if (schemeRequiresAuthority(m_protocol) && m_host.isEmpty())
+ m_isUnique = true;
+
+ // document.domain starts as m_host, but can be set by the DOM.
+ m_domain = m_host;
+
+ // By default, only local SecurityOrigins can load local resources.
+ m_canLoadLocalResources = isLocal();
+ if (m_canLoadLocalResources) {
+ // Directories should never be readable.
+ if (!url.hasPath() || url.path().endsWith("/"))
+ m_isUnique = true;
+ // Store the path in case we are doing per-file origin checking.
+ m_filePath = url.path();
+ }
+
+ if (isDefaultPortForProtocol(m_port, m_protocol))
+ m_port = 0;
+}
+
+SecurityOrigin::SecurityOrigin(const SecurityOrigin* other)
+ : m_sandboxFlags(other->m_sandboxFlags)
+ , m_protocol(other->m_protocol.threadsafeCopy())
+ , m_host(other->m_host.threadsafeCopy())
+ , m_encodedHost(other->m_encodedHost.threadsafeCopy())
+ , m_domain(other->m_domain.threadsafeCopy())
+ , m_filePath(other->m_filePath.threadsafeCopy())
+ , m_port(other->m_port)
+ , m_isUnique(other->m_isUnique)
+ , m_universalAccess(other->m_universalAccess)
+ , m_domainWasSetInDOM(other->m_domainWasSetInDOM)
+ , m_canLoadLocalResources(other->m_canLoadLocalResources)
+ , m_enforceFilePathSeparation(other->m_enforceFilePathSeparation)
+{
+}
+
+bool SecurityOrigin::isEmpty() const
+{
+ return m_protocol.isEmpty();
+}
+
+PassRefPtr<SecurityOrigin> SecurityOrigin::create(const KURL& url, SandboxFlags sandboxFlags)
+{
+ if (!url.isValid())
+ return adoptRef(new SecurityOrigin(KURL(), sandboxFlags));
+#if ENABLE(BLOB)
+ if (url.protocolIs(BlobURL::blobProtocol()))
+ return adoptRef(new SecurityOrigin(BlobURL::getOrigin(url), sandboxFlags));
+#endif
+ return adoptRef(new SecurityOrigin(url, sandboxFlags));
+}
+
+PassRefPtr<SecurityOrigin> SecurityOrigin::createEmpty()
+{
+ return create(KURL());
+}
+
+PassRefPtr<SecurityOrigin> SecurityOrigin::threadsafeCopy()
+{
+ return adoptRef(new SecurityOrigin(this));
+}
+
+void SecurityOrigin::setDomainFromDOM(const String& newDomain)
+{
+ m_domainWasSetInDOM = true;
+ m_domain = newDomain.lower();
+}
+
+static HashSet<String>& schemesForbiddenFromDomainRelaxation()
+{
+ DEFINE_STATIC_LOCAL(HashSet<String>, schemes, ());
+ return schemes;
+}
+
+void SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const String& scheme)
+{
+ if (scheme.isEmpty())
+ return;
+
+ if (forbidden)
+ schemesForbiddenFromDomainRelaxation().add(scheme);
+ else
+ schemesForbiddenFromDomainRelaxation().remove(scheme);
+}
+
+bool SecurityOrigin::isDomainRelaxationForbiddenForURLScheme(const String& scheme)
+{
+ if (scheme.isEmpty())
+ return false;
+
+ return schemesForbiddenFromDomainRelaxation().contains(scheme);
+}
+
+bool SecurityOrigin::canAccess(const SecurityOrigin* other) const
+{
+ if (m_universalAccess)
+ return true;
+
+ if (isUnique() || other->isUnique())
+ return false;
+
+ // Here are two cases where we should permit access:
+ //
+ // 1) Neither document has set document.domain. In this case, we insist
+ // that the scheme, host, and port of the URLs match.
+ //
+ // 2) Both documents have set document.domain. In this case, we insist
+ // that the documents have set document.domain to the same value and
+ // that the scheme of the URLs match.
+ //
+ // This matches the behavior of Firefox 2 and Internet Explorer 6.
+ //
+ // Internet Explorer 7 and Opera 9 are more strict in that they require
+ // the port numbers to match when both pages have document.domain set.
+ //
+ // FIXME: Evaluate whether we can tighten this policy to require matched
+ // port numbers.
+ //
+ // Opera 9 allows access when only one page has set document.domain, but
+ // this is a security vulnerability.
+
+ bool canAccess = false;
+ if (m_protocol == other->m_protocol) {
+ if (!m_domainWasSetInDOM && !other->m_domainWasSetInDOM) {
+ if (m_host == other->m_host && m_port == other->m_port)
+ canAccess = true;
+ } else if (m_domainWasSetInDOM && other->m_domainWasSetInDOM) {
+ if (m_domain == other->m_domain)
+ canAccess = true;
+ }
+ }
+
+ if (canAccess && isLocal())
+ canAccess = passesFileCheck(other);
+
+ return canAccess;
+}
+
+bool SecurityOrigin::passesFileCheck(const SecurityOrigin* other) const
+{
+ ASSERT(isLocal() && other->isLocal());
+
+ if (!m_enforceFilePathSeparation && !other->m_enforceFilePathSeparation)
+ return true;
+
+ return (m_filePath == other->m_filePath);
+}
+
+bool SecurityOrigin::canRequest(const KURL& url) const
+{
+ if (m_universalAccess)
+ return true;
+
+ if (isUnique())
+ return false;
+
+ RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url);
+
+ bool doUniqueOriginCheck = true;
+#if ENABLE(BLOB)
+ // For blob scheme, we want to ignore this check.
+ doUniqueOriginCheck = !url.protocolIs(BlobURL::blobProtocol());
+#endif
+ if (doUniqueOriginCheck && targetOrigin->isUnique())
+ return false;
+
+ // We call isSameSchemeHostPort here instead of canAccess because we want
+ // to ignore document.domain effects.
+ if (isSameSchemeHostPort(targetOrigin.get()))
+ return true;
+
+ if (isAccessWhiteListed(targetOrigin.get()))
+ return true;
+
+ return false;
+}
+
+bool SecurityOrigin::taintsCanvas(const KURL& url) const
+{
+ if (canRequest(url))
+ return false;
+
+ // This function exists because 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 let folks paint data URLs onto untainted canvases, so
+ // we special case data URLs below. If we change to match HTML5 w.r.t.
+ // data URL security, then we can remove this function in favor of
+ // !canRequest.
+ if (url.protocolIsData())
+ return false;
+
+ return true;
+}
+
+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
+ // match HTML5 w.r.t. data URL security, then we can remove this check.
+ if (m_protocol == "data")
+ return true;
+
+ return canAccess(dragInitiator);
+}
+
+bool SecurityOrigin::isAccessWhiteListed(const SecurityOrigin* targetOrigin) const
+{
+ if (OriginAccessWhiteList* list = originAccessMap().get(toString())) {
+ for (size_t i = 0; i < list->size(); ++i) {
+ if (list->at(i).matchesOrigin(*targetOrigin))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SecurityOrigin::canDisplay(const KURL& url) const
+{
+#if ENABLE(BLOB)
+ if (url.protocolIs(BlobURL::blobProtocol()))
+ return canRequest(url);
+#endif
+
+ if (!restrictAccessToLocal())
+ return true;
+
+ if (!SchemeRegistry::shouldTreatURLAsLocal(url.string()))
+ return true;
+
+ RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url);
+ if (isAccessWhiteListed(targetOrigin.get()))
+ return true;
+
+ return canLoadLocalResources();
+}
+
+void SecurityOrigin::grantLoadLocalResources()
+{
+ // This function exists only to support backwards compatibility with older
+ // versions of WebKit. Granting privileges to some, but not all, documents
+ // in a SecurityOrigin is a security hazard because the documents without
+ // the privilege can obtain the privilege by injecting script into the
+ // documents that have been granted the privilege.
+ ASSERT(allowSubstituteDataAccessToLocal());
+ m_canLoadLocalResources = true;
+}
+
+void SecurityOrigin::grantUniversalAccess()
+{
+ m_universalAccess = true;
+}
+
+void SecurityOrigin::enforceFilePathSeparation()
+{
+ ASSERT(isLocal());
+ m_enforceFilePathSeparation = true;
+}
+
+bool SecurityOrigin::isLocal() const
+{
+ return SchemeRegistry::shouldTreatURLSchemeAsLocal(m_protocol);
+}
+
+bool SecurityOrigin::isSecureTransitionTo(const KURL& url) const
+{
+ // New window created by the application
+ if (isEmpty())
+ return true;
+
+ RefPtr<SecurityOrigin> other = SecurityOrigin::create(url);
+ return canAccess(other.get());
+}
+
+String SecurityOrigin::toString() const
+{
+ if (isEmpty())
+ return "null";
+
+ if (isUnique())
+ return "null";
+
+ if (m_protocol == "file") {
+ if (m_enforceFilePathSeparation)
+ return "null";
+ return "file://";
+ }
+
+ Vector<UChar> result;
+ result.reserveInitialCapacity(m_protocol.length() + m_host.length() + 10);
+ append(result, m_protocol);
+ append(result, "://");
+ append(result, m_host);
+
+ if (m_port) {
+ append(result, ":");
+ append(result, String::number(m_port));
+ }
+
+ return String::adopt(result);
+}
+
+PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& originString)
+{
+ return SecurityOrigin::create(KURL(KURL(), originString));
+}
+
+static const char SeparatorCharacter = '_';
+
+PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const String& databaseIdentifier)
+{
+ // Make sure there's a first separator
+ size_t separator1 = databaseIdentifier.find(SeparatorCharacter);
+ if (separator1 == notFound)
+ return create(KURL());
+
+ // Make sure there's a second separator
+ size_t separator2 = databaseIdentifier.reverseFind(SeparatorCharacter);
+ if (separator2 == notFound)
+ return create(KURL());
+
+ // Ensure there were at least 2 separator characters. Some hostnames on intranets have
+ // underscores in them, so we'll assume that any additional underscores are part of the host.
+ if (separator1 == separator2)
+ return create(KURL());
+
+ // Make sure the port section is a valid port number or doesn't exist
+ bool portOkay;
+ int port = databaseIdentifier.right(databaseIdentifier.length() - separator2 - 1).toInt(&portOkay);
+ bool portAbsent = (separator2 == databaseIdentifier.length() - 1);
+ if (!(portOkay || portAbsent))
+ return create(KURL());
+
+ if (port < 0 || port > MaxAllowedPort)
+ return create(KURL());
+
+ // Split out the 3 sections of data
+ String protocol = databaseIdentifier.substring(0, separator1);
+ String host = databaseIdentifier.substring(separator1 + 1, separator2 - separator1 - 1);
+
+ host = decodeURLEscapeSequences(host);
+ return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(port)));
+}
+
+PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const String& host, int port)
+{
+ if (port < 0 || port > MaxAllowedPort)
+ create(KURL());
+ String decodedHost = decodeURLEscapeSequences(host);
+ return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(port)));
+}
+
+String SecurityOrigin::databaseIdentifier() const
+{
+ String separatorString(&SeparatorCharacter, 1);
+
+ if (m_encodedHost.isEmpty())
+ m_encodedHost = encodeForFileName(m_host);
+
+ return m_protocol + separatorString + m_encodedHost + separatorString + String::number(m_port);
+}
+
+bool SecurityOrigin::equal(const SecurityOrigin* other) const
+{
+ if (other == this)
+ return true;
+
+ if (!isSameSchemeHostPort(other))
+ return false;
+
+ if (m_domainWasSetInDOM != other->m_domainWasSetInDOM)
+ return false;
+
+ if (m_domainWasSetInDOM && m_domain != other->m_domain)
+ return false;
+
+ return true;
+}
+
+bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const
+{
+ if (m_host != other->m_host)
+ return false;
+
+ if (m_protocol != other->m_protocol)
+ return false;
+
+ if (m_port != other->m_port)
+ return false;
+
+ if (isLocal() && !passesFileCheck(other))
+ return false;
+
+ return true;
+}
+
+bool SecurityOrigin::shouldHideReferrer(const KURL& url, const String& referrer)
+{
+ bool referrerIsSecureURL = protocolIs(referrer, "https");
+ bool referrerIsWebURL = referrerIsSecureURL || protocolIs(referrer, "http");
+
+ if (!referrerIsWebURL)
+ return true;
+
+ if (!referrerIsSecureURL)
+ return false;
+
+ bool URLIsSecureURL = url.protocolIs("https");
+
+ return !URLIsSecureURL;
+}
+
+void SecurityOrigin::setLocalLoadPolicy(LocalLoadPolicy policy)
+{
+ localLoadPolicy = policy;
+}
+
+bool SecurityOrigin::restrictAccessToLocal()
+{
+ return localLoadPolicy != SecurityOrigin::AllowLocalLoadsForAll;
+}
+
+bool SecurityOrigin::allowSubstituteDataAccessToLocal()
+{
+ return localLoadPolicy != SecurityOrigin::AllowLocalLoadsForLocalOnly;
+}
+
+void SecurityOrigin::addOriginAccessWhitelistEntry(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains)
+{
+ ASSERT(isMainThread());
+ ASSERT(!sourceOrigin.isEmpty());
+ if (sourceOrigin.isEmpty())
+ return;
+
+ String sourceString = sourceOrigin.toString();
+ pair<OriginAccessMap::iterator, bool> result = originAccessMap().add(sourceString, 0);
+ if (result.second)
+ result.first->second = new OriginAccessWhiteList;
+
+ OriginAccessWhiteList* list = result.first->second;
+ list->append(OriginAccessEntry(destinationProtocol, destinationDomains, allowDestinationSubdomains ? OriginAccessEntry::AllowSubdomains : OriginAccessEntry::DisallowSubdomains));
+}
+
+void SecurityOrigin::removeOriginAccessWhitelistEntry(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains)
+{
+ ASSERT(isMainThread());
+ ASSERT(!sourceOrigin.isEmpty());
+ if (sourceOrigin.isEmpty())
+ return;
+
+ String sourceString = sourceOrigin.toString();
+ OriginAccessMap& map = originAccessMap();
+ OriginAccessMap::iterator it = map.find(sourceString);
+ if (it == map.end())
+ return;
+
+ OriginAccessWhiteList* list = it->second;
+ size_t index = list->find(OriginAccessEntry(destinationProtocol, destinationDomains, allowDestinationSubdomains ? OriginAccessEntry::AllowSubdomains : OriginAccessEntry::DisallowSubdomains));
+ if (index == notFound)
+ return;
+
+ list->remove(index);
+
+ if (!list->isEmpty())
+ return;
+
+ map.remove(it);
+ delete list;
+}
+
+void SecurityOrigin::resetOriginAccessWhitelists()
+{
+ ASSERT(isMainThread());
+ OriginAccessMap& map = originAccessMap();
+ deleteAllValues(map);
+ map.clear();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/SecurityOrigin.h b/Source/WebCore/page/SecurityOrigin.h
new file mode 100644
index 0000000..61f6ab8
--- /dev/null
+++ b/Source/WebCore/page/SecurityOrigin.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 SecurityOrigin_h
+#define SecurityOrigin_h
+
+#include "FrameLoaderTypes.h"
+#include "PlatformString.h"
+#include <wtf/ThreadSafeShared.h>
+
+namespace WebCore {
+
+class Document;
+class KURL;
+
+class SecurityOrigin : public ThreadSafeShared<SecurityOrigin> {
+public:
+ static PassRefPtr<SecurityOrigin> createFromDatabaseIdentifier(const String&);
+ static PassRefPtr<SecurityOrigin> createFromString(const String&);
+ static PassRefPtr<SecurityOrigin> create(const String& protocol, const String& host, int port);
+ static PassRefPtr<SecurityOrigin> create(const KURL&, SandboxFlags = SandboxNone);
+ static PassRefPtr<SecurityOrigin> createEmpty();
+
+ // Create a deep copy of this SecurityOrigin. This method is useful
+ // when marshalling a SecurityOrigin to another thread.
+ PassRefPtr<SecurityOrigin> threadsafeCopy();
+
+ // Set the domain property of this security origin to newDomain. This
+ // function does not check whether newDomain is a suffix of the current
+ // domain. The caller is responsible for validating newDomain.
+ void setDomainFromDOM(const String& newDomain);
+ bool domainWasSetInDOM() const { return m_domainWasSetInDOM; }
+
+ static void setDomainRelaxationForbiddenForURLScheme(bool forbidden, const String&);
+ static bool isDomainRelaxationForbiddenForURLScheme(const String&);
+
+ String protocol() const { return m_protocol; }
+ String host() const { return m_host; }
+ String domain() const { return m_domain; }
+ unsigned short port() const { return m_port; }
+
+ // Returns true if this SecurityOrigin can script objects in the given
+ // SecurityOrigin. For example, call this function before allowing
+ // script from one security origin to read or write objects from
+ // another SecurityOrigin.
+ bool canAccess(const SecurityOrigin*) const;
+
+ // Returns true if this SecurityOrigin can read content retrieved from
+ // the given URL. For example, call this function before issuing
+ // XMLHttpRequests.
+ bool canRequest(const KURL&) const;
+
+ // Returns true if drawing an image from this URL taints a canvas from
+ // this security origin. For example, call this function before
+ // drawing an image onto an HTML canvas element with the drawImage API.
+ bool taintsCanvas(const KURL&) const;
+
+ // Returns true if this SecurityOrigin can receive drag content from the
+ // initiator. For example, call this function before allowing content to be
+ // dropped onto a target.
+ bool canReceiveDragData(const SecurityOrigin* dragInitiator) const;
+
+ // Returns true if |document| can display content from the given URL (e.g.,
+ // in an iframe or as an image). For example, web sites generally cannot
+ // display content from the user's files system.
+ bool canDisplay(const KURL&) const;
+
+ // Returns true if this SecurityOrigin can load local resources, such
+ // as images, iframes, and style sheets, and can link to local URLs.
+ // For example, call this function before creating an iframe to a
+ // file:// URL.
+ //
+ // Note: A SecurityOrigin might be allowed to load local resources
+ // without being able to issue an XMLHttpRequest for a local URL.
+ // To determine whether the SecurityOrigin can issue an
+ // XMLHttpRequest for a URL, call canRequest(url).
+ bool canLoadLocalResources() const { return m_canLoadLocalResources; }
+
+ // Explicitly grant the ability to load local resources to this
+ // SecurityOrigin.
+ //
+ // Note: This method exists only to support backwards compatibility
+ // with older versions of WebKit.
+ void grantLoadLocalResources();
+
+ // Explicitly grant the ability to access very other SecurityOrigin.
+ //
+ // WARNING: This is an extremely powerful ability. Use with caution!
+ void grantUniversalAccess();
+
+ bool isSandboxed(SandboxFlags mask) const { return m_sandboxFlags & mask; }
+
+ bool canAccessDatabase() const { return !isUnique(); }
+ bool canAccessLocalStorage() const { return !isUnique(); }
+ bool canAccessCookies() const { return !isUnique(); }
+ bool canAccessPasswordManager() const { return !isUnique(); }
+ bool canAccessFileSystem() const { return !isUnique(); }
+
+ // Technically, we should always allow access to sessionStorage, but we
+ // currently don't handle creating a sessionStorage area for unique
+ // origins.
+ bool canAccessSessionStorage() const { return !isUnique(); }
+
+ bool isSecureTransitionTo(const KURL&) const;
+
+ // The local SecurityOrigin is the most privileged SecurityOrigin.
+ // The local SecurityOrigin can script any document, navigate to local
+ // resources, and can set arbitrary headers on XMLHttpRequests.
+ bool isLocal() const;
+
+ // The empty SecurityOrigin is the least privileged SecurityOrigin.
+ bool isEmpty() const;
+
+ // The origin is a globally unique identifier assigned when the Document is
+ // created. http://www.whatwg.org/specs/web-apps/current-work/#sandboxOrigin
+ //
+ // There's a subtle difference between a unique origin and an origin that
+ // has the SandboxOrigin flag set. The latter implies the former, and, in
+ // addition, the SandboxOrigin flag is inherited by iframes.
+ bool isUnique() const { return m_isUnique; }
+
+ // Marks a file:// origin as being in a domain defined by its path.
+ void enforceFilePathSeparation();
+
+ // Convert this SecurityOrigin into a string. The string
+ // representation of a SecurityOrigin is similar to a URL, except it
+ // lacks a path component. The string representation does not encode
+ // the value of the SecurityOrigin's domain property.
+ //
+ // When using the string value, it's important to remember that it might be
+ // "null". This happens when this SecurityOrigin is unique. For example,
+ // this SecurityOrigin might have come from a sandboxed iframe, the
+ // SecurityOrigin might be empty, or we might have explicitly decided that
+ // we shouldTreatURLSchemeAsNoAccess.
+ String toString() const;
+
+ // Serialize the security origin to a string that could be used as part of
+ // file names. This format should be used in storage APIs only.
+ String databaseIdentifier() const;
+
+ // This method checks for equality between SecurityOrigins, not whether
+ // one origin can access another. It is used for hash table keys.
+ // For access checks, use canAccess().
+ // FIXME: If this method is really only useful for hash table keys, it
+ // should be refactored into SecurityOriginHash.
+ bool equal(const SecurityOrigin*) const;
+
+ // This method checks for equality, ignoring the value of document.domain
+ // (and whether it was set) but considering the host. It is used for postMessage.
+ bool isSameSchemeHostPort(const SecurityOrigin*) const;
+
+ static bool shouldHideReferrer(const KURL&, const String& referrer);
+
+ enum LocalLoadPolicy {
+ AllowLocalLoadsForAll, // No restriction on local loads.
+ AllowLocalLoadsForLocalAndSubstituteData,
+ AllowLocalLoadsForLocalOnly,
+ };
+ static void setLocalLoadPolicy(LocalLoadPolicy);
+ static bool restrictAccessToLocal();
+ static bool allowSubstituteDataAccessToLocal();
+
+ static void addOriginAccessWhitelistEntry(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains);
+ static void removeOriginAccessWhitelistEntry(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains);
+ static void resetOriginAccessWhitelists();
+
+private:
+ SecurityOrigin(const KURL&, SandboxFlags);
+ explicit SecurityOrigin(const SecurityOrigin*);
+
+ bool passesFileCheck(const SecurityOrigin* other) const;
+
+ bool isAccessWhiteListed(const SecurityOrigin* targetOrigin) const;
+
+ SandboxFlags m_sandboxFlags;
+ String m_protocol;
+ String m_host;
+ mutable String m_encodedHost;
+ String m_domain;
+ String m_filePath;
+ unsigned short m_port;
+ bool m_isUnique;
+ bool m_universalAccess;
+ bool m_domainWasSetInDOM;
+ bool m_canLoadLocalResources;
+ bool m_enforceFilePathSeparation;
+};
+
+} // namespace WebCore
+
+#endif // SecurityOrigin_h
diff --git a/Source/WebCore/page/SecurityOriginHash.h b/Source/WebCore/page/SecurityOriginHash.h
new file mode 100644
index 0000000..c2ebdd1
--- /dev/null
+++ b/Source/WebCore/page/SecurityOriginHash.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 SecurityOriginHash_h
+#define SecurityOriginHash_h
+
+#include "KURL.h"
+#include "SecurityOrigin.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+struct SecurityOriginHash {
+ static unsigned hash(SecurityOrigin* origin)
+ {
+ unsigned hashCodes[3] = {
+ origin->protocol().impl() ? origin->protocol().impl()->hash() : 0,
+ origin->host().impl() ? origin->host().impl()->hash() : 0,
+ origin->port()
+ };
+ return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes);
+ }
+ static unsigned hash(const RefPtr<SecurityOrigin>& origin)
+ {
+ return hash(origin.get());
+ }
+
+ static bool equal(SecurityOrigin* a, SecurityOrigin* b)
+ {
+ // FIXME: The hash function above compares three specific fields.
+ // This code to compare those three specific fields should be moved here from
+ // SecurityOrigin as mentioned in SecurityOrigin.h so we don't accidentally change
+ // equal without changing hash to match it.
+ if (!a || !b)
+ return a == b;
+ return a->equal(b);
+ }
+ static bool equal(SecurityOrigin* a, const RefPtr<SecurityOrigin>& b)
+ {
+ return equal(a, b.get());
+ }
+ static bool equal(const RefPtr<SecurityOrigin>& a, SecurityOrigin* b)
+ {
+ return equal(a.get(), b);
+ }
+ static bool equal(const RefPtr<SecurityOrigin>& a, const RefPtr<SecurityOrigin>& b)
+ {
+ return equal(a.get(), b.get());
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = false;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/page/Settings.cpp b/Source/WebCore/page/Settings.cpp
new file mode 100644
index 0000000..8b174be
--- /dev/null
+++ b/Source/WebCore/page/Settings.cpp
@@ -0,0 +1,884 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Settings.h"
+
+#include "BackForwardController.h"
+#include "CachedResourceLoader.h"
+#include "CookieStorage.h"
+#include "DOMTimer.h"
+#include "Database.h"
+#include "Frame.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "HistoryItem.h"
+#include "Page.h"
+#include "PageCache.h"
+#include "StorageMap.h"
+#include <limits>
+
+using namespace std;
+
+namespace WebCore {
+
+static void setNeedsRecalcStyleInAllFrames(Page* page)
+{
+ for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frame->document()->styleSelectorChanged(DeferRecalcStyle);
+}
+
+static void setLoadsImagesAutomaticallyInAllFrames(Page* page)
+{
+ for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frame->document()->cachedResourceLoader()->setAutoLoadImages(page->settings()->loadsImagesAutomatically());
+}
+
+#if USE(SAFARI_THEME)
+bool Settings::gShouldPaintNativeControls = true;
+#endif
+
+#if PLATFORM(WIN) || (OS(WINDOWS) && PLATFORM(WX))
+bool Settings::gShouldUseHighResolutionTimers = true;
+#endif
+
+// NOTEs
+// 1) EditingMacBehavior comprises Tiger, Leopard, SnowLeopard and iOS builds, as well QtWebKit and Chromium when built on Mac;
+// 2) EditingWindowsBehavior comprises Win32 and WinCE builds, as well as QtWebKit and Chromium when built on Windows;
+// 3) EditingUnixBehavior comprises all unix-based systems, but Darwin/MacOS (and then abusing the terminology);
+// 99) MacEditingBehavior is used a fallback.
+static EditingBehaviorType editingBehaviorTypeForPlatform()
+{
+ return
+#if OS(DARWIN)
+ EditingMacBehavior
+#elif OS(WINDOWS)
+ EditingWindowsBehavior
+#elif OS(UNIX)
+ EditingUnixBehavior
+#else
+ // Fallback
+ EditingMacBehavior
+#endif
+ ;
+}
+
+Settings::Settings(Page* page)
+ : m_page(page)
+#ifdef ANDROID_LAYOUT
+ , m_layoutAlgorithm(kLayoutFitColumnToScreen)
+#endif
+ , m_editableLinkBehavior(EditableLinkDefaultBehavior)
+ , m_textDirectionSubmenuInclusionBehavior(TextDirectionSubmenuAutomaticallyIncluded)
+ , m_minimumFontSize(0)
+ , m_minimumLogicalFontSize(0)
+ , m_defaultFontSize(0)
+ , m_defaultFixedFontSize(0)
+#ifdef ANDROID_LAYOUT
+ , m_useWideViewport(false)
+#endif
+#ifdef ANDROID_MULTIPLE_WINDOWS
+ , m_supportMultipleWindows(true)
+#endif
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+ , m_blockNetworkImage(false)
+#endif
+ , m_maximumDecodedImageSize(numeric_limits<size_t>::max())
+#if ENABLE(DOM_STORAGE)
+ , m_sessionStorageQuota(StorageMap::noQuota)
+#endif
+ , m_pluginAllowedRunTime(numeric_limits<unsigned>::max())
+ , m_editingBehaviorType(editingBehaviorTypeForPlatform())
+ , m_isSpatialNavigationEnabled(false)
+ , m_isJavaEnabled(false)
+ , m_loadsImagesAutomatically(false)
+ , m_privateBrowsingEnabled(false)
+ , m_caretBrowsingEnabled(false)
+ , m_areImagesEnabled(true)
+ , m_isMediaEnabled(true)
+ , m_arePluginsEnabled(false)
+ , m_localStorageEnabled(false)
+ , m_isJavaScriptEnabled(false)
+ , m_isWebSecurityEnabled(true)
+ , m_allowUniversalAccessFromFileURLs(true)
+ , m_allowFileAccessFromFileURLs(true)
+ , m_javaScriptCanOpenWindowsAutomatically(false)
+ , m_javaScriptCanAccessClipboard(false)
+ , m_shouldPrintBackgrounds(false)
+ , m_textAreasAreResizable(false)
+#if ENABLE(DASHBOARD_SUPPORT)
+ , m_usesDashboardBackwardCompatibilityMode(false)
+#endif
+ , m_needsAdobeFrameReloadingQuirk(false)
+ , m_needsKeyboardEventDisambiguationQuirks(false)
+ , m_treatsAnyTextCSSLinkAsStylesheet(false)
+ , m_needsLeopardMailQuirks(false)
+ , m_needsTigerMailQuirks(false)
+ , m_isDOMPasteAllowed(false)
+ , m_shrinksStandaloneImagesToFit(true)
+ , m_usesPageCache(false)
+ , m_showsURLsInToolTips(false)
+ , m_forceFTPDirectoryListings(false)
+ , m_developerExtrasEnabled(false)
+ , m_authorAndUserStylesEnabled(true)
+ , m_needsSiteSpecificQuirks(false)
+ , m_fontRenderingMode(0)
+ , m_frameFlatteningEnabled(false)
+ , m_webArchiveDebugModeEnabled(false)
+ , m_localFileContentSniffingEnabled(false)
+ , m_inApplicationChromeMode(false)
+ , m_offlineWebApplicationCacheEnabled(false)
+ , m_shouldPaintCustomScrollbars(false)
+ , m_enforceCSSMIMETypeInNoQuirksMode(true)
+ , m_usesEncodingDetector(false)
+ , m_allowScriptsToCloseWindows(false)
+ // 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)
+ , m_webGLEnabled(false)
+ , m_acceleratedCanvas2dEnabled(false)
+ , m_loadDeferringEnabled(true)
+ , m_tiledBackingStoreEnabled(false)
+ , m_paginateDuringLayoutEnabled(false)
+ , m_dnsPrefetchingEnabled(false)
+#if ENABLE(FULLSCREEN_API)
+ , m_fullScreenAPIEnabled(false)
+#endif
+ , m_asynchronousSpellCheckingEnabled(false)
+ , m_memoryInfoEnabled(false)
+ , m_interactiveFormValidation(false)
+ , m_usePreHTML5ParserQuirks(false)
+ , m_hyperlinkAuditingEnabled(false)
+ , m_crossOriginCheckInGetMatchedCSSRulesDisabled(false)
+#if ENABLE(WEB_AUTOFILL)
+ , m_autoFillEnabled(false)
+#endif
+#ifdef ANDROID_PLUGINS
+ , m_pluginsOnDemand(false)
+#endif
+{
+ // A Frame may not have been created yet, so we initialize the AtomicString
+ // hash before trying to use it.
+ AtomicString::init();
+#ifdef ANDROID_META_SUPPORT
+ m_default_format_detection = true;
+ resetMetadataSettings();
+#endif
+}
+
+void Settings::setStandardFontFamily(const AtomicString& standardFontFamily)
+{
+ if (standardFontFamily == m_standardFontFamily)
+ return;
+
+ m_standardFontFamily = standardFontFamily;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+void Settings::setFixedFontFamily(const AtomicString& fixedFontFamily)
+{
+ if (m_fixedFontFamily == fixedFontFamily)
+ return;
+
+ m_fixedFontFamily = fixedFontFamily;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+void Settings::setSerifFontFamily(const AtomicString& serifFontFamily)
+{
+ if (m_serifFontFamily == serifFontFamily)
+ return;
+
+ m_serifFontFamily = serifFontFamily;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+void Settings::setSansSerifFontFamily(const AtomicString& sansSerifFontFamily)
+{
+ if (m_sansSerifFontFamily == sansSerifFontFamily)
+ return;
+
+ m_sansSerifFontFamily = sansSerifFontFamily;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+void Settings::setCursiveFontFamily(const AtomicString& cursiveFontFamily)
+{
+ if (m_cursiveFontFamily == cursiveFontFamily)
+ return;
+
+ m_cursiveFontFamily = cursiveFontFamily;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+void Settings::setFantasyFontFamily(const AtomicString& fantasyFontFamily)
+{
+ if (m_fantasyFontFamily == fantasyFontFamily)
+ return;
+
+ m_fantasyFontFamily = fantasyFontFamily;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+void Settings::setMinimumFontSize(int minimumFontSize)
+{
+ if (m_minimumFontSize == minimumFontSize)
+ return;
+
+ m_minimumFontSize = minimumFontSize;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+void Settings::setMinimumLogicalFontSize(int minimumLogicalFontSize)
+{
+ if (m_minimumLogicalFontSize == minimumLogicalFontSize)
+ return;
+
+ m_minimumLogicalFontSize = minimumLogicalFontSize;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+void Settings::setDefaultFontSize(int defaultFontSize)
+{
+ if (m_defaultFontSize == defaultFontSize)
+ return;
+
+ m_defaultFontSize = defaultFontSize;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+void Settings::setDefaultFixedFontSize(int defaultFontSize)
+{
+ if (m_defaultFixedFontSize == defaultFontSize)
+ return;
+
+ m_defaultFixedFontSize = defaultFontSize;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+void Settings::setBlockNetworkImage(bool blockNetworkImage)
+{
+ m_blockNetworkImage = blockNetworkImage;
+}
+#endif
+
+void Settings::setLoadsImagesAutomatically(bool loadsImagesAutomatically)
+{
+ m_loadsImagesAutomatically = loadsImagesAutomatically;
+ setLoadsImagesAutomaticallyInAllFrames(m_page);
+}
+
+void Settings::setJavaScriptEnabled(bool isJavaScriptEnabled)
+{
+ m_isJavaScriptEnabled = isJavaScriptEnabled;
+}
+
+void Settings::setWebSecurityEnabled(bool isWebSecurityEnabled)
+{
+ m_isWebSecurityEnabled = isWebSecurityEnabled;
+}
+
+void Settings::setAllowUniversalAccessFromFileURLs(bool allowUniversalAccessFromFileURLs)
+{
+ m_allowUniversalAccessFromFileURLs = allowUniversalAccessFromFileURLs;
+}
+
+void Settings::setAllowFileAccessFromFileURLs(bool allowFileAccessFromFileURLs)
+{
+ m_allowFileAccessFromFileURLs = allowFileAccessFromFileURLs;
+}
+
+void Settings::setSpatialNavigationEnabled(bool isSpatialNavigationEnabled)
+{
+ m_isSpatialNavigationEnabled = isSpatialNavigationEnabled;
+}
+
+void Settings::setJavaEnabled(bool isJavaEnabled)
+{
+ m_isJavaEnabled = isJavaEnabled;
+}
+
+void Settings::setImagesEnabled(bool areImagesEnabled)
+{
+ m_areImagesEnabled = areImagesEnabled;
+}
+
+void Settings::setMediaEnabled(bool isMediaEnabled)
+{
+ m_isMediaEnabled = isMediaEnabled;
+}
+
+void Settings::setPluginsEnabled(bool arePluginsEnabled)
+{
+ m_arePluginsEnabled = arePluginsEnabled;
+}
+
+void Settings::setLocalStorageEnabled(bool localStorageEnabled)
+{
+ m_localStorageEnabled = localStorageEnabled;
+}
+
+#if ENABLE(DOM_STORAGE)
+void Settings::setSessionStorageQuota(unsigned sessionStorageQuota)
+{
+ m_sessionStorageQuota = sessionStorageQuota;
+}
+#endif
+
+void Settings::setPrivateBrowsingEnabled(bool privateBrowsingEnabled)
+{
+ if (m_privateBrowsingEnabled == privateBrowsingEnabled)
+ return;
+
+ // FIXME: We can only enable cookie private browsing mode globally, so it's misleading to have it as a per-page setting.
+ setCookieStoragePrivateBrowsingEnabled(privateBrowsingEnabled);
+
+ m_privateBrowsingEnabled = privateBrowsingEnabled;
+ m_page->privateBrowsingStateChanged();
+}
+
+void Settings::setJavaScriptCanOpenWindowsAutomatically(bool javaScriptCanOpenWindowsAutomatically)
+{
+ m_javaScriptCanOpenWindowsAutomatically = javaScriptCanOpenWindowsAutomatically;
+}
+
+void Settings::setJavaScriptCanAccessClipboard(bool javaScriptCanAccessClipboard)
+{
+ m_javaScriptCanAccessClipboard = javaScriptCanAccessClipboard;
+}
+
+void Settings::setDefaultTextEncodingName(const String& defaultTextEncodingName)
+{
+ m_defaultTextEncodingName = defaultTextEncodingName;
+}
+
+void Settings::setUserStyleSheetLocation(const KURL& userStyleSheetLocation)
+{
+ if (m_userStyleSheetLocation == userStyleSheetLocation)
+ return;
+
+ m_userStyleSheetLocation = userStyleSheetLocation;
+
+ m_page->userStyleSheetLocationChanged();
+}
+
+void Settings::setShouldPrintBackgrounds(bool shouldPrintBackgrounds)
+{
+ m_shouldPrintBackgrounds = shouldPrintBackgrounds;
+}
+
+void Settings::setTextAreasAreResizable(bool textAreasAreResizable)
+{
+ if (m_textAreasAreResizable == textAreasAreResizable)
+ return;
+
+ m_textAreasAreResizable = textAreasAreResizable;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+void Settings::setEditableLinkBehavior(EditableLinkBehavior editableLinkBehavior)
+{
+ m_editableLinkBehavior = editableLinkBehavior;
+}
+
+void Settings::setTextDirectionSubmenuInclusionBehavior(TextDirectionSubmenuInclusionBehavior behavior)
+{
+ m_textDirectionSubmenuInclusionBehavior = behavior;
+}
+
+#if ENABLE(DASHBOARD_SUPPORT)
+void Settings::setUsesDashboardBackwardCompatibilityMode(bool usesDashboardBackwardCompatibilityMode)
+{
+ m_usesDashboardBackwardCompatibilityMode = usesDashboardBackwardCompatibilityMode;
+}
+#endif
+
+// FIXME: This quirk is needed because of Radar 4674537 and 5211271. We need to phase it out once Adobe
+// can fix the bug from their end.
+void Settings::setNeedsAdobeFrameReloadingQuirk(bool shouldNotReloadIFramesForUnchangedSRC)
+{
+ m_needsAdobeFrameReloadingQuirk = shouldNotReloadIFramesForUnchangedSRC;
+}
+
+// This is a quirk we are pro-actively applying to old applications. It changes keyboard event dispatching,
+// making keyIdentifier available on keypress events, making charCode available on keydown/keyup events,
+// and getting keypress dispatched in more cases.
+void Settings::setNeedsKeyboardEventDisambiguationQuirks(bool needsQuirks)
+{
+ m_needsKeyboardEventDisambiguationQuirks = needsQuirks;
+}
+
+void Settings::setTreatsAnyTextCSSLinkAsStylesheet(bool treatsAnyTextCSSLinkAsStylesheet)
+{
+ m_treatsAnyTextCSSLinkAsStylesheet = treatsAnyTextCSSLinkAsStylesheet;
+}
+
+void Settings::setNeedsLeopardMailQuirks(bool needsQuirks)
+{
+ m_needsLeopardMailQuirks = needsQuirks;
+}
+
+void Settings::setNeedsTigerMailQuirks(bool needsQuirks)
+{
+ m_needsTigerMailQuirks = needsQuirks;
+}
+
+void Settings::setDOMPasteAllowed(bool DOMPasteAllowed)
+{
+ m_isDOMPasteAllowed = DOMPasteAllowed;
+}
+
+void Settings::setMinDOMTimerInterval(double interval)
+{
+ DOMTimer::setMinTimerInterval(interval);
+}
+
+void Settings::setUsesPageCache(bool usesPageCache)
+{
+ if (m_usesPageCache == usesPageCache)
+ return;
+
+ m_usesPageCache = usesPageCache;
+ if (!m_usesPageCache) {
+ int first = -m_page->backForward()->backCount();
+ int last = m_page->backForward()->forwardCount();
+ for (int i = first; i <= last; i++)
+ pageCache()->remove(m_page->backForward()->itemAtIndex(i));
+ pageCache()->releaseAutoreleasedPagesNow();
+ }
+}
+
+void Settings::setShrinksStandaloneImagesToFit(bool shrinksStandaloneImagesToFit)
+{
+ m_shrinksStandaloneImagesToFit = shrinksStandaloneImagesToFit;
+}
+
+void Settings::setShowsURLsInToolTips(bool showsURLsInToolTips)
+{
+ m_showsURLsInToolTips = showsURLsInToolTips;
+}
+
+void Settings::setFTPDirectoryTemplatePath(const String& path)
+{
+ m_ftpDirectoryTemplatePath = path;
+}
+
+void Settings::setForceFTPDirectoryListings(bool force)
+{
+ m_forceFTPDirectoryListings = force;
+}
+
+void Settings::setDeveloperExtrasEnabled(bool developerExtrasEnabled)
+{
+ m_developerExtrasEnabled = developerExtrasEnabled;
+}
+
+#ifdef ANDROID_META_SUPPORT
+void Settings::resetMetadataSettings()
+{
+ m_viewport_width = -1;
+ m_viewport_height = -1;
+ m_viewport_initial_scale = 0;
+ m_viewport_minimum_scale = 0;
+ m_viewport_maximum_scale = 0;
+ m_viewport_user_scalable = true;
+ m_viewport_target_densitydpi = -1;
+ m_format_detection_telephone = m_default_format_detection;
+ m_format_detection_address = m_default_format_detection;
+ m_format_detection_email = m_default_format_detection;
+}
+
+void Settings::setMetadataSettings(const String& key, const String& value)
+{
+ if (key == "width") {
+ if (value == "device-width") {
+ m_viewport_width = 0;
+ } else {
+ int width = value.toInt();
+ if (width <= 10000) {
+ if (width <= 320) {
+ // This is a hack to accommodate the pages designed for the
+ // original iPhone. The new version, since 10/2007, is to
+ // use device-width which works for both portrait and
+ // landscape modes.
+ m_viewport_width = 0;
+ } else {
+ m_viewport_width = width;
+ }
+ }
+ }
+ } else if (key == "height") {
+ if (value == "device-height") {
+ m_viewport_height = 0;
+ } else {
+ int height = value.toInt();
+ if (height >= 200 && height <= 10000) {
+ m_viewport_height = height;
+ }
+ }
+ } else if (key == "initial-scale") {
+ int scale = int(value.toFloat() * 100);
+ if (scale >= 1 && scale <= 1000) {
+ m_viewport_initial_scale = scale;
+ }
+ } else if (key == "minimum-scale") {
+ int scale = int(value.toFloat() * 100);
+ if (scale >= 1 && scale <= 1000) {
+ m_viewport_minimum_scale = scale;
+ }
+ } else if (key == "maximum-scale") {
+ int scale = int(value.toFloat() * 100);
+ if (scale >= 1 && scale <= 1000) {
+ m_viewport_maximum_scale = scale;
+ }
+ } else if (key == "user-scalable") {
+ // even Apple doc says using "no", "0" is common in the real world, and
+ // some sites, e.g. gomoviesapp.com, use "false".
+ if (value == "no" || value == "0" || value == "false") {
+ m_viewport_user_scalable = false;
+ }
+ } else if (key == "target-densitydpi") {
+ if (value == "device-dpi") {
+ m_viewport_target_densitydpi = 0;
+ } else if (value == "low-dpi") {
+ m_viewport_target_densitydpi = 120;
+ } else if (value == "medium-dpi") {
+ m_viewport_target_densitydpi = 160;
+ } else if (value == "high-dpi") {
+ m_viewport_target_densitydpi = 240;
+ } else {
+ int dpi = value.toInt();
+ if (dpi >= 70 && dpi <= 400) {
+ m_viewport_target_densitydpi = dpi;
+ }
+ }
+ } else if (key == "telephone") {
+ if (value == "no") {
+ m_format_detection_telephone = false;
+ }
+ } else if (key == "address") {
+ if (value == "no") {
+ m_format_detection_address = false;
+ }
+ } else if (key == "email") {
+ if (value == "no") {
+ m_format_detection_email = false;
+ }
+ } else if (key == "format-detection") {
+ // even Apple doc says "format-detection" should be the name of the
+ // <meta> tag. In the real world, e.g. amazon.com, use
+ // "format-detection=no" in the "viewport" <meta> tag to disable all
+ // format detection.
+ if (value == "no") {
+ m_format_detection_telephone = false;
+ m_format_detection_address = false;
+ m_format_detection_email = false;
+ }
+ }
+}
+
+void Settings::setViewportWidth(int width)
+{
+ if (width < 0 || width > 10000)
+ m_viewport_width = -1;
+ else
+ m_viewport_width = width;
+}
+
+void Settings::setViewportHeight(int height)
+{
+ if (height < 0 || height > 10000)
+ m_viewport_height = -1;
+ else
+ m_viewport_height = height;
+}
+
+void Settings::setViewportInitialScale(int scale)
+{
+ if (scale < 1 || scale > 1000)
+ m_viewport_initial_scale = 0;
+ else
+ m_viewport_initial_scale = scale;
+}
+
+void Settings::setViewportMinimumScale(int scale)
+{
+ if (scale < 1 || scale > 1000)
+ m_viewport_minimum_scale = 0;
+ else
+ m_viewport_minimum_scale = scale;
+}
+
+void Settings::setViewportMaximumScale(int scale)
+{
+ if (scale < 1 || scale > 1000)
+ m_viewport_maximum_scale = 0;
+ else
+ m_viewport_maximum_scale = scale;
+}
+
+void Settings::setViewportUserScalable(bool scalable)
+{
+ m_viewport_user_scalable = scalable;
+}
+
+void Settings::setViewportTargetDensityDpi(int dpi)
+{
+ if (dpi < 0 || dpi > 400)
+ m_viewport_target_densitydpi = -1;
+ else
+ m_viewport_target_densitydpi = dpi;
+}
+
+void Settings::setFormatDetectionAddress(bool detect)
+{
+ m_format_detection_address = detect;
+}
+
+void Settings::setFormatDetectionEmail(bool detect)
+{
+ m_format_detection_email = detect;
+}
+
+void Settings::setFormatDetectionTelephone(bool detect)
+{
+ m_format_detection_telephone = detect;
+}
+#endif
+
+void Settings::setAuthorAndUserStylesEnabled(bool authorAndUserStylesEnabled)
+{
+ if (m_authorAndUserStylesEnabled == authorAndUserStylesEnabled)
+ return;
+
+ m_authorAndUserStylesEnabled = authorAndUserStylesEnabled;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+void Settings::setFontRenderingMode(FontRenderingMode mode)
+{
+ if (fontRenderingMode() == mode)
+ return;
+ m_fontRenderingMode = mode;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+FontRenderingMode Settings::fontRenderingMode() const
+{
+ return static_cast<FontRenderingMode>(m_fontRenderingMode);
+}
+
+void Settings::setNeedsSiteSpecificQuirks(bool needsQuirks)
+{
+ m_needsSiteSpecificQuirks = needsQuirks;
+}
+
+void Settings::setFrameFlatteningEnabled(bool frameFlatteningEnabled)
+{
+ m_frameFlatteningEnabled = frameFlatteningEnabled;
+}
+
+void Settings::setWebArchiveDebugModeEnabled(bool enabled)
+{
+ m_webArchiveDebugModeEnabled = enabled;
+}
+
+void Settings::setLocalFileContentSniffingEnabled(bool enabled)
+{
+ m_localFileContentSniffingEnabled = enabled;
+}
+
+void Settings::setLocalStorageDatabasePath(const String& path)
+{
+ m_localStorageDatabasePath = path;
+}
+
+void Settings::setApplicationChromeMode(bool mode)
+{
+ m_inApplicationChromeMode = mode;
+}
+
+void Settings::setOfflineWebApplicationCacheEnabled(bool enabled)
+{
+ m_offlineWebApplicationCacheEnabled = enabled;
+}
+
+void Settings::setShouldPaintCustomScrollbars(bool shouldPaintCustomScrollbars)
+{
+ m_shouldPaintCustomScrollbars = shouldPaintCustomScrollbars;
+}
+
+void Settings::setEnforceCSSMIMETypeInNoQuirksMode(bool enforceCSSMIMETypeInNoQuirksMode)
+{
+ m_enforceCSSMIMETypeInNoQuirksMode = enforceCSSMIMETypeInNoQuirksMode;
+}
+
+#if USE(SAFARI_THEME)
+void Settings::setShouldPaintNativeControls(bool shouldPaintNativeControls)
+{
+ gShouldPaintNativeControls = shouldPaintNativeControls;
+}
+#endif
+
+void Settings::setUsesEncodingDetector(bool usesEncodingDetector)
+{
+ m_usesEncodingDetector = usesEncodingDetector;
+}
+
+void Settings::setDNSPrefetchingEnabled(bool dnsPrefetchingEnabled)
+{
+ if (m_dnsPrefetchingEnabled == dnsPrefetchingEnabled)
+ return;
+
+ m_dnsPrefetchingEnabled = dnsPrefetchingEnabled;
+ m_page->dnsPrefetchingStateChanged();
+}
+
+void Settings::setAllowScriptsToCloseWindows(bool allowScriptsToCloseWindows)
+{
+ m_allowScriptsToCloseWindows = allowScriptsToCloseWindows;
+}
+
+void Settings::setCaretBrowsingEnabled(bool caretBrowsingEnabled)
+{
+ m_caretBrowsingEnabled = caretBrowsingEnabled;
+}
+
+void Settings::setDownloadableBinaryFontsEnabled(bool downloadableBinaryFontsEnabled)
+{
+ m_downloadableBinaryFontsEnabled = downloadableBinaryFontsEnabled;
+}
+
+void Settings::setXSSAuditorEnabled(bool xssAuditorEnabled)
+{
+ m_xssAuditorEnabled = xssAuditorEnabled;
+}
+
+void Settings::setAcceleratedCompositingEnabled(bool enabled)
+{
+ if (m_acceleratedCompositingEnabled == enabled)
+ return;
+
+ m_acceleratedCompositingEnabled = 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)
+ return;
+
+ m_showDebugBorders = enabled;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+void Settings::setShowRepaintCounter(bool enabled)
+{
+ if (m_showRepaintCounter == enabled)
+ return;
+
+ m_showRepaintCounter = enabled;
+ setNeedsRecalcStyleInAllFrames(m_page);
+}
+
+void Settings::setExperimentalNotificationsEnabled(bool enabled)
+{
+ m_experimentalNotificationsEnabled = enabled;
+}
+
+void Settings::setPluginAllowedRunTime(unsigned runTime)
+{
+ m_pluginAllowedRunTime = runTime;
+ m_page->pluginAllowedRunTimeChanged();
+}
+
+#if PLATFORM(WIN) || (OS(WINDOWS) && PLATFORM(WX))
+void Settings::setShouldUseHighResolutionTimers(bool shouldUseHighResolutionTimers)
+{
+ gShouldUseHighResolutionTimers = shouldUseHighResolutionTimers;
+}
+#endif
+
+void Settings::setWebGLEnabled(bool enabled)
+{
+ m_webGLEnabled = enabled;
+}
+
+void Settings::setAccelerated2dCanvasEnabled(bool enabled)
+{
+ m_acceleratedCanvas2dEnabled = enabled;
+}
+
+void Settings::setLoadDeferringEnabled(bool enabled)
+{
+ m_loadDeferringEnabled = enabled;
+}
+
+void Settings::setTiledBackingStoreEnabled(bool enabled)
+{
+ m_tiledBackingStoreEnabled = enabled;
+#if ENABLE(TILED_BACKING_STORE)
+ if (m_page->mainFrame())
+ m_page->mainFrame()->setTiledBackingStoreEnabled(enabled);
+#endif
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/Settings.h b/Source/WebCore/page/Settings.h
new file mode 100644
index 0000000..f6b2e2d
--- /dev/null
+++ b/Source/WebCore/page/Settings.h
@@ -0,0 +1,579 @@
+/*
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Settings_h
+#define Settings_h
+
+#include "EditingBehaviorTypes.h"
+#include "FontRenderingMode.h"
+#include "KURL.h"
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+ class Page;
+
+ enum EditableLinkBehavior {
+ EditableLinkDefaultBehavior,
+ EditableLinkAlwaysLive,
+ EditableLinkOnlyLiveWithShiftKey,
+ EditableLinkLiveWhenNotFocused,
+ EditableLinkNeverLive
+ };
+
+ enum TextDirectionSubmenuInclusionBehavior {
+ TextDirectionSubmenuNeverIncluded,
+ TextDirectionSubmenuAutomaticallyIncluded,
+ TextDirectionSubmenuAlwaysIncluded
+ };
+
+ class Settings : public Noncopyable {
+ public:
+ Settings(Page*);
+
+#ifdef ANDROID_LAYOUT
+ // FIXME: How do we determine the margins other than guessing?
+ #define ANDROID_SSR_MARGIN_PADDING 3
+ #define ANDROID_FCTS_MARGIN_PADDING 10
+
+ enum LayoutAlgorithm {
+ kLayoutNormal,
+ kLayoutSSR,
+ kLayoutFitColumnToScreen
+ };
+#endif
+ void setStandardFontFamily(const AtomicString&);
+ const AtomicString& standardFontFamily() const { return m_standardFontFamily; }
+
+ void setFixedFontFamily(const AtomicString&);
+ const AtomicString& fixedFontFamily() const { return m_fixedFontFamily; }
+
+#ifdef ANDROID_LAYOUT
+ LayoutAlgorithm layoutAlgorithm() const { return m_layoutAlgorithm; }
+ void setLayoutAlgorithm(LayoutAlgorithm algorithm) { m_layoutAlgorithm = algorithm; }
+
+ bool useWideViewport() const { return m_useWideViewport; }
+ void setUseWideViewport(bool use) { m_useWideViewport = use; }
+#endif
+
+ void setSerifFontFamily(const AtomicString&);
+ const AtomicString& serifFontFamily() const { return m_serifFontFamily; }
+
+ void setSansSerifFontFamily(const AtomicString&);
+ const AtomicString& sansSerifFontFamily() const { return m_sansSerifFontFamily; }
+
+ void setCursiveFontFamily(const AtomicString&);
+ const AtomicString& cursiveFontFamily() const { return m_cursiveFontFamily; }
+
+ void setFantasyFontFamily(const AtomicString&);
+ const AtomicString& fantasyFontFamily() const { return m_fantasyFontFamily; }
+
+ void setMinimumFontSize(int);
+ int minimumFontSize() const { return m_minimumFontSize; }
+
+ void setMinimumLogicalFontSize(int);
+ int minimumLogicalFontSize() const { return m_minimumLogicalFontSize; }
+
+ void setDefaultFontSize(int);
+ int defaultFontSize() const { return m_defaultFontSize; }
+
+ void setDefaultFixedFontSize(int);
+ int defaultFixedFontSize() const { return m_defaultFixedFontSize; }
+
+ // Unlike areImagesEnabled, this only suppresses the network load of
+ // the image URL. A cached image will still be rendered if requested.
+ void setLoadsImagesAutomatically(bool);
+ bool loadsImagesAutomatically() const { return m_loadsImagesAutomatically; }
+
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+ void setBlockNetworkImage(bool);
+ bool blockNetworkImage() const { return m_blockNetworkImage; }
+#endif
+ void setJavaScriptEnabled(bool);
+ // Instead of calling isJavaScriptEnabled directly, please consider calling
+ // ScriptController::canExecuteScripts, which takes things like the
+ // HTML sandbox attribute into account.
+ bool isJavaScriptEnabled() const { return m_isJavaScriptEnabled; }
+
+ void setWebSecurityEnabled(bool);
+ bool isWebSecurityEnabled() const { return m_isWebSecurityEnabled; }
+
+ void setAllowUniversalAccessFromFileURLs(bool);
+ bool allowUniversalAccessFromFileURLs() const { return m_allowUniversalAccessFromFileURLs; }
+
+ void setAllowFileAccessFromFileURLs(bool);
+ bool allowFileAccessFromFileURLs() const { return m_allowFileAccessFromFileURLs; }
+
+ void setJavaScriptCanOpenWindowsAutomatically(bool);
+ bool javaScriptCanOpenWindowsAutomatically() const { return m_javaScriptCanOpenWindowsAutomatically; }
+
+ void setJavaScriptCanAccessClipboard(bool);
+ bool javaScriptCanAccessClipboard() const { return m_javaScriptCanAccessClipboard; }
+
+ void setSpatialNavigationEnabled(bool);
+ bool isSpatialNavigationEnabled() const { return m_isSpatialNavigationEnabled; }
+
+ void setJavaEnabled(bool);
+ bool isJavaEnabled() const { return m_isJavaEnabled; }
+
+ void setImagesEnabled(bool);
+ bool areImagesEnabled() const { return m_areImagesEnabled; }
+
+ void setMediaEnabled(bool);
+ bool isMediaEnabled() const { return m_isMediaEnabled; }
+
+ void setPluginsEnabled(bool);
+ bool arePluginsEnabled() const { return m_arePluginsEnabled; }
+
+#ifdef ANDROID_PLUGINS
+ void setPluginsOnDemand(bool onDemand) { m_pluginsOnDemand = onDemand; }
+ bool arePluginsOnDemand() const { return m_pluginsOnDemand; }
+#endif
+
+ void setLocalStorageEnabled(bool);
+ bool localStorageEnabled() const { return m_localStorageEnabled; }
+
+#if ENABLE(DOM_STORAGE)
+ // Allow clients concerned with memory consumption to set a quota on session storage
+ // since the memory used won't be released until the Page is destroyed.
+ // Default is noQuota.
+ void setSessionStorageQuota(unsigned);
+ unsigned sessionStorageQuota() const { return m_sessionStorageQuota; }
+#endif
+
+ // When this option is set, WebCore will avoid storing any record of browsing activity
+ // that may persist on disk or remain displayed when the option is reset.
+ // This option does not affect the storage of such information in RAM.
+ // The following functions respect this setting:
+ // - HTML5/DOM Storage
+ // - Icon Database
+ // - Console Messages
+ // - MemoryCache
+ // - Application Cache
+ // - Back/Forward Page History
+ // - Page Search Results
+ // - HTTP Cookies
+ // - Plug-ins (that support NPNVprivateModeBool)
+ void setPrivateBrowsingEnabled(bool);
+ bool privateBrowsingEnabled() const { return m_privateBrowsingEnabled; }
+
+ void setCaretBrowsingEnabled(bool);
+ bool caretBrowsingEnabled() const { return m_caretBrowsingEnabled; }
+
+ void setDefaultTextEncodingName(const String&);
+ const String& defaultTextEncodingName() const { return m_defaultTextEncodingName; }
+
+ void setUsesEncodingDetector(bool);
+ bool usesEncodingDetector() const { return m_usesEncodingDetector; }
+
+ void setDNSPrefetchingEnabled(bool);
+ bool dnsPrefetchingEnabled() const { return m_dnsPrefetchingEnabled; }
+
+ void setUserStyleSheetLocation(const KURL&);
+ const KURL& userStyleSheetLocation() const { return m_userStyleSheetLocation; }
+
+ void setShouldPrintBackgrounds(bool);
+ bool shouldPrintBackgrounds() const { return m_shouldPrintBackgrounds; }
+
+ void setTextAreasAreResizable(bool);
+ bool textAreasAreResizable() const { return m_textAreasAreResizable; }
+
+ void setEditableLinkBehavior(EditableLinkBehavior);
+ EditableLinkBehavior editableLinkBehavior() const { return m_editableLinkBehavior; }
+
+ void setTextDirectionSubmenuInclusionBehavior(TextDirectionSubmenuInclusionBehavior);
+ TextDirectionSubmenuInclusionBehavior textDirectionSubmenuInclusionBehavior() const { return m_textDirectionSubmenuInclusionBehavior; }
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ void setUsesDashboardBackwardCompatibilityMode(bool);
+ bool usesDashboardBackwardCompatibilityMode() const { return m_usesDashboardBackwardCompatibilityMode; }
+#endif
+
+ void setNeedsAdobeFrameReloadingQuirk(bool);
+ bool needsAcrobatFrameReloadingQuirk() const { return m_needsAdobeFrameReloadingQuirk; }
+
+ void setNeedsKeyboardEventDisambiguationQuirks(bool);
+ bool needsKeyboardEventDisambiguationQuirks() const { return m_needsKeyboardEventDisambiguationQuirks; }
+
+ void setTreatsAnyTextCSSLinkAsStylesheet(bool);
+ bool treatsAnyTextCSSLinkAsStylesheet() const { return m_treatsAnyTextCSSLinkAsStylesheet; }
+
+ void setNeedsLeopardMailQuirks(bool);
+ bool needsLeopardMailQuirks() const { return m_needsLeopardMailQuirks; }
+
+ void setNeedsTigerMailQuirks(bool);
+ bool needsTigerMailQuirks() const { return m_needsTigerMailQuirks; }
+
+ void setDOMPasteAllowed(bool);
+ bool isDOMPasteAllowed() const { return m_isDOMPasteAllowed; }
+
+ static void setMinDOMTimerInterval(double); // Interval specified in seconds.
+
+ void setUsesPageCache(bool);
+ bool usesPageCache() const { return m_usesPageCache; }
+
+ void setShrinksStandaloneImagesToFit(bool);
+ bool shrinksStandaloneImagesToFit() const { return m_shrinksStandaloneImagesToFit; }
+
+ void setShowsURLsInToolTips(bool);
+ bool showsURLsInToolTips() const { return m_showsURLsInToolTips; }
+
+ void setFTPDirectoryTemplatePath(const String&);
+ const String& ftpDirectoryTemplatePath() const { return m_ftpDirectoryTemplatePath; }
+
+ void setForceFTPDirectoryListings(bool);
+ bool forceFTPDirectoryListings() const { return m_forceFTPDirectoryListings; }
+
+ void setDeveloperExtrasEnabled(bool);
+ bool developerExtrasEnabled() const { return m_developerExtrasEnabled; }
+
+ void setFrameFlatteningEnabled(bool);
+ bool frameFlatteningEnabled() const { return m_frameFlatteningEnabled; }
+
+#ifdef ANDROID_META_SUPPORT
+ void resetMetadataSettings();
+ void setMetadataSettings(const String& key, const String& value);
+
+ void setViewportWidth(int);
+ int viewportWidth() const { return m_viewport_width; }
+
+ void setViewportHeight(int);
+ int viewportHeight() const { return m_viewport_height; }
+
+ void setViewportInitialScale(int);
+ int viewportInitialScale() const { return m_viewport_initial_scale; }
+
+ void setViewportMinimumScale(int);
+ int viewportMinimumScale() const { return m_viewport_minimum_scale; }
+
+ void setViewportMaximumScale(int);
+ int viewportMaximumScale() const { return m_viewport_maximum_scale; }
+
+ void setViewportUserScalable(bool);
+ bool viewportUserScalable() const { return m_viewport_user_scalable; }
+
+ void setViewportTargetDensityDpi(int);
+ int viewportTargetDensityDpi() const { return m_viewport_target_densitydpi; }
+
+ void setFormatDetectionAddress(bool);
+ bool formatDetectionAddress() const { return m_format_detection_address; }
+
+ void setFormatDetectionEmail(bool);
+ bool formatDetectionEmail() const { return m_format_detection_email; }
+
+ void setFormatDetectionTelephone(bool);
+ bool formatDetectionTelephone() const { return m_format_detection_telephone; }
+
+ void setDefaultFormatDetection(bool flag) { m_default_format_detection = flag; }
+#endif
+#ifdef ANDROID_MULTIPLE_WINDOWS
+ bool supportMultipleWindows() const { return m_supportMultipleWindows; }
+ void setSupportMultipleWindows(bool support) { m_supportMultipleWindows = support; }
+#endif
+ void setAuthorAndUserStylesEnabled(bool);
+ bool authorAndUserStylesEnabled() const { return m_authorAndUserStylesEnabled; }
+
+ void setFontRenderingMode(FontRenderingMode mode);
+ FontRenderingMode fontRenderingMode() const;
+
+ void setNeedsSiteSpecificQuirks(bool);
+ bool needsSiteSpecificQuirks() const { return m_needsSiteSpecificQuirks; }
+
+ void setWebArchiveDebugModeEnabled(bool);
+ bool webArchiveDebugModeEnabled() const { return m_webArchiveDebugModeEnabled; }
+
+ void setLocalFileContentSniffingEnabled(bool);
+ bool localFileContentSniffingEnabled() const { return m_localFileContentSniffingEnabled; }
+
+ void setLocalStorageDatabasePath(const String&);
+ const String& localStorageDatabasePath() const { return m_localStorageDatabasePath; }
+
+ void setApplicationChromeMode(bool);
+ bool inApplicationChromeMode() const { return m_inApplicationChromeMode; }
+
+ void setOfflineWebApplicationCacheEnabled(bool);
+ bool offlineWebApplicationCacheEnabled() const { return m_offlineWebApplicationCacheEnabled; }
+
+ void setShouldPaintCustomScrollbars(bool);
+ bool shouldPaintCustomScrollbars() const { return m_shouldPaintCustomScrollbars; }
+
+ void setEnforceCSSMIMETypeInNoQuirksMode(bool);
+ bool enforceCSSMIMETypeInNoQuirksMode() { return m_enforceCSSMIMETypeInNoQuirksMode; }
+
+ void setMaximumDecodedImageSize(size_t size) { m_maximumDecodedImageSize = size; }
+ size_t maximumDecodedImageSize() const { return m_maximumDecodedImageSize; }
+
+#if USE(SAFARI_THEME)
+ // Windows debugging pref (global) for switching between the Aqua look and a native windows look.
+ static void setShouldPaintNativeControls(bool);
+ static bool shouldPaintNativeControls() { return gShouldPaintNativeControls; }
+#endif
+
+ void setAllowScriptsToCloseWindows(bool);
+ bool allowScriptsToCloseWindows() const { return m_allowScriptsToCloseWindows; }
+
+ void setEditingBehaviorType(EditingBehaviorType behavior) { m_editingBehaviorType = behavior; }
+ EditingBehaviorType editingBehaviorType() const { return static_cast<EditingBehaviorType>(m_editingBehaviorType); }
+
+ void setDownloadableBinaryFontsEnabled(bool);
+ bool downloadableBinaryFontsEnabled() const { return m_downloadableBinaryFontsEnabled; }
+
+ void setXSSAuditorEnabled(bool);
+ bool xssAuditorEnabled() const { return m_xssAuditorEnabled; }
+
+ 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; }
+
+ void setShowRepaintCounter(bool);
+ bool showRepaintCounter() const { return m_showRepaintCounter; }
+
+ void setExperimentalNotificationsEnabled(bool);
+ bool experimentalNotificationsEnabled() const { return m_experimentalNotificationsEnabled; }
+
+#if PLATFORM(WIN) || (OS(WINDOWS) && PLATFORM(WX))
+ static void setShouldUseHighResolutionTimers(bool);
+ static bool shouldUseHighResolutionTimers() { return gShouldUseHighResolutionTimers; }
+#endif
+
+ void setPluginAllowedRunTime(unsigned);
+ unsigned pluginAllowedRunTime() const { return m_pluginAllowedRunTime; }
+
+ void setWebGLEnabled(bool);
+ bool webGLEnabled() const { return m_webGLEnabled; }
+
+ void setAccelerated2dCanvasEnabled(bool);
+ bool accelerated2dCanvasEnabled() const { return m_acceleratedCanvas2dEnabled; }
+
+ void setLoadDeferringEnabled(bool);
+ bool loadDeferringEnabled() const { return m_loadDeferringEnabled; }
+
+ void setTiledBackingStoreEnabled(bool);
+ bool tiledBackingStoreEnabled() const { return m_tiledBackingStoreEnabled; }
+
+ void setPaginateDuringLayoutEnabled(bool flag) { m_paginateDuringLayoutEnabled = flag; }
+ bool paginateDuringLayoutEnabled() const { return m_paginateDuringLayoutEnabled; }
+
+#if ENABLE(FULLSCREEN_API)
+ void setFullScreenEnabled(bool flag) { m_fullScreenAPIEnabled = flag; }
+ bool fullScreenEnabled() const { return m_fullScreenAPIEnabled; }
+#endif
+
+ void setAsynchronousSpellCheckingEnabled(bool flag) { m_asynchronousSpellCheckingEnabled = flag; }
+ bool asynchronousSpellCheckingEnabled() const { return m_asynchronousSpellCheckingEnabled; }
+
+ void setMemoryInfoEnabled(bool flag) { m_memoryInfoEnabled = flag; }
+ bool memoryInfoEnabled() const { return m_memoryInfoEnabled; }
+
+ // This setting will be removed when an HTML5 compatibility issue is
+ // resolved and WebKit implementation of interactive validation is
+ // completed. See http://webkit.org/b/40520, http://webkit.org/b/40747,
+ // and http://webkit.org/b/40908
+ void setInteractiveFormValidationEnabled(bool flag) { m_interactiveFormValidation = flag; }
+ bool interactiveFormValidationEnabled() const { return m_interactiveFormValidation; }
+
+ void setUsePreHTML5ParserQuirks(bool flag) { m_usePreHTML5ParserQuirks = flag; }
+ bool usePreHTML5ParserQuirks() const { return m_usePreHTML5ParserQuirks; }
+
+ void setHyperlinkAuditingEnabled(bool flag) { m_hyperlinkAuditingEnabled = flag; }
+ bool hyperlinkAuditingEnabled() const { return m_hyperlinkAuditingEnabled; }
+
+ void setCrossOriginCheckInGetMatchedCSSRulesDisabled(bool flag) { m_crossOriginCheckInGetMatchedCSSRulesDisabled = flag; }
+ bool crossOriginCheckInGetMatchedCSSRulesDisabled() const { return m_crossOriginCheckInGetMatchedCSSRulesDisabled; }
+
+#if ENABLE(WEB_AUTOFILL)
+ void setAutoFillEnabled(bool flag) { m_autoFillEnabled = flag; }
+ bool autoFillEnabled() { return m_autoFillEnabled; }
+#endif
+
+ private:
+ Page* m_page;
+
+ String m_defaultTextEncodingName;
+ String m_ftpDirectoryTemplatePath;
+ String m_localStorageDatabasePath;
+ KURL m_userStyleSheetLocation;
+ AtomicString m_standardFontFamily;
+ AtomicString m_fixedFontFamily;
+ AtomicString m_serifFontFamily;
+ AtomicString m_sansSerifFontFamily;
+ AtomicString m_cursiveFontFamily;
+ AtomicString m_fantasyFontFamily;
+#ifdef ANDROID_LAYOUT
+ LayoutAlgorithm m_layoutAlgorithm;
+#endif
+ EditableLinkBehavior m_editableLinkBehavior;
+ TextDirectionSubmenuInclusionBehavior m_textDirectionSubmenuInclusionBehavior;
+ int m_minimumFontSize;
+ int m_minimumLogicalFontSize;
+ int m_defaultFontSize;
+ int m_defaultFixedFontSize;
+#ifdef ANDROID_META_SUPPORT
+ // range is from 200 to 10,000. 0 is a special value means device-width.
+ // default is -1, which means undefined.
+ int m_viewport_width;
+ // range is from 223 to 10,000. 0 is a special value means device-height
+ // default is -1, which means undefined.
+ int m_viewport_height;
+ // range is from 1 to 1000 in percent. default is 0, which means undefined.
+ int m_viewport_initial_scale;
+ // range is from 1 to 1000 in percent. default is 0, which means undefined.
+ int m_viewport_minimum_scale;
+ // range is from 1 to 1000 in percent. default is 0, which means undefined.
+ int m_viewport_maximum_scale;
+ // default is yes
+ bool m_viewport_user_scalable : 1;
+ // range is from 70 to 400. 0 is a special value means device-dpi
+ // default is -1, which means undefined.
+ int m_viewport_target_densitydpi;
+ // default is yes
+ bool m_format_detection_telephone : 1;
+ // default is yes
+ bool m_format_detection_address : 1;
+ // default is yes
+ bool m_format_detection_email : 1;
+ bool m_default_format_detection : 1;
+#endif
+#ifdef ANDROID_LAYOUT
+ bool m_useWideViewport : 1;
+#endif
+#ifdef ANDROID_MULTIPLE_WINDOWS
+ bool m_supportMultipleWindows : 1;
+#endif
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+ bool m_blockNetworkImage : 1;
+#endif
+ size_t m_maximumDecodedImageSize;
+#if ENABLE(DOM_STORAGE)
+ unsigned m_sessionStorageQuota;
+#endif
+ unsigned m_pluginAllowedRunTime;
+ unsigned m_editingBehaviorType;
+ bool m_isSpatialNavigationEnabled : 1;
+ bool m_isJavaEnabled : 1;
+ bool m_loadsImagesAutomatically : 1;
+ bool m_privateBrowsingEnabled : 1;
+ bool m_caretBrowsingEnabled : 1;
+ bool m_areImagesEnabled : 1;
+ bool m_isMediaEnabled : 1;
+ bool m_arePluginsEnabled : 1;
+ bool m_localStorageEnabled : 1;
+ bool m_isJavaScriptEnabled : 1;
+ bool m_isWebSecurityEnabled : 1;
+ bool m_allowUniversalAccessFromFileURLs: 1;
+ bool m_allowFileAccessFromFileURLs: 1;
+ bool m_javaScriptCanOpenWindowsAutomatically : 1;
+ bool m_javaScriptCanAccessClipboard : 1;
+ bool m_shouldPrintBackgrounds : 1;
+ bool m_textAreasAreResizable : 1;
+#if ENABLE(DASHBOARD_SUPPORT)
+ bool m_usesDashboardBackwardCompatibilityMode : 1;
+#endif
+ bool m_needsAdobeFrameReloadingQuirk : 1;
+ bool m_needsKeyboardEventDisambiguationQuirks : 1;
+ bool m_treatsAnyTextCSSLinkAsStylesheet : 1;
+ bool m_needsLeopardMailQuirks : 1;
+ bool m_needsTigerMailQuirks : 1;
+ bool m_isDOMPasteAllowed : 1;
+ bool m_shrinksStandaloneImagesToFit : 1;
+ bool m_usesPageCache: 1;
+ bool m_showsURLsInToolTips : 1;
+ bool m_forceFTPDirectoryListings : 1;
+ bool m_developerExtrasEnabled : 1;
+ bool m_authorAndUserStylesEnabled : 1;
+ bool m_needsSiteSpecificQuirks : 1;
+ unsigned m_fontRenderingMode : 1;
+ bool m_frameFlatteningEnabled : 1;
+ bool m_webArchiveDebugModeEnabled : 1;
+ bool m_localFileContentSniffingEnabled : 1;
+ bool m_inApplicationChromeMode : 1;
+ bool m_offlineWebApplicationCacheEnabled : 1;
+ bool m_shouldPaintCustomScrollbars : 1;
+ bool m_enforceCSSMIMETypeInNoQuirksMode : 1;
+ bool m_usesEncodingDetector : 1;
+ bool m_allowScriptsToCloseWindows : 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;
+ bool m_webGLEnabled : 1;
+ bool m_acceleratedCanvas2dEnabled : 1;
+ bool m_loadDeferringEnabled : 1;
+ bool m_tiledBackingStoreEnabled : 1;
+ bool m_paginateDuringLayoutEnabled : 1;
+ bool m_dnsPrefetchingEnabled : 1;
+#if ENABLE(FULLSCREEN_API)
+ bool m_fullScreenAPIEnabled : 1;
+#endif
+ bool m_asynchronousSpellCheckingEnabled: 1;
+ bool m_memoryInfoEnabled: 1;
+ bool m_interactiveFormValidation: 1;
+ bool m_usePreHTML5ParserQuirks: 1;
+ bool m_hyperlinkAuditingEnabled : 1;
+ bool m_crossOriginCheckInGetMatchedCSSRulesDisabled : 1;
+
+#if ENABLE(WEB_AUTOFILL)
+ bool m_autoFillEnabled: 1;
+#endif
+#ifdef ANDROID_PLUGINS
+ bool m_pluginsOnDemand : 1;
+#endif
+
+#if USE(SAFARI_THEME)
+ static bool gShouldPaintNativeControls;
+#endif
+#if PLATFORM(WIN) || (OS(WINDOWS) && PLATFORM(WX))
+ static bool gShouldUseHighResolutionTimers;
+#endif
+ };
+
+} // namespace WebCore
+
+#endif // Settings_h
diff --git a/Source/WebCore/page/SpatialNavigation.cpp b/Source/WebCore/page/SpatialNavigation.cpp
new file mode 100644
index 0000000..7d8ede3
--- /dev/null
+++ b/Source/WebCore/page/SpatialNavigation.cpp
@@ -0,0 +1,713 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Antonio Gomes <tonikitoo@webkit.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SpatialNavigation.h"
+
+#include "Frame.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "HTMLAreaElement.h"
+#include "HTMLImageElement.h"
+#include "HTMLMapElement.h"
+#include "HTMLNames.h"
+#include "IntRect.h"
+#include "Node.h"
+#include "Page.h"
+#include "RenderLayer.h"
+#include "Settings.h"
+
+namespace WebCore {
+
+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 IntRect rectToAbsoluteCoordinates(Frame* initialFrame, const IntRect&);
+static void entryAndExitPointsForDirection(FocusDirection direction, const IntRect& startingRect, const IntRect& potentialRect, IntPoint& exitPoint, IntPoint& entryPoint);
+static bool isScrollableNode(const Node*);
+
+FocusCandidate::FocusCandidate(Node* node, FocusDirection direction)
+ : visibleNode(0)
+ , focusableNode(0)
+ , enclosingScrollableBox(0)
+ , distance(maxDistance())
+ , parentDistance(maxDistance())
+ , alignment(None)
+ , parentAlignment(None)
+ , isOffscreen(true)
+ , isOffscreenAfterScrolling(true)
+{
+ ASSERT(node);
+ ASSERT(node->isElementNode());
+
+ if (node->hasTagName(HTMLNames::areaTag)) {
+ HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node);
+ HTMLImageElement* image = area->imageElement();
+ if (!image || !image->renderer())
+ return;
+
+ visibleNode = image;
+ rect = virtualRectForAreaElementAndDirection(area, direction);
+ } else {
+ if (!node->renderer())
+ return;
+
+ visibleNode = node;
+ rect = nodeRectInAbsoluteCoordinates(node, true /* ignore border */);
+ }
+
+ focusableNode = node;
+ isOffscreen = hasOffscreenRect(visibleNode);
+ isOffscreenAfterScrolling = hasOffscreenRect(visibleNode, direction);
+}
+
+bool isSpatialNavigationEnabled(const Frame* frame)
+{
+ return (frame && frame->settings() && frame->settings()->isSpatialNavigationEnabled());
+}
+
+static RectsAlignment alignmentForRects(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect, const IntSize& viewSize)
+{
+ // If we found a node in full alignment, but it is too far away, ignore it.
+ if (areRectsMoreThanFullScreenApart(direction, curRect, targetRect, viewSize))
+ return None;
+
+ if (areRectsFullyAligned(direction, curRect, targetRect))
+ return Full;
+
+ if (areRectsPartiallyAligned(direction, curRect, targetRect))
+ return Partial;
+
+ return None;
+}
+
+static inline bool isHorizontalMove(FocusDirection direction)
+{
+ return direction == FocusDirectionLeft || direction == FocusDirectionRight;
+}
+
+static inline int start(FocusDirection direction, const IntRect& rect)
+{
+ return isHorizontalMove(direction) ? rect.y() : rect.x();
+}
+
+static inline int middle(FocusDirection direction, const IntRect& rect)
+{
+ IntPoint center(rect.center());
+ return isHorizontalMove(direction) ? center.y(): center.x();
+}
+
+static inline int end(FocusDirection direction, const IntRect& rect)
+{
+ return isHorizontalMove(direction) ? rect.bottom() : rect.right();
+}
+
+// This method checks if rects |a| and |b| are fully aligned either vertically or
+// horizontally. In general, rects whose central point falls between the top or
+// bottom of each other are considered fully aligned.
+// Rects that match this criteria are preferable target nodes in move focus changing
+// operations.
+// * a = Current focused node's rect.
+// * b = Focus candidate node's rect.
+static bool areRectsFullyAligned(FocusDirection direction, const IntRect& a, const IntRect& b)
+{
+ int aStart, bStart, aEnd, bEnd;
+
+ switch (direction) {
+ case FocusDirectionLeft:
+ aStart = a.x();
+ bEnd = b.right();
+ break;
+ case FocusDirectionRight:
+ aStart = b.x();
+ bEnd = a.right();
+ break;
+ case FocusDirectionUp:
+ aStart = a.y();
+ bEnd = b.y();
+ break;
+ case FocusDirectionDown:
+ aStart = b.y();
+ bEnd = a.y();
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+
+ if (aStart < bEnd)
+ return false;
+
+ aStart = start(direction, a);
+ bStart = start(direction, b);
+
+ int aMiddle = middle(direction, a);
+ int bMiddle = middle(direction, b);
+
+ aEnd = end(direction, a);
+ bEnd = end(direction, b);
+
+ // Picture of the totally aligned logic:
+ //
+ // Horizontal Vertical Horizontal Vertical
+ // **************************** *****************************
+ // * _ * _ _ _ _ * * _ * _ _ *
+ // * |_| _ * |_|_|_|_| * * _ |_| * |_|_| *
+ // * |_|....|_| * . * * |_|....|_| * . *
+ // * |_| |_| (1) . * * |_| |_| (2) . *
+ // * |_| * _._ * * |_| * _ _._ _ *
+ // * * |_|_| * * * |_|_|_|_| *
+ // * * * * * *
+ // **************************** *****************************
+
+ // Horizontal Vertical Horizontal Vertical
+ // **************************** *****************************
+ // * _......_ * _ _ _ _ * * _ * _ _ _ _ *
+ // * |_| |_| * |_|_|_|_| * * |_| _ * |_|_|_|_| *
+ // * |_| |_| * . * * |_| |_| * . *
+ // * |_| (3) . * * |_|....|_| (4) . *
+ // * * ._ _ * * * _ _. *
+ // * * |_|_| * * * |_|_| *
+ // * * * * * *
+ // **************************** *****************************
+
+ return ((bMiddle >= aStart && bMiddle <= aEnd) // (1)
+ || (aMiddle >= bStart && aMiddle <= bEnd) // (2)
+ || (bStart == aStart) // (3)
+ || (bEnd == aEnd)); // (4)
+}
+
+// This method checks if |start| and |dest| have a partial intersection, either
+// horizontally or vertically.
+// * a = Current focused node's rect.
+// * b = Focus candidate node's rect.
+static bool areRectsPartiallyAligned(FocusDirection direction, const IntRect& a, const IntRect& b)
+{
+ int aStart = start(direction, a);
+ int bStart = start(direction, b);
+ int bMiddle = middle(direction, b);
+ int aEnd = end(direction, a);
+ int bEnd = end(direction, b);
+
+ // Picture of the partially aligned logic:
+ //
+ // Horizontal Vertical
+ // ********************************
+ // * _ * _ _ _ *
+ // * |_| * |_|_|_| *
+ // * |_|.... _ * . . *
+ // * |_| |_| * . . *
+ // * |_|....|_| * ._._ _ *
+ // * |_| * |_|_|_| *
+ // * |_| * *
+ // * * *
+ // ********************************
+ //
+ // ... and variants of the above cases.
+ return ((bStart >= aStart && bStart <= aEnd)
+ || (bStart >= aStart && bStart <= aEnd)
+ || (bEnd >= aStart && bEnd <= aEnd)
+ || (bMiddle >= aStart && bMiddle <= aEnd)
+ || (bEnd >= aStart && bEnd <= aEnd));
+}
+
+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)
+{
+ return a.y() > b.bottom();
+}
+
+// Return true if rect |a| is on the right of |b|. False otherwise.
+static inline bool rightOf(const IntRect& a, const IntRect& b)
+{
+ return a.x() > b.right();
+}
+
+static bool isRectInDirection(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect)
+{
+ switch (direction) {
+ case FocusDirectionLeft:
+ return targetRect.right() <= curRect.x();
+ case FocusDirectionRight:
+ return targetRect.x() >= curRect.right();
+ case FocusDirectionUp:
+ return targetRect.bottom() <= curRect.y();
+ case FocusDirectionDown:
+ return targetRect.y() >= curRect.bottom();
+ default:
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+}
+
+// Checks if |node| is offscreen the visible area (viewport) of its container
+// document. In case it is, one can scroll in direction or take any different
+// desired action later on.
+bool hasOffscreenRect(Node* node, 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
+ // before we actually move the focus to it.
+ FrameView* frameView = node->document()->view();
+ if (!frameView)
+ return true;
+
+ IntRect containerViewportRect = frameView->visibleContentRect();
+ // 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:
+ containerViewportRect.setX(containerViewportRect.x() - Scrollbar::pixelsPerLineStep());
+ containerViewportRect.setWidth(containerViewportRect.width() + Scrollbar::pixelsPerLineStep());
+ break;
+ case FocusDirectionRight:
+ containerViewportRect.setWidth(containerViewportRect.width() + Scrollbar::pixelsPerLineStep());
+ break;
+ case FocusDirectionUp:
+ containerViewportRect.setY(containerViewportRect.y() - Scrollbar::pixelsPerLineStep());
+ containerViewportRect.setHeight(containerViewportRect.height() + Scrollbar::pixelsPerLineStep());
+ break;
+ case FocusDirectionDown:
+ containerViewportRect.setHeight(containerViewportRect.height() + Scrollbar::pixelsPerLineStep());
+ break;
+ default:
+ break;
+ }
+
+ RenderObject* render = node->renderer();
+ if (!render)
+ return true;
+
+ IntRect rect(render->absoluteClippedOverflowRect());
+ if (rect.isEmpty())
+ return true;
+
+ return !containerViewportRect.intersects(rect);
+}
+
+bool scrollInDirection(Frame* frame, FocusDirection direction)
+{
+ ASSERT(frame);
+
+ if (frame && canScrollInDirection(frame->document(), direction)) {
+ 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 scrollInDirection(Node* container, FocusDirection direction)
+{
+ ASSERT(container);
+ if (container->isDocumentNode())
+ return scrollInDirection(static_cast<Document*>(container)->frame(), direction);
+
+ if (!container->renderBox())
+ return false;
+
+ if (canScrollInDirection(container, direction)) {
+ 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)
+{
+ if (!a.intersects(b) || a.contains(b) || b.contains(a))
+ return;
+
+ int deflateFactor = -fudgeFactor();
+
+ // Avoid negative width or height values.
+ if ((a.width() + 2 * deflateFactor > 0) && (a.height() + 2 * deflateFactor > 0))
+ a.inflate(deflateFactor);
+
+ if ((b.width() + 2 * deflateFactor > 0) && (b.height() + 2 * deflateFactor > 0))
+ b.inflate(deflateFactor);
+}
+
+bool isScrollableNode(const Node* node)
+{
+ ASSERT(!node->isDocumentNode());
+
+ if (!node)
+ return false;
+
+ if (RenderObject* renderer = node->renderer())
+ return renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea() && node->hasChildNodes();
+
+ return false;
+}
+
+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(parent, direction) && !parent->isDocumentNode());
+
+ return parent;
+}
+
+bool canScrollInDirection(const Node* container, FocusDirection direction)
+{
+ ASSERT(container);
+ if (container->isDocumentNode())
+ return canScrollInDirection(static_cast<const Document*>(container)->frame(), direction);
+
+ if (!isScrollableNode(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(const Frame* frame, FocusDirection direction)
+{
+ 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;
+}
+
+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;
+}
+
+IntRect frameRectInAbsoluteCoordinates(Frame* frame)
+{
+ return rectToAbsoluteCoordinates(frame, frame->view()->visibleContentRect());
+}
+
+// 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();
+ }
+
+ 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();
+ }
+}
+
+void distanceDataForNode(FocusDirection direction, const FocusCandidate& current, FocusCandidate& candidate)
+{
+ if (candidate.isNull())
+ return;
+ if (!candidate.visibleNode->renderer())
+ return;
+ IntRect nodeRect = candidate.rect;
+ IntRect currentRect = current.rect;
+ deflateIfOverlapped(currentRect, nodeRect);
+
+ if (!isRectInDirection(direction, currentRect, nodeRect))
+ return;
+
+ 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;
+ }
+
+ 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.visibleNode->document()->page()->mainFrame()->view()->visibleContentRect().size();
+ candidate.alignment = alignmentForRects(direction, currentRect, nodeRect, viewSize);
+}
+
+bool canBeScrolledIntoView(FocusDirection direction, const FocusCandidate& candidate)
+{
+ ASSERT(candidate.visibleNode && candidate.isOffscreen);
+ IntRect candidateRect = candidate.rect;
+ for (Node* parentNode = candidate.visibleNode->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(parentNode, direction);
+ }
+ return true;
+}
+
+// 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, int width)
+{
+ IntRect virtualStartingRect = startingRect;
+ switch (direction) {
+ case FocusDirectionLeft:
+ virtualStartingRect.setX(virtualStartingRect.right() - width);
+ virtualStartingRect.setWidth(width);
+ break;
+ case FocusDirectionUp:
+ virtualStartingRect.setY(virtualStartingRect.bottom() - width);
+ virtualStartingRect.setHeight(width);
+ break;
+ case FocusDirectionRight:
+ virtualStartingRect.setWidth(width);
+ break;
+ case FocusDirectionDown:
+ virtualStartingRect.setHeight(width);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return virtualStartingRect;
+}
+
+IntRect virtualRectForAreaElementAndDirection(HTMLAreaElement* area, FocusDirection direction)
+{
+ ASSERT(area);
+ ASSERT(area->imageElement());
+ // Area elements tend to overlap more than other focusable elements. We flatten the rect of the area elements
+ // to minimize the effect of overlapping areas.
+ IntRect rect = virtualRectForDirection(direction, rectToAbsoluteCoordinates(area->document()->frame(), area->getRect(area->imageElement()->renderer())), 1);
+ return rect;
+}
+
+HTMLFrameOwnerElement* frameOwnerElement(FocusCandidate& candidate)
+{
+ return candidate.isFrameOwnerElement() ? static_cast<HTMLFrameOwnerElement*>(candidate.visibleNode) : 0;
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/SpatialNavigation.h b/Source/WebCore/page/SpatialNavigation.h
new file mode 100644
index 0000000..9795f28
--- /dev/null
+++ b/Source/WebCore/page/SpatialNavigation.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Antonio Gomes <tonikitoo@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SpatialNavigation_h
+#define SpatialNavigation_h
+
+#include "FocusDirection.h"
+#include "HTMLFrameOwnerElement.h"
+#include "IntRect.h"
+#include "Node.h"
+
+#include <limits>
+
+namespace WebCore {
+
+class Element;
+class Frame;
+class HTMLAreaElement;
+class IntRect;
+class RenderObject;
+
+using namespace std;
+
+inline long long maxDistance()
+{
+ return numeric_limits<long long>::max();
+}
+
+inline int fudgeFactor()
+{
+ return 2;
+}
+
+bool isSpatialNavigationEnabled(const Frame*);
+
+// Spatially speaking, two given elements in a web page can be:
+// 1) Fully aligned: There is a full intersection between the rects, either
+// vertically or horizontally.
+//
+// * Horizontally * Vertically
+// _
+// |_| _ _ _ _ _ _
+// |_|...... _ |_|_|_|_|_|_|
+// |_| |_| . .
+// |_|......|_| OR . .
+// |_| |_| . .
+// |_|......|_| _ _ _ _
+// |_| |_|_|_|_|
+//
+//
+// 2) Partially aligned: There is a partial intersection between the rects, either
+// vertically or horizontally.
+//
+// * Horizontally * Vertically
+// _ _ _ _ _ _
+// |_| |_|_|_|_|_|
+// |_|.... _ OR . .
+// |_| |_| . .
+// |_|....|_| ._._ _
+// |_| |_|_|_|
+// |_|
+//
+// 3) Or, otherwise, not aligned at all.
+//
+// * Horizontally * Vertically
+// _ _ _ _ _
+// |_| |_|_|_|_|
+// |_| .
+// |_| .
+// . OR .
+// _ . ._ _ _ _ _
+// |_| |_|_|_|_|_|
+// |_|
+// |_|
+//
+// "Totally Aligned" elements are preferable candidates to move
+// focus to over "Partially Aligned" ones, that on its turns are
+// more preferable than "Not Aligned".
+enum RectsAlignment {
+ None = 0,
+ Partial,
+ Full
+};
+
+struct FocusCandidate {
+ FocusCandidate()
+ : visibleNode(0)
+ , focusableNode(0)
+ , enclosingScrollableBox(0)
+ , distance(maxDistance())
+ , parentDistance(maxDistance())
+ , alignment(None)
+ , parentAlignment(None)
+ , isOffscreen(true)
+ , isOffscreenAfterScrolling(true)
+ {
+ }
+
+ FocusCandidate(Node* n, FocusDirection);
+ explicit FocusCandidate(HTMLAreaElement* area, FocusDirection);
+ bool isNull() const { return !visibleNode; }
+ bool inScrollableContainer() const { return visibleNode && enclosingScrollableBox; }
+ bool isFrameOwnerElement() const { return visibleNode && visibleNode->isFrameOwnerElement(); }
+ Document* document() const { return visibleNode ? visibleNode->document() : 0; }
+
+ // We handle differently visibleNode and FocusableNode to properly handle the areas of imagemaps,
+ // where visibleNode would represent the image element and focusableNode would represent the area element.
+ // In all other cases, visibleNode and focusableNode are one and the same.
+ Node* visibleNode;
+ Node* focusableNode;
+ Node* enclosingScrollableBox;
+ long long distance;
+ long long parentDistance;
+ RectsAlignment alignment;
+ RectsAlignment parentAlignment;
+ IntRect rect;
+ bool isOffscreen;
+ bool isOffscreenAfterScrolling;
+};
+
+bool hasOffscreenRect(Node*, FocusDirection direction = FocusDirectionNone);
+bool scrollInDirection(Frame*, FocusDirection);
+bool scrollInDirection(Node* container, FocusDirection);
+bool canScrollInDirection(const Node* container, FocusDirection);
+bool canScrollInDirection(const Frame*, FocusDirection);
+bool canBeScrolledIntoView(FocusDirection, const FocusCandidate&);
+void distanceDataForNode(FocusDirection, const FocusCandidate& current, FocusCandidate& candidate);
+Node* scrollableEnclosingBoxOrParentFrameForNodeInDirection(FocusDirection, Node*);
+IntRect nodeRectInAbsoluteCoordinates(Node*, bool ignoreBorder = false);
+IntRect frameRectInAbsoluteCoordinates(Frame*);
+IntRect virtualRectForDirection(FocusDirection, const IntRect& startingRect, int width = 0);
+IntRect virtualRectForAreaElementAndDirection(HTMLAreaElement*, FocusDirection);
+HTMLFrameOwnerElement* frameOwnerElement(FocusCandidate&);
+
+} // namspace WebCore
+
+#endif // SpatialNavigation_h
diff --git a/Source/WebCore/page/SpeechInput.cpp b/Source/WebCore/page/SpeechInput.cpp
new file mode 100644
index 0000000..f36ed4d
--- /dev/null
+++ b/Source/WebCore/page/SpeechInput.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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 "SpeechInput.h"
+
+#if ENABLE(INPUT_SPEECH)
+
+#include "Frame.h"
+#include "SpeechInputClient.h"
+#include "SpeechInputListener.h"
+
+namespace WebCore {
+
+SpeechInput::SpeechInput(SpeechInputClient* client)
+ : m_client(client)
+ , m_nextListenerId(1)
+{
+ m_client->setListener(this);
+}
+
+SpeechInput::~SpeechInput()
+{
+ m_client->setListener(0);
+}
+
+int SpeechInput::registerListener(SpeechInputListener* listener)
+{
+#if defined(DEBUG)
+ // Check if already present.
+ for (HashMap<int, SpeechInputListener*>::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
+ ASSERT(it->second != listener);
+#endif
+
+ m_listeners.add(m_nextListenerId, listener);
+ return m_nextListenerId++;
+}
+
+void SpeechInput::unregisterListener(int listenerId)
+{
+ if (m_listeners.contains(listenerId))
+ m_listeners.remove(listenerId);
+}
+
+void SpeechInput::didCompleteRecording(int listenerId)
+{
+ // Don't assert if not present as the element might have been removed by the page while
+ // this event was on the way.
+ if (m_listeners.contains(listenerId))
+ m_listeners.get(listenerId)->didCompleteRecording(listenerId);
+}
+
+void SpeechInput::didCompleteRecognition(int listenerId)
+{
+ // Don't assert if not present as the element might have been removed by the page while
+ // this event was on the way.
+ if (m_listeners.contains(listenerId))
+ m_listeners.get(listenerId)->didCompleteRecognition(listenerId);
+}
+
+void SpeechInput::setRecognitionResult(int listenerId, const SpeechInputResultArray& result)
+{
+ // Don't assert if not present as the element might have been removed by the page while
+ // this event was on the way.
+ if (m_listeners.contains(listenerId))
+ m_listeners.get(listenerId)->setRecognitionResult(listenerId, result);
+}
+
+bool SpeechInput::startRecognition(int listenerId, const IntRect& elementRect, const AtomicString& language, const String& grammar)
+{
+ ASSERT(m_listeners.contains(listenerId));
+ return m_client->startRecognition(listenerId, elementRect, language, grammar);
+}
+
+void SpeechInput::stopRecording(int listenerId)
+{
+ ASSERT(m_listeners.contains(listenerId));
+ m_client->stopRecording(listenerId);
+}
+
+void SpeechInput::cancelRecognition(int listenerId)
+{
+ ASSERT(m_listeners.contains(listenerId));
+ m_client->cancelRecognition(listenerId);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INPUT_SPEECH)
diff --git a/Source/WebCore/page/SpeechInput.h b/Source/WebCore/page/SpeechInput.h
new file mode 100644
index 0000000..4532d49
--- /dev/null
+++ b/Source/WebCore/page/SpeechInput.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#ifndef SpeechInput_h
+#define SpeechInput_h
+
+#if ENABLE(INPUT_SPEECH)
+
+#include "SpeechInputListener.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class IntRect;
+class SpeechInputClient;
+class SpeechInputListener;
+
+// This class connects the input elements requiring speech input with the platform specific
+// speech recognition engine. It provides methods for the input elements to activate speech
+// recognition and methods for the speech recognition engine to return back the results.
+class SpeechInput : public Noncopyable, public SpeechInputListener {
+public:
+ SpeechInput(SpeechInputClient*);
+ virtual ~SpeechInput();
+
+ // Generates a unique ID for the given listener to be used for speech requests.
+ // This should be the first call made by listeners before anything else.
+ int registerListener(SpeechInputListener*);
+
+ // Invoked when the listener is done with recording or getting destroyed.
+ // Failure to unregister may result in crashes if there were any pending speech events.
+ void unregisterListener(int);
+
+ // Methods invoked by the input elements.
+ bool startRecognition(int listenerId, const IntRect& elementRect, const AtomicString& language, const String& grammar);
+ void stopRecording(int);
+ void cancelRecognition(int);
+
+ // SpeechInputListener methods.
+ virtual void didCompleteRecording(int);
+ virtual void didCompleteRecognition(int);
+ virtual void setRecognitionResult(int, const SpeechInputResultArray&);
+
+private:
+ SpeechInputClient* m_client;
+ HashMap<int, SpeechInputListener*> m_listeners;
+ int m_nextListenerId;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INPUT_SPEECH)
+
+#endif // SpeechInput_h
diff --git a/Source/WebCore/page/SpeechInputClient.h b/Source/WebCore/page/SpeechInputClient.h
new file mode 100644
index 0000000..2a2e160
--- /dev/null
+++ b/Source/WebCore/page/SpeechInputClient.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef SpeechInputClient_h
+#define SpeechInputClient_h
+
+#include <wtf/Forward.h>
+
+#if ENABLE(INPUT_SPEECH)
+
+namespace WebCore {
+
+class IntRect;
+class SpeechInputListener;
+
+// Provides an interface for SpeechInput to call into the embedder.
+class SpeechInputClient {
+public:
+ // This is the first call made by a listener, registering itself for future callbacks.
+ // When the listener no longer needs speech input (for e.g. when it gets destroyed),
+ // it should set a null listener to stop receiving callbacks.
+ // The client does not take ownership of the pointer.
+ virtual void setListener(SpeechInputListener*) = 0;
+
+ // Starts speech recognition and audio recording.
+ virtual bool startRecognition(int requestId, const IntRect& elementRect, const AtomicString& language, const String& grammar) = 0;
+
+ // Stops audio recording and performs recognition with the audio recorded until now
+ // (does not discard audio).
+ virtual void stopRecording(int requestId) = 0;
+
+ // Cancels an ongoing recognition and discards any audio recorded so far. No partial
+ // recognition results are returned to the listener.
+ virtual void cancelRecognition(int requestId) = 0;
+
+protected:
+ virtual ~SpeechInputClient() { }
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INPUT_SPEECH)
+
+#endif // SpeechInputClient_h
diff --git a/Source/WebCore/page/SpeechInputEvent.cpp b/Source/WebCore/page/SpeechInputEvent.cpp
new file mode 100644
index 0000000..181322f
--- /dev/null
+++ b/Source/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/Source/WebCore/page/SpeechInputEvent.h b/Source/WebCore/page/SpeechInputEvent.h
new file mode 100644
index 0000000..6a39f3c
--- /dev/null
+++ b/Source/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/Source/WebCore/page/SpeechInputEvent.idl b/Source/WebCore/page/SpeechInputEvent.idl
new file mode 100644
index 0000000..c461483
--- /dev/null
+++ b/Source/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/Source/WebCore/page/SpeechInputListener.h b/Source/WebCore/page/SpeechInputListener.h
new file mode 100644
index 0000000..7415301
--- /dev/null
+++ b/Source/WebCore/page/SpeechInputListener.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#ifndef SpeechInputListener_h
+#define SpeechInputListener_h
+
+#if ENABLE(INPUT_SPEECH)
+
+#include "SpeechInputResult.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+// Interface to be implemented by the element which invokes SpeechInput.
+class SpeechInputListener {
+public:
+ // Informs that audio recording has completed and recognition is underway.
+ virtual void didCompleteRecording(int requestId) = 0;
+
+ // Informs that speech recognition has completed. This gets invoked irrespective of whether
+ // recognition was succesful or not, whether setRecognitionResult() was invoked or not. The
+ // handler typically frees up any temporary resources allocated and waits for the next speech
+ // recognition request.
+ virtual void didCompleteRecognition(int requestId) = 0;
+
+ // Gives results from speech recognition, either partial or the final results.
+ // This method can potentially get called multiple times if there are partial results
+ // available as the user keeps speaking. If the speech could not be recognized properly
+ // or if there was any other errors in the process, this method may never be called.
+ virtual void setRecognitionResult(int requestId, const SpeechInputResultArray&) = 0;
+
+protected:
+ virtual ~SpeechInputListener() { }
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INPUT_SPEECH)
+
+#endif // SpeechInputListener_h
diff --git a/Source/WebCore/page/SpeechInputResult.cpp b/Source/WebCore/page/SpeechInputResult.cpp
new file mode 100644
index 0000000..1c042a0
--- /dev/null
+++ b/Source/WebCore/page/SpeechInputResult.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "SpeechInputResult.h"
+
+#if ENABLE(INPUT_SPEECH)
+
+namespace WebCore {
+
+PassRefPtr<SpeechInputResult> SpeechInputResult::create(const String& utterance, double confidence)
+{
+ 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)
+{
+}
+
+double SpeechInputResult::confidence() const
+{
+ return m_confidence;
+}
+
+const String& SpeechInputResult::utterance() const
+{
+ return m_utterance;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INPUT_SPEECH)
diff --git a/Source/WebCore/page/SpeechInputResult.h b/Source/WebCore/page/SpeechInputResult.h
new file mode 100644
index 0000000..457f078
--- /dev/null
+++ b/Source/WebCore/page/SpeechInputResult.h
@@ -0,0 +1,60 @@
+/*
+ * 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 SpeechInputResult_h
+#define SpeechInputResult_h
+
+#if ENABLE(INPUT_SPEECH)
+
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+// This class holds one speech recognition result including the text and other related
+// 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;
+ const String& utterance() const;
+
+private:
+ SpeechInputResult(const String& utterance, double confidence);
+
+ String m_utterance;
+ double m_confidence;
+};
+
+typedef Vector<RefPtr<SpeechInputResult> > SpeechInputResultArray;
+
+} // namespace WebCore
+
+#endif // ENABLE(INPUT_SPEECH)
+
+#endif // SpeechInputResult_h
diff --git a/Source/WebCore/page/SpeechInputResult.idl b/Source/WebCore/page/SpeechInputResult.idl
new file mode 100644
index 0000000..f688de4
--- /dev/null
+++ b/Source/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/Source/WebCore/page/SpeechInputResultList.cpp b/Source/WebCore/page/SpeechInputResultList.cpp
new file mode 100644
index 0000000..41fd108
--- /dev/null
+++ b/Source/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/Source/WebCore/page/SpeechInputResultList.h b/Source/WebCore/page/SpeechInputResultList.h
new file mode 100644
index 0000000..b050630
--- /dev/null
+++ b/Source/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/Source/WebCore/page/SpeechInputResultList.idl b/Source/WebCore/page/SpeechInputResultList.idl
new file mode 100644
index 0000000..5a23d4f
--- /dev/null
+++ b/Source/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/Source/WebCore/page/SuspendableTimer.cpp b/Source/WebCore/page/SuspendableTimer.cpp
new file mode 100644
index 0000000..23f00b0
--- /dev/null
+++ b/Source/WebCore/page/SuspendableTimer.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "SuspendableTimer.h"
+
+#include "ScriptExecutionContext.h"
+
+namespace WebCore {
+
+SuspendableTimer::SuspendableTimer(ScriptExecutionContext* context)
+ : ActiveDOMObject(context, this)
+ , m_nextFireInterval(0)
+ , m_repeatInterval(0)
+#if !ASSERT_DISABLED
+ , m_suspended(false)
+#endif
+{
+}
+
+SuspendableTimer::~SuspendableTimer()
+{
+}
+
+bool SuspendableTimer::hasPendingActivity() const
+{
+ return isActive();
+}
+
+void SuspendableTimer::stop()
+{
+ TimerBase::stop();
+}
+
+void SuspendableTimer::suspend(ReasonForSuspension)
+{
+#if !ASSERT_DISABLED
+ ASSERT(!m_suspended);
+ m_suspended = true;
+#endif
+ m_nextFireInterval = nextFireInterval();
+ m_repeatInterval = repeatInterval();
+ TimerBase::stop();
+}
+
+void SuspendableTimer::resume()
+{
+#if !ASSERT_DISABLED
+ ASSERT(m_suspended);
+ m_suspended = false;
+#endif
+ start(m_nextFireInterval, m_repeatInterval);
+}
+
+bool SuspendableTimer::canSuspend() const
+{
+ return true;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/SuspendableTimer.h b/Source/WebCore/page/SuspendableTimer.h
new file mode 100644
index 0000000..cc90b62
--- /dev/null
+++ b/Source/WebCore/page/SuspendableTimer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef SuspendableTimer_h
+#define SuspendableTimer_h
+
+#include "ActiveDOMObject.h"
+#include "Timer.h"
+
+namespace WebCore {
+
+class SuspendableTimer : public TimerBase, public ActiveDOMObject {
+public:
+ SuspendableTimer(ScriptExecutionContext*);
+ virtual ~SuspendableTimer();
+
+ // ActiveDOMObject
+ virtual bool hasPendingActivity() const;
+ virtual void stop();
+ virtual bool canSuspend() const;
+ virtual void suspend(ReasonForSuspension);
+ virtual void resume();
+
+private:
+ virtual void fired() = 0;
+
+ double m_nextFireInterval;
+ double m_repeatInterval;
+#if !ASSERT_DISABLED
+ bool m_suspended;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // SuspendableTimer_h
+
diff --git a/Source/WebCore/page/UserContentTypes.h b/Source/WebCore/page/UserContentTypes.h
new file mode 100644
index 0000000..d012b8c
--- /dev/null
+++ b/Source/WebCore/page/UserContentTypes.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UserContentTypes_h
+#define UserContentTypes_h
+
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+enum UserContentInjectedFrames { InjectInAllFrames, InjectInTopFrameOnly };
+
+} // namespace WebCore
+
+#endif // UserContentTypes_h
diff --git a/Source/WebCore/page/UserContentURLPattern.cpp b/Source/WebCore/page/UserContentURLPattern.cpp
new file mode 100644
index 0000000..272284a
--- /dev/null
+++ b/Source/WebCore/page/UserContentURLPattern.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "UserContentURLPattern.h"
+#include "KURL.h"
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+bool UserContentURLPattern::matchesPatterns(const KURL& url, const Vector<String>* whitelist, const Vector<String>* blacklist)
+{
+ // In order for a URL to be a match it has to be present in the whitelist and not present in the blacklist.
+ // If there is no whitelist at all, then all URLs are assumed to be in the whitelist.
+ bool matchesWhitelist = !whitelist || whitelist->isEmpty();
+ if (!matchesWhitelist) {
+ for (unsigned i = 0; i < whitelist->size(); ++i) {
+ UserContentURLPattern contentPattern(whitelist->at(i));
+ if (contentPattern.matches(url)) {
+ matchesWhitelist = true;
+ break;
+ }
+ }
+ }
+
+ bool matchesBlacklist = false;
+ if (blacklist) {
+ for (unsigned i = 0; i < blacklist->size(); ++i) {
+ UserContentURLPattern contentPattern(blacklist->at(i));
+ if (contentPattern.matches(url)) {
+ matchesBlacklist = true;
+ break;
+ }
+ }
+ }
+
+ return matchesWhitelist && !matchesBlacklist;
+}
+
+bool UserContentURLPattern::parse(const String& pattern)
+{
+ DEFINE_STATIC_LOCAL(const String, schemeSeparator, ("://"));
+
+ size_t schemeEndPos = pattern.find(schemeSeparator);
+ if (schemeEndPos == notFound)
+ return false;
+
+ m_scheme = pattern.left(schemeEndPos);
+
+ unsigned hostStartPos = schemeEndPos + schemeSeparator.length();
+ if (hostStartPos >= pattern.length())
+ return false;
+
+ int pathStartPos = 0;
+
+ if (equalIgnoringCase(m_scheme, "file"))
+ pathStartPos = hostStartPos;
+ else {
+ size_t hostEndPos = pattern.find("/", hostStartPos);
+ if (hostEndPos == notFound)
+ return false;
+
+ m_host = pattern.substring(hostStartPos, hostEndPos - hostStartPos);
+ m_matchSubdomains = false;
+
+ if (m_host == "*") {
+ // The pattern can be just '*', which means match all domains.
+ m_host = "";
+ m_matchSubdomains = true;
+ } else if (m_host.startsWith("*.")) {
+ // The first component can be '*', which means to match all subdomains.
+ m_host = m_host.substring(2); // Length of "*."
+ m_matchSubdomains = true;
+ }
+
+ // No other '*' can occur in the host.
+ if (m_host.find("*") != notFound)
+ return false;
+
+ pathStartPos = hostEndPos;
+ }
+
+ m_path = pattern.right(pattern.length() - pathStartPos);
+
+ return true;
+}
+
+bool UserContentURLPattern::matches(const KURL& test) const
+{
+ if (m_invalid)
+ return false;
+
+ if (!equalIgnoringCase(test.protocol(), m_scheme))
+ return false;
+
+ if (!equalIgnoringCase(m_scheme, "file") && !matchesHost(test))
+ return false;
+
+ return matchesPath(test);
+}
+
+bool UserContentURLPattern::matchesHost(const KURL& test) const
+{
+ const String& host = test.host();
+ if (equalIgnoringCase(host, m_host))
+ return true;
+
+ if (!m_matchSubdomains)
+ return false;
+
+ // If we're matching subdomains, and we have no host, that means the pattern
+ // was <scheme>://*/<whatever>, so we match anything.
+ if (!m_host.length())
+ return true;
+
+ // Check if the domain is a subdomain of our host.
+ if (!host.endsWith(m_host, false))
+ return false;
+
+ ASSERT(host.length() > m_host.length());
+
+ // Check that the character before the suffix is a period.
+ return host[host.length() - m_host.length() - 1] == '.';
+}
+
+struct MatchTester
+{
+ const String m_pattern;
+ unsigned m_patternIndex;
+
+ const String m_test;
+ unsigned m_testIndex;
+
+ MatchTester(const String& pattern, const String& test)
+ : m_pattern(pattern)
+ , m_patternIndex(0)
+ , m_test(test)
+ , m_testIndex(0)
+ {
+ }
+
+ bool testStringFinished() const { return m_testIndex >= m_test.length(); }
+ bool patternStringFinished() const { return m_patternIndex >= m_pattern.length(); }
+
+ void eatWildcard()
+ {
+ while (!patternStringFinished()) {
+ if (m_pattern[m_patternIndex] != '*')
+ return;
+ m_patternIndex++;
+ }
+ }
+
+ void eatSameChars()
+ {
+ while (!patternStringFinished() && !testStringFinished()) {
+ if (m_pattern[m_patternIndex] == '*')
+ return;
+ if (m_pattern[m_patternIndex] != m_test[m_testIndex])
+ return;
+ m_patternIndex++;
+ m_testIndex++;
+ }
+ }
+
+ bool test()
+ {
+ // Eat all the matching chars.
+ eatSameChars();
+
+ // If the string is finished, then the pattern must be empty too, or contains
+ // only wildcards.
+ if (testStringFinished()) {
+ eatWildcard();
+ if (patternStringFinished())
+ return true;
+ return false;
+ }
+
+ // Pattern is empty but not string, this is not a match.
+ if (patternStringFinished())
+ return false;
+
+ // If we don't encounter a *, then we're hosed.
+ if (m_pattern[m_patternIndex] != '*')
+ return false;
+
+ while (!testStringFinished()) {
+ MatchTester nextMatch(*this);
+ nextMatch.m_patternIndex++;
+ if (nextMatch.test())
+ return true;
+ m_testIndex++;
+ }
+
+ // We reached the end of the string. Let's see if the pattern contains only
+ // wildcards.
+ eatWildcard();
+ return patternStringFinished();
+ }
+};
+
+bool UserContentURLPattern::matchesPath(const KURL& test) const
+{
+ MatchTester match(m_path, test.path());
+ return match.test();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/UserContentURLPattern.h b/Source/WebCore/page/UserContentURLPattern.h
new file mode 100644
index 0000000..3450ed1
--- /dev/null
+++ b/Source/WebCore/page/UserContentURLPattern.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UserContentURLPattern_h
+#define UserContentURLPattern_h
+
+#include "PlatformString.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class KURL;
+
+class UserContentURLPattern {
+public:
+ UserContentURLPattern() : m_invalid(true), m_matchSubdomains(false) { }
+
+ UserContentURLPattern(const String& pattern)
+ : m_matchSubdomains(false)
+ {
+ m_invalid = !parse(pattern);
+ }
+
+ bool isValid() const { return !m_invalid; }
+
+ bool matches(const KURL&) const;
+
+ const String& scheme() const { return m_scheme; }
+ const String& host() const { return m_host; }
+ const String& path() const { return m_path; }
+
+ bool matchSubdomains() const { return m_matchSubdomains; }
+
+ static bool matchesPatterns(const KURL&, const Vector<String>* whitelist, const Vector<String>* blacklist);
+
+private:
+ bool parse(const String& pattern);
+
+ bool matchesHost(const KURL&) const;
+ bool matchesPath(const KURL&) const;
+
+ bool m_invalid;
+
+ String m_scheme;
+ String m_host;
+ String m_path;
+
+ bool m_matchSubdomains;
+};
+
+
+} // namespace WebCore
+
+#endif // UserContentURLPattern_h
diff --git a/Source/WebCore/page/UserScript.h b/Source/WebCore/page/UserScript.h
new file mode 100644
index 0000000..0652439
--- /dev/null
+++ b/Source/WebCore/page/UserScript.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UserScript_h
+#define UserScript_h
+
+#include "KURL.h"
+#include "UserContentTypes.h"
+#include "UserScriptTypes.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class UserScript : public Noncopyable {
+public:
+ UserScript(const String& source, const KURL& url,
+ PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist,
+ UserScriptInjectionTime injectionTime, UserContentInjectedFrames injectedFrames)
+ : m_source(source)
+ , m_url(url)
+ , m_whitelist(whitelist)
+ , m_blacklist(blacklist)
+ , m_injectionTime(injectionTime)
+ , m_injectedFrames(injectedFrames)
+ {
+ }
+
+ const String& source() const { return m_source; }
+ const KURL& url() const { return m_url; }
+ const Vector<String>* whitelist() const { return m_whitelist.get(); }
+ const Vector<String>* blacklist() const { return m_blacklist.get(); }
+ UserScriptInjectionTime injectionTime() const { return m_injectionTime; }
+ UserContentInjectedFrames injectedFrames() const { return m_injectedFrames; }
+
+private:
+ String m_source;
+ KURL m_url;
+ OwnPtr<Vector<String> > m_whitelist;
+ OwnPtr<Vector<String> > m_blacklist;
+ UserScriptInjectionTime m_injectionTime;
+ UserContentInjectedFrames m_injectedFrames;
+};
+
+} // namespace WebCore
+
+#endif // UserScript_h
diff --git a/Source/WebCore/page/UserScriptTypes.h b/Source/WebCore/page/UserScriptTypes.h
new file mode 100644
index 0000000..ad27e79
--- /dev/null
+++ b/Source/WebCore/page/UserScriptTypes.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UserScriptTypes_h
+#define UserScriptTypes_h
+
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+enum UserScriptInjectionTime { InjectAtDocumentStart, InjectAtDocumentEnd };
+
+class DOMWrapperWorld;
+class UserScript;
+
+typedef Vector<OwnPtr<UserScript> > UserScriptVector;
+typedef HashMap<RefPtr<DOMWrapperWorld>, UserScriptVector*> UserScriptMap;
+
+} // namespace WebCore
+
+#endif // UserScriptTypes_h
diff --git a/Source/WebCore/page/UserStyleSheet.h b/Source/WebCore/page/UserStyleSheet.h
new file mode 100644
index 0000000..fa42e2c
--- /dev/null
+++ b/Source/WebCore/page/UserStyleSheet.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UserStyleSheet_h
+#define UserStyleSheet_h
+
+#include "KURL.h"
+#include "UserContentTypes.h"
+#include "UserStyleSheetTypes.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class UserStyleSheet : public Noncopyable {
+public:
+ UserStyleSheet(const String& source, const KURL& url,
+ PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist,
+ UserContentInjectedFrames injectedFrames, UserStyleLevel level)
+ : m_source(source)
+ , m_url(url)
+ , m_whitelist(whitelist)
+ , m_blacklist(blacklist)
+ , m_injectedFrames(injectedFrames)
+ , m_level(level)
+ {
+ }
+
+ const String& source() const { return m_source; }
+ const KURL& url() const { return m_url; }
+ const Vector<String>* whitelist() const { return m_whitelist.get(); }
+ const Vector<String>* blacklist() const { return m_blacklist.get(); }
+ UserContentInjectedFrames injectedFrames() const { return m_injectedFrames; }
+ UserStyleLevel level() const { return m_level; }
+
+private:
+ String m_source;
+ KURL m_url;
+ OwnPtr<Vector<String> > m_whitelist;
+ OwnPtr<Vector<String> > m_blacklist;
+ UserContentInjectedFrames m_injectedFrames;
+ UserStyleLevel m_level;
+};
+
+} // namespace WebCore
+
+#endif // UserStyleSheet_h
diff --git a/Source/WebCore/page/UserStyleSheetTypes.h b/Source/WebCore/page/UserStyleSheetTypes.h
new file mode 100644
index 0000000..eda6604
--- /dev/null
+++ b/Source/WebCore/page/UserStyleSheetTypes.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UserStyleSheetTypes_h
+#define UserStyleSheetTypes_h
+
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+enum UserStyleInjectionTime { InjectInExistingDocuments, InjectInSubsequentDocuments };
+enum UserStyleLevel { UserStyleUserLevel, UserStyleAuthorLevel };
+
+class DOMWrapperWorld;
+class UserStyleSheet;
+
+typedef Vector<OwnPtr<UserStyleSheet> > UserStyleSheetVector;
+typedef HashMap<RefPtr<DOMWrapperWorld>, UserStyleSheetVector*> UserStyleSheetMap;
+
+} // namespace WebCore
+
+#endif // UserStyleSheetTypes_h
diff --git a/Source/WebCore/page/WebKitPoint.h b/Source/WebCore/page/WebKitPoint.h
new file mode 100644
index 0000000..ff5d442
--- /dev/null
+++ b/Source/WebCore/page/WebKitPoint.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebKitPoint_h
+#define WebKitPoint_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class WebKitPoint : public RefCounted<WebKitPoint> {
+ public:
+
+ static PassRefPtr<WebKitPoint> create()
+ {
+ return adoptRef(new WebKitPoint());
+ }
+ static PassRefPtr<WebKitPoint> create(float x, float y)
+ {
+ return adoptRef(new WebKitPoint(x, y));
+ }
+
+ float x() const { return m_x; }
+ float y() const { return m_y; }
+
+ void setX(float x) { m_x = x; }
+ void setY(float y) { m_y = y; }
+
+ private:
+ WebKitPoint(float x=0, float y=0)
+ : m_x(x)
+ , m_y(y)
+ {
+ }
+
+ float m_x, m_y;
+ };
+
+} // namespace WebCore
+
+#endif // WebKitPoint_h
diff --git a/Source/WebCore/page/WebKitPoint.idl b/Source/WebCore/page/WebKitPoint.idl
new file mode 100644
index 0000000..4e6021f
--- /dev/null
+++ b/Source/WebCore/page/WebKitPoint.idl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module window {
+
+ interface [
+ CanBeConstructed,
+ CustomConstructFunction,
+ ConstructorParameters=2,
+ V8CustomConstructor
+ ] WebKitPoint {
+ attribute float x;
+ attribute float y;
+ };
+
+}
diff --git a/Source/WebCore/page/WindowFeatures.cpp b/Source/WebCore/page/WindowFeatures.cpp
new file mode 100644
index 0000000..a229ae1
--- /dev/null
+++ b/Source/WebCore/page/WindowFeatures.cpp
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006 Jon Shier (jshier@iastate.edu)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights reseved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "config.h"
+#include "WindowFeatures.h"
+
+#include "FloatRect.h"
+#include "PlatformString.h"
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+// Though isspace() considers \t and \v to be whitespace, Win IE doesn't when parsing window features.
+static bool isWindowFeaturesSeparator(UChar c)
+{
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ',' || c == '\0';
+}
+
+WindowFeatures::WindowFeatures(const String& features)
+ : xSet(false)
+ , ySet(false)
+ , widthSet(false)
+ , heightSet(false)
+ , fullscreen(false)
+ , dialog(false)
+{
+ /*
+ The IE rule is: all features except for channelmode and fullscreen default to YES, but
+ if the user specifies a feature string, all features default to NO. (There is no public
+ standard that applies to this method.)
+
+ <http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_0.asp>
+ We always allow a window to be resized, which is consistent with Firefox.
+ */
+
+ if (features.length() == 0) {
+ menuBarVisible = true;
+ statusBarVisible = true;
+ toolBarVisible = true;
+ locationBarVisible = true;
+ scrollbarsVisible = true;
+ resizable = true;
+ return;
+ }
+
+ menuBarVisible = false;
+ statusBarVisible = false;
+ toolBarVisible = false;
+ locationBarVisible = false;
+ scrollbarsVisible = false;
+ resizable = true;
+
+ // Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior.
+ int keyBegin, keyEnd;
+ int valueBegin, valueEnd;
+
+ int i = 0;
+ int length = features.length();
+ String buffer = features.lower();
+ while (i < length) {
+ // skip to first non-separator, but don't skip past the end of the string
+ while (isWindowFeaturesSeparator(buffer[i])) {
+ if (i >= length)
+ break;
+ i++;
+ }
+ keyBegin = i;
+
+ // skip to first separator
+ while (!isWindowFeaturesSeparator(buffer[i]))
+ i++;
+ keyEnd = i;
+
+ // skip to first '=', but don't skip past a ',' or the end of the string
+ while (buffer[i] != '=') {
+ if (buffer[i] == ',' || i >= length)
+ break;
+ i++;
+ }
+
+ // skip to first non-separator, but don't skip past a ',' or the end of the string
+ while (isWindowFeaturesSeparator(buffer[i])) {
+ if (buffer[i] == ',' || i >= length)
+ break;
+ i++;
+ }
+ valueBegin = i;
+
+ // skip to first separator
+ while (!isWindowFeaturesSeparator(buffer[i]))
+ i++;
+ valueEnd = i;
+
+ ASSERT(i <= length);
+
+ String keyString(buffer.substring(keyBegin, keyEnd - keyBegin));
+ String valueString(buffer.substring(valueBegin, valueEnd - valueBegin));
+ setWindowFeature(keyString, valueString);
+ }
+}
+
+void WindowFeatures::setWindowFeature(const String& keyString, const String& valueString)
+{
+ int value;
+
+ // Listing a key with no value is shorthand for key=yes
+ if (valueString.isEmpty() || valueString == "yes")
+ value = 1;
+ else
+ value = valueString.toInt();
+
+ // We treat keyString of "resizable" here as an additional feature rather than setting resizeable to true.
+ // This is consistent with Firefox, but could also be handled at another level.
+
+ if (keyString == "left" || keyString == "screenx") {
+ xSet = true;
+ x = value;
+ } else if (keyString == "top" || keyString == "screeny") {
+ ySet = true;
+ y = value;
+ } else if (keyString == "width" || keyString == "innerwidth") {
+ widthSet = true;
+ width = value;
+ } else if (keyString == "height" || keyString == "innerheight") {
+ heightSet = true;
+ height = value;
+ } else if (keyString == "menubar")
+ menuBarVisible = value;
+ else if (keyString == "toolbar")
+ toolBarVisible = value;
+ else if (keyString == "location")
+ locationBarVisible = value;
+ else if (keyString == "status")
+ statusBarVisible = value;
+ else if (keyString == "fullscreen")
+ fullscreen = value;
+ else if (keyString == "scrollbars")
+ scrollbarsVisible = value;
+ else if (value == 1)
+ additionalFeatures.append(keyString);
+}
+
+WindowFeatures::WindowFeatures(const String& dialogFeaturesString, const FloatRect& screenAvailableRect)
+ : widthSet(true)
+ , heightSet(true)
+ , menuBarVisible(false)
+ , toolBarVisible(false)
+ , locationBarVisible(false)
+ , fullscreen(false)
+ , dialog(true)
+{
+ DialogFeaturesMap features;
+ parseDialogFeatures(dialogFeaturesString, features);
+
+ const bool trusted = false;
+
+ // The following features from Microsoft's documentation are not implemented:
+ // - default font settings
+ // - width, height, left, and top specified in units other than "px"
+ // - edge (sunken or raised, default is raised)
+ // - dialogHide: trusted && boolFeature(features, "dialoghide"), makes dialog hide when you print
+ // - help: boolFeature(features, "help", true), makes help icon appear in dialog (what does it do on Windows?)
+ // - unadorned: trusted && boolFeature(features, "unadorned");
+
+ width = floatFeature(features, "dialogwidth", 100, screenAvailableRect.width(), 620); // default here came from frame size of dialog in MacIE
+ height = floatFeature(features, "dialogheight", 100, screenAvailableRect.height(), 450); // default here came from frame size of dialog in MacIE
+
+ x = floatFeature(features, "dialogleft", screenAvailableRect.x(), screenAvailableRect.right() - width, -1);
+ xSet = x > 0;
+ y = floatFeature(features, "dialogtop", screenAvailableRect.y(), screenAvailableRect.bottom() - height, -1);
+ ySet = y > 0;
+
+ if (boolFeature(features, "center", true)) {
+ if (!xSet) {
+ x = screenAvailableRect.x() + (screenAvailableRect.width() - width) / 2;
+ xSet = true;
+ }
+ if (!ySet) {
+ y = screenAvailableRect.y() + (screenAvailableRect.height() - height) / 2;
+ ySet = true;
+ }
+ }
+
+ resizable = boolFeature(features, "resizable");
+ scrollbarsVisible = boolFeature(features, "scroll", true);
+ statusBarVisible = boolFeature(features, "status", !trusted);
+}
+
+bool WindowFeatures::boolFeature(const DialogFeaturesMap& features, const char* key, bool defaultValue)
+{
+ DialogFeaturesMap::const_iterator it = features.find(key);
+ if (it == features.end())
+ return defaultValue;
+ const String& value = it->second;
+ return value.isNull() || value == "1" || value == "yes" || value == "on";
+}
+
+float WindowFeatures::floatFeature(const DialogFeaturesMap& features, const char* key, float min, float max, float defaultValue)
+{
+ DialogFeaturesMap::const_iterator it = features.find(key);
+ if (it == features.end())
+ return defaultValue;
+ // FIXME: The toDouble function does not offer a way to tell "0q" from string with no digits in it: Both
+ // return the number 0 and false for ok. But "0q" should yield the minimum rather than the default.
+ bool ok;
+ double parsedNumber = it->second.toDouble(&ok);
+ if ((parsedNumber == 0 && !ok) || isnan(parsedNumber))
+ return defaultValue;
+ if (parsedNumber < min || max <= min)
+ return min;
+ if (parsedNumber > max)
+ return max;
+ // FIXME: Seems strange to cast a double to int and then convert back to a float. Why is this a good idea?
+ return static_cast<int>(parsedNumber);
+}
+
+void WindowFeatures::parseDialogFeatures(const String& string, DialogFeaturesMap& map)
+{
+ Vector<String> vector;
+ string.split(';', vector);
+ size_t size = vector.size();
+ for (size_t i = 0; i < size; ++i) {
+ const String& featureString = vector[i];
+
+ size_t separatorPosition = featureString.find('=');
+ size_t colonPosition = featureString.find(':');
+ if (separatorPosition != notFound && colonPosition != notFound)
+ continue; // ignore strings that have both = and :
+ if (separatorPosition == notFound)
+ separatorPosition = colonPosition;
+
+ String key = featureString.left(separatorPosition).stripWhiteSpace().lower();
+
+ // Null string for value indicates key without value.
+ String value;
+ if (separatorPosition != notFound) {
+ value = featureString.substring(separatorPosition + 1).stripWhiteSpace().lower();
+ value = value.left(value.find(' '));
+ }
+
+ map.set(key, value);
+ }
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/WindowFeatures.h b/Source/WebCore/page/WindowFeatures.h
new file mode 100644
index 0000000..ea5768f
--- /dev/null
+++ b/Source/WebCore/page/WindowFeatures.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2003, 2007, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 WindowFeatures_h
+#define WindowFeatures_h
+
+#include "PlatformString.h"
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+ class FloatRect;
+
+ struct WindowFeatures {
+ // FIXME: We can delete this constructor once V8 showModalDialog is changed to use DOMWindow.
+ WindowFeatures()
+ : xSet(false)
+ , ySet(false)
+ , widthSet(false)
+ , heightSet(false)
+ , menuBarVisible(true)
+ , statusBarVisible(true)
+ , toolBarVisible(true)
+ , locationBarVisible(true)
+ , scrollbarsVisible(true)
+ , resizable(true)
+ , fullscreen(false)
+ , dialog(false)
+ {
+ }
+
+ WindowFeatures(const String& windowFeaturesString);
+ WindowFeatures(const String& dialogFeaturesString, const FloatRect& screenAvailableRect);
+
+ float x;
+ bool xSet;
+ float y;
+ bool ySet;
+ float width;
+ bool widthSet;
+ float height;
+ bool heightSet;
+
+ bool menuBarVisible;
+ bool statusBarVisible;
+ bool toolBarVisible;
+ bool locationBarVisible;
+ bool scrollbarsVisible;
+ bool resizable;
+
+ bool fullscreen;
+ bool dialog;
+
+ Vector<String> additionalFeatures;
+
+ // FIXME: We can make these functions private non-member functions once V8 showModalDialog is changed to use DOMWindow.
+ typedef HashMap<String, String> DialogFeaturesMap;
+ static void parseDialogFeatures(const String&, HashMap<String, String>&);
+ static bool boolFeature(const DialogFeaturesMap&, const char* key, bool defaultValue = false);
+ static float floatFeature(const DialogFeaturesMap&, const char* key, float min, float max, float defaultValue);
+
+ private:
+ void setWindowFeature(const String& keyString, const String& valueString);
+ };
+
+} // namespace WebCore
+
+#endif // WindowFeatures_h
diff --git a/Source/WebCore/page/WorkerNavigator.cpp b/Source/WebCore/page/WorkerNavigator.cpp
new file mode 100644
index 0000000..339f107
--- /dev/null
+++ b/Source/WebCore/page/WorkerNavigator.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(WORKERS)
+
+#include "WorkerNavigator.h"
+
+namespace WebCore {
+
+WorkerNavigator::WorkerNavigator(const String& userAgent)
+ : m_userAgent(userAgent)
+{
+}
+
+WorkerNavigator::~WorkerNavigator()
+{
+}
+
+String WorkerNavigator::userAgent() const
+{
+ return m_userAgent;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WORKERS)
diff --git a/Source/WebCore/page/WorkerNavigator.h b/Source/WebCore/page/WorkerNavigator.h
new file mode 100644
index 0000000..8ca2fd9
--- /dev/null
+++ b/Source/WebCore/page/WorkerNavigator.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef WorkerNavigator_h
+#define WorkerNavigator_h
+
+#if ENABLE(WORKERS)
+
+#include "NavigatorBase.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ class WorkerNavigator : public NavigatorBase, public RefCounted<WorkerNavigator> {
+ public:
+ static PassRefPtr<WorkerNavigator> create(const String& userAgent) { return adoptRef(new WorkerNavigator(userAgent)); }
+ virtual ~WorkerNavigator();
+
+ virtual String userAgent() const;
+
+ private:
+ WorkerNavigator(const String&);
+
+ String m_userAgent;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(WORKERS)
+
+#endif // WorkerNavigator_h
diff --git a/Source/WebCore/page/WorkerNavigator.idl b/Source/WebCore/page/WorkerNavigator.idl
new file mode 100644
index 0000000..ec75f8a
--- /dev/null
+++ b/Source/WebCore/page/WorkerNavigator.idl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 threads {
+
+ interface [
+ Conditional=WORKERS,
+ NoStaticTables,
+ OmitConstructor
+ ] WorkerNavigator {
+ readonly attribute DOMString appName;
+ readonly attribute DOMString appVersion;
+ readonly attribute DOMString platform;
+ readonly attribute DOMString userAgent;
+
+ readonly attribute boolean onLine;
+ };
+
+}
diff --git a/Source/WebCore/page/XSSAuditor.cpp b/Source/WebCore/page/XSSAuditor.cpp
new file mode 100644
index 0000000..1b0e83f
--- /dev/null
+++ b/Source/WebCore/page/XSSAuditor.cpp
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2008, 2009 Daniel Bates (dbates@intudata.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "XSSAuditor.h"
+
+#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
+
+#include "Console.h"
+#include "DocumentLoader.h"
+#include "DOMWindow.h"
+#include "Frame.h"
+#include "HTMLEntityParser.h"
+#include "KURL.h"
+#include "ResourceResponseBase.h"
+#include "ScriptSourceCode.h"
+#include "Settings.h"
+#include "TextResourceDecoder.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
+
+namespace WebCore {
+
+static bool isNonCanonicalCharacter(UChar c)
+{
+ // We remove all non-ASCII characters, including non-printable ASCII characters.
+ //
+ // Note, we don't remove backslashes like PHP stripslashes(), which among other things converts "\\0" to the \0 character.
+ // Instead, we remove backslashes and zeros (since the string "\\0" =(remove backslashes)=> "0"). However, this has the
+ // adverse effect that we remove any legitimate zeros from a string.
+ //
+ // For instance: new String("http://localhost:8000") => new String("http://localhost:8").
+ return (c == '\\' || c == '0' || c < ' ' || c >= 127);
+}
+
+static bool isIllegalURICharacter(UChar c)
+{
+ // The characters described in section 2.4.3 of RFC 2396 <http://www.faqs.org/rfcs/rfc2396.html> in addition to the
+ // single quote character "'" are considered illegal URI characters. That is, the following characters cannot appear
+ // in a valid URI: ', ", <, >
+ //
+ // If the request does not contain these characters then we can assume that no inline scripts have been injected
+ // into the response page, because it is impossible to write an inline script of the form <script>...</script>
+ // without "<", ">".
+ return (c == '\'' || c == '"' || c == '<' || c == '>');
+}
+
+String XSSAuditor::CachingURLCanonicalizer::canonicalizeURL(FormData* formData, const TextEncoding& encoding, bool decodeEntities,
+ bool decodeURLEscapeSequencesTwice)
+{
+ if (decodeEntities == m_decodeEntities && decodeURLEscapeSequencesTwice == m_decodeURLEscapeSequencesTwice
+ && encoding == m_encoding && formData == m_formData)
+ return m_cachedCanonicalizedURL;
+ m_formData = formData;
+ return canonicalizeURL(formData->flattenToString(), encoding, decodeEntities, decodeURLEscapeSequencesTwice);
+}
+
+String XSSAuditor::CachingURLCanonicalizer::canonicalizeURL(const String& url, const TextEncoding& encoding, bool decodeEntities,
+ bool decodeURLEscapeSequencesTwice)
+{
+ if (decodeEntities == m_decodeEntities && decodeURLEscapeSequencesTwice == m_decodeURLEscapeSequencesTwice
+ && encoding == m_encoding && url == m_inputURL)
+ return m_cachedCanonicalizedURL;
+
+ m_cachedCanonicalizedURL = canonicalize(decodeURL(url, encoding, decodeEntities, decodeURLEscapeSequencesTwice));
+ m_inputURL = url;
+ m_encoding = encoding;
+ m_decodeEntities = decodeEntities;
+ m_decodeURLEscapeSequencesTwice = decodeURLEscapeSequencesTwice;
+ ++m_generation;
+ return m_cachedCanonicalizedURL;
+}
+
+void XSSAuditor::CachingURLCanonicalizer::clear()
+{
+ m_formData.clear();
+ m_inputURL = String();
+}
+
+XSSAuditor::XSSAuditor(Frame* frame)
+ : m_frame(frame)
+ , m_generationOfSuffixTree(-1)
+{
+}
+
+XSSAuditor::~XSSAuditor()
+{
+}
+
+bool XSSAuditor::isEnabled() const
+{
+ Settings* settings = m_frame->settings();
+ return (settings && settings->xssAuditorEnabled());
+}
+
+bool XSSAuditor::canEvaluate(const String& code) const
+{
+ if (!isEnabled())
+ return true;
+
+ FindTask task;
+ task.string = code;
+ task.decodeEntities = false;
+ task.allowRequestIfNoIllegalURICharacters = true;
+
+ if (findInRequest(task)) {
+ DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n"));
+ m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
+ return false;
+ }
+ return true;
+}
+
+bool XSSAuditor::canEvaluateJavaScriptURL(const String& code) const
+{
+ if (!isEnabled())
+ return true;
+
+ FindTask task;
+ task.string = code;
+ task.decodeURLEscapeSequencesTwice = true;
+
+ if (findInRequest(task)) {
+ DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n"));
+ m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
+ return false;
+ }
+ return true;
+}
+
+bool XSSAuditor::canCreateInlineEventListener(const String&, const String& code) const
+{
+ if (!isEnabled())
+ return true;
+
+ FindTask task;
+ task.string = code;
+ task.allowRequestIfNoIllegalURICharacters = true;
+
+ if (findInRequest(task)) {
+ DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n"));
+ m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
+ return false;
+ }
+ return true;
+}
+
+bool XSSAuditor::canLoadExternalScriptFromSrc(const String& url) const
+{
+ if (!isEnabled())
+ return true;
+
+ if (isSameOriginResource(url))
+ return true;
+
+ FindTask task;
+ task.string = url;
+ task.allowRequestIfNoIllegalURICharacters = true;
+
+ if (findInRequest(task)) {
+ DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n"));
+ m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
+ return false;
+ }
+ return true;
+}
+
+bool XSSAuditor::canLoadObject(const String& url) const
+{
+ if (!isEnabled())
+ return true;
+
+ if (isSameOriginResource(url))
+ return true;
+
+ FindTask task;
+ task.string = url;
+ task.allowRequestIfNoIllegalURICharacters = true;
+
+ if (findInRequest(task)) {
+ String consoleMessage = makeString("Refused to load an object. URL found within request: \"", url, "\".\n");
+ m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
+ return false;
+ }
+ return true;
+}
+
+bool XSSAuditor::canSetBaseElementURL(const String& url) const
+{
+ if (!isEnabled())
+ return true;
+
+ if (isSameOriginResource(url))
+ return true;
+
+ FindTask task;
+ task.string = url;
+ task.allowRequestIfNoIllegalURICharacters = true;
+
+ if (findInRequest(task)) {
+ DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to load from document base URL. URL found within request.\n"));
+ m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
+ return false;
+ }
+ return true;
+}
+
+String XSSAuditor::canonicalize(const String& string)
+{
+ String result = decodeHTMLEntities(string);
+ return result.removeCharacters(&isNonCanonicalCharacter);
+}
+
+String XSSAuditor::decodeURL(const String& string, const TextEncoding& encoding, bool decodeEntities, bool decodeURLEscapeSequencesTwice)
+{
+ String result;
+ String url = string;
+
+ url.replace('+', ' ');
+ result = decodeURLEscapeSequences(url);
+ CString utf8Url = result.utf8();
+ String decodedResult = encoding.decode(utf8Url.data(), utf8Url.length());
+ if (!decodedResult.isEmpty())
+ result = decodedResult;
+ if (decodeURLEscapeSequencesTwice) {
+ result = decodeURLEscapeSequences(result);
+ utf8Url = result.utf8();
+ decodedResult = encoding.decode(utf8Url.data(), utf8Url.length());
+ if (!decodedResult.isEmpty())
+ result = decodedResult;
+ }
+ if (decodeEntities)
+ result = decodeHTMLEntities(result);
+ return result;
+}
+
+String XSSAuditor::decodeHTMLEntities(const String& string, bool leaveUndecodableEntitiesUntouched)
+{
+ SegmentedString source(string);
+ SegmentedString sourceShadow;
+ Vector<UChar> result;
+
+ while (!source.isEmpty()) {
+ UChar cc = *source;
+ source.advance();
+
+ if (cc != '&') {
+ result.append(cc);
+ continue;
+ }
+
+ if (leaveUndecodableEntitiesUntouched)
+ sourceShadow = source;
+ bool notEnoughCharacters = false;
+ Vector<UChar, 16> decodedEntity;
+ bool success = consumeHTMLEntity(source, decodedEntity, notEnoughCharacters);
+ // We ignore notEnoughCharacters because we might as well use this loop
+ // to copy the remaining characters into |result|.
+ if (!success || (!leaveUndecodableEntitiesUntouched && decodedEntity.size() == 1 && decodedEntity[0] == 0xFFFD)) {
+ result.append('&');
+ if (leaveUndecodableEntitiesUntouched)
+ source = sourceShadow;
+ } else {
+ Vector<UChar>::const_iterator iter = decodedEntity.begin();
+ for (; iter != decodedEntity.end(); ++iter)
+ result.append(*iter);
+ }
+ }
+
+ return String::adopt(result);
+}
+
+bool XSSAuditor::isSameOriginResource(const String& url) const
+{
+ // If the resource is loaded from the same URL as the enclosing page, it's
+ // probably not an XSS attack, so we reduce false positives by allowing the
+ // request. If the resource has a query string, we're more suspicious,
+ // however, because that's pretty rare and the attacker might be able to
+ // trick a server-side script into doing something dangerous with the query
+ // string.
+ KURL resourceURL(m_frame->document()->url(), url);
+ return (m_frame->document()->url().host() == resourceURL.host() && resourceURL.query().isEmpty());
+}
+
+XSSProtectionDisposition XSSAuditor::xssProtection() const
+{
+ DEFINE_STATIC_LOCAL(String, XSSProtectionHeader, ("X-XSS-Protection"));
+
+ Frame* frame = m_frame;
+ if (frame->document()->url() == blankURL())
+ frame = m_frame->tree()->parent();
+
+ return parseXSSProtectionHeader(frame->loader()->documentLoader()->response().httpHeaderField(XSSProtectionHeader));
+}
+
+bool XSSAuditor::findInRequest(const FindTask& task) const
+{
+ bool result = false;
+ Frame* parentFrame = m_frame->tree()->parent();
+ Frame* blockFrame = parentFrame;
+ if (parentFrame && m_frame->document()->url() == blankURL())
+ result = findInRequest(parentFrame, task);
+ if (!result) {
+ result = findInRequest(m_frame, task);
+ blockFrame = m_frame;
+ }
+ if (!result)
+ return false;
+
+ switch (xssProtection()) {
+ case XSSProtectionDisabled:
+ return false;
+ case XSSProtectionEnabled:
+ break;
+ case XSSProtectionBlockEnabled:
+ if (blockFrame) {
+ blockFrame->loader()->stopAllLoaders();
+ blockFrame->navigationScheduler()->scheduleLocationChange(blockFrame->document()->securityOrigin(), blankURL(), String());
+ }
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return true;
+}
+
+bool XSSAuditor::findInRequest(Frame* frame, const FindTask& task) const
+{
+ ASSERT(frame->document());
+
+ if (!frame->document()->decoder()) {
+ // Note, JavaScript URLs do not have a charset.
+ return false;
+ }
+
+ if (task.string.isEmpty())
+ return false;
+
+ DocumentLoader *documentLoader = frame->loader()->documentLoader();
+ if (!documentLoader)
+ return false;
+
+ FormData* formDataObj = documentLoader->originalRequest().httpBody();
+ const bool hasFormData = formDataObj && !formDataObj->isEmpty();
+ String pageURL = frame->document()->url().string();
+
+ if (!hasFormData) {
+ // We clear out our form data caches, in case we're holding onto a bunch of memory.
+ m_formDataCache.clear();
+ m_formDataSuffixTree.clear();
+ }
+
+ String canonicalizedString;
+ if (!hasFormData && task.string.length() > 2 * pageURL.length()) {
+ // Q: Why do we bother to do this check at all?
+ // A: Canonicalizing large inline scripts can be expensive. We want to
+ // reduce the size of the string before we call canonicalize below,
+ // since it could result in an unneeded allocation and memcpy.
+ //
+ // Q: Why do we multiply by two here?
+ // A: We attempt to detect reflected XSS even when the server
+ // transforms the attacker's input with addSlashes. The best the
+ // attacker can do get the server to inflate his/her input by a
+ // factor of two by sending " characters, which the server
+ // transforms to \".
+ canonicalizedString = task.string.substring(0, 2 * pageURL.length());
+ } else
+ canonicalizedString = task.string;
+
+ if (frame->document()->url().protocolIsData())
+ return false;
+
+ canonicalizedString = canonicalize(canonicalizedString);
+ if (canonicalizedString.isEmpty())
+ return false;
+
+ if (!task.context.isEmpty())
+ canonicalizedString = task.context + canonicalizedString;
+
+ String decodedPageURL = m_pageURLCache.canonicalizeURL(pageURL, frame->document()->decoder()->encoding(), task.decodeEntities, task.decodeURLEscapeSequencesTwice);
+
+ if (task.allowRequestIfNoIllegalURICharacters && !hasFormData && decodedPageURL.find(&isIllegalURICharacter, 0) == notFound)
+ return false; // Injection is impossible because the request does not contain any illegal URI characters.
+
+ if (decodedPageURL.find(canonicalizedString, 0, false) != notFound)
+ return true; // We've found the string in the GET data.
+
+ if (hasFormData) {
+ String decodedFormData = m_formDataCache.canonicalizeURL(formDataObj, frame->document()->decoder()->encoding(), task.decodeEntities, task.decodeURLEscapeSequencesTwice);
+
+ if (m_generationOfSuffixTree != m_formDataCache.generation()) {
+ m_formDataSuffixTree = new SuffixTree<ASCIICodebook>(decodedFormData, 5);
+ m_generationOfSuffixTree = m_formDataCache.generation();
+ }
+
+ // Try a fast-reject via the suffixTree.
+ if (m_formDataSuffixTree && !m_formDataSuffixTree->mightContain(canonicalizedString))
+ return false;
+
+ if (decodedFormData.find(canonicalizedString, 0, false) != notFound)
+ return true; // We found the string in the POST data.
+ }
+
+ return false;
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/page/XSSAuditor.h b/Source/WebCore/page/XSSAuditor.h
new file mode 100644
index 0000000..2b781f1
--- /dev/null
+++ b/Source/WebCore/page/XSSAuditor.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2008, 2009 Daniel Bates (dbates@intudata.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef XSSAuditor_h
+#define XSSAuditor_h
+
+#include "HTTPParsers.h"
+#include "PlatformString.h"
+#include "SuffixTree.h"
+#include "TextEncoding.h"
+
+namespace WebCore {
+
+ class FormData;
+ class Frame;
+ class ScriptSourceCode;
+
+ // The XSSAuditor class is used to prevent type 1 cross-site scripting
+ // vulnerabilities (also known as reflected vulnerabilities).
+ //
+ // More specifically, the XSSAuditor class decides whether the execution of
+ // a script is to be allowed or denied based on the content of any
+ // user-submitted data, including:
+ //
+ // * the URL.
+ // * the HTTP-POST data.
+ //
+ // If the source code of a script resembles any user-submitted data then it
+ // is denied execution.
+ //
+ // When you instantiate the XSSAuditor you must specify the Frame of the
+ // page that you wish to audit.
+ //
+ // Bindings
+ //
+ // An XSSAuditor is instantiated within the constructor of a
+ // ScriptController object and passed the Frame the script originated. The
+ // ScriptController calls back to the XSSAuditor to determine whether a
+ // JavaScript script is safe to execute before executing it. The following
+ // methods call into XSSAuditor:
+ //
+ // * ScriptController::evaluateInWorld - used to evaluate JavaScript scripts.
+ // * ScriptController::executeIfJavaScriptURL - used to evaluate JavaScript URLs.
+ // * ScriptEventListener::createAttributeEventListener - used to create JavaScript event handlers.
+ // * HTMLBaseElement::process - used to set the document base URL.
+ // * HTMLDocumentParser::shouldLoadExternalScriptFromSrc - used to load external JavaScript scripts.
+ // * SubframeLoader::requestObject - used to load <object>/<embed> elements.
+ //
+ class XSSAuditor : public Noncopyable {
+ public:
+ XSSAuditor(Frame*);
+ ~XSSAuditor();
+
+ bool isEnabled() const;
+
+ // Determines whether the script should be allowed or denied execution
+ // based on the content of any user-submitted data.
+ bool canEvaluate(const String& code) const;
+
+ // Determines whether the JavaScript URL should be allowed or denied execution
+ // based on the content of any user-submitted data.
+ bool canEvaluateJavaScriptURL(const String& code) const;
+
+ // Determines whether the event listener should be created based on the
+ // content of any user-submitted data.
+ bool canCreateInlineEventListener(const String& functionName, const String& code) const;
+
+ // Determines whether the external script should be loaded based on the
+ // content of any user-submitted data.
+ bool canLoadExternalScriptFromSrc(const String& url) const;
+
+ // Determines whether object should be loaded based on the content of
+ // any user-submitted data.
+ //
+ // This method is called by SubframeLoader::requestObject.
+ bool canLoadObject(const String& url) const;
+
+ // Determines whether the base URL should be changed based on the content
+ // of any user-submitted data.
+ //
+ // This method is called by HTMLBaseElement::process.
+ bool canSetBaseElementURL(const String& url) const;
+
+ private:
+ class CachingURLCanonicalizer
+ {
+ public:
+ CachingURLCanonicalizer() : m_decodeEntities(false), m_decodeURLEscapeSequencesTwice(false), m_generation(0) { }
+ String canonicalizeURL(FormData*, const TextEncoding& encoding, bool decodeEntities,
+ bool decodeURLEscapeSequencesTwice);
+ String canonicalizeURL(const String& url, const TextEncoding& encoding, bool decodeEntities,
+ bool decodeURLEscapeSequencesTwice);
+
+ void clear();
+
+ int generation() const { return m_generation; }
+
+ private:
+ // The parameters we were called with last.
+ String m_inputURL;
+ TextEncoding m_encoding;
+ bool m_decodeEntities;
+ bool m_decodeURLEscapeSequencesTwice;
+ RefPtr<FormData> m_formData;
+
+ // Incremented every time we see a new URL.
+ int m_generation;
+
+ // The cached result.
+ String m_cachedCanonicalizedURL;
+ };
+
+ struct FindTask {
+ FindTask()
+ : decodeEntities(true)
+ , allowRequestIfNoIllegalURICharacters(false)
+ , decodeURLEscapeSequencesTwice(false)
+ {
+ }
+
+ String context;
+ String string;
+ bool decodeEntities;
+ bool allowRequestIfNoIllegalURICharacters;
+ bool decodeURLEscapeSequencesTwice;
+ };
+
+ static String canonicalize(const String&);
+ static String decodeURL(const String& url, const TextEncoding& encoding, bool decodeEntities,
+ bool decodeURLEscapeSequencesTwice = false);
+ static String decodeHTMLEntities(const String&, bool leaveUndecodableEntitiesUntouched = true);
+
+ bool isSameOriginResource(const String& url) const;
+ bool findInRequest(const FindTask&) const;
+ bool findInRequest(Frame*, const FindTask&) const;
+
+ XSSProtectionDisposition xssProtection() const;
+
+ // The frame to audit.
+ Frame* m_frame;
+
+ // A state store to help us avoid canonicalizing the same URL repeated.
+ // When a page has form data, we need two caches: one to store the
+ // canonicalized URL and another to store the cannonicalized form
+ // data. If we only had one cache, we'd always generate a cache miss
+ // and load some pages extremely slowly.
+ // https://bugs.webkit.org/show_bug.cgi?id=35373
+ mutable CachingURLCanonicalizer m_pageURLCache;
+ mutable CachingURLCanonicalizer m_formDataCache;
+
+ mutable OwnPtr<SuffixTree<ASCIICodebook> > m_formDataSuffixTree;
+ mutable int m_generationOfSuffixTree;
+ };
+
+} // namespace WebCore
+
+#endif // XSSAuditor_h
diff --git a/Source/WebCore/page/android/DragControllerAndroid.cpp b/Source/WebCore/page/android/DragControllerAndroid.cpp
new file mode 100644
index 0000000..b20ab60
--- /dev/null
+++ b/Source/WebCore/page/android/DragControllerAndroid.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DragController.h"
+
+#include "DragData.h"
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+bool DragController::isCopyKeyDown()
+{
+ return false;
+}
+
+DragOperation DragController::dragOperation(DragData* dragData)
+{
+ // FIXME: This logic is incomplete
+ notImplemented();
+ if (dragData->containsURL())
+ return DragOperationCopy;
+
+ return DragOperationNone;
+}
+
+void DragController::cleanupAfterSystemDrag()
+{
+}
+
+const float DragController::DragImageAlpha = 1.0f;
+static IntSize dummy;
+const IntSize& DragController::maxDragImageSize() { return dummy; }
+const int DragController::DragIconRightInset = 0;
+const int DragController::DragIconBottomInset = 0;
+const int DragController::LinkDragBorderInset = 0;
+const int DragController::MaxOriginalImageArea = 0;
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/android/EventHandlerAndroid.cpp b/Source/WebCore/page/android/EventHandlerAndroid.cpp
new file mode 100644
index 0000000..bdc5f2a
--- /dev/null
+++ b/Source/WebCore/page/android/EventHandlerAndroid.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define LOG_TAG "WebCore"
+
+#include "config.h"
+#include "EventHandler.h"
+
+#include "FocusController.h"
+#include "Frame.h"
+#include "KeyboardEvent.h"
+#include "MouseEventWithHitTestResults.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "RenderWidget.h"
+
+namespace WebCore {
+
+bool EventHandler::tabsToAllControls(KeyboardEvent*) const
+{
+ return true;
+}
+
+void EventHandler::focusDocumentView()
+{
+ if (Page* page = m_frame->page())
+ page->focusController()->setFocusedFrame(m_frame);
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
+{
+ // Figure out which view to send the event to.
+ RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0;
+ if (!target || !target->isWidget())
+ return false;
+ return passMouseDownEventToWidget(toRenderWidget(target)->widget());
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
+{
+ return passMouseDownEventToWidget(renderWidget->widget());
+}
+
+// This function is used to route the mouse down event to the native widgets, it seems like a
+// work around for the Mac platform which does not support double clicks, but browsers do.
+bool EventHandler::passMouseDownEventToWidget(Widget*)
+{
+ // return false so the normal propogation handles the event
+ return false;
+}
+
+bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const
+{
+ notImplemented();
+ return false;
+}
+
+// This is called to route wheel events to child widgets when they are RenderWidget
+// as the parent usually gets wheel event. Don't have a mouse with a wheel to confirm
+// the operation of this function.
+bool EventHandler::passWheelEventToWidget(PlatformWheelEvent&, Widget*)
+{
+ notImplemented();
+ return false;
+}
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMousePressEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev,
+ Frame* subframe, HitTestResult* hoveredNode)
+{
+ subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
+ return true;
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
+ return true;
+}
+
+class Clipboard : public RefCounted<Clipboard> {
+};
+
+PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
+{
+ return PassRefPtr<Clipboard>(0);
+}
+
+unsigned EventHandler::accessKeyModifiers()
+{
+ return PlatformKeyboardEvent::AltKey;
+}
+
+const double EventHandler::TextDragDelay = 0.0;
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/animation/AnimationBase.cpp b/Source/WebCore/page/animation/AnimationBase.cpp
new file mode 100644
index 0000000..14a44d2
--- /dev/null
+++ b/Source/WebCore/page/animation/AnimationBase.cpp
@@ -0,0 +1,1399 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "AnimationBase.h"
+
+#include "AnimationControllerPrivate.h"
+#include "CSSMutableStyleDeclaration.h"
+#include "CSSPropertyLonghand.h"
+#include "CSSPropertyNames.h"
+#include "CompositeAnimation.h"
+#include "Document.h"
+#include "EventNames.h"
+#include "FloatConversion.h"
+#include "Frame.h"
+#include "IdentityTransformOperation.h"
+#include "ImplicitAnimation.h"
+#include "KeyframeAnimation.h"
+#include "MatrixTransformOperation.h"
+#include "Matrix3DTransformOperation.h"
+#include "RenderBox.h"
+#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
+#include "RenderStyle.h"
+#include "UnitBezier.h"
+#include <algorithm>
+#include <wtf/CurrentTime.h>
+
+using namespace std;
+
+namespace WebCore {
+
+// The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. The longer the
+// animation, the more precision we need in the timing function result to avoid ugly discontinuities.
+static inline double solveEpsilon(double duration)
+{
+ return 1.0 / (200.0 * duration);
+}
+
+static inline double solveCubicBezierFunction(double p1x, double p1y, double p2x, double p2y, double t, double duration)
+{
+ // Convert from input time to parametric value in curve, then from
+ // that to output time.
+ UnitBezier bezier(p1x, p1y, p2x, p2y);
+ return bezier.solve(t, solveEpsilon(duration));
+}
+
+static inline double solveStepsFunction(int numSteps, bool stepAtStart, double t)
+{
+ if (stepAtStart)
+ return min(1.0, (floor(numSteps * t) + 1) / numSteps);
+ return floor(numSteps * t) / numSteps;
+}
+
+static inline int blendFunc(const AnimationBase*, int from, int to, double progress)
+{
+ return int(from + (to - from) * progress);
+}
+
+static inline double blendFunc(const AnimationBase*, double from, double to, double progress)
+{
+ return from + (to - from) * progress;
+}
+
+static inline float blendFunc(const AnimationBase*, float from, float to, double progress)
+{
+ return narrowPrecisionToFloat(from + (to - from) * progress);
+}
+
+static inline Color blendFunc(const AnimationBase* anim, const Color& from, const Color& to, double progress)
+{
+ // We need to preserve the state of the valid flag at the end of the animation
+ if (progress == 1 && !to.isValid())
+ return Color();
+
+ // Contrary to the name, RGBA32 actually stores ARGB, so we can initialize Color directly from premultipliedARGBFromColor().
+ // Also, premultipliedARGBFromColor() bails on zero alpha, so special-case that.
+ Color premultFrom = from.alpha() ? premultipliedARGBFromColor(from) : 0;
+ Color premultTo = to.alpha() ? premultipliedARGBFromColor(to) : 0;
+
+ Color premultBlended(blendFunc(anim, premultFrom.red(), premultTo.red(), progress),
+ blendFunc(anim, premultFrom.green(), premultTo.green(), progress),
+ blendFunc(anim, premultFrom.blue(), premultTo.blue(), progress),
+ blendFunc(anim, premultFrom.alpha(), premultTo.alpha(), progress));
+
+ return Color(colorFromPremultipliedARGB(premultBlended.rgb()));
+}
+
+static inline Length blendFunc(const AnimationBase*, const Length& from, const Length& to, double progress)
+{
+ return to.blend(from, progress);
+}
+
+static inline LengthSize blendFunc(const AnimationBase* anim, const LengthSize& from, const LengthSize& to, double progress)
+{
+ return LengthSize(blendFunc(anim, from.width(), to.width(), progress),
+ blendFunc(anim, from.height(), to.height(), progress));
+}
+
+static inline IntSize blendFunc(const AnimationBase* anim, const IntSize& from, const IntSize& to, double progress)
+{
+ return IntSize(blendFunc(anim, from.width(), to.width(), progress),
+ blendFunc(anim, from.height(), to.height(), progress));
+}
+
+static inline ShadowStyle blendFunc(const AnimationBase* anim, ShadowStyle from, ShadowStyle to, double progress)
+{
+ if (from == to)
+ return to;
+
+ double fromVal = from == Normal ? 1 : 0;
+ double toVal = to == Normal ? 1 : 0;
+ double result = blendFunc(anim, fromVal, toVal, progress);
+ return result > 0 ? Normal : Inset;
+}
+
+static inline ShadowData* blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress)
+{
+ ASSERT(from && to);
+ return new ShadowData(blendFunc(anim, from->x(), to->x(), progress),
+ blendFunc(anim, from->y(), to->y(), progress),
+ blendFunc(anim, from->blur(), to->blur(), progress),
+ blendFunc(anim, from->spread(), to->spread(), progress),
+ blendFunc(anim, from->style(), to->style(), progress),
+ from->isWebkitBoxShadow(),
+ blendFunc(anim, from->color(), to->color(), progress));
+}
+
+static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress)
+{
+ TransformOperations result;
+
+ // If we have a transform function list, use that to do a per-function animation. Otherwise do a Matrix animation
+ if (anim->isTransformFunctionListValid()) {
+ unsigned fromSize = from.operations().size();
+ unsigned toSize = to.operations().size();
+ unsigned size = max(fromSize, toSize);
+ for (unsigned i = 0; i < size; i++) {
+ RefPtr<TransformOperation> fromOp = (i < fromSize) ? from.operations()[i].get() : 0;
+ RefPtr<TransformOperation> toOp = (i < toSize) ? to.operations()[i].get() : 0;
+ RefPtr<TransformOperation> blendedOp = toOp ? toOp->blend(fromOp.get(), progress) : (fromOp ? fromOp->blend(0, progress, true) : 0);
+ if (blendedOp)
+ result.operations().append(blendedOp);
+ else {
+ RefPtr<TransformOperation> identityOp = IdentityTransformOperation::create();
+ if (progress > 0.5)
+ result.operations().append(toOp ? toOp : identityOp);
+ else
+ result.operations().append(fromOp ? fromOp : identityOp);
+ }
+ }
+ } else {
+ // Convert the TransformOperations into matrices
+ IntSize size = anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : IntSize();
+ TransformationMatrix fromT;
+ TransformationMatrix toT;
+ from.apply(size, fromT);
+ to.apply(size, toT);
+
+ toT.blend(fromT, progress);
+
+ // Append the result
+ result.operations().append(Matrix3DTransformOperation::create(toT));
+ }
+ return result;
+}
+
+static inline EVisibility blendFunc(const AnimationBase* anim, EVisibility from, EVisibility to, double progress)
+{
+ // Any non-zero result means we consider the object to be visible. Only at 0 do we consider the object to be
+ // invisible. The invisible value we use (HIDDEN vs. COLLAPSE) depends on the specified from/to values.
+ double fromVal = from == VISIBLE ? 1. : 0.;
+ double toVal = to == VISIBLE ? 1. : 0.;
+ if (fromVal == toVal)
+ return to;
+ double result = blendFunc(anim, fromVal, toVal, progress);
+ return result > 0. ? VISIBLE : (to != VISIBLE ? to : from);
+}
+
+static inline LengthBox blendFunc(const AnimationBase* anim, const LengthBox& from, const LengthBox& to, double progress)
+{
+ // Length types have to match to animate
+ if (from.top().type() != to.top().type()
+ || from.right().type() != to.right().type()
+ || from.bottom().type() != to.bottom().type()
+ || from.left().type() != to.left().type())
+ return to;
+
+ LengthBox result(blendFunc(anim, from.top(), to.top(), progress),
+ blendFunc(anim, from.right(), to.right(), progress),
+ blendFunc(anim, from.bottom(), to.bottom(), progress),
+ blendFunc(anim, from.left(), to.left(), progress));
+ return result;
+}
+
+class PropertyWrapperBase;
+
+static void addShorthandProperties();
+static PropertyWrapperBase* wrapperForProperty(int propertyID);
+
+class PropertyWrapperBase : public Noncopyable {
+public:
+ PropertyWrapperBase(int prop)
+ : m_prop(prop)
+ {
+ }
+
+ virtual ~PropertyWrapperBase() { }
+
+ virtual bool isShorthandWrapper() const { return false; }
+ virtual bool equals(const RenderStyle* a, const RenderStyle* b) const = 0;
+ virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const = 0;
+
+ int property() const { return m_prop; }
+
+#if USE(ACCELERATED_COMPOSITING)
+ virtual bool animationIsAccelerated() const { return false; }
+#endif
+
+private:
+ int m_prop;
+};
+
+template <typename T>
+class PropertyWrapperGetter : public PropertyWrapperBase {
+public:
+ PropertyWrapperGetter(int prop, T (RenderStyle::*getter)() const)
+ : PropertyWrapperBase(prop)
+ , m_getter(getter)
+ {
+ }
+
+ virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ {
+ // If the style pointers are the same, don't bother doing the test.
+ // If either is null, return false. If both are null, return true.
+ if ((!a && !b) || a == b)
+ return true;
+ if (!a || !b)
+ return false;
+ return (a->*m_getter)() == (b->*m_getter)();
+ }
+
+protected:
+ T (RenderStyle::*m_getter)() const;
+};
+
+template <typename T>
+class PropertyWrapper : public PropertyWrapperGetter<T> {
+public:
+ PropertyWrapper(int prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T))
+ : PropertyWrapperGetter<T>(prop, getter)
+ , m_setter(setter)
+ {
+ }
+
+ virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ {
+ (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), progress));
+ }
+
+protected:
+ void (RenderStyle::*m_setter)(T);
+};
+
+#if USE(ACCELERATED_COMPOSITING)
+class PropertyWrapperAcceleratedOpacity : public PropertyWrapper<float> {
+public:
+ PropertyWrapperAcceleratedOpacity()
+ : PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity)
+ {
+ }
+
+ virtual bool animationIsAccelerated() const { return true; }
+
+ virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ {
+ float fromOpacity = a->opacity();
+
+ // This makes sure we put the object being animated into a RenderLayer during the animation
+ dst->setOpacity(blendFunc(anim, (fromOpacity == 1) ? 0.999999f : fromOpacity, b->opacity(), progress));
+ }
+};
+
+class PropertyWrapperAcceleratedTransform : public PropertyWrapper<const TransformOperations&> {
+public:
+ PropertyWrapperAcceleratedTransform()
+ : PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform)
+ {
+ }
+
+ virtual bool animationIsAccelerated() const { return true; }
+
+ virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ {
+ dst->setTransform(blendFunc(anim, a->transform(), b->transform(), progress));
+ }
+};
+#endif // USE(ACCELERATED_COMPOSITING)
+
+class PropertyWrapperShadow : public PropertyWrapperBase {
+public:
+ PropertyWrapperShadow(int prop, const ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(ShadowData*, bool))
+ : PropertyWrapperBase(prop)
+ , m_getter(getter)
+ , m_setter(setter)
+ {
+ }
+
+ virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ {
+ const ShadowData* shadowA = (a->*m_getter)();
+ const ShadowData* shadowB = (b->*m_getter)();
+
+ while (true) {
+ if (!shadowA && !shadowB) // end of both lists
+ return true;
+
+ if (!shadowA || !shadowB) // end of just one of the lists
+ return false;
+
+ if (*shadowA != *shadowB)
+ return false;
+
+ shadowA = shadowA->next();
+ shadowB = shadowB->next();
+ }
+
+ return true;
+ }
+
+ virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ {
+ const ShadowData* shadowA = (a->*m_getter)();
+ const ShadowData* shadowB = (b->*m_getter)();
+ ShadowData defaultShadowData(0, 0, 0, 0, Normal, property() == CSSPropertyWebkitBoxShadow, Color::transparent);
+
+ ShadowData* newShadowData = 0;
+ ShadowData* lastShadow = 0;
+
+ while (shadowA || shadowB) {
+ const ShadowData* srcShadow = shadowA ? shadowA : &defaultShadowData;
+ const ShadowData* dstShadow = shadowB ? shadowB : &defaultShadowData;
+
+ ShadowData* blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress);
+ if (!lastShadow)
+ newShadowData = blendedShadow;
+ else
+ lastShadow->setNext(blendedShadow);
+
+ lastShadow = blendedShadow;
+
+ shadowA = shadowA ? shadowA->next() : 0;
+ shadowB = shadowB ? shadowB->next() : 0;
+ }
+
+ (dst->*m_setter)(newShadowData, false);
+ }
+
+private:
+ const ShadowData* (RenderStyle::*m_getter)() const;
+ void (RenderStyle::*m_setter)(ShadowData*, bool);
+};
+
+class PropertyWrapperMaybeInvalidColor : public PropertyWrapperBase {
+public:
+ PropertyWrapperMaybeInvalidColor(int prop, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
+ : PropertyWrapperBase(prop)
+ , m_getter(getter)
+ , m_setter(setter)
+ {
+ }
+
+ virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ {
+ Color fromColor = (a->*m_getter)();
+ Color toColor = (b->*m_getter)();
+
+ if (!fromColor.isValid() && !toColor.isValid())
+ return true;
+
+ if (!fromColor.isValid())
+ fromColor = a->color();
+ if (!toColor.isValid())
+ toColor = b->color();
+
+ return fromColor == toColor;
+ }
+
+ virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ {
+ Color fromColor = (a->*m_getter)();
+ Color toColor = (b->*m_getter)();
+
+ if (!fromColor.isValid() && !toColor.isValid())
+ return;
+
+ if (!fromColor.isValid())
+ fromColor = a->color();
+ if (!toColor.isValid())
+ toColor = b->color();
+ (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
+ }
+
+private:
+ const Color& (RenderStyle::*m_getter)() const;
+ void (RenderStyle::*m_setter)(const Color&);
+};
+
+// Wrapper base class for an animatable property in a FillLayer
+class FillLayerPropertyWrapperBase {
+public:
+ FillLayerPropertyWrapperBase()
+ {
+ }
+
+ virtual ~FillLayerPropertyWrapperBase() { }
+
+ virtual bool equals(const FillLayer* a, const FillLayer* b) const = 0;
+ virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const = 0;
+};
+
+template <typename T>
+class FillLayerPropertyWrapperGetter : public FillLayerPropertyWrapperBase, public Noncopyable {
+public:
+ FillLayerPropertyWrapperGetter(T (FillLayer::*getter)() const)
+ : m_getter(getter)
+ {
+ }
+
+ virtual bool equals(const FillLayer* a, const FillLayer* b) const
+ {
+ // If the style pointers are the same, don't bother doing the test.
+ // If either is null, return false. If both are null, return true.
+ if ((!a && !b) || a == b)
+ return true;
+ if (!a || !b)
+ return false;
+ return (a->*m_getter)() == (b->*m_getter)();
+ }
+
+protected:
+ T (FillLayer::*m_getter)() const;
+};
+
+template <typename T>
+class FillLayerPropertyWrapper : public FillLayerPropertyWrapperGetter<T> {
+public:
+ FillLayerPropertyWrapper(T (FillLayer::*getter)() const, void (FillLayer::*setter)(T))
+ : FillLayerPropertyWrapperGetter<T>(getter)
+ , m_setter(setter)
+ {
+ }
+
+ virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const
+ {
+ (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T>::m_getter)(), progress));
+ }
+
+protected:
+ void (FillLayer::*m_setter)(T);
+};
+
+
+class FillLayersPropertyWrapper : public PropertyWrapperBase {
+public:
+ typedef const FillLayer* (RenderStyle::*LayersGetter)() const;
+ typedef FillLayer* (RenderStyle::*LayersAccessor)();
+
+ FillLayersPropertyWrapper(int prop, LayersGetter getter, LayersAccessor accessor)
+ : PropertyWrapperBase(prop)
+ , m_layersGetter(getter)
+ , m_layersAccessor(accessor)
+ {
+ switch (prop) {
+ case CSSPropertyBackgroundPositionX:
+ case CSSPropertyWebkitMaskPositionX:
+ m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::xPosition, &FillLayer::setXPosition);
+ break;
+ case CSSPropertyBackgroundPositionY:
+ case CSSPropertyWebkitMaskPositionY:
+ m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::yPosition, &FillLayer::setYPosition);
+ break;
+ case CSSPropertyBackgroundSize:
+ case CSSPropertyWebkitBackgroundSize:
+ case CSSPropertyWebkitMaskSize:
+ m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<LengthSize>(&FillLayer::sizeLength, &FillLayer::setSizeLength);
+ break;
+ }
+ }
+
+ virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ {
+ const FillLayer* fromLayer = (a->*m_layersGetter)();
+ const FillLayer* toLayer = (b->*m_layersGetter)();
+
+ while (fromLayer && toLayer) {
+ if (!m_fillLayerPropertyWrapper->equals(fromLayer, toLayer))
+ return false;
+
+ fromLayer = fromLayer->next();
+ toLayer = toLayer->next();
+ }
+
+ return true;
+ }
+
+ virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ {
+ const FillLayer* aLayer = (a->*m_layersGetter)();
+ const FillLayer* bLayer = (b->*m_layersGetter)();
+ FillLayer* dstLayer = (dst->*m_layersAccessor)();
+
+ while (aLayer && bLayer && dstLayer) {
+ m_fillLayerPropertyWrapper->blend(anim, dstLayer, aLayer, bLayer, progress);
+ aLayer = aLayer->next();
+ bLayer = bLayer->next();
+ dstLayer = dstLayer->next();
+ }
+ }
+
+private:
+ FillLayerPropertyWrapperBase* m_fillLayerPropertyWrapper;
+
+ LayersGetter m_layersGetter;
+ LayersAccessor m_layersAccessor;
+};
+
+class ShorthandPropertyWrapper : public PropertyWrapperBase {
+public:
+ ShorthandPropertyWrapper(int property, const CSSPropertyLonghand& longhand)
+ : PropertyWrapperBase(property)
+ {
+ for (unsigned i = 0; i < longhand.length(); ++i) {
+ PropertyWrapperBase* wrapper = wrapperForProperty(longhand.properties()[i]);
+ if (wrapper)
+ m_propertyWrappers.append(wrapper);
+ }
+ }
+
+ virtual bool isShorthandWrapper() const { return true; }
+
+ virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ {
+ Vector<PropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
+ for (Vector<PropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) {
+ if (!(*it)->equals(a, b))
+ return false;
+ }
+ return true;
+ }
+
+ virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ {
+ Vector<PropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
+ for (Vector<PropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it)
+ (*it)->blend(anim, dst, a, b, progress);
+ }
+
+ const Vector<PropertyWrapperBase*> propertyWrappers() const { return m_propertyWrappers; }
+
+private:
+ Vector<PropertyWrapperBase*> m_propertyWrappers;
+};
+
+
+static Vector<PropertyWrapperBase*>* gPropertyWrappers = 0;
+static int gPropertyWrapperMap[numCSSProperties];
+
+static const int cInvalidPropertyWrapperIndex = -1;
+
+
+void AnimationBase::ensurePropertyMap()
+{
+ // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed?
+ if (gPropertyWrappers == 0) {
+ gPropertyWrappers = new Vector<PropertyWrapperBase*>();
+
+ // build the list of property wrappers to do the comparisons and blends
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLeft, &RenderStyle::left, &RenderStyle::setLeft));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom));
+
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinWidth, &RenderStyle::minWidth, &RenderStyle::setMinWidth));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxWidth, &RenderStyle::maxWidth, &RenderStyle::setMaxWidth));
+
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinHeight, &RenderStyle::minHeight, &RenderStyle::setMinHeight));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxHeight, &RenderStyle::maxHeight, &RenderStyle::setMaxHeight));
+
+ gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth));
+ gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth));
+ gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth));
+ gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginBottom, &RenderStyle::marginBottom, &RenderStyle::setMarginBottom));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingLeft, &RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingRight, &RenderStyle::paddingRight, &RenderStyle::setPaddingRight));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingTop, &RenderStyle::paddingTop, &RenderStyle::setPaddingTop));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingBottom, &RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom));
+ gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor));
+
+ gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor));
+
+ gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
+ gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
+ gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
+ gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
+
+ gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
+ gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
+ gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
+
+ gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyFontSize, &RenderStyle::fontSize, &RenderStyle::setBlendedFontSize));
+ gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth));
+ gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap));
+ gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount));
+ gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth));
+ gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing));
+ gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing));
+ gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::lineHeight, &RenderStyle::setLineHeight));
+ gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset));
+ gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth));
+ gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing));
+ gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent));
+
+ gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY));
+ gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ));
+ gPropertyWrappers->append(new PropertyWrapper<const LengthSize&>(CSSPropertyBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius));
+ gPropertyWrappers->append(new PropertyWrapper<const LengthSize&>(CSSPropertyBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius));
+ gPropertyWrappers->append(new PropertyWrapper<const LengthSize&>(CSSPropertyBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius));
+ gPropertyWrappers->append(new PropertyWrapper<const LengthSize&>(CSSPropertyBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius));
+ gPropertyWrappers->append(new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility));
+ gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoom));
+
+ gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyClip, &RenderStyle::clip, &RenderStyle::setClip));
+
+#if USE(ACCELERATED_COMPOSITING)
+ gPropertyWrappers->append(new PropertyWrapperAcceleratedOpacity());
+ gPropertyWrappers->append(new PropertyWrapperAcceleratedTransform());
+#else
+ gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity));
+ gPropertyWrappers->append(new PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform));
+#endif
+
+ gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitColumnRuleColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor));
+ gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextStrokeColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor));
+ gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextFillColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor));
+ gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderLeftColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor));
+ gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderRightColor, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor));
+ gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderTopColor, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor));
+ gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderBottomColor, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor));
+ gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyOutlineColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor));
+
+ gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
+ gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
+ gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow));
+
+#if ENABLE(SVG)
+ gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFillOpacity, &RenderStyle::fillOpacity, &RenderStyle::setFillOpacity));
+ gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFloodOpacity, &RenderStyle::floodOpacity, &RenderStyle::setFloodOpacity));
+ gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeOpacity, &RenderStyle::strokeOpacity, &RenderStyle::setStrokeOpacity));
+#endif
+
+ // TODO:
+ //
+ // CSSPropertyVerticalAlign
+ //
+ // Compound properties that have components that should be animatable:
+ //
+ // CSSPropertyWebkitColumns
+ // CSSPropertyWebkitBoxReflect
+
+ // Make sure unused slots have a value
+ for (unsigned int i = 0; i < static_cast<unsigned int>(numCSSProperties); ++i)
+ gPropertyWrapperMap[i] = cInvalidPropertyWrapperIndex;
+
+ // First we put the non-shorthand property wrappers into the map, so the shorthand-building
+ // code can find them.
+ size_t n = gPropertyWrappers->size();
+ for (unsigned int i = 0; i < n; ++i) {
+ ASSERT((*gPropertyWrappers)[i]->property() - firstCSSProperty < numCSSProperties);
+ gPropertyWrapperMap[(*gPropertyWrappers)[i]->property() - firstCSSProperty] = i;
+ }
+
+ // Now add the shorthand wrappers.
+ addShorthandProperties();
+ }
+}
+
+static void addPropertyWrapper(int propertyID, PropertyWrapperBase* wrapper)
+{
+ int propIndex = propertyID - firstCSSProperty;
+
+ ASSERT(gPropertyWrapperMap[propIndex] == cInvalidPropertyWrapperIndex);
+
+ unsigned wrapperIndex = gPropertyWrappers->size();
+ gPropertyWrappers->append(wrapper);
+ gPropertyWrapperMap[propIndex] = wrapperIndex;
+}
+
+static void addShorthandProperties()
+{
+ static const int animatableShorthandProperties[] = {
+ CSSPropertyBackground, // for background-color, background-position
+ CSSPropertyBackgroundPosition,
+ CSSPropertyWebkitMask, // for mask-position
+ CSSPropertyWebkitMaskPosition,
+ CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft,
+ CSSPropertyBorderColor,
+ CSSPropertyBorderRadius,
+ CSSPropertyBorderWidth,
+ CSSPropertyBorder,
+ CSSPropertyBorderSpacing,
+ CSSPropertyMargin,
+ CSSPropertyOutline,
+ CSSPropertyPadding,
+ CSSPropertyWebkitTextStroke,
+ CSSPropertyWebkitColumnRule,
+ CSSPropertyWebkitBorderRadius,
+ CSSPropertyWebkitTransformOrigin
+ };
+
+ for (size_t i = 0; i < WTF_ARRAY_LENGTH(animatableShorthandProperties); ++i) {
+ int propertyID = animatableShorthandProperties[i];
+ CSSPropertyLonghand longhand = longhandForProperty(propertyID);
+ if (longhand.length() > 0)
+ addPropertyWrapper(propertyID, new ShorthandPropertyWrapper(propertyID, longhand));
+ }
+
+ // 'font' is not in the shorthand map.
+ static const int animatableFontProperties[] = {
+ CSSPropertyFontSize,
+ CSSPropertyFontWeight
+ };
+
+ CSSPropertyLonghand fontLonghand(animatableFontProperties, WTF_ARRAY_LENGTH(animatableFontProperties));
+ addPropertyWrapper(CSSPropertyFont, new ShorthandPropertyWrapper(CSSPropertyFont, fontLonghand));
+}
+
+static PropertyWrapperBase* wrapperForProperty(int propertyID)
+{
+ int propIndex = propertyID - firstCSSProperty;
+ if (propIndex >= 0 && propIndex < numCSSProperties) {
+ int wrapperIndex = gPropertyWrapperMap[propIndex];
+ if (wrapperIndex >= 0)
+ return (*gPropertyWrappers)[wrapperIndex];
+ }
+ return 0;
+}
+
+AnimationBase::AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim)
+ : m_animState(AnimationStateNew)
+ , m_isAnimating(false)
+ , m_startTime(0)
+ , m_pauseTime(-1)
+ , m_requestedStartTime(0)
+ , m_object(renderer)
+ , m_animation(const_cast<Animation*>(transition))
+ , m_compAnim(compAnim)
+ , m_isAccelerated(false)
+ , m_transformFunctionListValid(false)
+ , m_nextIterationDuration(-1)
+ , m_next(0)
+{
+ // Compute the total duration
+ m_totalDuration = -1;
+ if (m_animation->iterationCount() > 0)
+ m_totalDuration = m_animation->duration() * m_animation->iterationCount();
+}
+
+AnimationBase::~AnimationBase()
+{
+ m_compAnim->animationController()->removeFromStyleAvailableWaitList(this);
+ m_compAnim->animationController()->removeFromStartTimeResponseWaitList(this);
+}
+
+bool AnimationBase::propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b)
+{
+ ensurePropertyMap();
+ if (prop == cAnimateAll) {
+ size_t n = gPropertyWrappers->size();
+ for (unsigned int i = 0; i < n; ++i) {
+ PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i];
+ // No point comparing shorthand wrappers for 'all'.
+ if (!wrapper->isShorthandWrapper() && !wrapper->equals(a, b))
+ return false;
+ }
+ } else {
+ PropertyWrapperBase* wrapper = wrapperForProperty(prop);
+ if (wrapper)
+ return wrapper->equals(a, b);
+ }
+ return true;
+}
+
+int AnimationBase::getPropertyAtIndex(int i, bool& isShorthand)
+{
+ ensurePropertyMap();
+ if (i < 0 || i >= static_cast<int>(gPropertyWrappers->size()))
+ return CSSPropertyInvalid;
+
+ PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i];
+ isShorthand = wrapper->isShorthandWrapper();
+ return wrapper->property();
+}
+
+int AnimationBase::getNumProperties()
+{
+ ensurePropertyMap();
+ return gPropertyWrappers->size();
+}
+
+// Returns true if we need to start animation timers
+bool AnimationBase::blendProperties(const AnimationBase* anim, int prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress)
+{
+ ASSERT(prop != cAnimateAll);
+
+ ensurePropertyMap();
+ PropertyWrapperBase* wrapper = wrapperForProperty(prop);
+ if (wrapper) {
+ wrapper->blend(anim, dst, a, b, progress);
+#if USE(ACCELERATED_COMPOSITING)
+ return !wrapper->animationIsAccelerated() || !anim->isAccelerated();
+#else
+ return true;
+#endif
+ }
+
+ return false;
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+bool AnimationBase::animationOfPropertyIsAccelerated(int prop)
+{
+ ensurePropertyMap();
+ PropertyWrapperBase* wrapper = wrapperForProperty(prop);
+ return wrapper ? wrapper->animationIsAccelerated() : false;
+}
+#endif
+
+static bool gatherEnclosingShorthandProperties(int property, PropertyWrapperBase* wrapper, HashSet<int>& propertySet)
+{
+ if (!wrapper->isShorthandWrapper())
+ return false;
+
+ ShorthandPropertyWrapper* shorthandWrapper = static_cast<ShorthandPropertyWrapper*>(wrapper);
+
+ bool contained = false;
+ for (size_t i = 0; i < shorthandWrapper->propertyWrappers().size(); ++i) {
+ PropertyWrapperBase* currWrapper = shorthandWrapper->propertyWrappers()[i];
+
+ if (gatherEnclosingShorthandProperties(property, currWrapper, propertySet) || currWrapper->property() == property)
+ contained = true;
+ }
+
+ if (contained)
+ propertySet.add(wrapper->property());
+
+ return contained;
+}
+
+// Note: this is inefficient. It's only called from pauseTransitionAtTime().
+HashSet<int> AnimationBase::animatableShorthandsAffectingProperty(int property)
+{
+ ensurePropertyMap();
+
+ HashSet<int> foundProperties;
+ for (int i = 0; i < getNumProperties(); ++i)
+ gatherEnclosingShorthandProperties(property, (*gPropertyWrappers)[i], foundProperties);
+
+ return foundProperties;
+}
+
+void AnimationBase::setNeedsStyleRecalc(Node* node)
+{
+ ASSERT(!node || (node->document() && !node->document()->inPageCache()));
+ if (node)
+ node->setNeedsStyleRecalc(SyntheticStyleChange);
+}
+
+double AnimationBase::duration() const
+{
+ return m_animation->duration();
+}
+
+bool AnimationBase::playStatePlaying() const
+{
+ return m_animation->playState() == AnimPlayStatePlaying;
+}
+
+bool AnimationBase::animationsMatch(const Animation* anim) const
+{
+ return m_animation->animationsMatch(anim);
+}
+
+void AnimationBase::updateStateMachine(AnimStateInput input, double param)
+{
+ // If we get AnimationStateInputRestartAnimation then we force a new animation, regardless of state.
+ if (input == AnimationStateInputMakeNew) {
+ if (m_animState == AnimationStateStartWaitStyleAvailable)
+ m_compAnim->animationController()->removeFromStyleAvailableWaitList(this);
+ m_animState = AnimationStateNew;
+ m_startTime = 0;
+ m_pauseTime = -1;
+ m_requestedStartTime = 0;
+ m_nextIterationDuration = -1;
+ endAnimation();
+ return;
+ }
+
+ if (input == AnimationStateInputRestartAnimation) {
+ if (m_animState == AnimationStateStartWaitStyleAvailable)
+ m_compAnim->animationController()->removeFromStyleAvailableWaitList(this);
+ m_animState = AnimationStateNew;
+ m_startTime = 0;
+ m_pauseTime = -1;
+ m_requestedStartTime = 0;
+ m_nextIterationDuration = -1;
+ endAnimation();
+
+ if (!paused())
+ updateStateMachine(AnimationStateInputStartAnimation, -1);
+ return;
+ }
+
+ if (input == AnimationStateInputEndAnimation) {
+ if (m_animState == AnimationStateStartWaitStyleAvailable)
+ m_compAnim->animationController()->removeFromStyleAvailableWaitList(this);
+ m_animState = AnimationStateDone;
+ endAnimation();
+ return;
+ }
+
+ if (input == AnimationStateInputPauseOverride) {
+ if (m_animState == AnimationStateStartWaitResponse) {
+ // If we are in AnimationStateStartWaitResponse, the animation will get canceled before
+ // we get a response, so move to the next state.
+ endAnimation();
+ updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
+ }
+ return;
+ }
+
+ if (input == AnimationStateInputResumeOverride) {
+ if (m_animState == AnimationStateLooping || m_animState == AnimationStateEnding) {
+ // Start the animation
+ startAnimation(beginAnimationUpdateTime() - m_startTime);
+ }
+ return;
+ }
+
+ // Execute state machine
+ switch (m_animState) {
+ case AnimationStateNew:
+ ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning || input == AnimationStateInputPlayStatePaused);
+ if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning) {
+ m_requestedStartTime = beginAnimationUpdateTime();
+ m_animState = AnimationStateStartWaitTimer;
+ }
+ break;
+ case AnimationStateStartWaitTimer:
+ ASSERT(input == AnimationStateInputStartTimerFired || input == AnimationStateInputPlayStatePaused);
+
+ if (input == AnimationStateInputStartTimerFired) {
+ ASSERT(param >= 0);
+ // Start timer has fired, tell the animation to start and wait for it to respond with start time
+ m_animState = AnimationStateStartWaitStyleAvailable;
+ m_compAnim->animationController()->addToStyleAvailableWaitList(this);
+
+ // Trigger a render so we can start the animation
+ if (m_object)
+ m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
+ } else {
+ ASSERT(!paused());
+ // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait
+ m_pauseTime = beginAnimationUpdateTime();
+ m_animState = AnimationStatePausedWaitTimer;
+ }
+ break;
+ case AnimationStateStartWaitStyleAvailable:
+ ASSERT(input == AnimationStateInputStyleAvailable || input == AnimationStateInputPlayStatePaused);
+
+ if (input == AnimationStateInputStyleAvailable) {
+ // Start timer has fired, tell the animation to start and wait for it to respond with start time
+ m_animState = AnimationStateStartWaitResponse;
+
+ overrideAnimations();
+
+ // Start the animation
+ if (overridden()) {
+ // We won't try to start accelerated animations if we are overridden and
+ // just move on to the next state.
+ m_animState = AnimationStateStartWaitResponse;
+ m_isAccelerated = false;
+ updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
+ } else {
+ double timeOffset = 0;
+ // If the value for 'animation-delay' is negative then the animation appears to have started in the past.
+ if (m_animation->delay() < 0)
+ timeOffset = -m_animation->delay();
+ bool started = startAnimation(timeOffset);
+
+ m_compAnim->animationController()->addToStartTimeResponseWaitList(this, started);
+ m_isAccelerated = started;
+ }
+ } else {
+ // We're waiting for the style to be available and we got a pause. Pause and wait
+ m_pauseTime = beginAnimationUpdateTime();
+ m_animState = AnimationStatePausedWaitStyleAvailable;
+ }
+ break;
+ case AnimationStateStartWaitResponse:
+ ASSERT(input == AnimationStateInputStartTimeSet || input == AnimationStateInputPlayStatePaused);
+
+ if (input == AnimationStateInputStartTimeSet) {
+ ASSERT(param >= 0);
+ // We have a start time, set it, unless the startTime is already set
+ if (m_startTime <= 0) {
+ m_startTime = param;
+ // If the value for 'animation-delay' is negative then the animation appears to have started in the past.
+ if (m_animation->delay() < 0)
+ m_startTime += m_animation->delay();
+ }
+
+ // Now that we know the start time, fire the start event.
+ onAnimationStart(0); // The elapsedTime is 0.
+
+ // Decide whether to go into looping or ending state
+ goIntoEndingOrLoopingState();
+
+ // Dispatch updateStyleIfNeeded so we can start the animation
+ if (m_object)
+ m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
+ } else {
+ // We are pausing while waiting for a start response. Cancel the animation and wait. When
+ // we unpause, we will act as though the start timer just fired
+ m_pauseTime = -1;
+ pauseAnimation(beginAnimationUpdateTime() - m_startTime);
+ m_animState = AnimationStatePausedWaitResponse;
+ }
+ break;
+ case AnimationStateLooping:
+ ASSERT(input == AnimationStateInputLoopTimerFired || input == AnimationStateInputPlayStatePaused);
+
+ if (input == AnimationStateInputLoopTimerFired) {
+ ASSERT(param >= 0);
+ // Loop timer fired, loop again or end.
+ onAnimationIteration(param);
+
+ // Decide whether to go into looping or ending state
+ goIntoEndingOrLoopingState();
+ } else {
+ // We are pausing while running. Cancel the animation and wait
+ m_pauseTime = beginAnimationUpdateTime();
+ pauseAnimation(beginAnimationUpdateTime() - m_startTime);
+ m_animState = AnimationStatePausedRun;
+ }
+ break;
+ case AnimationStateEnding:
+ ASSERT(input == AnimationStateInputEndTimerFired || input == AnimationStateInputPlayStatePaused);
+
+ if (input == AnimationStateInputEndTimerFired) {
+
+ ASSERT(param >= 0);
+ // End timer fired, finish up
+ onAnimationEnd(param);
+
+ m_animState = AnimationStateDone;
+
+ if (m_object) {
+ if (m_animation->fillsForwards())
+ m_animState = AnimationStateFillingForwards;
+ else
+ resumeOverriddenAnimations();
+
+ // Fire off another style change so we can set the final value
+ m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
+ }
+ } else {
+ // We are pausing while running. Cancel the animation and wait
+ m_pauseTime = beginAnimationUpdateTime();
+ pauseAnimation(beginAnimationUpdateTime() - m_startTime);
+ m_animState = AnimationStatePausedRun;
+ }
+ // |this| may be deleted here
+ break;
+ case AnimationStatePausedWaitTimer:
+ ASSERT(input == AnimationStateInputPlayStateRunning);
+ ASSERT(paused());
+ // Update the times
+ m_startTime += beginAnimationUpdateTime() - m_pauseTime;
+ m_pauseTime = -1;
+
+ // we were waiting for the start timer to fire, go back and wait again
+ m_animState = AnimationStateNew;
+ updateStateMachine(AnimationStateInputStartAnimation, 0);
+ break;
+ case AnimationStatePausedWaitResponse:
+ case AnimationStatePausedWaitStyleAvailable:
+ case AnimationStatePausedRun:
+ // We treat these two cases the same. The only difference is that, when we are in
+ // AnimationStatePausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation.
+ // When the AnimationStateInputStartTimeSet comes in and we were in AnimationStatePausedRun, we will notice
+ // that we have already set the startTime and will ignore it.
+ ASSERT(input == AnimationStateInputPlayStateRunning || input == AnimationStateInputStartTimeSet || input == AnimationStateInputStyleAvailable);
+ ASSERT(paused());
+
+ if (input == AnimationStateInputPlayStateRunning) {
+ // Update the times
+ if (m_animState == AnimationStatePausedRun)
+ m_startTime += beginAnimationUpdateTime() - m_pauseTime;
+ else
+ m_startTime = 0;
+ m_pauseTime = -1;
+
+ if (m_animState == AnimationStatePausedWaitStyleAvailable)
+ m_animState = AnimationStateStartWaitStyleAvailable;
+ else {
+ // We were either running or waiting for a begin time response from the animation.
+ // Either way we need to restart the animation (possibly with an offset if we
+ // had already been running) and wait for it to start.
+ m_animState = AnimationStateStartWaitResponse;
+
+ // Start the animation
+ if (overridden()) {
+ // We won't try to start accelerated animations if we are overridden and
+ // just move on to the next state.
+ updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
+ m_isAccelerated = true;
+ } else {
+ bool started = startAnimation(beginAnimationUpdateTime() - m_startTime);
+ m_compAnim->animationController()->addToStartTimeResponseWaitList(this, started);
+ m_isAccelerated = started;
+ }
+ }
+ break;
+ }
+
+ if (input == AnimationStateInputStartTimeSet) {
+ ASSERT(m_animState == AnimationStatePausedWaitResponse);
+
+ // We are paused but we got the callback that notifies us that an accelerated animation started.
+ // We ignore the start time and just move into the paused-run state.
+ m_animState = AnimationStatePausedRun;
+ ASSERT(m_startTime == 0);
+ m_startTime = param;
+ m_pauseTime += m_startTime;
+ break;
+ }
+
+ ASSERT(m_animState == AnimationStatePausedWaitStyleAvailable);
+ // We are paused but we got the callback that notifies us that style has been updated.
+ // We move to the AnimationStatePausedWaitResponse state
+ m_animState = AnimationStatePausedWaitResponse;
+ overrideAnimations();
+ break;
+ case AnimationStateFillingForwards:
+ case AnimationStateDone:
+ // We're done. Stay in this state until we are deleted
+ break;
+ }
+}
+
+void AnimationBase::fireAnimationEventsIfNeeded()
+{
+ // If we are waiting for the delay time to expire and it has, go to the next state
+ if (m_animState != AnimationStateStartWaitTimer && m_animState != AnimationStateLooping && m_animState != AnimationStateEnding)
+ return;
+
+ // We have to make sure to keep a ref to the this pointer, because it could get destroyed
+ // during an animation callback that might get called. Since the owner is a CompositeAnimation
+ // and it ref counts this object, we will keep a ref to that instead. That way the AnimationBase
+ // can still access the resources of its CompositeAnimation as needed.
+ RefPtr<AnimationBase> protector(this);
+ RefPtr<CompositeAnimation> compProtector(m_compAnim);
+
+ // Check for start timeout
+ if (m_animState == AnimationStateStartWaitTimer) {
+ if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->delay())
+ updateStateMachine(AnimationStateInputStartTimerFired, 0);
+ return;
+ }
+
+ double elapsedDuration = beginAnimationUpdateTime() - m_startTime;
+ // FIXME: we need to ensure that elapsedDuration is never < 0. If it is, this suggests that
+ // we had a recalcStyle() outside of beginAnimationUpdate()/endAnimationUpdate().
+ // Also check in getTimeToNextEvent().
+ elapsedDuration = max(elapsedDuration, 0.0);
+
+ // Check for end timeout
+ if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) {
+ // We may still be in AnimationStateLooping if we've managed to skip a
+ // whole iteration, in which case we should jump to the end state.
+ m_animState = AnimationStateEnding;
+
+ // Fire an end event
+ updateStateMachine(AnimationStateInputEndTimerFired, m_totalDuration);
+ } else {
+ // Check for iteration timeout
+ if (m_nextIterationDuration < 0) {
+ // Hasn't been set yet, set it
+ double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
+ m_nextIterationDuration = elapsedDuration + durationLeft;
+ }
+
+ if (elapsedDuration >= m_nextIterationDuration) {
+ // Set to the next iteration
+ double previous = m_nextIterationDuration;
+ double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
+ m_nextIterationDuration = elapsedDuration + durationLeft;
+
+ // Send the event
+ updateStateMachine(AnimationStateInputLoopTimerFired, previous);
+ }
+ }
+}
+
+void AnimationBase::updatePlayState(EAnimPlayState playState)
+{
+ // When we get here, we can have one of 4 desired states: running, paused, suspended, paused & suspended.
+ // The state machine can be in one of two states: running, paused.
+ // Set the state machine to the desired state.
+ bool pause = playState == AnimPlayStatePaused || m_compAnim->suspended();
+
+ if (pause == paused() && !isNew())
+ return;
+
+ updateStateMachine(pause ? AnimationStateInputPlayStatePaused : AnimationStateInputPlayStateRunning, -1);
+}
+
+double AnimationBase::timeToNextService()
+{
+ // Returns the time at which next service is required. -1 means no service is required. 0 means
+ // service is required now, and > 0 means service is required that many seconds in the future.
+ if (paused() || isNew() || m_animState == AnimationStateFillingForwards)
+ return -1;
+
+ if (m_animState == AnimationStateStartWaitTimer) {
+ double timeFromNow = m_animation->delay() - (beginAnimationUpdateTime() - m_requestedStartTime);
+ return max(timeFromNow, 0.0);
+ }
+
+ fireAnimationEventsIfNeeded();
+
+ // In all other cases, we need service right away.
+ return 0;
+}
+
+double AnimationBase::progress(double scale, double offset, const TimingFunction* tf) const
+{
+ if (preActive())
+ return 0;
+
+ double elapsedTime = getElapsedTime();
+
+ double dur = m_animation->duration();
+ if (m_animation->iterationCount() > 0)
+ dur *= m_animation->iterationCount();
+
+ if (postActive() || !m_animation->duration())
+ return 1.0;
+ if (m_animation->iterationCount() > 0 && elapsedTime >= dur)
+ return (m_animation->iterationCount() % 2) ? 1.0 : 0.0;
+
+ // Compute the fractional time, taking into account direction.
+ // There is no need to worry about iterations, we assume that we would have
+ // short circuited above if we were done.
+ double fractionalTime = elapsedTime / m_animation->duration();
+ int integralTime = static_cast<int>(fractionalTime);
+ fractionalTime -= integralTime;
+
+ if ((m_animation->direction() == Animation::AnimationDirectionAlternate) && (integralTime & 1))
+ fractionalTime = 1 - fractionalTime;
+
+ if (scale != 1 || offset)
+ fractionalTime = (fractionalTime - offset) * scale;
+
+ if (!tf)
+ tf = m_animation->timingFunction().get();
+
+ if (tf->isCubicBezierTimingFunction()) {
+ const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(tf);
+ return solveCubicBezierFunction(ctf->x1(),
+ ctf->y1(),
+ ctf->x2(),
+ ctf->y2(),
+ fractionalTime, m_animation->duration());
+ } else if (tf->isStepsTimingFunction()) {
+ const StepsTimingFunction* stf = static_cast<const StepsTimingFunction*>(tf);
+ return solveStepsFunction(stf->numberOfSteps(), stf->stepAtStart(), fractionalTime);
+ } else
+ return fractionalTime;
+}
+
+void AnimationBase::getTimeToNextEvent(double& time, bool& isLooping) const
+{
+ // Decide when the end or loop event needs to fire
+ const double elapsedDuration = max(beginAnimationUpdateTime() - m_startTime, 0.0);
+ double durationLeft = 0;
+ double nextIterationTime = m_totalDuration;
+
+ if (m_totalDuration < 0 || elapsedDuration < m_totalDuration) {
+ durationLeft = m_animation->duration() > 0 ? (m_animation->duration() - fmod(elapsedDuration, m_animation->duration())) : 0;
+ nextIterationTime = elapsedDuration + durationLeft;
+ }
+
+ if (m_totalDuration < 0 || nextIterationTime < m_totalDuration) {
+ // We are not at the end yet
+ ASSERT(nextIterationTime > 0);
+ isLooping = true;
+ } else {
+ // We are at the end
+ isLooping = false;
+ }
+
+ time = durationLeft;
+}
+
+void AnimationBase::goIntoEndingOrLoopingState()
+{
+ double t;
+ bool isLooping;
+ getTimeToNextEvent(t, isLooping);
+ m_animState = isLooping ? AnimationStateLooping : AnimationStateEnding;
+}
+
+void AnimationBase::freezeAtTime(double t)
+{
+ if (!m_startTime) {
+ // If we haven't started yet, just generate the start event now
+ m_compAnim->animationController()->receivedStartTimeResponse(currentTime());
+ }
+
+ ASSERT(m_startTime); // if m_startTime is zero, we haven't started yet, so we'll get a bad pause time.
+ m_pauseTime = m_startTime + t - m_animation->delay();
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_object && m_object->hasLayer()) {
+ RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
+ if (layer->isComposited())
+ layer->backing()->suspendAnimations(m_pauseTime);
+ }
+#endif
+}
+
+double AnimationBase::beginAnimationUpdateTime() const
+{
+ return m_compAnim->animationController()->beginAnimationUpdateTime();
+}
+
+double AnimationBase::getElapsedTime() const
+{
+ if (paused())
+ return m_pauseTime - m_startTime;
+ if (m_startTime <= 0)
+ return 0;
+ if (postActive())
+ return 1;
+
+ return beginAnimationUpdateTime() - m_startTime;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/animation/AnimationBase.h b/Source/WebCore/page/animation/AnimationBase.h
new file mode 100644
index 0000000..877d649
--- /dev/null
+++ b/Source/WebCore/page/animation/AnimationBase.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 AnimationBase_h
+#define AnimationBase_h
+
+#include "RenderStyleConstants.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+class Animation;
+class AnimationBase;
+class AnimationController;
+class CompositeAnimation;
+class Element;
+class Node;
+class RenderObject;
+class RenderStyle;
+class TimingFunction;
+
+class AnimationBase : public RefCounted<AnimationBase> {
+ friend class CompositeAnimation;
+
+public:
+ AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim);
+ virtual ~AnimationBase();
+
+ RenderObject* renderer() const { return m_object; }
+ void clearRenderer() { m_object = 0; }
+
+ double duration() const;
+
+ // Animations and Transitions go through the states below. When entering the STARTED state
+ // the animation is started. This may or may not require deferred response from the animator.
+ // If so, we stay in this state until that response is received (and it returns the start time).
+ // Otherwise, we use the current time as the start time and go immediately to AnimationStateLooping
+ // or AnimationStateEnding.
+ enum AnimState {
+ AnimationStateNew, // animation just created, animation not running yet
+ AnimationStateStartWaitTimer, // start timer running, waiting for fire
+ AnimationStateStartWaitStyleAvailable, // waiting for style setup so we can start animations
+ AnimationStateStartWaitResponse, // animation started, waiting for response
+ AnimationStateLooping, // response received, animation running, loop timer running, waiting for fire
+ AnimationStateEnding, // received, animation running, end timer running, waiting for fire
+ AnimationStatePausedWaitTimer, // in pause mode when animation started
+ AnimationStatePausedWaitStyleAvailable, // in pause mode when waiting for style setup
+ AnimationStatePausedWaitResponse, // animation paused when in STARTING state
+ AnimationStatePausedRun, // animation paused when in LOOPING or ENDING state
+ AnimationStateDone, // end timer fired, animation finished and removed
+ AnimationStateFillingForwards // animation has ended and is retaining its final value
+ };
+
+ enum AnimStateInput {
+ AnimationStateInputMakeNew, // reset back to new from any state
+ AnimationStateInputStartAnimation, // animation requests a start
+ AnimationStateInputRestartAnimation, // force a restart from any state
+ AnimationStateInputStartTimerFired, // start timer fired
+ AnimationStateInputStyleAvailable, // style is setup, ready to start animating
+ AnimationStateInputStartTimeSet, // m_startTime was set
+ AnimationStateInputLoopTimerFired, // loop timer fired
+ AnimationStateInputEndTimerFired, // end timer fired
+ AnimationStateInputPauseOverride, // pause an animation due to override
+ AnimationStateInputResumeOverride, // resume an overridden animation
+ AnimationStateInputPlayStateRunning, // play state paused -> running
+ AnimationStateInputPlayStatePaused, // play state running -> paused
+ AnimationStateInputEndAnimation // force an end from any state
+ };
+
+ // Called when animation is in AnimationStateNew to start animation
+ void updateStateMachine(AnimStateInput, double param);
+
+ // Animation has actually started, at passed time
+ void onAnimationStartResponse(double startTime)
+ {
+ updateStateMachine(AnimationBase::AnimationStateInputStartTimeSet, startTime);
+ }
+
+ // Called to change to or from paused state
+ void updatePlayState(EAnimPlayState);
+ bool playStatePlaying() const;
+
+ bool waitingToStart() const { return m_animState == AnimationStateNew || m_animState == AnimationStateStartWaitTimer; }
+ bool preActive() const
+ {
+ return m_animState == AnimationStateNew || m_animState == AnimationStateStartWaitTimer || m_animState == AnimationStateStartWaitStyleAvailable || m_animState == AnimationStateStartWaitResponse;
+ }
+
+ bool postActive() const { return m_animState == AnimationStateDone; }
+ bool active() const { return !postActive() && !preActive(); }
+ bool running() const { return !isNew() && !postActive(); }
+ bool paused() const { return m_pauseTime >= 0; }
+ bool isNew() const { return m_animState == AnimationStateNew; }
+ bool waitingForStartTime() const { return m_animState == AnimationStateStartWaitResponse; }
+ bool waitingForStyleAvailable() const { return m_animState == AnimationStateStartWaitStyleAvailable; }
+
+ // "animating" means that something is running that requires a timer to keep firing
+ // (e.g. a software animation)
+ void setAnimating(bool inAnimating = true) { m_isAnimating = inAnimating; }
+ virtual double timeToNextService();
+
+ double progress(double scale, double offset, const TimingFunction*) const;
+
+ virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* /*currentStyle*/, RenderStyle* /*targetStyle*/, RefPtr<RenderStyle>& /*animatedStyle*/) = 0;
+ virtual void getAnimatedStyle(RefPtr<RenderStyle>& /*animatedStyle*/) = 0;
+
+ virtual bool shouldFireEvents() const { return false; }
+
+ void fireAnimationEventsIfNeeded();
+
+ bool animationsMatch(const Animation*) const;
+
+ void setAnimation(const Animation* anim) { m_animation = const_cast<Animation*>(anim); }
+
+ // Return true if this animation is overridden. This will only be the case for
+ // ImplicitAnimations and is used to determine whether or not we should force
+ // set the start time. If an animation is overridden, it will probably not get
+ // back the AnimationStateInputStartTimeSet input.
+ virtual bool overridden() const { return false; }
+
+ // Does this animation/transition involve the given property?
+ virtual bool affectsProperty(int /*property*/) const { return false; }
+
+ bool isAnimatingProperty(int property, bool acceleratedOnly, bool isRunningNow) const
+ {
+ if (acceleratedOnly && !m_isAccelerated)
+ return false;
+
+ if (isRunningNow)
+ return (!waitingToStart() && !postActive()) && affectsProperty(property);
+
+ return !postActive() && affectsProperty(property);
+ }
+
+ bool isTransformFunctionListValid() const { return m_transformFunctionListValid; }
+
+ // Freeze the animation; used by DumpRenderTree.
+ void freezeAtTime(double t);
+
+ double beginAnimationUpdateTime() const;
+
+ double getElapsedTime() const;
+
+ AnimationBase* next() const { return m_next; }
+ void setNext(AnimationBase* animation) { m_next = animation; }
+
+ void styleAvailable()
+ {
+ ASSERT(waitingForStyleAvailable());
+ updateStateMachine(AnimationBase::AnimationStateInputStyleAvailable, -1);
+ }
+
+#if USE(ACCELERATED_COMPOSITING)
+ static bool animationOfPropertyIsAccelerated(int prop);
+#endif
+
+ static HashSet<int> animatableShorthandsAffectingProperty(int property);
+
+protected:
+ virtual void overrideAnimations() { }
+ virtual void resumeOverriddenAnimations() { }
+
+ CompositeAnimation* compositeAnimation() { return m_compAnim; }
+
+ // These are called when the corresponding timer fires so subclasses can do any extra work
+ virtual void onAnimationStart(double /*elapsedTime*/) { }
+ virtual void onAnimationIteration(double /*elapsedTime*/) { }
+ virtual void onAnimationEnd(double /*elapsedTime*/) { }
+
+ // timeOffset is an offset from the current time when the animation should start. Negative values are OK.
+ // Return value indicates whether to expect an asynchronous notifyAnimationStarted() callback.
+ virtual bool startAnimation(double /*timeOffset*/) { return false; }
+ // timeOffset is the time at which the animation is being paused.
+ virtual void pauseAnimation(double /*timeOffset*/) { }
+ virtual void endAnimation() { }
+
+ void goIntoEndingOrLoopingState();
+
+ bool isAccelerated() const { return m_isAccelerated; }
+
+ static bool propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b);
+ static int getPropertyAtIndex(int, bool& isShorthand);
+ static int getNumProperties();
+
+ // Return true if we need to start software animation timers
+ static bool blendProperties(const AnimationBase* anim, int prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress);
+
+ static void setNeedsStyleRecalc(Node*);
+
+ void getTimeToNextEvent(double& time, bool& isLooping) const;
+
+ AnimState m_animState;
+
+ bool m_isAnimating; // transition/animation requires continual timer firing
+ double m_startTime;
+ double m_pauseTime;
+ double m_requestedStartTime;
+ RenderObject* m_object;
+
+ RefPtr<Animation> m_animation;
+ CompositeAnimation* m_compAnim;
+ bool m_isAccelerated;
+ bool m_transformFunctionListValid;
+ double m_totalDuration, m_nextIterationDuration;
+
+ AnimationBase* m_next;
+
+private:
+ static void ensurePropertyMap();
+};
+
+} // namespace WebCore
+
+#endif // AnimationBase_h
diff --git a/Source/WebCore/page/animation/AnimationController.cpp b/Source/WebCore/page/animation/AnimationController.cpp
new file mode 100644
index 0000000..e1281dd
--- /dev/null
+++ b/Source/WebCore/page/animation/AnimationController.cpp
@@ -0,0 +1,615 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "AnimationController.h"
+
+#include "AnimationBase.h"
+#include "AnimationControllerPrivate.h"
+#include "CSSParser.h"
+#include "CompositeAnimation.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "RenderView.h"
+#include "WebKitAnimationEvent.h"
+#include "WebKitTransitionEvent.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+static const double cAnimationTimerDelay = 0.025;
+static const double cBeginAnimationUpdateTimeNotSet = -1;
+
+AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame)
+ : m_animationTimer(this, &AnimationControllerPrivate::animationTimerFired)
+ , m_updateStyleIfNeededDispatcher(this, &AnimationControllerPrivate::updateStyleIfNeededDispatcherFired)
+ , m_frame(frame)
+ , m_beginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet)
+ , m_styleAvailableWaiters(0)
+ , m_lastStyleAvailableWaiter(0)
+ , m_startTimeResponseWaiters(0)
+ , m_lastStartTimeResponseWaiter(0)
+ , m_waitingForStartTimeResponse(false)
+{
+}
+
+AnimationControllerPrivate::~AnimationControllerPrivate()
+{
+}
+
+PassRefPtr<CompositeAnimation> AnimationControllerPrivate::accessCompositeAnimation(RenderObject* renderer)
+{
+ RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer);
+ if (!animation) {
+ animation = CompositeAnimation::create(this);
+ m_compositeAnimations.set(renderer, animation);
+ }
+ return animation;
+}
+
+bool AnimationControllerPrivate::clear(RenderObject* renderer)
+{
+ // Return false if we didn't do anything OR we are suspended (so we don't try to
+ // do a setNeedsStyleRecalc() when suspended).
+ PassRefPtr<CompositeAnimation> animation = m_compositeAnimations.take(renderer);
+ if (!animation)
+ return false;
+ animation->clearRenderer();
+ return animation->suspended();
+}
+
+void AnimationControllerPrivate::updateAnimationTimer(bool callSetChanged/* = false*/)
+{
+ double needsService = -1;
+ bool calledSetChanged = false;
+
+ RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
+ for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
+ CompositeAnimation* compAnim = it->second.get();
+ if (!compAnim->suspended() && compAnim->hasAnimations()) {
+ double t = compAnim->timeToNextService();
+ if (t != -1 && (t < needsService || needsService == -1))
+ needsService = t;
+ if (needsService == 0) {
+ if (callSetChanged) {
+ Node* node = it->first->node();
+ ASSERT(!node || (node->document() && !node->document()->inPageCache()));
+ node->setNeedsStyleRecalc(SyntheticStyleChange);
+ calledSetChanged = true;
+ }
+ else
+ break;
+ }
+ }
+ }
+
+ if (calledSetChanged)
+ m_frame->document()->updateStyleIfNeeded();
+
+ // If we want service immediately, we start a repeating timer to reduce the overhead of starting
+ if (needsService == 0) {
+ if (!m_animationTimer.isActive() || m_animationTimer.repeatInterval() == 0)
+ m_animationTimer.startRepeating(cAnimationTimerDelay);
+ return;
+ }
+
+ // If we don't need service, we want to make sure the timer is no longer running
+ if (needsService < 0) {
+ if (m_animationTimer.isActive())
+ m_animationTimer.stop();
+ return;
+ }
+
+ // Otherwise, we want to start a one-shot timer so we get here again
+ if (m_animationTimer.isActive())
+ m_animationTimer.stop();
+ m_animationTimer.startOneShot(needsService);
+}
+
+void AnimationControllerPrivate::updateStyleIfNeededDispatcherFired(Timer<AnimationControllerPrivate>*)
+{
+ fireEventsAndUpdateStyle();
+}
+
+void AnimationControllerPrivate::fireEventsAndUpdateStyle()
+{
+ // Protect the frame from getting destroyed in the event handler
+ RefPtr<Frame> protector = m_frame;
+
+ bool updateStyle = !m_eventsToDispatch.isEmpty() || !m_nodeChangesToDispatch.isEmpty();
+
+ // fire all the events
+ Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = m_eventsToDispatch.end();
+ for (Vector<EventToDispatch>::const_iterator it = m_eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) {
+ if (it->eventType == eventNames().webkitTransitionEndEvent)
+ it->element->dispatchEvent(WebKitTransitionEvent::create(it->eventType, it->name, it->elapsedTime));
+ else
+ it->element->dispatchEvent(WebKitAnimationEvent::create(it->eventType, it->name, it->elapsedTime));
+ }
+
+ m_eventsToDispatch.clear();
+
+ // call setChanged on all the elements
+ Vector<RefPtr<Node> >::const_iterator nodeChangesToDispatchEnd = m_nodeChangesToDispatch.end();
+ for (Vector<RefPtr<Node> >::const_iterator it = m_nodeChangesToDispatch.begin(); it != nodeChangesToDispatchEnd; ++it)
+ (*it)->setNeedsStyleRecalc(SyntheticStyleChange);
+
+ m_nodeChangesToDispatch.clear();
+
+ if (updateStyle && m_frame)
+ m_frame->document()->updateStyleIfNeeded();
+}
+
+void AnimationControllerPrivate::startUpdateStyleIfNeededDispatcher()
+{
+ if (!m_updateStyleIfNeededDispatcher.isActive())
+ m_updateStyleIfNeededDispatcher.startOneShot(0);
+}
+
+void AnimationControllerPrivate::addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime)
+{
+ m_eventsToDispatch.grow(m_eventsToDispatch.size()+1);
+ EventToDispatch& event = m_eventsToDispatch[m_eventsToDispatch.size()-1];
+ event.element = element;
+ event.eventType = eventType;
+ event.name = name;
+ event.elapsedTime = elapsedTime;
+
+ startUpdateStyleIfNeededDispatcher();
+}
+
+void AnimationControllerPrivate::addNodeChangeToDispatch(PassRefPtr<Node> node)
+{
+ ASSERT(!node || (node->document() && !node->document()->inPageCache()));
+ if (!node)
+ return;
+
+ m_nodeChangesToDispatch.append(node);
+ startUpdateStyleIfNeededDispatcher();
+}
+
+void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPrivate>*)
+{
+ // Make sure animationUpdateTime is updated, so that it is current even if no
+ // styleChange has happened (e.g. accelerated animations)
+ setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
+
+ // When the timer fires, all we do is call setChanged on all DOM nodes with running animations and then do an immediate
+ // updateStyleIfNeeded. It will then call back to us with new information.
+ updateAnimationTimer(true);
+
+ // Fire events right away, to avoid a flash of unanimated style after an animation completes, and before
+ // the 'end' event fires.
+ fireEventsAndUpdateStyle();
+}
+
+bool AnimationControllerPrivate::isRunningAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const
+{
+ RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer);
+ if (!animation)
+ return false;
+
+ return animation->isAnimatingProperty(property, false, isRunningNow);
+}
+
+bool AnimationControllerPrivate::isRunningAcceleratedAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const
+{
+ RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer);
+ if (!animation)
+ return false;
+
+ return animation->isAnimatingProperty(property, true, isRunningNow);
+}
+
+void AnimationControllerPrivate::suspendAnimations()
+{
+ suspendAnimationsForDocument(m_frame->document());
+
+ // Traverse subframes
+ for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
+ child->animation()->suspendAnimations();
+}
+
+void AnimationControllerPrivate::resumeAnimations()
+{
+ resumeAnimationsForDocument(m_frame->document());
+
+ // Traverse subframes
+ for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
+ child->animation()->resumeAnimations();
+}
+
+void AnimationControllerPrivate::suspendAnimationsForDocument(Document* document)
+{
+ setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
+
+ RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
+ for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
+ RenderObject* renderer = it->first;
+ if (renderer->document() == document) {
+ CompositeAnimation* compAnim = it->second.get();
+ compAnim->suspendAnimations();
+ }
+ }
+
+ updateAnimationTimer();
+}
+
+void AnimationControllerPrivate::resumeAnimationsForDocument(Document* document)
+{
+ setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
+
+ RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
+ for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
+ RenderObject* renderer = it->first;
+ if (renderer->document() == document) {
+ CompositeAnimation* compAnim = it->second.get();
+ compAnim->resumeAnimations();
+ }
+ }
+
+ updateAnimationTimer();
+}
+
+bool AnimationControllerPrivate::pauseAnimationAtTime(RenderObject* renderer, const String& name, double t)
+{
+ if (!renderer)
+ return false;
+
+ RefPtr<CompositeAnimation> compAnim = accessCompositeAnimation(renderer);
+ if (!compAnim)
+ return false;
+
+ if (compAnim->pauseAnimationAtTime(name, t)) {
+ renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
+ startUpdateStyleIfNeededDispatcher();
+ return true;
+ }
+
+ return false;
+}
+
+bool AnimationControllerPrivate::pauseTransitionAtTime(RenderObject* renderer, const String& property, double t)
+{
+ if (!renderer)
+ return false;
+
+ RefPtr<CompositeAnimation> compAnim = accessCompositeAnimation(renderer);
+ if (!compAnim)
+ return false;
+
+ if (compAnim->pauseTransitionAtTime(cssPropertyID(property), t)) {
+ renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
+ startUpdateStyleIfNeededDispatcher();
+ return true;
+ }
+
+ return false;
+}
+
+double AnimationControllerPrivate::beginAnimationUpdateTime()
+{
+ if (m_beginAnimationUpdateTime == cBeginAnimationUpdateTimeNotSet)
+ m_beginAnimationUpdateTime = currentTime();
+ return m_beginAnimationUpdateTime;
+}
+
+void AnimationControllerPrivate::endAnimationUpdate()
+{
+ styleAvailable();
+ if (!m_waitingForStartTimeResponse)
+ startTimeResponse(beginAnimationUpdateTime());
+}
+
+void AnimationControllerPrivate::receivedStartTimeResponse(double time)
+{
+ m_waitingForStartTimeResponse = false;
+ startTimeResponse(time);
+}
+
+PassRefPtr<RenderStyle> AnimationControllerPrivate::getAnimatedStyleForRenderer(RenderObject* renderer)
+{
+ if (!renderer)
+ return 0;
+
+ RefPtr<CompositeAnimation> rendererAnimations = m_compositeAnimations.get(renderer);
+ if (!rendererAnimations)
+ return renderer->style();
+
+ // Make sure animationUpdateTime is updated, so that it is current even if no
+ // styleChange has happened (e.g. accelerated animations).
+ setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
+ RefPtr<RenderStyle> animatingStyle = rendererAnimations->getAnimatedStyle();
+ if (!animatingStyle)
+ animatingStyle = renderer->style();
+
+ return animatingStyle.release();
+}
+
+unsigned AnimationControllerPrivate::numberOfActiveAnimations() const
+{
+ unsigned count = 0;
+
+ RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
+ for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
+ CompositeAnimation* compAnim = it->second.get();
+ count += compAnim->numberOfActiveAnimations();
+ }
+
+ return count;
+}
+
+void AnimationControllerPrivate::addToStyleAvailableWaitList(AnimationBase* animation)
+{
+ ASSERT(!animation->next());
+
+ if (m_styleAvailableWaiters)
+ m_lastStyleAvailableWaiter->setNext(animation);
+ else
+ m_styleAvailableWaiters = animation;
+
+ m_lastStyleAvailableWaiter = animation;
+ animation->setNext(0);
+}
+
+void AnimationControllerPrivate::removeFromStyleAvailableWaitList(AnimationBase* animationToRemove)
+{
+ AnimationBase* prevAnimation = 0;
+ for (AnimationBase* animation = m_styleAvailableWaiters; animation; animation = animation->next()) {
+ if (animation == animationToRemove) {
+ if (prevAnimation)
+ prevAnimation->setNext(animation->next());
+ else
+ m_styleAvailableWaiters = animation->next();
+
+ if (m_lastStyleAvailableWaiter == animation)
+ m_lastStyleAvailableWaiter = prevAnimation;
+
+ animationToRemove->setNext(0);
+ }
+ }
+}
+
+void AnimationControllerPrivate::styleAvailable()
+{
+ // Go through list of waiters and send them on their way
+ for (AnimationBase* animation = m_styleAvailableWaiters; animation; ) {
+ AnimationBase* nextAnimation = animation->next();
+ animation->setNext(0);
+ animation->styleAvailable();
+ animation = nextAnimation;
+ }
+
+ m_styleAvailableWaiters = 0;
+ m_lastStyleAvailableWaiter = 0;
+}
+
+void AnimationControllerPrivate::addToStartTimeResponseWaitList(AnimationBase* animation, bool willGetResponse)
+{
+ // If willGetResponse is true, it means this animation is actually waiting for a response
+ // (which will come in as a call to notifyAnimationStarted()).
+ // In that case we don't need to add it to this list. We just set a waitingForAResponse flag
+ // which says we are waiting for the response. If willGetResponse is false, this animation
+ // is not waiting for a response for itself, but rather for a notifyXXXStarted() call for
+ // another animation to which it will sync.
+ //
+ // When endAnimationUpdate() is called we check to see if the waitingForAResponse flag is
+ // true. If so, we just return and will do our work when the first notifyXXXStarted() call
+ // comes in. If it is false, we will not be getting a notifyXXXStarted() call, so we will
+ // do our work right away. In both cases we call the onAnimationStartResponse() method
+ // on each animation. In the first case we send in the time we got from notifyXXXStarted().
+ // In the second case, we just pass in the beginAnimationUpdateTime().
+ //
+ // This will synchronize all software and accelerated animations started in the same
+ // updateStyleIfNeeded cycle.
+ //
+ ASSERT(!animation->next());
+
+ if (willGetResponse)
+ m_waitingForStartTimeResponse = true;
+
+ if (m_startTimeResponseWaiters)
+ m_lastStartTimeResponseWaiter->setNext(animation);
+ else
+ m_startTimeResponseWaiters = animation;
+
+ m_lastStartTimeResponseWaiter = animation;
+ animation->setNext(0);
+}
+
+void AnimationControllerPrivate::removeFromStartTimeResponseWaitList(AnimationBase* animationToRemove)
+{
+ AnimationBase* prevAnimation = 0;
+ for (AnimationBase* animation = m_startTimeResponseWaiters; animation; animation = animation->next()) {
+ if (animation == animationToRemove) {
+ if (prevAnimation)
+ prevAnimation->setNext(animation->next());
+ else
+ m_startTimeResponseWaiters = animation->next();
+
+ if (m_lastStartTimeResponseWaiter == animation)
+ m_lastStartTimeResponseWaiter = prevAnimation;
+
+ animationToRemove->setNext(0);
+ }
+ prevAnimation = animation;
+ }
+
+ if (!m_startTimeResponseWaiters)
+ m_waitingForStartTimeResponse = false;
+}
+
+void AnimationControllerPrivate::startTimeResponse(double time)
+{
+ // Go through list of waiters and send them on their way
+ for (AnimationBase* animation = m_startTimeResponseWaiters; animation; ) {
+ AnimationBase* nextAnimation = animation->next();
+ animation->setNext(0);
+ animation->onAnimationStartResponse(time);
+ animation = nextAnimation;
+ }
+
+ m_startTimeResponseWaiters = 0;
+ m_lastStartTimeResponseWaiter = 0;
+}
+
+AnimationController::AnimationController(Frame* frame)
+ : m_data(new AnimationControllerPrivate(frame))
+{
+}
+
+AnimationController::~AnimationController()
+{
+ delete m_data;
+}
+
+void AnimationController::cancelAnimations(RenderObject* renderer)
+{
+ if (!m_data->hasAnimations())
+ return;
+
+ if (m_data->clear(renderer)) {
+ Node* node = renderer->node();
+ ASSERT(!node || (node->document() && !node->document()->inPageCache()));
+ node->setNeedsStyleRecalc(SyntheticStyleChange);
+ }
+}
+
+PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* renderer, RenderStyle* newStyle)
+{
+ // Don't do anything if we're in the cache
+ if (!renderer->document() || renderer->document()->inPageCache())
+ return newStyle;
+
+ RenderStyle* oldStyle = renderer->style();
+
+ if ((!oldStyle || (!oldStyle->animations() && !oldStyle->transitions())) && (!newStyle->animations() && !newStyle->transitions()))
+ return newStyle;
+
+ // Don't run transitions when printing.
+ if (renderer->view()->printing())
+ return newStyle;
+
+ // Fetch our current set of implicit animations from a hashtable. We then compare them
+ // against the animations in the style and make sure we're in sync. If destination values
+ // have changed, we reset the animation. We then do a blend to get new values and we return
+ // a new style.
+ ASSERT(renderer->node()); // FIXME: We do not animate generated content yet.
+
+ RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer);
+ RefPtr<RenderStyle> blendedStyle = rendererAnimations->animate(renderer, oldStyle, newStyle);
+
+ m_data->updateAnimationTimer();
+
+ if (blendedStyle != newStyle) {
+ // If the animations/transitions change opacity or transform, we need to update
+ // the style to impose the stacking rules. Note that this is also
+ // done in CSSStyleSelector::adjustRenderStyle().
+ if (blendedStyle->hasAutoZIndex() && (blendedStyle->opacity() < 1.0f || blendedStyle->hasTransform()))
+ blendedStyle->setZIndex(0);
+ }
+ return blendedStyle.release();
+}
+
+PassRefPtr<RenderStyle> AnimationController::getAnimatedStyleForRenderer(RenderObject* renderer)
+{
+ return m_data->getAnimatedStyleForRenderer(renderer);
+}
+
+void AnimationController::notifyAnimationStarted(RenderObject*, double startTime)
+{
+ m_data->receivedStartTimeResponse(startTime);
+}
+
+bool AnimationController::pauseAnimationAtTime(RenderObject* renderer, const String& name, double t)
+{
+ return m_data->pauseAnimationAtTime(renderer, name, t);
+}
+
+unsigned AnimationController::numberOfActiveAnimations() const
+{
+ return m_data->numberOfActiveAnimations();
+}
+
+bool AnimationController::pauseTransitionAtTime(RenderObject* renderer, const String& property, double t)
+{
+ return m_data->pauseTransitionAtTime(renderer, property, t);
+}
+
+bool AnimationController::isRunningAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const
+{
+ return m_data->isRunningAnimationOnRenderer(renderer, property, isRunningNow);
+}
+
+bool AnimationController::isRunningAcceleratedAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const
+{
+ return m_data->isRunningAcceleratedAnimationOnRenderer(renderer, property, isRunningNow);
+}
+
+void AnimationController::suspendAnimations()
+{
+ m_data->suspendAnimations();
+}
+
+void AnimationController::resumeAnimations()
+{
+ m_data->resumeAnimations();
+}
+
+void AnimationController::suspendAnimationsForDocument(Document* document)
+{
+ m_data->suspendAnimationsForDocument(document);
+}
+
+void AnimationController::resumeAnimationsForDocument(Document* document)
+{
+ m_data->resumeAnimationsForDocument(document);
+}
+
+void AnimationController::beginAnimationUpdate()
+{
+ m_data->setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
+}
+
+void AnimationController::endAnimationUpdate()
+{
+ m_data->endAnimationUpdate();
+}
+
+bool AnimationController::supportsAcceleratedAnimationOfProperty(CSSPropertyID property)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ return AnimationBase::animationOfPropertyIsAccelerated(property);
+#else
+ UNUSED_PARAM(property);
+ return false;
+#endif
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/animation/AnimationController.h b/Source/WebCore/page/animation/AnimationController.h
new file mode 100644
index 0000000..5279467
--- /dev/null
+++ b/Source/WebCore/page/animation/AnimationController.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 AnimationController_h
+#define AnimationController_h
+
+#include "CSSPropertyNames.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class AnimationBase;
+class AnimationControllerPrivate;
+class Document;
+class Element;
+class Frame;
+class Node;
+class RenderObject;
+class RenderStyle;
+
+class AnimationController {
+public:
+ AnimationController(Frame*);
+ ~AnimationController();
+
+ void cancelAnimations(RenderObject*);
+ PassRefPtr<RenderStyle> updateAnimations(RenderObject*, RenderStyle* newStyle);
+ PassRefPtr<RenderStyle> getAnimatedStyleForRenderer(RenderObject*);
+
+ // This is called when an accelerated animation or transition has actually started to animate.
+ void notifyAnimationStarted(RenderObject*, double startTime);
+
+ bool pauseAnimationAtTime(RenderObject*, const String& name, double t); // To be used only for testing
+ bool pauseTransitionAtTime(RenderObject*, const String& property, double t); // To be used only for testing
+ unsigned numberOfActiveAnimations() const; // To be used only for testing
+
+ bool isRunningAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow = true) const;
+ bool isRunningAcceleratedAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow = true) const;
+
+ void suspendAnimations();
+ void resumeAnimations();
+
+ void suspendAnimationsForDocument(Document*);
+ void resumeAnimationsForDocument(Document*);
+
+ void beginAnimationUpdate();
+ void endAnimationUpdate();
+
+ static bool supportsAcceleratedAnimationOfProperty(CSSPropertyID);
+
+private:
+ AnimationControllerPrivate* m_data;
+};
+
+} // namespace WebCore
+
+#endif // AnimationController_h
diff --git a/Source/WebCore/page/animation/AnimationControllerPrivate.h b/Source/WebCore/page/animation/AnimationControllerPrivate.h
new file mode 100644
index 0000000..6812e09
--- /dev/null
+++ b/Source/WebCore/page/animation/AnimationControllerPrivate.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 AnimationControllerPrivate_h
+#define AnimationControllerPrivate_h
+
+#include "CSSPropertyNames.h"
+#include "PlatformString.h"
+#include "Timer.h"
+#include <wtf/HashMap.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+class AnimationBase;
+class CompositeAnimation;
+class Document;
+class Element;
+class Frame;
+class Node;
+class RenderObject;
+class RenderStyle;
+
+class AnimationControllerPrivate : public Noncopyable {
+public:
+ AnimationControllerPrivate(Frame*);
+ ~AnimationControllerPrivate();
+
+ void updateAnimationTimer(bool callSetChanged = false);
+
+ PassRefPtr<CompositeAnimation> accessCompositeAnimation(RenderObject*);
+ bool clear(RenderObject*);
+
+ void updateStyleIfNeededDispatcherFired(Timer<AnimationControllerPrivate>*);
+ void startUpdateStyleIfNeededDispatcher();
+ void addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime);
+ void addNodeChangeToDispatch(PassRefPtr<Node>);
+
+ bool hasAnimations() const { return !m_compositeAnimations.isEmpty(); }
+
+ void suspendAnimations();
+ void resumeAnimations();
+
+ void suspendAnimationsForDocument(Document*);
+ void resumeAnimationsForDocument(Document*);
+
+ bool isRunningAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow) const;
+ bool isRunningAcceleratedAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow) const;
+
+ bool pauseAnimationAtTime(RenderObject*, const String& name, double t);
+ bool pauseTransitionAtTime(RenderObject*, const String& property, double t);
+ unsigned numberOfActiveAnimations() const;
+
+ PassRefPtr<RenderStyle> getAnimatedStyleForRenderer(RenderObject* renderer);
+
+ double beginAnimationUpdateTime();
+ void setBeginAnimationUpdateTime(double t) { m_beginAnimationUpdateTime = t; }
+ void endAnimationUpdate();
+ void receivedStartTimeResponse(double);
+
+ void addToStyleAvailableWaitList(AnimationBase*);
+ void removeFromStyleAvailableWaitList(AnimationBase*);
+
+ void addToStartTimeResponseWaitList(AnimationBase*, bool willGetResponse);
+ void removeFromStartTimeResponseWaitList(AnimationBase*);
+
+private:
+ void animationTimerFired(Timer<AnimationControllerPrivate>*);
+
+ void styleAvailable();
+ void fireEventsAndUpdateStyle();
+ void startTimeResponse(double t);
+
+ typedef HashMap<RenderObject*, RefPtr<CompositeAnimation> > RenderObjectAnimationMap;
+
+ RenderObjectAnimationMap m_compositeAnimations;
+ Timer<AnimationControllerPrivate> m_animationTimer;
+ Timer<AnimationControllerPrivate> m_updateStyleIfNeededDispatcher;
+ Frame* m_frame;
+
+ class EventToDispatch {
+ public:
+ RefPtr<Element> element;
+ AtomicString eventType;
+ String name;
+ double elapsedTime;
+ };
+
+ Vector<EventToDispatch> m_eventsToDispatch;
+ Vector<RefPtr<Node> > m_nodeChangesToDispatch;
+
+ double m_beginAnimationUpdateTime;
+ AnimationBase* m_styleAvailableWaiters;
+ AnimationBase* m_lastStyleAvailableWaiter;
+
+ AnimationBase* m_startTimeResponseWaiters;
+ AnimationBase* m_lastStartTimeResponseWaiter;
+ bool m_waitingForStartTimeResponse;
+};
+
+} // namespace WebCore
+
+#endif // AnimationControllerPrivate_h
diff --git a/Source/WebCore/page/animation/CompositeAnimation.cpp b/Source/WebCore/page/animation/CompositeAnimation.cpp
new file mode 100644
index 0000000..602491e
--- /dev/null
+++ b/Source/WebCore/page/animation/CompositeAnimation.cpp
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "CompositeAnimation.h"
+
+#include "AnimationControllerPrivate.h"
+#include "CSSPropertyLonghand.h"
+#include "CSSPropertyNames.h"
+#include "ImplicitAnimation.h"
+#include "KeyframeAnimation.h"
+#include "RenderObject.h"
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+CompositeAnimation::~CompositeAnimation()
+{
+ // Toss the refs to all animations
+ m_transitions.clear();
+ m_keyframeAnimations.clear();
+}
+
+void CompositeAnimation::clearRenderer()
+{
+ if (!m_transitions.isEmpty()) {
+ // Clear the renderers from all running animations, in case we are in the middle of
+ // an animation callback (see https://bugs.webkit.org/show_bug.cgi?id=22052)
+ CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
+ ImplicitAnimation* transition = it->second.get();
+ transition->clearRenderer();
+ }
+ }
+ if (!m_keyframeAnimations.isEmpty()) {
+ m_keyframeAnimations.checkConsistency();
+ AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
+ KeyframeAnimation* anim = it->second.get();
+ anim->clearRenderer();
+ }
+ }
+}
+
+void CompositeAnimation::updateTransitions(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
+{
+ // If currentStyle is null or there are no old or new transitions, just skip it
+ if (!currentStyle || (!targetStyle->transitions() && m_transitions.isEmpty()))
+ return;
+
+ // Mark all existing transitions as no longer active. We will mark the still active ones
+ // in the next loop and then toss the ones that didn't get marked.
+ CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it)
+ it->second->setActive(false);
+
+ RefPtr<RenderStyle> modifiedCurrentStyle;
+
+ // Check to see if we need to update the active transitions
+ if (targetStyle->transitions()) {
+ for (size_t i = 0; i < targetStyle->transitions()->size(); ++i) {
+ const Animation* anim = targetStyle->transitions()->animation(i);
+ bool isActiveTransition = anim->duration() || anim->delay() > 0;
+
+ int prop = anim->property();
+
+ if (prop == cAnimateNone)
+ continue;
+
+ bool all = prop == cAnimateAll;
+
+ // Handle both the 'all' and single property cases. For the single prop case, we make only one pass
+ // through the loop.
+ for (int propertyIndex = 0; propertyIndex < AnimationBase::getNumProperties(); ++propertyIndex) {
+ if (all) {
+ // Get the next property which is not a shorthand.
+ bool isShorthand;
+ prop = AnimationBase::getPropertyAtIndex(propertyIndex, isShorthand);
+ if (isShorthand)
+ continue;
+ }
+
+ // ImplicitAnimations are always hashed by actual properties, never cAnimateAll
+ ASSERT(prop >= firstCSSProperty && prop < (firstCSSProperty + numCSSProperties));
+
+ // If there is a running animation for this property, the transition is overridden
+ // and we have to use the unanimatedStyle from the animation. We do the test
+ // against the unanimated style here, but we "override" the transition later.
+ RefPtr<KeyframeAnimation> keyframeAnim = getAnimationForProperty(prop);
+ RenderStyle* fromStyle = keyframeAnim ? keyframeAnim->unanimatedStyle() : currentStyle;
+
+ // See if there is a current transition for this prop
+ ImplicitAnimation* implAnim = m_transitions.get(prop).get();
+ bool equal = true;
+
+ if (implAnim) {
+ // If we are post active don't bother setting the active flag. This will cause
+ // this animation to get removed at the end of this function.
+ if (!implAnim->postActive())
+ implAnim->setActive(true);
+
+ // This might be a transition that is just finishing. That would be the case
+ // if it were postActive. But we still need to check for equality because
+ // it could be just finishing AND changing to a new goal state.
+ //
+ // This implAnim might also not be an already running transition. It might be
+ // newly added to the list in a previous iteration. This would happen if
+ // you have both an explicit transition-property and 'all' in the same
+ // list. In this case, the latter one overrides the earlier one, so we
+ // behave as though this is a running animation being replaced.
+ if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) {
+ #if USE(ACCELERATED_COMPOSITING)
+ // For accelerated animations we need to return a new RenderStyle with the _current_ value
+ // of the property, so that restarted transitions use the correct starting point.
+ if (AnimationBase::animationOfPropertyIsAccelerated(prop) && implAnim->isAccelerated()) {
+ if (!modifiedCurrentStyle)
+ modifiedCurrentStyle = RenderStyle::clone(currentStyle);
+
+ implAnim->blendPropertyValueInStyle(prop, modifiedCurrentStyle.get());
+ }
+ #endif
+ m_transitions.remove(prop);
+ equal = false;
+ }
+ } else {
+ // We need to start a transition if it is active and the properties don't match
+ equal = !isActiveTransition || AnimationBase::propertiesEqual(prop, fromStyle, targetStyle);
+ }
+
+ // We can be in this loop with an inactive transition (!isActiveTransition). We need
+ // to do that to check to see if we are canceling a transition. But we don't want to
+ // start one of the inactive transitions. So short circuit that here. (See
+ // <https://bugs.webkit.org/show_bug.cgi?id=24787>
+ if (!equal && isActiveTransition) {
+ // Add the new transition
+ m_transitions.set(prop, ImplicitAnimation::create(const_cast<Animation*>(anim), prop, renderer, this, modifiedCurrentStyle ? modifiedCurrentStyle.get() : fromStyle));
+ }
+
+ // We only need one pass for the single prop case
+ if (!all)
+ break;
+ }
+ }
+ }
+
+ // Make a list of transitions to be removed
+ Vector<int> toBeRemoved;
+ end = m_transitions.end();
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
+ ImplicitAnimation* anim = it->second.get();
+ if (!anim->active())
+ toBeRemoved.append(anim->animatingProperty());
+ }
+
+ // Now remove the transitions from the list
+ for (size_t j = 0; j < toBeRemoved.size(); ++j)
+ m_transitions.remove(toBeRemoved[j]);
+}
+
+void CompositeAnimation::updateKeyframeAnimations(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
+{
+ // Nothing to do if we don't have any animations, and didn't have any before
+ if (m_keyframeAnimations.isEmpty() && !targetStyle->hasAnimations())
+ return;
+
+ m_keyframeAnimations.checkConsistency();
+
+ AnimationNameMap::const_iterator kfend = m_keyframeAnimations.end();
+
+ if (currentStyle && currentStyle->hasAnimations() && targetStyle->hasAnimations() && *(currentStyle->animations()) == *(targetStyle->animations())) {
+ // The current and target animations are the same so we just need to toss any
+ // animation which is finished (postActive).
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) {
+ if (it->second->postActive())
+ it->second->setIndex(-1);
+ }
+ } else {
+ // Mark all existing animations as no longer active.
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it)
+ it->second->setIndex(-1);
+
+ // Toss the animation order map.
+ m_keyframeAnimationOrderMap.clear();
+
+ DEFINE_STATIC_LOCAL(const AtomicString, none, ("none"));
+
+ // Now mark any still active animations as active and add any new animations.
+ if (targetStyle->animations()) {
+ int numAnims = targetStyle->animations()->size();
+ for (int i = 0; i < numAnims; ++i) {
+ const Animation* anim = targetStyle->animations()->animation(i);
+ AtomicString animationName(anim->name());
+
+ if (!anim->isValidAnimation())
+ continue;
+
+ // See if there is a current animation for this name.
+ RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(animationName.impl());
+
+ if (keyframeAnim) {
+ // If this animation is postActive, skip it so it gets removed at the end of this function.
+ if (keyframeAnim->postActive())
+ continue;
+
+ // This one is still active.
+
+ // Animations match, but play states may differ. Update if needed.
+ keyframeAnim->updatePlayState(anim->playState());
+
+ // Set the saved animation to this new one, just in case the play state has changed.
+ keyframeAnim->setAnimation(anim);
+ keyframeAnim->setIndex(i);
+ } else if ((anim->duration() || anim->delay()) && anim->iterationCount() && animationName != none) {
+ keyframeAnim = KeyframeAnimation::create(const_cast<Animation*>(anim), renderer, i, this, targetStyle);
+ m_keyframeAnimations.set(keyframeAnim->name().impl(), keyframeAnim);
+ }
+
+ // Add this to the animation order map.
+ if (keyframeAnim)
+ m_keyframeAnimationOrderMap.append(keyframeAnim->name().impl());
+ }
+ }
+ }
+
+ // Make a list of animations to be removed.
+ Vector<AtomicStringImpl*> animsToBeRemoved;
+ kfend = m_keyframeAnimations.end();
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) {
+ KeyframeAnimation* keyframeAnim = it->second.get();
+ if (keyframeAnim->index() < 0)
+ animsToBeRemoved.append(keyframeAnim->name().impl());
+ }
+
+ // Now remove the animations from the list.
+ for (size_t j = 0; j < animsToBeRemoved.size(); ++j)
+ m_keyframeAnimations.remove(animsToBeRemoved[j]);
+}
+
+PassRefPtr<RenderStyle> CompositeAnimation::animate(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
+{
+ RefPtr<RenderStyle> resultStyle;
+
+ // We don't do any transitions if we don't have a currentStyle (on startup).
+ updateTransitions(renderer, currentStyle, targetStyle);
+ updateKeyframeAnimations(renderer, currentStyle, targetStyle);
+ m_keyframeAnimations.checkConsistency();
+
+ if (currentStyle) {
+ // Now that we have transition objects ready, let them know about the new goal state. We want them
+ // to fill in a RenderStyle*& only if needed.
+ if (!m_transitions.isEmpty()) {
+ CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
+ if (ImplicitAnimation* anim = it->second.get())
+ anim->animate(this, renderer, currentStyle, targetStyle, resultStyle);
+ }
+ }
+ }
+
+ // Now that we have animation objects ready, let them know about the new goal state. We want them
+ // to fill in a RenderStyle*& only if needed.
+ for (Vector<AtomicStringImpl*>::const_iterator it = m_keyframeAnimationOrderMap.begin(); it != m_keyframeAnimationOrderMap.end(); ++it) {
+ RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(*it);
+ if (keyframeAnim)
+ keyframeAnim->animate(this, renderer, currentStyle, targetStyle, resultStyle);
+ }
+
+ return resultStyle ? resultStyle.release() : targetStyle;
+}
+
+PassRefPtr<RenderStyle> CompositeAnimation::getAnimatedStyle() const
+{
+ RefPtr<RenderStyle> resultStyle;
+ CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
+ if (ImplicitAnimation* implicitAnimation = it->second.get())
+ implicitAnimation->getAnimatedStyle(resultStyle);
+ }
+
+ m_keyframeAnimations.checkConsistency();
+
+ for (Vector<AtomicStringImpl*>::const_iterator it = m_keyframeAnimationOrderMap.begin(); it != m_keyframeAnimationOrderMap.end(); ++it) {
+ RefPtr<KeyframeAnimation> keyframeAnimation = m_keyframeAnimations.get(*it);
+ if (keyframeAnimation)
+ keyframeAnimation->getAnimatedStyle(resultStyle);
+ }
+
+ return resultStyle;
+}
+
+// "animating" means that something is running that requires the timer to keep firing
+void CompositeAnimation::setAnimating(bool animating)
+{
+ if (!m_transitions.isEmpty()) {
+ CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
+ ImplicitAnimation* transition = it->second.get();
+ transition->setAnimating(animating);
+ }
+ }
+ if (!m_keyframeAnimations.isEmpty()) {
+ m_keyframeAnimations.checkConsistency();
+ AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
+ KeyframeAnimation* anim = it->second.get();
+ anim->setAnimating(animating);
+ }
+ }
+}
+
+double CompositeAnimation::timeToNextService() const
+{
+ // Returns the time at which next service is required. -1 means no service is required. 0 means
+ // service is required now, and > 0 means service is required that many seconds in the future.
+ double minT = -1;
+
+ if (!m_transitions.isEmpty()) {
+ CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
+ ImplicitAnimation* transition = it->second.get();
+ double t = transition ? transition->timeToNextService() : -1;
+ if (t < minT || minT == -1)
+ minT = t;
+ if (minT == 0)
+ return 0;
+ }
+ }
+ if (!m_keyframeAnimations.isEmpty()) {
+ m_keyframeAnimations.checkConsistency();
+ AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
+ KeyframeAnimation* animation = it->second.get();
+ double t = animation ? animation->timeToNextService() : -1;
+ if (t < minT || minT == -1)
+ minT = t;
+ if (minT == 0)
+ return 0;
+ }
+ }
+
+ return minT;
+}
+
+PassRefPtr<KeyframeAnimation> CompositeAnimation::getAnimationForProperty(int property) const
+{
+ RefPtr<KeyframeAnimation> retval;
+
+ // We want to send back the last animation with the property if there are multiples.
+ // So we need to iterate through all animations
+ if (!m_keyframeAnimations.isEmpty()) {
+ m_keyframeAnimations.checkConsistency();
+ AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
+ RefPtr<KeyframeAnimation> anim = it->second;
+ if (anim->hasAnimationForProperty(property))
+ retval = anim;
+ }
+ }
+
+ return retval;
+}
+
+void CompositeAnimation::suspendAnimations()
+{
+ if (m_suspended)
+ return;
+
+ m_suspended = true;
+
+ if (!m_keyframeAnimations.isEmpty()) {
+ m_keyframeAnimations.checkConsistency();
+ AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
+ if (KeyframeAnimation* anim = it->second.get())
+ anim->updatePlayState(AnimPlayStatePaused);
+ }
+ }
+ if (!m_transitions.isEmpty()) {
+ CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
+ ImplicitAnimation* anim = it->second.get();
+ if (anim && anim->hasStyle())
+ anim->updatePlayState(AnimPlayStatePaused);
+ }
+ }
+}
+
+void CompositeAnimation::resumeAnimations()
+{
+ if (!m_suspended)
+ return;
+
+ m_suspended = false;
+
+ if (!m_keyframeAnimations.isEmpty()) {
+ m_keyframeAnimations.checkConsistency();
+ AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
+ KeyframeAnimation* anim = it->second.get();
+ if (anim && anim->playStatePlaying())
+ anim->updatePlayState(AnimPlayStatePlaying);
+ }
+ }
+
+ if (!m_transitions.isEmpty()) {
+ CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
+ ImplicitAnimation* anim = it->second.get();
+ if (anim && anim->hasStyle())
+ anim->updatePlayState(AnimPlayStatePlaying);
+ }
+ }
+}
+
+void CompositeAnimation::overrideImplicitAnimations(int property)
+{
+ CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
+ if (!m_transitions.isEmpty()) {
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
+ ImplicitAnimation* anim = it->second.get();
+ if (anim && anim->animatingProperty() == property)
+ anim->setOverridden(true);
+ }
+ }
+}
+
+void CompositeAnimation::resumeOverriddenImplicitAnimations(int property)
+{
+ if (!m_transitions.isEmpty()) {
+ CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
+ ImplicitAnimation* anim = it->second.get();
+ if (anim && anim->animatingProperty() == property)
+ anim->setOverridden(false);
+ }
+ }
+}
+
+bool CompositeAnimation::isAnimatingProperty(int property, bool acceleratedOnly, bool isRunningNow) const
+{
+ if (!m_keyframeAnimations.isEmpty()) {
+ m_keyframeAnimations.checkConsistency();
+ AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
+ KeyframeAnimation* anim = it->second.get();
+ if (anim && anim->isAnimatingProperty(property, acceleratedOnly, isRunningNow))
+ return true;
+ }
+ }
+
+ if (!m_transitions.isEmpty()) {
+ CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
+ ImplicitAnimation* anim = it->second.get();
+ if (anim && anim->isAnimatingProperty(property, acceleratedOnly, isRunningNow))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CompositeAnimation::pauseAnimationAtTime(const AtomicString& name, double t)
+{
+ if (!name)
+ return false;
+
+ m_keyframeAnimations.checkConsistency();
+
+ RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(name.impl());
+ if (!keyframeAnim || !keyframeAnim->running())
+ return false;
+
+ int count = keyframeAnim->m_animation->iterationCount();
+ if ((t >= 0.0) && (!count || (t <= count * keyframeAnim->duration()))) {
+ keyframeAnim->freezeAtTime(t);
+ return true;
+ }
+
+ return false;
+}
+
+bool CompositeAnimation::pauseTransitionAtTime(int property, double t)
+{
+ if ((property < firstCSSProperty) || (property >= firstCSSProperty + numCSSProperties))
+ return false;
+
+ ImplicitAnimation* implAnim = m_transitions.get(property).get();
+ if (!implAnim) {
+ // Check to see if this property is being animated via a shorthand.
+ // This code is only used for testing, so performance is not critical here.
+ HashSet<int> shorthandProperties = AnimationBase::animatableShorthandsAffectingProperty(property);
+ bool anyPaused = false;
+ HashSet<int>::const_iterator end = shorthandProperties.end();
+ for (HashSet<int>::const_iterator it = shorthandProperties.begin(); it != end; ++it) {
+ if (pauseTransitionAtTime(*it, t))
+ anyPaused = true;
+ }
+ return anyPaused;
+ }
+
+ if (!implAnim->running())
+ return false;
+
+ if ((t >= 0.0) && (t <= implAnim->duration())) {
+ implAnim->freezeAtTime(t);
+ return true;
+ }
+
+ return false;
+}
+
+unsigned CompositeAnimation::numberOfActiveAnimations() const
+{
+ unsigned count = 0;
+
+ if (!m_keyframeAnimations.isEmpty()) {
+ m_keyframeAnimations.checkConsistency();
+ AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
+ KeyframeAnimation* anim = it->second.get();
+ if (anim->running())
+ ++count;
+ }
+ }
+
+ if (!m_transitions.isEmpty()) {
+ CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
+ ImplicitAnimation* anim = it->second.get();
+ if (anim->running())
+ ++count;
+ }
+ }
+
+ return count;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/animation/CompositeAnimation.h b/Source/WebCore/page/animation/CompositeAnimation.h
new file mode 100644
index 0000000..249f4c3
--- /dev/null
+++ b/Source/WebCore/page/animation/CompositeAnimation.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 CompositeAnimation_h
+#define CompositeAnimation_h
+
+#include "ImplicitAnimation.h"
+#include "KeyframeAnimation.h"
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/text/AtomicString.h>
+
+namespace WebCore {
+
+class AnimationControllerPrivate;
+class AnimationController;
+class RenderObject;
+class RenderStyle;
+
+// A CompositeAnimation represents a collection of animations that are running
+// on a single RenderObject, such as a number of properties transitioning at once.
+class CompositeAnimation : public RefCounted<CompositeAnimation> {
+public:
+ static PassRefPtr<CompositeAnimation> create(AnimationControllerPrivate* animationController)
+ {
+ return adoptRef(new CompositeAnimation(animationController));
+ };
+
+ ~CompositeAnimation();
+
+ void clearRenderer();
+
+ PassRefPtr<RenderStyle> animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
+ PassRefPtr<RenderStyle> getAnimatedStyle() const;
+
+ double timeToNextService() const;
+
+ AnimationControllerPrivate* animationController() const { return m_animationController; }
+
+ void suspendAnimations();
+ void resumeAnimations();
+ bool suspended() const { return m_suspended; }
+
+ bool hasAnimations() const { return !m_transitions.isEmpty() || !m_keyframeAnimations.isEmpty(); }
+
+ void setAnimating(bool);
+ bool isAnimatingProperty(int property, bool acceleratedOnly, bool isRunningNow) const;
+
+ PassRefPtr<KeyframeAnimation> getAnimationForProperty(int property) const;
+
+ void overrideImplicitAnimations(int property);
+ void resumeOverriddenImplicitAnimations(int property);
+
+ bool pauseAnimationAtTime(const AtomicString& name, double t);
+ bool pauseTransitionAtTime(int property, double t);
+ unsigned numberOfActiveAnimations() const;
+
+private:
+ CompositeAnimation(AnimationControllerPrivate* animationController)
+ : m_animationController(animationController)
+ , m_numStyleAvailableWaiters(0)
+ , m_suspended(false)
+ {
+ }
+
+ void updateTransitions(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
+ void updateKeyframeAnimations(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
+
+ typedef HashMap<int, RefPtr<ImplicitAnimation> > CSSPropertyTransitionsMap;
+ typedef HashMap<AtomicStringImpl*, RefPtr<KeyframeAnimation> > AnimationNameMap;
+
+ AnimationControllerPrivate* m_animationController;
+ CSSPropertyTransitionsMap m_transitions;
+ AnimationNameMap m_keyframeAnimations;
+ Vector<AtomicStringImpl*> m_keyframeAnimationOrderMap;
+ unsigned m_numStyleAvailableWaiters;
+ bool m_suspended;
+};
+
+} // namespace WebCore
+
+#endif // CompositeAnimation_h
diff --git a/Source/WebCore/page/animation/ImplicitAnimation.cpp b/Source/WebCore/page/animation/ImplicitAnimation.cpp
new file mode 100644
index 0000000..34607f6
--- /dev/null
+++ b/Source/WebCore/page/animation/ImplicitAnimation.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "AnimationControllerPrivate.h"
+#include "CompositeAnimation.h"
+#include "CSSPropertyNames.h"
+#include "EventNames.h"
+#include "ImplicitAnimation.h"
+#include "KeyframeAnimation.h"
+#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+ImplicitAnimation::ImplicitAnimation(const Animation* transition, int animatingProperty, RenderObject* renderer, CompositeAnimation* compAnim, RenderStyle* fromStyle)
+ : AnimationBase(transition, renderer, compAnim)
+ , m_transitionProperty(transition->property())
+ , m_animatingProperty(animatingProperty)
+ , m_overridden(false)
+ , m_active(true)
+ , m_fromStyle(fromStyle)
+{
+ ASSERT(animatingProperty != cAnimateAll);
+}
+
+ImplicitAnimation::~ImplicitAnimation()
+{
+ // // Make sure to tell the renderer that we are ending. This will make sure any accelerated animations are removed.
+ if (!postActive())
+ endAnimation();
+}
+
+bool ImplicitAnimation::shouldSendEventForListener(Document::ListenerType inListenerType) const
+{
+ return m_object->document()->hasListenerType(inListenerType);
+}
+
+void ImplicitAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
+{
+ // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
+ // So just return. Everything is already all cleaned up.
+ if (postActive())
+ return;
+
+ // Reset to start the transition if we are new
+ if (isNew())
+ reset(targetStyle);
+
+ // Run a cycle of animation.
+ // We know we will need a new render style, so make one if needed
+ if (!animatedStyle)
+ animatedStyle = RenderStyle::clone(targetStyle);
+
+ bool needsAnim = blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0));
+ // FIXME: we also need to detect cases where we have to software animate for other reasons,
+ // such as a child using inheriting the transform. https://bugs.webkit.org/show_bug.cgi?id=23902
+ if (needsAnim)
+ setAnimating();
+ else {
+#if USE(ACCELERATED_COMPOSITING)
+ // If we are running an accelerated animation, set a flag in the style which causes the style
+ // to compare as different to any other style. This ensures that changes to the property
+ // that is animating are correctly detected during the animation (e.g. when a transition
+ // gets interrupted).
+ animatedStyle->setIsRunningAcceleratedAnimation();
+#endif
+ }
+
+ // Fire the start timeout if needed
+ fireAnimationEventsIfNeeded();
+}
+
+void ImplicitAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle)
+{
+ if (!animatedStyle)
+ animatedStyle = RenderStyle::clone(m_toStyle.get());
+
+ blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0));
+}
+
+bool ImplicitAnimation::startAnimation(double timeOffset)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_object && m_object->hasLayer()) {
+ RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
+ if (layer->isComposited())
+ return layer->backing()->startTransition(timeOffset, m_animatingProperty, m_fromStyle.get(), m_toStyle.get());
+ }
+#else
+ UNUSED_PARAM(timeOffset);
+#endif
+ return false;
+}
+
+void ImplicitAnimation::pauseAnimation(double timeOffset)
+{
+ if (!m_object)
+ return;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_object->hasLayer()) {
+ RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
+ if (layer->isComposited())
+ layer->backing()->transitionPaused(timeOffset, m_animatingProperty);
+ }
+#else
+ UNUSED_PARAM(timeOffset);
+#endif
+ // Restore the original (unanimated) style
+ if (!paused())
+ setNeedsStyleRecalc(m_object->node());
+}
+
+void ImplicitAnimation::endAnimation()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_object && m_object->hasLayer()) {
+ RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
+ if (layer->isComposited())
+ layer->backing()->transitionFinished(m_animatingProperty);
+ }
+#endif
+}
+
+void ImplicitAnimation::onAnimationEnd(double elapsedTime)
+{
+ // If we have a keyframe animation on this property, this transition is being overridden. The keyframe
+ // animation keeps an unanimated style in case a transition starts while the keyframe animation is
+ // running. But now that the transition has completed, we need to update this style with its new
+ // destination. If we didn't, the next time through we would think a transition had started
+ // (comparing the old unanimated style with the new final style of the transition).
+ RefPtr<KeyframeAnimation> keyframeAnim = m_compAnim->getAnimationForProperty(m_animatingProperty);
+ if (keyframeAnim)
+ keyframeAnim->setUnanimatedStyle(m_toStyle);
+
+ sendTransitionEvent(eventNames().webkitTransitionEndEvent, elapsedTime);
+ endAnimation();
+}
+
+bool ImplicitAnimation::sendTransitionEvent(const AtomicString& eventType, double elapsedTime)
+{
+ if (eventType == eventNames().webkitTransitionEndEvent) {
+ Document::ListenerType listenerType = Document::TRANSITIONEND_LISTENER;
+
+ if (shouldSendEventForListener(listenerType)) {
+ String propertyName;
+ if (m_animatingProperty != cAnimateAll)
+ propertyName = getPropertyName(static_cast<CSSPropertyID>(m_animatingProperty));
+
+ // Dispatch the event
+ RefPtr<Element> element = 0;
+ if (m_object->node() && m_object->node()->isElementNode())
+ element = static_cast<Element*>(m_object->node());
+
+ ASSERT(!element || (element->document() && !element->document()->inPageCache()));
+ if (!element)
+ return false;
+
+ // Schedule event handling
+ m_compAnim->animationController()->addEventToDispatch(element, eventType, propertyName, elapsedTime);
+
+ // Restore the original (unanimated) style
+ if (eventType == eventNames().webkitTransitionEndEvent && element->renderer())
+ setNeedsStyleRecalc(element.get());
+
+ return true; // Did dispatch an event
+ }
+ }
+
+ return false; // Didn't dispatch an event
+}
+
+void ImplicitAnimation::reset(RenderStyle* to)
+{
+ ASSERT(to);
+ ASSERT(m_fromStyle);
+
+ m_toStyle = to;
+
+ // Restart the transition
+ if (m_fromStyle && m_toStyle)
+ updateStateMachine(AnimationStateInputRestartAnimation, -1);
+
+ // set the transform animation list
+ validateTransformFunctionList();
+}
+
+void ImplicitAnimation::setOverridden(bool b)
+{
+ if (b == m_overridden)
+ return;
+
+ m_overridden = b;
+ updateStateMachine(m_overridden ? AnimationStateInputPauseOverride : AnimationStateInputResumeOverride, -1);
+}
+
+bool ImplicitAnimation::affectsProperty(int property) const
+{
+ return (m_animatingProperty == property);
+}
+
+bool ImplicitAnimation::isTargetPropertyEqual(int prop, const RenderStyle* targetStyle)
+{
+ // We can get here for a transition that has not started yet. This would make m_toStyle unset and null.
+ // So we check that here (see <https://bugs.webkit.org/show_bug.cgi?id=26706>)
+ if (!m_toStyle)
+ return false;
+ return propertiesEqual(prop, m_toStyle.get(), targetStyle);
+}
+
+void ImplicitAnimation::blendPropertyValueInStyle(int prop, RenderStyle* currentStyle)
+{
+ // We should never add a transition with a 0 duration and delay. But if we ever did
+ // it would have a null toStyle. So just in case, let's check that here. (See
+ // <https://bugs.webkit.org/show_bug.cgi?id=24787>
+ if (!m_toStyle)
+ return;
+
+ blendProperties(this, prop, currentStyle, m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0));
+}
+
+void ImplicitAnimation::validateTransformFunctionList()
+{
+ m_transformFunctionListValid = false;
+
+ if (!m_fromStyle || !m_toStyle)
+ return;
+
+ const TransformOperations* val = &m_fromStyle->transform();
+ const TransformOperations* toVal = &m_toStyle->transform();
+
+ if (val->operations().isEmpty())
+ val = toVal;
+
+ if (val->operations().isEmpty())
+ return;
+
+ // See if the keyframes are valid
+ if (val != toVal) {
+ // A list of length 0 matches anything
+ if (!toVal->operations().isEmpty()) {
+ // If the sizes of the function lists don't match, the lists don't match
+ if (val->operations().size() != toVal->operations().size())
+ return;
+
+ // If the types of each function are not the same, the lists don't match
+ for (size_t j = 0; j < val->operations().size(); ++j) {
+ if (!val->operations()[j]->isSameType(*toVal->operations()[j]))
+ return;
+ }
+ }
+ }
+
+ // Keyframes are valid
+ m_transformFunctionListValid = true;
+}
+
+double ImplicitAnimation::timeToNextService()
+{
+ double t = AnimationBase::timeToNextService();
+#if USE(ACCELERATED_COMPOSITING)
+ if (t != 0 || preActive())
+ return t;
+
+ // A return value of 0 means we need service. But if this is an accelerated animation we
+ // only need service at the end of the transition.
+ if (animationOfPropertyIsAccelerated(m_animatingProperty) && isAccelerated()) {
+ bool isLooping;
+ getTimeToNextEvent(t, isLooping);
+ }
+#endif
+ return t;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/animation/ImplicitAnimation.h b/Source/WebCore/page/animation/ImplicitAnimation.h
new file mode 100644
index 0000000..c40c00a
--- /dev/null
+++ b/Source/WebCore/page/animation/ImplicitAnimation.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 ImplicitAnimation_h
+#define ImplicitAnimation_h
+
+#include "AnimationBase.h"
+#include "Document.h"
+
+namespace WebCore {
+
+// An ImplicitAnimation tracks the state of a transition of a specific CSS property
+// for a single RenderObject.
+class ImplicitAnimation : public AnimationBase {
+public:
+ static PassRefPtr<ImplicitAnimation> create(const Animation* animation, int animatingProperty, RenderObject* renderer, CompositeAnimation* compositeAnimation, RenderStyle* fromStyle)
+ {
+ return adoptRef(new ImplicitAnimation(animation, animatingProperty, renderer, compositeAnimation, fromStyle));
+ };
+
+ int transitionProperty() const { return m_transitionProperty; }
+ int animatingProperty() const { return m_animatingProperty; }
+
+ virtual void onAnimationEnd(double elapsedTime);
+ virtual bool startAnimation(double timeOffset);
+ virtual void pauseAnimation(double /*timeOffset*/);
+ virtual void endAnimation();
+
+ virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* currentStyle, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle);
+ virtual void getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle);
+ virtual void reset(RenderStyle* to);
+
+ void setOverridden(bool);
+ virtual bool overridden() const { return m_overridden; }
+
+ virtual bool affectsProperty(int) const;
+
+ bool hasStyle() const { return m_fromStyle && m_toStyle; }
+
+ bool isTargetPropertyEqual(int, const RenderStyle* targetStyle);
+
+ void blendPropertyValueInStyle(int, RenderStyle* currentStyle);
+
+ virtual double timeToNextService();
+
+ bool active() const { return m_active; }
+ void setActive(bool b) { m_active = b; }
+
+protected:
+ bool shouldSendEventForListener(Document::ListenerType) const;
+ bool sendTransitionEvent(const AtomicString&, double elapsedTime);
+
+ void validateTransformFunctionList();
+
+private:
+ ImplicitAnimation(const Animation*, int animatingProperty, RenderObject*, CompositeAnimation*, RenderStyle* fromStyle);
+ virtual ~ImplicitAnimation();
+
+ int m_transitionProperty; // Transition property as specified in the RenderStyle. May be cAnimateAll
+ int m_animatingProperty; // Specific property for this ImplicitAnimation
+ bool m_overridden; // true when there is a keyframe animation that overrides the transitioning property
+ bool m_active; // used for culling the list of transitions
+
+ // The two styles that we are blending.
+ RefPtr<RenderStyle> m_fromStyle;
+ RefPtr<RenderStyle> m_toStyle;
+};
+
+} // namespace WebCore
+
+#endif // ImplicitAnimation_h
diff --git a/Source/WebCore/page/animation/KeyframeAnimation.cpp b/Source/WebCore/page/animation/KeyframeAnimation.cpp
new file mode 100644
index 0000000..a499188
--- /dev/null
+++ b/Source/WebCore/page/animation/KeyframeAnimation.cpp
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "KeyframeAnimation.h"
+
+#include "AnimationControllerPrivate.h"
+#include "CSSPropertyNames.h"
+#include "CSSStyleSelector.h"
+#include "CompositeAnimation.h"
+#include "EventNames.h"
+#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
+#include "RenderStyle.h"
+#include <wtf/UnusedParam.h>
+
+using namespace std;
+
+namespace WebCore {
+
+KeyframeAnimation::KeyframeAnimation(const Animation* animation, RenderObject* renderer, int index, CompositeAnimation* compAnim, RenderStyle* unanimatedStyle)
+ : AnimationBase(animation, renderer, compAnim)
+ , m_keyframes(renderer, animation->name())
+ , m_index(index)
+ , m_startEventDispatched(false)
+ , m_unanimatedStyle(unanimatedStyle)
+{
+ // Get the keyframe RenderStyles
+ if (m_object && m_object->node() && m_object->node()->isElementNode())
+ m_object->document()->styleSelector()->keyframeStylesForAnimation(static_cast<Element*>(m_object->node()), unanimatedStyle, m_keyframes);
+
+ // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match.
+ validateTransformFunctionList();
+}
+
+KeyframeAnimation::~KeyframeAnimation()
+{
+ // Make sure to tell the renderer that we are ending. This will make sure any accelerated animations are removed.
+ if (!postActive())
+ endAnimation();
+}
+
+void KeyframeAnimation::fetchIntervalEndpointsForProperty(int property, const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const
+{
+ // Find the first key
+ double elapsedTime = getElapsedTime();
+ if (m_animation->duration() && m_animation->iterationCount() != Animation::IterationCountInfinite)
+ elapsedTime = min(elapsedTime, m_animation->duration() * m_animation->iterationCount());
+
+ double fractionalTime = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1;
+
+ // FIXME: startTime can be before the current animation "frame" time. This is to sync with the frame time
+ // concept in AnimationTimeController. So we need to somehow sync the two. Until then, the possible
+ // error is small and will probably not be noticeable. Until we fix this, remove the assert.
+ // https://bugs.webkit.org/show_bug.cgi?id=52037
+ // ASSERT(fractionalTime >= 0);
+ if (fractionalTime < 0)
+ fractionalTime = 0;
+
+ // FIXME: share this code with AnimationBase::progress().
+ int iteration = static_cast<int>(fractionalTime);
+ if (m_animation->iterationCount() != Animation::IterationCountInfinite)
+ iteration = min(iteration, m_animation->iterationCount() - 1);
+ fractionalTime -= iteration;
+
+ bool reversing = (m_animation->direction() == Animation::AnimationDirectionAlternate) && (iteration & 1);
+ if (reversing)
+ fractionalTime = 1 - fractionalTime;
+
+ size_t numKeyframes = m_keyframes.size();
+ if (!numKeyframes)
+ return;
+
+ ASSERT(!m_keyframes[0].key());
+ ASSERT(m_keyframes[m_keyframes.size() - 1].key() == 1);
+
+ int prevIndex = -1;
+ int nextIndex = -1;
+
+ // FIXME: with a lot of keys, this linear search will be slow. We could binary search.
+ for (size_t i = 0; i < numKeyframes; ++i) {
+ const KeyframeValue& currKeyFrame = m_keyframes[i];
+
+ if (!currKeyFrame.containsProperty(property))
+ continue;
+
+ if (fractionalTime < currKeyFrame.key()) {
+ nextIndex = i;
+ break;
+ }
+
+ prevIndex = i;
+ }
+
+ double scale = 1;
+ double offset = 0;
+
+ if (prevIndex == -1)
+ prevIndex = 0;
+
+ if (nextIndex == -1)
+ nextIndex = m_keyframes.size() - 1;
+
+ const KeyframeValue& prevKeyframe = m_keyframes[prevIndex];
+ const KeyframeValue& nextKeyframe = m_keyframes[nextIndex];
+
+ fromStyle = prevKeyframe.style();
+ toStyle = nextKeyframe.style();
+
+ offset = prevKeyframe.key();
+ scale = 1.0 / (nextKeyframe.key() - prevKeyframe.key());
+
+ const TimingFunction* timingFunction = 0;
+ if (fromStyle->animations() && fromStyle->animations()->size() > 0) {
+ // We get the timing function from the first animation, because we've synthesized a RenderStyle for each keyframe.
+ timingFunction = fromStyle->animations()->animation(0)->timingFunction().get();
+ }
+
+ prog = progress(scale, offset, timingFunction);
+}
+
+void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
+{
+ // Fire the start timeout if needed
+ fireAnimationEventsIfNeeded();
+
+ // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
+ if (isNew() && m_animation->playState() == AnimPlayStatePlaying)
+ updateStateMachine(AnimationStateInputStartAnimation, -1);
+
+ // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
+ // If so, we need to send back the targetStyle.
+ if (postActive()) {
+ if (!animatedStyle)
+ animatedStyle = const_cast<RenderStyle*>(targetStyle);
+ return;
+ }
+
+ // If we are waiting for the start timer, we don't want to change the style yet.
+ // Special case 1 - if the delay time is 0, then we do want to set the first frame of the
+ // animation right away. This avoids a flash when the animation starts.
+ // Special case 2 - if there is a backwards fill mode, then we want to continue
+ // through to the style blend so that we get the fromStyle.
+ if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards())
+ return;
+
+ // If we have no keyframes, don't animate.
+ if (!m_keyframes.size()) {
+ updateStateMachine(AnimationStateInputEndAnimation, -1);
+ return;
+ }
+
+ // Run a cycle of animation.
+ // We know we will need a new render style, so make one if needed.
+ if (!animatedStyle)
+ animatedStyle = RenderStyle::clone(targetStyle);
+
+ // FIXME: we need to be more efficient about determining which keyframes we are animating between.
+ // We should cache the last pair or something.
+ HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
+ for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
+ int property = *it;
+
+ // Get the from/to styles and progress between
+ const RenderStyle* fromStyle = 0;
+ const RenderStyle* toStyle = 0;
+ double progress;
+ fetchIntervalEndpointsForProperty(property, fromStyle, toStyle, progress);
+
+ bool needsAnim = blendProperties(this, property, animatedStyle.get(), fromStyle, toStyle, progress);
+ if (needsAnim)
+ setAnimating();
+ else {
+#if USE(ACCELERATED_COMPOSITING)
+ // If we are running an accelerated animation, set a flag in the style
+ // to indicate it. This can be used to make sure we get an updated
+ // style for hit testing, etc.
+ animatedStyle->setIsRunningAcceleratedAnimation();
+#endif
+ }
+ }
+}
+
+void KeyframeAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle)
+{
+ // If we're in the delay phase and we're not backwards filling, tell the caller
+ // to use the current style.
+ if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards())
+ return;
+
+ if (!m_keyframes.size())
+ return;
+
+ if (!animatedStyle)
+ animatedStyle = RenderStyle::clone(m_object->style());
+
+ HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
+ for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
+ int property = *it;
+
+ // Get the from/to styles and progress between
+ const RenderStyle* fromStyle = 0;
+ const RenderStyle* toStyle = 0;
+ double progress;
+ fetchIntervalEndpointsForProperty(property, fromStyle, toStyle, progress);
+
+ blendProperties(this, property, animatedStyle.get(), fromStyle, toStyle, progress);
+ }
+}
+
+bool KeyframeAnimation::hasAnimationForProperty(int property) const
+{
+ // FIXME: why not just m_keyframes.containsProperty()?
+ HashSet<int>::const_iterator end = m_keyframes.endProperties();
+ for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
+ if (*it == property)
+ return true;
+ }
+
+ return false;
+}
+
+bool KeyframeAnimation::startAnimation(double timeOffset)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_object && m_object->hasLayer()) {
+ RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
+ if (layer->isComposited())
+ return layer->backing()->startAnimation(timeOffset, m_animation.get(), m_keyframes);
+ }
+#else
+ UNUSED_PARAM(timeOffset);
+#endif
+ return false;
+}
+
+void KeyframeAnimation::pauseAnimation(double timeOffset)
+{
+ if (!m_object)
+ return;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_object->hasLayer()) {
+ RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
+ if (layer->isComposited())
+ layer->backing()->animationPaused(timeOffset, m_keyframes.animationName());
+ }
+#else
+ UNUSED_PARAM(timeOffset);
+#endif
+ // Restore the original (unanimated) style
+ if (!paused())
+ setNeedsStyleRecalc(m_object->node());
+}
+
+void KeyframeAnimation::endAnimation()
+{
+ if (!m_object)
+ return;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_object->hasLayer()) {
+ RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
+ if (layer->isComposited())
+ layer->backing()->animationFinished(m_keyframes.animationName());
+ }
+#endif
+ // Restore the original (unanimated) style
+ if (!paused())
+ setNeedsStyleRecalc(m_object->node());
+}
+
+bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) const
+{
+ return m_object->document()->hasListenerType(listenerType);
+}
+
+void KeyframeAnimation::onAnimationStart(double elapsedTime)
+{
+ sendAnimationEvent(eventNames().webkitAnimationStartEvent, elapsedTime);
+}
+
+void KeyframeAnimation::onAnimationIteration(double elapsedTime)
+{
+ sendAnimationEvent(eventNames().webkitAnimationIterationEvent, elapsedTime);
+}
+
+void KeyframeAnimation::onAnimationEnd(double elapsedTime)
+{
+ sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime);
+ // End the animation if we don't fill forwards. Forward filling
+ // animations are ended properly in the class destructor.
+ if (!m_animation->fillsForwards())
+ endAnimation();
+}
+
+bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime)
+{
+ Document::ListenerType listenerType;
+ if (eventType == eventNames().webkitAnimationIterationEvent)
+ listenerType = Document::ANIMATIONITERATION_LISTENER;
+ else if (eventType == eventNames().webkitAnimationEndEvent)
+ listenerType = Document::ANIMATIONEND_LISTENER;
+ else {
+ ASSERT(eventType == eventNames().webkitAnimationStartEvent);
+ if (m_startEventDispatched)
+ return false;
+ m_startEventDispatched = true;
+ listenerType = Document::ANIMATIONSTART_LISTENER;
+ }
+
+ if (shouldSendEventForListener(listenerType)) {
+ // Dispatch the event
+ RefPtr<Element> element;
+ if (m_object->node() && m_object->node()->isElementNode())
+ element = static_cast<Element*>(m_object->node());
+
+ ASSERT(!element || (element->document() && !element->document()->inPageCache()));
+ if (!element)
+ return false;
+
+ // Schedule event handling
+ m_compAnim->animationController()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime);
+
+ // Restore the original (unanimated) style
+ if (eventType == eventNames().webkitAnimationEndEvent && element->renderer())
+ setNeedsStyleRecalc(element.get());
+
+ return true; // Did dispatch an event
+ }
+
+ return false; // Did not dispatch an event
+}
+
+void KeyframeAnimation::overrideAnimations()
+{
+ // This will override implicit animations that match the properties in the keyframe animation
+ HashSet<int>::const_iterator end = m_keyframes.endProperties();
+ for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
+ compositeAnimation()->overrideImplicitAnimations(*it);
+}
+
+void KeyframeAnimation::resumeOverriddenAnimations()
+{
+ // This will resume overridden implicit animations
+ HashSet<int>::const_iterator end = m_keyframes.endProperties();
+ for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
+ compositeAnimation()->resumeOverriddenImplicitAnimations(*it);
+}
+
+bool KeyframeAnimation::affectsProperty(int property) const
+{
+ HashSet<int>::const_iterator end = m_keyframes.endProperties();
+ for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
+ if (*it == property)
+ return true;
+ }
+ return false;
+}
+
+void KeyframeAnimation::validateTransformFunctionList()
+{
+ m_transformFunctionListValid = false;
+
+ if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform))
+ return;
+
+ // Empty transforms match anything, so find the first non-empty entry as the reference
+ size_t numKeyframes = m_keyframes.size();
+ size_t firstNonEmptyTransformKeyframeIndex = numKeyframes;
+
+ for (size_t i = 0; i < numKeyframes; ++i) {
+ const KeyframeValue& currentKeyframe = m_keyframes[i];
+ if (currentKeyframe.style()->transform().operations().size()) {
+ firstNonEmptyTransformKeyframeIndex = i;
+ break;
+ }
+ }
+
+ if (firstNonEmptyTransformKeyframeIndex == numKeyframes)
+ return;
+
+ const TransformOperations* firstVal = &m_keyframes[firstNonEmptyTransformKeyframeIndex].style()->transform();
+
+ // See if the keyframes are valid
+ for (size_t i = firstNonEmptyTransformKeyframeIndex + 1; i < numKeyframes; ++i) {
+ const KeyframeValue& currentKeyframe = m_keyframes[i];
+ const TransformOperations* val = &currentKeyframe.style()->transform();
+
+ // A null transform matches anything
+ if (val->operations().isEmpty())
+ continue;
+
+ // If the sizes of the function lists don't match, the lists don't match
+ if (firstVal->operations().size() != val->operations().size())
+ return;
+
+ // If the types of each function are not the same, the lists don't match
+ for (size_t j = 0; j < firstVal->operations().size(); ++j) {
+ if (!firstVal->operations()[j]->isSameType(*val->operations()[j]))
+ return;
+ }
+ }
+
+ // Keyframes are valid
+ m_transformFunctionListValid = true;
+}
+
+double KeyframeAnimation::timeToNextService()
+{
+ double t = AnimationBase::timeToNextService();
+#if USE(ACCELERATED_COMPOSITING)
+ if (t != 0 || preActive())
+ return t;
+
+ // A return value of 0 means we need service. But if we only have accelerated animations we
+ // only need service at the end of the transition
+ HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
+ bool acceleratedPropertiesOnly = true;
+
+ for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
+ if (!animationOfPropertyIsAccelerated(*it) || !isAccelerated()) {
+ acceleratedPropertiesOnly = false;
+ break;
+ }
+ }
+
+ if (acceleratedPropertiesOnly) {
+ bool isLooping;
+ getTimeToNextEvent(t, isLooping);
+ }
+#endif
+ return t;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/animation/KeyframeAnimation.h b/Source/WebCore/page/animation/KeyframeAnimation.h
new file mode 100644
index 0000000..5099b50
--- /dev/null
+++ b/Source/WebCore/page/animation/KeyframeAnimation.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 KeyframeAnimation_h
+#define KeyframeAnimation_h
+
+#include "AnimationBase.h"
+#include "Document.h"
+#include "KeyframeList.h"
+
+namespace WebCore {
+
+class RenderStyle;
+
+// A KeyframeAnimation tracks the state of an explicit animation
+// for a single RenderObject.
+class KeyframeAnimation : public AnimationBase {
+public:
+ static PassRefPtr<KeyframeAnimation> create(const Animation* animation, RenderObject* renderer, int index, CompositeAnimation* compositeAnimation, RenderStyle* unanimatedStyle)
+ {
+ return adoptRef(new KeyframeAnimation(animation, renderer, index, compositeAnimation, unanimatedStyle));
+ };
+
+ virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* currentStyle, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle);
+ virtual void getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle);
+
+ const AtomicString& name() const { return m_keyframes.animationName(); }
+ int index() const { return m_index; }
+ void setIndex(int i) { m_index = i; }
+
+ bool hasAnimationForProperty(int property) const;
+
+ void setUnanimatedStyle(PassRefPtr<RenderStyle> style) { m_unanimatedStyle = style; }
+ RenderStyle* unanimatedStyle() const { return m_unanimatedStyle.get(); }
+
+ virtual double timeToNextService();
+
+protected:
+ virtual void onAnimationStart(double elapsedTime);
+ virtual void onAnimationIteration(double elapsedTime);
+ virtual void onAnimationEnd(double elapsedTime);
+ virtual bool startAnimation(double timeOffset);
+ virtual void pauseAnimation(double timeOffset);
+ virtual void endAnimation();
+
+ virtual void overrideAnimations();
+ virtual void resumeOverriddenAnimations();
+
+ bool shouldSendEventForListener(Document::ListenerType inListenerType) const;
+ bool sendAnimationEvent(const AtomicString&, double elapsedTime);
+
+ virtual bool affectsProperty(int) const;
+
+ void validateTransformFunctionList();
+
+private:
+ KeyframeAnimation(const Animation* animation, RenderObject*, int index, CompositeAnimation*, RenderStyle* unanimatedStyle);
+ virtual ~KeyframeAnimation();
+
+ // Get the styles for the given property surrounding the current animation time and the progress between them.
+ void fetchIntervalEndpointsForProperty(int property, const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& progress) const;
+
+ // The keyframes that we are blending.
+ KeyframeList m_keyframes;
+
+ // The order in which this animation appears in the animation-name style.
+ int m_index;
+ bool m_startEventDispatched;
+
+ // The style just before we started animation
+ RefPtr<RenderStyle> m_unanimatedStyle;
+};
+
+} // namespace WebCore
+
+#endif // KeyframeAnimation_h
diff --git a/Source/WebCore/page/brew/ChromeClientBrew.h b/Source/WebCore/page/brew/ChromeClientBrew.h
new file mode 100644
index 0000000..d1fac2d
--- /dev/null
+++ b/Source/WebCore/page/brew/ChromeClientBrew.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010, Company 100, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ChromeClientBrew_h
+#define ChromeClientBrew_h
+
+#include "ChromeClient.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+class IntRect;
+class PopupMenuClient;
+
+// Contains Brew-specific extensions to the ChromeClient. Only put
+// things here that don't make sense for other ports.
+class ChromeClientBrew : public ChromeClient {
+public:
+ virtual void createSelectPopup(PopupMenuClient*, int selected, const IntRect& rect) = 0;
+ virtual bool destroySelectPopup() = 0;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/page/brew/DragControllerBrew.cpp b/Source/WebCore/page/brew/DragControllerBrew.cpp
new file mode 100644
index 0000000..ef89821
--- /dev/null
+++ b/Source/WebCore/page/brew/DragControllerBrew.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009-2010 Company 100, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DragController.h"
+
+#include "DragData.h"
+
+namespace WebCore {
+
+// FIXME: These values are straight out of DragControllerMac, so probably have
+// little correlation with BREW standards...
+const int DragController::LinkDragBorderInset = 2;
+const int DragController::MaxOriginalImageArea = 1500 * 1500;
+const int DragController::DragIconRightInset = 7;
+const int DragController::DragIconBottomInset = 3;
+
+const float DragController::DragImageAlpha = 0.75f;
+
+
+bool DragController::isCopyKeyDown()
+{
+ return false;
+}
+
+DragOperation DragController::dragOperation(DragData* dragData)
+{
+ // FIXME: This logic is incomplete
+ if (dragData->containsURL())
+ return DragOperationCopy;
+
+ return DragOperationNone;
+}
+
+const IntSize& DragController::maxDragImageSize()
+{
+ static const IntSize maxDragImageSize(400, 400);
+
+ return maxDragImageSize;
+}
+
+void DragController::cleanupAfterSystemDrag()
+{
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/page/brew/EventHandlerBrew.cpp b/Source/WebCore/page/brew/EventHandlerBrew.cpp
new file mode 100644
index 0000000..e3b6645
--- /dev/null
+++ b/Source/WebCore/page/brew/EventHandlerBrew.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2010 Company 100, Inc.
+ * Copyright 2009, The Android Open Source Project
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "EventHandler.h"
+
+#include "ClipboardBrew.h"
+#include "EventNames.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "HitTestResult.h"
+#include "KeyboardEvent.h"
+#include "MouseEventWithHitTestResults.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "RenderWidget.h"
+
+namespace WebCore {
+
+bool EventHandler::tabsToAllControls(KeyboardEvent* event) const
+{
+ return true;
+}
+
+void EventHandler::focusDocumentView()
+{
+ Page* page = m_frame->page();
+ if (page)
+ page->focusController()->setFocusedFrame(m_frame);
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
+{
+ // Figure out which view to send the event to.
+ RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0;
+ if (!target || !target->isWidget())
+ return false;
+ return passMouseDownEventToWidget(toRenderWidget(target)->widget());
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
+{
+ return passMouseDownEventToWidget(renderWidget->widget());
+}
+
+// This function is used to route the mouse down event to the native widgets, it seems like a
+// work around for the Mac platform which does not support double clicks, but browsers do.
+bool EventHandler::passMouseDownEventToWidget(Widget* widget)
+{
+ notImplemented();
+ return false;
+}
+
+bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const
+{
+ notImplemented();
+ return false;
+}
+
+// This function is called for mouse events by FrameView::handleMousePressEvent().
+// It is used to ensure that events are sync'ed correctly between frames. For example
+// if the user presses down in one frame and up in another frame, this function will
+// returns true, and pass the event to the correct frame.
+bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult*)
+{
+ notImplemented();
+ return false;
+}
+
+// This is called to route wheel events to child widgets when they are RenderWidget
+// as the parent usually gets wheel event. Don't have a mouse with a wheel to confirm
+// the operation of this function.
+bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& event, Widget* widget)
+{
+ notImplemented();
+ return false;
+}
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ return passSubframeEventToSubframe(mev, subframe);
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
+{
+ return passSubframeEventToSubframe(mev, subframe, hoveredNode);
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ return passSubframeEventToSubframe(mev, subframe);
+}
+
+unsigned EventHandler::accessKeyModifiers()
+{
+ return PlatformKeyboardEvent::AltKey;
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/page/brew/FrameBrew.cpp b/Source/WebCore/page/brew/FrameBrew.cpp
new file mode 100644
index 0000000..7825dbd
--- /dev/null
+++ b/Source/WebCore/page/brew/FrameBrew.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Company 100, Inc. All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Frame.h"
+
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+DragImageRef Frame::nodeImage(Node*)
+{
+ notImplemented();
+ return 0;
+}
+
+DragImageRef Frame::dragImageForSelection()
+{
+ notImplemented();
+ return 0;
+}
+
+}
diff --git a/Source/WebCore/page/chromium/ChromeClientChromium.h b/Source/WebCore/page/chromium/ChromeClientChromium.h
new file mode 100644
index 0000000..02e2a94
--- /dev/null
+++ b/Source/WebCore/page/chromium/ChromeClientChromium.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ChromeClientChromium_h
+#define ChromeClientChromium_h
+
+#include "ChromeClient.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+class IntRect;
+class PopupContainer;
+
+// Contains Chromium-specific extensions to the ChromeClient. Only put
+// things here that don't make sense for other ports.
+class ChromeClientChromium : public ChromeClient {
+public:
+ // Notifies the client of a new popup widget. The client should place
+ // and size the widget with the given bounds, relative to the screen.
+ // If handleExternal is true, then drawing and input handling for the
+ // popup will be handled by the external embedder.
+ virtual void popupOpened(PopupContainer* popupContainer, const IntRect& bounds,
+ bool handleExternal) = 0;
+
+ // Notifies the client a popup was closed.
+ virtual void popupClosed(PopupContainer* popupContainer) = 0;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/WebCore/page/chromium/DragControllerChromium.cpp b/Source/WebCore/page/chromium/DragControllerChromium.cpp
new file mode 100644
index 0000000..de53d19
--- /dev/null
+++ b/Source/WebCore/page/chromium/DragControllerChromium.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DragController.h"
+
+#include "DragData.h"
+#include "SelectionController.h"
+#include <wtf/RefPtr.h>
+
+#if OS(WINDOWS)
+#include <windows.h>
+#endif
+
+namespace WebCore {
+
+const int DragController::LinkDragBorderInset = 2;
+const int DragController::MaxOriginalImageArea = 1500 * 1500;
+const int DragController::DragIconRightInset = 7;
+const int DragController::DragIconBottomInset = 3;
+
+const float DragController::DragImageAlpha = 0.75f;
+
+DragOperation DragController::dragOperation(DragData* dragData)
+{
+ // FIXME: To match the MacOS behaviour we should return DragOperationNone
+ // if we are a modal window, we are the drag source, or the window is an
+ // attached sheet If this can be determined from within WebCore
+ // operationForDrag can be pulled into WebCore itself
+ ASSERT(dragData);
+ return dragData->containsURL() && !m_didInitiateDrag ? DragOperationCopy : DragOperationNone;
+}
+
+bool DragController::isCopyKeyDown()
+{
+ // FIXME: This should not be OS specific. Delegate to the embedder instead.
+#if OS(WINDOWS)
+ return ::GetAsyncKeyState(VK_CONTROL);
+#else
+ return false;
+#endif
+}
+
+const IntSize& DragController::maxDragImageSize()
+{
+#if OS(DARWIN)
+ // Match Safari's drag image size.
+ static const IntSize maxDragImageSize(400, 400);
+#else
+ static const IntSize maxDragImageSize(200, 200);
+#endif
+ return maxDragImageSize;
+}
+
+void DragController::cleanupAfterSystemDrag()
+{
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/chromium/EventHandlerChromium.cpp b/Source/WebCore/page/chromium/EventHandlerChromium.cpp
new file mode 100644
index 0000000..9b40fb3
--- /dev/null
+++ b/Source/WebCore/page/chromium/EventHandlerChromium.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "EventHandler.h"
+
+#include "ChromiumDataObject.h"
+#include "ClipboardChromium.h"
+#include "Cursor.h"
+#include "FloatPoint.h"
+#include "FocusController.h"
+#include "FrameView.h"
+#include "Frame.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "MouseEventWithHitTestResults.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "RenderWidget.h"
+#include "SelectionController.h"
+
+namespace WebCore {
+
+#if OS(DARWIN)
+const double EventHandler::TextDragDelay = 0.15;
+#else
+const double EventHandler::TextDragDelay = 0.0;
+#endif
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ // If we're clicking into a frame that is selected, the frame will appear
+ // greyed out even though we're clicking on the selection. This looks
+ // really strange (having the whole frame be greyed out), so we deselect the
+ // selection.
+ IntPoint p = m_frame->view()->windowToContents(mev.event().pos());
+ if (m_frame->selection()->contains(p)) {
+ VisiblePosition visiblePos(
+ mev.targetNode()->renderer()->positionForPoint(mev.localPoint()));
+ VisibleSelection newSelection(visiblePos);
+ if (m_frame->selection()->shouldChangeSelection(newSelection))
+ m_frame->selection()->setSelection(newSelection);
+ }
+
+ subframe->eventHandler()->handleMousePressEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
+{
+ if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
+ return false;
+ subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
+ return true;
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& wheelEvent, Widget* widget)
+{
+ // We can sometimes get a null widget! EventHandlerMac handles a null
+ // widget by returning false, so we do the same.
+ if (!widget)
+ return false;
+
+ // If not a FrameView, then probably a plugin widget. Those will receive
+ // the event via an EventTargetNode dispatch when this returns false.
+ if (!widget->isFrameView())
+ return false;
+
+ return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent);
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
+{
+ // Figure out which view to send the event to.
+ if (!event.targetNode() || !event.targetNode()->renderer() || !event.targetNode()->renderer()->isWidget())
+ return false;
+ return passMouseDownEventToWidget(toRenderWidget(event.targetNode()->renderer())->widget());
+}
+
+bool EventHandler::passMouseDownEventToWidget(Widget* widget)
+{
+ notImplemented();
+ return false;
+}
+
+bool EventHandler::tabsToAllControls(KeyboardEvent*) const
+{
+ return true;
+}
+
+bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
+{
+ // FIXME: EventHandlerWin.cpp does the following:
+ // return event.activatedWebView();
+ return false;
+}
+
+PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
+{
+ RefPtr<ChromiumDataObjectLegacy> dataObject = ChromiumDataObjectLegacy::create(Clipboard::DragAndDrop);
+ return ClipboardChromium::create(Clipboard::DragAndDrop, ChromiumDataObject::create(dataObject), ClipboardWritable, m_frame);
+}
+
+void EventHandler::focusDocumentView()
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+ page->focusController()->setFocusedFrame(m_frame);
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
+{
+ return passMouseDownEventToWidget(renderWidget->widget());
+}
+
+unsigned EventHandler::accessKeyModifiers()
+{
+#if OS(DARWIN)
+ return PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey;
+#else
+ return PlatformKeyboardEvent::AltKey;
+#endif
+}
+
+#if OS(LINUX) || OS(FREEBSD)
+// GTK+ must scroll horizontally if the mouse pointer is on top of the
+// horizontal scrollbar while scrolling with the wheel.
+// This code comes from gtk/EventHandlerGtk.cpp.
+bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult& result) const
+{
+ return result.scrollbar() && result.scrollbar()->orientation() == HorizontalScrollbar;
+}
+#endif
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/chromium/FrameChromium.cpp b/Source/WebCore/page/chromium/FrameChromium.cpp
new file mode 100644
index 0000000..15ff8b4
--- /dev/null
+++ b/Source/WebCore/page/chromium/FrameChromium.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Document.h"
+#include "FloatRect.h"
+#include "ImageBuffer.h"
+#include "RenderView.h"
+#include "Settings.h"
+
+namespace WebCore {
+
+namespace {
+
+struct ScopedState {
+ ScopedState(Frame* theFrame, RenderObject* theRenderer)
+ : frame(theFrame)
+ , renderer(theRenderer)
+ , paintBehavior(frame->view()->paintBehavior())
+ , backgroundColor(frame->view()->baseBackgroundColor())
+ {
+ }
+
+ ~ScopedState()
+ {
+ if (renderer)
+ renderer->updateDragState(false);
+ frame->view()->setPaintBehavior(paintBehavior);
+ frame->view()->setBaseBackgroundColor(backgroundColor);
+ frame->view()->setNodeToDraw(0);
+ }
+
+ Frame* frame;
+ RenderObject* renderer;
+ PaintBehavior paintBehavior;
+ Color backgroundColor;
+};
+
+} // namespace
+
+DragImageRef Frame::nodeImage(Node* node)
+{
+ RenderObject* renderer = node->renderer();
+ if (!renderer)
+ return 0;
+
+ const ScopedState state(this, renderer);
+
+ renderer->updateDragState(true);
+ m_view->setPaintBehavior(state.paintBehavior | PaintBehaviorFlattenCompositingLayers);
+ // When generating the drag image for an element, ignore the document background.
+ m_view->setBaseBackgroundColor(colorWithOverrideAlpha(Color::white, 1.0));
+ m_doc->updateLayout();
+ m_view->setNodeToDraw(node); // Enable special sub-tree drawing mode.
+
+ IntRect topLevelRect;
+ IntRect paintingRect = renderer->paintingRootRect(topLevelRect);
+
+ OwnPtr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size()));
+ if (!buffer)
+ return 0;
+ buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
+ buffer->context()->clip(FloatRect(0, 0, paintingRect.right(), paintingRect.bottom()));
+
+ m_view->paintContents(buffer->context(), paintingRect);
+
+ RefPtr<Image> image = buffer->copyImage();
+ return createDragImageFromImage(image.get());
+}
+
+DragImageRef Frame::dragImageForSelection()
+{
+ if (!selection()->isRange())
+ return 0;
+
+ const ScopedState state(this, 0);
+ m_view->setPaintBehavior(PaintBehaviorSelectionOnly);
+ m_doc->updateLayout();
+
+ IntRect paintingRect = enclosingIntRect(selection()->bounds());
+
+ OwnPtr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size()));
+ if (!buffer)
+ return 0;
+ buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
+ buffer->context()->clip(FloatRect(0, 0, paintingRect.right(), paintingRect.bottom()));
+
+ m_view->paintContents(buffer->context(), paintingRect);
+
+ RefPtr<Image> image = buffer->copyImage();
+ return createDragImageFromImage(image.get());
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/efl/DragControllerEfl.cpp b/Source/WebCore/page/efl/DragControllerEfl.cpp
new file mode 100644
index 0000000..0c5f002
--- /dev/null
+++ b/Source/WebCore/page/efl/DragControllerEfl.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007 Apple Inc.
+ * Copyright (C) 2009-2010 ProFUSION embedded systems
+ * Copyright (C) 2009-2010 Samsung Electronics
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DragController.h"
+
+#include "DragData.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "Page.h"
+
+namespace WebCore {
+
+const int DragController::LinkDragBorderInset = 2;
+const int DragController::MaxOriginalImageArea = 1500 * 1500;
+const int DragController::DragIconRightInset = 7;
+const int DragController::DragIconBottomInset = 3;
+
+const float DragController::DragImageAlpha = 0.75f;
+
+bool DragController::isCopyKeyDown()
+{
+ return false;
+}
+
+DragOperation DragController::dragOperation(DragData* dragData)
+{
+ if (dragData->containsURL())
+ return DragOperationCopy;
+
+ return DragOperationNone;
+}
+
+const IntSize& DragController::maxDragImageSize()
+{
+ static const IntSize maxDragImageSize(400, 400);
+
+ return maxDragImageSize;
+}
+
+void DragController::cleanupAfterSystemDrag()
+{}
+
+}
diff --git a/Source/WebCore/page/efl/EventHandlerEfl.cpp b/Source/WebCore/page/efl/EventHandlerEfl.cpp
new file mode 100644
index 0000000..33db17e
--- /dev/null
+++ b/Source/WebCore/page/efl/EventHandlerEfl.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia
+ * Copyright (C) 2009,2010 ProFUSION embedded systems
+ * Copyright (C) 2009,2010 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "EventHandler.h"
+
+#include "ClipboardEfl.h"
+#include "EventNames.h"
+#include "FloatPoint.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "KeyboardEvent.h"
+#include "MouseEventWithHitTestResults.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "RenderWidget.h"
+#include "Scrollbar.h"
+
+namespace WebCore {
+
+const double EventHandler::TextDragDelay = 0.0;
+
+static bool isKeyboardOptionTab(KeyboardEvent* event)
+{
+ return event
+ && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
+ && event->altKey()
+ && event->keyIdentifier() == "U+0009";
+}
+
+bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const
+{
+ return isKeyboardOptionTab(event);
+}
+
+bool EventHandler::tabsToAllControls(KeyboardEvent* event) const
+{
+ return true;
+}
+
+void EventHandler::focusDocumentView()
+{
+ if (Page* page = m_frame->page())
+ page->focusController()->setFocusedFrame(m_frame);
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
+{
+ RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0;
+
+ if (!target || !target->isWidget())
+ return false;
+
+ return passMouseDownEventToWidget(static_cast<RenderWidget*>(target)->widget());
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
+{
+ return passMouseDownEventToWidget(renderWidget->widget());
+}
+
+bool EventHandler::passMouseDownEventToWidget(Widget* widget)
+{
+ notImplemented();
+ return false;
+}
+
+bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const
+{
+ notImplemented();
+ return false;
+}
+
+bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& event, Widget* widget)
+{
+ ASSERT(widget);
+ if (!widget->isFrameView())
+ return false;
+
+ return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(event);
+}
+
+PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
+{
+ return ClipboardEfl::create(ClipboardWritable, Clipboard::DragAndDrop);
+}
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMousePressEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
+{
+ subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
+ return true;
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
+ return true;
+}
+
+unsigned EventHandler::accessKeyModifiers()
+{
+ return PlatformKeyboardEvent::AltKey;
+}
+}
diff --git a/Source/WebCore/page/efl/FrameEfl.cpp b/Source/WebCore/page/efl/FrameEfl.cpp
new file mode 100644
index 0000000..b1be9ca
--- /dev/null
+++ b/Source/WebCore/page/efl/FrameEfl.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia
+ * Copyright (C) 2009-2010 ProFUSION embedded systems
+ * Copyright (C) 2009-2010 Samsung Electronics
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Frame.h"
+
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+DragImageRef Frame::nodeImage(Node* node)
+{
+ notImplemented();
+ return 0;
+}
+
+DragImageRef Frame::dragImageForSelection()
+{
+ notImplemented();
+ return 0;
+}
+
+}
diff --git a/Source/WebCore/page/gtk/DragControllerGtk.cpp b/Source/WebCore/page/gtk/DragControllerGtk.cpp
new file mode 100644
index 0000000..5f9044f
--- /dev/null
+++ b/Source/WebCore/page/gtk/DragControllerGtk.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DragController.h"
+
+#include "DragData.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "Page.h"
+
+namespace WebCore {
+
+// FIXME: These values are straight out of DragControllerMac, so probably have
+// little correlation with Gdk standards...
+const int DragController::LinkDragBorderInset = 2;
+const int DragController::MaxOriginalImageArea = 1500 * 1500;
+const int DragController::DragIconRightInset = 7;
+const int DragController::DragIconBottomInset = 3;
+
+const float DragController::DragImageAlpha = 0.75f;
+
+bool DragController::isCopyKeyDown()
+{
+ return false;
+}
+
+DragOperation DragController::dragOperation(DragData* dragData)
+{
+ //FIXME: This logic is incomplete
+ if (dragData->containsURL())
+ return DragOperationCopy;
+
+ return DragOperationNone;
+}
+
+const IntSize& DragController::maxDragImageSize()
+{
+ static const IntSize maxDragImageSize(200, 200);
+ return maxDragImageSize;
+}
+
+void DragController::cleanupAfterSystemDrag()
+{
+}
+
+}
diff --git a/Source/WebCore/page/gtk/EventHandlerGtk.cpp b/Source/WebCore/page/gtk/EventHandlerGtk.cpp
new file mode 100644
index 0000000..6e69d9f
--- /dev/null
+++ b/Source/WebCore/page/gtk/EventHandlerGtk.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "EventHandler.h"
+
+#include "ClipboardGtk.h"
+#include "FloatPoint.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "KeyboardEvent.h"
+#include "MouseEventWithHitTestResults.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "RenderWidget.h"
+#include "Scrollbar.h"
+
+namespace WebCore {
+
+const double EventHandler::TextDragDelay = 0.0;
+
+bool EventHandler::tabsToAllControls(KeyboardEvent* event) const
+{
+ // We always allow tabs to all controls
+ return true;
+}
+
+void EventHandler::focusDocumentView()
+{
+ if (Page* page = m_frame->page())
+ page->focusController()->setFocusedFrame(m_frame);
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
+{
+ // Figure out which view to send the event to.
+ RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0;
+ if (!target || !target->isWidget())
+ return false;
+ return passMouseDownEventToWidget(toRenderWidget(target)->widget());
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
+{
+ return passMouseDownEventToWidget(renderWidget->widget());
+}
+
+bool EventHandler::passMouseDownEventToWidget(Widget* widget)
+{
+ notImplemented();
+ return false;
+}
+
+bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const
+{
+ //GTK+ activation is not necessarily tied to mouse events, so it may
+ //not make sense to implement this
+
+ notImplemented();
+ return false;
+}
+
+bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& event, Widget* widget)
+{
+ ASSERT(widget);
+ if (!widget->isFrameView())
+ return false;
+
+ return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(event);
+}
+
+PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
+{
+ return ClipboardGtk::create(ClipboardWritable, DataObjectGtk::create(), Clipboard::DragAndDrop, m_frame);
+}
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMousePressEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
+{
+ subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
+ return true;
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
+ return true;
+}
+
+unsigned EventHandler::accessKeyModifiers()
+{
+ return PlatformKeyboardEvent::AltKey;
+}
+
+// GTK+ must scroll horizontally if the mouse pointer is on top of the
+// horizontal scrollbar while scrolling with the wheel; we need to
+// add the deltas and ticks here so that this behavior is consistent
+// for styled scrollbars.
+bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult& result) const
+{
+ return result.scrollbar() && result.scrollbar()->orientation() == HorizontalScrollbar;
+}
+
+}
diff --git a/Source/WebCore/page/gtk/FrameGtk.cpp b/Source/WebCore/page/gtk/FrameGtk.cpp
new file mode 100644
index 0000000..14a0f8b
--- /dev/null
+++ b/Source/WebCore/page/gtk/FrameGtk.cpp
@@ -0,0 +1,43 @@
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Frame.h"
+
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+DragImageRef Frame::nodeImage(Node*)
+{
+ notImplemented();
+ return 0;
+}
+
+DragImageRef Frame::dragImageForSelection()
+{
+ notImplemented();
+ return 0;
+}
+
+}
diff --git a/Source/WebCore/page/haiku/DragControllerHaiku.cpp b/Source/WebCore/page/haiku/DragControllerHaiku.cpp
new file mode 100644
index 0000000..ef08ac2
--- /dev/null
+++ b/Source/WebCore/page/haiku/DragControllerHaiku.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DragController.h"
+
+#include "DragData.h"
+
+#include <InterfaceDefs.h>
+
+
+namespace WebCore {
+
+// FIXME: These values are straight out of DragControllerMac, so probably have
+// little correlation with Haiku standards...
+const int DragController::LinkDragBorderInset = 2;
+const int DragController::MaxOriginalImageArea = 1500 * 1500;
+const int DragController::DragIconRightInset = 7;
+const int DragController::DragIconBottomInset = 3;
+
+const float DragController::DragImageAlpha = 0.75f;
+
+
+bool DragController::isCopyKeyDown()
+{
+ if (modifiers() & B_COMMAND_KEY)
+ return true;
+
+ return false;
+}
+
+DragOperation DragController::dragOperation(DragData* dragData)
+{
+ // FIXME: This logic is incomplete
+ if (dragData->containsURL())
+ return DragOperationCopy;
+
+ return DragOperationNone;
+}
+
+const IntSize& DragController::maxDragImageSize()
+{
+ static const IntSize maxDragImageSize(400, 400);
+
+ return maxDragImageSize;
+}
+
+void DragController::cleanupAfterSystemDrag()
+{
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/page/haiku/EventHandlerHaiku.cpp b/Source/WebCore/page/haiku/EventHandlerHaiku.cpp
new file mode 100644
index 0000000..933921a
--- /dev/null
+++ b/Source/WebCore/page/haiku/EventHandlerHaiku.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com>
+ * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "EventHandler.h"
+
+#include "ClipboardHaiku.h"
+#include "EventNames.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "HitTestResult.h"
+#include "KeyboardEvent.h"
+#include "MouseEventWithHitTestResults.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "RenderWidget.h"
+
+#include <interface/View.h>
+
+
+namespace WebCore {
+
+const double EventHandler::TextDragDelay = 0.0;
+
+static bool isKeyboardOptionTab(KeyboardEvent* event)
+{
+ return event
+ && (event->type() == eventNames().keydownEvent
+ || event->type() == eventNames().keypressEvent)
+ && event->altKey()
+ && event->keyIdentifier() == "U+0009";
+}
+
+bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const
+{
+ return isKeyboardOptionTab(event);
+}
+
+bool EventHandler::tabsToAllControls(KeyboardEvent* event) const
+{
+ bool handlingOptionTab = isKeyboardOptionTab(event);
+
+ return handlingOptionTab;
+}
+
+void EventHandler::focusDocumentView()
+{
+ BView* view = m_frame->view()->platformWidget();
+ if (view && view->LockLooperWithTimeout(5000) == B_OK) {
+ view->MakeFocus(true);
+ view->UnlockLooper();
+ }
+
+ Page* page = m_frame->page();
+ if (page)
+ page->focusController()->setFocusedFrame(m_frame);
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
+{
+ // Figure out which view to send the event to.
+ RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0;
+ if (!target || !target->isWidget())
+ return false;
+ return passMouseDownEventToWidget(toRenderWidget(target)->widget());
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
+{
+ return passMouseDownEventToWidget(renderWidget->widget());
+}
+
+bool EventHandler::passMouseDownEventToWidget(Widget* widget)
+{
+ notImplemented();
+ return false;
+}
+
+bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
+{
+ // On Haiku, clicks which activate the window in non focus-follows-mouse mode
+ // are not passed to the window, so any event we generate is not the activation
+ // event.
+ return false;
+}
+
+bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& event, Widget* widget)
+{
+ if (!widget->isFrameView())
+ return false;
+
+ return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(event);
+}
+
+PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
+{
+ return ClipboardHaiku::create(ClipboardWritable, Clipboard::DragAndDrop);
+}
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMousePressEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
+{
+ subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
+ return true;
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
+ return true;
+}
+
+unsigned EventHandler::accessKeyModifiers()
+{
+ // NOTE: On Haiku, the user can choose Alt or Ctrl as access key, but
+ // the PlatformKeyboardEvent already takes care of this, internally,
+ // we always use Alt.
+ return PlatformKeyboardEvent::AltKey;
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/page/haiku/FrameHaiku.cpp b/Source/WebCore/page/haiku/FrameHaiku.cpp
new file mode 100644
index 0000000..5ff6950
--- /dev/null
+++ b/Source/WebCore/page/haiku/FrameHaiku.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Frame.h"
+
+#include "NotImplemented.h"
+
+
+namespace WebCore {
+
+DragImageRef Frame::nodeImage(Node*)
+{
+ notImplemented();
+ return 0;
+}
+
+DragImageRef Frame::dragImageForSelection()
+{
+ notImplemented();
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/mac/ChromeMac.mm b/Source/WebCore/page/mac/ChromeMac.mm
new file mode 100644
index 0000000..d2ae39d
--- /dev/null
+++ b/Source/WebCore/page/mac/ChromeMac.mm
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#import "config.h"
+#import "Chrome.h"
+
+#import "BlockExceptions.h"
+#import "ChromeClient.h"
+
+namespace WebCore {
+
+
+void Chrome::focusNSView(NSView* view)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ NSResponder *firstResponder = client()->firstResponder();
+ if (firstResponder == view)
+ return;
+
+ if (![view window] || ![view superview] || ![view acceptsFirstResponder])
+ return;
+
+ client()->makeFirstResponder(view);
+
+ // Setting focus can actually cause a style change which might
+ // remove the view from its superview while it's being made
+ // first responder. This confuses AppKit so we must restore
+ // the old first responder.
+ if (![view superview])
+ client()->makeFirstResponder(firstResponder);
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/mac/DragControllerMac.mm b/Source/WebCore/page/mac/DragControllerMac.mm
new file mode 100644
index 0000000..05c8e09
--- /dev/null
+++ b/Source/WebCore/page/mac/DragControllerMac.mm
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "DragController.h"
+
+#if ENABLE(DRAG_SUPPORT)
+#import "DragData.h"
+#import "Frame.h"
+#import "FrameView.h"
+#import "Page.h"
+
+namespace WebCore {
+
+const int DragController::LinkDragBorderInset = -2;
+
+const int DragController::MaxOriginalImageArea = 1500 * 1500;
+const int DragController::DragIconRightInset = 7;
+const int DragController::DragIconBottomInset = 3;
+
+const float DragController::DragImageAlpha = 0.75f;
+
+bool DragController::isCopyKeyDown()
+{
+ return [[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask;
+}
+
+DragOperation DragController::dragOperation(DragData* dragData)
+{
+ ASSERT(dragData);
+ if ([NSApp modalWindow] || !dragData->containsURL())
+ return DragOperationNone;
+
+ if (!m_documentUnderMouse || (![[m_page->mainFrame()->view()->getOuterView() window] attachedSheet]
+ && [dragData->platformData() draggingSource] != m_page->mainFrame()->view()->getOuterView()))
+ return DragOperationCopy;
+
+ return DragOperationNone;
+}
+
+const IntSize& DragController::maxDragImageSize()
+{
+ static const IntSize maxDragImageSize(400, 400);
+
+ return maxDragImageSize;
+}
+
+void DragController::cleanupAfterSystemDrag()
+{
+ // Drag has ended, dragEnded *should* have been called, however it is possible
+ // for the UIDelegate to take over the drag, and fail to send the appropriate
+ // drag termination event. As dragEnded just resets drag variables, we just
+ // call it anyway to be on the safe side
+ dragEnded();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(DRAG_SUPPORT)
diff --git a/Source/WebCore/page/mac/EventHandlerMac.mm b/Source/WebCore/page/mac/EventHandlerMac.mm
new file mode 100644
index 0000000..2d4d86b
--- /dev/null
+++ b/Source/WebCore/page/mac/EventHandlerMac.mm
@@ -0,0 +1,790 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "EventHandler.h"
+
+#include "AXObjectCache.h"
+#include "BlockExceptions.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "ClipboardMac.h"
+#include "DragController.h"
+#include "EventNames.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "KeyboardEvent.h"
+#include "MouseEventWithHitTestResults.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "RenderWidget.h"
+#include "RuntimeApplicationChecks.h"
+#include "Scrollbar.h"
+#include "Settings.h"
+#include "WebCoreSystemInterface.h"
+#include <objc/objc-runtime.h>
+#include <wtf/StdLibExtras.h>
+
+#if !(defined(OBJC_API_VERSION) && OBJC_API_VERSION > 0)
+static inline IMP method_setImplementation(Method m, IMP i)
+{
+ IMP oi = m->method_imp;
+ m->method_imp = i;
+ return oi;
+}
+#endif
+
+namespace WebCore {
+
+#if ENABLE(DRAG_SUPPORT)
+const double EventHandler::TextDragDelay = 0.15;
+#endif
+
+static RetainPtr<NSEvent>& currentNSEventSlot()
+{
+ DEFINE_STATIC_LOCAL(RetainPtr<NSEvent>, event, ());
+ return event;
+}
+
+NSEvent *EventHandler::currentNSEvent()
+{
+ return currentNSEventSlot().get();
+}
+
+class CurrentEventScope : public Noncopyable {
+public:
+ CurrentEventScope(NSEvent *);
+ ~CurrentEventScope();
+
+private:
+ RetainPtr<NSEvent> m_savedCurrentEvent;
+#ifndef NDEBUG
+ RetainPtr<NSEvent> m_event;
+#endif
+};
+
+inline CurrentEventScope::CurrentEventScope(NSEvent *event)
+ : m_savedCurrentEvent(currentNSEventSlot())
+#ifndef NDEBUG
+ , m_event(event)
+#endif
+{
+ currentNSEventSlot() = event;
+}
+
+inline CurrentEventScope::~CurrentEventScope()
+{
+ ASSERT(currentNSEventSlot() == m_event);
+ currentNSEventSlot() = m_savedCurrentEvent;
+}
+
+bool EventHandler::wheelEvent(NSEvent *event)
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return false;
+
+ CurrentEventScope scope(event);
+
+ m_useLatchedWheelEventNode = wkIsLatchingWheelEvent(event);
+
+ PlatformWheelEvent wheelEvent(event, page->chrome()->platformPageClient());
+ handleWheelEvent(wheelEvent);
+
+ return wheelEvent.isAccepted();
+}
+
+PassRefPtr<KeyboardEvent> EventHandler::currentKeyboardEvent() const
+{
+ NSEvent *event = [NSApp currentEvent];
+ if (!event)
+ return 0;
+ switch ([event type]) {
+ case NSKeyDown: {
+ PlatformKeyboardEvent platformEvent(event);
+ platformEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown);
+ return KeyboardEvent::create(platformEvent, m_frame->document()->defaultView());
+ }
+ case NSKeyUp:
+ return KeyboardEvent::create(event, m_frame->document()->defaultView());
+ default:
+ return 0;
+ }
+}
+
+bool EventHandler::keyEvent(NSEvent *event)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
+
+ CurrentEventScope scope(event);
+ return keyEvent(PlatformKeyboardEvent(event));
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return false;
+}
+
+void EventHandler::focusDocumentView()
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ if (FrameView* frameView = m_frame->view()) {
+ if (NSView *documentView = frameView->documentView())
+ page->chrome()->focusNSView(documentView);
+ }
+
+ page->focusController()->setFocusedFrame(m_frame);
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
+{
+ // Figure out which view to send the event to.
+ RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0;
+ if (!target || !target->isWidget())
+ return false;
+
+ // Double-click events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget will
+ // just pass currentEvent down to the widget, we don't want to call it for events that
+ // don't correspond to Cocoa events. The mousedown/ups will have already been passed on as
+ // part of the pressed/released handling.
+ return passMouseDownEventToWidget(toRenderWidget(target)->widget());
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
+{
+ return passMouseDownEventToWidget(renderWidget->widget());
+}
+
+static bool lastEventIsMouseUp()
+{
+ // Many AppKit widgets run their own event loops and consume events while the mouse is down.
+ // When they finish, currentEvent is the mouseUp that they exited on. We need to update
+ // the WebCore state with this mouseUp, which we never saw. This method lets us detect
+ // that state. Handling this was critical when we used AppKit widgets for form elements.
+ // It's not clear in what cases this is helpful now -- it's possible it can be removed.
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
+ return EventHandler::currentNSEvent() != currentEventAfterHandlingMouseDown
+ && [currentEventAfterHandlingMouseDown type] == NSLeftMouseUp
+ && [currentEventAfterHandlingMouseDown timestamp] >= [EventHandler::currentNSEvent() timestamp];
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return false;
+}
+
+bool EventHandler::passMouseDownEventToWidget(Widget* pWidget)
+{
+ // FIXME: This function always returns true. It should be changed either to return
+ // false in some cases or the return value should be removed.
+
+ RefPtr<Widget> widget = pWidget;
+
+ if (!widget) {
+ LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
+ return true;
+ }
+
+ // In WebKit2 we will never have an NSView. Just return early and let the regular event handler machinery take care of
+ // dispatching the event.
+ if (!widget->platformWidget())
+ return false;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ NSView *nodeView = widget->platformWidget();
+ ASSERT([nodeView superview]);
+ NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
+ if (!view) {
+ // We probably hit the border of a RenderWidget
+ return true;
+ }
+
+ Page* page = m_frame->page();
+ if (!page)
+ return true;
+
+ if (page->chrome()->client()->firstResponder() != view) {
+ // Normally [NSWindow sendEvent:] handles setting the first responder.
+ // But in our case, the event was sent to the view representing the entire web page.
+ if ([currentNSEvent() clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey])
+ page->chrome()->client()->makeFirstResponder(view);
+ }
+
+ // We need to "defer loading" while tracking the mouse, because tearing down the
+ // page while an AppKit control is tracking the mouse can cause a crash.
+
+ // FIXME: In theory, WebCore now tolerates tear-down while tracking the
+ // mouse. We should confirm that, and then remove the deferrsLoading
+ // hack entirely.
+
+ bool wasDeferringLoading = page->defersLoading();
+ if (!wasDeferringLoading)
+ page->setDefersLoading(true);
+
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ NSView *outerView = widget->getOuterView();
+ widget->beforeMouseDown(outerView, widget.get());
+ [view mouseDown:currentNSEvent()];
+ widget->afterMouseDown(outerView, widget.get());
+ m_sendingEventToSubview = false;
+
+ if (!wasDeferringLoading)
+ page->setDefersLoading(false);
+
+ // Remember which view we sent the event to, so we can direct the release event properly.
+ m_mouseDownView = view;
+ m_mouseDownWasInSubframe = false;
+
+ // Many AppKit widgets run their own event loops and consume events while the mouse is down.
+ // When they finish, currentEvent is the mouseUp that they exited on. We need to update
+ // the EventHandler state with this mouseUp, which we never saw.
+ // If this event isn't a mouseUp, we assume that the mouseUp will be coming later. There
+ // is a hole here if the widget consumes both the mouseUp and subsequent events.
+ if (lastEventIsMouseUp())
+ m_mousePressed = false;
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return true;
+}
+
+// Note that this does the same kind of check as [target isDescendantOf:superview].
+// There are two differences: This is a lot slower because it has to walk the whole
+// tree, and this works in cases where the target has already been deallocated.
+static bool findViewInSubviews(NSView *superview, NSView *target)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ NSEnumerator *e = [[superview subviews] objectEnumerator];
+ NSView *subview;
+ while ((subview = [e nextObject])) {
+ if (subview == target || findViewInSubviews(subview, target)) {
+ return true;
+ }
+ }
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return false;
+}
+
+NSView *EventHandler::mouseDownViewIfStillGood()
+{
+ // Since we have no way of tracking the lifetime of m_mouseDownView, we have to assume that
+ // it could be deallocated already. We search for it in our subview tree; if we don't find
+ // it, we set it to nil.
+ NSView *mouseDownView = m_mouseDownView;
+ if (!mouseDownView) {
+ return nil;
+ }
+ FrameView* topFrameView = m_frame->view();
+ NSView *topView = topFrameView ? topFrameView->platformWidget() : nil;
+ if (!topView || !findViewInSubviews(topView, mouseDownView)) {
+ m_mouseDownView = nil;
+ return nil;
+ }
+ return mouseDownView;
+}
+
+#if ENABLE(DRAG_SUPPORT)
+bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
+{
+ NSView *view = mouseDownViewIfStillGood();
+
+ if (!view)
+ return false;
+
+ if (!m_mouseDownWasInSubframe) {
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ [view mouseDragged:currentNSEvent()];
+ END_BLOCK_OBJC_EXCEPTIONS;
+ m_sendingEventToSubview = false;
+ }
+
+ return true;
+}
+#endif // ENABLE(DRAG_SUPPORT)
+
+bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
+{
+ NSView *view = mouseDownViewIfStillGood();
+ if (!view)
+ return false;
+
+ if (!m_mouseDownWasInSubframe) {
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ [view mouseUp:currentNSEvent()];
+ END_BLOCK_OBJC_EXCEPTIONS;
+ m_sendingEventToSubview = false;
+ }
+
+ return true;
+}
+
+bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult* hoveredNode)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ switch ([currentNSEvent() type]) {
+ case NSLeftMouseDragged:
+ case NSOtherMouseDragged:
+ case NSRightMouseDragged:
+ // This check is bogus and results in <rdar://6813830>, but removing it breaks a number of
+ // layout tests.
+ if (!m_mouseDownWasInSubframe)
+ return false;
+#if ENABLE(DRAG_SUPPORT)
+ if (subframe->page()->dragController()->didInitiateDrag())
+ return false;
+#endif
+ case NSMouseMoved:
+ // Since we're passing in currentNSEvent() here, we can call
+ // handleMouseMoveEvent() directly, since the save/restore of
+ // currentNSEvent() that mouseMoved() does would have no effect.
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ subframe->eventHandler()->handleMouseMoveEvent(currentPlatformMouseEvent(), hoveredNode);
+ m_sendingEventToSubview = false;
+ return true;
+
+ case NSLeftMouseDown: {
+ Node* node = event.targetNode();
+ if (!node)
+ return false;
+ RenderObject* renderer = node->renderer();
+ if (!renderer || !renderer->isWidget())
+ return false;
+ Widget* widget = toRenderWidget(renderer)->widget();
+ if (!widget || !widget->isFrameView())
+ return false;
+ if (!passWidgetMouseDownEventToWidget(toRenderWidget(renderer)))
+ return false;
+ m_mouseDownWasInSubframe = true;
+ return true;
+ }
+ case NSLeftMouseUp: {
+ if (!m_mouseDownWasInSubframe)
+ return false;
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ subframe->eventHandler()->handleMouseReleaseEvent(currentPlatformMouseEvent());
+ m_sendingEventToSubview = false;
+ return true;
+ }
+ default:
+ return false;
+ }
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return false;
+}
+
+static IMP originalNSScrollViewScrollWheel;
+static bool _nsScrollViewScrollWheelShouldRetainSelf;
+static void selfRetainingNSScrollViewScrollWheel(NSScrollView *, SEL, NSEvent *);
+
+static bool nsScrollViewScrollWheelShouldRetainSelf()
+{
+ ASSERT(isMainThread());
+
+ return _nsScrollViewScrollWheelShouldRetainSelf;
+}
+
+static void setNSScrollViewScrollWheelShouldRetainSelf(bool shouldRetain)
+{
+ ASSERT(isMainThread());
+
+ if (!originalNSScrollViewScrollWheel) {
+ Method method = class_getInstanceMethod(objc_getRequiredClass("NSScrollView"), @selector(scrollWheel:));
+ originalNSScrollViewScrollWheel = method_setImplementation(method, reinterpret_cast<IMP>(selfRetainingNSScrollViewScrollWheel));
+ }
+
+ _nsScrollViewScrollWheelShouldRetainSelf = shouldRetain;
+}
+
+static void selfRetainingNSScrollViewScrollWheel(NSScrollView *self, SEL selector, NSEvent *event)
+{
+ bool shouldRetainSelf = isMainThread() && nsScrollViewScrollWheelShouldRetainSelf();
+
+ if (shouldRetainSelf)
+ [self retain];
+ originalNSScrollViewScrollWheel(self, selector, event);
+ if (shouldRetainSelf)
+ [self release];
+}
+
+bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& wheelEvent, Widget* widget)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ if (!widget)
+ return false;
+
+ NSView* nodeView = widget->platformWidget();
+ if (!nodeView) {
+ // WebKit2 code path.
+ if (!widget->isFrameView())
+ return false;
+
+ return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent);
+ }
+
+ if ([currentNSEvent() type] != NSScrollWheel || m_sendingEventToSubview)
+ return false;
+
+ ASSERT(nodeView);
+ ASSERT([nodeView superview]);
+ NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
+ if (!view)
+ // We probably hit the border of a RenderWidget
+ return false;
+
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ // Work around <rdar://problem/6806810> which can cause -[NSScrollView scrollWheel:] to
+ // crash if the NSScrollView is released during timer or network callback dispatch
+ // in the nested tracking runloop that -[NSScrollView scrollWheel:] runs.
+ setNSScrollViewScrollWheelShouldRetainSelf(true);
+ [view scrollWheel:currentNSEvent()];
+ setNSScrollViewScrollWheelShouldRetainSelf(false);
+ m_sendingEventToSubview = false;
+ return true;
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+ return false;
+}
+
+void EventHandler::mouseDown(NSEvent *event)
+{
+ FrameView* v = m_frame->view();
+ if (!v || m_sendingEventToSubview)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ m_frame->loader()->resetMultipleFormSubmissionProtection();
+
+ m_mouseDownView = nil;
+
+ CurrentEventScope scope(event);
+
+ handleMousePressEvent(currentPlatformMouseEvent());
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+void EventHandler::mouseDragged(NSEvent *event)
+{
+ FrameView* v = m_frame->view();
+ if (!v || m_sendingEventToSubview)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ CurrentEventScope scope(event);
+ handleMouseMoveEvent(currentPlatformMouseEvent());
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+void EventHandler::mouseUp(NSEvent *event)
+{
+ FrameView* v = m_frame->view();
+ if (!v || m_sendingEventToSubview)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ CurrentEventScope scope(event);
+
+ // Our behavior here is a little different that Qt. Qt always sends
+ // a mouse release event, even for a double click. To correct problems
+ // in khtml's DOM click event handling we do not send a release here
+ // for a double click. Instead we send that event from FrameView's
+ // handleMouseDoubleClickEvent. Note also that the third click of
+ // a triple click is treated as a single click, but the fourth is then
+ // treated as another double click. Hence the "% 2" below.
+ int clickCount = [event clickCount];
+ if (clickCount > 0 && clickCount % 2 == 0)
+ handleMouseDoubleClickEvent(currentPlatformMouseEvent());
+ else
+ handleMouseReleaseEvent(currentPlatformMouseEvent());
+
+ m_mouseDownView = nil;
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+/*
+ A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
+ eats all subsequent events after it is starts its modal tracking loop. After the interaction
+ is done, this routine is used to fix things up. When a mouse down started us tracking in
+ the widget, we post a fake mouse up to balance the mouse down we started with. When a
+ key down started us tracking in the widget, we post a fake key up to balance things out.
+ In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to
+ be over after the tracking is done.
+ */
+void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
+{
+ FrameView* view = m_frame->view();
+ if (!view)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ m_sendingEventToSubview = false;
+ int eventType = [initiatingEvent type];
+ if (eventType == NSLeftMouseDown || eventType == NSKeyDown) {
+ NSEvent *fakeEvent = nil;
+ if (eventType == NSLeftMouseDown) {
+ fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
+ location:[initiatingEvent locationInWindow]
+ modifierFlags:[initiatingEvent modifierFlags]
+ timestamp:[initiatingEvent timestamp]
+ windowNumber:[initiatingEvent windowNumber]
+ context:[initiatingEvent context]
+ eventNumber:[initiatingEvent eventNumber]
+ clickCount:[initiatingEvent clickCount]
+ pressure:[initiatingEvent pressure]];
+
+ [NSApp postEvent:fakeEvent atStart:YES];
+ } else { // eventType == NSKeyDown
+ fakeEvent = [NSEvent keyEventWithType:NSKeyUp
+ location:[initiatingEvent locationInWindow]
+ modifierFlags:[initiatingEvent modifierFlags]
+ timestamp:[initiatingEvent timestamp]
+ windowNumber:[initiatingEvent windowNumber]
+ context:[initiatingEvent context]
+ characters:[initiatingEvent characters]
+ charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers]
+ isARepeat:[initiatingEvent isARepeat]
+ keyCode:[initiatingEvent keyCode]];
+ [NSApp postEvent:fakeEvent atStart:YES];
+ }
+ // FIXME: We should really get the current modifierFlags here, but there's no way to poll
+ // them in Cocoa, and because the event stream was stolen by the Carbon menu code we have
+ // no up-to-date cache of them anywhere.
+ fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
+ location:[[view->platformWidget() window] convertScreenToBase:[NSEvent mouseLocation]]
+ modifierFlags:[initiatingEvent modifierFlags]
+ timestamp:[initiatingEvent timestamp]
+ windowNumber:[initiatingEvent windowNumber]
+ context:[initiatingEvent context]
+ eventNumber:0
+ clickCount:0
+ pressure:0];
+ [NSApp postEvent:fakeEvent atStart:YES];
+ }
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+void EventHandler::mouseMoved(NSEvent *event)
+{
+ // Reject a mouse moved if the button is down - screws up tracking during autoscroll
+ // These happen because WebKit sometimes has to fake up moved events.
+ if (!m_frame->view() || m_mousePressed || m_sendingEventToSubview)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ CurrentEventScope scope(event);
+ mouseMoved(currentPlatformMouseEvent());
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+static bool frameHasPlatformWidget(Frame* frame)
+{
+ if (FrameView* frameView = frame->view()) {
+ if (frameView->platformWidget())
+ return true;
+ }
+
+ return false;
+}
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ // WebKit1 code path.
+ if (frameHasPlatformWidget(m_frame))
+ return passSubframeEventToSubframe(mev, subframe);
+
+ // WebKit2 code path.
+ subframe->eventHandler()->handleMousePressEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
+{
+ // WebKit1 code path.
+ if (frameHasPlatformWidget(m_frame))
+ return passSubframeEventToSubframe(mev, subframe, hoveredNode);
+
+ // WebKit2 code path.
+ if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
+ return false;
+ subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
+ return true;
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ // WebKit1 code path.
+ if (frameHasPlatformWidget(m_frame))
+ return passSubframeEventToSubframe(mev, subframe);
+
+ // WebKit2 code path.
+ subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
+ return true;
+}
+
+PlatformMouseEvent EventHandler::currentPlatformMouseEvent() const
+{
+ NSView *windowView = nil;
+ if (Page* page = m_frame->page())
+ windowView = page->chrome()->platformPageClient();
+ return PlatformMouseEvent(currentNSEvent(), windowView);
+}
+
+#if ENABLE(CONTEXT_MENUS)
+bool EventHandler::sendContextMenuEvent(NSEvent *event)
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return false;
+ return sendContextMenuEvent(PlatformMouseEvent(event, page->chrome()->platformPageClient()));
+}
+#endif // ENABLE(CONTEXT_MENUS)
+
+#if ENABLE(DRAG_SUPPORT)
+bool EventHandler::eventMayStartDrag(NSEvent *event)
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return false;
+ return eventMayStartDrag(PlatformMouseEvent(event, page->chrome()->platformPageClient()));
+}
+#endif // ENABLE(DRAG_SUPPORT)
+
+bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
+{
+ return m_activationEventNumber == event.eventNumber();
+}
+
+#if ENABLE(DRAG_SUPPORT)
+
+PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
+{
+ NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
+ // Must be done before ondragstart adds types and data to the pboard,
+ // also done for security, as it erases data from the last drag
+ [pasteboard declareTypes:[NSArray array] owner:nil];
+ return ClipboardMac::create(Clipboard::DragAndDrop, pasteboard, ClipboardWritable, m_frame);
+}
+
+#endif
+
+static inline bool isKeyboardOptionTab(KeyboardEvent* event)
+{
+ return event
+ && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
+ && event->altKey()
+ && event->keyIdentifier() == "U+0009";
+}
+
+bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const
+{
+ return isKeyboardOptionTab(event);
+}
+
+bool EventHandler::tabsToAllControls(KeyboardEvent* event) const
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return false;
+
+ KeyboardUIMode keyboardUIMode = page->chrome()->client()->keyboardUIMode();
+ bool handlingOptionTab = isKeyboardOptionTab(event);
+
+ // If tab-to-links is off, option-tab always highlights all controls
+ if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab)
+ return true;
+
+ // If system preferences say to include all controls, we always include all controls
+ if (keyboardUIMode & KeyboardAccessFull)
+ return true;
+
+ // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab.
+ if (keyboardUIMode & KeyboardAccessTabsToLinks)
+ return !handlingOptionTab;
+
+ return handlingOptionTab;
+}
+
+bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
+{
+ Document* document = m_frame->document();
+
+ // RSS view needs arrow key keypress events.
+ if (applicationIsSafari() && (document->url().protocolIs("feed") || document->url().protocolIs("feeds")))
+ return true;
+ Settings* settings = m_frame->settings();
+ if (!settings)
+ return false;
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ if (settings->usesDashboardBackwardCompatibilityMode())
+ return true;
+#endif
+
+ if (settings->needsKeyboardEventDisambiguationQuirks())
+ return true;
+
+ return false;
+}
+
+unsigned EventHandler::accessKeyModifiers()
+{
+ // Control+Option key combinations are usually unused on Mac OS X, but not when VoiceOver is enabled.
+ // So, we use Control in this case, even though it conflicts with Emacs-style key bindings.
+ // See <https://bugs.webkit.org/show_bug.cgi?id=21107> for more detail.
+ if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
+ return PlatformKeyboardEvent::CtrlKey;
+
+ return PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey;
+}
+
+}
diff --git a/Source/WebCore/page/mac/FrameMac.mm b/Source/WebCore/page/mac/FrameMac.mm
new file mode 100644
index 0000000..d4e4098
--- /dev/null
+++ b/Source/WebCore/page/mac/FrameMac.mm
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ * Copyright (C) 2008 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "Frame.h"
+
+#import "BlockExceptions.h"
+#import "ColorMac.h"
+#import "Cursor.h"
+#import "DOMInternal.h"
+#import "Event.h"
+#import "FrameLoaderClient.h"
+#import "FrameView.h"
+#import "GraphicsContext.h"
+#import "HTMLNames.h"
+#import "HTMLTableCellElement.h"
+#import "HitTestRequest.h"
+#import "HitTestResult.h"
+#import "KeyboardEvent.h"
+#import "Logging.h"
+#import "MouseEventWithHitTestResults.h"
+#import "Page.h"
+#import "PlatformKeyboardEvent.h"
+#import "PlatformWheelEvent.h"
+#import "RegularExpression.h"
+#import "RenderTableCell.h"
+#import "Scrollbar.h"
+#import "SimpleFontData.h"
+#import "WebCoreViewFactory.h"
+#import "visible_units.h"
+#import <Carbon/Carbon.h>
+#import <wtf/StdLibExtras.h>
+
+@interface NSView (WebCoreHTMLDocumentView)
+- (void)drawSingleRect:(NSRect)rect;
+@end
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// Either get cached regexp or build one that matches any of the labels.
+// The regexp we build is of the form: (STR1|STR2|STRN)
+static RegularExpression* regExpForLabels(NSArray* labels)
+{
+ // All the ObjC calls in this method are simple array and string
+ // calls which we can assume do not raise exceptions
+
+
+ // Parallel arrays that we use to cache regExps. In practice the number of expressions
+ // that the app will use is equal to the number of locales is used in searching.
+ static const unsigned int regExpCacheSize = 4;
+ static NSMutableArray* regExpLabels = nil;
+ DEFINE_STATIC_LOCAL(Vector<RegularExpression*>, regExps, ());
+ DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));
+
+ RegularExpression* result;
+ if (!regExpLabels)
+ regExpLabels = [[NSMutableArray alloc] initWithCapacity:regExpCacheSize];
+ CFIndex cacheHit = [regExpLabels indexOfObject:labels];
+ if (cacheHit != NSNotFound)
+ result = regExps.at(cacheHit);
+ else {
+ String pattern("(");
+ unsigned int numLabels = [labels count];
+ unsigned int i;
+ for (i = 0; i < numLabels; i++) {
+ String label = [labels objectAtIndex:i];
+
+ bool startsWithWordChar = false;
+ bool endsWithWordChar = false;
+ if (label.length() != 0) {
+ startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;
+ endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;
+ }
+
+ if (i != 0)
+ pattern.append("|");
+ // Search for word boundaries only if label starts/ends with "word characters".
+ // If we always searched for word boundaries, this wouldn't work for languages
+ // such as Japanese.
+ if (startsWithWordChar)
+ pattern.append("\\b");
+ pattern.append(label);
+ if (endsWithWordChar)
+ pattern.append("\\b");
+ }
+ pattern.append(")");
+ result = new RegularExpression(pattern, TextCaseInsensitive);
+ }
+
+ // add regexp to the cache, making sure it is at the front for LRU ordering
+ if (cacheHit != 0) {
+ if (cacheHit != NSNotFound) {
+ // remove from old spot
+ [regExpLabels removeObjectAtIndex:cacheHit];
+ regExps.remove(cacheHit);
+ }
+ // add to start
+ [regExpLabels insertObject:labels atIndex:0];
+ regExps.insert(0, result);
+ // trim if too big
+ if ([regExpLabels count] > regExpCacheSize) {
+ [regExpLabels removeObjectAtIndex:regExpCacheSize];
+ RegularExpression* last = regExps.last();
+ regExps.removeLast();
+ delete last;
+ }
+ }
+ return result;
+}
+
+NSString* Frame::searchForLabelsBeforeElement(NSArray* labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
+{
+ RegularExpression* regExp = regExpForLabels(labels);
+ // We stop searching after we've seen this many chars
+ const unsigned int charsSearchedThreshold = 500;
+ // This is the absolute max we search. We allow a little more slop than
+ // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
+ const unsigned int maxCharsSearched = 600;
+ // If the starting element is within a table, the cell that contains it
+ HTMLTableCellElement* startingTableCell = 0;
+ bool searchedCellAbove = false;
+
+ if (resultDistance)
+ *resultDistance = notFound;
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = false;
+
+ // walk backwards in the node tree, until another element, or form, or end of tree
+ unsigned lengthSearched = 0;
+ Node* n;
+ for (n = element->traversePreviousNode();
+ n && lengthSearched < charsSearchedThreshold;
+ n = n->traversePreviousNode())
+ {
+ if (n->hasTagName(formTag)
+ || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))
+ {
+ // We hit another form element or the start of the form - bail out
+ break;
+ } else if (n->hasTagName(tdTag) && !startingTableCell) {
+ startingTableCell = static_cast<HTMLTableCellElement*>(n);
+ } else if (n->hasTagName(trTag) && startingTableCell) {
+ NSString* result = searchForLabelsAboveCell(regExp, startingTableCell, resultDistance);
+ if (result && [result length] > 0) {
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = true;
+ return result;
+ }
+ searchedCellAbove = true;
+ } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
+ // For each text chunk, run the regexp
+ String nodeString = n->nodeValue();
+ // add 100 for slop, to make it more likely that we'll search whole nodes
+ if (lengthSearched + nodeString.length() > maxCharsSearched)
+ nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
+ int pos = regExp->searchRev(nodeString);
+ if (pos >= 0) {
+ if (resultDistance)
+ *resultDistance = lengthSearched;
+ return nodeString.substring(pos, regExp->matchedLength());
+ }
+ lengthSearched += nodeString.length();
+ }
+ }
+
+ // If we started in a cell, but bailed because we found the start of the form or the
+ // previous element, we still might need to search the row above us for a label.
+ if (startingTableCell && !searchedCellAbove) {
+ NSString* result = searchForLabelsAboveCell(regExp, startingTableCell, resultDistance);
+ if (result && [result length] > 0) {
+ if (resultIsInCellAbove)
+ *resultIsInCellAbove = true;
+ return result;
+ }
+ }
+
+ return nil;
+}
+
+static NSString *matchLabelsAgainstString(NSArray *labels, const String& stringToMatch)
+{
+ if (stringToMatch.isEmpty())
+ return nil;
+
+ String mutableStringToMatch = stringToMatch;
+
+ // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
+ replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
+ mutableStringToMatch.replace('_', ' ');
+
+ RegularExpression* regExp = regExpForLabels(labels);
+ // Use the largest match we can find in the whole string
+ int pos;
+ int length;
+ int bestPos = -1;
+ int bestLength = -1;
+ int start = 0;
+ do {
+ pos = regExp->match(mutableStringToMatch, start);
+ if (pos != -1) {
+ length = regExp->matchedLength();
+ if (length >= bestLength) {
+ bestPos = pos;
+ bestLength = length;
+ }
+ start = pos + 1;
+ }
+ } while (pos != -1);
+
+ if (bestPos != -1)
+ return mutableStringToMatch.substring(bestPos, bestLength);
+ return nil;
+}
+
+NSString* Frame::matchLabelsAgainstElement(NSArray* labels, Element* element)
+{
+ // Match against the name element, then against the id element if no match is found for the name element.
+ // See 7538330 for one popular site that benefits from the id element check.
+ // FIXME: This code is mirrored in Frame.cpp. It would be nice to make the Mac code call the platform-agnostic
+ // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
+ String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getAttribute(nameAttr));
+ if (!resultFromNameAttribute.isEmpty())
+ return resultFromNameAttribute;
+
+ return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
+}
+
+NSImage* Frame::imageFromRect(NSRect rect) const
+{
+ NSView* view = m_view->documentView();
+ if (!view)
+ return nil;
+ if (![view respondsToSelector:@selector(drawSingleRect:)])
+ return nil;
+
+ PaintBehavior oldPaintBehavior = m_view->paintBehavior();
+ m_view->setPaintBehavior(oldPaintBehavior | PaintBehaviorFlattenCompositingLayers);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ NSRect bounds = [view bounds];
+
+ // Round image rect size in window coordinate space to avoid pixel cracks at HiDPI (4622794)
+ rect = [view convertRect:rect toView:nil];
+ rect.size.height = roundf(rect.size.height);
+ rect.size.width = roundf(rect.size.width);
+ rect = [view convertRect:rect fromView:nil];
+
+ NSImage* resultImage = [[[NSImage alloc] initWithSize:rect.size] autorelease];
+
+ if (rect.size.width != 0 && rect.size.height != 0) {
+ [resultImage setFlipped:YES];
+ [resultImage lockFocus];
+ CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+ CGContextSaveGState(context);
+ CGContextTranslateCTM(context, bounds.origin.x - rect.origin.x, bounds.origin.y - rect.origin.y);
+
+ // Note: Must not call drawRect: here, because drawRect: assumes that it's called from AppKit's
+ // display machinery. It calls getRectsBeingDrawn:count:, which can only be called inside
+ // when a real AppKit display is underway.
+ [view drawSingleRect:rect];
+
+ CGContextRestoreGState(context);
+ [resultImage unlockFocus];
+ [resultImage setFlipped:NO];
+ }
+
+ m_view->setPaintBehavior(oldPaintBehavior);
+ return resultImage;
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ m_view->setPaintBehavior(oldPaintBehavior);
+ return nil;
+}
+
+NSImage* Frame::selectionImage(bool forceBlackText) const
+{
+ m_view->setPaintBehavior(PaintBehaviorSelectionOnly | (forceBlackText ? PaintBehaviorForceBlackText : 0));
+ m_doc->updateLayout();
+ NSImage* result = imageFromRect(selection()->bounds());
+ m_view->setPaintBehavior(PaintBehaviorNormal);
+ return result;
+}
+
+NSImage* Frame::snapshotDragImage(Node* node, NSRect* imageRect, NSRect* elementRect) const
+{
+ RenderObject* renderer = node->renderer();
+ if (!renderer)
+ return nil;
+
+ renderer->updateDragState(true); // mark dragged nodes (so they pick up the right CSS)
+ m_doc->updateLayout(); // forces style recalc - needed since changing the drag state might
+ // imply new styles, plus JS could have changed other things
+ IntRect topLevelRect;
+ NSRect paintingRect = renderer->paintingRootRect(topLevelRect);
+
+ m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode
+ NSImage* result = imageFromRect(paintingRect);
+ renderer->updateDragState(false);
+ m_doc->updateLayout();
+ m_view->setNodeToDraw(0);
+
+ if (elementRect)
+ *elementRect = topLevelRect;
+ if (imageRect)
+ *imageRect = paintingRect;
+ return result;
+}
+
+DragImageRef Frame::nodeImage(Node* node)
+{
+ RenderObject* renderer = node->renderer();
+ if (!renderer)
+ return nil;
+
+ m_doc->updateLayout(); // forces style recalc
+
+ IntRect topLevelRect;
+ NSRect paintingRect = renderer->paintingRootRect(topLevelRect);
+
+ m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode
+ NSImage* result = imageFromRect(paintingRect);
+ m_view->setNodeToDraw(0);
+
+ return result;
+}
+
+DragImageRef Frame::dragImageForSelection()
+{
+ if (!selection()->isRange())
+ return nil;
+ return selectionImage();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/mac/PageMac.cpp b/Source/WebCore/page/mac/PageMac.cpp
new file mode 100644
index 0000000..7386eea
--- /dev/null
+++ b/Source/WebCore/page/mac/PageMac.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "DocumentLoader.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "Page.h"
+
+namespace WebCore {
+
+void Page::addSchedulePair(PassRefPtr<SchedulePair> prpPair)
+{
+ RefPtr<SchedulePair> pair = prpPair;
+
+ if (!m_scheduledRunLoopPairs)
+ m_scheduledRunLoopPairs.set(new SchedulePairHashSet);
+ m_scheduledRunLoopPairs->add(pair);
+
+#ifndef BUILDING_ON_TIGER
+ for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
+ if (DocumentLoader* documentLoader = frame->loader()->documentLoader())
+ documentLoader->schedule(pair.get());
+ if (DocumentLoader* documentLoader = frame->loader()->provisionalDocumentLoader())
+ documentLoader->schedule(pair.get());
+ }
+#endif
+
+ // FIXME: make SharedTimerMac use these SchedulePairs.
+}
+
+void Page::removeSchedulePair(PassRefPtr<SchedulePair> prpPair)
+{
+ ASSERT(m_scheduledRunLoopPairs);
+ if (!m_scheduledRunLoopPairs)
+ return;
+
+ RefPtr<SchedulePair> pair = prpPair;
+ m_scheduledRunLoopPairs->remove(pair);
+
+#ifndef BUILDING_ON_TIGER
+ for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
+ if (DocumentLoader* documentLoader = frame->loader()->documentLoader())
+ documentLoader->unschedule(pair.get());
+ if (DocumentLoader* documentLoader = frame->loader()->provisionalDocumentLoader())
+ documentLoader->unschedule(pair.get());
+ }
+#endif
+}
+
+} // namespace
diff --git a/Source/WebCore/page/mac/WebCoreFrameView.h b/Source/WebCore/page/mac/WebCoreFrameView.h
new file mode 100644
index 0000000..b76350d
--- /dev/null
+++ b/Source/WebCore/page/mac/WebCoreFrameView.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ScrollTypes.h"
+
+namespace WebCore {
+ class Frame;
+}
+
+@protocol WebCoreFrameScrollView
+- (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
+- (WebCore::Frame*)_web_frame;
+@end
diff --git a/Source/WebCore/page/mac/WebCoreKeyboardUIMode.h b/Source/WebCore/page/mac/WebCoreKeyboardUIMode.h
new file mode 100644
index 0000000..187cf09
--- /dev/null
+++ b/Source/WebCore/page/mac/WebCoreKeyboardUIMode.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebCoreKeyboardUIMode_h
+#define WebCoreKeyboardUIMode_h
+
+namespace WebCore {
+
+ enum KeyboardUIMode {
+ KeyboardAccessDefault = 0x00000000,
+ KeyboardAccessFull = 0x00000001,
+ // this flag may be or'ed with either of the two above
+ KeyboardAccessTabsToLinks = 0x10000000
+ };
+
+}
+
+#endif
diff --git a/Source/WebCore/page/mac/WebCoreViewFactory.h b/Source/WebCore/page/mac/WebCoreViewFactory.h
new file mode 100644
index 0000000..7af75cb
--- /dev/null
+++ b/Source/WebCore/page/mac/WebCoreViewFactory.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2003, 2005, 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+@class WebCoreTextMarker;
+@class WebCoreTextMarkerRange;
+
+@protocol WebCoreViewFactory
+
+- (BOOL)objectIsTextMarker:(id)object;
+- (BOOL)objectIsTextMarkerRange:(id)object;
+
+- (WebCoreTextMarker *)textMarkerWithBytes:(const void *)bytes length:(size_t)length;
+- (BOOL)getBytes:(void *)bytes fromTextMarker:(WebCoreTextMarker *)textMarker length:(size_t)length;
+
+- (WebCoreTextMarkerRange *)textMarkerRangeWithStart:(WebCoreTextMarker *)start end:(WebCoreTextMarker *)end;
+- (WebCoreTextMarker *)startOfTextMarkerRange:(WebCoreTextMarkerRange *)range;
+- (WebCoreTextMarker *)endOfTextMarkerRange:(WebCoreTextMarkerRange *)range;
+
+- (void)accessibilityHandleFocusChanged;
+- (CGRect)accessibilityConvertScreenRect:(CGRect)bounds;
+
+- (AXUIElementRef)AXUIElementForElement:(id)element;
+- (void)unregisterUniqueIdForUIElement:(id)element;
+
+@end
+
+@interface WebCoreViewFactory : NSObject
++ (WebCoreViewFactory *)sharedFactory;
+@end
+
+@interface WebCoreViewFactory (SubclassResponsibility) <WebCoreViewFactory>
+@end
diff --git a/Source/WebCore/page/mac/WebCoreViewFactory.m b/Source/WebCore/page/mac/WebCoreViewFactory.m
new file mode 100644
index 0000000..5398989
--- /dev/null
+++ b/Source/WebCore/page/mac/WebCoreViewFactory.m
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#import "WebCoreViewFactory.h"
+#import <wtf/Assertions.h>
+
+@implementation WebCoreViewFactory
+
+static WebCoreViewFactory *sharedFactory;
+
++ (WebCoreViewFactory *)sharedFactory
+{
+ return sharedFactory;
+}
+
+- init
+{
+ [super init];
+
+ ASSERT(!sharedFactory);
+ sharedFactory = [self retain];
+
+ return self;
+}
+
+@end
diff --git a/Source/WebCore/page/qt/DragControllerQt.cpp b/Source/WebCore/page/qt/DragControllerQt.cpp
new file mode 100644
index 0000000..33815b5
--- /dev/null
+++ b/Source/WebCore/page/qt/DragControllerQt.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DragController.h"
+
+#include "DragData.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "Page.h"
+
+namespace WebCore {
+
+// FIXME: These values are straight out of DragControllerMac, so probably have
+// little correlation with Qt standards...
+const int DragController::LinkDragBorderInset = 2;
+const int DragController::MaxOriginalImageArea = 1500 * 1500;
+const int DragController::DragIconRightInset = 7;
+const int DragController::DragIconBottomInset = 3;
+
+const float DragController::DragImageAlpha = 0.75f;
+
+
+bool DragController::isCopyKeyDown()
+{
+ return false;
+}
+
+DragOperation DragController::dragOperation(DragData* dragData)
+{
+ //FIXME: This logic is incomplete
+ if (dragData->containsURL())
+ return DragOperationCopy;
+
+ return DragOperationNone;
+}
+
+const IntSize& DragController::maxDragImageSize()
+{
+ static const IntSize maxDragImageSize(400, 400);
+
+ return maxDragImageSize;
+}
+
+void DragController::cleanupAfterSystemDrag()
+{
+ dragEnded();
+}
+
+}
diff --git a/Source/WebCore/page/qt/EventHandlerQt.cpp b/Source/WebCore/page/qt/EventHandlerQt.cpp
new file mode 100644
index 0000000..2c658e7
--- /dev/null
+++ b/Source/WebCore/page/qt/EventHandlerQt.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "EventHandler.h"
+
+#include "ClipboardQt.h"
+#include "Cursor.h"
+#include "Document.h"
+#include "EventNames.h"
+#include "FloatPoint.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "HTMLFrameSetElement.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "KeyboardEvent.h"
+#include "MouseEventWithHitTestResults.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "RenderWidget.h"
+#include "Scrollbar.h"
+
+QT_BEGIN_NAMESPACE
+Q_GUI_EXPORT extern bool qt_tab_all_widgets; // from qapplication.cpp
+QT_END_NAMESPACE
+
+namespace WebCore {
+
+#if defined(Q_WS_MAC)
+const double EventHandler::TextDragDelay = 0.15;
+#else
+const double EventHandler::TextDragDelay = 0.0;
+#endif
+
+static bool isKeyboardOptionTab(KeyboardEvent* event)
+{
+ return event
+ && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
+ && event->altKey()
+ && event->keyIdentifier() == "U+0009";
+}
+
+bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const
+{
+ return isKeyboardOptionTab(event);
+}
+
+bool EventHandler::tabsToAllControls(KeyboardEvent* event) const
+{
+ return (isKeyboardOptionTab(event) ? !qt_tab_all_widgets : qt_tab_all_widgets);
+}
+
+void EventHandler::focusDocumentView()
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+ page->focusController()->setFocusedFrame(m_frame);
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults&)
+{
+ notImplemented();
+ return false;
+}
+
+bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const
+{
+ // Qt has an activation event which is sent independently
+ // of mouse event so this thing will be a snafu to implement
+ // correctly
+ return false;
+}
+
+bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& event, Widget* widget)
+{
+ Q_ASSERT(widget);
+ if (!widget->isFrameView())
+ return false;
+
+ return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(event);
+}
+
+PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
+{
+ return ClipboardQt::create(ClipboardWritable, Clipboard::DragAndDrop);
+}
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMousePressEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
+{
+ subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
+ return true;
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
+ return true;
+}
+
+unsigned EventHandler::accessKeyModifiers()
+{
+#if OS(DARWIN)
+ return PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey;
+#else
+ return PlatformKeyboardEvent::AltKey;
+#endif
+}
+
+}
diff --git a/Source/WebCore/page/qt/FrameQt.cpp b/Source/WebCore/page/qt/FrameQt.cpp
new file mode 100644
index 0000000..467592c
--- /dev/null
+++ b/Source/WebCore/page/qt/FrameQt.cpp
@@ -0,0 +1,66 @@
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "Image.h"
+#include "ImageBuffer.h"
+
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+DragImageRef Frame::nodeImage(Node*)
+{
+ notImplemented();
+ return 0;
+}
+
+DragImageRef Frame::dragImageForSelection()
+{
+ 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());
+}
+
+}
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/page/win/DragControllerWin.cpp b/Source/WebCore/page/win/DragControllerWin.cpp
new file mode 100644
index 0000000..f0404ff
--- /dev/null
+++ b/Source/WebCore/page/win/DragControllerWin.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DragController.h"
+
+#include "DragData.h"
+#include "windows.h"
+#include "SelectionController.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+const int DragController::LinkDragBorderInset = 2;
+const int DragController::MaxOriginalImageArea = 1500 * 1500;
+const int DragController::DragIconRightInset = 7;
+const int DragController::DragIconBottomInset = 3;
+
+const float DragController::DragImageAlpha = 0.75f;
+
+DragOperation DragController::dragOperation(DragData* dragData)
+{
+ //FIXME: to match the macos behaviour we should return DragOperationNone
+ //if we are a modal window, we are the drag source, or the window is an attached sheet
+ //If this can be determined from within WebCore operationForDrag can be pulled into
+ //WebCore itself
+ ASSERT(dragData);
+ return dragData->containsURL() && !m_didInitiateDrag ? DragOperationCopy : DragOperationNone;
+}
+
+bool DragController::isCopyKeyDown()
+{
+ return ::GetAsyncKeyState(VK_CONTROL);
+}
+
+const IntSize& DragController::maxDragImageSize()
+{
+ static const IntSize maxDragImageSize(200, 200);
+
+ return maxDragImageSize;
+}
+
+void DragController::cleanupAfterSystemDrag()
+{
+}
+
+}
diff --git a/Source/WebCore/page/win/EventHandlerWin.cpp b/Source/WebCore/page/win/EventHandlerWin.cpp
new file mode 100644
index 0000000..039d70b
--- /dev/null
+++ b/Source/WebCore/page/win/EventHandlerWin.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "EventHandler.h"
+
+#include "Cursor.h"
+#include "FloatPoint.h"
+#include "FocusController.h"
+#include "FrameView.h"
+#include "Frame.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "MouseEventWithHitTestResults.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "Scrollbar.h"
+#include "SelectionController.h"
+#include "WCDataObject.h"
+#include "NotImplemented.h"
+
+#if OS(WINCE)
+#include "Clipboard.h"
+#else
+#include "ClipboardWin.h"
+#endif
+
+namespace WebCore {
+
+const double EventHandler::TextDragDelay = 0.0;
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMousePressEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
+{
+ if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
+ return false;
+ subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
+ return true;
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& wheelEvent, Widget* widget)
+{
+ if (!widget->isFrameView())
+ return false;
+
+ return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent);
+}
+
+bool EventHandler::tabsToAllControls(KeyboardEvent*) const
+{
+ return true;
+}
+
+bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
+{
+ return event.didActivateWebView();
+}
+
+PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
+{
+#if OS(WINCE)
+ return 0;
+#else
+ COMPtr<WCDataObject> dataObject;
+ WCDataObject::createInstance(&dataObject);
+ return ClipboardWin::create(Clipboard::DragAndDrop, dataObject.get(), ClipboardWritable, m_frame);
+#endif
+}
+
+void EventHandler::focusDocumentView()
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+ page->focusController()->setFocusedFrame(m_frame);
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults&)
+{
+ notImplemented();
+ return false;
+}
+
+unsigned EventHandler::accessKeyModifiers()
+{
+ return PlatformKeyboardEvent::AltKey;
+}
+
+}
diff --git a/Source/WebCore/page/win/FrameCGWin.cpp b/Source/WebCore/page/win/FrameCGWin.cpp
new file mode 100644
index 0000000..c9351a2
--- /dev/null
+++ b/Source/WebCore/page/win/FrameCGWin.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FrameWin.h"
+
+#include <windows.h>
+
+#include "BitmapInfo.h"
+#include "FrameView.h"
+#include "GraphicsContextCG.h"
+#include "Settings.h"
+
+#include <CoreGraphics/CoreGraphics.h>
+
+using std::min;
+
+namespace WebCore {
+
+static void drawRectIntoContext(IntRect rect, FrameView* view, GraphicsContext* gc)
+{
+ IntSize offset = view->scrollOffset();
+ rect.move(-offset.width(), -offset.height());
+ rect = view->convertToContainingWindow(rect);
+
+ gc->concatCTM(AffineTransform().translate(-rect.x(), -rect.y()));
+
+ view->paint(gc, rect);
+}
+
+static HBITMAP imageFromRect(const Frame* frame, IntRect& ir)
+{
+ PaintBehavior oldPaintBehavior = frame->view()->paintBehavior();
+ frame->view()->setPaintBehavior(oldPaintBehavior | PaintBehaviorFlattenCompositingLayers);
+
+ void* bits;
+ HDC hdc = CreateCompatibleDC(0);
+ int w = ir.width();
+ int h = ir.height();
+ BitmapInfo bmp = BitmapInfo::create(IntSize(w, h));
+
+ HBITMAP hbmp = CreateDIBSection(0, &bmp, DIB_RGB_COLORS, static_cast<void**>(&bits), 0, 0);
+ HBITMAP hbmpOld = static_cast<HBITMAP>(SelectObject(hdc, hbmp));
+ CGContextRef context = CGBitmapContextCreate(static_cast<void*>(bits), w, h,
+ 8, w * sizeof(RGBQUAD), deviceRGBColorSpaceRef(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
+ CGContextSaveGState(context);
+
+ GraphicsContext gc(context);
+
+ drawRectIntoContext(ir, frame->view(), &gc);
+
+ CGContextRelease(context);
+ SelectObject(hdc, hbmpOld);
+ DeleteDC(hdc);
+
+ frame->view()->setPaintBehavior(oldPaintBehavior);
+
+ return hbmp;
+}
+
+HBITMAP imageFromSelection(Frame* frame, bool forceBlackText)
+{
+ frame->document()->updateLayout();
+
+ frame->view()->setPaintBehavior(PaintBehaviorSelectionOnly | (forceBlackText ? PaintBehaviorForceBlackText : 0));
+ FloatRect fr = frame->selection()->bounds();
+ IntRect ir(static_cast<int>(fr.x()), static_cast<int>(fr.y()),
+ static_cast<int>(fr.width()), static_cast<int>(fr.height()));
+ HBITMAP image = imageFromRect(frame, ir);
+ frame->view()->setPaintBehavior(PaintBehaviorNormal);
+ return image;
+}
+
+DragImageRef Frame::nodeImage(Node* node)
+{
+ RenderObject* renderer = node->renderer();
+ if (!renderer)
+ return 0;
+
+ IntRect topLevelRect;
+ IntRect paintingRect = renderer->paintingRootRect(topLevelRect);
+
+ document()->updateLayout();
+
+ m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode
+ HBITMAP result = imageFromRect(this, paintingRect);
+ m_view->setNodeToDraw(0);
+
+ return result;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/win/FrameCairoWin.cpp b/Source/WebCore/page/win/FrameCairoWin.cpp
new file mode 100644
index 0000000..f843ba1
--- /dev/null
+++ b/Source/WebCore/page/win/FrameCairoWin.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Frame.h"
+#include "FrameWin.h"
+
+#include "EditorClient.h"
+#include "NotImplemented.h"
+
+using std::min;
+
+namespace WebCore {
+
+HBITMAP imageFromSelection(Frame* frame, bool forceBlackText)
+{
+ notImplemented();
+ return 0;
+}
+
+DragImageRef Frame::nodeImage(Node*)
+{
+ notImplemented();
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/win/FrameWin.cpp b/Source/WebCore/page/win/FrameWin.cpp
new file mode 100644
index 0000000..2b5435d
--- /dev/null
+++ b/Source/WebCore/page/win/FrameWin.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FrameWin.h"
+
+#include "Bridge.h"
+#include "Document.h"
+#include "FloatRect.h"
+#include "PrintContext.h"
+#include "RenderView.h"
+#include "Settings.h"
+#include "TransformationMatrix.h"
+
+namespace WebCore {
+
+void computePageRectsForFrame(Frame* frame, const IntRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, Vector<IntRect>& outPages, int& outPageHeight)
+{
+ PrintContext printContext(frame);
+ float pageHeight = 0;
+ printContext.computePageRects(printRect, headerHeight, footerHeight, userScaleFactor, pageHeight);
+ outPageHeight = static_cast<int>(pageHeight);
+ outPages = printContext.pageRects();
+}
+
+DragImageRef Frame::dragImageForSelection()
+{
+ if (selection()->isRange())
+ return imageFromSelection(this, false);
+
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/win/FrameWin.h b/Source/WebCore/page/win/FrameWin.h
new file mode 100644
index 0000000..cbfe33d
--- /dev/null
+++ b/Source/WebCore/page/win/FrameWin.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FrameWin_h
+#define FrameWin_h
+
+#include <wtf/Vector.h>
+
+// Forward declared so we don't need wingdi.h.
+typedef struct HBITMAP__* HBITMAP;
+
+namespace WebCore {
+
+ class Frame;
+ class IntRect;
+
+ HBITMAP imageFromSelection(Frame* frame, bool forceWhiteText);
+ void computePageRectsForFrame(Frame*, const IntRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, Vector<IntRect>& outPages, int& outPageHeight);
+
+}
+
+#endif
diff --git a/Source/WebCore/page/wince/FrameWinCE.cpp b/Source/WebCore/page/wince/FrameWinCE.cpp
new file mode 100644
index 0000000..9eb487b
--- /dev/null
+++ b/Source/WebCore/page/wince/FrameWinCE.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Frame.h"
+
+#include "Document.h"
+#include "FloatRect.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLIFrameElement.h"
+#include "HTMLNames.h"
+#include "HTMLTableCellElement.h"
+#include "KeyboardEvent.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "RenderFrame.h"
+#include "RenderLayer.h"
+#include "RenderView.h"
+#include "ResourceHandle.h"
+
+#include <windows.h>
+
+using std::min;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+extern HDC g_screenDC;
+
+void computePageRectsForFrame(Frame* frame, const IntRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, Vector<IntRect>& pages, int& outPageHeight)
+{
+ ASSERT(frame);
+
+ pages.clear();
+ outPageHeight = 0;
+
+ if (!frame->document() || !frame->view() || !frame->document()->renderer())
+ return;
+
+ RenderView* root = toRenderView(frame->document()->renderer());
+
+ if (!root) {
+ LOG_ERROR("document to be printed has no renderer");
+ return;
+ }
+
+ if (userScaleFactor <= 0) {
+ LOG_ERROR("userScaleFactor has bad value %.2f", userScaleFactor);
+ return;
+ }
+
+ float ratio = (float)printRect.height() / (float)printRect.width();
+
+ float pageWidth = (float) root->rightLayoutOverflow();
+ float pageHeight = pageWidth * ratio;
+ outPageHeight = (int) pageHeight; // this is the height of the page adjusted by margins
+ pageHeight -= (headerHeight + footerHeight);
+
+ if (pageHeight <= 0) {
+ LOG_ERROR("pageHeight has bad value %.2f", pageHeight);
+ return;
+ }
+
+ float currPageHeight = pageHeight / userScaleFactor;
+ float docHeight = root->layer()->height();
+ float docWidth = root->layer()->width();
+ float currPageWidth = pageWidth / userScaleFactor;
+
+
+ // always return at least one page, since empty files should print a blank page
+ float printedPagesHeight = 0.0;
+ do {
+ float proposedBottom = min(docHeight, printedPagesHeight + pageHeight);
+ frame->view()->adjustPageHeightDeprecated(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight);
+ currPageHeight = max(1.0f, proposedBottom - printedPagesHeight);
+
+ pages.append(IntRect(0, printedPagesHeight, currPageWidth, currPageHeight));
+ printedPagesHeight += currPageHeight;
+ } while (printedPagesHeight < docHeight);
+}
+
+HBITMAP imageFromSelection(Frame* frame, bool forceBlackText)
+{
+ if (!frame->view())
+ return 0;
+
+ frame->view()->setPaintBehavior(PaintBehaviorSelectionOnly | (forceBlackText ? PaintBehaviorForceBlackText : 0));
+ FloatRect fr = frame->selection()->bounds();
+ IntRect ir((int)fr.x(), (int)fr.y(), (int)fr.width(), (int)fr.height());
+ if (ir.isEmpty())
+ return 0;
+
+ int w;
+ int h;
+ FrameView* view = frame->view();
+ if (view->parent()) {
+ ir.setLocation(view->parent()->convertChildToSelf(view, ir.location()));
+ w = ir.width() * frame->pageZoomFactor() + 0.5;
+ h = ir.height() * frame->pageZoomFactor() + 0.5;
+ } else {
+ ir = view->contentsToWindow(ir);
+ w = ir.width();
+ h = ir.height();
+ }
+
+ OwnPtr<HDC> bmpDC(CreateCompatibleDC(g_screenDC));
+ HBITMAP hBmp = CreateCompatibleBitmap(g_screenDC, w, h);
+ if (!hBmp)
+ return 0;
+
+ HGDIOBJ hbmpOld = SelectObject(bmpDC.get(), hBmp);
+
+ {
+ GraphicsContext gc(bmpDC.get());
+ frame->document()->updateLayout();
+ view->paint(&gc, ir);
+ }
+
+ SelectObject(bmpDC.get(), hbmpOld);
+
+ frame->view()->setPaintBehavior(PaintBehaviorNormal);
+
+ return hBmp;
+}
+
+DragImageRef Frame::nodeImage(Node*)
+{
+ notImplemented();
+ return 0;
+}
+
+DragImageRef Frame::dragImageForSelection()
+{
+ if (selection()->isRange())
+ return imageFromSelection(this, false);
+
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/wx/DragControllerWx.cpp b/Source/WebCore/page/wx/DragControllerWx.cpp
new file mode 100644
index 0000000..c288a01
--- /dev/null
+++ b/Source/WebCore/page/wx/DragControllerWx.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DragController.h"
+
+#include "DragData.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "NotImplemented.h"
+#include "Page.h"
+
+namespace WebCore {
+
+// FIXME: These values are straight out of DragControllerMac, so probably have
+// little correlation with wx standards...
+const int DragController::LinkDragBorderInset = 2;
+const int DragController::MaxOriginalImageArea = 1500 * 1500;
+const int DragController::DragIconRightInset = 7;
+const int DragController::DragIconBottomInset = 3;
+
+const float DragController::DragImageAlpha = 0.75f;
+
+bool DragController::isCopyKeyDown()
+{
+ notImplemented();
+ return false;
+}
+
+DragOperation DragController::dragOperation(DragData* dragData)
+{
+ //FIXME: This logic is incomplete
+ if (dragData->containsURL())
+ return DragOperationCopy;
+
+ return DragOperationNone;
+}
+
+const IntSize& DragController::maxDragImageSize()
+{
+ static const IntSize maxDragImageSize(400, 400);
+
+ return maxDragImageSize;
+}
+
+void DragController::cleanupAfterSystemDrag()
+{
+}
+
+}
diff --git a/Source/WebCore/page/wx/EventHandlerWx.cpp b/Source/WebCore/page/wx/EventHandlerWx.cpp
new file mode 100644
index 0000000..fbb1eaa
--- /dev/null
+++ b/Source/WebCore/page/wx/EventHandlerWx.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "EventHandler.h"
+
+#include "ClipboardWx.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "KeyboardEvent.h"
+#include "MouseEventWithHitTestResults.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "RenderWidget.h"
+#include "Scrollbar.h"
+
+namespace WebCore {
+
+const double EventHandler::TextDragDelay = 0.0;
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMousePressEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, WebCore::HitTestResult* hittest)
+{
+ subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hittest);
+ return true;
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
+{
+ // Figure out which view to send the event to.
+ if (!event.targetNode() || !event.targetNode()->renderer() || !event.targetNode()->renderer()->isWidget())
+ return false;
+
+ return passMouseDownEventToWidget(toRenderWidget(event.targetNode()->renderer())->widget());
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
+{
+ return passMouseDownEventToWidget(renderWidget->widget());
+}
+
+bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& event, Widget* widget)
+{
+ if (!widget || !widget->isFrameView())
+ return false;
+
+ return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(event);
+}
+
+bool EventHandler::tabsToAllControls(KeyboardEvent* event) const
+{
+ notImplemented();
+ return false;
+}
+
+bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe, HitTestResult*)
+{
+ notImplemented();
+ return false;
+}
+
+bool EventHandler::passMouseDownEventToWidget(Widget*)
+{
+ notImplemented();
+ return false;
+}
+
+void EventHandler::focusDocumentView()
+{
+ if (Page* page = m_frame->page())
+ page->focusController()->setFocusedFrame(m_frame);
+}
+
+bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const
+{
+ // wx sends activate events separate from mouse events.
+ // We'll have to test the exact order of events,
+ // but for the moment just return false.
+ return false;
+}
+
+PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
+{
+ return ClipboardWx::create(ClipboardWritable, Clipboard::DragAndDrop);
+}
+
+unsigned EventHandler::accessKeyModifiers()
+{
+ return PlatformKeyboardEvent::AltKey;
+}
+
+}
diff --git a/Source/WebCore/page/wx/FrameWx.cpp b/Source/WebCore/page/wx/FrameWx.cpp
new file mode 100644
index 0000000..6c16adc
--- /dev/null
+++ b/Source/WebCore/page/wx/FrameWx.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 Kevin Ollivier <kevino@theolliviers.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Frame.h"
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+DragImageRef Frame::nodeImage(Node*)
+{
+ notImplemented();
+ return 0;
+}
+
+DragImageRef Frame::dragImageForSelection()
+{
+ notImplemented();
+ return 0;
+}
+
+}