summaryrefslogtreecommitdiffstats
path: root/WebCore/page
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:52 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:52 -0800
commit8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (patch)
tree11425ea0b299d6fb89c6d3618a22d97d5bf68d0f /WebCore/page
parent648161bb0edfc3d43db63caed5cc5213bc6cb78f (diff)
downloadexternal_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.zip
external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.gz
external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'WebCore/page')
-rw-r--r--WebCore/page/AXObjectCache.cpp239
-rw-r--r--WebCore/page/AXObjectCache.h113
-rw-r--r--WebCore/page/AbstractView.idl36
-rw-r--r--WebCore/page/AccessibilityImageMapLink.cpp130
-rw-r--r--WebCore/page/AccessibilityImageMapLink.h72
-rw-r--r--WebCore/page/AccessibilityList.cpp94
-rw-r--r--WebCore/page/AccessibilityList.h56
-rw-r--r--WebCore/page/AccessibilityListBox.cpp179
-rw-r--r--WebCore/page/AccessibilityListBox.h66
-rw-r--r--WebCore/page/AccessibilityListBoxOption.cpp207
-rw-r--r--WebCore/page/AccessibilityListBoxOption.h79
-rw-r--r--WebCore/page/AccessibilityObject.cpp1030
-rw-r--r--WebCore/page/AccessibilityObject.h419
-rw-r--r--WebCore/page/AccessibilityRenderObject.cpp2378
-rw-r--r--WebCore/page/AccessibilityRenderObject.h236
-rw-r--r--WebCore/page/AccessibilityTable.cpp491
-rw-r--r--WebCore/page/AccessibilityTable.h86
-rw-r--r--WebCore/page/AccessibilityTableCell.cpp122
-rw-r--r--WebCore/page/AccessibilityTableCell.h61
-rw-r--r--WebCore/page/AccessibilityTableColumn.cpp167
-rw-r--r--WebCore/page/AccessibilityTableColumn.h75
-rw-r--r--WebCore/page/AccessibilityTableHeaderContainer.cpp87
-rw-r--r--WebCore/page/AccessibilityTableHeaderContainer.h67
-rw-r--r--WebCore/page/AccessibilityTableRow.cpp110
-rw-r--r--WebCore/page/AccessibilityTableRow.h65
-rw-r--r--WebCore/page/BarInfo.cpp72
-rw-r--r--WebCore/page/BarInfo.h57
-rw-r--r--WebCore/page/BarInfo.idl35
-rw-r--r--WebCore/page/Chrome.cpp500
-rw-r--r--WebCore/page/Chrome.h131
-rw-r--r--WebCore/page/ChromeClient.h166
-rw-r--r--WebCore/page/Console.cpp481
-rw-r--r--WebCore/page/Console.h116
-rw-r--r--WebCore/page/Console.idl53
-rw-r--r--WebCore/page/ContextMenuClient.h59
-rw-r--r--WebCore/page/ContextMenuController.cpp297
-rw-r--r--WebCore/page/ContextMenuController.h61
-rw-r--r--WebCore/page/DOMSelection.cpp424
-rw-r--r--WebCore/page/DOMSelection.h102
-rw-r--r--WebCore/page/DOMSelection.idl70
-rw-r--r--WebCore/page/DOMWindow.cpp1279
-rw-r--r--WebCore/page/DOMWindow.h320
-rw-r--r--WebCore/page/DOMWindow.idl430
-rw-r--r--WebCore/page/DragActions.h66
-rw-r--r--WebCore/page/DragClient.h81
-rw-r--r--WebCore/page/DragController.cpp782
-rw-r--r--WebCore/page/DragController.h131
-rw-r--r--WebCore/page/EditorClient.h142
-rw-r--r--WebCore/page/EventHandler.cpp2348
-rw-r--r--WebCore/page/EventHandler.h364
-rw-r--r--WebCore/page/FocusController.cpp307
-rw-r--r--WebCore/page/FocusController.h64
-rw-r--r--WebCore/page/FocusDirection.h36
-rw-r--r--WebCore/page/Frame.cpp1847
-rw-r--r--WebCore/page/Frame.h314
-rw-r--r--WebCore/page/FrameLoadRequest.h90
-rw-r--r--WebCore/page/FramePrivate.h99
-rw-r--r--WebCore/page/FrameTree.cpp314
-rw-r--r--WebCore/page/FrameTree.h86
-rw-r--r--WebCore/page/FrameView.cpp1258
-rw-r--r--WebCore/page/FrameView.h191
-rw-r--r--WebCore/page/Geolocation.cpp222
-rw-r--r--WebCore/page/Geolocation.h104
-rw-r--r--WebCore/page/Geolocation.idl38
-rw-r--r--WebCore/page/Geoposition.cpp38
-rw-r--r--WebCore/page/Geoposition.h77
-rw-r--r--WebCore/page/Geoposition.idl42
-rw-r--r--WebCore/page/History.cpp77
-rw-r--r--WebCore/page/History.h56
-rw-r--r--WebCore/page/History.idl41
-rw-r--r--WebCore/page/Location.cpp135
-rw-r--r--WebCore/page/Location.h71
-rw-r--r--WebCore/page/Location.idl57
-rw-r--r--WebCore/page/MouseEventWithHitTestResults.cpp74
-rw-r--r--WebCore/page/MouseEventWithHitTestResults.h51
-rw-r--r--WebCore/page/Navigator.cpp218
-rw-r--r--WebCore/page/Navigator.h74
-rw-r--r--WebCore/page/Navigator.idl46
-rw-r--r--WebCore/page/Page.cpp582
-rw-r--r--WebCore/page/Page.h237
-rw-r--r--WebCore/page/PageGroup.cpp184
-rw-r--r--WebCore/page/PageGroup.h85
-rw-r--r--WebCore/page/PositionCallback.h44
-rw-r--r--WebCore/page/PositionCallback.idl34
-rw-r--r--WebCore/page/PositionError.h63
-rw-r--r--WebCore/page/PositionError.idl35
-rw-r--r--WebCore/page/PositionErrorCallback.h44
-rw-r--r--WebCore/page/PositionErrorCallback.idl34
-rw-r--r--WebCore/page/PositionOptions.h56
-rw-r--r--WebCore/page/PositionOptions.idl35
-rw-r--r--WebCore/page/PrintContext.cpp137
-rw-r--r--WebCore/page/PrintContext.h57
-rw-r--r--WebCore/page/Screen.cpp107
-rw-r--r--WebCore/page/Screen.h65
-rw-r--r--WebCore/page/Screen.idl43
-rw-r--r--WebCore/page/SecurityOrigin.cpp295
-rw-r--r--WebCore/page/SecurityOrigin.h141
-rw-r--r--WebCore/page/SecurityOriginHash.h81
-rw-r--r--WebCore/page/Settings.cpp512
-rw-r--r--WebCore/page/Settings.h326
-rw-r--r--WebCore/page/WindowFeatures.cpp188
-rw-r--r--WebCore/page/WindowFeatures.h83
-rw-r--r--WebCore/page/android/DragControllerAndroid.cpp57
-rw-r--r--WebCore/page/android/EventHandlerAndroid.cpp129
-rw-r--r--WebCore/page/android/InspectorControllerAndroid.cpp109
-rw-r--r--WebCore/page/animation/AnimationBase.cpp815
-rw-r--r--WebCore/page/animation/AnimationBase.h254
-rw-r--r--WebCore/page/animation/AnimationController.cpp298
-rw-r--r--WebCore/page/animation/AnimationController.h78
-rw-r--r--WebCore/page/animation/CompositeAnimation.cpp594
-rw-r--r--WebCore/page/animation/CompositeAnimation.h77
-rw-r--r--WebCore/page/animation/ImplicitAnimation.cpp203
-rw-r--r--WebCore/page/animation/ImplicitAnimation.h88
-rw-r--r--WebCore/page/animation/KeyframeAnimation.cpp293
-rw-r--r--WebCore/page/animation/KeyframeAnimation.h92
-rw-r--r--WebCore/page/gtk/AXObjectCacheAtk.cpp52
-rw-r--r--WebCore/page/gtk/AccessibilityObjectAtk.cpp30
-rw-r--r--WebCore/page/gtk/AccessibilityObjectWrapperAtk.cpp676
-rw-r--r--WebCore/page/gtk/AccessibilityObjectWrapperAtk.h62
-rw-r--r--WebCore/page/gtk/DragControllerGtk.cpp66
-rw-r--r--WebCore/page/gtk/EventHandlerGtk.cpp123
-rw-r--r--WebCore/page/gtk/FrameGtk.cpp37
-rw-r--r--WebCore/page/mac/AXObjectCacheMac.mm87
-rw-r--r--WebCore/page/mac/AccessibilityObjectMac.mm38
-rw-r--r--WebCore/page/mac/AccessibilityObjectWrapper.h55
-rw-r--r--WebCore/page/mac/AccessibilityObjectWrapper.mm1996
-rw-r--r--WebCore/page/mac/ChromeMac.mm51
-rw-r--r--WebCore/page/mac/DragControllerMac.mm69
-rw-r--r--WebCore/page/mac/EventHandlerMac.mm646
-rw-r--r--WebCore/page/mac/FrameMac.mm553
-rw-r--r--WebCore/page/mac/PageMac.cpp77
-rw-r--r--WebCore/page/mac/WebCoreFrameView.h40
-rw-r--r--WebCore/page/mac/WebCoreKeyboardUIMode.h40
-rw-r--r--WebCore/page/mac/WebCoreViewFactory.h146
-rw-r--r--WebCore/page/mac/WebCoreViewFactory.m48
-rw-r--r--WebCore/page/mac/WebDashboardRegion.h51
-rw-r--r--WebCore/page/mac/WebDashboardRegion.m77
-rw-r--r--WebCore/page/qt/AccessibilityObjectQt.cpp30
-rw-r--r--WebCore/page/qt/DragControllerQt.cpp68
-rw-r--r--WebCore/page/qt/EventHandlerQt.cpp135
-rw-r--r--WebCore/page/qt/FrameQt.cpp53
-rw-r--r--WebCore/page/win/AXObjectCacheWin.cpp61
-rw-r--r--WebCore/page/win/AccessibilityObjectWin.cpp37
-rw-r--r--WebCore/page/win/AccessibilityObjectWrapperWin.h54
-rw-r--r--WebCore/page/win/DragControllerWin.cpp64
-rw-r--r--WebCore/page/win/EventHandlerWin.cpp111
-rw-r--r--WebCore/page/win/FrameCGWin.cpp87
-rw-r--r--WebCore/page/win/FrameCairoWin.cpp42
-rw-r--r--WebCore/page/win/FrameWin.cpp101
-rw-r--r--WebCore/page/win/FrameWin.h41
-rw-r--r--WebCore/page/win/PageWin.cpp38
-rw-r--r--WebCore/page/wx/AccessibilityObjectWx.cpp30
-rw-r--r--WebCore/page/wx/DragControllerWx.cpp68
-rw-r--r--WebCore/page/wx/EventHandlerWx.cpp94
154 files changed, 33948 insertions, 0 deletions
diff --git a/WebCore/page/AXObjectCache.cpp b/WebCore/page/AXObjectCache.cpp
new file mode 100644
index 0000000..d9c4c9a
--- /dev/null
+++ b/WebCore/page/AXObjectCache.cpp
@@ -0,0 +1,239 @@
+/*
+ * 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 "AXObjectCache.h"
+
+#include "AccessibilityList.h"
+#include "AccessibilityListBox.h"
+#include "AccessibilityListBoxOption.h"
+#include "AccessibilityImageMapLink.h"
+#include "AccessibilityRenderObject.h"
+#include "AccessibilityTable.h"
+#include "AccessibilityTableCell.h"
+#include "AccessibilityTableColumn.h"
+#include "AccessibilityTableHeaderContainer.h"
+#include "AccessibilityTableRow.h"
+#include "HTMLNames.h"
+#include "RenderObject.h"
+
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+bool AXObjectCache::gAccessibilityEnabled = false;
+bool AXObjectCache::gAccessibilityEnhancedUserInterfaceEnabled = false;
+
+AXObjectCache::~AXObjectCache()
+{
+ HashMap<AXID, RefPtr<AccessibilityObject> >::iterator end = m_objects.end();
+ for (HashMap<AXID, RefPtr<AccessibilityObject> >::iterator it = m_objects.begin(); it != end; ++it) {
+ AccessibilityObject* obj = (*it).second.get();
+ detachWrapper(obj);
+ obj->detach();
+ }
+}
+
+AccessibilityObject* AXObjectCache::get(RenderObject* renderer)
+{
+ if (!renderer)
+ return 0;
+
+ RefPtr<AccessibilityObject> obj = 0;
+ AXID axID = m_renderObjectMapping.get(renderer);
+ ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
+
+ if (axID)
+ obj = m_objects.get(axID).get();
+
+ Node* element = renderer->element();
+ if (!obj) {
+ if (renderer->isListBox())
+ obj = AccessibilityListBox::create(renderer);
+ else if (element && (element->hasTagName(ulTag) || element->hasTagName(olTag) || element->hasTagName(dlTag)))
+ obj = AccessibilityList::create(renderer);
+ else if (renderer->isTable())
+ obj = AccessibilityTable::create(renderer);
+ else if (renderer->isTableRow())
+ obj = AccessibilityTableRow::create(renderer);
+ else if (renderer->isTableCell())
+ obj = AccessibilityTableCell::create(renderer);
+ else
+ obj = AccessibilityRenderObject::create(renderer);
+
+ getAXID(obj.get());
+
+ m_renderObjectMapping.set(renderer, obj.get()->axObjectID());
+ m_objects.set(obj.get()->axObjectID(), obj);
+ attachWrapper(obj.get());
+ }
+
+ return obj.get();
+}
+
+AccessibilityObject* AXObjectCache::get(AccessibilityRole role)
+{
+ RefPtr<AccessibilityObject> obj = 0;
+
+ // will be filled in...
+ switch (role) {
+ case ListBoxOptionRole:
+ obj = AccessibilityListBoxOption::create();
+ break;
+ case ImageMapLinkRole:
+ obj = AccessibilityImageMapLink::create();
+ break;
+ case ColumnRole:
+ obj = AccessibilityTableColumn::create();
+ break;
+ case TableHeaderContainerRole:
+ obj = AccessibilityTableHeaderContainer::create();
+ break;
+ default:
+ obj = 0;
+ }
+
+ if (obj)
+ getAXID(obj.get());
+ else
+ return 0;
+
+ m_objects.set(obj->axObjectID(), obj);
+ attachWrapper(obj.get());
+ return obj.get();
+}
+
+void AXObjectCache::remove(AXID axID)
+{
+ if (!axID)
+ return;
+
+ // first fetch object to operate some cleanup functions on it
+ AccessibilityObject* obj = m_objects.get(axID).get();
+ if (!obj)
+ return;
+
+ detachWrapper(obj);
+ obj->detach();
+ removeAXID(obj);
+
+ // finally remove the object
+ if (!m_objects.take(axID)) {
+ return;
+ }
+
+ ASSERT(m_objects.size() >= m_idsInUse.size());
+}
+
+void AXObjectCache::remove(RenderObject* renderer)
+{
+ if (!renderer)
+ return;
+
+ AXID axID = m_renderObjectMapping.get(renderer);
+ remove(axID);
+ m_renderObjectMapping.remove(renderer);
+}
+
+AXID AXObjectCache::getAXID(AccessibilityObject* obj)
+{
+ // check for already-assigned ID
+ AXID objID = obj->axObjectID();
+ if (objID) {
+ ASSERT(m_idsInUse.contains(objID));
+ return objID;
+ }
+
+ // generate a new ID
+ static AXID lastUsedID = 0;
+ objID = lastUsedID;
+ do
+ ++objID;
+ while (objID == 0 || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID));
+ m_idsInUse.add(objID);
+ lastUsedID = objID;
+ obj->setAXObjectID(objID);
+
+ return objID;
+}
+
+void AXObjectCache::removeAXID(AccessibilityObject* obj)
+{
+ AXID objID = obj->axObjectID();
+ if (objID == 0)
+ return;
+ ASSERT(!HashTraits<AXID>::isDeletedValue(objID));
+ ASSERT(m_idsInUse.contains(objID));
+ obj->setAXObjectID(0);
+ m_idsInUse.remove(objID);
+}
+
+void AXObjectCache::childrenChanged(RenderObject* renderer)
+{
+ if (!renderer)
+ return;
+
+ AXID axID = m_renderObjectMapping.get(renderer);
+ if (!axID)
+ return;
+
+ AccessibilityObject* obj = m_objects.get(axID).get();
+ if (obj)
+ obj->childrenChanged();
+}
+
+#if HAVE(ACCESSIBILITY)
+void AXObjectCache::selectedChildrenChanged(RenderObject* renderer)
+{
+ postNotificationToElement(renderer, "AXSelectedChildrenChanged");
+}
+#endif
+
+#if HAVE(ACCESSIBILITY)
+void AXObjectCache::handleActiveDescendantChanged(RenderObject* renderer)
+{
+ if (!renderer)
+ return;
+ AccessibilityObject* obj = get(renderer);
+ if (obj)
+ obj->handleActiveDescendantChanged();
+}
+
+void AXObjectCache::handleAriaRoleChanged(RenderObject* renderer)
+{
+ if (!renderer)
+ return;
+ AccessibilityObject* obj = get(renderer);
+ if (obj && obj->isAccessibilityRenderObject())
+ static_cast<AccessibilityRenderObject*>(obj)->setAriaRole();
+}
+#endif
+
+} // namespace WebCore
diff --git a/WebCore/page/AXObjectCache.h b/WebCore/page/AXObjectCache.h
new file mode 100644
index 0000000..5e95f74
--- /dev/null
+++ b/WebCore/page/AXObjectCache.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2003, 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.
+ */
+
+#ifndef AXObjectCache_h
+#define AXObjectCache_h
+
+#include "AccessibilityObject.h"
+#include <limits.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/RefPtr.h>
+
+#ifdef __OBJC__
+@class WebCoreTextMarker;
+#else
+class WebCoreTextMarker;
+#endif
+
+namespace WebCore {
+
+ class RenderObject;
+ class String;
+ class VisiblePosition;
+ class AccessibilityObject;
+ class Node;
+
+ typedef unsigned AXID;
+
+ struct TextMarkerData {
+ AXID axID;
+ Node* node;
+ int offset;
+ EAffinity affinity;
+ };
+
+ class AXObjectCache {
+ public:
+ ~AXObjectCache();
+
+ // to be used with render objects
+ AccessibilityObject* get(RenderObject*);
+
+ // used for objects without backing elements
+ AccessibilityObject* get(AccessibilityRole);
+
+ void remove(RenderObject*);
+ void remove(AXID);
+
+ void detachWrapper(AccessibilityObject*);
+ void attachWrapper(AccessibilityObject*);
+ void postNotification(RenderObject*, const String&);
+ void postNotificationToElement(RenderObject*, const String&);
+ void childrenChanged(RenderObject*);
+ void selectedChildrenChanged(RenderObject*);
+ void handleActiveDescendantChanged(RenderObject*);
+ void handleAriaRoleChanged(RenderObject*);
+ void handleFocusedUIElementChanged();
+ static void enableAccessibility() { gAccessibilityEnabled = true; }
+ static void enableEnhancedUserInterfaceAccessibility() { gAccessibilityEnhancedUserInterfaceEnabled = true; }
+
+ static bool accessibilityEnabled() { return gAccessibilityEnabled; }
+ static bool accessibilityEnhancedUserInterfaceEnabled() { return gAccessibilityEnhancedUserInterfaceEnabled; }
+
+ void removeAXID(AccessibilityObject*);
+ bool isIDinUse(AXID id) const { return m_idsInUse.contains(id); }
+
+ private:
+ HashMap<AXID, RefPtr<AccessibilityObject> > m_objects;
+ HashMap<RenderObject*, AXID> m_renderObjectMapping;
+ static bool gAccessibilityEnabled;
+ static bool gAccessibilityEnhancedUserInterfaceEnabled;
+
+ HashSet<AXID> m_idsInUse;
+
+ AXID getAXID(AccessibilityObject*);
+ };
+
+#if !HAVE(ACCESSIBILITY)
+ inline void AXObjectCache::handleActiveDescendantChanged(RenderObject*) { }
+ inline void AXObjectCache::handleAriaRoleChanged(RenderObject*) { }
+ inline void AXObjectCache::handleFocusedUIElementChanged() { }
+ inline void AXObjectCache::detachWrapper(AccessibilityObject*) { }
+ inline void AXObjectCache::attachWrapper(AccessibilityObject*) { }
+ inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { }
+ inline void AXObjectCache::postNotification(RenderObject*, const String&) { }
+ inline void AXObjectCache::postNotificationToElement(RenderObject*, const String&) { }
+#endif
+
+}
+
+#endif
diff --git a/WebCore/page/AbstractView.idl b/WebCore/page/AbstractView.idl
new file mode 100644
index 0000000..5b7ce89
--- /dev/null
+++ b/WebCore/page/AbstractView.idl
@@ -0,0 +1,36 @@
+/*
+ * 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
+ ] AbstractView {
+ readonly attribute Document document;
+ };
+
+}
diff --git a/WebCore/page/AccessibilityImageMapLink.cpp b/WebCore/page/AccessibilityImageMapLink.cpp
new file mode 100644
index 0000000..5557446
--- /dev/null
+++ b/WebCore/page/AccessibilityImageMapLink.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 "AccessibilityImageMapLink.h"
+
+#include "AccessibilityRenderObject.h"
+#include "AXObjectCache.h"
+#include "Document.h"
+#include "HTMLNames.h"
+#include "IntRect.h"
+#include "RenderObject.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+AccessibilityImageMapLink::AccessibilityImageMapLink()
+ : m_areaElement(0),
+ m_mapElement(0)
+{
+}
+
+AccessibilityImageMapLink::~AccessibilityImageMapLink()
+{
+}
+
+PassRefPtr<AccessibilityImageMapLink> AccessibilityImageMapLink::create()
+{
+ return adoptRef(new AccessibilityImageMapLink());
+}
+
+AccessibilityObject* AccessibilityImageMapLink::parentObject() const
+{
+ if (m_parent)
+ return m_parent;
+
+ if (!m_mapElement || !m_mapElement->renderer())
+ return 0;
+
+ return m_mapElement->document()->axObjectCache()->get(m_mapElement->renderer());
+}
+
+Element* AccessibilityImageMapLink::actionElement() const
+{
+ return anchorElement();
+}
+
+Element* AccessibilityImageMapLink::anchorElement() const
+{
+ return m_areaElement;
+}
+
+String AccessibilityImageMapLink::accessibilityDescription() const
+{
+ if (!m_areaElement)
+ return String();
+
+ const AtomicString& alt = m_areaElement->getAttribute(altAttr);
+ if (!alt.isEmpty())
+ return alt;
+
+ return String();
+}
+
+String AccessibilityImageMapLink::title() const
+{
+ if (!m_areaElement)
+ return String();
+
+ const AtomicString& title = m_areaElement->getAttribute(titleAttr);
+ if (!title.isEmpty())
+ return title;
+ const AtomicString& summary = m_areaElement->getAttribute(summaryAttr);
+ if (!summary.isEmpty())
+ return summary;
+
+ return String();
+}
+
+IntRect AccessibilityImageMapLink::elementRect() const
+{
+ if (!m_mapElement || !m_areaElement)
+ return IntRect();
+
+ RenderObject* renderer;
+ if (m_parent && m_parent->isAccessibilityRenderObject())
+ renderer = static_cast<AccessibilityRenderObject*>(m_parent)->renderer();
+ else
+ renderer = m_mapElement->renderer();
+
+ if (!renderer)
+ return IntRect();
+
+ return m_areaElement->getRect(renderer);
+}
+
+IntSize AccessibilityImageMapLink::size() const
+{
+ return elementRect().size();
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/AccessibilityImageMapLink.h b/WebCore/page/AccessibilityImageMapLink.h
new file mode 100644
index 0000000..7fc8d3c
--- /dev/null
+++ b/WebCore/page/AccessibilityImageMapLink.h
@@ -0,0 +1,72 @@
+/*
+ * 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 AccessibilityImageMapLink_h
+#define AccessibilityImageMapLink_h
+
+#include "AccessibilityObject.h"
+#include "HTMLAreaElement.h"
+#include "HTMLMapElement.h"
+
+namespace WebCore {
+
+class AccessibilityImageMapLink : public AccessibilityObject {
+
+private:
+ AccessibilityImageMapLink();
+public:
+ static PassRefPtr<AccessibilityImageMapLink> create();
+ virtual ~AccessibilityImageMapLink();
+
+ void setHTMLAreaElement(HTMLAreaElement* element) { m_areaElement = element; }
+ void setHTMLMapElement(HTMLMapElement* element) { m_mapElement = element; }
+ void setParent(AccessibilityObject* parent) { m_parent = parent; }
+
+ virtual AccessibilityRole roleValue() const { return WebCoreLinkRole; }
+ virtual bool accessibilityIsIgnored() const { return false; }
+
+ virtual AccessibilityObject* parentObject() const;
+ virtual Element* anchorElement() const;
+ virtual Element* actionElement() const;
+
+ virtual bool isLink() const { return true; }
+ virtual String title() const;
+ virtual String accessibilityDescription() const;
+
+ virtual IntSize size() const;
+ virtual IntRect elementRect() const;
+
+private:
+ HTMLAreaElement* m_areaElement;
+ HTMLMapElement* m_mapElement;
+ AccessibilityObject* m_parent;
+};
+
+} // namespace WebCore
+
+#endif // AccessibilityImageMapLink_h
diff --git a/WebCore/page/AccessibilityList.cpp b/WebCore/page/AccessibilityList.cpp
new file mode 100644
index 0000000..ad71ff4
--- /dev/null
+++ b/WebCore/page/AccessibilityList.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 "AccessibilityList.h"
+
+#include "AXObjectCache.h"
+#include "HTMLNames.h"
+#include "RenderObject.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+AccessibilityList::AccessibilityList(RenderObject* renderer)
+ : AccessibilityRenderObject(renderer)
+{
+}
+
+AccessibilityList::~AccessibilityList()
+{
+}
+
+PassRefPtr<AccessibilityList> AccessibilityList::create(RenderObject* renderer)
+{
+ return adoptRef(new AccessibilityList(renderer));
+}
+
+bool AccessibilityList::accessibilityIsIgnored() const
+{
+ // lists don't appear on tiger/leopard on the mac
+#if PLATFORM(MAC) && (defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD))
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool AccessibilityList::isUnorderedList() const
+{
+ if (!m_renderer)
+ return false;
+
+ Node* element = m_renderer->element();
+ return element && element->hasTagName(ulTag);
+}
+
+bool AccessibilityList::isOrderedList() const
+{
+ if (!m_renderer)
+ return false;
+
+ Node* element = m_renderer->element();
+ return element && element->hasTagName(olTag);
+}
+
+bool AccessibilityList::isDefinitionList() const
+{
+ if (!m_renderer)
+ return false;
+
+ Node* element = m_renderer->element();
+ return element && element->hasTagName(dlTag);
+}
+
+
+} // namespace WebCore
diff --git a/WebCore/page/AccessibilityList.h b/WebCore/page/AccessibilityList.h
new file mode 100644
index 0000000..315ccac
--- /dev/null
+++ b/WebCore/page/AccessibilityList.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.
+ * 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 AccessibilityList_h
+#define AccessibilityList_h
+
+#include "AccessibilityRenderObject.h"
+
+namespace WebCore {
+
+class AccessibilityList : public AccessibilityRenderObject {
+
+private:
+ AccessibilityList(RenderObject*);
+public:
+ static PassRefPtr<AccessibilityList> create(RenderObject*);
+ virtual ~AccessibilityList();
+
+ virtual bool isList() const { return true; };
+ bool isUnorderedList() const;
+ bool isOrderedList() const;
+ bool isDefinitionList() const;
+
+ virtual AccessibilityRole roleValue() const { return ListRole; }
+ virtual bool accessibilityIsIgnored() const;
+
+};
+
+} // namespace WebCore
+
+#endif // AccessibilityList_h
diff --git a/WebCore/page/AccessibilityListBox.cpp b/WebCore/page/AccessibilityListBox.cpp
new file mode 100644
index 0000000..912351e
--- /dev/null
+++ b/WebCore/page/AccessibilityListBox.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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 "AccessibilityListBox.h"
+
+#include "AXObjectCache.h"
+#include "AccessibilityListBoxOption.h"
+#include "HitTestResult.h"
+#include "HTMLNames.h"
+#include "HTMLSelectElement.h"
+#include "RenderListBox.h"
+#include "RenderObject.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+AccessibilityListBox::AccessibilityListBox(RenderObject* renderer)
+ : AccessibilityRenderObject(renderer)
+{
+}
+
+AccessibilityListBox::~AccessibilityListBox()
+{
+}
+
+PassRefPtr<AccessibilityListBox> AccessibilityListBox::create(RenderObject* renderer)
+{
+ return adoptRef(new AccessibilityListBox(renderer));
+}
+
+bool AccessibilityListBox::canSetSelectedChildrenAttribute() const
+{
+ Node* selectNode = m_renderer->node();
+ if (!selectNode)
+ return false;
+
+ return !static_cast<HTMLSelectElement*>(selectNode)->disabled();
+}
+
+void AccessibilityListBox::addChildren()
+{
+ Node* selectNode = m_renderer->node();
+ if (!selectNode)
+ return;
+
+ m_haveChildren = true;
+
+ const Vector<HTMLElement*>& listItems = static_cast<HTMLSelectElement*>(selectNode)->listItems();
+ unsigned length = listItems.size();
+ for (unsigned i = 0; i < length; i++) {
+ AccessibilityObject* listOption = listBoxOptionAccessibilityObject(listItems[i]);
+ if (listOption)
+ m_children.append(listOption);
+ }
+}
+
+void AccessibilityListBox::setSelectedChildren(AccessibilityChildrenVector& children)
+{
+ if (!canSetSelectedChildrenAttribute())
+ return;
+
+ Node* selectNode = m_renderer->node();
+ if (!selectNode)
+ return;
+
+ // disable any selected options
+ unsigned length = m_children.size();
+ for (unsigned i = 0; i < length; i++) {
+ AccessibilityListBoxOption* listBoxOption = static_cast<AccessibilityListBoxOption*>(m_children[i].get());
+ if (listBoxOption->isSelected())
+ listBoxOption->setSelected(false);
+ }
+
+ length = children.size();
+ for (unsigned i = 0; i < length; i++) {
+ AccessibilityObject* obj = children[i].get();
+ if (obj->roleValue() != ListBoxOptionRole)
+ continue;
+
+ static_cast<AccessibilityListBoxOption*>(obj)->setSelected(true);
+ }
+}
+
+void AccessibilityListBox::selectedChildren(AccessibilityChildrenVector& result)
+{
+ ASSERT(result.isEmpty());
+
+ if (!hasChildren())
+ addChildren();
+
+ unsigned length = m_children.size();
+ for (unsigned i = 0; i < length; i++) {
+ if (static_cast<AccessibilityListBoxOption*>(m_children[i].get())->isSelected())
+ result.append(m_children[i]);
+ }
+}
+
+void AccessibilityListBox::visibleChildren(AccessibilityChildrenVector& result)
+{
+ ASSERT(result.isEmpty());
+
+ if (!hasChildren())
+ addChildren();
+
+ unsigned length = m_children.size();
+ for (unsigned i = 0; i < length; i++) {
+ if (static_cast<RenderListBox*>(m_renderer)->listIndexIsVisible(i))
+ result.append(m_children[i]);
+ }
+}
+
+AccessibilityObject* AccessibilityListBox::listBoxOptionAccessibilityObject(HTMLElement* element) const
+{
+ // skip hr elements
+ if (!element || element->hasTagName(hrTag))
+ return 0;
+
+ AccessibilityObject* listBoxObject = m_renderer->document()->axObjectCache()->get(ListBoxOptionRole);
+ static_cast<AccessibilityListBoxOption*>(listBoxObject)->setHTMLElement(element);
+
+ return listBoxObject;
+}
+
+AccessibilityObject* AccessibilityListBox::doAccessibilityHitTest(const IntPoint& point)
+{
+ // the internal HTMLSelectElement methods for returning a listbox option at a point
+ // ignore optgroup elements.
+ if (!m_renderer)
+ return 0;
+
+ Node *element = m_renderer->element();
+ if (!element)
+ return 0;
+
+ if (!hasChildren())
+ addChildren();
+
+ IntRect parentRect = boundingBoxRect();
+
+ unsigned length = m_children.size();
+ for (unsigned i = 0; i < length; i++) {
+ IntRect rect = static_cast<RenderListBox*>(m_renderer)->itemBoundingBoxRect(parentRect.x(), parentRect.y(), i);
+ if (rect.contains(point))
+ return m_children[i].get();
+ }
+
+ return this;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/AccessibilityListBox.h b/WebCore/page/AccessibilityListBox.h
new file mode 100644
index 0000000..f95a921
--- /dev/null
+++ b/WebCore/page/AccessibilityListBox.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.
+ * 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 AccessibilityListBox_h
+#define AccessibilityListBox_h
+
+#include "AccessibilityObject.h"
+#include "AccessibilityRenderObject.h"
+
+namespace WebCore {
+
+class AccessibilityListBox : public AccessibilityRenderObject {
+
+private:
+ AccessibilityListBox(RenderObject*);
+public:
+ static PassRefPtr<AccessibilityListBox> create(RenderObject*);
+ virtual ~AccessibilityListBox();
+
+ virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&);
+ virtual bool isListBox() const { return true; };
+
+ virtual bool canSetFocusAttribute() const { return true; }
+ virtual bool canSetSelectedChildrenAttribute() const;
+ void setSelectedChildren(AccessibilityChildrenVector&);
+ virtual AccessibilityRole roleValue() const { return ListBoxRole; }
+
+ virtual bool accessibilityIsIgnored() const { return false; }
+
+ virtual void selectedChildren(AccessibilityChildrenVector&);
+ virtual void visibleChildren(AccessibilityChildrenVector&);
+
+ virtual void addChildren();
+
+private:
+ AccessibilityObject* listBoxOptionAccessibilityObject(HTMLElement*) const;
+};
+
+} // namespace WebCore
+
+#endif // AccessibilityListBox_h
diff --git a/WebCore/page/AccessibilityListBoxOption.cpp b/WebCore/page/AccessibilityListBoxOption.cpp
new file mode 100644
index 0000000..fedfe91
--- /dev/null
+++ b/WebCore/page/AccessibilityListBoxOption.cpp
@@ -0,0 +1,207 @@
+/*
+ * 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 "AccessibilityListBoxOption.h"
+
+#include "AXObjectCache.h"
+#include "AccessibilityListBox.h"
+#include "Element.h"
+#include "HTMLElement.h"
+#include "HTMLNames.h"
+#include "HTMLOptionElement.h"
+#include "HTMLOptGroupElement.h"
+#include "HTMLSelectElement.h"
+#include "IntRect.h"
+#include "RenderObject.h"
+#include "RenderListBox.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+AccessibilityListBoxOption::AccessibilityListBoxOption()
+ : m_optionElement(0)
+{
+}
+
+AccessibilityListBoxOption::~AccessibilityListBoxOption()
+{
+}
+
+PassRefPtr<AccessibilityListBoxOption> AccessibilityListBoxOption::create()
+{
+ return adoptRef(new AccessibilityListBoxOption());
+}
+
+bool AccessibilityListBoxOption::isEnabled() const
+{
+ if (!m_optionElement)
+ return false;
+
+ if (m_optionElement->hasTagName(optgroupTag))
+ return false;
+
+ return true;
+}
+
+bool AccessibilityListBoxOption::isSelected() const
+{
+ if (!m_optionElement)
+ return false;
+
+ if (!m_optionElement->hasTagName(optionTag))
+ return false;
+
+ return static_cast<HTMLOptionElement*>(m_optionElement)->selected();
+}
+
+IntRect AccessibilityListBoxOption::elementRect() const
+{
+ IntRect rect;
+ if (!m_optionElement)
+ return rect;
+
+ HTMLSelectElement* listBoxParentNode = listBoxOptionParentNode();
+ if (!listBoxParentNode)
+ return rect;
+
+ RenderObject* listBoxRenderer = listBoxParentNode->renderer();
+ if (!listBoxRenderer)
+ return rect;
+
+ IntRect parentRect = listBoxRenderer->document()->axObjectCache()->get(listBoxRenderer)->boundingBoxRect();
+ int index = listBoxOptionIndex();
+ if (index != -1)
+ rect = static_cast<RenderListBox*>(listBoxRenderer)->itemBoundingBoxRect(parentRect.x(), parentRect.y(), index);
+
+ return rect;
+}
+
+bool AccessibilityListBoxOption::canSetSelectedAttribute() const
+{
+ if (!m_optionElement)
+ return false;
+
+ if (!m_optionElement->hasTagName(optionTag))
+ return false;
+
+ if (m_optionElement->disabled())
+ return false;
+
+ HTMLSelectElement* selectElement = listBoxOptionParentNode();
+ if (selectElement && selectElement->disabled())
+ return false;
+
+ return true;
+}
+
+String AccessibilityListBoxOption::stringValue() const
+{
+ if (!m_optionElement)
+ return String();
+
+ if (m_optionElement->hasTagName(optionTag))
+ return static_cast<HTMLOptionElement*>(m_optionElement)->text();
+
+ if (m_optionElement->hasTagName(optgroupTag))
+ return static_cast<HTMLOptGroupElement*>(m_optionElement)->groupLabelText();
+
+ return String();
+}
+
+IntSize AccessibilityListBoxOption::size() const
+{
+ return elementRect().size();
+}
+
+Element* AccessibilityListBoxOption::actionElement() const
+{
+ return m_optionElement;
+}
+
+AccessibilityObject* AccessibilityListBoxOption::parentObject() const
+{
+ HTMLSelectElement* parentNode = listBoxOptionParentNode();
+ if (!parentNode)
+ return 0;
+
+ return m_optionElement->document()->axObjectCache()->get(parentNode->renderer());
+}
+
+void AccessibilityListBoxOption::setSelected(bool selected)
+{
+ HTMLSelectElement* selectElement = listBoxOptionParentNode();
+ if (!selectElement)
+ return;
+
+ if (!canSetSelectedAttribute())
+ return;
+
+ bool isOptionSelected = isSelected();
+ if ((isOptionSelected && selected) || (!isOptionSelected && !selected))
+ return;
+
+ selectElement->accessKeySetSelectedIndex(listBoxOptionIndex());
+}
+
+HTMLSelectElement* AccessibilityListBoxOption::listBoxOptionParentNode() const
+{
+ if (!m_optionElement)
+ return 0;
+
+ if (m_optionElement->hasTagName(optionTag))
+ return static_cast<HTMLOptionElement*>(m_optionElement)->ownerSelectElement();
+
+ if (m_optionElement->hasTagName(optgroupTag))
+ return static_cast<HTMLOptGroupElement*>(m_optionElement)->ownerSelectElement();
+
+ return 0;
+}
+
+int AccessibilityListBoxOption::listBoxOptionIndex() const
+{
+ if (!m_optionElement)
+ return -1;
+
+ HTMLSelectElement* selectElement = listBoxOptionParentNode();
+ if (!selectElement)
+ return -1;
+
+ const Vector<HTMLElement*>& listItems = selectElement->listItems();
+ unsigned length = listItems.size();
+ for (unsigned i = 0; i < length; i++)
+ if (listItems[i] == m_optionElement)
+ return i;
+
+ return -1;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/AccessibilityListBoxOption.h b/WebCore/page/AccessibilityListBoxOption.h
new file mode 100644
index 0000000..1b588cd
--- /dev/null
+++ b/WebCore/page/AccessibilityListBoxOption.h
@@ -0,0 +1,79 @@
+/*
+ * 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 AccessibilityListBoxOption_h
+#define AccessibilityListBoxOption_h
+
+#include "AccessibilityObject.h"
+#include "HTMLElement.h"
+
+namespace WebCore {
+
+class AccessibilityListBox;
+class Element;
+class HTMLElement;
+class HTMLSelectElement;
+class String;
+
+class AccessibilityListBoxOption : public AccessibilityObject {
+
+private:
+ AccessibilityListBoxOption();
+public:
+ static PassRefPtr<AccessibilityListBoxOption> create();
+ virtual ~AccessibilityListBoxOption();
+
+ void setHTMLElement(HTMLElement* element) { m_optionElement = element; }
+
+ virtual AccessibilityRole roleValue() const { return ListBoxOptionRole; }
+ virtual bool accessibilityIsIgnored() const { return false; }
+ virtual bool isSelected() const;
+ virtual bool isEnabled() const;
+ virtual String stringValue() const;
+ virtual Element* actionElement() const;
+
+ virtual void setSelected(bool);
+ virtual bool canSetSelectedAttribute() const;
+
+ virtual IntRect elementRect() const;
+ virtual IntSize size() const;
+ virtual AccessibilityObject* parentObject() const;
+ bool isListBoxOption() const { return true; };
+
+private:
+ HTMLElement* m_optionElement;
+
+ HTMLSelectElement* listBoxOptionParentNode() const;
+ int listBoxOptionIndex() const;
+ IntRect listBoxOptionRect() const;
+ AccessibilityObject* listBoxOptionAccessibilityObject(HTMLElement* element) const;
+};
+
+} // namespace WebCore
+
+#endif // AccessibilityListBoxOption_h
diff --git a/WebCore/page/AccessibilityObject.cpp b/WebCore/page/AccessibilityObject.cpp
new file mode 100644
index 0000000..6be8c1a
--- /dev/null
+++ b/WebCore/page/AccessibilityObject.cpp
@@ -0,0 +1,1030 @@
+/*
+ * 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 "AccessibilityObject.h"
+
+#include "AccessibilityRenderObject.h"
+#include "AXObjectCache.h"
+#include "CharacterNames.h"
+#include "FloatRect.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "LocalizedStrings.h"
+#include "NodeList.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "RenderImage.h"
+#include "RenderListMarker.h"
+#include "RenderMenuList.h"
+#include "RenderTextControl.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include "RenderWidget.h"
+#include "SelectionController.h"
+#include "TextIterator.h"
+#include "htmlediting.h"
+#include "visible_units.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+AccessibilityObject::AccessibilityObject()
+ : m_id(0)
+ , m_haveChildren(false)
+#if PLATFORM(GTK)
+ , m_wrapper(0)
+#endif
+{
+}
+
+AccessibilityObject::~AccessibilityObject()
+{
+ ASSERT(isDetached());
+}
+
+void AccessibilityObject::detach()
+{
+ removeAXObjectID();
+#if HAVE(ACCESSIBILITY)
+ setWrapper(0);
+#endif
+}
+
+AccessibilityObject* AccessibilityObject::firstChild() const
+{
+ return 0;
+}
+
+AccessibilityObject* AccessibilityObject::lastChild() const
+{
+ return 0;
+}
+
+AccessibilityObject* AccessibilityObject::previousSibling() const
+{
+ return 0;
+}
+
+AccessibilityObject* AccessibilityObject::nextSibling() const
+{
+ return 0;
+}
+
+AccessibilityObject* AccessibilityObject::parentObject() const
+{
+ return 0;
+}
+
+AccessibilityObject* AccessibilityObject::parentObjectUnignored() const
+{
+ AccessibilityObject* parent;
+ for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject())
+ ;
+ return parent;
+}
+
+int AccessibilityObject::layoutCount() const
+{
+ return 0;
+}
+
+String AccessibilityObject::text() const
+{
+ return String();
+}
+
+String AccessibilityObject::helpText() const
+{
+ return String();
+}
+
+String AccessibilityObject::textUnderElement() const
+{
+ return String();
+}
+
+bool AccessibilityObject::isARIAInput(AccessibilityRole ariaRole)
+{
+ return ariaRole == RadioButtonRole || ariaRole == CheckBoxRole || ariaRole == TextFieldRole;
+}
+
+bool AccessibilityObject::isARIAControl(AccessibilityRole ariaRole)
+{
+ return isARIAInput(ariaRole) || ariaRole == TextAreaRole || ariaRole == ButtonRole
+ || ariaRole == ComboBoxRole || ariaRole == SliderRole;
+}
+
+int AccessibilityObject::intValue() const
+{
+ return 0;
+}
+
+String AccessibilityObject::stringValue() const
+{
+ return String();
+}
+
+String AccessibilityObject::ariaAccessiblityName(const String&) const
+{
+ return String();
+}
+
+String AccessibilityObject::ariaLabeledByAttribute() const
+{
+ return String();
+}
+
+String AccessibilityObject::title() const
+{
+ return String();
+}
+
+String AccessibilityObject::ariaDescribedByAttribute() const
+{
+ return String();
+}
+
+String AccessibilityObject::accessibilityDescription() const
+{
+ return String();
+}
+
+IntRect AccessibilityObject::boundingBoxRect() const
+{
+ return IntRect();
+}
+
+IntRect AccessibilityObject::elementRect() const
+{
+ return IntRect();
+}
+
+IntSize AccessibilityObject::size() const
+{
+ return IntSize();
+}
+
+IntPoint AccessibilityObject::clickPoint() const
+{
+ IntRect rect = elementRect();
+ return IntPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2);
+}
+
+void AccessibilityObject::linkedUIElements(AccessibilityChildrenVector&) const
+{
+ return;
+}
+
+AccessibilityObject* AccessibilityObject::titleUIElement() const
+{
+ return 0;
+}
+
+int AccessibilityObject::textLength() const
+{
+ return 0;
+}
+
+PassRefPtr<Range> AccessibilityObject::ariaSelectedTextDOMRange() const
+{
+ return 0;
+}
+
+String AccessibilityObject::selectedText() const
+{
+ return String();
+}
+
+const AtomicString& AccessibilityObject::accessKey() const
+{
+ return nullAtom;
+}
+
+Selection AccessibilityObject::selection() const
+{
+ return Selection();
+}
+
+PlainTextRange AccessibilityObject::selectedTextRange() const
+{
+ return PlainTextRange();
+}
+
+unsigned AccessibilityObject::selectionStart() const
+{
+ return selectedTextRange().start;
+}
+
+unsigned AccessibilityObject::selectionEnd() const
+{
+ return selectedTextRange().length;
+}
+
+void AccessibilityObject::setSelectedText(const String&)
+{
+ // TODO: set selected text (ReplaceSelectionCommand). <rdar://problem/4712125>
+ notImplemented();
+}
+
+void AccessibilityObject::setSelectedTextRange(const PlainTextRange& range)
+{
+}
+
+void AccessibilityObject::makeRangeVisible(const PlainTextRange&)
+{
+ // TODO: make range visible (scrollRectToVisible). <rdar://problem/4712101>
+ notImplemented();
+}
+
+KURL AccessibilityObject::url() const
+{
+ return KURL();
+}
+
+void AccessibilityObject::setFocused(bool on)
+{
+}
+
+void AccessibilityObject::setValue(const String& string)
+{
+}
+
+void AccessibilityObject::setSelected(bool)
+{
+}
+
+bool AccessibilityObject::press() const
+{
+ Element* actionElem = actionElement();
+ if (!actionElem)
+ return false;
+ if (Frame* f = actionElem->document()->frame())
+ f->loader()->resetMultipleFormSubmissionProtection();
+ actionElem->accessKeyAction(true);
+ return true;
+}
+
+AXObjectCache* AccessibilityObject::axObjectCache() const
+{
+ return 0;
+}
+
+Widget* AccessibilityObject::widget() const
+{
+ return 0;
+}
+
+Widget* AccessibilityObject::widgetForAttachmentView() const
+{
+ return 0;
+}
+
+Element* AccessibilityObject::anchorElement() const
+{
+ return 0;
+}
+
+Element* AccessibilityObject::actionElement() const
+{
+ return 0;
+}
+
+// This function is like a cross-platform version of - (WebCoreTextMarkerRange*)textMarkerRange. It returns
+// a Range that we can convert to a WebCoreRange in the Obj-C file
+VisiblePositionRange AccessibilityObject::visiblePositionRange() const
+{
+ return VisiblePositionRange();
+}
+
+VisiblePositionRange AccessibilityObject::visiblePositionRangeForLine(unsigned lineCount) const
+{
+ return VisiblePositionRange();
+}
+
+VisiblePosition AccessibilityObject::visiblePositionForIndex(int index) const
+{
+ return VisiblePosition();
+}
+
+int AccessibilityObject::indexForVisiblePosition(const VisiblePosition& pos) const
+{
+ return 0;
+}
+
+VisiblePositionRange AccessibilityObject::visiblePositionRangeForUnorderedPositions(const VisiblePosition& visiblePos1, const VisiblePosition& visiblePos2) const
+{
+ if (visiblePos1.isNull() || visiblePos2.isNull())
+ return VisiblePositionRange();
+
+ VisiblePosition startPos;
+ VisiblePosition endPos;
+ bool alreadyInOrder;
+
+ // upstream is ordered before downstream for the same position
+ if (visiblePos1 == visiblePos2 && visiblePos2.affinity() == UPSTREAM)
+ alreadyInOrder = false;
+
+ // use selection order to see if the positions are in order
+ else
+ alreadyInOrder = Selection(visiblePos1, visiblePos2).isBaseFirst();
+
+ if (alreadyInOrder) {
+ startPos = visiblePos1;
+ endPos = visiblePos2;
+ } else {
+ startPos = visiblePos2;
+ endPos = visiblePos1;
+ }
+
+ return VisiblePositionRange(startPos, endPos);
+}
+
+VisiblePositionRange AccessibilityObject::positionOfLeftWord(const VisiblePosition& visiblePos) const
+{
+ VisiblePosition startPosition = startOfWord(visiblePos, LeftWordIfOnBoundary);
+ VisiblePosition endPosition = endOfWord(startPosition);
+ return VisiblePositionRange(startPosition, endPosition);
+}
+
+VisiblePositionRange AccessibilityObject::positionOfRightWord(const VisiblePosition& visiblePos) const
+{
+ VisiblePosition startPosition = startOfWord(visiblePos, RightWordIfOnBoundary);
+ VisiblePosition endPosition = endOfWord(startPosition);
+ return VisiblePositionRange(startPosition, endPosition);
+}
+
+static VisiblePosition updateAXLineStartForVisiblePosition(const VisiblePosition& visiblePosition)
+{
+ // A line in the accessibility sense should include floating objects, such as aligned image, as part of a line.
+ // So let's update the position to include that.
+ VisiblePosition tempPosition;
+ VisiblePosition startPosition = visiblePosition;
+ Position p;
+ RenderObject* renderer;
+ while (true) {
+ tempPosition = startPosition.previous();
+ if (tempPosition.isNull())
+ break;
+ p = tempPosition.deepEquivalent();
+ if (!p.node())
+ break;
+ renderer = p.node()->renderer();
+ if (!renderer || renderer->isRenderBlock() && !p.offset())
+ break;
+ InlineBox* box;
+ int ignoredCaretOffset;
+ p.getInlineBoxAndOffset(tempPosition.affinity(), box, ignoredCaretOffset);
+ if (box)
+ break;
+ startPosition = tempPosition;
+ }
+
+ return startPosition;
+}
+
+VisiblePositionRange AccessibilityObject::leftLineVisiblePositionRange(const VisiblePosition& visiblePos) const
+{
+ if (visiblePos.isNull())
+ return VisiblePositionRange();
+
+ // make a caret selection for the position before marker position (to make sure
+ // we move off of a line start)
+ VisiblePosition prevVisiblePos = visiblePos.previous();
+ if (prevVisiblePos.isNull())
+ return VisiblePositionRange();
+
+ VisiblePosition startPosition = startOfLine(prevVisiblePos);
+
+ // keep searching for a valid line start position. Unless the VisiblePosition is at the very beginning, there should
+ // always be a valid line range. However, startOfLine will return null for position next to a floating object,
+ // since floating object doesn't really belong to any line.
+ // This check will reposition the marker before the floating object, to ensure we get a line start.
+ if (startPosition.isNull()) {
+ while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
+ prevVisiblePos = prevVisiblePos.previous();
+ startPosition = startOfLine(prevVisiblePos);
+ }
+ } else
+ startPosition = updateAXLineStartForVisiblePosition(startPosition);
+
+ VisiblePosition endPosition = endOfLine(prevVisiblePos);
+ return VisiblePositionRange(startPosition, endPosition);
+}
+
+VisiblePositionRange AccessibilityObject::rightLineVisiblePositionRange(const VisiblePosition& visiblePos) const
+{
+ if (visiblePos.isNull())
+ return VisiblePositionRange();
+
+ // make sure we move off of a line end
+ VisiblePosition nextVisiblePos = visiblePos.next();
+ if (nextVisiblePos.isNull())
+ return VisiblePositionRange();
+
+ VisiblePosition startPosition = startOfLine(nextVisiblePos);
+
+ // fetch for a valid line start position
+ if (startPosition.isNull() ) {
+ startPosition = visiblePos;
+ nextVisiblePos = nextVisiblePos.next();
+ } else
+ startPosition = updateAXLineStartForVisiblePosition(startPosition);
+
+ VisiblePosition endPosition = endOfLine(nextVisiblePos);
+
+ // as long as the position hasn't reached the end of the doc, keep searching for a valid line end position
+ // Unless the VisiblePosition is at the very end, there should always be a valid line range. However, endOfLine will
+ // return null for position by a floating object, since floating object doesn't really belong to any line.
+ // This check will reposition the marker after the floating object, to ensure we get a line end.
+ while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
+ nextVisiblePos = nextVisiblePos.next();
+ endPosition = endOfLine(nextVisiblePos);
+ }
+
+ return VisiblePositionRange(startPosition, endPosition);
+}
+
+VisiblePositionRange AccessibilityObject::sentenceForPosition(const VisiblePosition& visiblePos) const
+{
+ // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
+ // Related? <rdar://problem/3927736> Text selection broken in 8A336
+ VisiblePosition startPosition = startOfSentence(visiblePos);
+ VisiblePosition endPosition = endOfSentence(startPosition);
+ return VisiblePositionRange(startPosition, endPosition);
+}
+
+VisiblePositionRange AccessibilityObject::paragraphForPosition(const VisiblePosition& visiblePos) const
+{
+ VisiblePosition startPosition = startOfParagraph(visiblePos);
+ VisiblePosition endPosition = endOfParagraph(startPosition);
+ return VisiblePositionRange(startPosition, endPosition);
+}
+
+static VisiblePosition startOfStyleRange(const VisiblePosition visiblePos)
+{
+ RenderObject* renderer = visiblePos.deepEquivalent().node()->renderer();
+ RenderObject* startRenderer = renderer;
+ RenderStyle* style = renderer->style();
+
+ // traverse backward by renderer to look for style change
+ for (RenderObject* r = renderer->previousInPreOrder(); r; r = r->previousInPreOrder()) {
+ // skip non-leaf nodes
+ if (r->firstChild())
+ continue;
+
+ // stop at style change
+ if (r->style() != style)
+ break;
+
+ // remember match
+ startRenderer = r;
+ }
+
+ return VisiblePosition(startRenderer->node(), 0, VP_DEFAULT_AFFINITY);
+}
+
+static VisiblePosition endOfStyleRange(const VisiblePosition visiblePos)
+{
+ RenderObject* renderer = visiblePos.deepEquivalent().node()->renderer();
+ RenderObject* endRenderer = renderer;
+ RenderStyle* style = renderer->style();
+
+ // traverse forward by renderer to look for style change
+ for (RenderObject* r = renderer->nextInPreOrder(); r; r = r->nextInPreOrder()) {
+ // skip non-leaf nodes
+ if (r->firstChild())
+ continue;
+
+ // stop at style change
+ if (r->style() != style)
+ break;
+
+ // remember match
+ endRenderer = r;
+ }
+
+ return VisiblePosition(endRenderer->node(), maxDeepOffset(endRenderer->node()), VP_DEFAULT_AFFINITY);
+}
+
+VisiblePositionRange AccessibilityObject::styleRangeForPosition(const VisiblePosition& visiblePos) const
+{
+ if (visiblePos.isNull())
+ return VisiblePositionRange();
+
+ return VisiblePositionRange(startOfStyleRange(visiblePos), endOfStyleRange(visiblePos));
+}
+
+// NOTE: Consider providing this utility method as AX API
+VisiblePositionRange AccessibilityObject::visiblePositionRangeForRange(const PlainTextRange& range) const
+{
+ if (range.start + range.length > text().length())
+ return VisiblePositionRange();
+
+ VisiblePosition startPosition = visiblePositionForIndex(range.start);
+ startPosition.setAffinity(DOWNSTREAM);
+ VisiblePosition endPosition = visiblePositionForIndex(range.start + range.length);
+ return VisiblePositionRange(startPosition, endPosition);
+}
+
+static bool replacedNodeNeedsCharacter(Node* replacedNode)
+{
+ // we should always be given a rendered node and a replaced node, but be safe
+ // replaced nodes are either attachments (widgets) or images
+ if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) {
+ return false;
+ }
+
+ // create an AX object, but skip it if it is not supposed to be seen
+ AccessibilityObject* object = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer());
+ if (object->accessibilityIsIgnored())
+ return false;
+
+ return true;
+}
+
+String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
+{
+ if (visiblePositionRange.isNull())
+ return String();
+
+ Vector<UChar> resultVector;
+ RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
+ for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
+ // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
+ if (it.length() != 0) {
+ resultVector.append(it.characters(), it.length());
+ } else {
+ // locate the node and starting offset for this replaced range
+ int exception = 0;
+ Node* node = it.range()->startContainer(exception);
+ ASSERT(node == it.range()->endContainer(exception));
+ int offset = it.range()->startOffset(exception);
+
+ if (replacedNodeNeedsCharacter(node->childNode(offset))) {
+ resultVector.append(objectReplacementCharacter);
+ }
+ }
+ }
+
+ return String::adopt(resultVector);
+}
+
+IntRect AccessibilityObject::boundsForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
+{
+ return IntRect();
+}
+
+int AccessibilityObject::lengthForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
+{
+ // FIXME: Multi-byte support
+ if (visiblePositionRange.isNull())
+ return -1;
+
+ int length = 0;
+ RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end);
+ for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
+ // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
+ if (it.length() != 0) {
+ length += it.length();
+ } else {
+ // locate the node and starting offset for this replaced range
+ int exception = 0;
+ Node* node = it.range()->startContainer(exception);
+ ASSERT(node == it.range()->endContainer(exception));
+ int offset = it.range()->startOffset(exception);
+
+ if (replacedNodeNeedsCharacter(node->childNode(offset)))
+ length++;
+ }
+ }
+
+ return length;
+}
+
+void AccessibilityObject::setSelectedVisiblePositionRange(const VisiblePositionRange&) const
+{
+}
+
+VisiblePosition AccessibilityObject::visiblePositionForPoint(const IntPoint& point) const
+{
+ return VisiblePosition();
+}
+
+VisiblePosition AccessibilityObject::nextVisiblePosition(const VisiblePosition& visiblePos) const
+{
+ return visiblePos.next();
+}
+
+VisiblePosition AccessibilityObject::previousVisiblePosition(const VisiblePosition& visiblePos) const
+{
+ return visiblePos.previous();
+}
+
+VisiblePosition AccessibilityObject::nextWordEnd(const VisiblePosition& visiblePos) const
+{
+ if (visiblePos.isNull())
+ return VisiblePosition();
+
+ // make sure we move off of a word end
+ VisiblePosition nextVisiblePos = visiblePos.next();
+ if (nextVisiblePos.isNull())
+ return VisiblePosition();
+
+ return endOfWord(nextVisiblePos, LeftWordIfOnBoundary);
+}
+
+VisiblePosition AccessibilityObject::previousWordStart(const VisiblePosition& visiblePos) const
+{
+ if (visiblePos.isNull())
+ return VisiblePosition();
+
+ // make sure we move off of a word start
+ VisiblePosition prevVisiblePos = visiblePos.previous();
+ if (prevVisiblePos.isNull())
+ return VisiblePosition();
+
+ return startOfWord(prevVisiblePos, RightWordIfOnBoundary);
+}
+
+VisiblePosition AccessibilityObject::nextLineEndPosition(const VisiblePosition& visiblePos) const
+{
+ if (visiblePos.isNull())
+ return VisiblePosition();
+
+ // to make sure we move off of a line end
+ VisiblePosition nextVisiblePos = visiblePos.next();
+ if (nextVisiblePos.isNull())
+ return VisiblePosition();
+
+ VisiblePosition endPosition = endOfLine(nextVisiblePos);
+
+ // as long as the position hasn't reached the end of the doc, keep searching for a valid line end position
+ // There are cases like when the position is next to a floating object that'll return null for end of line. This code will avoid returning null.
+ while (endPosition.isNull() && nextVisiblePos.isNotNull()) {
+ nextVisiblePos = nextVisiblePos.next();
+ endPosition = endOfLine(nextVisiblePos);
+ }
+
+ return endPosition;
+}
+
+VisiblePosition AccessibilityObject::previousLineStartPosition(const VisiblePosition& visiblePos) const
+{
+ if (visiblePos.isNull())
+ return VisiblePosition();
+
+ // make sure we move off of a line start
+ VisiblePosition prevVisiblePos = visiblePos.previous();
+ if (prevVisiblePos.isNull())
+ return VisiblePosition();
+
+ VisiblePosition startPosition = startOfLine(prevVisiblePos);
+
+ // as long as the position hasn't reached the beginning of the doc, keep searching for a valid line start position
+ // There are cases like when the position is next to a floating object that'll return null for start of line. This code will avoid returning null.
+ if (startPosition.isNull()) {
+ while (startPosition.isNull() && prevVisiblePos.isNotNull()) {
+ prevVisiblePos = prevVisiblePos.previous();
+ startPosition = startOfLine(prevVisiblePos);
+ }
+ } else
+ startPosition = updateAXLineStartForVisiblePosition(startPosition);
+
+ return startPosition;
+}
+
+VisiblePosition AccessibilityObject::nextSentenceEndPosition(const VisiblePosition& visiblePos) const
+{
+ // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
+ // Related? <rdar://problem/3927736> Text selection broken in 8A336
+ if (visiblePos.isNull())
+ return VisiblePosition();
+
+ // make sure we move off of a sentence end
+ VisiblePosition nextVisiblePos = visiblePos.next();
+ if (nextVisiblePos.isNull())
+ return VisiblePosition();
+
+ // an empty line is considered a sentence. If it's skipped, then the sentence parser will not
+ // see this empty line. Instead, return the end position of the empty line.
+ VisiblePosition endPosition;
+ String lineString = plainText(makeRange(startOfLine(visiblePos), endOfLine(visiblePos)).get());
+ if (lineString.isEmpty())
+ endPosition = nextVisiblePos;
+ else
+ endPosition = endOfSentence(nextVisiblePos);
+
+ return endPosition;
+}
+
+VisiblePosition AccessibilityObject::previousSentenceStartPosition(const VisiblePosition& visiblePos) const
+{
+ // FIXME: FO 2 IMPLEMENT (currently returns incorrect answer)
+ // Related? <rdar://problem/3927736> Text selection broken in 8A336
+ if (visiblePos.isNull())
+ return VisiblePosition();
+
+ // make sure we move off of a sentence start
+ VisiblePosition previousVisiblePos = visiblePos.previous();
+ if (previousVisiblePos.isNull())
+ return VisiblePosition();
+
+ // treat empty line as a separate sentence.
+ VisiblePosition startPosition;
+ String lineString = plainText(makeRange(startOfLine(previousVisiblePos), endOfLine(previousVisiblePos)).get());
+ if (lineString.isEmpty())
+ startPosition = previousVisiblePos;
+ else
+ startPosition = startOfSentence(previousVisiblePos);
+
+ return startPosition;
+}
+
+VisiblePosition AccessibilityObject::nextParagraphEndPosition(const VisiblePosition& visiblePos) const
+{
+ if (visiblePos.isNull())
+ return VisiblePosition();
+
+ // make sure we move off of a paragraph end
+ VisiblePosition nextPos = visiblePos.next();
+ if (nextPos.isNull())
+ return VisiblePosition();
+
+ return endOfParagraph(nextPos);
+}
+
+VisiblePosition AccessibilityObject::previousParagraphStartPosition(const VisiblePosition& visiblePos) const
+{
+ if (visiblePos.isNull())
+ return VisiblePosition();
+
+ // make sure we move off of a paragraph start
+ VisiblePosition previousPos = visiblePos.previous();
+ if (previousPos.isNull())
+ return VisiblePosition();
+
+ return startOfParagraph(previousPos);
+}
+
+// NOTE: Consider providing this utility method as AX API
+VisiblePosition AccessibilityObject::visiblePositionForIndex(unsigned indexValue, bool lastIndexOK) const
+{
+ return VisiblePosition();
+}
+
+AccessibilityObject* AccessibilityObject::accessibilityObjectForPosition(const VisiblePosition& visiblePos) const
+{
+ if (visiblePos.isNull())
+ return 0;
+
+ RenderObject* obj = visiblePos.deepEquivalent().node()->renderer();
+ if (!obj)
+ return 0;
+
+ return obj->document()->axObjectCache()->get(obj);
+}
+
+int AccessibilityObject::lineForPosition(const VisiblePosition& visiblePos) const
+{
+ if (visiblePos.isNull())
+ return 0;
+
+ unsigned lineCount = 0;
+ VisiblePosition currentVisiblePos = visiblePos;
+ VisiblePosition savedVisiblePos;
+
+ // move up until we get to the top
+ // FIXME: This only takes us to the top of the rootEditableElement, not the top of the
+ // top document.
+ while (currentVisiblePos.isNotNull() && !(inSameLine(currentVisiblePos, savedVisiblePos))) {
+ ++lineCount;
+ savedVisiblePos = currentVisiblePos;
+ VisiblePosition prevVisiblePos = previousLinePosition(currentVisiblePos, 0);
+ currentVisiblePos = prevVisiblePos;
+ }
+
+ return lineCount - 1;
+}
+
+// NOTE: Consider providing this utility method as AX API
+PlainTextRange AccessibilityObject::plainTextRangeForVisiblePositionRange(const VisiblePositionRange& positionRange) const
+{
+ int index1 = index(positionRange.start);
+ int index2 = index(positionRange.end);
+ if (index1 < 0 || index2 < 0 || index1 > index2)
+ return PlainTextRange();
+
+ return PlainTextRange(index1, index2 - index1);
+}
+
+// NOTE: Consider providing this utility method as AX API
+int AccessibilityObject::index(const VisiblePosition& position) const
+{
+ return -1;
+}
+
+// Given a line number, the range of characters of the text associated with this accessibility
+// object that contains the line number.
+PlainTextRange AccessibilityObject::doAXRangeForLine(unsigned lineNumber) const
+{
+ return PlainTextRange();
+}
+
+// The composed character range in the text associated with this accessibility object that
+// is specified by the given screen coordinates. This parameterized attribute returns the
+// complete range of characters (including surrogate pairs of multi-byte glyphs) at the given
+// screen coordinates.
+// NOTE: This varies from AppKit when the point is below the last line. AppKit returns an
+// an error in that case. We return textControl->text().length(), 1. Does this matter?
+PlainTextRange AccessibilityObject::doAXRangeForPosition(const IntPoint& point) const
+{
+ int i = index(visiblePositionForPoint(point));
+ if (i < 0)
+ return PlainTextRange();
+
+ return PlainTextRange(i, 1);
+}
+
+// The composed character range in the text associated with this accessibility object that
+// is specified by the given index value. This parameterized attribute returns the complete
+// range of characters (including surrogate pairs of multi-byte glyphs) at the given index.
+PlainTextRange AccessibilityObject::doAXRangeForIndex(unsigned index) const
+{
+ return PlainTextRange();
+}
+
+// Given a character index, the range of text associated with this accessibility object
+// over which the style in effect at that character index applies.
+PlainTextRange AccessibilityObject::doAXStyleRangeForIndex(unsigned index) const
+{
+ VisiblePositionRange range = styleRangeForPosition(visiblePositionForIndex(index, false));
+ return plainTextRangeForVisiblePositionRange(range);
+}
+
+// A substring of the text associated with this accessibility object that is
+// specified by the given character range.
+String AccessibilityObject::doAXStringForRange(const PlainTextRange& range) const
+{
+ return String();
+}
+
+// The bounding rectangle of the text associated with this accessibility object that is
+// specified by the given range. This is the bounding rectangle a sighted user would see
+// on the display screen, in pixels.
+IntRect AccessibilityObject::doAXBoundsForRange(const PlainTextRange& range) const
+{
+ return IntRect();
+}
+
+// Given an indexed character, the line number of the text associated with this accessibility
+// object that contains the character.
+unsigned AccessibilityObject::doAXLineForIndex(unsigned index)
+{
+ return lineForPosition(visiblePositionForIndex(index, false));
+}
+
+FrameView* AccessibilityObject::documentFrameView() const
+{
+ const AccessibilityObject* object = this;
+ while (object && !object->isAccessibilityRenderObject())
+ object = object->parentObject();
+
+ if (!object)
+ return 0;
+
+ return object->documentFrameView();
+}
+
+AccessibilityObject* AccessibilityObject::doAccessibilityHitTest(const IntPoint& point) const
+{
+ return 0;
+}
+
+AccessibilityObject* AccessibilityObject::focusedUIElement() const
+{
+ return 0;
+}
+
+AccessibilityObject* AccessibilityObject::observableObject() const
+{
+ return 0;
+}
+
+AccessibilityRole AccessibilityObject::roleValue() const
+{
+ return UnknownRole;
+}
+
+AccessibilityRole AccessibilityObject::ariaRoleAttribute() const
+{
+ return UnknownRole;
+}
+
+bool AccessibilityObject::isPresentationalChildOfAriaRole() const
+{
+ return false;
+}
+
+bool AccessibilityObject::ariaRoleHasPresentationalChildren() const
+{
+ return false;
+}
+
+void AccessibilityObject::clearChildren()
+{
+ m_haveChildren = false;
+ m_children.clear();
+}
+
+void AccessibilityObject::childrenChanged()
+{
+ return;
+}
+
+void AccessibilityObject::addChildren()
+{
+}
+
+void AccessibilityObject::selectedChildren(AccessibilityChildrenVector&)
+{
+}
+
+void AccessibilityObject::visibleChildren(AccessibilityChildrenVector&)
+{
+}
+
+unsigned AccessibilityObject::axObjectID() const
+{
+ return m_id;
+}
+
+void AccessibilityObject::setAXObjectID(unsigned axObjectID)
+{
+ m_id = axObjectID;
+}
+
+void AccessibilityObject::removeAXObjectID()
+{
+ return;
+}
+
+const String& AccessibilityObject::actionVerb() const
+{
+ // FIXME: Need to add verbs for select elements.
+ static const String buttonAction = AXButtonActionVerb();
+ static const String textFieldAction = AXTextFieldActionVerb();
+ static const String radioButtonAction = AXRadioButtonActionVerb();
+ static const String checkedCheckBoxAction = AXCheckedCheckBoxActionVerb();
+ static const String uncheckedCheckBoxAction = AXUncheckedCheckBoxActionVerb();
+ static const String linkAction = AXLinkActionVerb();
+ static const String noAction;
+
+ switch (roleValue()) {
+ case ButtonRole:
+ return buttonAction;
+ case TextFieldRole:
+ case TextAreaRole:
+ return textFieldAction;
+ case RadioButtonRole:
+ return radioButtonAction;
+ case CheckBoxRole:
+ return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
+ case LinkRole:
+ case WebCoreLinkRole:
+ return linkAction;
+ default:
+ return noAction;
+ }
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/AccessibilityObject.h b/WebCore/page/AccessibilityObject.h
new file mode 100644
index 0000000..947757a
--- /dev/null
+++ b/WebCore/page/AccessibilityObject.h
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2008 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.
+ * 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 AccessibilityObject_h
+#define AccessibilityObject_h
+
+#include "VisiblePosition.h"
+#include <wtf/Platform.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(MAC)
+#include <wtf/RetainPtr.h>
+#elif PLATFORM(WIN)
+#include "AccessibilityObjectWrapperWin.h"
+#include "COMPtr.h"
+#elif PLATFORM(CHROMIUM)
+#include "AccessibilityObjectWrapper.h"
+#endif
+
+typedef struct _NSRange NSRange;
+
+#ifdef __OBJC__
+@class AccessibilityObjectWrapper;
+@class NSArray;
+@class NSAttributedString;
+@class NSData;
+@class NSMutableAttributedString;
+@class NSString;
+@class NSValue;
+@class NSView;
+#else
+class NSArray;
+class NSAttributedString;
+class NSData;
+class NSMutableAttributedString;
+class NSString;
+class NSValue;
+class NSView;
+#if PLATFORM(GTK)
+typedef struct _AtkObject AtkObject;
+typedef struct _AtkObject AccessibilityObjectWrapper;
+#else
+class AccessibilityObjectWrapper;
+#endif
+#endif
+
+namespace WebCore {
+
+class AXObjectCache;
+class Element;
+class Frame;
+class FrameView;
+class HTMLAnchorElement;
+class HTMLAreaElement;
+class IntPoint;
+class IntSize;
+class Node;
+class RenderObject;
+class Selection;
+class String;
+class Widget;
+
+enum AccessibilityRole {
+ UnknownRole = 1,
+ ButtonRole,
+ RadioButtonRole,
+ CheckBoxRole,
+ SliderRole,
+ TabGroupRole,
+ TextFieldRole,
+ StaticTextRole,
+ TextAreaRole,
+ ScrollAreaRole,
+ PopUpButtonRole,
+ MenuButtonRole,
+ TableRole,
+ ApplicationRole,
+ GroupRole,
+ RadioGroupRole,
+ ListRole,
+ ScrollBarRole,
+ ValueIndicatorRole,
+ ImageRole,
+ MenuBarRole,
+ MenuRole,
+ MenuItemRole,
+ ColumnRole,
+ RowRole,
+ ToolbarRole,
+ BusyIndicatorRole,
+ ProgressIndicatorRole,
+ WindowRole,
+ DrawerRole,
+ SystemWideRole,
+ OutlineRole,
+ IncrementorRole,
+ BrowserRole,
+ ComboBoxRole,
+ SplitGroupRole,
+ SplitterRole,
+ ColorWellRole,
+ GrowAreaRole,
+ SheetRole,
+ HelpTagRole,
+ MatteRole,
+ RulerRole,
+ RulerMarkerRole,
+ LinkRole,
+ DisclosureTriangleRole,
+ GridRole,
+ CellRole,
+ // AppKit includes SortButtonRole but it is misnamed and really a subrole of ButtonRole so we do not include it here.
+
+ // WebCore-specific roles
+ WebCoreLinkRole,
+ ImageMapLinkRole,
+ ImageMapRole,
+ ListMarkerRole,
+ WebAreaRole,
+ HeadingRole,
+ ListBoxRole,
+ ListBoxOptionRole,
+ TableHeaderContainerRole,
+ DefinitionListTermRole,
+ DefinitionListDefinitionRole
+};
+
+struct VisiblePositionRange {
+
+ VisiblePosition start;
+ VisiblePosition end;
+
+ VisiblePositionRange() {}
+
+ VisiblePositionRange(const VisiblePosition& s, const VisiblePosition& e)
+ : start(s)
+ , end(e)
+ { }
+
+ bool isNull() const { return start.isNull() || end.isNull(); }
+};
+
+struct PlainTextRange {
+
+ unsigned start;
+ unsigned length;
+
+ PlainTextRange()
+ : start(0)
+ , length(0)
+ { }
+
+ PlainTextRange(unsigned s, unsigned l)
+ : start(s)
+ , length(l)
+ { }
+
+ bool isNull() const { return start == 0 && length == 0; }
+};
+
+class AccessibilityObject : public RefCounted<AccessibilityObject> {
+protected:
+ AccessibilityObject();
+public:
+ virtual ~AccessibilityObject();
+
+ typedef Vector<RefPtr<AccessibilityObject> > AccessibilityChildrenVector;
+
+ virtual bool isAccessibilityRenderObject() const { return false; };
+ virtual bool isAnchor() const { return false; };
+ virtual bool isAttachment() const { return false; };
+ virtual bool isHeading() const { return false; };
+ virtual bool isLink() const { return false; };
+ virtual bool isImage() const { return false; };
+ virtual bool isNativeImage() const { return false; };
+ virtual bool isImageButton() const { return false; };
+ virtual bool isPasswordField() const { return false; };
+ virtual bool isTextControl() const { return false; };
+ virtual bool isNativeTextControl() const { return false; };
+ virtual bool isWebArea() const { return false; };
+ virtual bool isCheckboxOrRadio() const { return false; };
+ virtual bool isListBox() const { return roleValue() == ListBoxRole; };
+ virtual bool isMenuRelated() const { return false; }
+ virtual bool isMenu() const { return false; }
+ virtual bool isMenuBar() const { return false; }
+ virtual bool isMenuButton() const { return false; }
+ virtual bool isMenuItem() const { return false; }
+ virtual bool isFileUploadButton() const { return false; };
+ virtual bool isProgressIndicator() const { return false; };
+ virtual bool isSlider() const { return false; };
+ virtual bool isControl() const { return false; };
+ virtual bool isList() const { return false; };
+ virtual bool isDataTable() const { return false; };
+ virtual bool isTableRow() const { return false; };
+ virtual bool isTableColumn() const { return false; };
+ virtual bool isTableCell() const { return false; };
+ virtual bool isFieldset() const { return false; };
+
+ virtual bool isChecked() const { return false; };
+ virtual bool isEnabled() const { return false; };
+ virtual bool isSelected() const { return false; };
+ virtual bool isFocused() const { return false; };
+ virtual bool isHovered() const { return false; };
+ virtual bool isIndeterminate() const { return false; };
+ virtual bool isLoaded() const { return false; };
+ virtual bool isMultiSelect() const { return false; };
+ virtual bool isOffScreen() const { return false; };
+ virtual bool isPressed() const { return false; };
+ virtual bool isReadOnly() const { return false; };
+ virtual bool isVisited() const { return false; };
+
+ virtual bool canSetFocusAttribute() const { return false; };
+ virtual bool canSetTextRangeAttributes() const { return false; };
+ virtual bool canSetValueAttribute() const { return false; };
+ virtual bool canSetSelectedAttribute() const { return false; }
+ virtual bool canSetSelectedChildrenAttribute() const { return false; }
+
+ virtual bool hasIntValue() const { return false; };
+
+ bool accessibilityShouldUseUniqueId() const { return true; };
+ virtual bool accessibilityIsIgnored() const { return true; };
+
+ virtual int intValue() const;
+ virtual float valueForRange() const { return 0.0f; }
+ virtual float maxValueForRange() const { return 0.0f; }
+ virtual float minValueForRange() const {return 0.0f; }
+ virtual int layoutCount() const;
+ static bool isARIAControl(AccessibilityRole);
+ static bool isARIAInput(AccessibilityRole);
+ unsigned axObjectID() const;
+
+ virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&) const;
+ virtual AccessibilityObject* focusedUIElement() const;
+ virtual AccessibilityObject* firstChild() const;
+ virtual AccessibilityObject* lastChild() const;
+ virtual AccessibilityObject* previousSibling() const;
+ virtual AccessibilityObject* nextSibling() const;
+ virtual AccessibilityObject* parentObject() const;
+ virtual AccessibilityObject* parentObjectUnignored() const;
+ virtual AccessibilityObject* observableObject() const;
+ virtual void linkedUIElements(AccessibilityChildrenVector&) const;
+ virtual AccessibilityObject* titleUIElement() const;
+ virtual AccessibilityRole ariaRoleAttribute() const;
+ virtual bool isPresentationalChildOfAriaRole() const;
+ virtual bool ariaRoleHasPresentationalChildren() const;
+
+ virtual AccessibilityRole roleValue() const;
+ virtual AXObjectCache* axObjectCache() const;
+
+ virtual Element* anchorElement() const;
+ virtual Element* actionElement() const;
+ virtual IntRect boundingBoxRect() const;
+ virtual IntRect elementRect() const;
+ virtual IntSize size() const;
+ IntPoint clickPoint() const;
+
+ virtual KURL url() const;
+ virtual PlainTextRange selectedTextRange() const;
+ virtual Selection selection() const;
+ unsigned selectionStart() const;
+ unsigned selectionEnd() const;
+ virtual String stringValue() const;
+ virtual String ariaAccessiblityName(const String&) const;
+ virtual String ariaLabeledByAttribute() const;
+ virtual String title() const;
+ virtual String ariaDescribedByAttribute() const;
+ virtual String accessibilityDescription() const;
+ virtual String helpText() const;
+ virtual String textUnderElement() const;
+ virtual String text() const;
+ virtual int textLength() const;
+ virtual PassRefPtr<Range> ariaSelectedTextDOMRange() const;
+ virtual String selectedText() const;
+ virtual const AtomicString& accessKey() const;
+ const String& actionVerb() const;
+ virtual Widget* widget() const;
+ virtual Widget* widgetForAttachmentView() const;
+ virtual Document* document() const { return 0; }
+ virtual FrameView* topDocumentFrameView() const { return 0; }
+ virtual FrameView* documentFrameView() const;
+
+ void setAXObjectID(unsigned);
+ virtual void setFocused(bool);
+ virtual void setSelectedText(const String&);
+ virtual void setSelectedTextRange(const PlainTextRange&);
+ virtual void setValue(const String&);
+ virtual void setSelected(bool);
+
+ virtual void detach();
+ virtual void makeRangeVisible(const PlainTextRange&);
+ virtual bool press() const;
+ bool performDefaultAction() const { return press(); }
+
+ virtual void childrenChanged();
+ virtual const AccessibilityChildrenVector& children() { return m_children; }
+ virtual void addChildren();
+ virtual bool canHaveChildren() const { return true; }
+ virtual bool hasChildren() const { return m_haveChildren; };
+ virtual void selectedChildren(AccessibilityChildrenVector&);
+ virtual void visibleChildren(AccessibilityChildrenVector&);
+ virtual bool shouldFocusActiveDescendant() const { return false; }
+ virtual AccessibilityObject* activeDescendant() const { return 0; }
+ virtual void handleActiveDescendantChanged() { }
+
+ virtual VisiblePositionRange visiblePositionRange() const;
+ virtual VisiblePositionRange visiblePositionRangeForLine(unsigned) const;
+
+ VisiblePositionRange visiblePositionRangeForUnorderedPositions(const VisiblePosition&, const VisiblePosition&) const;
+ VisiblePositionRange positionOfLeftWord(const VisiblePosition&) const;
+ VisiblePositionRange positionOfRightWord(const VisiblePosition&) const;
+ VisiblePositionRange leftLineVisiblePositionRange(const VisiblePosition&) const;
+ VisiblePositionRange rightLineVisiblePositionRange(const VisiblePosition&) const;
+ VisiblePositionRange sentenceForPosition(const VisiblePosition&) const;
+ VisiblePositionRange paragraphForPosition(const VisiblePosition&) const;
+ VisiblePositionRange styleRangeForPosition(const VisiblePosition&) const;
+ VisiblePositionRange visiblePositionRangeForRange(const PlainTextRange&) const;
+
+ String stringForVisiblePositionRange(const VisiblePositionRange&) const;
+ virtual IntRect boundsForVisiblePositionRange(const VisiblePositionRange&) const;
+ int lengthForVisiblePositionRange(const VisiblePositionRange&) const;
+ virtual void setSelectedVisiblePositionRange(const VisiblePositionRange&) const;
+
+ virtual VisiblePosition visiblePositionForPoint(const IntPoint&) const;
+ VisiblePosition nextVisiblePosition(const VisiblePosition&) const;
+ VisiblePosition previousVisiblePosition(const VisiblePosition&) const;
+ VisiblePosition nextWordEnd(const VisiblePosition&) const;
+ VisiblePosition previousWordStart(const VisiblePosition&) const;
+ VisiblePosition nextLineEndPosition(const VisiblePosition&) const;
+ VisiblePosition previousLineStartPosition(const VisiblePosition&) const;
+ VisiblePosition nextSentenceEndPosition(const VisiblePosition&) const;
+ VisiblePosition previousSentenceStartPosition(const VisiblePosition&) const;
+ VisiblePosition nextParagraphEndPosition(const VisiblePosition&) const;
+ VisiblePosition previousParagraphStartPosition(const VisiblePosition&) const;
+ virtual VisiblePosition visiblePositionForIndex(unsigned indexValue, bool lastIndexOK) const;
+
+ virtual VisiblePosition visiblePositionForIndex(int) const;
+ virtual int indexForVisiblePosition(const VisiblePosition&) const;
+
+ AccessibilityObject* accessibilityObjectForPosition(const VisiblePosition&) const;
+ int lineForPosition(const VisiblePosition&) const;
+ PlainTextRange plainTextRangeForVisiblePositionRange(const VisiblePositionRange&) const;
+ virtual int index(const VisiblePosition&) const;
+
+ virtual PlainTextRange doAXRangeForLine(unsigned) const;
+ PlainTextRange doAXRangeForPosition(const IntPoint&) const;
+ virtual PlainTextRange doAXRangeForIndex(unsigned) const;
+ PlainTextRange doAXStyleRangeForIndex(unsigned) const;
+
+ virtual String doAXStringForRange(const PlainTextRange&) const;
+ virtual IntRect doAXBoundsForRange(const PlainTextRange&) const;
+
+ unsigned doAXLineForIndex(unsigned);
+
+#if HAVE(ACCESSIBILITY)
+#if PLATFORM(GTK)
+ AccessibilityObjectWrapper* wrapper() const;
+ void setWrapper(AccessibilityObjectWrapper*);
+#else
+ AccessibilityObjectWrapper* wrapper() const { return m_wrapper.get(); }
+ void setWrapper(AccessibilityObjectWrapper* wrapper)
+ {
+ m_wrapper = wrapper;
+ }
+#endif
+#endif
+
+ // a platform-specific method for determining if an attachment is ignored
+ bool accessibilityIgnoreAttachment() const;
+
+protected:
+ unsigned m_id;
+ AccessibilityChildrenVector m_children;
+ mutable bool m_haveChildren;
+
+ virtual void clearChildren();
+ virtual void removeAXObjectID();
+ virtual bool isDetached() const { return true; }
+
+#if PLATFORM(MAC)
+ RetainPtr<AccessibilityObjectWrapper> m_wrapper;
+#elif PLATFORM(WIN)
+ COMPtr<AccessibilityObjectWrapper> m_wrapper;
+#elif PLATFORM(GTK)
+ AtkObject* m_wrapper;
+#elif PLATFORM(CHROMIUM)
+ RefPtr<AccessibilityObjectWrapper> m_wrapper;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // AccessibilityObject_h
diff --git a/WebCore/page/AccessibilityRenderObject.cpp b/WebCore/page/AccessibilityRenderObject.cpp
new file mode 100644
index 0000000..144aab0
--- /dev/null
+++ b/WebCore/page/AccessibilityRenderObject.cpp
@@ -0,0 +1,2378 @@
+/*
+* 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 "AccessibilityRenderObject.h"
+
+#include "AXObjectCache.h"
+#include "AccessibilityListBox.h"
+#include "AccessibilityImageMapLink.h"
+#include "CharacterNames.h"
+#include "EventNames.h"
+#include "FloatRect.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "HTMLAreaElement.h"
+#include "HTMLFrameElementBase.h"
+#include "HTMLImageElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLLabelElement.h"
+#include "HTMLMapElement.h"
+#include "HTMLOptGroupElement.h"
+#include "HTMLOptionElement.h"
+#include "HTMLOptionsCollection.h"
+#include "HTMLSelectElement.h"
+#include "HTMLTextAreaElement.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "LocalizedStrings.h"
+#include "NodeList.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "RenderFieldset.h"
+#include "RenderFileUploadControl.h"
+#include "RenderImage.h"
+#include "RenderListBox.h"
+#include "RenderListMarker.h"
+#include "RenderMenuList.h"
+#include "RenderTextControl.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include "RenderWidget.h"
+#include "SelectionController.h"
+#include "Text.h"
+#include "TextIterator.h"
+#include "htmlediting.h"
+#include "visible_units.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+AccessibilityRenderObject::AccessibilityRenderObject(RenderObject* renderer)
+ : m_renderer(renderer)
+ , m_ariaRole(UnknownRole)
+{
+ setAriaRole();
+#ifndef NDEBUG
+ m_renderer->setHasAXObject(true);
+#endif
+}
+
+AccessibilityRenderObject::~AccessibilityRenderObject()
+{
+ ASSERT(isDetached());
+}
+
+PassRefPtr<AccessibilityRenderObject> AccessibilityRenderObject::create(RenderObject* renderer)
+{
+ return adoptRef(new AccessibilityRenderObject(renderer));
+}
+
+void AccessibilityRenderObject::detach()
+{
+ clearChildren();
+ AccessibilityObject::detach();
+
+#ifndef NDEBUG
+ if (m_renderer)
+ m_renderer->setHasAXObject(false);
+#endif
+ m_renderer = 0;
+}
+
+AccessibilityObject* AccessibilityRenderObject::firstChild() const
+{
+ if (!m_renderer)
+ return 0;
+
+ RenderObject* firstChild = m_renderer->firstChild();
+ if (!firstChild)
+ return 0;
+
+ return m_renderer->document()->axObjectCache()->get(firstChild);
+}
+
+AccessibilityObject* AccessibilityRenderObject::lastChild() const
+{
+ if (!m_renderer)
+ return 0;
+
+ RenderObject* lastChild = m_renderer->lastChild();
+ if (!lastChild)
+ return 0;
+
+ return m_renderer->document()->axObjectCache()->get(lastChild);
+}
+
+AccessibilityObject* AccessibilityRenderObject::previousSibling() const
+{
+ if (!m_renderer)
+ return 0;
+
+ RenderObject* previousSibling = m_renderer->previousSibling();
+ if (!previousSibling)
+ return 0;
+
+ return m_renderer->document()->axObjectCache()->get(previousSibling);
+}
+
+AccessibilityObject* AccessibilityRenderObject::nextSibling() const
+{
+ if (!m_renderer)
+ return 0;
+
+ RenderObject* nextSibling = m_renderer->nextSibling();
+ if (!nextSibling)
+ return 0;
+
+ return m_renderer->document()->axObjectCache()->get(nextSibling);
+}
+
+AccessibilityObject* AccessibilityRenderObject::parentObject() const
+{
+ if (!m_renderer)
+ return 0;
+
+ RenderObject *parent = m_renderer->parent();
+ if (!parent)
+ return 0;
+
+ if (ariaRoleAttribute() == MenuBarRole)
+ return m_renderer->document()->axObjectCache()->get(parent);
+
+ // menuButton and its corresponding menu are DOM siblings, but Accessibility needs them to be parent/child
+ if (ariaRoleAttribute() == MenuRole) {
+ AccessibilityObject* parent = menuButtonForMenu();
+ if (parent)
+ return parent;
+ }
+
+ return m_renderer->document()->axObjectCache()->get(parent);
+}
+
+bool AccessibilityRenderObject::isWebArea() const
+{
+ return roleValue() == WebAreaRole;
+}
+
+bool AccessibilityRenderObject::isImageButton() const
+{
+ return isNativeImage() && roleValue() == ButtonRole;
+}
+
+bool AccessibilityRenderObject::isAnchor() const
+{
+ return !isNativeImage() && isLink();
+}
+
+bool AccessibilityRenderObject::isNativeTextControl() const
+{
+ return m_renderer->isTextField() || m_renderer->isTextArea();
+}
+
+bool AccessibilityRenderObject::isTextControl() const
+{
+ AccessibilityRole role = roleValue();
+ return role == TextAreaRole || role == TextFieldRole;
+}
+
+bool AccessibilityRenderObject::isNativeImage() const
+{
+ return m_renderer->isImage();
+}
+
+bool AccessibilityRenderObject::isImage() const
+{
+ return roleValue() == ImageRole;
+}
+
+bool AccessibilityRenderObject::isAttachment() const
+{
+ // Widgets are the replaced elements that we represent to AX as attachments
+ bool isWidget = m_renderer && m_renderer->isWidget();
+ ASSERT(!isWidget || (m_renderer->isReplaced() && !isImage()));
+ return isWidget && ariaRoleAttribute() == UnknownRole;
+}
+
+bool AccessibilityRenderObject::isPasswordField() const
+{
+ ASSERT(m_renderer);
+ if (!m_renderer->element() || !m_renderer->element()->isHTMLElement())
+ return false;
+ return static_cast<HTMLElement*>(m_renderer->element())->isPasswordField() && ariaRoleAttribute() == UnknownRole;
+}
+
+bool AccessibilityRenderObject::isCheckboxOrRadio() const
+{
+ AccessibilityRole role = roleValue();
+ return role == RadioButtonRole || role == CheckBoxRole;
+}
+
+bool AccessibilityRenderObject::isFileUploadButton() const
+{
+ if (m_renderer && m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) {
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
+ return input->inputType() == HTMLInputElement::FILE;
+ }
+
+ return false;
+}
+
+bool AccessibilityRenderObject::isProgressIndicator() const
+{
+ return roleValue() == ProgressIndicatorRole;
+}
+
+bool AccessibilityRenderObject::isSlider() const
+{
+ return roleValue() == SliderRole;
+}
+
+bool AccessibilityRenderObject::isMenuRelated() const
+{
+ AccessibilityRole role = roleValue();
+ return role == MenuRole ||
+ role == MenuBarRole ||
+ role == MenuButtonRole ||
+ role == MenuItemRole;
+}
+
+bool AccessibilityRenderObject::isMenu() const
+{
+ return roleValue() == MenuRole;
+}
+
+bool AccessibilityRenderObject::isMenuBar() const
+{
+ return roleValue() == MenuBarRole;
+}
+
+bool AccessibilityRenderObject::isMenuButton() const
+{
+ return roleValue() == MenuButtonRole;
+}
+
+bool AccessibilityRenderObject::isMenuItem() const
+{
+ return roleValue() == MenuItemRole;
+}
+
+bool AccessibilityRenderObject::isPressed() const
+{
+ ASSERT(m_renderer);
+ if (roleValue() != ButtonRole)
+ return false;
+
+ Node* node = m_renderer->node();
+ if (!node)
+ return false;
+
+ // If this is an ARIA button, check the aria-pressed attribute rather than node()->active()
+ if (ariaRoleAttribute() == ButtonRole) {
+ if (equalIgnoringCase(getAttribute(aria_pressedAttr).string(), "true"))
+ return true;
+ return false;
+ }
+
+ return node->active();
+}
+
+bool AccessibilityRenderObject::isIndeterminate() const
+{
+ ASSERT(m_renderer);
+ return m_renderer->node() && m_renderer->node()->isIndeterminate();
+}
+
+bool AccessibilityRenderObject::isChecked() const
+{
+ ASSERT(m_renderer);
+ return m_renderer->node() && m_renderer->node()->isChecked();
+}
+
+bool AccessibilityRenderObject::isHovered() const
+{
+ ASSERT(m_renderer);
+ return m_renderer->node() && m_renderer->node()->hovered();
+}
+
+bool AccessibilityRenderObject::isMultiSelect() const
+{
+ ASSERT(m_renderer);
+ if (!m_renderer->isListBox())
+ return false;
+ return m_renderer->element() && static_cast<HTMLSelectElement*>(m_renderer->element())->multiple();
+}
+
+bool AccessibilityRenderObject::isReadOnly() const
+{
+ ASSERT(m_renderer);
+
+ if (isWebArea()) {
+ Document* document = m_renderer->document();
+ if (!document)
+ return true;
+
+ Frame* frame = document->frame();
+ if (!frame)
+ return true;
+
+ return !frame->isContentEditable();
+ }
+
+ return !m_renderer->node() || !m_renderer->node()->isContentEditable();
+}
+
+bool AccessibilityRenderObject::isOffScreen() const
+{
+ ASSERT(m_renderer);
+ IntRect contentRect = m_renderer->absoluteClippedOverflowRect();
+ FrameView* view = m_renderer->document()->frame()->view();
+ FloatRect viewRect = view->visibleContentRect();
+ viewRect.intersect(contentRect);
+ return viewRect.isEmpty();
+}
+
+int AccessibilityRenderObject::headingLevel(Node* node)
+{
+ // headings can be in block flow and non-block flow
+ if (!node)
+ return 0;
+
+ if (RenderObject* renderer = node->renderer()) {
+ AccessibilityObject* axObjectForNode = node->document()->axObjectCache()->get(renderer);
+ if (axObjectForNode->ariaRoleAttribute() == HeadingRole) {
+ if (!node->isElementNode())
+ return 0;
+ Element* element = static_cast<Element*>(node);
+ return element->getAttribute(aria_levelAttr).toInt();
+ }
+ }
+
+
+ if (node->hasTagName(h1Tag))
+ return 1;
+
+ if (node->hasTagName(h2Tag))
+ return 2;
+
+ if (node->hasTagName(h3Tag))
+ return 3;
+
+ if (node->hasTagName(h4Tag))
+ return 4;
+
+ if (node->hasTagName(h5Tag))
+ return 5;
+
+ if (node->hasTagName(h6Tag))
+ return 6;
+
+ return 0;
+}
+
+bool AccessibilityRenderObject::isHeading() const
+{
+ return roleValue() == HeadingRole;
+}
+
+bool AccessibilityRenderObject::isLink() const
+{
+ return roleValue() == WebCoreLinkRole;
+}
+
+bool AccessibilityRenderObject::isControl() const
+{
+ if (!m_renderer)
+ return false;
+
+ Node* node = m_renderer->element();
+ return node && (node->isControl() || AccessibilityObject::isARIAControl(ariaRoleAttribute()));
+}
+
+bool AccessibilityRenderObject::isFieldset() const
+{
+ if (!m_renderer)
+ return false;
+
+ return m_renderer->isFieldset();
+}
+
+const AtomicString& AccessibilityRenderObject::getAttribute(const QualifiedName& attribute) const
+{
+ Node* node = m_renderer->element();
+ if (!node)
+ return nullAtom;
+
+ if (!node->isElementNode())
+ return nullAtom;
+
+ Element* element = static_cast<Element*>(node);
+ return element->getAttribute(attribute);
+}
+
+Element* AccessibilityRenderObject::anchorElement() const
+{
+ if (!m_renderer)
+ return 0;
+
+ AXObjectCache* cache = axObjectCache();
+ RenderObject* currRenderer;
+
+ // Search up the render tree for a RenderObject with a DOM node. Defer to an earlier continuation, though.
+ for (currRenderer = m_renderer; currRenderer && !currRenderer->element(); currRenderer = currRenderer->parent()) {
+ if (currRenderer->continuation())
+ return cache->get(currRenderer->continuation())->anchorElement();
+ }
+
+ // bail if none found
+ if (!currRenderer)
+ return 0;
+
+ // search up the DOM tree for an anchor element
+ // NOTE: this assumes that any non-image with an anchor is an HTMLAnchorElement
+ Node* node = currRenderer->node();
+ for ( ; node; node = node->parentNode()) {
+ if (node->hasTagName(aTag) || (node->renderer() && cache->get(node->renderer())->isAnchor()))
+ return static_cast<Element*>(node);
+ }
+
+ return 0;
+}
+
+Element* AccessibilityRenderObject::actionElement() const
+{
+ if (m_renderer->element() && m_renderer->element()->hasTagName(inputTag)) {
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
+ if (!input->disabled() && (isCheckboxOrRadio() || input->isTextButton()))
+ return input;
+ }
+
+ if (isFileUploadButton())
+ return static_cast<Element*>(m_renderer->element());
+
+ if (AccessibilityObject::isARIAInput(ariaRoleAttribute()))
+ return static_cast<Element*>(m_renderer->element());
+
+ if (isImageButton())
+ return static_cast<Element*>(m_renderer->element());
+
+ if (m_renderer->isMenuList())
+ return static_cast<RenderMenuList*>(m_renderer)->selectElement();
+
+ Element* elt = anchorElement();
+ if (!elt)
+ elt = mouseButtonListener();
+ return elt;
+}
+
+Element* AccessibilityRenderObject::mouseButtonListener() const
+{
+ Node* node = m_renderer->element();
+ if (!node)
+ return 0;
+ if (!node->isEventTargetNode())
+ return 0;
+
+ // FIXME: Do the continuation search like anchorElement does
+ for (EventTargetNode* elt = static_cast<EventTargetNode*>(node); elt; elt = static_cast<EventTargetNode*>(elt->parentNode())) {
+ if (elt->inlineEventListenerForType(eventNames().clickEvent) || elt->inlineEventListenerForType(eventNames().mousedownEvent) || elt->inlineEventListenerForType(eventNames().mouseupEvent))
+ return static_cast<Element*>(elt);
+ }
+
+ return 0;
+}
+
+static Element* siblingWithAriaRole(String role, Node* node)
+{
+ Node* sibling = node->parent()->firstChild();
+ while (sibling) {
+ if (sibling->isElementNode()) {
+ String siblingAriaRole = static_cast<Element*>(sibling)->getAttribute(roleAttr).string();
+ if (equalIgnoringCase(siblingAriaRole, role))
+ return static_cast<Element*>(sibling);
+ }
+ sibling = sibling->nextSibling();
+ }
+
+ return 0;
+}
+
+Element* AccessibilityRenderObject::menuElementForMenuButton() const
+{
+ if (ariaRoleAttribute() != MenuButtonRole)
+ return 0;
+
+ return siblingWithAriaRole("menu", renderer()->node());
+}
+
+AccessibilityObject* AccessibilityRenderObject::menuForMenuButton() const
+{
+ Element* menu = menuElementForMenuButton();
+ if (menu && menu->renderer())
+ return m_renderer->document()->axObjectCache()->get(menu->renderer());
+ return 0;
+}
+
+Element* AccessibilityRenderObject::menuItemElementForMenu() const
+{
+ if (ariaRoleAttribute() != MenuRole)
+ return 0;
+
+ return siblingWithAriaRole("menuitem", renderer()->node());
+}
+
+AccessibilityObject* AccessibilityRenderObject::menuButtonForMenu() const
+{
+ Element* menuItem = menuItemElementForMenu();
+
+ if (menuItem && menuItem->renderer()) {
+ // ARIA just has generic menu items. AppKit needs to know if this is a top level items like MenuBarButton or MenuBarItem
+ AccessibilityObject* menuItemAX = m_renderer->document()->axObjectCache()->get(menuItem->renderer());
+ if (menuItemAX->isMenuButton())
+ return menuItemAX;
+ }
+ return 0;
+}
+
+String AccessibilityRenderObject::helpText() const
+{
+ if (!m_renderer)
+ return String();
+
+ for (RenderObject* curr = m_renderer; curr; curr = curr->parent()) {
+ if (curr->element() && curr->element()->isHTMLElement()) {
+ const AtomicString& summary = static_cast<Element*>(curr->element())->getAttribute(summaryAttr);
+ if (!summary.isEmpty())
+ return summary;
+ const AtomicString& title = static_cast<Element*>(curr->element())->getAttribute(titleAttr);
+ if (!title.isEmpty())
+ return title;
+ }
+ }
+
+ return String();
+}
+
+String AccessibilityRenderObject::textUnderElement() const
+{
+ if (!m_renderer)
+ return String();
+
+ if (isFileUploadButton()) {
+ RenderFileUploadControl* uploadControl = static_cast<RenderFileUploadControl*>(m_renderer);
+ return uploadControl->buttonValue();
+ }
+
+ Node* node = m_renderer->element();
+ if (node) {
+ if (Frame* frame = node->document()->frame()) {
+ // catch stale WebCoreAXObject (see <rdar://problem/3960196>)
+ if (frame->document() != node->document())
+ return String();
+ return plainText(rangeOfContents(node).get());
+ }
+ }
+
+ // return the null string for anonymous text because it is non-trivial to get
+ // the actual text and, so far, that is not needed
+ return String();
+}
+
+bool AccessibilityRenderObject::hasIntValue() const
+{
+ if (isHeading())
+ return true;
+
+ if (m_renderer->element() && isCheckboxOrRadio())
+ return true;
+
+ return false;
+}
+
+int AccessibilityRenderObject::intValue() const
+{
+ if (!m_renderer || isPasswordField())
+ return 0;
+
+ if (isHeading())
+ return headingLevel(m_renderer->element());
+
+ Node* node = m_renderer->element();
+ if (!node || !isCheckboxOrRadio())
+ return 0;
+
+ // If this is an ARIA checkbox or radio, check the aria-checked attribute rather than node()->checked()
+ AccessibilityRole ariaRole = ariaRoleAttribute();
+ if (ariaRole == RadioButtonRole || ariaRole == CheckBoxRole) {
+ if (equalIgnoringCase(getAttribute(aria_checkedAttr).string(), "true"))
+ return true;
+ return false;
+ }
+
+ return static_cast<HTMLInputElement*>(node)->checked();
+}
+
+float AccessibilityRenderObject::valueForRange() const
+{
+ if (!isProgressIndicator() && !isSlider())
+ return 0.0f;
+
+ return getAttribute(aria_valuenowAttr).toFloat();
+}
+
+float AccessibilityRenderObject::maxValueForRange() const
+{
+ if (!isProgressIndicator() && !isSlider())
+ return 0.0f;
+
+ return getAttribute(aria_valuemaxAttr).toFloat();
+}
+
+float AccessibilityRenderObject::minValueForRange() const
+{
+ if (!isProgressIndicator() && !isSlider())
+ return 0.0f;
+
+ return getAttribute(aria_valueminAttr).toFloat();
+}
+
+String AccessibilityRenderObject::stringValue() const
+{
+ if (!m_renderer || isPasswordField())
+ return String();
+
+ if (m_renderer->isText())
+ return textUnderElement();
+
+ if (m_renderer->isMenuList())
+ return static_cast<RenderMenuList*>(m_renderer)->text();
+
+ if (m_renderer->isListMarker())
+ return static_cast<RenderListMarker*>(m_renderer)->text();
+
+ if (isWebArea()) {
+ if (m_renderer->document()->frame())
+ return String();
+
+ // FIXME: should use startOfDocument and endOfDocument (or rangeForDocument?) here
+ VisiblePosition startVisiblePosition = m_renderer->positionForCoordinates(0, 0);
+ VisiblePosition endVisiblePosition = m_renderer->positionForCoordinates(INT_MAX, INT_MAX);
+ if (startVisiblePosition.isNull() || endVisiblePosition.isNull())
+ return String();
+
+ return plainText(makeRange(startVisiblePosition, endVisiblePosition).get());
+ }
+
+ if (isTextControl())
+ return text();
+
+ if (isFileUploadButton()) {
+ RenderFileUploadControl* uploadControl = static_cast<RenderFileUploadControl*>(m_renderer);
+ return uploadControl->fileTextValue();
+ }
+
+ // FIXME: We might need to implement a value here for more types
+ // FIXME: It would be better not to advertise a value at all for the types for which we don't implement one;
+ // this would require subclassing or making accessibilityAttributeNames do something other than return a
+ // single static array.
+ return String();
+}
+
+// This function implements the ARIA accessible name as described by the Mozilla
+// ARIA Implementer's Guide.
+static String accessibleNameForNode(Node* node)
+{
+ if (node->isTextNode())
+ return static_cast<Text*>(node)->data();
+
+ if (node->hasTagName(inputTag))
+ return static_cast<HTMLInputElement*>(node)->value();
+
+ if (node->isHTMLElement()) {
+ const AtomicString& alt = static_cast<HTMLElement*>(node)->getAttribute(altAttr);
+ if (!alt.isEmpty())
+ return alt;
+ }
+
+ return String();
+}
+
+String AccessibilityRenderObject::ariaAccessiblityName(const String& s) const
+{
+ Document* document = m_renderer->document();
+ if (!document)
+ return String();
+
+ String idList = s;
+ idList.replace('\n', ' ');
+ Vector<String> idVector;
+ idList.split(' ', idVector);
+
+ Vector<UChar> ariaLabel;
+ unsigned size = idVector.size();
+ for (unsigned i = 0; i < size; ++i) {
+ String idName = idVector[i];
+ Element* idElement = document->getElementById(idName);
+ if (idElement) {
+ String nameFragment = accessibleNameForNode(idElement);
+ ariaLabel.append(nameFragment.characters(), nameFragment.length());
+ for (Node* n = idElement->firstChild(); n; n = n->traverseNextNode(idElement->nextSibling())) {
+ nameFragment = accessibleNameForNode(n);
+ ariaLabel.append(nameFragment.characters(), nameFragment.length());
+ }
+ ariaLabel.append(' ');
+ }
+ }
+ return String::adopt(ariaLabel);
+}
+
+String AccessibilityRenderObject::ariaLabeledByAttribute() const
+{
+ Node* node = m_renderer->node();
+ if (!node)
+ return String();
+
+ if (!node->isElementNode())
+ return String();
+
+ // The ARIA spec uses the British spelling: "labelled." It seems prudent to support the American
+ // spelling ("labeled") as well.
+ String idList = getAttribute(aria_labeledbyAttr).string();
+ if (idList.isEmpty()) {
+ idList = getAttribute(aria_labelledbyAttr).string();
+ if (idList.isEmpty())
+ return String();
+ }
+
+ return ariaAccessiblityName(idList);
+}
+
+static HTMLLabelElement* labelForElement(Element* element)
+{
+ RefPtr<NodeList> list = element->document()->getElementsByTagName("label");
+ unsigned len = list->length();
+ for (unsigned i = 0; i < len; i++) {
+ if (list->item(i)->hasTagName(labelTag)) {
+ HTMLLabelElement* label = static_cast<HTMLLabelElement*>(list->item(i));
+ if (label->correspondingControl() == element)
+ return label;
+ }
+ }
+
+ return 0;
+}
+
+HTMLLabelElement* AccessibilityRenderObject::labelElementContainer() const
+{
+ if (!m_renderer)
+ return false;
+
+ // the control element should not be considered part of the label
+ if (isControl())
+ return false;
+
+ // find if this has a parent that is a label
+ for (Node* parentNode = m_renderer->element(); parentNode; parentNode = parentNode->parentNode()) {
+ if (parentNode->hasTagName(labelTag))
+ return static_cast<HTMLLabelElement*>(parentNode);
+ }
+
+ return 0;
+}
+
+String AccessibilityRenderObject::title() const
+{
+ AccessibilityRole ariaRole = ariaRoleAttribute();
+
+ if (!m_renderer)
+ return String();
+
+ Node* node = m_renderer->element();
+ if (!node)
+ return String();
+
+ String ariaLabel = ariaLabeledByAttribute();
+ if (!ariaLabel.isEmpty())
+ return ariaLabel;
+
+ const AtomicString& title = getAttribute(titleAttr);
+ if (!title.isEmpty())
+ return title;
+
+ bool isInputTag = node->hasTagName(inputTag);
+ if (isInputTag) {
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
+ if (input->isTextButton())
+ return input->value();
+ }
+
+ if (isInputTag || AccessibilityObject::isARIAInput(ariaRole) || isControl()) {
+ HTMLLabelElement* label = labelForElement(static_cast<Element*>(node));
+ if (label)
+ return label->innerText();
+ }
+
+ if (roleValue() == ButtonRole
+ || ariaRole == ListBoxOptionRole
+ || ariaRole == MenuItemRole
+ || ariaRole == MenuButtonRole
+ || isHeading())
+ return textUnderElement();
+
+ if (isLink())
+ return textUnderElement();
+
+ return String();
+}
+
+String AccessibilityRenderObject::ariaDescribedByAttribute() const
+{
+ String idList = getAttribute(aria_describedbyAttr).string();
+ if (idList.isEmpty())
+ return String();
+
+ return ariaAccessiblityName(idList);
+}
+
+String AccessibilityRenderObject::accessibilityDescription() const
+{
+ if (!m_renderer)
+ return String();
+
+ String ariaDescription = ariaDescribedByAttribute();
+ if (!ariaDescription.isEmpty())
+ return ariaDescription;
+
+ if (isImage()) {
+ if (m_renderer->element() && m_renderer->element()->isHTMLElement()) {
+ const AtomicString& alt = static_cast<HTMLElement*>(m_renderer->element())->getAttribute(altAttr);
+ if (alt.isEmpty())
+ return String();
+ return alt;
+ }
+ }
+
+ if (isWebArea()) {
+ Document *document = m_renderer->document();
+ Node* owner = document->ownerElement();
+ if (owner) {
+ if (owner->hasTagName(frameTag) || owner->hasTagName(iframeTag)) {
+ const AtomicString& title = static_cast<HTMLFrameElementBase*>(owner)->getAttribute(titleAttr);
+ if (!title.isEmpty())
+ return title;
+ return static_cast<HTMLFrameElementBase*>(owner)->name();
+ }
+ if (owner->isHTMLElement())
+ return static_cast<HTMLElement*>(owner)->getAttribute(nameAttr);
+ }
+ owner = document->body();
+ if (owner && owner->isHTMLElement())
+ return static_cast<HTMLElement*>(owner)->getAttribute(nameAttr);
+ }
+
+ if (roleValue() == DefinitionListTermRole)
+ return AXDefinitionListTermText();
+ if (roleValue() == DefinitionListDefinitionRole)
+ return AXDefinitionListDefinitionText();
+
+ return String();
+}
+
+IntRect AccessibilityRenderObject::boundingBoxRect() const
+{
+ IntRect rect;
+ RenderObject* obj = m_renderer;
+
+ if (!obj)
+ return IntRect();
+
+ if (obj->isInlineContinuation())
+ obj = obj->element()->renderer();
+
+ // FIXME: This doesn't work correctly with transforms.
+ Vector<IntRect> rects;
+ int x, y;
+ obj->absolutePosition(x, y);
+ obj->absoluteRects(rects, x, y);
+ const size_t n = rects.size();
+ for (size_t i = 0; i < n; ++i) {
+ IntRect r = rects[i];
+ if (!r.isEmpty()) {
+ if (obj->style()->hasAppearance())
+ theme()->adjustRepaintRect(obj, r);
+ rect.unite(r);
+ }
+ }
+ return rect;
+}
+
+IntRect AccessibilityRenderObject::checkboxOrRadioRect() const
+{
+ if (!m_renderer)
+ return IntRect();
+
+ HTMLLabelElement* label = labelForElement(static_cast<Element*>(m_renderer->element()));
+ if (!label || !label->renderer())
+ return boundingBoxRect();
+
+ IntRect labelRect = axObjectCache()->get(label->renderer())->elementRect();
+ labelRect.unite(boundingBoxRect());
+ return labelRect;
+}
+
+IntRect AccessibilityRenderObject::elementRect() const
+{
+ // a checkbox or radio button should encompass its label
+ if (isCheckboxOrRadio())
+ return checkboxOrRadioRect();
+
+ return boundingBoxRect();
+}
+
+IntSize AccessibilityRenderObject::size() const
+{
+ IntRect rect = elementRect();
+ return rect.size();
+}
+
+AccessibilityObject* AccessibilityRenderObject::internalLinkElement() const
+{
+ Element* element = anchorElement();
+ if (!element)
+ return 0;
+
+ // Right now, we do not support ARIA links as internal link elements
+ if (!element->hasTagName(aTag))
+ return 0;
+ HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(element);
+
+ KURL linkURL = anchor->href();
+ String ref = linkURL.ref();
+ if (ref.isEmpty())
+ return 0;
+
+ // check if URL is the same as current URL
+ linkURL.removeRef();
+ if (m_renderer->document()->url() != linkURL)
+ return 0;
+
+ Node* linkedNode = m_renderer->document()->getElementById(ref);
+ if (!linkedNode) {
+ linkedNode = m_renderer->document()->anchors()->namedItem(ref, !m_renderer->document()->inCompatMode());
+ if (!linkedNode)
+ return 0;
+ }
+
+ // the element we find may not be accessible, keep searching until we find a good one
+ AccessibilityObject* linkedAXElement = m_renderer->document()->axObjectCache()->get(linkedNode->renderer());
+ while (linkedAXElement && linkedAXElement->accessibilityIsIgnored()) {
+ linkedNode = linkedNode->traverseNextNode();
+
+ while (linkedNode && !linkedNode->renderer())
+ linkedNode = linkedNode->traverseNextSibling();
+
+ if (!linkedNode)
+ return 0;
+ linkedAXElement = m_renderer->document()->axObjectCache()->get(linkedNode->renderer());
+ }
+
+ return linkedAXElement;
+}
+
+void AccessibilityRenderObject::addRadioButtonGroupMembers(AccessibilityChildrenVector& linkedUIElements) const
+{
+ if (!m_renderer || roleValue() != RadioButtonRole)
+ return;
+
+ Node* node = m_renderer->node();
+ if (!node || !node->hasTagName(inputTag))
+ return;
+
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
+ // if there's a form, then this is easy
+ if (input->form()) {
+ Vector<RefPtr<Node> > formElements;
+ input->form()->getNamedElements(input->name(), formElements);
+
+ unsigned len = formElements.size();
+ for (unsigned i = 0; i < len; ++i) {
+ Node* associateElement = formElements[i].get();
+ if (AccessibilityObject* object = m_renderer->document()->axObjectCache()->get(associateElement->renderer()))
+ linkedUIElements.append(object);
+ }
+ } else {
+ RefPtr<NodeList> list = node->document()->getElementsByTagName("input");
+ unsigned len = list->length();
+ for (unsigned i = 0; i < len; ++i) {
+ if (list->item(i)->hasTagName(inputTag)) {
+ HTMLInputElement* associateElement = static_cast<HTMLInputElement*>(list->item(i));
+ if (associateElement->isRadioButton() && associateElement->name() == input->name()) {
+ if (AccessibilityObject* object = m_renderer->document()->axObjectCache()->get(associateElement->renderer()))
+ linkedUIElements.append(object);
+ }
+ }
+ }
+ }
+}
+
+// linked ui elements could be all the related radio buttons in a group
+// or an internal anchor connection
+void AccessibilityRenderObject::linkedUIElements(AccessibilityChildrenVector& linkedUIElements) const
+{
+ if (isAnchor()) {
+ AccessibilityObject* linkedAXElement = internalLinkElement();
+ if (linkedAXElement)
+ linkedUIElements.append(linkedAXElement);
+ }
+
+ if (roleValue() == RadioButtonRole)
+ addRadioButtonGroupMembers(linkedUIElements);
+}
+
+AccessibilityObject* AccessibilityRenderObject::titleUIElement() const
+{
+ if (!m_renderer)
+ return 0;
+
+ // if isFieldset is true, the renderer is guaranteed to be a RenderFieldset
+ if (isFieldset())
+ return axObjectCache()->get(static_cast<RenderFieldset*>(m_renderer)->findLegend());
+
+ // checkbox and radio hide their labels. Only controls get titleUIElements for now
+ if (isCheckboxOrRadio() || !isControl())
+ return 0;
+
+ Node* element = m_renderer->element();
+ HTMLLabelElement* label = labelForElement(static_cast<Element*>(element));
+ if (label && label->renderer())
+ return axObjectCache()->get(label->renderer());
+
+ return 0;
+}
+
+bool AccessibilityRenderObject::accessibilityIsIgnored() const
+{
+ // ignore invisible element
+ if (!m_renderer || m_renderer->style()->visibility() != VISIBLE)
+ return true;
+
+ if (isPresentationalChildOfAriaRole())
+ return true;
+
+ // ignore popup menu items because AppKit does
+ for (RenderObject* parent = m_renderer->parent(); parent; parent = parent->parent()) {
+ if (parent->isMenuList())
+ return true;
+ }
+
+ // find out if this element is inside of a label element.
+ // if so, it may be ignored because it's the label for a checkbox or radio button
+ HTMLLabelElement* labelElement = labelElementContainer();
+ if (labelElement) {
+ HTMLElement* correspondingControl = labelElement->correspondingControl();
+ if (correspondingControl && correspondingControl->renderer()) {
+ AccessibilityObject* controlObject = axObjectCache()->get(correspondingControl->renderer());
+ if (controlObject->isCheckboxOrRadio())
+ return true;
+ }
+ }
+
+ AccessibilityRole ariaRole = ariaRoleAttribute();
+ if (ariaRole == TextAreaRole || ariaRole == StaticTextRole) {
+ String ariaText = text();
+ return ariaText.isNull() || ariaText.isEmpty();
+ }
+
+ // NOTE: BRs always have text boxes now, so the text box check here can be removed
+ if (m_renderer->isText()) {
+ // static text beneath MenuItems and MenuButtons are just reported along with the menu item, so it's ignored on an individual level
+ if (parentObjectUnignored()->ariaRoleAttribute() == MenuItemRole ||
+ parentObjectUnignored()->ariaRoleAttribute() == MenuButtonRole)
+ return true;
+ return m_renderer->isBR() || !static_cast<RenderText*>(m_renderer)->firstTextBox();
+ }
+
+ if (isHeading())
+ return false;
+
+ if (isLink())
+ return false;
+
+ // all controls are accessible
+ if (isControl())
+ return false;
+
+ // don't ignore labels, because they serve as TitleUIElements
+ Node* node = m_renderer->element();
+ if (node && node->hasTagName(labelTag))
+ return false;
+
+ if (m_renderer->isBlockFlow() && m_renderer->childrenInline())
+ return !static_cast<RenderBlock*>(m_renderer)->firstLineBox() && !mouseButtonListener();
+
+ // ignore images seemingly used as spacers
+ if (isImage()) {
+ if (node && node->isElementNode()) {
+ Element* elt = static_cast<Element*>(node);
+ const AtomicString& alt = elt->getAttribute(altAttr);
+ // don't ignore an image that has an alt tag
+ if (!alt.isEmpty())
+ return false;
+ // informal standard is to ignore images with zero-length alt strings
+ if (!alt.isNull())
+ return true;
+ }
+
+ // check for one-dimensional image
+ if (m_renderer->height() <= 1 || m_renderer->width() <= 1)
+ return true;
+
+ // check whether rendered image was stretched from one-dimensional file image
+ if (isNativeImage()) {
+ RenderImage* image = static_cast<RenderImage*>(m_renderer);
+ if (image->cachedImage()) {
+ IntSize imageSize = image->cachedImage()->imageSize(image->view()->zoomFactor());
+ return imageSize.height() <= 1 || imageSize.width() <= 1;
+ }
+ }
+ return false;
+ }
+
+ if (ariaRole != UnknownRole)
+ return false;
+
+ // make a platform-specific decision
+ if (isAttachment())
+ return accessibilityIgnoreAttachment();
+
+ return !m_renderer->isListMarker() && !isWebArea();
+}
+
+bool AccessibilityRenderObject::isLoaded() const
+{
+ return !m_renderer->document()->tokenizer();
+}
+
+int AccessibilityRenderObject::layoutCount() const
+{
+ if (!m_renderer->isRenderView())
+ return 0;
+ return static_cast<RenderView*>(m_renderer)->frameView()->layoutCount();
+}
+
+String AccessibilityRenderObject::text() const
+{
+ if (!isTextControl() || isPasswordField())
+ return String();
+
+ if (isNativeTextControl())
+ return static_cast<RenderTextControl*>(m_renderer)->text();
+
+ Node* node = m_renderer->element();
+ if (!node)
+ return String();
+ if (!node->isElementNode())
+ return String();
+
+ return static_cast<Element*>(node)->innerText();
+}
+
+int AccessibilityRenderObject::textLength() const
+{
+ ASSERT(isTextControl());
+
+ if (isPasswordField())
+ return -1; // need to return something distinct from 0
+
+ return text().length();
+}
+
+PassRefPtr<Range> AccessibilityRenderObject::ariaSelectedTextDOMRange() const
+{
+ Node* node = m_renderer->element();
+ if (!node)
+ return 0;
+
+ RefPtr<Range> currentSelectionRange = selection().toRange();
+ if (!currentSelectionRange)
+ return 0;
+
+ ExceptionCode ec = 0;
+ if (!currentSelectionRange->intersectsNode(node, ec))
+ return Range::create(currentSelectionRange->ownerDocument());
+
+ RefPtr<Range> ariaRange = rangeOfContents(node);
+ Position startPosition, endPosition;
+
+ // Find intersection of currentSelectionRange and ariaRange
+ if (ariaRange->startOffset() > currentSelectionRange->startOffset())
+ startPosition = ariaRange->startPosition();
+ else
+ startPosition = currentSelectionRange->startPosition();
+
+ if (ariaRange->endOffset() < currentSelectionRange->endOffset())
+ endPosition = ariaRange->endPosition();
+ else
+ endPosition = currentSelectionRange->endPosition();
+
+ return Range::create(ariaRange->ownerDocument(), startPosition, endPosition);
+}
+
+String AccessibilityRenderObject::selectedText() const
+{
+ ASSERT(isTextControl());
+
+ if (isPasswordField())
+ return String(); // need to return something distinct from empty string
+
+ if (isNativeTextControl()) {
+ RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
+ return textControl->text().substring(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart());
+ }
+
+ if (ariaRoleAttribute() == UnknownRole)
+ return String();
+
+ RefPtr<Range> ariaRange = ariaSelectedTextDOMRange();
+ if (!ariaRange)
+ return String();
+ return ariaRange->text();
+}
+
+const AtomicString& AccessibilityRenderObject::accessKey() const
+{
+ Node* node = m_renderer->element();
+ if (!node)
+ return nullAtom;
+ if (!node->isElementNode())
+ return nullAtom;
+ return static_cast<Element*>(node)->getAttribute(accesskeyAttr);
+}
+
+Selection AccessibilityRenderObject::selection() const
+{
+ return m_renderer->document()->frame()->selection()->selection();
+}
+
+PlainTextRange AccessibilityRenderObject::selectedTextRange() const
+{
+ ASSERT(isTextControl());
+
+ if (isPasswordField())
+ return PlainTextRange();
+
+ AccessibilityRole ariaRole = ariaRoleAttribute();
+ if (isNativeTextControl() && ariaRole == UnknownRole) {
+ RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
+ return PlainTextRange(textControl->selectionStart(), textControl->selectionEnd() - textControl->selectionStart());
+ }
+
+ if (ariaRole == UnknownRole)
+ return PlainTextRange();
+
+ RefPtr<Range> ariaRange = ariaSelectedTextDOMRange();
+ if (!ariaRange)
+ return PlainTextRange();
+ return PlainTextRange(ariaRange->startOffset(), ariaRange->endOffset());
+}
+
+void AccessibilityRenderObject::setSelectedTextRange(const PlainTextRange& range)
+{
+ if (isNativeTextControl()) {
+ RenderTextControl* textControl = static_cast<RenderTextControl*>(m_renderer);
+ textControl->setSelectionRange(range.start, range.start + range.length);
+ return;
+ }
+
+ Document* document = m_renderer->document();
+ if (!document)
+ return;
+ Frame* frame = document->frame();
+ if (!frame)
+ return;
+ Node* node = m_renderer->element();
+ frame->selection()->setSelection(Selection(Position(node, range.start),
+ Position(node, range.start + range.length), DOWNSTREAM));
+}
+
+KURL AccessibilityRenderObject::url() const
+{
+ if (isAnchor() && m_renderer->element()->hasTagName(aTag)) {
+ if (HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(anchorElement()))
+ return anchor->href();
+ }
+
+ if (isWebArea())
+ return m_renderer->document()->url();
+
+ if (isImage() && m_renderer->element() && m_renderer->element()->hasTagName(imgTag))
+ return static_cast<HTMLImageElement*>(m_renderer->element())->src();
+
+ return KURL();
+}
+
+bool AccessibilityRenderObject::isVisited() const
+{
+ return m_renderer->style()->pseudoState() == PseudoVisited;
+}
+
+bool AccessibilityRenderObject::isSelected() const
+{
+ if (!m_renderer)
+ return false;
+
+ Node* node = m_renderer->node();
+ if (!node)
+ return false;
+
+ return false;
+}
+
+bool AccessibilityRenderObject::isFocused() const
+{
+ if (!m_renderer)
+ return false;
+
+ Document* document = m_renderer->document();
+ if (!document)
+ return false;
+
+ Node* focusedNode = document->focusedNode();
+ if (!focusedNode)
+ return false;
+
+ // A web area is represented by the Document node in the DOM tree, which isn't focusable.
+ // Check instead if the frame's selection controller is focused
+ if (focusedNode == m_renderer->element() ||
+ (roleValue() == WebAreaRole && document->frame()->selection()->isFocusedAndActive()))
+ return true;
+
+ return false;
+}
+
+void AccessibilityRenderObject::setFocused(bool on)
+{
+ if (!canSetFocusAttribute())
+ return;
+
+ if (!on)
+ m_renderer->document()->setFocusedNode(0);
+ else {
+ if (m_renderer->element()->isElementNode())
+ static_cast<Element*>(m_renderer->element())->focus();
+ else
+ m_renderer->document()->setFocusedNode(m_renderer->element());
+ }
+}
+
+void AccessibilityRenderObject::setValue(const String& string)
+{
+ // FIXME: Do we want to do anything here for ARIA textboxes?
+ if (m_renderer->isTextField()) {
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(m_renderer->element());
+ input->setValue(string);
+ } else if (m_renderer->isTextArea()) {
+ HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(m_renderer->element());
+ textArea->setValue(string);
+ }
+}
+
+bool AccessibilityRenderObject::isEnabled() const
+{
+ return m_renderer->element() ? m_renderer->element()->isEnabled() : true;
+}
+
+RenderObject* AccessibilityRenderObject::topRenderer() const
+{
+ return m_renderer->document()->topDocument()->renderer();
+}
+
+Document* AccessibilityRenderObject::document() const
+{
+ return m_renderer->document();
+}
+
+FrameView* AccessibilityRenderObject::topDocumentFrameView() const
+{
+ return topRenderer()->view()->frameView();
+}
+
+Widget* AccessibilityRenderObject::widget() const
+{
+ if (!m_renderer->isWidget())
+ return 0;
+
+ return static_cast<RenderWidget*>(m_renderer)->widget();
+}
+
+AXObjectCache* AccessibilityRenderObject::axObjectCache() const
+{
+ return m_renderer->document()->axObjectCache();
+}
+
+AccessibilityObject* AccessibilityRenderObject::accessibilityParentForImageMap(HTMLMapElement* map) const
+{
+ // find an image that is using this map
+ if (!m_renderer || !map)
+ return 0;
+
+ RefPtr<HTMLCollection> coll = m_renderer->document()->images();
+ for (Node* curr = coll->firstItem(); curr; curr = coll->nextItem()) {
+ RenderObject* obj = curr->renderer();
+ if (!obj || !curr->hasTagName(imgTag))
+ continue;
+
+ // The HTMLImageElement's useMap() value includes the '#' symbol at the beginning,
+ // which has to be stripped off
+ if (static_cast<HTMLImageElement*>(curr)->useMap().substring(1) == map->getName())
+ return axObjectCache()->get(obj);
+ }
+
+ return 0;
+}
+
+void AccessibilityRenderObject::getDocumentLinks(AccessibilityChildrenVector& result)
+{
+ Document* document = m_renderer->document();
+ RefPtr<HTMLCollection> coll = document->links();
+ Node* curr = coll->firstItem();
+ while (curr) {
+ RenderObject* obj = curr->renderer();
+ if (obj) {
+ RefPtr<AccessibilityObject> axobj = document->axObjectCache()->get(obj);
+ ASSERT(axobj);
+ ASSERT(axobj->roleValue() == WebCoreLinkRole);
+ if (!axobj->accessibilityIsIgnored())
+ result.append(axobj);
+ } else {
+ Node* parent = curr->parent();
+ if (parent && curr->hasTagName(areaTag) && parent->hasTagName(mapTag)) {
+ AccessibilityImageMapLink* areaObject = static_cast<AccessibilityImageMapLink*>(axObjectCache()->get(ImageMapLinkRole));
+ areaObject->setHTMLAreaElement(static_cast<HTMLAreaElement*>(curr));
+ areaObject->setHTMLMapElement(static_cast<HTMLMapElement*>(parent));
+ areaObject->setParent(accessibilityParentForImageMap(static_cast<HTMLMapElement*>(parent)));
+
+ result.append(areaObject);
+ }
+ }
+ curr = coll->nextItem();
+ }
+}
+
+FrameView* AccessibilityRenderObject::documentFrameView() const
+{
+ if (!m_renderer || !m_renderer->document())
+ return 0;
+
+ // this is the RenderObject's Document's Frame's FrameView
+ return m_renderer->document()->view();
+}
+
+Widget* AccessibilityRenderObject::widgetForAttachmentView() const
+{
+ if (!isAttachment())
+ return 0;
+ return static_cast<RenderWidget*>(m_renderer)->widget();
+}
+
+FrameView* AccessibilityRenderObject::frameViewIfRenderView() const
+{
+ if (!m_renderer->isRenderView())
+ return 0;
+ // this is the RenderObject's Document's renderer's FrameView
+ return m_renderer->view()->frameView();
+}
+
+// This function is like a cross-platform version of - (WebCoreTextMarkerRange*)textMarkerRange. It returns
+// a Range that we can convert to a WebCoreTextMarkerRange in the Obj-C file
+VisiblePositionRange AccessibilityRenderObject::visiblePositionRange() const
+{
+ if (!m_renderer)
+ return VisiblePositionRange();
+
+ // construct VisiblePositions for start and end
+ Node* node = m_renderer->element();
+ if (!node)
+ return VisiblePositionRange();
+
+ VisiblePosition startPos = VisiblePosition(node, 0, VP_DEFAULT_AFFINITY);
+ VisiblePosition endPos = VisiblePosition(node, maxDeepOffset(node), VP_DEFAULT_AFFINITY);
+
+ // the VisiblePositions are equal for nodes like buttons, so adjust for that
+ if (startPos == endPos) {
+ endPos = endPos.next();
+ if (endPos.isNull())
+ endPos = startPos;
+ }
+
+ return VisiblePositionRange(startPos, endPos);
+}
+
+VisiblePositionRange AccessibilityRenderObject::visiblePositionRangeForLine(unsigned lineCount) const
+{
+ if (lineCount == 0 || !m_renderer)
+ return VisiblePositionRange();
+
+ // iterate over the lines
+ // FIXME: this is wrong when lineNumber is lineCount+1, because nextLinePosition takes you to the
+ // last offset of the last line
+ VisiblePosition visiblePos = m_renderer->document()->renderer()->positionForCoordinates(0, 0);
+ VisiblePosition savedVisiblePos;
+ while (--lineCount != 0) {
+ savedVisiblePos = visiblePos;
+ visiblePos = nextLinePosition(visiblePos, 0);
+ if (visiblePos.isNull() || visiblePos == savedVisiblePos)
+ return VisiblePositionRange();
+ }
+
+ // make a caret selection for the marker position, then extend it to the line
+ // NOTE: ignores results of sel.modify because it returns false when
+ // starting at an empty line. The resulting selection in that case
+ // will be a caret at visiblePos.
+ SelectionController selection;
+ selection.setSelection(Selection(visiblePos));
+ selection.modify(SelectionController::EXTEND, SelectionController::RIGHT, LineBoundary);
+
+ return VisiblePositionRange(selection.selection().visibleStart(), selection.selection().visibleEnd());
+}
+
+VisiblePosition AccessibilityRenderObject::visiblePositionForIndex(int index) const
+{
+ if (!m_renderer)
+ return VisiblePosition();
+
+ if (isNativeTextControl())
+ return static_cast<RenderTextControl*>(m_renderer)->visiblePositionForIndex(index);
+
+ if (!isTextControl() && !m_renderer->isText())
+ return VisiblePosition();
+
+ Node* node = m_renderer->node();
+ if (!node)
+ return VisiblePosition();
+
+ if (index <= 0)
+ return VisiblePosition(node, 0, DOWNSTREAM);
+
+ ExceptionCode ec = 0;
+ RefPtr<Range> range = Range::create(m_renderer->document());
+ range->selectNodeContents(node, ec);
+ CharacterIterator it(range.get());
+ it.advance(index - 1);
+ return VisiblePosition(it.range()->endContainer(ec), it.range()->endOffset(ec), UPSTREAM);
+}
+
+int AccessibilityRenderObject::indexForVisiblePosition(const VisiblePosition& pos) const
+{
+ if (isNativeTextControl())
+ return static_cast<RenderTextControl*>(m_renderer)->indexForVisiblePosition(pos);
+
+ if (!isTextControl())
+ return 0;
+
+ Node* node = m_renderer->node();
+ if (!node)
+ return 0;
+
+ Position indexPosition = pos.deepEquivalent();
+ if (!indexPosition.node() || indexPosition.node()->rootEditableElement() != node)
+ return 0;
+
+ ExceptionCode ec = 0;
+ RefPtr<Range> range = Range::create(m_renderer->document());
+ range->setStart(node, 0, ec);
+ range->setEnd(indexPosition.node(), indexPosition.offset(), ec);
+ return TextIterator::rangeLength(range.get());
+}
+
+IntRect AccessibilityRenderObject::boundsForVisiblePositionRange(const VisiblePositionRange& visiblePositionRange) const
+{
+ if (visiblePositionRange.isNull())
+ return IntRect();
+
+ // Create a mutable VisiblePositionRange.
+ VisiblePositionRange range(visiblePositionRange);
+ IntRect rect1 = range.start.caretRect();
+ IntRect rect2 = range.end.caretRect();
+
+ // readjust for position at the edge of a line. This is to exclude line rect that doesn't need to be accounted in the range bounds
+ if (rect2.y() != rect1.y()) {
+ VisiblePosition endOfFirstLine = endOfLine(range.start);
+ if (range.start == endOfFirstLine) {
+ range.start.setAffinity(DOWNSTREAM);
+ rect1 = range.start.caretRect();
+ }
+ if (range.end == endOfFirstLine) {
+ range.end.setAffinity(UPSTREAM);
+ rect2 = range.end.caretRect();
+ }
+ }
+
+ IntRect ourrect = rect1;
+ ourrect.unite(rect2);
+
+ // if the rectangle spans lines and contains multiple text chars, use the range's bounding box intead
+ if (rect1.bottom() != rect2.bottom()) {
+ RefPtr<Range> dataRange = makeRange(range.start, range.end);
+ IntRect boundingBox = dataRange->boundingBox();
+ String rangeString = plainText(dataRange.get());
+ if (rangeString.length() > 1 && !boundingBox.isEmpty())
+ ourrect = boundingBox;
+ }
+
+#if PLATFORM(MAC)
+ return m_renderer->document()->view()->contentsToScreen(ourrect);
+#else
+ return ourrect;
+#endif
+}
+
+void AccessibilityRenderObject::setSelectedVisiblePositionRange(const VisiblePositionRange& range) const
+{
+ if (range.start.isNull() || range.end.isNull())
+ return;
+
+ // make selection and tell the document to use it. if it's zero length, then move to that position
+ if (range.start == range.end) {
+ m_renderer->document()->frame()->selection()->moveTo(range.start, true);
+ }
+ else {
+ Selection newSelection = Selection(range.start, range.end);
+ m_renderer->document()->frame()->selection()->setSelection(newSelection);
+ }
+}
+
+VisiblePosition AccessibilityRenderObject::visiblePositionForPoint(const IntPoint& point) const
+{
+ // convert absolute point to view coordinates
+ FrameView* frameView = m_renderer->document()->topDocument()->renderer()->view()->frameView();
+ RenderObject* renderer = topRenderer();
+ Node* innerNode = 0;
+
+ // locate the node containing the point
+ IntPoint pointResult;
+ while (1) {
+ IntPoint ourpoint;
+#if PLATFORM(MAC)
+ ourpoint = frameView->screenToContents(point);
+#else
+ ourpoint = point;
+#endif
+ HitTestRequest request(true, true);
+ HitTestResult result(ourpoint);
+ renderer->layer()->hitTest(request, result);
+ innerNode = result.innerNode();
+ if (!innerNode || !innerNode->renderer())
+ return VisiblePosition();
+
+ pointResult = result.localPoint();
+
+ // done if hit something other than a widget
+ renderer = innerNode->renderer();
+ if (!renderer->isWidget())
+ break;
+
+ // descend into widget (FRAME, IFRAME, OBJECT...)
+ Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
+ if (!widget || !widget->isFrameView())
+ break;
+ Frame* frame = static_cast<FrameView*>(widget)->frame();
+ if (!frame)
+ break;
+ Document* document = frame->document();
+ if (!document)
+ break;
+ renderer = document->renderer();
+ frameView = static_cast<FrameView*>(widget);
+ }
+
+ return innerNode->renderer()->positionForPoint(pointResult);
+}
+
+// NOTE: Consider providing this utility method as AX API
+VisiblePosition AccessibilityRenderObject::visiblePositionForIndex(unsigned indexValue, bool lastIndexOK) const
+{
+ if (!isTextControl())
+ return VisiblePosition();
+
+ // lastIndexOK specifies whether the position after the last character is acceptable
+ if (indexValue >= text().length()) {
+ if (!lastIndexOK || indexValue > text().length())
+ return VisiblePosition();
+ }
+ VisiblePosition position = visiblePositionForIndex(indexValue);
+ position.setAffinity(DOWNSTREAM);
+ return position;
+}
+
+// NOTE: Consider providing this utility method as AX API
+int AccessibilityRenderObject::index(const VisiblePosition& position) const
+{
+ if (!isTextControl())
+ return -1;
+
+ Node* node = position.deepEquivalent().node();
+ if (!node)
+ return -1;
+
+ for (RenderObject* renderer = node->renderer(); renderer && renderer->element(); renderer = renderer->parent()) {
+ if (renderer == m_renderer)
+ return indexForVisiblePosition(position);
+ }
+
+ return -1;
+}
+
+// Given a line number, the range of characters of the text associated with this accessibility
+// object that contains the line number.
+PlainTextRange AccessibilityRenderObject::doAXRangeForLine(unsigned lineNumber) const
+{
+ if (!isTextControl())
+ return PlainTextRange();
+
+ // iterate to the specified line
+ VisiblePosition visiblePos = visiblePositionForIndex(0);
+ VisiblePosition savedVisiblePos;
+ for (unsigned lineCount = lineNumber; lineCount != 0; lineCount -= 1) {
+ savedVisiblePos = visiblePos;
+ visiblePos = nextLinePosition(visiblePos, 0);
+ if (visiblePos.isNull() || visiblePos == savedVisiblePos)
+ return PlainTextRange();
+ }
+
+ // make a caret selection for the marker position, then extend it to the line
+ // NOTE: ignores results of selection.modify because it returns false when
+ // starting at an empty line. The resulting selection in that case
+ // will be a caret at visiblePos.
+ SelectionController selection;
+ selection.setSelection(Selection(visiblePos));
+ selection.modify(SelectionController::EXTEND, SelectionController::LEFT, LineBoundary);
+ selection.modify(SelectionController::EXTEND, SelectionController::RIGHT, LineBoundary);
+
+ // calculate the indices for the selection start and end
+ VisiblePosition startPosition = selection.selection().visibleStart();
+ VisiblePosition endPosition = selection.selection().visibleEnd();
+ int index1 = indexForVisiblePosition(startPosition);
+ int index2 = indexForVisiblePosition(endPosition);
+
+ // add one to the end index for a line break not caused by soft line wrap (to match AppKit)
+ if (endPosition.affinity() == DOWNSTREAM && endPosition.next().isNotNull())
+ index2 += 1;
+
+ // return nil rather than an zero-length range (to match AppKit)
+ if (index1 == index2)
+ return PlainTextRange();
+
+ return PlainTextRange(index1, index2 - index1);
+}
+
+// The composed character range in the text associated with this accessibility object that
+// is specified by the given index value. This parameterized attribute returns the complete
+// range of characters (including surrogate pairs of multi-byte glyphs) at the given index.
+PlainTextRange AccessibilityRenderObject::doAXRangeForIndex(unsigned index) const
+{
+ if (!isTextControl())
+ return PlainTextRange();
+
+ String elementText = text();
+ if (!elementText.length() || index > elementText.length() - 1)
+ return PlainTextRange();
+
+ return PlainTextRange(index, 1);
+}
+
+// A substring of the text associated with this accessibility object that is
+// specified by the given character range.
+String AccessibilityRenderObject::doAXStringForRange(const PlainTextRange& range) const
+{
+ if (isPasswordField())
+ return String();
+
+ if (range.length == 0)
+ return "";
+
+ if (!isTextControl())
+ return String();
+
+ String elementText = text();
+ if (range.start + range.length > elementText.length())
+ return String();
+
+ return elementText.substring(range.start, range.length);
+}
+
+// The bounding rectangle of the text associated with this accessibility object that is
+// specified by the given range. This is the bounding rectangle a sighted user would see
+// on the display screen, in pixels.
+IntRect AccessibilityRenderObject::doAXBoundsForRange(const PlainTextRange& range) const
+{
+ if (isTextControl())
+ return boundsForVisiblePositionRange(visiblePositionRangeForRange(range));
+ return IntRect();
+}
+
+AccessibilityObject* AccessibilityRenderObject::doAccessibilityHitTest(const IntPoint& point) const
+{
+ if (!m_renderer)
+ return 0;
+
+ RenderLayer* layer = m_renderer->layer();
+ if (!layer)
+ return 0;
+
+ HitTestRequest request(true, true);
+ HitTestResult hitTestResult = HitTestResult(point);
+ layer->hitTest(request, hitTestResult);
+ if (!hitTestResult.innerNode())
+ return 0;
+ Node* node = hitTestResult.innerNode()->shadowAncestorNode();
+ RenderObject* obj = node->renderer();
+ if (!obj)
+ return 0;
+
+ AccessibilityObject *result = obj->document()->axObjectCache()->get(obj);
+
+ if (obj->isListBox())
+ return static_cast<AccessibilityListBox*>(result)->doAccessibilityHitTest(point);
+
+ if (result->accessibilityIsIgnored())
+ result = result->parentObjectUnignored();
+
+ return result;
+}
+
+AccessibilityObject* AccessibilityRenderObject::focusedUIElement() const
+{
+ // get the focused node in the page
+ Page* page = m_renderer->document()->page();
+ if (!page)
+ return 0;
+
+ Document* focusedDocument = page->focusController()->focusedOrMainFrame()->document();
+ Node* focusedNode = focusedDocument->focusedNode();
+ if (!focusedNode)
+ focusedNode = focusedDocument;
+
+ RenderObject* focusedNodeRenderer = focusedNode->renderer();
+ if (!focusedNodeRenderer)
+ return 0;
+
+ AccessibilityObject* obj = focusedNodeRenderer->document()->axObjectCache()->get(focusedNodeRenderer);
+
+ if (obj->shouldFocusActiveDescendant()) {
+ if (AccessibilityObject* descendant = obj->activeDescendant())
+ obj = descendant;
+ }
+
+ // the HTML element, for example, is focusable but has an AX object that is ignored
+ if (obj->accessibilityIsIgnored())
+ obj = obj->parentObjectUnignored();
+
+ return obj;
+}
+
+bool AccessibilityRenderObject::shouldFocusActiveDescendant() const
+{
+ switch (ariaRoleAttribute()) {
+ case GroupRole:
+ case ComboBoxRole:
+ case ListBoxRole:
+ case MenuRole:
+ case MenuBarRole:
+ case RadioGroupRole:
+ case RowRole:
+ case PopUpButtonRole:
+ case ProgressIndicatorRole:
+ case ToolbarRole:
+ case OutlineRole:
+ /* FIXME: replace these with actual roles when they are added to AccessibilityRole
+ composite
+ alert
+ alertdialog
+ grid
+ status
+ timer
+ tree
+ */
+ return true;
+ default:
+ return false;
+ }
+}
+
+AccessibilityObject* AccessibilityRenderObject::activeDescendant() const
+{
+ if (renderer()->element() && !renderer()->element()->isElementNode())
+ return 0;
+ Element* element = static_cast<Element*>(renderer()->element());
+
+ String activeDescendantAttrStr = element->getAttribute(aria_activedescendantAttr).string();
+ if (activeDescendantAttrStr.isNull() || activeDescendantAttrStr.isEmpty())
+ return 0;
+
+ Element* target = renderer()->document()->getElementById(activeDescendantAttrStr);
+ AccessibilityObject* obj = renderer()->document()->axObjectCache()->get(target->renderer());
+ if (obj->isAccessibilityRenderObject())
+ // an activedescendant is only useful if it has a renderer, because that's what's needed to post the notification
+ return obj;
+ return 0;
+}
+
+
+void AccessibilityRenderObject::handleActiveDescendantChanged()
+{
+ Element* element = static_cast<Element*>(renderer()->element());
+ if (!element)
+ return;
+ Document* doc = renderer()->document();
+ if (!doc->frame()->selection()->isFocusedAndActive() || doc->focusedNode() != element)
+ return;
+ AccessibilityRenderObject* activedescendant = static_cast<AccessibilityRenderObject*>(activeDescendant());
+
+ if (activedescendant && shouldFocusActiveDescendant())
+ doc->axObjectCache()->postNotificationToElement(activedescendant->renderer(), "AXFocusedUIElementChanged");
+}
+
+
+AccessibilityObject* AccessibilityRenderObject::observableObject() const
+{
+ for (RenderObject* renderer = m_renderer; renderer && renderer->element(); renderer = renderer->parent()) {
+ if (renderer->isTextField() || renderer->isTextArea())
+ return renderer->document()->axObjectCache()->get(renderer);
+ }
+
+ return 0;
+}
+
+typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap;
+
+static const ARIARoleMap& createARIARoleMap()
+{
+ struct RoleEntry {
+ String ariaRole;
+ AccessibilityRole webcoreRole;
+ };
+
+ static const RoleEntry roles[] = {
+ { "button", ButtonRole },
+ { "checkbox", CheckBoxRole },
+ { "group", GroupRole },
+ { "heading", HeadingRole },
+ { "img", ImageRole },
+ { "link", WebCoreLinkRole },
+ { "listbox", ListBoxRole },
+ // "option" isn't here because it may map to different roles depending on the parent element's role
+ { "menu", MenuRole },
+ { "menubar", GroupRole },
+ // "menuitem" isn't here because it may map to different roles depending on the parent element's role
+ { "menuitemcheckbox", MenuItemRole },
+ { "menuitemradio", MenuItemRole },
+ { "progressbar", ProgressIndicatorRole },
+ { "radio", RadioButtonRole },
+ { "range", SliderRole },
+ { "slider", SliderRole },
+ { "spinbutton", ProgressIndicatorRole },
+ { "textbox", TextAreaRole }
+ };
+ ARIARoleMap& roleMap = *new ARIARoleMap;
+
+ const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
+ for (unsigned i = 0; i < numRoles; ++i)
+ roleMap.set(roles[i].ariaRole, roles[i].webcoreRole);
+ return roleMap;
+}
+
+static AccessibilityRole ariaRoleToWebCoreRole(String value)
+{
+ ASSERT(!value.isEmpty() && !value.isNull());
+ static const ARIARoleMap& roleMap = createARIARoleMap();
+ return roleMap.get(value);
+}
+
+AccessibilityRole AccessibilityRenderObject::determineAriaRoleAttribute() const
+{
+ String ariaRole = getAttribute(roleAttr).string();
+ if (ariaRole.isNull() || ariaRole.isEmpty())
+ return UnknownRole;
+
+ AccessibilityRole role = ariaRoleToWebCoreRole(ariaRole);
+ if (role)
+ return role;
+ // selects and listboxes both have options as child roles, but they map to different roles within WebCore
+ if (equalIgnoringCase(ariaRole,"option")) {
+ if (parentObjectUnignored()->ariaRoleAttribute() == MenuRole)
+ return MenuItemRole;
+ if (parentObjectUnignored()->ariaRoleAttribute() == ListBoxRole)
+ return ListBoxOptionRole;
+ }
+ // an aria "menuitem" may map to MenuButton or MenuItem depending on its parent
+ if (equalIgnoringCase(ariaRole,"menuitem")) {
+ if (parentObjectUnignored()->ariaRoleAttribute() == GroupRole)
+ return MenuButtonRole;
+ if (parentObjectUnignored()->ariaRoleAttribute() == MenuRole)
+ return MenuItemRole;
+ }
+
+ return UnknownRole;
+}
+
+void AccessibilityRenderObject::setAriaRole()
+{
+ m_ariaRole = determineAriaRoleAttribute();
+}
+
+AccessibilityRole AccessibilityRenderObject::ariaRoleAttribute() const
+{
+ return m_ariaRole;
+}
+
+AccessibilityRole AccessibilityRenderObject::roleValue() const
+{
+ if (!m_renderer)
+ return UnknownRole;
+
+ Node* node = m_renderer->element();
+ AccessibilityRole ariaRole = ariaRoleAttribute();
+ if (ariaRole != UnknownRole)
+ return ariaRole;
+
+ if (node && node->isLink()) {
+ if (m_renderer->isImage())
+ return ImageMapRole;
+ return WebCoreLinkRole;
+ }
+ if (m_renderer->isListMarker())
+ return ListMarkerRole;
+ if (node && node->hasTagName(buttonTag))
+ return ButtonRole;
+ if (m_renderer->isText())
+ return StaticTextRole;
+ if (m_renderer->isImage()) {
+ if (node && node->hasTagName(inputTag))
+ return ButtonRole;
+ return ImageRole;
+ }
+ if (m_renderer->isRenderView())
+ return WebAreaRole;
+
+ if (m_renderer->isTextField())
+ return TextFieldRole;
+
+ if (m_renderer->isTextArea())
+ return TextAreaRole;
+
+ if (node && node->hasTagName(inputTag)) {
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
+ if (input->inputType() == HTMLInputElement::CHECKBOX)
+ return CheckBoxRole;
+ if (input->inputType() == HTMLInputElement::RADIO)
+ return RadioButtonRole;
+ if (input->isTextButton())
+ return ButtonRole;
+ }
+
+ if (node && node->hasTagName(buttonTag))
+ return ButtonRole;
+
+ if (isFileUploadButton())
+ return ButtonRole;
+
+ if (m_renderer->isMenuList())
+ return PopUpButtonRole;
+
+ if (headingLevel(m_renderer->element()) != 0)
+ return HeadingRole;
+
+ if (node && node->hasTagName(ddTag))
+ return DefinitionListDefinitionRole;
+
+ if (node && node->hasTagName(dtTag))
+ return DefinitionListTermRole;
+
+ if (m_renderer->isBlockFlow() || (node && node->hasTagName(labelTag)))
+ return GroupRole;
+
+ return UnknownRole;
+}
+
+bool AccessibilityRenderObject::isPresentationalChildOfAriaRole() const
+{
+ // Walk the parent chain looking for a parent that has presentational children
+ AccessibilityObject* parent;
+ for (parent = parentObject(); parent && !parent->ariaRoleHasPresentationalChildren(); parent = parent->parentObject())
+ ;
+ return parent;
+}
+
+bool AccessibilityRenderObject::ariaRoleHasPresentationalChildren() const
+{
+ switch (m_ariaRole) {
+ case ButtonRole:
+ case SliderRole:
+ case ImageRole:
+ case ProgressIndicatorRole:
+ //case SeparatorRole:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool AccessibilityRenderObject::canSetFocusAttribute() const
+{
+ // NOTE: It would be more accurate to ask the document whether setFocusedNode() would
+ // do anything. For example, it setFocusedNode() will do nothing if the current focused
+ // node will not relinquish the focus.
+ if (!m_renderer->element() || !m_renderer->element()->isEnabled())
+ return false;
+
+ switch (roleValue()) {
+ case WebCoreLinkRole:
+ case ImageMapLinkRole:
+ case TextFieldRole:
+ case TextAreaRole:
+ case ButtonRole:
+ case PopUpButtonRole:
+ case CheckBoxRole:
+ case RadioButtonRole:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool AccessibilityRenderObject::canSetValueAttribute() const
+{
+ if (isWebArea())
+ return !isReadOnly();
+
+ return isTextControl() || isProgressIndicator() || isSlider();
+}
+
+bool AccessibilityRenderObject::canSetTextRangeAttributes() const
+{
+ return isTextControl();
+}
+
+void AccessibilityRenderObject::childrenChanged()
+{
+ clearChildren();
+
+ if (accessibilityIsIgnored()) {
+ AccessibilityObject* parent = parentObject();
+ if (parent)
+ parent->childrenChanged();
+ }
+}
+
+bool AccessibilityRenderObject::canHaveChildren() const
+{
+ if (!m_renderer)
+ return false;
+
+ // Elements that should not have children
+ switch (roleValue()) {
+ case ImageRole:
+ case ButtonRole:
+ case PopUpButtonRole:
+ case CheckBoxRole:
+ case RadioButtonRole:
+ return false;
+ default:
+ return true;
+ }
+}
+
+const AccessibilityObject::AccessibilityChildrenVector& AccessibilityRenderObject::children()
+{
+ if (!m_haveChildren)
+ addChildren();
+ return m_children;
+}
+
+void AccessibilityRenderObject::addChildren()
+{
+ // If the need to add more children in addition to existing children arises,
+ // childrenChanged should have been called, leaving the object with no children.
+ ASSERT(!m_haveChildren);
+
+ // nothing to add if there is no RenderObject
+ if (!m_renderer)
+ return;
+
+ m_haveChildren = true;
+
+ if (!canHaveChildren())
+ return;
+
+ // add all unignored acc children
+ for (RefPtr<AccessibilityObject> obj = firstChild(); obj; obj = obj->nextSibling()) {
+ if (obj->accessibilityIsIgnored()) {
+ if (!obj->hasChildren())
+ obj->addChildren();
+ AccessibilityChildrenVector children = obj->children();
+ unsigned length = children.size();
+ for (unsigned i = 0; i < length; ++i)
+ m_children.append(children[i]);
+ } else
+ m_children.append(obj);
+ }
+
+ // for a RenderImage, add the <area> elements as individual accessibility objects
+ if (m_renderer->isRenderImage()) {
+ HTMLMapElement* map = static_cast<RenderImage*>(m_renderer)->imageMap();
+ if (map) {
+ for (Node* current = map->firstChild(); current; current = current->traverseNextNode(map)) {
+
+ // add an <area> element for this child if it has a link
+ if (current->isLink()) {
+ AccessibilityImageMapLink* areaObject = static_cast<AccessibilityImageMapLink*>(m_renderer->document()->axObjectCache()->get(ImageMapLinkRole));
+ areaObject->setHTMLAreaElement(static_cast<HTMLAreaElement*>(current));
+ areaObject->setHTMLMapElement(map);
+ areaObject->setParent(this);
+
+ m_children.append(areaObject);
+ }
+ }
+ }
+ }
+}
+
+void AccessibilityRenderObject::ariaListboxSelectedChildren(AccessibilityChildrenVector& result)
+{
+ AccessibilityObject* child = firstChild();
+ bool isMultiselectable = false;
+
+ Element* element = static_cast<Element*>(renderer()->element());
+ if (!element || !element->isElementNode()) // do this check to ensure safety of static_cast above
+ return;
+
+ String multiselectablePropertyStr = element->getAttribute("aria-multiselectable").string();
+ isMultiselectable = equalIgnoringCase(multiselectablePropertyStr, "true");
+
+ while (child) {
+ // every child should have aria-role option, and if so, check for selected attribute/state
+ AccessibilityRole ariaRole = child->ariaRoleAttribute();
+ RenderObject* childRenderer = 0;
+ if (child->isAccessibilityRenderObject())
+ childRenderer = static_cast<AccessibilityRenderObject*>(child)->renderer();
+ if (childRenderer && ariaRole == ListBoxOptionRole) {
+ Element* childElement = static_cast<Element*>(childRenderer->element());
+ if (childElement && childElement->isElementNode()) { // do this check to ensure safety of static_cast above
+ String selectedAttrString = childElement->getAttribute("aria-selected").string();
+ if (equalIgnoringCase(selectedAttrString, "true")) {
+ result.append(child);
+ if (isMultiselectable)
+ return;
+ }
+ }
+ }
+ child = child->nextSibling();
+ }
+}
+
+void AccessibilityRenderObject::selectedChildren(AccessibilityChildrenVector& result)
+{
+ ASSERT(result.isEmpty());
+
+ // only listboxes should be asked for their selected children.
+ if (ariaRoleAttribute() != ListBoxRole) { // native list boxes would be AccessibilityListBoxes, so only check for aria list boxes
+ ASSERT_NOT_REACHED();
+ return;
+ }
+ return ariaListboxSelectedChildren(result);
+}
+
+void AccessibilityRenderObject::ariaListboxVisibleChildren(AccessibilityChildrenVector& result)
+{
+ if (!hasChildren())
+ addChildren();
+
+ unsigned length = m_children.size();
+ for (unsigned i = 0; i < length; i++) {
+ if (!m_children[i]->isOffScreen())
+ result.append(m_children[i]);
+ }
+}
+
+void AccessibilityRenderObject::visibleChildren(AccessibilityChildrenVector& result)
+{
+ ASSERT(result.isEmpty());
+
+ // only listboxes are asked for their visible children.
+ if (ariaRoleAttribute() != ListBoxRole) { // native list boxes would be AccessibilityListBoxes, so only check for aria list boxes
+ ASSERT_NOT_REACHED();
+ return;
+ }
+ return ariaListboxVisibleChildren(result);
+}
+
+void AccessibilityRenderObject::removeAXObjectID()
+{
+ if (!m_id)
+ return;
+#if PLATFORM(MAC)
+ m_renderer->document()->axObjectCache()->removeAXID(this);
+#endif
+}
+
+const String& AccessibilityRenderObject::actionVerb() const
+{
+ // FIXME: Need to add verbs for select elements.
+ static const String buttonAction = AXButtonActionVerb();
+ static const String textFieldAction = AXTextFieldActionVerb();
+ static const String radioButtonAction = AXRadioButtonActionVerb();
+ static const String checkedCheckBoxAction = AXCheckedCheckBoxActionVerb();
+ static const String uncheckedCheckBoxAction = AXUncheckedCheckBoxActionVerb();
+ static const String linkAction = AXLinkActionVerb();
+ static const String noAction;
+
+ switch (roleValue()) {
+ case ButtonRole:
+ return buttonAction;
+ case TextFieldRole:
+ case TextAreaRole:
+ return textFieldAction;
+ case RadioButtonRole:
+ return radioButtonAction;
+ case CheckBoxRole:
+ return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction;
+ case LinkRole:
+ case WebCoreLinkRole:
+ return linkAction;
+ default:
+ return noAction;
+ }
+}
+
+
+} // namespace WebCore
diff --git a/WebCore/page/AccessibilityRenderObject.h b/WebCore/page/AccessibilityRenderObject.h
new file mode 100644
index 0000000..c859b5a
--- /dev/null
+++ b/WebCore/page/AccessibilityRenderObject.h
@@ -0,0 +1,236 @@
+/*
+ * 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 AccessibilityRenderObject_h
+#define AccessibilityRenderObject_h
+
+#include "AccessibilityObject.h"
+
+namespace WebCore {
+
+class AXObjectCache;
+class Element;
+class Frame;
+class FrameView;
+class HitTestResult;
+class HTMLAnchorElement;
+class HTMLAreaElement;
+class HTMLElement;
+class HTMLLabelElement;
+class HTMLMapElement;
+class HTMLSelectElement;
+class IntPoint;
+class IntSize;
+class Node;
+class RenderObject;
+class RenderListBox;
+class RenderTextControl;
+class Selection;
+class String;
+class Widget;
+
+class AccessibilityRenderObject : public AccessibilityObject {
+protected:
+ AccessibilityRenderObject(RenderObject*);
+public:
+ static PassRefPtr<AccessibilityRenderObject> create(RenderObject*);
+ virtual ~AccessibilityRenderObject();
+
+ bool isAccessibilityRenderObject() const { return true; };
+
+ virtual bool isAnchor() const;
+ virtual bool isAttachment() const;
+ virtual bool isHeading() const;
+ virtual bool isLink() const;
+ virtual bool isImageButton() const;
+ virtual bool isImage() const;
+ virtual bool isNativeImage() const;
+ virtual bool isPasswordField() const;
+ virtual bool isTextControl() const;
+ virtual bool isNativeTextControl() const;
+ virtual bool isWebArea() const;
+ virtual bool isCheckboxOrRadio() const;
+ virtual bool isFileUploadButton() const;
+ virtual bool isProgressIndicator() const;
+ virtual bool isSlider() const;
+ virtual bool isMenuRelated() const;
+ virtual bool isMenu() const;
+ virtual bool isMenuBar() const;
+ virtual bool isMenuButton() const;
+ virtual bool isMenuItem() const;
+ virtual bool isControl() const;
+ virtual bool isFieldset() const;
+
+ virtual bool isEnabled() const;
+ virtual bool isSelected() const;
+ virtual bool isFocused() const;
+ virtual bool isChecked() const;
+ virtual bool isHovered() const;
+ virtual bool isIndeterminate() const;
+ virtual bool isLoaded() const;
+ virtual bool isMultiSelect() const;
+ virtual bool isOffScreen() const;
+ virtual bool isPressed() const;
+ virtual bool isReadOnly() const;
+ virtual bool isVisited() const;
+
+ const AtomicString& getAttribute(const QualifiedName&) const;
+ virtual bool canSetFocusAttribute() const;
+ virtual bool canSetTextRangeAttributes() const;
+ virtual bool canSetValueAttribute() const;
+
+ virtual bool hasIntValue() const;
+
+ virtual bool accessibilityIsIgnored() const;
+
+ static int headingLevel(Node*);
+ virtual int intValue() const;
+ virtual float valueForRange() const;
+ virtual float maxValueForRange() const;
+ virtual float minValueForRange() const;
+ virtual int layoutCount() const;
+
+ virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&) const;
+ virtual AccessibilityObject* focusedUIElement() const;
+ virtual AccessibilityObject* firstChild() const;
+ virtual AccessibilityObject* lastChild() const;
+ virtual AccessibilityObject* previousSibling() const;
+ virtual AccessibilityObject* nextSibling() const;
+ virtual AccessibilityObject* parentObject() const;
+ virtual AccessibilityObject* observableObject() const;
+ virtual void linkedUIElements(AccessibilityChildrenVector&) const;
+ virtual AccessibilityObject* titleUIElement() const;
+ virtual AccessibilityRole ariaRoleAttribute() const;
+ virtual bool isPresentationalChildOfAriaRole() const;
+ virtual bool ariaRoleHasPresentationalChildren() const;
+ void setAriaRole();
+ virtual AccessibilityRole roleValue() const;
+ virtual AXObjectCache* axObjectCache() const;
+
+ virtual Element* actionElement() const;
+ Element* mouseButtonListener() const;
+ FrameView* frameViewIfRenderView() const;
+ virtual Element* anchorElement() const;
+ AccessibilityObject* menuForMenuButton() const;
+ AccessibilityObject* menuButtonForMenu() const;
+
+ virtual IntRect boundingBoxRect() const;
+ virtual IntRect elementRect() const;
+ virtual IntSize size() const;
+
+ void setRenderer(RenderObject* renderer) { m_renderer = renderer; }
+ RenderObject* renderer() const { return m_renderer; }
+ RenderObject* topRenderer() const;
+ RenderTextControl* textControl() const;
+ Document* document() const;
+ FrameView* topDocumentFrameView() const;
+ HTMLLabelElement* labelElementContainer() const;
+
+ virtual KURL url() const;
+ virtual PlainTextRange selectedTextRange() const;
+ virtual Selection selection() const;
+ virtual String stringValue() const;
+ virtual String ariaAccessiblityName(const String&) const;
+ virtual String ariaLabeledByAttribute() const;
+ virtual String title() const;
+ virtual String ariaDescribedByAttribute() const;
+ virtual String accessibilityDescription() const;
+ virtual String helpText() const;
+ virtual String textUnderElement() const;
+ virtual String text() const;
+ virtual int textLength() const;
+ virtual PassRefPtr<Range> ariaSelectedTextDOMRange() const;
+ virtual String selectedText() const;
+ virtual const AtomicString& accessKey() const;
+ virtual const String& actionVerb() const;
+ virtual Widget* widget() const;
+ virtual Widget* widgetForAttachmentView() const;
+ virtual void getDocumentLinks(AccessibilityChildrenVector&);
+ virtual FrameView* documentFrameView() const;
+
+ virtual const AccessibilityChildrenVector& children();
+
+ virtual void setFocused(bool);
+ virtual void setSelectedTextRange(const PlainTextRange&);
+ virtual void setValue(const String&);
+
+ virtual void detach();
+ virtual void childrenChanged();
+ virtual void addChildren();
+ virtual bool canHaveChildren() const;
+ virtual void selectedChildren(AccessibilityChildrenVector&);
+ virtual void visibleChildren(AccessibilityChildrenVector&);
+ virtual bool shouldFocusActiveDescendant() const;
+ virtual AccessibilityObject* activeDescendant() const;
+ virtual void handleActiveDescendantChanged();
+
+ virtual VisiblePositionRange visiblePositionRange() const;
+ virtual VisiblePositionRange visiblePositionRangeForLine(unsigned) const;
+ virtual IntRect boundsForVisiblePositionRange(const VisiblePositionRange&) const;
+ virtual void setSelectedVisiblePositionRange(const VisiblePositionRange&) const;
+
+ virtual VisiblePosition visiblePositionForPoint(const IntPoint&) const;
+ virtual VisiblePosition visiblePositionForIndex(unsigned indexValue, bool lastIndexOK) const;
+ virtual int index(const VisiblePosition&) const;
+
+ virtual VisiblePosition visiblePositionForIndex(int) const;
+ virtual int indexForVisiblePosition(const VisiblePosition&) const;
+
+ virtual PlainTextRange doAXRangeForLine(unsigned) const;
+ virtual PlainTextRange doAXRangeForIndex(unsigned) const;
+
+ virtual String doAXStringForRange(const PlainTextRange&) const;
+ virtual IntRect doAXBoundsForRange(const PlainTextRange&) const;
+
+protected:
+ RenderObject* m_renderer;
+ AccessibilityRole m_ariaRole;
+
+ void setRenderObject(RenderObject* renderer) { m_renderer = renderer; }
+ virtual void removeAXObjectID();
+
+ virtual bool isDetached() const { return !m_renderer; }
+
+private:
+ void ariaListboxSelectedChildren(AccessibilityChildrenVector&);
+ void ariaListboxVisibleChildren(AccessibilityChildrenVector&);
+
+ Element* menuElementForMenuButton() const;
+ Element* menuItemElementForMenu() const;
+ AccessibilityRole determineAriaRoleAttribute() const;
+
+ IntRect checkboxOrRadioRect() const;
+ void addRadioButtonGroupMembers(AccessibilityChildrenVector& linkedUIElements) const;
+ AccessibilityObject* internalLinkElement() const;
+ AccessibilityObject* accessibilityParentForImageMap(HTMLMapElement* map) const;
+
+};
+
+} // namespace WebCore
+
+#endif // AccessibilityRenderObject_h
diff --git a/WebCore/page/AccessibilityTable.cpp b/WebCore/page/AccessibilityTable.cpp
new file mode 100644
index 0000000..11c36ef
--- /dev/null
+++ b/WebCore/page/AccessibilityTable.cpp
@@ -0,0 +1,491 @@
+/*
+ * 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 "AccessibilityTable.h"
+
+#include "AccessibilityTableCell.h"
+#include "AccessibilityTableColumn.h"
+#include "AccessibilityTableHeaderContainer.h"
+#include "AccessibilityTableRow.h"
+#include "AXObjectCache.h"
+#include "HTMLNames.h"
+#include "HTMLTableElement.h"
+#include "HTMLTableCaptionElement.h"
+#include "HTMLTableCellElement.h"
+#include "RenderObject.h"
+#include "RenderTable.h"
+#include "RenderTableCell.h"
+#include "RenderTableSection.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+AccessibilityTable::AccessibilityTable(RenderObject* renderer)
+ : AccessibilityRenderObject(renderer),
+ m_headerContainer(0)
+{
+ // AXTables should not appear in tiger or leopard, on the mac
+#if PLATFORM(MAC) && (defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD))
+ m_isAccessibilityTable = false;
+#else
+ m_isAccessibilityTable = isTableExposableThroughAccessibility();
+#endif
+
+}
+
+AccessibilityTable::~AccessibilityTable()
+{
+}
+
+PassRefPtr<AccessibilityTable> AccessibilityTable::create(RenderObject* renderer)
+{
+ return adoptRef(new AccessibilityTable(renderer));
+}
+
+bool AccessibilityTable::isTableExposableThroughAccessibility()
+{
+ // the following is a heuristic used to determine if a
+ // <table> should be exposed as an AXTable. The goal
+ // is to only show "data" tables
+
+ if (!m_renderer || !m_renderer->isTable())
+ return false;
+
+ // if the developer assigned an aria role to this, then we shouldn't
+ // expose it as a table, unless, of course, the aria role is a table
+ AccessibilityRole ariaRole = ariaRoleAttribute();
+ if (ariaRole == TableRole)
+ return true;
+ if (ariaRole != UnknownRole)
+ return false;
+
+ RenderTable* table = static_cast<RenderTable*>(m_renderer);
+
+ // this employs a heuristic to determine if this table should appear.
+ // Only "data" tables should be exposed as tables.
+ // Unfortunately, there is no good way to determine the difference
+ // between a "layout" table and a "data" table
+
+ Node* tableNode = table->element();
+ if (!tableNode || !tableNode->hasTagName(tableTag))
+ return false;
+
+ // if there is a caption element, summary, THEAD, or TFOOT section, it's most certainly a data table
+ HTMLTableElement* tableElement = static_cast<HTMLTableElement*>(tableNode);
+ if (!tableElement->summary().isEmpty() || tableElement->tHead() || tableElement->tFoot() || tableElement->caption())
+ return true;
+
+ // if someone used "rules" attribute than the table should appear
+ if (!tableElement->rules().isEmpty())
+ return true;
+
+ // go through the cell's and check for tell-tale signs of "data" table status
+ // cells have borders, or use attributes like headers, abbr, scope or axis
+ RenderTableSection* firstBody = table->firstBody();
+ if (!firstBody)
+ return false;
+
+ int numCols = firstBody->numColumns();
+ int numRows = firstBody->numRows();
+
+ // if there's only one cell, it's not a good AXTable candidate
+ if (numRows == 1 && numCols == 1)
+ return false;
+
+ // store the background color of the table to check against cell's background colors
+ RenderStyle* tableStyle = table->style();
+ if (!tableStyle)
+ return false;
+ Color tableBGColor = tableStyle->backgroundColor();
+
+ // check enough of the cells to find if the table matches our criteria
+ // Criteria:
+ // 1) must have at least one valid cell (and)
+ // 2) at least half of cells have borders (or)
+ // 3) at least half of cells have different bg colors than the table, and there is cell spacing
+ unsigned validCellCount = 0;
+ unsigned borderedCellCount = 0;
+ unsigned backgroundDifferenceCellCount = 0;
+
+ for (int row = 0; row < numRows; ++row) {
+ for (int col = 0; col < numCols; ++col) {
+ RenderTableCell* cell = firstBody->cellAt(row, col).cell;
+ if (!cell)
+ continue;
+ Node* cellNode = cell->element();
+ if (!cellNode)
+ continue;
+
+ if (cell->width() < 1 || cell->height() < 1)
+ continue;
+
+ validCellCount++;
+
+ HTMLTableCellElement* cellElement = static_cast<HTMLTableCellElement*>(cellNode);
+
+ // in this case, the developer explicitly assigned a "data" table attribute
+ if (!cellElement->headers().isEmpty() || !cellElement->abbr().isEmpty() ||
+ !cellElement->axis().isEmpty() || !cellElement->scope().isEmpty())
+ return true;
+
+ RenderStyle* renderStyle = cell->style();
+ if (!renderStyle)
+ continue;
+
+ // a cell needs to have matching bordered sides, before it can be considered a bordered cell.
+ if ((cell->borderTop() > 0 && cell->borderBottom() > 0) ||
+ (cell->borderLeft() > 0 && cell->borderRight() > 0))
+ borderedCellCount++;
+
+ // if the cell has a different color from the table and there is cell spacing,
+ // then it is probably a data table cell (spacing and colors take the place of borders)
+ Color cellColor = renderStyle->backgroundColor();
+ if (table->hBorderSpacing() > 0 && table->vBorderSpacing() > 0 &&
+ tableBGColor != cellColor && cellColor.alpha() != 1)
+ backgroundDifferenceCellCount++;
+
+ // if we've found 10 "good" cells, we don't need to keep searching
+ if (borderedCellCount >= 10 || backgroundDifferenceCellCount >= 10)
+ return true;
+ }
+ }
+
+ // if there is less than two valid cells, it's not a data table
+ if (validCellCount <= 1)
+ return false;
+
+ // half of the cells had borders, it's a data table
+ unsigned neededCellCount = validCellCount / 2;
+ if (borderedCellCount >= neededCellCount)
+ return true;
+
+ // half had different background colors, it's a data table
+ if (backgroundDifferenceCellCount >= neededCellCount)
+ return true;
+
+ return false;
+}
+
+void AccessibilityTable::clearChildren()
+{
+ m_children.clear();
+ m_rows.clear();
+ m_columns.clear();
+ m_haveChildren = false;
+}
+
+void AccessibilityTable::addChildren()
+{
+ if (!isDataTable()) {
+ AccessibilityRenderObject::addChildren();
+ return;
+ }
+
+ ASSERT(!m_haveChildren);
+
+ m_haveChildren = true;
+ if (!m_renderer)
+ return;
+
+ RenderTable* table = static_cast<RenderTable*>(m_renderer);
+ AXObjectCache* axCache = m_renderer->document()->axObjectCache();
+
+ // go through all the available sections to pull out the rows
+ // and add them as children
+ RenderTableSection* tableSection = table->header();
+ if (!tableSection)
+ tableSection = table->firstBody();
+
+ if (!tableSection)
+ return;
+
+ RenderTableSection* initialTableSection = tableSection;
+
+ while (tableSection) {
+
+ HashSet<AccessibilityObject*> appendedRows;
+
+ unsigned numRows = tableSection->numRows();
+ unsigned numCols = tableSection->numColumns();
+ for (unsigned rowIndex = 0; rowIndex < numRows; ++rowIndex) {
+ for (unsigned colIndex = 0; colIndex < numCols; ++colIndex) {
+
+ RenderTableCell* cell = tableSection->cellAt(rowIndex, colIndex).cell;
+ if (!cell)
+ continue;
+
+ AccessibilityObject* rowObject = axCache->get(cell->parent());
+ if (!rowObject->isTableRow())
+ continue;
+
+ AccessibilityTableRow* row = static_cast<AccessibilityTableRow*>(rowObject);
+ // we need to check every cell for a new row, because cell spans
+ // can cause us to mess rows if we just check the first column
+ if (appendedRows.contains(row))
+ continue;
+
+ row->setRowIndex((int)m_rows.size());
+ m_rows.append(row);
+ m_children.append(row);
+ appendedRows.add(row);
+ }
+ }
+
+ tableSection = table->sectionBelow(tableSection, true);
+ }
+
+ // make the columns based on the number of columns in the first body
+ unsigned length = initialTableSection->numColumns();
+ for (unsigned i = 0; i < length; ++i) {
+ AccessibilityTableColumn* column = static_cast<AccessibilityTableColumn*>(axCache->get(ColumnRole));
+ column->setColumnIndex((int)i);
+ column->setParentTable(this);
+ m_columns.append(column);
+ m_children.append(column);
+ }
+
+ AccessibilityObject* headerContainerObject = headerContainer();
+ if (headerContainerObject)
+ m_children.append(headerContainerObject);
+}
+
+AccessibilityObject* AccessibilityTable::headerContainer()
+{
+ if (m_headerContainer)
+ return m_headerContainer;
+
+ m_headerContainer = static_cast<AccessibilityTableHeaderContainer*>(axObjectCache()->get(TableHeaderContainerRole));
+ m_headerContainer->setParentTable(this);
+
+ return m_headerContainer;
+}
+
+AccessibilityObject::AccessibilityChildrenVector& AccessibilityTable::columns()
+{
+ if (!hasChildren())
+ addChildren();
+
+ return m_columns;
+}
+
+AccessibilityObject::AccessibilityChildrenVector& AccessibilityTable::rows()
+{
+ if (!hasChildren())
+ addChildren();
+
+ return m_rows;
+}
+
+void AccessibilityTable::rowHeaders(AccessibilityChildrenVector& headers)
+{
+ if (!m_renderer)
+ return;
+
+ if (!hasChildren())
+ addChildren();
+
+ unsigned rowCount = m_rows.size();
+ for (unsigned k = 0; k < rowCount; ++k) {
+ AccessibilityObject* header = static_cast<AccessibilityTableRow*>(m_rows[k].get())->headerObject();
+ if (!header)
+ continue;
+ headers.append(header);
+ }
+}
+
+void AccessibilityTable::columnHeaders(AccessibilityChildrenVector& headers)
+{
+ if (!m_renderer)
+ return;
+
+ if (!hasChildren())
+ addChildren();
+
+ unsigned colCount = m_columns.size();
+ for (unsigned k = 0; k < colCount; ++k) {
+ AccessibilityObject* header = static_cast<AccessibilityTableColumn*>(m_columns[k].get())->headerObject();
+ if (!header)
+ continue;
+ headers.append(header);
+ }
+}
+
+void AccessibilityTable::cells(AccessibilityObject::AccessibilityChildrenVector& cells)
+{
+ if (!m_renderer)
+ return;
+
+ if (!hasChildren())
+ addChildren();
+
+ int numRows = m_rows.size();
+ for (int row = 0; row < numRows; ++row) {
+ AccessibilityChildrenVector rowChildren = m_rows[row]->children();
+ cells.append(rowChildren);
+ }
+}
+
+const unsigned AccessibilityTable::columnCount()
+{
+ if (!hasChildren())
+ addChildren();
+
+ return m_columns.size();
+}
+
+const unsigned AccessibilityTable::rowCount()
+{
+ if (!hasChildren())
+ addChildren();
+
+ return m_rows.size();
+}
+
+AccessibilityTableCell* AccessibilityTable::cellForColumnAndRow(unsigned column, unsigned row)
+{
+ if (!m_renderer)
+ return 0;
+
+ if (!hasChildren())
+ addChildren();
+
+ RenderTable* table = static_cast<RenderTable*>(m_renderer);
+ RenderTableSection* tableSection = table->header();
+ if (!tableSection)
+ tableSection = table->firstBody();
+
+ RenderTableCell* cell = 0;
+ unsigned rowCount = 0;
+ unsigned rowOffset = 0;
+ while (tableSection) {
+
+ rowCount += tableSection->numRows();
+ unsigned numCols = tableSection->numColumns();
+
+ if (row < rowCount && column < numCols) {
+ int sectionSpecificRow = row - rowOffset;
+ cell = tableSection->cellAt(sectionSpecificRow, column).cell;
+
+ // we didn't find the cell, which means there's spanning happening
+ // search backwards to find the spanning cell
+ if (!cell) {
+
+ // first try rows
+ for (int testRow = sectionSpecificRow-1; testRow >= 0; --testRow) {
+ cell = tableSection->cellAt(testRow, column).cell;
+ // cell overlapped. use this one
+ if (cell && ((cell->row() + (cell->rowSpan()-1)) >= (int)sectionSpecificRow))
+ break;
+ cell = 0;
+ }
+
+ if (!cell) {
+ // try cols
+ for (int testCol = column-1; testCol >= 0; --testCol) {
+ cell = tableSection->cellAt(sectionSpecificRow, testCol).cell;
+ // cell overlapped. use this one
+ if (cell && ((cell->col() + (cell->colSpan()-1)) >= (int)column))
+ break;
+ cell = 0;
+ }
+ }
+ }
+ }
+
+ if (cell)
+ break;
+
+ rowOffset += rowCount;
+ // we didn't find anything between the rows we should have
+ if (row < rowOffset)
+ break;
+ tableSection = table->sectionBelow(tableSection, true);
+ }
+
+ if (!cell)
+ return 0;
+
+ AccessibilityObject* cellObject = axObjectCache()->get(cell);
+ ASSERT(cellObject->isTableCell());
+
+ return static_cast<AccessibilityTableCell*>(cellObject);
+}
+
+AccessibilityRole AccessibilityTable::roleValue() const
+{
+ if (!isDataTable())
+ return AccessibilityRenderObject::roleValue();
+
+ return TableRole;
+}
+
+bool AccessibilityTable::accessibilityIsIgnored() const
+{
+ if (!isDataTable())
+ return AccessibilityRenderObject::accessibilityIsIgnored();
+
+ return false;
+}
+
+String AccessibilityTable::title() const
+{
+ if (!isDataTable())
+ return AccessibilityRenderObject::title();
+
+ String title;
+ if (!m_renderer)
+ return title;
+
+ // see if there is a caption
+ Node *tableElement = m_renderer->element();
+ if (tableElement) {
+ HTMLTableCaptionElement* caption = static_cast<HTMLTableElement*>(tableElement)->caption();
+ if (caption)
+ title = caption->innerText();
+ }
+
+ // try the standard
+ if (title.isEmpty())
+ title = AccessibilityRenderObject::title();
+
+ return title;
+}
+
+bool AccessibilityTable::isDataTable() const
+{
+ if (!m_renderer)
+ return false;
+
+ return m_isAccessibilityTable;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/AccessibilityTable.h b/WebCore/page/AccessibilityTable.h
new file mode 100644
index 0000000..b98b6b7
--- /dev/null
+++ b/WebCore/page/AccessibilityTable.h
@@ -0,0 +1,86 @@
+/*
+ * 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 AccessibilityTable_h
+#define AccessibilityTable_h
+
+#include "AccessibilityRenderObject.h"
+
+namespace WebCore {
+
+class String;
+class AccessibilityTableCell;
+class AccessibilityTableHeaderContainer;
+
+class AccessibilityTable : public AccessibilityRenderObject {
+
+private:
+ AccessibilityTable(RenderObject*);
+public:
+ static PassRefPtr<AccessibilityTable> create(RenderObject*);
+ virtual ~AccessibilityTable();
+
+ virtual bool isDataTable() const;
+ virtual AccessibilityRole roleValue() const;
+
+ virtual bool accessibilityIsIgnored() const;
+
+ virtual void addChildren();
+ virtual void clearChildren();
+
+ AccessibilityChildrenVector& columns();
+ AccessibilityChildrenVector& rows();
+
+ const unsigned columnCount();
+ const unsigned rowCount();
+
+ virtual String title() const;
+
+ // all the cells in the table
+ void cells(AccessibilityChildrenVector&);
+ AccessibilityTableCell* cellForColumnAndRow(unsigned column, unsigned row);
+
+ void columnHeaders(AccessibilityChildrenVector&);
+ void rowHeaders(AccessibilityChildrenVector&);
+
+ // an object that contains, as children, all the objects that act as headers
+ AccessibilityObject* headerContainer();
+
+private:
+ AccessibilityChildrenVector m_rows;
+ AccessibilityChildrenVector m_columns;
+
+ AccessibilityTableHeaderContainer* m_headerContainer;
+ mutable bool m_isAccessibilityTable;
+
+ bool isTableExposableThroughAccessibility();
+};
+
+} // namespace WebCore
+
+#endif // AccessibilityTable_h
diff --git a/WebCore/page/AccessibilityTableCell.cpp b/WebCore/page/AccessibilityTableCell.cpp
new file mode 100644
index 0000000..2062a88
--- /dev/null
+++ b/WebCore/page/AccessibilityTableCell.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 "AccessibilityTableCell.h"
+
+#include "AXObjectCache.h"
+#include "RenderObject.h"
+#include "RenderTableCell.h"
+
+using namespace std;
+
+namespace WebCore {
+
+AccessibilityTableCell::AccessibilityTableCell(RenderObject* renderer)
+ : AccessibilityRenderObject(renderer)
+{
+}
+
+AccessibilityTableCell::~AccessibilityTableCell()
+{
+}
+
+PassRefPtr<AccessibilityTableCell> AccessibilityTableCell::create(RenderObject* renderer)
+{
+ return adoptRef(new AccessibilityTableCell(renderer));
+}
+
+bool AccessibilityTableCell::accessibilityIsIgnored() const
+{
+ if (!isTableCell())
+ return AccessibilityRenderObject::accessibilityIsIgnored();
+
+ return false;
+}
+
+bool AccessibilityTableCell::isTableCell() const
+{
+ if (!m_renderer)
+ return false;
+
+ AccessibilityObject* renderTable = axObjectCache()->get(static_cast<RenderTableCell*>(m_renderer)->table());
+ if (!renderTable->isDataTable())
+ return false;
+
+ return true;
+}
+
+AccessibilityRole AccessibilityTableCell::roleValue() const
+{
+ if (!isTableCell())
+ return AccessibilityRenderObject::roleValue();
+
+ return CellRole;
+}
+
+void AccessibilityTableCell::rowIndexRange(pair<int, int>& rowRange)
+{
+ if (!m_renderer)
+ return;
+
+ RenderTableCell *renderCell = static_cast<RenderTableCell*>(m_renderer);
+ rowRange.first = renderCell->row();
+ rowRange.second = renderCell->rowSpan();
+
+ // since our table might have multiple sections, we have to offset our row appropriately
+ RenderTableSection* section = renderCell->section();
+ RenderTable* table = renderCell->table();
+ if (!table || !section)
+ return;
+
+ RenderTableSection* tableSection = table->header();
+ if (!tableSection)
+ tableSection = table->firstBody();
+
+ unsigned rowOffset = 0;
+ while (tableSection) {
+ if (tableSection == section)
+ break;
+ rowOffset += tableSection->numRows();
+ tableSection = table->sectionBelow(tableSection, true);
+ }
+
+ rowRange.first += rowOffset;
+}
+
+void AccessibilityTableCell::columnIndexRange(pair<int, int>& columnRange)
+{
+ if (!m_renderer)
+ return;
+
+ RenderTableCell *renderCell = static_cast<RenderTableCell*>(m_renderer);
+ columnRange.first = renderCell->col();
+ columnRange.second = renderCell->colSpan();
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/AccessibilityTableCell.h b/WebCore/page/AccessibilityTableCell.h
new file mode 100644
index 0000000..e77dfb2
--- /dev/null
+++ b/WebCore/page/AccessibilityTableCell.h
@@ -0,0 +1,61 @@
+/*
+ * 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 AccessibilityTableCell_h
+#define AccessibilityTableCell_h
+
+#include "AccessibilityRenderObject.h"
+
+namespace WebCore {
+
+class AccessibilityTableCell : public AccessibilityRenderObject {
+
+private:
+ AccessibilityTableCell(RenderObject*);
+public:
+ static PassRefPtr<AccessibilityTableCell> create(RenderObject*);
+ virtual ~AccessibilityTableCell();
+
+ virtual bool isTableCell() const;
+ virtual AccessibilityRole roleValue() const;
+
+ virtual bool accessibilityIsIgnored() const;
+
+ // fills in the start location and row span of cell
+ void rowIndexRange(pair<int, int>& rowRange);
+ // fills in the start location and column span of cell
+ void columnIndexRange(pair<int, int>& columnRange);
+
+private:
+ int m_rowIndex;
+
+};
+
+} // namespace WebCore
+
+#endif // AccessibilityTableCell_h
diff --git a/WebCore/page/AccessibilityTableColumn.cpp b/WebCore/page/AccessibilityTableColumn.cpp
new file mode 100644
index 0000000..6e03af9
--- /dev/null
+++ b/WebCore/page/AccessibilityTableColumn.cpp
@@ -0,0 +1,167 @@
+/*
+ * 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 "AccessibilityTableColumn.h"
+
+#include "AccessibilityTableCell.h"
+#include "AXObjectCache.h"
+#include "HTMLNames.h"
+#include "RenderTable.h"
+#include "RenderTableSection.h"
+#include "RenderTableCell.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+AccessibilityTableColumn::AccessibilityTableColumn()
+ : m_parentTable(0)
+{
+}
+
+AccessibilityTableColumn::~AccessibilityTableColumn()
+{
+}
+
+PassRefPtr<AccessibilityTableColumn> AccessibilityTableColumn::create()
+{
+ return adoptRef(new AccessibilityTableColumn());
+}
+
+void AccessibilityTableColumn::setParentTable(AccessibilityTable* table)
+{
+ m_parentTable = table;
+
+ clearChildren();
+ addChildren();
+}
+
+IntRect AccessibilityTableColumn::elementRect() const
+{
+ // this will be filled in when addChildren is called
+ return m_columnRect;
+}
+
+IntSize AccessibilityTableColumn::size() const
+{
+ return elementRect().size();
+}
+
+const AccessibilityObject::AccessibilityChildrenVector& AccessibilityTableColumn::children()
+{
+ if (!m_haveChildren)
+ addChildren();
+ return m_children;
+}
+
+AccessibilityObject* AccessibilityTableColumn::headerObject()
+{
+ if (!m_parentTable)
+ return 0;
+
+ RenderTable* table = static_cast<RenderTable*>(m_parentTable->renderer());
+
+ AccessibilityObject* headerObject = 0;
+
+ // try the <thead> section first. this doesn't require th tags
+ headerObject = headerObjectForSection(table->header(), false);
+
+ if (headerObject)
+ return headerObject;
+
+ // now try for <th> tags in the first body
+ headerObject = headerObjectForSection(table->firstBody(), true);
+
+ return headerObject;
+}
+
+AccessibilityObject* AccessibilityTableColumn::headerObjectForSection(RenderTableSection* section, bool thTagRequired)
+{
+ if (!section)
+ return 0;
+
+ int numCols = section->numColumns();
+ if (m_columnIndex >= numCols)
+ return 0;
+
+ RenderTableCell* cell = 0;
+ // also account for cells that have a span
+ for (int testCol = m_columnIndex; testCol >= 0; --testCol) {
+ RenderTableCell* testCell = section->cellAt(0, testCol).cell;
+ if (!testCell)
+ continue;
+
+ // we've reached a cell that doesn't even overlap our column
+ // it can't be our header
+ if ((testCell->col() + (testCell->colSpan()-1)) < m_columnIndex)
+ break;
+
+ Node* node = testCell->element();
+ if (!node)
+ continue;
+
+ if (thTagRequired && !node->hasTagName(thTag))
+ continue;
+
+ cell = testCell;
+ }
+
+ if (!cell)
+ return 0;
+
+ return m_parentTable->axObjectCache()->get(cell);
+}
+
+void AccessibilityTableColumn::addChildren()
+{
+ ASSERT(!m_haveChildren);
+
+ m_haveChildren = true;
+ if (!m_parentTable)
+ return;
+
+ int numRows = m_parentTable->rowCount();
+
+ for (int i = 0; i < numRows; i++) {
+ AccessibilityTableCell* cell = m_parentTable->cellForColumnAndRow(m_columnIndex, i);
+ if (!cell)
+ continue;
+
+ // make sure the last one isn't the same as this one (rowspan cells)
+ if (m_children.size() > 0 && m_children.last() == cell)
+ continue;
+
+ m_children.append(cell);
+ m_columnRect.unite(cell->elementRect());
+ }
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/AccessibilityTableColumn.h b/WebCore/page/AccessibilityTableColumn.h
new file mode 100644
index 0000000..6270398
--- /dev/null
+++ b/WebCore/page/AccessibilityTableColumn.h
@@ -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.
+ */
+
+#ifndef AccessibilityTableColumn_h
+#define AccessibilityTableColumn_h
+
+#include "AccessibilityObject.h"
+#include "AccessibilityTable.h"
+#include "IntRect.h"
+
+namespace WebCore {
+
+class RenderTableSection;
+
+class AccessibilityTableColumn : public AccessibilityObject {
+
+private:
+ AccessibilityTableColumn();
+public:
+ static PassRefPtr<AccessibilityTableColumn> create();
+ virtual ~AccessibilityTableColumn();
+
+ void setParentTable(AccessibilityTable*);
+ virtual AccessibilityObject* parentObject() const { return m_parentTable; }
+ AccessibilityObject* headerObject();
+
+ virtual AccessibilityRole roleValue() const { return ColumnRole; }
+ virtual bool accessibilityIsIgnored() const { return false; }
+ virtual bool isTableColumn() const { return true; }
+
+ void setColumnIndex(int columnIndex) { m_columnIndex = columnIndex; }
+ int columnIndex() const { return m_columnIndex; }
+
+ virtual const AccessibilityChildrenVector& children();
+ virtual void addChildren();
+
+ virtual IntSize size() const;
+ virtual IntRect elementRect() const;
+
+private:
+ AccessibilityTable* m_parentTable;
+ int m_columnIndex;
+ IntRect m_columnRect;
+
+ AccessibilityObject* headerObjectForSection(RenderTableSection*, bool thTagRequired);
+};
+
+} // namespace WebCore
+
+#endif // AccessibilityTableColumn_h
diff --git a/WebCore/page/AccessibilityTableHeaderContainer.cpp b/WebCore/page/AccessibilityTableHeaderContainer.cpp
new file mode 100644
index 0000000..af9de39
--- /dev/null
+++ b/WebCore/page/AccessibilityTableHeaderContainer.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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 "AccessibilityTableHeaderContainer.h"
+
+#include "AccessibilityTable.h"
+#include "AXObjectCache.h"
+
+using namespace std;
+
+namespace WebCore {
+
+AccessibilityTableHeaderContainer::AccessibilityTableHeaderContainer()
+ : m_parentTable(0)
+{
+}
+
+AccessibilityTableHeaderContainer::~AccessibilityTableHeaderContainer()
+{
+}
+
+PassRefPtr<AccessibilityTableHeaderContainer> AccessibilityTableHeaderContainer::create()
+{
+ return adoptRef(new AccessibilityTableHeaderContainer());
+}
+
+const AccessibilityObject::AccessibilityChildrenVector& AccessibilityTableHeaderContainer::children()
+{
+ if (!m_haveChildren)
+ addChildren();
+ return m_children;
+}
+
+IntRect AccessibilityTableHeaderContainer::elementRect() const
+{
+ // this will be filled in when addChildren is called
+ return m_headerRect;
+}
+
+IntSize AccessibilityTableHeaderContainer::size() const
+{
+ return elementRect().size();
+}
+
+void AccessibilityTableHeaderContainer::addChildren()
+{
+ ASSERT(!m_haveChildren);
+
+ m_haveChildren = true;
+ if (!m_parentTable || !m_parentTable->isDataTable())
+ return;
+
+ static_cast<AccessibilityTable*>(m_parentTable)->columnHeaders(m_children);
+
+ unsigned length = m_children.size();
+ for (unsigned k = 0; k < length; ++k) {
+ m_headerRect.unite(m_children[k]->elementRect());
+ }
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/AccessibilityTableHeaderContainer.h b/WebCore/page/AccessibilityTableHeaderContainer.h
new file mode 100644
index 0000000..8a9448a
--- /dev/null
+++ b/WebCore/page/AccessibilityTableHeaderContainer.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.
+ * 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 AccessibilityTableHeaderContainer_h
+#define AccessibilityTableHeaderContainer_h
+
+#include "AccessibilityObject.h"
+#include "AccessibilityTable.h"
+#include "IntRect.h"
+
+namespace WebCore {
+
+class AccessibilityTableHeaderContainer : public AccessibilityObject {
+
+private:
+ AccessibilityTableHeaderContainer();
+public:
+ static PassRefPtr<AccessibilityTableHeaderContainer> create();
+ virtual ~AccessibilityTableHeaderContainer();
+
+ virtual AccessibilityRole roleValue() const { return TableHeaderContainerRole; }
+
+ void setParentTable(AccessibilityTable* table) { m_parentTable = table; }
+ virtual AccessibilityObject* parentObject() const { return m_parentTable; }
+
+ virtual bool accessibilityIsIgnored() const { return false; }
+
+ virtual const AccessibilityChildrenVector& children();
+ virtual void addChildren();
+
+ virtual IntSize size() const;
+ virtual IntRect elementRect() const;
+
+private:
+ AccessibilityTable* m_parentTable;
+ IntRect m_headerRect;
+
+};
+
+} // namespace WebCore
+
+#endif // AccessibilityTableHeaderContainer_h
diff --git a/WebCore/page/AccessibilityTableRow.cpp b/WebCore/page/AccessibilityTableRow.cpp
new file mode 100644
index 0000000..caccff5
--- /dev/null
+++ b/WebCore/page/AccessibilityTableRow.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 "AccessibilityTableRow.h"
+
+#include "AccessibilityTableCell.h"
+#include "AXObjectCache.h"
+#include "HTMLNames.h"
+#include "HTMLTableRowElement.h"
+#include "RenderObject.h"
+#include "RenderTableCell.h"
+#include "RenderTableRow.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+AccessibilityTableRow::AccessibilityTableRow(RenderObject* renderer)
+ : AccessibilityRenderObject(renderer)
+{
+}
+
+AccessibilityTableRow::~AccessibilityTableRow()
+{
+}
+
+PassRefPtr<AccessibilityTableRow> AccessibilityTableRow::create(RenderObject* renderer)
+{
+ return adoptRef(new AccessibilityTableRow(renderer));
+}
+
+AccessibilityRole AccessibilityTableRow::roleValue() const
+{
+ if (!isTableRow())
+ return AccessibilityRenderObject::roleValue();
+
+ return RowRole;
+}
+
+bool AccessibilityTableRow::isTableRow() const
+{
+ if (!m_renderer)
+ return true;
+
+ AccessibilityObject* renderTable = axObjectCache()->get(static_cast<RenderTableRow*>(m_renderer)->table());
+ if (!renderTable->isDataTable())
+ return false;
+
+ return true;
+}
+
+bool AccessibilityTableRow::accessibilityIsIgnored() const
+{
+ if (!isTableRow())
+ return AccessibilityRenderObject::accessibilityIsIgnored();
+
+ return false;
+}
+
+AccessibilityObject* AccessibilityTableRow::headerObject()
+{
+ AccessibilityChildrenVector rowChildren = children();
+ if (!rowChildren.size())
+ return 0;
+
+ // check the first element in the row to see if it is a TH element
+ AccessibilityObject* cell = rowChildren[0].get();
+ if (!cell->isTableCell())
+ return 0;
+
+ RenderObject* cellRenderer = static_cast<AccessibilityTableCell*>(cell)->renderer();
+ if (!cellRenderer)
+ return 0;
+
+ Node* cellNode = cellRenderer->element();
+ if (!cellNode || !cellNode->hasTagName(thTag))
+ return 0;
+
+ return cell;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/AccessibilityTableRow.h b/WebCore/page/AccessibilityTableRow.h
new file mode 100644
index 0000000..0ec7f04
--- /dev/null
+++ b/WebCore/page/AccessibilityTableRow.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.
+ * 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 AccessibilityTableRow_h
+#define AccessibilityTableRow_h
+
+#include "AccessibilityRenderObject.h"
+
+namespace WebCore {
+
+class AccessibilityTableRow : public AccessibilityRenderObject {
+
+private:
+ AccessibilityTableRow(RenderObject*);
+public:
+ static PassRefPtr<AccessibilityTableRow> create(RenderObject*);
+ virtual ~AccessibilityTableRow();
+
+ virtual bool isTableRow() const;
+ virtual AccessibilityRole roleValue() const;
+
+ // retrieves the "row" header (a th tag in the rightmost column)
+ AccessibilityObject* headerObject();
+
+ virtual bool accessibilityIsIgnored() const;
+
+ void setRowIndex(int rowIndex) { m_rowIndex = rowIndex; }
+ int rowIndex() const { return m_rowIndex; }
+
+ // allows the table to add other children that may not originate
+ // in the row, but their col/row spans overlap into it
+ void appendChild(AccessibilityObject*);
+
+private:
+ int m_rowIndex;
+};
+
+} // namespace WebCore
+
+#endif // AccessibilityTableRow_h
diff --git a/WebCore/page/BarInfo.cpp b/WebCore/page/BarInfo.cpp
new file mode 100644
index 0000000..153aee0
--- /dev/null
+++ b/WebCore/page/BarInfo.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.
+ * 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)
+{
+}
+
+void BarInfo::disconnectFrame()
+{
+ m_frame = 0;
+}
+
+bool BarInfo::visible() const
+{
+ if (!m_frame)
+ return false;
+
+ switch (m_type) {
+ case Locationbar:
+ return m_frame->page()->chrome()->toolbarsVisible();
+ case Toolbar:
+ return m_frame->page()->chrome()->toolbarsVisible();
+ case Personalbar:
+ return m_frame->page()->chrome()->toolbarsVisible();
+ case Menubar:
+ return m_frame->page()->chrome()->menubarVisible();
+ case Scrollbars:
+ return m_frame->page()->chrome()->scrollbarsVisible();
+ case Statusbar:
+ return m_frame->page()->chrome()->statusbarVisible();
+ default:
+ return false;
+ }
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/BarInfo.h b/WebCore/page/BarInfo.h
new file mode 100644
index 0000000..4cbbcfc
--- /dev/null
+++ b/WebCore/page/BarInfo.h
@@ -0,0 +1,57 @@
+/*
+ * 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)); }
+
+ void disconnectFrame();
+
+ bool visible() const;
+
+ private:
+ BarInfo(Frame*, Type);
+ Frame* m_frame;
+ Type m_type;
+ };
+
+} // namespace WebCore
+
+#endif // BarInfo_h
diff --git a/WebCore/page/BarInfo.idl b/WebCore/page/BarInfo.idl
new file mode 100644
index 0000000..42041c51
--- /dev/null
+++ b/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 BarInfo {
+ readonly attribute boolean visible;
+ };
+
+}
diff --git a/WebCore/page/Chrome.cpp b/WebCore/page/Chrome.cpp
new file mode 100644
index 0000000..c9b57f2
--- /dev/null
+++ b/WebCore/page/Chrome.cpp
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2006, 2007 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 "Chrome.h"
+
+#include "ChromeClient.h"
+#include "DNS.h"
+#include "Document.h"
+#include "FileList.h"
+#include "FloatRect.h"
+#include "Frame.h"
+#include "FrameTree.h"
+#include "HTMLFormElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "HitTestResult.h"
+#include "InspectorController.h"
+#include "Page.h"
+#include "PageGroup.h"
+#include "PausedTimeouts.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 "SessionStorage.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace std;
+
+class PageGroupLoadDeferrer : Noncopyable {
+public:
+ PageGroupLoadDeferrer(Page*, bool deferSelf);
+ ~PageGroupLoadDeferrer();
+private:
+ Vector<RefPtr<Frame>, 16> m_deferredFrames;
+#if !PLATFORM(MAC)
+ Vector<pair<RefPtr<Frame>, PausedTimeouts*>, 16> m_pausedTimeouts;
+#endif
+};
+
+Chrome::Chrome(Page* page, ChromeClient* client)
+ : m_page(page)
+ , m_client(client)
+{
+ ASSERT(m_client);
+}
+
+Chrome::~Chrome()
+{
+ m_client->chromeDestroyed();
+}
+
+void Chrome::repaint(const IntRect& windowRect, bool contentChanged, bool immediate, bool repaintContentOnly)
+{
+ m_client->repaint(windowRect, contentChanged, immediate, repaintContentOnly);
+}
+
+void Chrome::scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
+{
+ m_client->scroll(scrollDelta, rectToScroll, clipRect);
+}
+
+IntPoint Chrome::screenToWindow(const IntPoint& point) const
+{
+ return m_client->screenToWindow(point);
+}
+
+IntRect Chrome::windowToScreen(const IntRect& rect) const
+{
+ return m_client->windowToScreen(rect);
+}
+
+PlatformWidget Chrome::platformWindow() const
+{
+ return m_client->platformWindow();
+}
+
+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);
+}
+
+Page* Chrome::createWindow(Frame* frame, const FrameLoadRequest& request, const WindowFeatures& features) const
+{
+ Page* newPage = m_client->createWindow(frame, request, features);
+#if ENABLE(DOM_STORAGE)
+
+ if (newPage) {
+ if (SessionStorage* oldSessionStorage = m_page->sessionStorage(false))
+ newPage->setSessionStorage(oldSessionStorage->copy(newPage));
+ }
+#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);
+ String text = message;
+ text.replace('\\', frame->backslashAsCurrencySymbol());
+
+ m_client->runJavaScriptAlert(frame, text);
+}
+
+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);
+ String text = message;
+ text.replace('\\', frame->backslashAsCurrencySymbol());
+
+ return m_client->runJavaScriptConfirm(frame, text);
+}
+
+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);
+ String promptText = prompt;
+ promptText.replace('\\', frame->backslashAsCurrencySymbol());
+ String defaultValueText = defaultValue;
+ defaultValueText.replace('\\', frame->backslashAsCurrencySymbol());
+
+ bool ok = m_client->runJavaScriptPrompt(frame, promptText, defaultValueText, result);
+
+ if (ok)
+ result.replace(frame->backslashAsCurrencySymbol(), '\\');
+
+ return ok;
+}
+
+void Chrome::setStatusbarText(Frame* frame, const String& status)
+{
+ ASSERT(frame);
+ String text = status;
+ text.replace('\\', frame->backslashAsCurrencySymbol());
+
+ m_client->setStatusbarText(text);
+}
+
+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())
+ prefetchDNS(result.absoluteLinkURL().host());
+ }
+ m_client->mouseDidMoveOverElement(result, modifierFlags);
+
+ if (InspectorController* inspector = m_page->inspectorController())
+ inspector->mouseDidMoveOverElement(result, modifierFlags);
+}
+
+void Chrome::setToolTip(const HitTestResult& result)
+{
+ // First priority is a potential toolTip representing a spelling or grammar error
+ String toolTip = result.spellingToolTip();
+
+ // 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->inputType() == HTMLInputElement::SUBMIT)
+ if (HTMLFormElement* form = input->form())
+ toolTip = form->action();
+ }
+ }
+
+ // 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();
+ }
+
+ // Next we'll consider a tooltip for element with "title" attribute
+ if (toolTip.isEmpty())
+ toolTip = result.title();
+
+ // 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->inputType() == HTMLInputElement::FILE) {
+ 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);
+ }
+ }
+ }
+ }
+ }
+
+ m_client->setToolTip(toolTip);
+}
+
+void Chrome::print(Frame* frame)
+{
+ m_client->print(frame);
+}
+
+void Chrome::disableSuddenTermination()
+{
+ m_client->disableSuddenTermination();
+}
+
+void Chrome::enableSuddenTermination()
+{
+ m_client->enableSuddenTermination();
+}
+
+void Chrome::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> fileChooser)
+{
+ m_client->runOpenPanel(frame, fileChooser);
+}
+// --------
+
+#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();
+}
+
+void ChromeClient::disableSuddenTermination()
+{
+}
+
+void ChromeClient::enableSuddenTermination()
+{
+}
+
+bool ChromeClient::paintCustomScrollbar(GraphicsContext*, const FloatRect&, ScrollbarControlSize,
+ ScrollbarControlState, ScrollbarPart, bool vertical,
+ float value, float proportion, ScrollbarControlPartMask)
+{
+ return false;
+}
+
+bool ChromeClient::paintCustomScrollCorner(GraphicsContext*, const FloatRect&)
+{
+ return false;
+}
+
+// --------
+
+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());
+
+#if !PLATFORM(MAC)
+ for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ OwnPtr<PausedTimeouts> timeouts;
+ frame->script()->pauseTimeouts(timeouts);
+ if (timeouts)
+ m_pausedTimeouts.append(make_pair(RefPtr<Frame>(frame), timeouts.release()));
+ }
+#endif
+ }
+ }
+
+ 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);
+
+#if !PLATFORM(MAC)
+ for (size_t i = 0; i < m_pausedTimeouts.size(); i++) {
+ Frame* frame = m_pausedTimeouts[i].first.get();
+ OwnPtr<PausedTimeouts> timeouts(m_pausedTimeouts[i].second);
+ frame->script()->resumeTimeouts(timeouts);
+ }
+#endif
+}
+
+
+} // namespace WebCore
diff --git a/WebCore/page/Chrome.h b/WebCore/page/Chrome.h
new file mode 100644
index 0000000..0dd4013
--- /dev/null
+++ b/WebCore/page/Chrome.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2006, 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.
+ */
+
+#ifndef Chrome_h
+#define Chrome_h
+
+#include "FileChooser.h"
+#include "FocusDirection.h"
+#include "HostWindow.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 HitTestResult;
+ class IntRect;
+ class Page;
+ class String;
+
+ struct FrameLoadRequest;
+ struct WindowFeatures;
+
+ class Chrome : public HostWindow {
+ public:
+ Chrome(Page*, ChromeClient*);
+ ~Chrome();
+
+ ChromeClient* client() { return m_client; }
+
+ // HostWindow methods.
+ virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false);
+ virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect);
+ virtual IntPoint screenToWindow(const IntPoint&) const;
+ virtual IntRect windowToScreen(const IntRect&) const;
+ virtual PlatformWidget platformWindow() 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;
+
+ Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&) 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*);
+
+ void enableSuddenTermination();
+ void disableSuddenTermination();
+
+ void runOpenPanel(Frame*, PassRefPtr<FileChooser>);
+
+#if PLATFORM(MAC)
+ void focusNSView(NSView*);
+#endif
+
+ private:
+ Page* m_page;
+ ChromeClient* m_client;
+ };
+}
+
+#endif // Chrome_h
diff --git a/WebCore/page/ChromeClient.h b/WebCore/page/ChromeClient.h
new file mode 100644
index 0000000..7678dc2
--- /dev/null
+++ b/WebCore/page/ChromeClient.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2006, 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.
+ */
+
+#ifndef ChromeClient_h
+#define ChromeClient_h
+
+#include "GraphicsContext.h"
+#include "FocusDirection.h"
+#include "ScrollTypes.h"
+#include "HostWindow.h"
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(MAC)
+#include "WebCoreKeyboardUIMode.h"
+#endif
+
+#ifndef __OBJC__
+class NSMenu;
+class NSResponder;
+#endif
+
+namespace WebCore {
+
+ class AtomicString;
+ class FileChooser;
+ class FloatRect;
+ class Frame;
+ class HitTestResult;
+ class IntRect;
+ class Node;
+ class Page;
+ class String;
+ class Widget;
+
+ struct FrameLoadRequest;
+ struct WindowFeatures;
+
+ 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;
+
+ // 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&) = 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(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 repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false) = 0;
+ virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) = 0;
+ virtual IntPoint screenToWindow(const IntPoint&) const = 0;
+ virtual IntRect windowToScreen(const IntRect&) const = 0;
+ virtual PlatformWidget platformWindow() const = 0;
+ // End methods used by HostWindow.
+
+ virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags) = 0;
+
+ virtual void setToolTip(const String&) = 0;
+
+ virtual void print(Frame*) = 0;
+
+ virtual void exceededDatabaseQuota(Frame*, const String& databaseName) = 0;
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ virtual void dashboardRegionsChanged();
+#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 void enableSuddenTermination();
+ virtual void disableSuddenTermination();
+
+ virtual bool paintCustomScrollbar(GraphicsContext*, const FloatRect&, ScrollbarControlSize,
+ ScrollbarControlState, ScrollbarPart pressedPart, bool vertical,
+ float value, float proportion, ScrollbarControlPartMask);
+ virtual bool paintCustomScrollCorner(GraphicsContext*, const FloatRect&);
+
+ virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>) = 0;
+
+#if PLATFORM(MAC)
+ virtual KeyboardUIMode keyboardUIMode() { return KeyboardAccessDefault; }
+
+ virtual NSResponder *firstResponder() { return 0; }
+ virtual void makeFirstResponder(NSResponder *) { }
+
+ virtual void willPopUpMenu(NSMenu *) { }
+#endif
+
+ protected:
+ virtual ~ChromeClient() { }
+ };
+
+}
+
+#endif // ChromeClient_h
diff --git a/WebCore/page/Console.cpp b/WebCore/page/Console.cpp
new file mode 100644
index 0000000..bfcc478
--- /dev/null
+++ b/WebCore/page/Console.cpp
@@ -0,0 +1,481 @@
+/*
+ * 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 "ChromeClient.h"
+#include "CString.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "InspectorController.h"
+#include "JSDOMBinding.h"
+#include "Page.h"
+#include "PageGroup.h"
+#include "PlatformString.h"
+#include <runtime/ArgList.h>
+#include <kjs/interpreter.h>
+#include <runtime/JSObject.h>
+#include <VM/Machine.h>
+#include <profiler/Profiler.h>
+#include <stdio.h>
+
+using namespace JSC;
+
+namespace WebCore {
+
+Console::Console(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+void Console::disconnectFrame()
+{
+ 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 XMLMessageSource:
+ sourceString = "XML";
+ break;
+ case JSMessageSource:
+ sourceString = "JS";
+ break;
+ case CSSMessageSource:
+ sourceString = "CSS";
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ // Fall thru.
+ case OtherMessageSource:
+ sourceString = "OTHER";
+ break;
+ }
+
+ const char* levelString;
+ switch (level) {
+ case TipMessageLevel:
+ levelString = "TIP";
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ // Fall thru.
+ case LogMessageLevel:
+ levelString = "LOG";
+ break;
+ case WarningMessageLevel:
+ levelString = "WARN";
+ break;
+ case ErrorMessageLevel:
+ levelString = "ERROR";
+ break;
+ }
+
+ printf("%s %s:", sourceString, levelString);
+}
+
+static void printToStandardOut(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber)
+{
+ if (!Console::shouldPrintExceptions())
+ return;
+
+ printSourceURLAndLine(sourceURL, lineNumber);
+ printMessageSourceAndLevelPrefix(source, level);
+
+ printf(" %s\n", message.utf8().data());
+}
+
+static void printToStandardOut(MessageLevel level, ExecState* exec, const ArgList& args, const KURL& url)
+{
+ if (!Console::shouldPrintExceptions())
+ return;
+
+ printSourceURLAndLine(url.prettyURL(), 0);
+ printMessageSourceAndLevelPrefix(JSMessageSource, level);
+
+ for (size_t i = 0; i < args.size(); ++i) {
+ UString argAsString = args.at(exec, i)->toString(exec);
+ printf(" %s", argAsString.UTF8String().c_str());
+ }
+
+ printf("\n");
+}
+
+static inline void retrieveLastCaller(ExecState* exec, KURL& url, unsigned& lineNumber)
+{
+ int signedLineNumber;
+ intptr_t sourceID;
+ UString urlString;
+ JSValue* function;
+
+ exec->machine()->retrieveLastCaller(exec, signedLineNumber, sourceID, urlString, function);
+
+ url = KURL(urlString);
+ lineNumber = (signedLineNumber >= 0 ? signedLineNumber : 0);
+}
+
+void Console::addMessage(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL)
+{
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ if (source == JSMessageSource)
+ page->chrome()->client()->addMessageToConsole(message, lineNumber, sourceURL);
+
+ page->inspectorController()->addMessageToConsole(source, level, message, lineNumber, sourceURL);
+
+ printToStandardOut(source, level, message, sourceURL, lineNumber);
+}
+
+void Console::debug(ExecState* exec, const ArgList& args)
+{
+ // In Firebug, console.debug has the same behavior as console.log. So we'll do the same.
+ log(exec, args);
+}
+
+void Console::error(ExecState* exec, const ArgList& args)
+{
+ if (args.isEmpty())
+ return;
+
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ String message = args.at(exec, 0)->toString(exec);
+
+ KURL url;
+ unsigned lineNumber;
+ retrieveLastCaller(exec, url, lineNumber);
+
+ page->chrome()->client()->addMessageToConsole(message, lineNumber, url.prettyURL());
+ page->inspectorController()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, exec, args, lineNumber, url.string());
+
+ printToStandardOut(ErrorMessageLevel, exec, args, url);
+}
+
+void Console::info(ExecState* exec, const ArgList& args)
+{
+ if (args.isEmpty())
+ return;
+
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ String message = args.at(exec, 0)->toString(exec);
+
+ KURL url;
+ unsigned lineNumber;
+ retrieveLastCaller(exec, url, lineNumber);
+
+ page->chrome()->client()->addMessageToConsole(message, lineNumber, url.prettyURL());
+ page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageLevel, exec, args, lineNumber, url.string());
+
+ printToStandardOut(LogMessageLevel, exec, args, url);
+}
+
+void Console::log(ExecState* exec, const ArgList& args)
+{
+ if (args.isEmpty())
+ return;
+
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ String message = args.at(exec, 0)->toString(exec);
+
+ KURL url;
+ unsigned lineNumber;
+ retrieveLastCaller(exec, url, lineNumber);
+
+ page->chrome()->client()->addMessageToConsole(message, lineNumber, url.prettyURL());
+ page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageLevel, exec, args, lineNumber, url.string());
+
+ printToStandardOut(LogMessageLevel, exec, args, url);
+}
+
+void Console::dir(ExecState* exec, const ArgList& args)
+{
+ if (args.isEmpty())
+ return;
+
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ page->inspectorController()->addMessageToConsole(JSMessageSource, ObjectMessageLevel, exec, args, 0, String());
+}
+
+void Console::dirxml(ExecState* exec, const ArgList& args)
+{
+ if (args.isEmpty())
+ return;
+
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ page->inspectorController()->addMessageToConsole(JSMessageSource, NodeMessageLevel, exec, args, 0, String());
+}
+
+void Console::trace(ExecState* exec)
+{
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ int signedLineNumber;
+ intptr_t sourceID;
+ UString urlString;
+ JSValue* func;
+
+ exec->machine()->retrieveLastCaller(exec, signedLineNumber, sourceID, urlString, func);
+
+ ArgList args;
+ while (!func->isNull()) {
+ args.append(func);
+ func = exec->machine()->retrieveCaller(exec, asInternalFunction(func));
+ }
+
+ page->inspectorController()->addMessageToConsole(JSMessageSource, TraceMessageLevel, exec, args, 0, String());
+}
+
+void Console::assertCondition(bool condition, ExecState* exec, const ArgList& args)
+{
+ if (condition)
+ return;
+
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ KURL url;
+ unsigned lineNumber;
+ retrieveLastCaller(exec, url, lineNumber);
+
+ // FIXME: <https://bugs.webkit.org/show_bug.cgi?id=19135> It would be nice to prefix assertion failures with a message like "Assertion failed: ".
+ // FIXME: <https://bugs.webkit.org/show_bug.cgi?id=19136> We should print a message even when args.isEmpty() is true.
+
+ page->inspectorController()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, exec, args, lineNumber, url.string());
+
+ printToStandardOut(ErrorMessageLevel, exec, args, url);
+}
+
+void Console::count(ExecState* exec, const ArgList& args)
+{
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ KURL url;
+ unsigned lineNumber;
+ retrieveLastCaller(exec, url, lineNumber);
+
+ UString title;
+ if (args.size() >= 1)
+ title = valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 0));
+
+ page->inspectorController()->count(title, lineNumber, url.string());
+}
+
+void Console::profile(ExecState* exec, const ArgList& args)
+{
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ // FIXME: log a console message when profiling is disabled.
+ if (!page->inspectorController()->profilerEnabled())
+ return;
+
+ UString title = args.at(exec, 0)->toString(exec);
+ Profiler::profiler()->startProfiling(exec, title);
+}
+
+void Console::profileEnd(ExecState* exec, const ArgList& args)
+{
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ if (!page->inspectorController()->profilerEnabled())
+ return;
+
+ UString title;
+ if (args.size() >= 1)
+ title = valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 0));
+
+ RefPtr<Profile> profile = Profiler::profiler()->stopProfiling(exec, title);
+ if (!profile)
+ return;
+
+ m_profiles.append(profile);
+
+ if (Page* page = this->page()) {
+ KURL url;
+ unsigned lineNumber;
+ retrieveLastCaller(exec, url, lineNumber);
+
+ page->inspectorController()->addProfile(profile, lineNumber, url);
+ }
+}
+
+void Console::time(const UString& title)
+{
+ if (title.isNull())
+ return;
+
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ page->inspectorController()->startTiming(title);
+}
+
+void Console::timeEnd(ExecState* exec, const ArgList& args)
+{
+ UString title;
+ if (args.size() >= 1)
+ title = valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 0));
+ if (title.isNull())
+ return;
+
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ double elapsed;
+ if (!page->inspectorController()->stopTiming(title, elapsed))
+ return;
+
+ String message = String(title) + String::format(": %.0fms", elapsed);
+
+ KURL url;
+ unsigned lineNumber;
+ retrieveLastCaller(exec, url, lineNumber);
+
+ page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageLevel, message, lineNumber, url.string());
+}
+
+void Console::group(ExecState* exec, const ArgList& arguments)
+{
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ page->inspectorController()->startGroup(JSMessageSource, exec, arguments, 0, String());
+}
+
+void Console::groupEnd()
+{
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ page->inspectorController()->endGroup(JSMessageSource, 0, String());
+}
+
+void Console::warn(ExecState* exec, const ArgList& args)
+{
+ if (args.isEmpty())
+ return;
+
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ String message = args.at(exec, 0)->toString(exec);
+
+ KURL url;
+ unsigned lineNumber;
+ retrieveLastCaller(exec, url, lineNumber);
+
+ page->chrome()->client()->addMessageToConsole(message, lineNumber, url.prettyURL());
+ page->inspectorController()->addMessageToConsole(JSMessageSource, WarningMessageLevel, exec, args, lineNumber, url.string());
+
+ printToStandardOut(WarningMessageLevel, exec, args, url);
+}
+
+void Console::reportException(ExecState* exec, JSValue* exception)
+{
+ UString errorMessage = exception->toString(exec);
+ JSObject* exceptionObject = exception->toObject(exec);
+ int lineNumber = exceptionObject->get(exec, Identifier(exec, "line"))->toInt32(exec);
+ UString exceptionSourceURL = exceptionObject->get(exec, Identifier(exec, "sourceURL"))->toString(exec);
+ addMessage(JSMessageSource, ErrorMessageLevel, errorMessage, lineNumber, exceptionSourceURL);
+ if (exec->hadException())
+ exec->clearException();
+}
+
+void Console::reportCurrentException(ExecState* exec)
+{
+ JSValue* exception = exec->exception();
+ exec->clearException();
+ reportException(exec, exception);
+}
+
+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/WebCore/page/Console.h b/WebCore/page/Console.h
new file mode 100644
index 0000000..8f33e96
--- /dev/null
+++ b/WebCore/page/Console.h
@@ -0,0 +1,116 @@
+/*
+ * 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 "PlatformString.h"
+#include <profiler/Profile.h>
+#include <wtf/RefCounted.h>
+#include <wtf/PassRefPtr.h>
+
+namespace JSC {
+ class ExecState;
+ class ArgList;
+}
+
+namespace WebCore {
+
+ typedef Vector<RefPtr<JSC::Profile> > ProfilesArray;
+
+ class Frame;
+ class Page;
+ class String;
+
+ enum MessageSource {
+ HTMLMessageSource,
+ XMLMessageSource,
+ JSMessageSource,
+ CSSMessageSource,
+ OtherMessageSource
+ };
+
+ enum MessageLevel {
+ TipMessageLevel,
+ LogMessageLevel,
+ WarningMessageLevel,
+ ErrorMessageLevel,
+ ObjectMessageLevel,
+ NodeMessageLevel,
+ TraceMessageLevel,
+ StartGroupMessageLevel,
+ EndGroupMessageLevel
+ };
+
+ class Console : public RefCounted<Console> {
+ public:
+ static PassRefPtr<Console> create(Frame* frame) { return adoptRef(new Console(frame)); }
+
+ void disconnectFrame();
+
+ void addMessage(MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL);
+
+#if USE(JSC)
+ void debug(JSC::ExecState*, const JSC::ArgList&);
+ void error(JSC::ExecState*, const JSC::ArgList&);
+ void info(JSC::ExecState*, const JSC::ArgList&);
+ void log(JSC::ExecState*, const JSC::ArgList&);
+ void warn(JSC::ExecState*, const JSC::ArgList&);
+ void dir(JSC::ExecState*, const JSC::ArgList&);
+ void dirxml(JSC::ExecState*, const JSC::ArgList& arguments);
+ void trace(JSC::ExecState*);
+ void assertCondition(bool condition, JSC::ExecState*, const JSC::ArgList&);
+ void count(JSC::ExecState*, const JSC::ArgList&);
+ void profile(JSC::ExecState*, const JSC::ArgList&);
+ void profileEnd(JSC::ExecState*, const JSC::ArgList&);
+ void time(const JSC::UString& title);
+ void timeEnd(JSC::ExecState*, const JSC::ArgList&);
+ void group(JSC::ExecState*, const JSC::ArgList&);
+ void groupEnd();
+
+ void reportException(JSC::ExecState*, JSC::JSValue*);
+ void reportCurrentException(JSC::ExecState*);
+
+ static bool shouldPrintExceptions();
+ static void setShouldPrintExceptions(bool);
+
+ const ProfilesArray& profiles() const { return m_profiles; }
+#endif
+
+ private:
+ inline Page* page() const;
+
+ Console(Frame*);
+
+ Frame* m_frame;
+ ProfilesArray m_profiles;
+ };
+
+} // namespace WebCore
+
+#endif // Console_h
diff --git a/WebCore/page/Console.idl b/WebCore/page/Console.idl
new file mode 100644
index 0000000..9075963
--- /dev/null
+++ b/WebCore/page/Console.idl
@@ -0,0 +1,53 @@
+/*
+ * 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 Console {
+ readonly attribute [CustomGetter] Array profiles;
+
+ [Custom] void debug();
+ [Custom] void error();
+ [Custom] void info();
+ [Custom] void log();
+ [Custom] void warn();
+ [Custom] void dir();
+ [Custom] void dirxml();
+ [Custom] void trace();
+ [Custom, ImplementationFunction=assertCondition] void assert(in boolean condition);
+ [Custom] void count();
+
+ [Custom] void profile(in DOMString title);
+ [Custom] void profileEnd();
+ void time(in [ConvertUndefinedOrNullToNullString] DOMString title);
+ [Custom] void timeEnd();
+ [Custom] void group();
+ void groupEnd();
+ };
+
+}
diff --git a/WebCore/page/ContextMenuClient.h b/WebCore/page/ContextMenuClient.h
new file mode 100644
index 0000000..775adc5
--- /dev/null
+++ b/WebCore/page/ContextMenuClient.h
@@ -0,0 +1,59 @@
+/*
+ * 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 "PlatformMenuDescription.h"
+
+namespace WebCore {
+ class ContextMenu;
+ class ContextMenuItem;
+ class Frame;
+ class HitTestResult;
+ class KURL;
+ class String;
+
+ class ContextMenuClient {
+ public:
+ virtual ~ContextMenuClient() { }
+ virtual void contextMenuDestroyed() = 0;
+
+ virtual PlatformMenuDescription getCustomMenuFromDefaultItems(ContextMenu*) = 0;
+ 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 void speak(const String&) = 0;
+ virtual void stopSpeaking() = 0;
+
+#if PLATFORM(MAC)
+ virtual void searchWithSpotlight() = 0;
+#endif
+ };
+}
+
+#endif
diff --git a/WebCore/page/ContextMenuController.cpp b/WebCore/page/ContextMenuController.cpp
new file mode 100644
index 0000000..813f8e2
--- /dev/null
+++ b/WebCore/page/ContextMenuController.cpp
@@ -0,0 +1,297 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "ContextMenuController.h"
+
+#include "Chrome.h"
+#include "ContextMenu.h"
+#include "ContextMenuClient.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 "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoadRequest.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "InspectorController.h"
+#include "MouseEvent.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"
+
+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);
+}
+
+void ContextMenuController::handleContextMenuEvent(Event* event)
+{
+ ASSERT(event->type() == eventNames().contextmenuEvent);
+ if (!event->isMouseEvent())
+ return;
+ MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+ IntPoint point = IntPoint(mouseEvent->pageX(), mouseEvent->pageY());
+ HitTestResult result(point);
+
+ if (Frame* frame = event->target()->toNode()->document()->frame())
+ result = frame->eventHandler()->hitTestResultAtPoint(point, false);
+
+ if (!result.innerNonSharedNode())
+ return;
+
+ m_contextMenu.set(new ContextMenu(result));
+ m_contextMenu->populate();
+ if (m_page->inspectorController()->enabled())
+ m_contextMenu->addInspectElementItem();
+
+ PlatformMenuDescription customMenu = m_client->getCustomMenuFromDefaultItems(m_contextMenu.get());
+ m_contextMenu->setPlatformDescription(customMenu);
+
+ event->setDefaultHandled();
+}
+
+static void openNewWindow(const KURL& urlToLoad, Frame* frame)
+{
+ if (Page* oldPage = frame->page()) {
+ WindowFeatures features;
+ if (Page* newPage = oldPage->chrome()->createWindow(frame,
+ FrameLoadRequest(ResourceRequest(urlToLoad, frame->loader()->outgoingReferrer())), features))
+ 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;
+ }
+
+ HitTestResult result = m_contextMenu->hitTestResult();
+ Frame* frame = result.innerNonSharedNode()->document()->frame();
+ if (!frame)
+ return;
+
+ switch (item->action()) {
+ case ContextMenuItemTagOpenLinkInNewWindow:
+ openNewWindow(result.absoluteLinkURL(), frame);
+ break;
+ case ContextMenuItemTagDownloadLinkToDisk:
+ // FIXME: Some day we should be able to do this from within WebCore.
+ m_client->downloadURL(result.absoluteLinkURL());
+ break;
+ case ContextMenuItemTagCopyLinkToClipboard:
+ frame->editor()->copyURL(result.absoluteLinkURL(), result.textContent());
+ break;
+ case ContextMenuItemTagOpenImageInNewWindow:
+ openNewWindow(result.absoluteImageURL(), frame);
+ break;
+ case ContextMenuItemTagDownloadImageToDisk:
+ // FIXME: Some day we should be able to do this from within WebCore.
+ m_client->downloadURL(result.absoluteImageURL());
+ break;
+ case ContextMenuItemTagCopyImageToClipboard:
+ // FIXME: The Pasteboard class is not written yet
+ // For now, call into the client. This is temporary!
+ frame->editor()->copyImage(result);
+ 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:
+ frame->loader()->goBackOrForward(-1);
+ break;
+ case ContextMenuItemTagGoForward:
+ frame->loader()->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;
+ case ContextMenuItemTagSelectAll:
+ frame->editor()->command("SelectAll").execute();
+ break;
+#endif
+ case ContextMenuItemTagSpellingGuess:
+ ASSERT(frame->selectedText().length());
+ if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toRange().get(),
+ EditorInsertActionPasted)) {
+ Document* document = frame->document();
+ RefPtr<ReplaceSelectionCommand> command =
+ ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""),
+ true, false, true);
+ applyCommand(command);
+ frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
+ }
+ 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 = result.targetFrame())
+ targetFrame->loader()->loadFrameRequestWithFormAndValues(FrameLoadRequest(ResourceRequest(result.absoluteLinkURL(),
+ frame->loader()->outgoingReferrer())), false, 0, 0, HashMap<String, String>());
+ else
+ openNewWindow(result.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()->toRange();
+ if (!selectedRange || selectedRange->collapsed(ec)) {
+ Document* document = result.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;
+#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
+ case ContextMenuItemTagInspectElement:
+ if (Page* page = frame->page())
+ page->inspectorController()->inspect(result.innerNonSharedNode());
+ break;
+ default:
+ break;
+ }
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/ContextMenuController.h b/WebCore/page/ContextMenuController.h
new file mode 100644
index 0000000..cb7e6ee
--- /dev/null
+++ b/WebCore/page/ContextMenuController.h
@@ -0,0 +1,61 @@
+/*
+ * 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 <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+ class ContextMenu;
+ class ContextMenuClient;
+ class ContextMenuItem;
+ class Event;
+ class Page;
+
+ class ContextMenuController : Noncopyable {
+ public:
+ ContextMenuController(Page*, ContextMenuClient*);
+ ~ContextMenuController();
+
+ ContextMenuClient* client() { return m_client; }
+
+ ContextMenu* contextMenu() const { return m_contextMenu.get(); }
+ void clearContextMenu();
+
+ void handleContextMenuEvent(Event*);
+ void contextMenuItemSelected(ContextMenuItem*);
+
+ private:
+ Page* m_page;
+ ContextMenuClient* m_client;
+ OwnPtr<ContextMenu> m_contextMenu;
+ };
+
+}
+
+#endif
diff --git a/WebCore/page/DOMSelection.cpp b/WebCore/page/DOMSelection.cpp
new file mode 100644
index 0000000..5dab325
--- /dev/null
+++ b/WebCore/page/DOMSelection.cpp
@@ -0,0 +1,424 @@
+/*
+ * 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 "DOMSelection.h"
+
+#include "ExceptionCode.h"
+#include "Frame.h"
+#include "htmlediting.h"
+#include "Node.h"
+#include "PlatformString.h"
+#include "Range.h"
+#include "SelectionController.h"
+#include "TextIterator.h"
+
+namespace WebCore {
+
+DOMSelection::DOMSelection(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+Frame* DOMSelection::frame() const
+{
+ return m_frame;
+}
+
+void DOMSelection::disconnectFrame()
+{
+ m_frame = 0;
+}
+
+Node* DOMSelection::anchorNode() const
+{
+ if (!m_frame)
+ return 0;
+
+ const Selection& selection = m_frame->selection()->selection();
+ Position anchor = selection.isBaseFirst() ? selection.start() : selection.end();
+ anchor = rangeCompliantEquivalent(anchor);
+ return anchor.node();
+}
+
+Node* DOMSelection::baseNode() const
+{
+ if (!m_frame)
+ return 0;
+ return rangeCompliantEquivalent(m_frame->selection()->selection().base()).node();
+}
+
+int DOMSelection::anchorOffset() const
+{
+ if (!m_frame)
+ return 0;
+
+ const Selection& selection = m_frame->selection()->selection();
+ Position anchor = selection.isBaseFirst() ? selection.start() : selection.end();
+ anchor = rangeCompliantEquivalent(anchor);
+ return anchor.offset();
+}
+
+int DOMSelection::baseOffset() const
+{
+ if (!m_frame)
+ return 0;
+ return rangeCompliantEquivalent(m_frame->selection()->selection().base()).offset();
+}
+
+Node* DOMSelection::focusNode() const
+{
+ if (!m_frame)
+ return 0;
+
+ const Selection& selection = m_frame->selection()->selection();
+ Position focus = selection.isBaseFirst() ? selection.end() : selection.start();
+ focus = rangeCompliantEquivalent(focus);
+ return focus.node();
+}
+
+Node* DOMSelection::extentNode() const
+{
+ if (!m_frame)
+ return 0;
+ return rangeCompliantEquivalent(m_frame->selection()->selection().extent()).node();
+}
+
+int DOMSelection::focusOffset() const
+{
+ if (!m_frame)
+ return 0;
+
+ const Selection& selection = m_frame->selection()->selection();
+ Position focus = selection.isBaseFirst() ? selection.end() : selection.start();
+ focus = rangeCompliantEquivalent(focus);
+ return focus.offset();
+}
+
+int DOMSelection::extentOffset() const
+{
+ if (!m_frame)
+ return 0;
+ return rangeCompliantEquivalent(m_frame->selection()->selection().extent()).offset();
+}
+
+bool DOMSelection::isCollapsed() const
+{
+ if (!m_frame)
+ return false;
+ return !m_frame->selection()->isRange();
+}
+
+String DOMSelection::type() const
+{
+ if (!m_frame)
+ return String();
+
+ SelectionController* selection = m_frame->selection();
+
+ 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;
+ }
+ m_frame->selection()->moveTo(VisiblePosition(node, offset, DOWNSTREAM));
+}
+
+void DOMSelection::collapseToEnd()
+{
+ if (!m_frame)
+ return;
+
+ const Selection& selection = m_frame->selection()->selection();
+ m_frame->selection()->moveTo(VisiblePosition(selection.end(), DOWNSTREAM));
+}
+
+void DOMSelection::collapseToStart()
+{
+ if (!m_frame)
+ return;
+
+ const Selection& selection = m_frame->selection()->selection();
+ m_frame->selection()->moveTo(VisiblePosition(selection.start(), DOWNSTREAM));
+}
+
+void DOMSelection::empty()
+{
+ if (!m_frame)
+ return;
+ m_frame->selection()->moveTo(VisiblePosition());
+}
+
+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;
+ }
+ 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;
+ }
+ 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::EXTEND;
+ else if (equalIgnoringCase(alterString, "move"))
+ alter = SelectionController::MOVE;
+ else
+ return;
+
+ SelectionController::EDirection direction;
+ if (equalIgnoringCase(directionString, "forward"))
+ direction = SelectionController::FORWARD;
+ else if (equalIgnoringCase(directionString, "backward"))
+ direction = SelectionController::BACKWARD;
+ else if (equalIgnoringCase(directionString, "left"))
+ direction = SelectionController::LEFT;
+ else if (equalIgnoringCase(directionString, "right"))
+ direction = SelectionController::RIGHT;
+ 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;
+ }
+
+ SelectionController* selection = m_frame->selection();
+ selection->expandUsingGranularity(CharacterGranularity);
+ 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;
+ }
+
+ const Selection& selection = m_frame->selection()->selection();
+ return selection.toRange();
+}
+
+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(Selection(r));
+ return;
+ }
+
+ RefPtr<Range> range = selection->selection().toRange();
+ 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(Selection(r->startPosition(), range->endPosition(), DOWNSTREAM));
+ else
+ // r contains the original range.
+ selection->setSelection(Selection(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(Selection(range.get()));
+ else
+ // The original range and r intersect.
+ selection->setSelection(Selection(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::EXTEND, SelectionController::BACKWARD, CharacterGranularity);
+
+ RefPtr<Range> selectedRange = selection->selection().toRange();
+
+ 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 || selection->isNone())
+ return false;
+
+ Node* parentNode = n->parentNode();
+ unsigned nodeIndex = n->nodeIndex();
+ RefPtr<Range> selectedRange = selection->selection().toRange();
+
+ 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().toRange().get());
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/DOMSelection.h b/WebCore/page/DOMSelection.h
new file mode 100644
index 0000000..fd8d1fc
--- /dev/null
+++ b/WebCore/page/DOMSelection.h
@@ -0,0 +1,102 @@
+/*
+ * 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/RefCounted.h>
+#include <wtf/Forward.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+ class Frame;
+ class Range;
+ class Node;
+ class String;
+
+ 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();
+ void collapseToStart();
+ 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();
+ //void clear();
+ //TextRange *createRange();
+
+ private:
+ DOMSelection(Frame*);
+
+ Frame* m_frame;
+ };
+
+} // namespace WebCore
+
+#endif // DOMSelection_h
diff --git a/WebCore/page/DOMSelection.idl b/WebCore/page/DOMSelection.idl
new file mode 100644
index 0000000..85d23bf
--- /dev/null
+++ b/WebCore/page/DOMSelection.idl
@@ -0,0 +1,70 @@
+/*
+ * 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 DOMSelection {
+ readonly attribute Node anchorNode;
+ readonly attribute long anchorOffset;
+ readonly attribute Node focusNode;
+ readonly attribute long focusOffset;
+ readonly attribute Node baseNode;
+ readonly attribute long baseOffset;
+ readonly attribute Node extentNode;
+ readonly attribute long extentOffset;
+ readonly attribute boolean isCollapsed;
+ readonly attribute DOMString type;
+ readonly attribute long rangeCount;
+
+ void collapse(in Node node, in long index)
+ raises(DOMException);
+ void collapseToEnd();
+ void collapseToStart();
+ void deleteFromDocument();
+ boolean containsNode(in Node node, in boolean allowPartial);
+ void selectAllChildren(in Node node)
+ raises(DOMException);
+ void empty();
+ 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);
+ void modify(in DOMString alter, in DOMString direction, in DOMString granularity);
+ 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)
+ [DontEnum] DOMString toString();
+#endif
+ };
+
+}
diff --git a/WebCore/page/DOMWindow.cpp b/WebCore/page/DOMWindow.cpp
new file mode 100644
index 0000000..4ab69ca
--- /dev/null
+++ b/WebCore/page/DOMWindow.cpp
@@ -0,0 +1,1279 @@
+/*
+ * 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 "DOMWindow.h"
+
+#include "BarInfo.h"
+#include "CSSComputedStyleDeclaration.h"
+#include "CSSRuleList.h"
+#include "CSSStyleSelector.h"
+#include "CString.h"
+#include "Chrome.h"
+#include "Console.h"
+#include "DOMSelection.h"
+#include "Document.h"
+#include "Element.h"
+#include "EventListener.h"
+#include "EventNames.h"
+#include "ExceptionCode.h"
+#include "FloatRect.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "HTMLFrameOwnerElement.h"
+#include "History.h"
+#include "Location.h"
+#include "MessageEvent.h"
+#include "Navigator.h"
+#include "Page.h"
+#include "PageGroup.h"
+#include "PlatformScreen.h"
+#include "PlatformString.h"
+#include "Screen.h"
+#include "SecurityOrigin.h"
+#include <algorithm>
+#include <wtf/MathExtras.h>
+
+#if ENABLE(DATABASE)
+#include "Database.h"
+#endif
+
+#if ENABLE(DOM_STORAGE)
+#include "LocalStorage.h"
+#include "SessionStorage.h"
+#include "Storage.h"
+#include "StorageArea.h"
+#endif
+
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+#include "DOMApplicationCache.h"
+#endif
+
+using std::min;
+using std::max;
+
+namespace WebCore {
+
+class PostMessageTimer : public TimerBase {
+public:
+ PostMessageTimer(DOMWindow* window, PassRefPtr<MessageEvent> event, SecurityOrigin* targetOrigin)
+ : m_window(window)
+ , m_event(event)
+ , m_targetOrigin(targetOrigin)
+ {
+ }
+
+ MessageEvent* event() const { return m_event.get(); }
+ SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); }
+
+private:
+ virtual void fired()
+ {
+ m_window->postMessageTimerFired(this);
+ }
+
+ RefPtr<DOMWindow> m_window;
+ RefPtr<MessageEvent> m_event;
+ RefPtr<SecurityOrigin> m_targetOrigin;
+};
+
+// 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())));
+}
+
+DOMWindow::DOMWindow(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+DOMWindow::~DOMWindow()
+{
+ if (m_frame)
+ m_frame->clearFormerDOMWindow(this);
+}
+
+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 (m_location)
+ m_location->disconnectFrame();
+ m_location = 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
+}
+
+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();
+}
+
+Location* DOMWindow::location() const
+{
+ if (!m_location)
+ m_location = Location::create(m_frame);
+ return m_location.get();
+}
+
+#if ENABLE(DOM_STORAGE)
+Storage* DOMWindow::sessionStorage() const
+{
+ if (m_sessionStorage)
+ return m_sessionStorage.get();
+
+ Page* page = m_frame->page();
+ if (!page)
+ return 0;
+
+ Document* document = m_frame->document();
+ if (!document)
+ return 0;
+
+ RefPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin());
+ m_sessionStorage = Storage::create(m_frame, storageArea.release());
+ return m_sessionStorage.get();
+}
+
+Storage* DOMWindow::localStorage() const
+{
+ Document* document = this->document();
+ if (!document)
+ return 0;
+
+ Page* page = document->page();
+ if (!page)
+ return 0;
+
+ LocalStorage* localStorage = page->group().localStorage();
+ RefPtr<StorageArea> storageArea = localStorage ? localStorage->storageArea(m_frame, document->securityOrigin()) : 0;
+ if (storageArea)
+ m_localStorage = Storage::create(m_frame, storageArea.release());
+
+ return m_localStorage.get();
+}
+#endif
+
+void DOMWindow::postMessage(const String& message, MessagePort* messagePort, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec)
+{
+ if (!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::create(KURL(targetOrigin));
+ if (target->isEmpty()) {
+ ec = SYNTAX_ERR;
+ return;
+ }
+ }
+
+ RefPtr<MessagePort> newMessagePort;
+ if (messagePort)
+ newMessagePort = messagePort->clone(document(), 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, MessageEvent::create(message, sourceOrigin, "", source, newMessagePort), 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 = String::format("Unable to post message to %s. Recipient has origin %s.\n",
+ timer->targetOrigin()->toString().utf8().data(), document()->securityOrigin()->toString().utf8().data());
+ console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 0, String());
+ return;
+ }
+ }
+
+ document()->dispatchWindowEvent(timer->event());
+}
+
+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;
+
+ m_frame->focusWindow();
+}
+
+void DOMWindow::blur()
+{
+ if (!m_frame)
+ return;
+
+ m_frame->unfocusWindow();
+}
+
+void DOMWindow::close()
+{
+ if (!m_frame)
+ return;
+
+ if (m_frame->loader()->openedByDOM() || m_frame->loader()->getHistoryLength() <= 1)
+ m_frame->scheduleClose();
+}
+
+void DOMWindow::print()
+{
+ if (!m_frame)
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ 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;
+
+ Document* doc = m_frame->document();
+ ASSERT(doc);
+ if (doc)
+ doc->updateRendering();
+
+ 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;
+
+ Document* doc = m_frame->document();
+ ASSERT(doc);
+ if (doc)
+ doc->updateRendering();
+
+ 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();
+
+ Document* doc = m_frame->document();
+ ASSERT(doc);
+ if (doc)
+ doc->updateRendering();
+
+ Page* page = m_frame->page();
+ if (!page)
+ return String();
+
+ String returnValue;
+ if (page->chrome()->runJavaScriptPrompt(m_frame, message, defaultValue, returnValue))
+ return returnValue;
+
+ return String();
+}
+
+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->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;
+
+ return static_cast<int>(view->height() / m_frame->pageZoomFactor());
+}
+
+int DOMWindow::innerWidth() const
+{
+ if (!m_frame)
+ return 0;
+
+ FrameView* view = m_frame->view();
+ if (!view)
+ return 0;
+
+ return static_cast<int>(view->width() / m_frame->pageZoomFactor());
+}
+
+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;
+
+ Document* doc = m_frame->document();
+ ASSERT(doc);
+ if (doc)
+ doc->updateLayoutIgnorePendingStylesheets();
+
+ return static_cast<int>(view->scrollX() / m_frame->pageZoomFactor());
+}
+
+#ifdef ANDROID_ORIENTATION_SUPPORT
+int DOMWindow::orientation() const
+{
+ return screen()->orientation();
+}
+#endif
+
+int DOMWindow::scrollY() const
+{
+ if (!m_frame)
+ return 0;
+
+ FrameView* view = m_frame->view();
+ if (!view)
+ return 0;
+
+ Document* doc = m_frame->document();
+ ASSERT(doc);
+ if (doc)
+ doc->updateLayoutIgnorePendingStylesheets();
+
+ return static_cast<int>(view->scrollY() / m_frame->pageZoomFactor());
+}
+
+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);
+}
+
+String DOMWindow::status() const
+{
+ if (!m_frame)
+ return String();
+
+ return m_frame->jsStatusBarText();
+}
+
+void DOMWindow::setStatus(const String& string)
+{
+ if (!m_frame)
+ return;
+
+ m_frame->setJSStatusBarText(string);
+}
+
+String DOMWindow::defaultStatus() const
+{
+ if (!m_frame)
+ return String();
+
+ return m_frame->jsDefaultStatusBarText();
+}
+
+void DOMWindow::setDefaultStatus(const String& string)
+{
+ if (!m_frame)
+ return;
+
+ m_frame->setJSDefaultStatusBarText(string);
+}
+
+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
+{
+ if (!m_frame)
+ return 0;
+
+ ASSERT(m_frame->document());
+ return m_frame->document();
+}
+
+PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String&) const
+{
+ if (!elt)
+ return 0;
+
+ // FIXME: This needs take pseudo elements into account.
+ return computedStyle(elt);
+}
+
+PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* elt, const String& pseudoElt, bool authorOnly) const
+{
+ if (!m_frame)
+ return 0;
+
+ Document* doc = m_frame->document();
+ ASSERT(doc);
+ if (!doc)
+ return 0;
+
+ if (!pseudoElt.isEmpty())
+ return doc->styleSelector()->pseudoStyleRulesForElement(elt, pseudoElt, authorOnly);
+ return doc->styleSelector()->styleRulesForElement(elt, authorOnly);
+}
+
+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, ExceptionCode& ec)
+{
+ if (!m_frame)
+ return 0;
+
+ Document* doc = m_frame->document();
+ ASSERT(doc);
+ if (!doc)
+ return 0;
+
+ return Database::openDatabase(doc, name, version, displayName, estimatedSize, ec);
+}
+#endif
+
+void DOMWindow::scrollBy(int x, int y) const
+{
+ if (!m_frame)
+ return;
+
+ Document* doc = m_frame->document();
+ ASSERT(doc);
+ if (doc)
+ doc->updateLayoutIgnorePendingStylesheets();
+
+ 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;
+
+ Document* doc = m_frame->document();
+ ASSERT(doc);
+ if (doc)
+ doc->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);
+}
+
+inline void DOMWindow::setInlineEventListenerForType(const AtomicString& eventType, PassRefPtr<EventListener> eventListener)
+{
+ Document* document = this->document();
+ if (!document)
+ return;
+ document->setWindowInlineEventListenerForType(eventType, eventListener);
+}
+
+inline EventListener* DOMWindow::inlineEventListenerForType(const AtomicString& eventType) const
+{
+ Document* document = this->document();
+ if (!document)
+ return 0;
+ return document->windowInlineEventListenerForType(eventType);
+}
+
+EventListener* DOMWindow::onabort() const
+{
+ return inlineEventListenerForType(eventNames().abortEvent);
+}
+
+void DOMWindow::setOnabort(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().abortEvent, eventListener);
+}
+
+EventListener* DOMWindow::onblur() const
+{
+ return inlineEventListenerForType(eventNames().blurEvent);
+}
+
+void DOMWindow::setOnblur(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().blurEvent, eventListener);
+}
+
+EventListener* DOMWindow::onchange() const
+{
+ return inlineEventListenerForType(eventNames().changeEvent);
+}
+
+void DOMWindow::setOnchange(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().changeEvent, eventListener);
+}
+
+EventListener* DOMWindow::onclick() const
+{
+ return inlineEventListenerForType(eventNames().clickEvent);
+}
+
+void DOMWindow::setOnclick(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().clickEvent, eventListener);
+}
+
+EventListener* DOMWindow::ondblclick() const
+{
+ return inlineEventListenerForType(eventNames().dblclickEvent);
+}
+
+void DOMWindow::setOndblclick(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().dblclickEvent, eventListener);
+}
+
+EventListener* DOMWindow::onerror() const
+{
+ return inlineEventListenerForType(eventNames().errorEvent);
+}
+
+void DOMWindow::setOnerror(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().errorEvent, eventListener);
+}
+
+EventListener* DOMWindow::onfocus() const
+{
+ return inlineEventListenerForType(eventNames().focusEvent);
+}
+
+void DOMWindow::setOnfocus(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().focusEvent, eventListener);
+}
+
+EventListener* DOMWindow::onkeydown() const
+{
+ return inlineEventListenerForType(eventNames().keydownEvent);
+}
+
+void DOMWindow::setOnkeydown(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().keydownEvent, eventListener);
+}
+
+EventListener* DOMWindow::onkeypress() const
+{
+ return inlineEventListenerForType(eventNames().keypressEvent);
+}
+
+void DOMWindow::setOnkeypress(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().keypressEvent, eventListener);
+}
+
+EventListener* DOMWindow::onkeyup() const
+{
+ return inlineEventListenerForType(eventNames().keyupEvent);
+}
+
+void DOMWindow::setOnkeyup(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().keyupEvent, eventListener);
+}
+
+EventListener* DOMWindow::onload() const
+{
+ return inlineEventListenerForType(eventNames().loadEvent);
+}
+
+void DOMWindow::setOnload(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().loadEvent, eventListener);
+}
+
+EventListener* DOMWindow::onmousedown() const
+{
+ return inlineEventListenerForType(eventNames().mousedownEvent);
+}
+
+void DOMWindow::setOnmousedown(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().mousedownEvent, eventListener);
+}
+
+EventListener* DOMWindow::onmousemove() const
+{
+ return inlineEventListenerForType(eventNames().mousemoveEvent);
+}
+
+void DOMWindow::setOnmousemove(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().mousemoveEvent, eventListener);
+}
+
+EventListener* DOMWindow::onmouseout() const
+{
+ return inlineEventListenerForType(eventNames().mouseoutEvent);
+}
+
+void DOMWindow::setOnmouseout(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().mouseoutEvent, eventListener);
+}
+
+EventListener* DOMWindow::onmouseover() const
+{
+ return inlineEventListenerForType(eventNames().mouseoverEvent);
+}
+
+void DOMWindow::setOnmouseover(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().mouseoverEvent, eventListener);
+}
+
+EventListener* DOMWindow::onmouseup() const
+{
+ return inlineEventListenerForType(eventNames().mouseupEvent);
+}
+
+void DOMWindow::setOnmouseup(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().mouseupEvent, eventListener);
+}
+
+EventListener* DOMWindow::onmousewheel() const
+{
+ return inlineEventListenerForType(eventNames().mousewheelEvent);
+}
+
+void DOMWindow::setOnmousewheel(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().mousewheelEvent, eventListener);
+}
+
+EventListener* DOMWindow::onreset() const
+{
+ return inlineEventListenerForType(eventNames().resetEvent);
+}
+
+void DOMWindow::setOnreset(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().resetEvent, eventListener);
+}
+
+EventListener* DOMWindow::onresize() const
+{
+ return inlineEventListenerForType(eventNames().resizeEvent);
+}
+
+void DOMWindow::setOnresize(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().resizeEvent, eventListener);
+}
+
+EventListener* DOMWindow::onscroll() const
+{
+ return inlineEventListenerForType(eventNames().scrollEvent);
+}
+
+void DOMWindow::setOnscroll(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().scrollEvent, eventListener);
+}
+
+EventListener* DOMWindow::onsearch() const
+{
+ return inlineEventListenerForType(eventNames().searchEvent);
+}
+
+void DOMWindow::setOnsearch(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().searchEvent, eventListener);
+}
+
+EventListener* DOMWindow::onselect() const
+{
+ return inlineEventListenerForType(eventNames().selectEvent);
+}
+
+void DOMWindow::setOnselect(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().selectEvent, eventListener);
+}
+
+EventListener* DOMWindow::onsubmit() const
+{
+ return inlineEventListenerForType(eventNames().submitEvent);
+}
+
+void DOMWindow::setOnsubmit(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().submitEvent, eventListener);
+}
+
+EventListener* DOMWindow::onunload() const
+{
+ return inlineEventListenerForType(eventNames().unloadEvent);
+}
+
+void DOMWindow::setOnunload(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().unloadEvent, eventListener);
+}
+
+EventListener* DOMWindow::onbeforeunload() const
+{
+ return inlineEventListenerForType(eventNames().beforeunloadEvent);
+}
+
+void DOMWindow::setOnbeforeunload(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().beforeunloadEvent, eventListener);
+}
+
+EventListener* DOMWindow::onwebkitanimationstart() const
+{
+ return inlineEventListenerForType(eventNames().webkitAnimationStartEvent);
+}
+
+void DOMWindow::setOnwebkitanimationstart(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().webkitAnimationStartEvent, eventListener);
+}
+
+EventListener* DOMWindow::onwebkitanimationiteration() const
+{
+ return inlineEventListenerForType(eventNames().webkitAnimationIterationEvent);
+}
+
+void DOMWindow::setOnwebkitanimationiteration(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().webkitAnimationIterationEvent, eventListener);
+}
+
+EventListener* DOMWindow::onwebkitanimationend() const
+{
+ return inlineEventListenerForType(eventNames().webkitAnimationEndEvent);
+}
+
+void DOMWindow::setOnwebkitanimationend(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().webkitAnimationEndEvent, eventListener);
+}
+
+EventListener* DOMWindow::onwebkittransitionend() const
+{
+ return inlineEventListenerForType(eventNames().webkitTransitionEndEvent);
+}
+
+void DOMWindow::setOnwebkittransitionend(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().webkitTransitionEndEvent, eventListener);
+}
+
+#if ENABLE(TOUCH_EVENTS) // Android
+EventListener* DOMWindow::ontouchstart() const
+{
+ return inlineEventListenerForType(eventNames().touchstartEvent);
+}
+
+void DOMWindow::setOntouchstart(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().touchstartEvent, eventListener);
+}
+
+EventListener* DOMWindow::ontouchend() const
+{
+ return inlineEventListenerForType(eventNames().touchendEvent);
+}
+
+void DOMWindow::setOntouchend(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().touchendEvent, eventListener);
+}
+
+EventListener* DOMWindow::ontouchmove() const
+{
+ return inlineEventListenerForType(eventNames().touchmoveEvent);
+}
+
+void DOMWindow::setOntouchmove(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().touchmoveEvent, eventListener);
+}
+
+EventListener* DOMWindow::ontouchcancel() const
+{
+ return inlineEventListenerForType(eventNames().touchcancelEvent);
+}
+
+void DOMWindow::setOntouchcancel(PassRefPtr<EventListener> eventListener)
+{
+ setInlineEventListenerForType(eventNames().touchcancelEvent, eventListener);
+}
+#endif
+
+} // namespace WebCore
diff --git a/WebCore/page/DOMWindow.h b/WebCore/page/DOMWindow.h
new file mode 100644
index 0000000..da84e35
--- /dev/null
+++ b/WebCore/page/DOMWindow.h
@@ -0,0 +1,320 @@
+/*
+ * 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 DOMWindow_h
+#define DOMWindow_h
+
+#include "KURL.h"
+#include "PlatformString.h"
+#include "SecurityOrigin.h"
+#include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ class BarInfo;
+ class CSSRuleList;
+ class CSSStyleDeclaration;
+ class Console;
+ class DOMSelection;
+ class Database;
+ class Document;
+ class Element;
+ class EventListener;
+ class FloatRect;
+ class Frame;
+ class History;
+ class Location;
+ class MessagePort;
+ class Navigator;
+ class PostMessageTimer;
+ class Screen;
+
+#if ENABLE(DOM_STORAGE)
+ class SessionStorage;
+ class Storage;
+#endif
+
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ class DOMApplicationCache;
+#endif
+
+ typedef int ExceptionCode;
+
+ class DOMWindow : public RefCounted<DOMWindow> {
+ public:
+ static PassRefPtr<DOMWindow> create(Frame* frame) { return adoptRef(new DOMWindow(frame)); }
+ virtual ~DOMWindow();
+
+ Frame* frame() { return m_frame; }
+ void disconnectFrame();
+
+ void clear();
+
+ 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; }
+
+ static void adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges);
+
+ // 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;
+
+ DOMSelection* getSelection();
+
+ Element* frameElement() const;
+
+ void focus();
+ void blur();
+ void close();
+ void print();
+ void stop();
+
+ void alert(const String& message);
+ bool confirm(const String& message);
+ String prompt(const String& message, const String& defaultValue);
+
+ 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(); }
+#ifdef ANDROID_ORIENTATION_SUPPORT
+ int orientation() const;
+#endif
+
+ 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;
+
+ // 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;
+
+#if ENABLE(DATABASE)
+ // HTML 5 client-side database
+ PassRefPtr<Database> openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode&);
+#endif
+
+#if ENABLE(DOM_STORAGE)
+ // HTML 5 key/value storage
+ Storage* sessionStorage() const;
+ Storage* localStorage() const;
+#endif
+
+ Console* console() const;
+
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ DOMApplicationCache* applicationCache() const;
+#endif
+
+ void postMessage(const String& 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;
+
+ EventListener* onabort() const;
+ void setOnabort(PassRefPtr<EventListener>);
+ EventListener* onblur() const;
+ void setOnblur(PassRefPtr<EventListener>);
+ EventListener* onchange() const;
+ void setOnchange(PassRefPtr<EventListener>);
+ EventListener* onclick() const;
+ void setOnclick(PassRefPtr<EventListener>);
+ EventListener* ondblclick() const;
+ void setOndblclick(PassRefPtr<EventListener>);
+ EventListener* onerror() const;
+ void setOnerror(PassRefPtr<EventListener>);
+ EventListener* onfocus() const;
+ void setOnfocus(PassRefPtr<EventListener>);
+ EventListener* onkeydown() const;
+ void setOnkeydown(PassRefPtr<EventListener>);
+ EventListener* onkeypress() const;
+ void setOnkeypress(PassRefPtr<EventListener>);
+ EventListener* onkeyup() const;
+ void setOnkeyup(PassRefPtr<EventListener>);
+ EventListener* onload() const;
+ void setOnload(PassRefPtr<EventListener>);
+ EventListener* onmousedown() const;
+ void setOnmousedown(PassRefPtr<EventListener>);
+ EventListener* onmousemove() const;
+ void setOnmousemove(PassRefPtr<EventListener>);
+ EventListener* onmouseout() const;
+ void setOnmouseout(PassRefPtr<EventListener>);
+ EventListener* onmouseover() const;
+ void setOnmouseover(PassRefPtr<EventListener>);
+ EventListener* onmouseup() const;
+ void setOnmouseup(PassRefPtr<EventListener>);
+ EventListener* onmousewheel() const;
+ void setOnmousewheel(PassRefPtr<EventListener>);
+ EventListener* onreset() const;
+ void setOnreset(PassRefPtr<EventListener>);
+ EventListener* onresize() const;
+ void setOnresize(PassRefPtr<EventListener>);
+ EventListener* onscroll() const;
+ void setOnscroll(PassRefPtr<EventListener>);
+ EventListener* onsearch() const;
+ void setOnsearch(PassRefPtr<EventListener>);
+ EventListener* onselect() const;
+ void setOnselect(PassRefPtr<EventListener>);
+ EventListener* onsubmit() const;
+ void setOnsubmit(PassRefPtr<EventListener>);
+ EventListener* onunload() const;
+ void setOnunload(PassRefPtr<EventListener>);
+ EventListener* onbeforeunload() const;
+ void setOnbeforeunload(PassRefPtr<EventListener>);
+ EventListener* onwebkitanimationstart() const;
+ void setOnwebkitanimationstart(PassRefPtr<EventListener>);
+ EventListener* onwebkitanimationiteration() const;
+ void setOnwebkitanimationiteration(PassRefPtr<EventListener>);
+ EventListener* onwebkitanimationend() const;
+ void setOnwebkitanimationend(PassRefPtr<EventListener>);
+ EventListener* onwebkittransitionend() const;
+ void setOnwebkittransitionend(PassRefPtr<EventListener>);
+#if ENABLE(TOUCH_EVENTS) // Android
+ EventListener* ontouchstart() const;
+ void setOntouchstart(PassRefPtr<EventListener>);
+ EventListener* ontouchend() const;
+ void setOntouchend(PassRefPtr<EventListener>);
+ EventListener* ontouchmove() const;
+ void setOntouchmove(PassRefPtr<EventListener>);
+ EventListener* ontouchcancel() const;
+ void setOntouchcancel(PassRefPtr<EventListener>);
+#endif
+
+ // These methods are used for GC marking. See JSDOMWindow::mark() 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(); }
+#if ENABLE(DOM_STORAGE)
+ Storage* optionalSessionStorage() const { return m_sessionStorage.get(); }
+ Storage* optionalLocalStorage() const { return m_sessionStorage.get(); }
+#endif
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ DOMApplicationCache* optionalApplicationCache() const { return m_applicationCache.get(); }
+#endif
+
+ private:
+ DOMWindow(Frame*);
+
+ void setInlineEventListenerForType(const AtomicString& eventType, PassRefPtr<EventListener>);
+ EventListener* inlineEventListenerForType(const AtomicString& eventType) const;
+
+ RefPtr<SecurityOrigin> m_securityOrigin;
+ KURL m_url;
+
+ 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;
+#if ENABLE(DOM_STORAGE)
+ mutable RefPtr<Storage> m_sessionStorage;
+ mutable RefPtr<Storage> m_localStorage;
+#endif
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ mutable RefPtr<DOMApplicationCache> m_applicationCache;
+#endif
+ };
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/page/DOMWindow.idl b/WebCore/page/DOMWindow.idl
new file mode 100644
index 0000000..ce519b5
--- /dev/null
+++ b/WebCore/page/DOMWindow.idl
@@ -0,0 +1,430 @@
+/*
+ * 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.
+ */
+
+module window {
+
+ interface [
+ CheckDomainSecurity,
+ CustomDefineGetter,
+ CustomDefineSetter,
+ CustomDeleteProperty,
+ CustomGetOwnPropertySlot,
+ CustomGetPropertyAttributes,
+ CustomGetPropertyNames,
+ CustomLookupGetter,
+ CustomLookupSetter,
+ CustomMarkFunction,
+ CustomNativeConverter,
+ CustomPutFunction,
+ GenerateNativeConverter,
+ LegacyParent=JSDOMWindowBase
+ ] DOMWindow {
+ // DOM Level 0
+ readonly attribute Screen screen;
+ readonly attribute [DoNotCheckDomainSecurity] 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, CustomSetter] Location location;
+
+ DOMSelection getSelection();
+
+ readonly attribute [CheckNodeSecurity] Element frameElement;
+
+ [DoNotCheckDomainSecurity] void focus();
+ [DoNotCheckDomainSecurity] void blur();
+ [DoNotCheckDomainSecurity] void close();
+
+ void print();
+ void stop();
+
+ 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;
+#if defined(ANDROID_ORIENTATION_SUPPORT)
+ attribute [Replaceable] long orientation;
+#endif
+
+ [RequiresAllArguments] void scrollBy(in long x, in long y);
+ [RequiresAllArguments] void scrollTo(in long x, in long y);
+ [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)
+ // 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] DOMWindow window;
+ attribute [Replaceable, DoNotCheckDomainSecurityOnGet] DOMWindow frames;
+
+ attribute [Replaceable, DoNotCheckDomainSecurityOnGet] DOMWindow opener;
+ attribute [Replaceable, DoNotCheckDomainSecurity] DOMWindow parent;
+ attribute [Replaceable, DoNotCheckDomainSecurity] DOMWindow top;
+
+ // DOM Level 2 AbstractView Interface
+ readonly attribute Document document;
+
+ // DOM Level 2 Style Interface
+ CSSStyleDeclaration getComputedStyle(in Element element,
+ in DOMString pseudoElement);
+
+ // WebKit extensions
+ CSSRuleList getMatchedCSSRules(in Element element,
+ in DOMString pseudoElement,
+ in [Optional] boolean authorOnly);
+ attribute [Replaceable] double devicePixelRatio;
+
+#if ENABLE_OFFLINE_WEB_APPLICATIONS
+ readonly attribute DOMApplicationCache applicationCache;
+#endif
+#if ENABLE_DATABASE
+ Database openDatabase(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize)
+ raises(DOMException);
+#endif
+#if ENABLE_DOM_STORAGE
+ readonly attribute Storage sessionStorage;
+ readonly attribute Storage localStorage;
+#endif
+
+ attribute [Replaceable] Console console;
+
+ // cross-document messaging
+ [DoNotCheckDomainSecurity, Custom] void postMessage(in DOMString message, in [Optional] MessagePort messagePort, in DOMString targetOrigin)
+ raises(DOMException);
+
+ // Timers
+ [Custom] long setTimeout(in TimeoutHandler handler, in long timeout);
+ // [Custom] long setTimeout(in DOMString code, in long timeout);
+ [Custom] void clearTimeout(in long handle);
+
+ [Custom] long setInterval(in TimeoutHandler handler, in long timeout);
+ // [Custom] long setInterval(in DOMString code, in long timeout);
+ [Custom] void clearInterval(in long handle);
+
+ // Base64
+ [Custom] DOMString atob(in DOMString string)
+ raises(DOMException);
+ [Custom] DOMString btoa(in DOMString string)
+ raises(DOMException);
+
+ // Events
+ attribute [ProtectedListener] EventListener onabort;
+ attribute [ProtectedListener] EventListener onblur;
+ attribute [ProtectedListener] EventListener onchange;
+ attribute [ProtectedListener] EventListener onclick;
+ attribute [ProtectedListener] EventListener ondblclick;
+ attribute [ProtectedListener] EventListener onerror;
+ attribute [ProtectedListener] EventListener onfocus;
+ attribute [ProtectedListener] EventListener onkeydown;
+ attribute [ProtectedListener] EventListener onkeypress;
+ attribute [ProtectedListener] EventListener onkeyup;
+ attribute [ProtectedListener] EventListener onload;
+ attribute [ProtectedListener] EventListener onmousedown;
+ attribute [ProtectedListener] EventListener onmousemove;
+ attribute [ProtectedListener] EventListener onmouseout;
+ attribute [ProtectedListener] EventListener onmouseover;
+ attribute [ProtectedListener] EventListener onmouseup;
+ attribute [ProtectedListener] EventListener onmousewheel;
+ attribute [ProtectedListener] EventListener onreset;
+ attribute [ProtectedListener] EventListener onresize;
+ attribute [ProtectedListener] EventListener onscroll;
+ attribute [ProtectedListener] EventListener onsearch;
+ attribute [ProtectedListener] EventListener onselect;
+ attribute [ProtectedListener] EventListener onsubmit;
+ attribute [ProtectedListener] EventListener onunload;
+ attribute [ProtectedListener] EventListener onbeforeunload;
+ attribute [ProtectedListener] EventListener onwebkitanimationstart;
+ attribute [ProtectedListener] EventListener onwebkitanimationiteration;
+ attribute [ProtectedListener] EventListener onwebkitanimationend;
+ attribute [ProtectedListener] EventListener onwebkittransitionend;
+#if ENABLE_TOUCH_EVENTS
+ attribute [ProtectedListener] EventListener ontouchstart;
+ attribute [ProtectedListener] EventListener ontouchend;
+ attribute [ProtectedListener] EventListener ontouchmove;
+ attribute [ProtectedListener] EventListener ontouchcancel;
+#endif
+
+ // 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);
+ // FIXME: Implement dispatchEvent
+
+#if defined(LANGUAGE_JAVASCRIPT)
+ // Global constructors
+ attribute StyleSheetConstructor StyleSheet;
+ attribute CSSStyleSheetConstructor CSSStyleSheet;
+
+ attribute CSSValueConstructor CSSValue;
+ attribute CSSPrimitiveValueConstructor CSSPrimitiveValue;
+ attribute CSSValueListConstructor CSSValueList;
+
+ attribute CSSRuleConstructor CSSRule;
+ attribute CSSCharsetRuleConstructor CSSCharsetRule;
+ attribute CSSFontFaceRuleConstructor CSSFontFaceRule;
+ attribute CSSImportRuleConstructor CSSImportRule;
+ attribute CSSMediaRuleConstructor CSSMediaRule;
+ attribute CSSPageRuleConstructor CSSPageRule;
+ attribute CSSStyleRuleConstructor CSSStyleRule;
+
+ attribute CSSVariablesRuleConstructor CSSVariablesRule;
+ attribute CSSVariablesDeclarationConstructor CSSVariablesDeclaration;
+
+ attribute CSSStyleDeclarationConstructor CSSStyleDeclaration;
+ attribute MediaListConstructor MediaList;
+ attribute CounterConstructor Counter;
+ attribute CSSRuleListConstructor CSSRuleList;
+ attribute RectConstructor Rect;
+ 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 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 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;
+ attribute HTMLModElementConstructor HTMLModElement;
+ attribute HTMLOListElementConstructor HTMLOListElement;
+ attribute HTMLObjectElementConstructor HTMLObjectElement;
+ attribute HTMLOptGroupElementConstructor HTMLOptGroupElement;
+ attribute HTMLOptionElementConstructor HTMLOptionElement;
+ attribute HTMLParagraphElementConstructor HTMLParagraphElement;
+ attribute HTMLParamElementConstructor HTMLParamElement;
+ attribute HTMLPreElementConstructor HTMLPreElement;
+ 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 CanvasRenderingContext2DConstructor CanvasRenderingContext2D;
+ attribute TextMetricsConstructor TextMetrics;
+
+ attribute EventConstructor Event;
+ attribute KeyboardEventConstructor KeyboardEvent;
+ attribute MouseEventConstructor MouseEvent;
+ attribute MutationEventConstructor MutationEvent;
+ attribute OverflowEventConstructor OverflowEvent;
+ attribute ProgressEventConstructor ProgressEvent;
+ attribute TextEventConstructor TextEvent;
+ attribute UIEventConstructor UIEvent;
+ attribute WheelEventConstructor WheelEvent;
+ attribute MessageEventConstructor MessageEvent;
+ attribute EventExceptionConstructor EventException;
+#if ENABLE_TOUCH_EVENTS
+ attribute TouchEventConstructor TouchEvent;
+#endif
+
+ attribute MessagePortConstructor MessagePort;
+
+ attribute ClipboardConstructor Clipboard;
+
+ attribute FileConstructor File;
+ attribute FileListConstructor FileList;
+
+ attribute NodeFilterConstructor NodeFilter;
+ attribute RangeConstructor Range;
+ attribute RangeExceptionConstructor RangeException;
+
+ // 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 XMLHttpRequestUploadConstructor XMLHttpRequestUpload;
+ attribute XMLHttpRequestExceptionConstructor XMLHttpRequestException;
+
+#if ENABLE_DOM_STORAGE
+ attribute StorageConstructor Storage;
+ attribute StorageEventConstructor StorageEvent;
+#endif
+
+#if ENABLE_VIDEO
+ attribute HTMLAudioElementConstructor HTMLAudioElement;
+ attribute HTMLMediaElementConstructor HTMLMediaElement;
+ attribute HTMLVideoElementConstructor HTMLVideoElement;
+ attribute MediaErrorConstructor MediaError;
+#endif
+
+#if ENABLE_XPATH
+ attribute XPathEvaluatorConstructor XPathEvaluator;
+ attribute XPathResultConstructor XPathResult;
+ attribute XPathExceptionConstructor XPathException;
+#endif
+
+#if ENABLE_SVG
+ attribute SVGAngleConstructor SVGAngle;
+ attribute SVGColorConstructor SVGColor;
+// attribute SVGCSSRuleConstructor SVGCSSRule;
+ attribute SVGExceptionConstructor SVGException;
+ attribute SVGGradientElementConstructor SVGGradientElement;
+ attribute SVGLengthConstructor SVGLength;
+ attribute SVGMarkerElementConstructor SVGMarkerElement;
+ attribute SVGPaintConstructor SVGPaint;
+ attribute SVGPathSegConstructor SVGPathSeg;
+ attribute SVGPreserveAspectRatioConstructor SVGPreserveAspectRatio;
+ attribute SVGRenderingIntentConstructor SVGRenderingIntent;
+ attribute SVGTextContentElementConstructor SVGTextContentElement;
+ attribute SVGTextPathElementConstructor SVGTextPathElement;
+ attribute SVGTransformConstructor SVGTransform;
+ attribute SVGUnitTypesConstructor SVGUnitTypes;
+// attribute SVGZoomAndPanConstructor SVGZoomAndPan;
+#endif
+
+#if ENABLE_SVG_FILTERS
+ attribute SVGComponentTransferFunctionElementConstructor SVGComponentTransferFunctionElement;
+ attribute SVGFEBlendElementConstructor SVGFEBlendElement;
+ attribute SVGFEColorMatrixElementConstructor SVGFEColorMatrixElement;
+ attribute SVGFECompositeElementConstructor SVGFECompositeElement;
+// attribute SVGFEConvolveMatrixElementConstructor SVGFEConvolveMatrixElement;
+ attribute SVGFEDisplacementMapElementConstructor SVGFEDisplacementMapElement;
+// attribute SVGFEMorphologyElementConstructor SVGFEMorphologyElement;
+ attribute SVGFETurbulenceElementConstructor SVGFETurbulenceElement;
+#endif
+
+#endif // defined(LANGUAGE_JAVASCRIPT)
+ };
+
+}
diff --git a/WebCore/page/DragActions.h b/WebCore/page/DragActions.h
new file mode 100644
index 0000000..37b783b
--- /dev/null
+++ b/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/WebCore/page/DragClient.h b/WebCore/page/DragClient.h
new file mode 100644
index 0000000..4f343a0
--- /dev/null
+++ b/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/WebCore/page/DragController.cpp b/WebCore/page/DragController.cpp
new file mode 100644
index 0000000..268397e
--- /dev/null
+++ b/WebCore/page/DragController.cpp
@@ -0,0 +1,782 @@
+/*
+ * 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 "CSSStyleDeclaration.h"
+#include "Clipboard.h"
+#include "ClipboardAccessPolicy.h"
+#include "DocLoader.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 "HitTestResult.h"
+#include "Image.h"
+#include "MoveSelectionCommand.h"
+#include "Node.h"
+#include "Page.h"
+#include "RenderFileUploadControl.h"
+#include "RenderImage.h"
+#include "ReplaceSelectionCommand.h"
+#include "ResourceRequest.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "SystemTime.h"
+#include "Text.h"
+#include "htmlediting.h"
+#include "markup.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+static PlatformMouseEvent createMouseEvent(DragData* dragData)
+{
+ // FIXME: We should fake modifier keys here.
+ return PlatformMouseEvent(dragData->clientPosition(), dragData->globalPosition(),
+ LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime());
+
+}
+
+DragController::DragController(Page* page, DragClient* client)
+ : m_page(page)
+ , m_client(client)
+ , m_document(0)
+ , m_dragInitiator(0)
+ , m_dragDestinationAction(DragDestinationActionNone)
+ , m_dragSourceAction(DragSourceActionNone)
+ , m_didInitiateDrag(false)
+ , m_isHandlingDrag(false)
+ , m_dragOperation(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()) {
+ String title;
+ String url = dragData->asURL(&title);
+ if (!url.isEmpty()) {
+ ExceptionCode ec;
+ RefPtr<HTMLAnchorElement> anchor = static_cast<HTMLAnchorElement*>(document->createElement("a", ec).get());
+ anchor->setHref(url);
+ RefPtr<Node> anchorText = document->createTextNode(title);
+ 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, DragData* dragData)
+{
+ return m_document == m_dragInitiator
+ && selection->isContentEditable()
+ && !isCopyKeyDown();
+}
+
+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 = mainFrame->loader()->baseURL().isLocalFile() ? ClipboardReadable : ClipboardTypesReadable;
+ RefPtr<Clipboard> clipboard = dragData->createClipboard(policy);
+ clipboard->setSourceOperation(dragData->draggingSourceOperationMask());
+ mainFrame->eventHandler()->cancelDragAndDrop(createMouseEvent(dragData), clipboard.get());
+ clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security
+ }
+
+ cancelDrag();
+ m_document = 0;
+}
+
+DragOperation DragController::dragUpdated(DragData* dragData)
+{
+ return dragEnteredOrUpdated(dragData);
+}
+
+bool DragController::performDrag(DragData* dragData)
+{
+ ASSERT(dragData);
+ m_document = 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 = dragData->createClipboard(ClipboardReadable);
+ clipboard->setSourceOperation(dragData->draggingSourceOperationMask());
+ mainFrame->eventHandler()->performDragAndDrop(createMouseEvent(dragData), clipboard.get());
+ clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security
+ }
+ m_document = 0;
+ return true;
+ }
+
+ if ((m_dragDestinationAction & DragDestinationActionEdit) && concludeDrag(dragData, m_dragDestinationAction)) {
+ m_document = 0;
+ return true;
+ }
+
+ m_document = 0;
+
+ if (operationForLoad(dragData) == DragOperationNone)
+ return false;
+
+ m_client->willPerformDragDestinationAction(DragDestinationActionLoad, dragData);
+ m_page->mainFrame()->loader()->load(ResourceRequest(dragData->asURL()));
+ return true;
+}
+
+DragOperation DragController::dragEnteredOrUpdated(DragData* dragData)
+{
+ ASSERT(dragData);
+ IntPoint windowPoint = dragData->clientPosition();
+
+ Document* newDraggingDoc = 0;
+ if (Frame* frame = m_page->mainFrame())
+ newDraggingDoc = frame->documentAtPoint(windowPoint);
+ if (m_document != newDraggingDoc) {
+ if (m_document)
+ cancelDrag();
+ m_document = newDraggingDoc;
+ }
+
+ m_dragDestinationAction = m_client->actionMaskForDrag(dragData);
+
+ DragOperation operation = DragOperationNone;
+
+ if (m_dragDestinationAction == DragDestinationActionNone)
+ cancelDrag();
+ else {
+ operation = tryDocumentDrag(dragData, m_dragDestinationAction);
+ if (operation == DragOperationNone && (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->isShadowNode() && static_cast<HTMLInputElement*>(node)->inputType() != HTMLInputElement::FILE)
+ node = node->shadowParentNode();
+
+ if (!node || !node->hasTagName(HTMLNames::inputTag))
+ return 0;
+
+ HTMLInputElement* inputElem = static_cast<HTMLInputElement*>(node);
+ if (inputElem->inputType() == HTMLInputElement::FILE)
+ return inputElem;
+
+ return 0;
+}
+
+DragOperation DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask)
+{
+ ASSERT(dragData);
+
+ if (!m_document)
+ return DragOperationNone;
+
+ DragOperation operation = DragOperationNone;
+ if (actionMask & DragDestinationActionDHTML)
+ operation = tryDHTMLDrag(dragData);
+ m_isHandlingDrag = operation != DragOperationNone;
+
+ RefPtr<FrameView> frameView = m_document->view();
+ if (!frameView)
+ return operation;
+
+ if ((actionMask & DragDestinationActionEdit) && !m_isHandlingDrag && canProcessDrag(dragData)) {
+ if (dragData->containsColor())
+ return DragOperationGeneric;
+
+ IntPoint dragPos = dragData->clientPosition();
+ IntPoint point = frameView->windowToContents(dragPos);
+ Element* element = m_document->elementFromPoint(point.x(), point.y());
+ ASSERT(element);
+ Frame* innerFrame = element->document()->frame();
+ ASSERT(innerFrame);
+ if (!asFileInput(element)) {
+ Selection dragCaret;
+ if (Frame* frame = m_document->frame())
+ dragCaret = frame->visiblePositionForPoint(point);
+ m_page->dragCaretController()->setSelection(dragCaret);
+ }
+
+ return dragIsMove(innerFrame->selection(), dragData) ? DragOperationMove : DragOperationCopy;
+ }
+
+ m_page->dragCaretController()->clear();
+ return operation;
+}
+
+DragSourceAction DragController::delegateDragSourceAction(const IntPoint& windowPoint)
+{
+ m_dragSourceAction = m_client->dragSourceActionMaskForPoint(windowPoint);
+ return m_dragSourceAction;
+}
+
+DragOperation DragController::operationForLoad(DragData* dragData)
+{
+ ASSERT(dragData);
+ Document* doc = 0;
+ 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, Selection& 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.toRange();
+ }
+ return !frame->selection()->isNone() && frame->selection()->isContentEditable();
+}
+
+bool DragController::concludeDrag(DragData* dragData, DragDestinationAction actionMask)
+{
+ ASSERT(dragData);
+ ASSERT(!m_isHandlingDrag);
+ ASSERT(actionMask & DragDestinationActionEdit);
+
+ if (!m_document)
+ return false;
+
+ IntPoint point = m_document->view()->windowToContents(dragData->clientPosition());
+ Element* element = m_document->elementFromPoint(point.x(), point.y());
+ ASSERT(element);
+ Frame* innerFrame = element->ownerDocument()->frame();
+ ASSERT(innerFrame);
+
+ if (dragData->containsColor()) {
+ Color color = dragData->asColor();
+ if (!color.isValid())
+ return false;
+ if (!innerFrame)
+ return false;
+ RefPtr<Range> innerRange = innerFrame->selection()->toRange();
+ RefPtr<CSSStyleDeclaration> style = m_document->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->isEnabled())
+ return false;
+
+ if (!dragData->containsFiles())
+ return false;
+
+ Vector<String> filenames;
+ dragData->asFilenames(filenames);
+ if (filenames.isEmpty())
+ return false;
+
+ // Ugly. For security none of the API's available to us to 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 = static_cast<RenderFileUploadControl*>(fileInput->renderer());
+
+ if (!renderer)
+ return false;
+
+ renderer->receiveDroppedFiles(filenames);
+ return true;
+ }
+
+ Selection dragCaret(m_page->dragCaretController()->selection());
+ m_page->dragCaretController()->clear();
+ RefPtr<Range> range = dragCaret.toRange();
+
+ // For range to be null a WebKit client must have done something bad while
+ // manually controlling drag behaviour
+ if (!range)
+ return false;
+ DocLoader* loader = range->ownerDocument()->docLoader();
+ loader->setAllowStaleResources(true);
+ if (dragIsMove(innerFrame->selection(), dragData) || dragCaret.isContentRichlyEditable()) {
+ bool chosePlainText = false;
+ RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, range, true, chosePlainText);
+ if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, range, EditorInsertActionDropped)) {
+ loader->setAllowStaleResources(false);
+ return false;
+ }
+
+ m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
+ if (dragIsMove(innerFrame->selection(), dragData)) {
+ bool smartMove = innerFrame->selectionGranularity() == WordGranularity
+ && innerFrame->editor()->smartInsertDeleteEnabled()
+ && dragData->canSmartReplace();
+ applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartMove));
+ } else {
+ if (setSelectionToDragCaret(innerFrame, dragCaret, range, point))
+ applyCommand(ReplaceSelectionCommand::create(m_document, fragment, true, dragData->canSmartReplace(), chosePlainText));
+ }
+ } else {
+ String text = dragData->asPlainText();
+ if (text.isEmpty() || !innerFrame->editor()->shouldInsertText(text, range.get(), EditorInsertActionDropped)) {
+ loader->setAllowStaleResources(false);
+ return false;
+ }
+
+ m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData);
+ if (setSelectionToDragCaret(innerFrame, dragCaret, range, point))
+ applyCommand(ReplaceSelectionCommand::create(m_document, createFragmentFromText(range.get(), text), true, false, true));
+ }
+ loader->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_document == m_dragInitiator && result.isSelected())
+ return false;
+
+ return true;
+}
+
+DragOperation DragController::tryDHTMLDrag(DragData* dragData)
+{
+ ASSERT(dragData);
+ ASSERT(m_document);
+ DragOperation op = DragOperationNone;
+ RefPtr<Frame> frame = m_page->mainFrame();
+ RefPtr<FrameView> viewProtector = frame->view();
+ if (!viewProtector)
+ return DragOperationNone;
+
+ ClipboardAccessPolicy policy = frame->loader()->baseURL().isLocalFile() ? ClipboardReadable : ClipboardTypesReadable;
+ RefPtr<Clipboard> clipboard = dragData->createClipboard(policy);
+ DragOperation srcOp = dragData->draggingSourceOperationMask();
+ clipboard->setSourceOperation(srcOp);
+
+ PlatformMouseEvent event = createMouseEvent(dragData);
+ if (frame->eventHandler()->updateDragAndDrop(event, clipboard.get())) {
+ // *op unchanged if no source op was set
+ if (!clipboard->destinationOperation(op)) {
+ // The element accepted but they didn't pick an operation, so we pick one for them
+ // (as does WinIE).
+ if (srcOp & DragOperationCopy)
+ op = DragOperationCopy;
+ else if (srcOp & DragOperationMove || srcOp & DragOperationGeneric)
+ op = DragOperationMove;
+ else if (srcOp & DragOperationLink)
+ op = DragOperationLink;
+ else
+ op = DragOperationGeneric;
+ } else if (!(op & srcOp)) {
+ op = DragOperationNone;
+ }
+
+ clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security
+ return op;
+ }
+ return op;
+}
+
+bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPoint& framePos)
+{
+ ASSERT(frame);
+ ASSERT(frame->settings());
+
+ if (!frame->view() || !frame->contentRenderer())
+ return false;
+
+ HitTestResult mouseDownTarget = HitTestResult(framePos);
+
+ mouseDownTarget = frame->eventHandler()->hitTestResultAtPoint(framePos, true);
+
+ if (mouseDownTarget.image()
+ && !mouseDownTarget.absoluteImageURL().isEmpty()
+ && frame->settings()->loadsImagesAutomatically()
+ && m_dragSourceAction & DragSourceActionImage)
+ return true;
+
+ if (!mouseDownTarget.absoluteLinkURL().isEmpty()
+ && m_dragSourceAction & DragSourceActionLink
+ && mouseDownTarget.isLiveLink())
+ 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 = static_cast<RenderImage*>(renderer);
+ return image->cachedImage();
+}
+
+static Image* getImage(Element* element)
+{
+ ASSERT(element);
+ RenderObject* renderer = element->renderer();
+ if (!renderer || !renderer->isImage())
+ return 0;
+
+ RenderImage* image = static_cast<RenderImage*>(renderer);
+ if (image->cachedImage() && !image->cachedImage()->errorOccurred())
+ return image->cachedImage()->image();
+ return 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 == 0);
+ src->selection()->setSelection(Selection(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->selectionRect());
+ 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_dragOperation = srcOp;
+
+ DragImageRef dragImage = 0;
+ IntPoint dragLoc(0, 0);
+ IntPoint dragImageOffset(0, 0);
+
+ if (isDHTMLDrag)
+ dragImage = clipboard->createDragImage(dragImageOffset);
+
+ // 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();
+
+ if (!imageURL.isEmpty() && node && node->isElementNode()
+ && getImage(static_cast<Element*>(node))
+ && (m_dragSourceAction & DragSourceActionImage)) {
+ 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(Selection::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)) {
+ RefPtr<Range> selectionRange = src->selection()->toRange();
+ ASSERT(selectionRange);
+ if (!clipboard->hasData())
+ 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);
+
+ // 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();
+}
+
+// Manual drag caret manipulation
+void DragController::placeDragCaret(const IntPoint& windowPoint)
+{
+ Frame* mainFrame = m_page->mainFrame();
+ Document* newDraggingDoc = mainFrame->documentAtPoint(windowPoint);
+ if (m_document != newDraggingDoc) {
+ if (m_document)
+ cancelDrag();
+ m_document = newDraggingDoc;
+ }
+ if (!m_document)
+ return;
+ Frame* frame = m_document->frame();
+ ASSERT(frame);
+ FrameView* frameView = frame->view();
+ if (!frameView)
+ return;
+ IntPoint framePoint = frameView->windowToContents(windowPoint);
+ Selection dragCaret(frame->visiblePositionForPoint(framePoint));
+ m_page->dragCaretController()->setSelection(dragCaret);
+}
+
+}
diff --git a/WebCore/page/DragController.h b/WebCore/page/DragController.h
new file mode 100644
index 0000000..efa8292
--- /dev/null
+++ b/WebCore/page/DragController.h
@@ -0,0 +1,131 @@
+/*
+ * 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 DragController_h
+#define DragController_h
+
+#include "DragActions.h"
+#include "DragImage.h"
+#include "IntPoint.h"
+#include "IntRect.h"
+#include "KURL.h"
+
+namespace WebCore {
+
+ class Clipboard;
+ class Document;
+ class DragClient;
+ class DragData;
+ class Element;
+ class Frame;
+ class Image;
+ class Node;
+ class Page;
+ class PlatformMouseEvent;
+ class Range;
+ class SelectionController;
+
+ class DragController {
+ 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; }
+ void setDragOperation(DragOperation dragOp) { m_dragOperation = dragOp; }
+ DragOperation dragOperation() const { return m_dragOperation; }
+ void setDraggingImageURL(const KURL& url) { m_draggingImageURL = url; }
+ const KURL& draggingImageURL() const { return m_draggingImageURL; }
+ void setDragInitiator(Document* initiator) { m_dragInitiator = initiator; m_didInitiateDrag = true; }
+ Document* dragInitiator() const { return m_dragInitiator; }
+ void setDragOffset(const IntPoint& offset) { m_dragOffset = offset; }
+ const IntPoint& dragOffset() const { return m_dragOffset; }
+ DragSourceAction dragSourceAction() const { return m_dragSourceAction; }
+
+ Document* document() const { return m_document; }
+ DragDestinationAction dragDestinationAction() const { return m_dragDestinationAction; }
+ DragSourceAction delegateDragSourceAction(const IntPoint& pagePoint);
+
+ bool mayStartDragAtEventLocation(const Frame*, const IntPoint& framePos);
+ 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 canProcessDrag(DragData*);
+ bool concludeDrag(DragData*, DragDestinationAction);
+ DragOperation dragEnteredOrUpdated(DragData*);
+ DragOperation operationForLoad(DragData*);
+ DragOperation tryDocumentDrag(DragData*, DragDestinationAction);
+ DragOperation tryDHTMLDrag(DragData*);
+ DragOperation dragOperation(DragData*);
+ void cancelDrag();
+ bool dragIsMove(SelectionController*, DragData*);
+ bool isCopyKeyDown();
+
+ 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);
+ Page* m_page;
+ DragClient* m_client;
+
+ //The Document the mouse was last dragged over
+ Document* m_document;
+
+ //The Document (if any) that initiated the drag
+ Document* m_dragInitiator;
+
+ DragDestinationAction m_dragDestinationAction;
+ DragSourceAction m_dragSourceAction;
+ bool m_didInitiateDrag;
+ bool m_isHandlingDrag;
+ DragOperation m_dragOperation;
+ IntPoint m_dragOffset;
+ KURL m_draggingImageURL;
+
+ };
+
+}
+
+#endif
diff --git a/WebCore/page/EditorClient.h b/WebCore/page/EditorClient.h
new file mode 100644
index 0000000..b36709f
--- /dev/null
+++ b/WebCore/page/EditorClient.h
@@ -0,0 +1,142 @@
+/*
+ * 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 "EditorInsertAction.h"
+#include "PlatformString.h"
+#include "TextAffinity.h"
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(MAC)
+class NSArray;
+class NSData;
+class NSString;
+class NSURL;
+#endif
+
+namespace WebCore {
+
+class CSSStyleDeclaration;
+class EditCommand;
+class Element;
+class Frame;
+class HTMLElement;
+class KeyboardEvent;
+class Node;
+class Range;
+class Selection;
+class String;
+class VisiblePosition;
+
+struct GrammarDetail {
+ int location;
+ int length;
+ Vector<String> guesses;
+ String userDescription;
+};
+
+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 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;
+#ifdef BUILDING_ON_TIGER
+ virtual NSArray* pasteboardTypesForSelection(Frame*) = 0;
+#endif
+#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 void checkGrammarOfString(const UChar*, int length, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength) = 0;
+ 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;
+ virtual void getGuessesForWord(const String&, Vector<String>& guesses) = 0;
+ virtual void setInputMethodState(bool enabled) = 0;
+};
+
+}
+
+#endif // EditorClient_h
diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp
new file mode 100644
index 0000000..3f45b92
--- /dev/null
+++ b/WebCore/page/EventHandler.cpp
@@ -0,0 +1,2348 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 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 "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 "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "HTMLFrameSetElement.h"
+#include "HTMLFrameElementBase.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.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 "RenderFrameSet.h"
+#include "RenderWidget.h"
+#include "RenderView.h"
+#include "Scrollbar.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "TextEvent.h"
+
+#if ENABLE(SVG)
+#include "SVGDocument.h"
+#include "SVGElementInstance.h"
+#include "SVGNames.h"
+#include "SVGUseElement.h"
+#endif
+
+#if ENABLE(TOUCH_EVENTS) // Android
+#include "TouchEvent.h"
+#include "PlatformTouchEvent.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// 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;
+
+// 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;
+
+static Frame* subframeForTargetNode(Node*);
+static Frame* subframeForHitTestResult(const MouseEventWithHitTestResults&);
+
+static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDirection, ScrollDirection negativeDirection, PlatformWheelEvent& e, Node* node)
+{
+ if (!delta)
+ return;
+ if (e.granularity() == ScrollByPageWheelEvent) {
+ if (node->renderer()->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, 1))
+ e.accept();
+ return;
+ }
+ float pixelsToScroll = delta > 0 ? delta : -delta;
+ if (e.granularity() == ScrollByLineWheelEvent)
+ pixelsToScroll *= cMouseWheelPixelsPerLineStep;
+ if (node->renderer()->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll))
+ e.accept();
+}
+
+EventHandler::EventHandler(Frame* frame)
+ : m_frame(frame)
+ , m_mousePressed(false)
+ , m_mouseDownMayStartSelect(false)
+ , m_mouseDownMayStartDrag(false)
+ , m_mouseDownWasSingleClickInSelection(false)
+ , m_beganSelectingText(false)
+ , m_panScrollInProgress(false)
+ , m_hoverTimer(this, &EventHandler::hoverTimerFired)
+ , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired)
+ , m_autoscrollRenderer(0)
+ , m_autoscrollInProgress(false)
+ , m_mouseDownMayStartAutoscroll(false)
+ , m_mouseDownWasInSubframe(false)
+#if ENABLE(SVG)
+ , m_svgPan(false)
+#endif
+ , m_resizeLayer(0)
+ , m_capturingMouseEventsNode(0)
+ , m_clickCount(0)
+ , m_mouseDownTimestamp(0)
+ , m_pendingFrameUnloadEventCount(0)
+ , m_pendingFrameBeforeUnloadEventCount(0)
+#if PLATFORM(MAC)
+ , m_mouseDownView(nil)
+ , m_sendingEventToSubview(false)
+ , m_activationEventNumber(0)
+#endif
+{
+}
+
+EventHandler::~EventHandler()
+{
+}
+
+EventHandler::EventHandlerDragState& EventHandler::dragState()
+{
+ static EventHandlerDragState state;
+ return state;
+}
+
+void EventHandler::clear()
+{
+ m_hoverTimer.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;
+#if ENABLE(TOUCH_EVENTS) // Android
+ m_touch = 0;
+#endif
+ m_frameSetBeingResized = 0;
+ m_dragTarget = 0;
+ m_currentMousePosition = IntPoint();
+ m_mousePressNode = 0;
+ m_mousePressed = false;
+ m_capturingMouseEventsNode = 0;
+}
+
+void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
+{
+ Node* innerNode = result.targetNode();
+ Selection newSelection;
+
+ if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
+ VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
+ if (pos.isNotNull()) {
+ newSelection = Selection(pos);
+ newSelection.expandUsingGranularity(WordGranularity);
+ }
+
+ if (newSelection.isRange()) {
+ m_frame->setSelectionGranularity(WordGranularity);
+ m_beganSelectingText = true;
+ }
+
+ if (m_frame->shouldChangeSelection(newSelection))
+ m_frame->selection()->setSelection(newSelection);
+ }
+}
+
+void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
+{
+ if (!result.hitTestResult().isLiveLink())
+ return selectClosestWordFromMouseEvent(result);
+
+ Node* innerNode = result.targetNode();
+
+ if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
+ Selection newSelection;
+ Element* URLElement = result.hitTestResult().URLElement();
+ VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
+ if (pos.isNotNull() && pos.deepEquivalent().node()->isDescendantOf(URLElement))
+ newSelection = Selection::selectionFromContentsOfNode(URLElement);
+
+ if (newSelection.isRange()) {
+ m_frame->setSelectionGranularity(WordGranularity);
+ m_beganSelectingText = true;
+ }
+
+ if (m_frame->shouldChangeSelection(newSelection))
+ m_frame->selection()->setSelection(newSelection);
+ }
+}
+
+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;
+
+ Selection newSelection;
+ VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
+ if (pos.isNotNull()) {
+ newSelection = Selection(pos);
+ newSelection.expandUsingGranularity(ParagraphGranularity);
+ }
+ if (newSelection.isRange()) {
+ m_frame->setSelectionGranularity(ParagraphGranularity);
+ m_beganSelectingText = true;
+ }
+
+ if (m_frame->shouldChangeSelection(newSelection))
+ m_frame->selection()->setSelection(newSelection);
+
+ return true;
+}
+
+bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
+{
+ if (event.event().button() != LeftButton)
+ return false;
+
+ 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.
+ IntPoint vPoint = m_frame->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();
+
+ Selection newSelection = m_frame->selection()->selection();
+ if (extendSelection && newSelection.isCaretOrRange()) {
+ m_frame->selection()->setLastChangeWasHorizontalExtension(false);
+
+ // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
+ // was created right-to-left
+ Position start = newSelection.start();
+ Position end = newSelection.end();
+ short before = Range::compareBoundaryPoints(pos.node(), pos.offset(), start.node(), start.offset());
+ if (before <= 0)
+ newSelection = Selection(pos, end);
+ else
+ newSelection = Selection(start, pos);
+
+ if (m_frame->selectionGranularity() != CharacterGranularity)
+ newSelection.expandUsingGranularity(m_frame->selectionGranularity());
+ m_beganSelectingText = true;
+ } else {
+ newSelection = Selection(visiblePos);
+ m_frame->setSelectionGranularity(CharacterGranularity);
+ }
+
+ if (m_frame->shouldChangeSelection(newSelection))
+ m_frame->selection()->setSelection(newSelection);
+
+ return true;
+}
+
+bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
+{
+ // Reset drag state.
+ dragState().m_dragSrc = 0;
+
+ 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());
+
+ // Careful that the drag starting logic stays in sync with eventMayStartDrag()
+ m_mouseDownMayStartDrag = singleClick;
+
+ m_mouseDownWasSingleClickInSelection = false;
+
+ 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;
+ m_dragStartPos = event.event().pos();
+
+ bool swallowEvent = false;
+ if (event.event().button() == LeftButton || event.event().button() == MiddleButton) {
+ m_frame->selection()->setCaretBlinkingSuspended(true);
+ 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->renderer() && m_mousePressNode->renderer()->canBeProgramaticallyScrolled(true));
+
+ return swallowEvent;
+}
+
+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) {
+ // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll
+ // Otherwise, let the bridge handle it so the view can scroll itself.
+ RenderObject* renderer = targetNode->renderer();
+ while (renderer && !renderer->canBeProgramaticallyScrolled(false)) {
+ 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()
+ || event.button() != LeftButton || event.clickCount() != 1)
+ return false;
+
+ bool DHTMLFlag;
+ bool UAFlag;
+ allowDHTMLDrag(DHTMLFlag, UAFlag);
+ if (!DHTMLFlag && !UAFlag)
+ return false;
+
+ HitTestRequest request(true, false);
+ HitTestResult result(m_frame->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;
+ RenderObject* renderer = m_frame->contentRenderer();
+ if (!renderer)
+ return;
+ RenderLayer* layer = renderer->layer();
+ if (!layer)
+ return;
+
+ HitTestResult result(view->windowToContents(m_currentMousePosition));
+ layer->hitTest(HitTestRequest(true, true, true), result);
+ updateSelectionForMouseDrag(result.innerNode(), result.localPoint());
+}
+
+void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint& localPoint)
+{
+ if (!m_mouseDownMayStartSelect)
+ return;
+
+ if (!targetNode)
+ return;
+
+ RenderObject* targetRenderer = targetNode->renderer();
+ if (!targetRenderer)
+ return;
+
+ if (!canMouseDragExtendSelect(targetNode))
+ 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.
+ Selection 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 = Selection(targetPosition);
+ }
+
+ newSelection.setExtent(targetPosition);
+ if (m_frame->selectionGranularity() != CharacterGranularity)
+ newSelection.expandUsingGranularity(m_frame->selectionGranularity());
+
+ if (m_frame->shouldChangeSelection(newSelection)) {
+ m_frame->selection()->setLastChangeWasHorizontalExtension(false);
+ m_frame->selection()->setSelection(newSelection);
+ }
+}
+
+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_mouseDownMayStartDrag = false;
+ 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.
+ // 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
+ && m_dragStartPos == event.event().pos()
+ && m_frame->selection()->isRange()) {
+ Selection newSelection;
+ Node *node = event.targetNode();
+ if (node && node->isContentEditable() && node->renderer()) {
+ VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
+ newSelection = Selection(pos);
+ }
+ if (m_frame->shouldChangeSelection(newSelection))
+ m_frame->selection()->setSelection(newSelection);
+
+ handled = true;
+ }
+
+ m_frame->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();
+ m_frame->view()->addPanScrollIcon(m_panScrollStartPos);
+ // If we're not in the top frame we notify it that we are using the panScroll
+ if (m_frame != m_frame->page()->mainFrame())
+ m_frame->page()->mainFrame()->eventHandler()->setPanScrollInProgress(true);
+ }
+#endif
+
+ startAutoscrollTimer();
+}
+
+void EventHandler::autoscrollTimerFired(Timer<EventHandler>*)
+{
+ RenderObject* r = autoscrollRenderer();
+ if (!r) {
+ stopAutoscrollTimer();
+ return;
+ }
+
+ if (m_autoscrollInProgress) {
+ if (!m_mousePressed) {
+ stopAutoscrollTimer();
+ return;
+ }
+ r->autoscroll();
+ } else {
+ // we verify that the main frame hasn't received the order to stop the panScroll
+ if (!m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress()) {
+ stopAutoscrollTimer();
+ return;
+ }
+#if ENABLE(PAN_SCROLLING)
+ setPanScrollCursor();
+ r->panScroll(m_panScrollStartPos);
+#endif
+ }
+}
+
+void EventHandler::setPanScrollCursor()
+{
+ // 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
+ const int noScrollRadius = 9;
+ bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - noScrollRadius);
+ bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + noScrollRadius);
+ bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + noScrollRadius);
+ bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - noScrollRadius);
+
+ if (north) {
+ if (east)
+ m_frame->view()->setCursor(northEastPanningCursor());
+ else if (west)
+ m_frame->view()->setCursor(northWestPanningCursor());
+ else
+ m_frame->view()->setCursor(northPanningCursor());
+ } else if (south) {
+ if (east)
+ m_frame->view()->setCursor(southEastPanningCursor());
+ else if (west)
+ m_frame->view()->setCursor(southWestPanningCursor());
+ else
+ m_frame->view()->setCursor(southPanningCursor());
+ } else if (east)
+ m_frame->view()->setCursor(eastPanningCursor());
+ else if (west)
+ m_frame->view()->setCursor(westPanningCursor());
+ else
+ m_frame->view()->setCursor(middlePanningCursor());
+}
+
+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 && !m_autoscrollRenderer->canBeProgramaticallyScrolled(false))
+ m_autoscrollRenderer = m_autoscrollRenderer->parent();
+}
+
+void EventHandler::setAutoscrollRenderer(RenderObject* renderer)
+{
+ m_autoscrollRenderer = renderer;
+}
+
+void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const
+{
+ if (!m_frame || !m_frame->document()) {
+ flagDHTML = false;
+ flagUA = false;
+ return;
+ }
+
+ unsigned mask = m_frame->page()->dragController()->delegateDragSourceAction(m_frame->view()->contentsToWindow(m_mouseDownPos));
+ flagDHTML = (mask & DragSourceActionDHTML) != DragSourceActionNone;
+ flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection));
+}
+
+HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent)
+{
+ HitTestResult result(point);
+ if (!m_frame->contentRenderer())
+ return result;
+ m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(true, true), result);
+
+ while (true) {
+ Node* n = result.innerNode();
+ if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget())
+ break;
+ Widget* widget = static_cast<RenderWidget*>(n->renderer())->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() - n->renderer()->borderLeft() - n->renderer()->paddingLeft(),
+ result.localPoint().y() + view->scrollY() - n->renderer()->borderTop() - n->renderer()->paddingTop());
+ HitTestResult widgetHitTestResult(widgetPoint);
+ frame->contentRenderer()->layer()->hitTest(HitTestRequest(true, true), widgetHitTestResult);
+ result = widgetHitTestResult;
+ }
+
+ // 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;
+ Frame* mainFrame = m_frame->page()->mainFrame();
+ if (m_frame != mainFrame && resultFrame && resultFrame != mainFrame && !resultFrame->editor()->insideVisibleArea(result.point())) {
+ IntPoint windowPoint = resultFrame->view()->contentsToWindow(result.point());
+ IntPoint mainFramePoint = mainFrame->view()->windowToContents(windowPoint);
+ result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent);
+ }
+
+ 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))
+ autoscrollRenderer()->stopAutoscroll();
+#if ENABLE(PAN_SCROLLING)
+ if (m_panScrollInProgress) {
+ m_frame->view()->removePanScrollIcon();
+ m_frame->view()->setCursor(pointerCursor());
+ }
+#endif
+
+ setAutoscrollRenderer(0);
+ }
+
+ m_autoscrollTimer.stop();
+
+ m_panScrollInProgress = false;
+ // If we're not in the top frame we notify it that we are not using the panScroll anymore
+ if (m_frame->page() && m_frame != m_frame->page()->mainFrame())
+ m_frame->page()->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)
+{
+ if (!m_frame->document())
+ return false;
+
+ Node* node = m_frame->document()->focusedNode();
+ if (!node)
+ node = m_mousePressNode.get();
+
+ if (node) {
+ RenderObject *r = node->renderer();
+ if (r && !r->isListBox())
+ return r->scroll(direction, granularity);
+ }
+
+ return false;
+}
+
+IntPoint EventHandler::currentMousePosition() const
+{
+ return m_currentMousePosition;
+}
+
+Frame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
+{
+ if (!hitTestResult.isOverWidget())
+ return 0;
+ return subframeForTargetNode(hitTestResult.targetNode());
+}
+
+Frame* subframeForTargetNode(Node* node)
+{
+ if (!node)
+ return 0;
+
+ RenderObject* renderer = node->renderer();
+ if (!renderer || !renderer->isWidget())
+ return 0;
+
+ Widget* widget = static_cast<RenderWidget*>(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)->inputType() == HTMLInputElement::IMAGE;
+}
+
+// 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)
+{
+ // 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 iBeamCursor();
+
+ Node* node = event.targetNode();
+ RenderObject* renderer = node ? node->renderer() : 0;
+ RenderStyle* style = renderer ? renderer->style() : 0;
+
+ if (renderer && renderer->isFrameSet()) {
+ RenderFrameSet* fs = static_cast<RenderFrameSet*>(renderer);
+ if (fs->canResizeRow(event.localPoint()))
+ return rowResizeCursor();
+ if (fs->canResizeColumn(event.localPoint()))
+ return columnResizeCursor();
+ }
+
+ if (style && style->cursors()) {
+ const CursorList* cursors = style->cursors();
+ for (unsigned i = 0; i < cursors->size(); ++i) {
+ CachedImage* cimage = (*cursors)[i].cursorImage.get();
+ IntPoint hotSpot = (*cursors)[i].hotSpot;
+ if (!cimage)
+ continue;
+ // 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;
+ // Do not let the hotspot be outside the bounds of the image.
+ if (hotSpot.x() < 0 || hotSpot.y() < 0 || hotSpot.x() > size.width() || hotSpot.y() > size.height())
+ 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();
+ RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0;
+ bool inResizer = false;
+ if (m_frame->view() && layer && layer->isPointInResizeControl(m_frame->view()->windowToContents(event.event().pos())))
+ inResizer = true;
+ if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !scrollbar)
+ return iBeamCursor();
+ 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();
+}
+
+bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
+{
+ if (!m_frame->document())
+ return false;
+
+ RefPtr<FrameView> protector(m_frame->view());
+
+ m_mousePressed = true;
+ m_currentMousePosition = mouseEvent.pos();
+ m_mouseDownTimestamp = mouseEvent.timestamp();
+ m_mouseDownMayStartDrag = false;
+ m_mouseDownMayStartSelect = false;
+ m_mouseDownMayStartAutoscroll = false;
+ m_mouseDownPos = m_frame->view()->windowToContents(mouseEvent.pos());
+ m_mouseDownWasInSubframe = false;
+
+ MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, true), mouseEvent);
+
+ if (!mev.targetNode()) {
+ invalidateClick();
+ return false;
+ }
+
+ m_mousePressNode = mev.targetNode();
+
+ InspectorController* inspector = m_frame->page()->inspectorController();
+ if (inspector && inspector->enabled() && inspector->searchingForNodeInPage()) {
+ inspector->handleMousePressOnNode(m_mousePressNode.get());
+ invalidateClick();
+ return true;
+ }
+
+ 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.
+ if (m_mousePressed)
+ m_capturingMouseEventsNode = mev.targetNode();
+ invalidateClick();
+ return true;
+ }
+
+#if ENABLE(PAN_SCROLLING)
+ if (m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) {
+ stopAutoscrollTimer();
+ invalidateClick();
+ return true;
+ }
+
+ if (mouseEvent.button() == MiddleButton && !mev.isOverLink()) {
+ RenderObject* renderer = mev.targetNode()->renderer();
+
+ while (renderer && !renderer->canBeProgramaticallyScrolled(false)) {
+ if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
+ renderer = renderer->document()->ownerElement()->renderer();
+ else
+ renderer = renderer->parent();
+ }
+
+ if (renderer) {
+ m_panScrollInProgress = true;
+ handleAutoscroll(renderer);
+ invalidateClick();
+ return true;
+ }
+ }
+#endif
+
+ m_clickCount = mouseEvent.clickCount();
+ m_clickNode = mev.targetNode();
+
+ RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
+ IntPoint p = m_frame->view()->windowToContents(mouseEvent.pos());
+ if (layer && layer->isPointInResizeControl(p)) {
+ layer->setInResizeMode(true);
+ m_resizeLayer = layer;
+ m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
+ invalidateClick();
+ return true;
+ }
+
+ bool swallowEvent = dispatchMouseEvent(eventNames().mousedownEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
+
+ // 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();
+ mev = prepareMouseEvent(HitTestRequest(true, true), mouseEvent);
+
+ if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
+ m_lastScrollbarUnderMouse = 0;
+ }
+
+ if (swallowEvent) {
+ // scrollbars should get events anyway, even disabled controls might be scrollable
+ if (mev.scrollbar())
+ passMousePressEventToScrollbar(mev, 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()->isShadowNode() && mev.targetNode()->shadowParentNode()->hasTagName(inputTag))
+ mev = prepareMouseEvent(HitTestRequest(true, true), mouseEvent);
+
+ Scrollbar* scrollbar = m_frame->view()->scrollbarUnderMouse(mouseEvent);
+ if (!scrollbar)
+ scrollbar = mev.scrollbar();
+ 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)
+{
+ if (!m_frame->document())
+ return false;
+
+ RefPtr<FrameView> protector(m_frame->view());
+
+ // We get this instead of a second mouse-up
+ m_mousePressed = false;
+ m_currentMousePosition = mouseEvent.pos();
+
+ MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, true), mouseEvent);
+ Frame* subframe = subframeForHitTestResult(mev);
+ if (subframe && passMousePressEventToSubframe(mev, subframe)) {
+ m_capturingMouseEventsNode = 0;
+ return true;
+ }
+
+ m_clickCount = mouseEvent.clickCount();
+ bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
+
+ bool swallowClickEvent = false;
+ // Don't ever dispatch click events for right clicks
+ if (mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode)
+ swallowClickEvent = dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
+
+ if (m_lastScrollbarUnderMouse)
+ swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp();
+
+ bool swallowMouseReleaseEvent = false;
+ if (!swallowMouseUpEvent)
+ swallowMouseReleaseEvent = 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 || !m_frame->document())
+ return false;
+
+ RefPtr<FrameView> protector(m_frame->view());
+ m_currentMousePosition = mouseEvent.pos();
+
+ if (m_hoverTimer.isActive())
+ m_hoverTimer.stop();
+
+#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(m_lastScrollbarUnderMouse->transformEvent(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 request(m_mousePressed && m_mouseDownMayStartSelect, m_mousePressed, true);
+ 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 (m_frame->view())
+ scrollbar = m_frame->view()->scrollbarUnderMouse(mouseEvent);
+
+ if (!scrollbar)
+ scrollbar = mev.scrollbar();
+
+ if (m_lastScrollbarUnderMouse != scrollbar) {
+ // Send mouse exited to the old scrollbar.
+ if (m_lastScrollbarUnderMouse)
+ m_lastScrollbarUnderMouse->mouseExited();
+ m_lastScrollbarUnderMouse = m_mousePressed ? 0 : scrollbar;
+ }
+ }
+
+ 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(scrollbar->transformEvent(mouseEvent)); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
+ if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress() && m_frame->view())
+ m_frame->view()->setCursor(selectCursor(mev, scrollbar));
+ }
+
+ m_lastMouseMoveEventSubframe = newSubframe;
+
+ if (swallowEvent)
+ return true;
+
+ swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true);
+ if (!swallowEvent)
+ swallowEvent = handleMouseDraggedEvent(mev);
+
+ return swallowEvent;
+}
+
+void EventHandler::invalidateClick()
+{
+ m_clickCount = 0;
+ m_clickNode = 0;
+}
+
+bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
+{
+ if (!m_frame->document())
+ return false;
+
+ RefPtr<FrameView> protector(m_frame->view());
+
+ 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();
+ }
+
+ MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, false, false, true), mouseEvent);
+ Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
+ if (subframe && passMouseReleaseEventToSubframe(mev, subframe)) {
+ m_capturingMouseEventsNode = 0;
+ return true;
+ }
+
+ bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
+
+ // Don't ever dispatch click events for right clicks
+ bool swallowClickEvent = false;
+ if (m_clickCount > 0 && mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode)
+ swallowClickEvent = 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;
+}
+
+bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
+{
+ IntPoint contentsPos = m_frame->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 = 0;
+ EventTargetNodeCast(dragTarget)->dispatchEvent(me.get(), ec);
+ return me->defaultPrevented();
+}
+
+bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
+{
+ bool accept = false;
+
+ if (!m_frame->document())
+ return false;
+
+ if (!m_frame->view())
+ return false;
+
+ MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(true, false), 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.
+ if (newTarget)
+ if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag))
+ accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard);
+ else
+ accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget, event, clipboard);
+
+ if (m_dragTarget) {
+ Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag))
+ ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0;
+ if (frame)
+ accept = frame->eventHandler()->updateDragAndDrop(event, clipboard);
+ else
+ dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
+ }
+ } else {
+ if (newTarget)
+ if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag))
+ accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard);
+ else
+ accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget, event, clipboard);
+ }
+ m_dragTarget = newTarget;
+
+ return accept;
+}
+
+void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
+{
+ if (m_dragTarget) {
+ Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag))
+ ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0;
+ if (frame)
+ frame->eventHandler()->cancelDragAndDrop(event, clipboard);
+ else
+ dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
+ }
+ clearDragState();
+}
+
+bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
+{
+ bool accept = false;
+ if (m_dragTarget) {
+ Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag))
+ ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0;
+ if (frame)
+ accept = frame->eventHandler()->performDragAndDrop(event, clipboard);
+ else
+ accept = dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
+ }
+ clearDragState();
+ return accept;
+}
+
+void EventHandler::clearDragState()
+{
+ m_dragTarget = 0;
+ m_capturingMouseEventsNode = 0;
+#if PLATFORM(MAC)
+ m_sendingEventToSubview = false;
+#endif
+}
+
+void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
+{
+ m_capturingMouseEventsNode = n;
+}
+
+MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
+{
+ ASSERT(m_frame);
+ ASSERT(m_frame->document());
+
+ IntPoint documentPoint = m_frame->view()->windowToContents(mev.pos());
+ return m_frame->document()->prepareMouseEvent(request, documentPoint, mev);
+}
+
+#if ENABLE(SVG)
+static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
+{
+ if (!referenceNode || !referenceNode->isSVGElement())
+ return 0;
+
+ Node* shadowTreeElement = referenceNode->shadowTreeRootNode();
+ if (!shadowTreeElement)
+ return 0;
+
+ Node* shadowTreeParentElement = shadowTreeElement->shadowParentNode();
+ 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();
+ if (result)
+ result = result->shadowAncestorNode();
+ }
+ 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)
+ EventTargetNodeCast(m_lastNodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_nodeUnderMouse.get());
+ // send mouseover event to the new node
+ if (m_nodeUnderMouse)
+ EventTargetNodeCast(m_nodeUnderMouse.get())->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)
+{
+ updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
+
+ bool swallowEvent = false;
+
+ if (m_nodeUnderMouse)
+ swallowEvent = EventTargetNodeCast(m_nodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, eventType, clickCount);
+
+ if (!swallowEvent && eventType == eventNames().mousedownEvent) {
+ // Blur current focus node when a link/button is clicked; this
+ // is expected by some sites that rely on onChange handlers running
+ // from form fields before the button click is processed.
+ Node* node = m_nodeUnderMouse.get();
+ RenderObject* renderer = node ? node->renderer() : 0;
+
+ // Walk up the render tree to search for a node to focus.
+ // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
+ while (renderer) {
+ node = renderer->element();
+ if (node && node->isFocusable()) {
+ // 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->isShadowNode() ? node->shadowParentNode() : node;
+ if (m_frame->selection()->isRange() &&
+ m_frame->selection()->toRange()->compareNode(n, ec) == Range::NODE_INSIDE &&
+ n->isDescendantOf(m_frame->document()->focusedNode()))
+ return false;
+
+ break;
+ }
+
+ renderer = renderer->parent();
+ }
+ // 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 (node && node->isMouseFocusable()) {
+ if (!m_frame->page()->focusController()->setFocusedNode(node, m_frame))
+ swallowEvent = true;
+ } else if (!node || !node->focused()) {
+ if (!m_frame->page()->focusController()->setFocusedNode(0, m_frame))
+ swallowEvent = true;
+ }
+ }
+
+ return swallowEvent;
+}
+
+bool EventHandler::handleWheelEvent(PlatformWheelEvent& e)
+{
+ Document* doc = m_frame->document();
+ if (!doc)
+ return false;
+
+ RenderObject* docRenderer = doc->renderer();
+ if (!docRenderer)
+ return false;
+
+ IntPoint vPoint = m_frame->view()->windowToContents(e.pos());
+
+ HitTestRequest request(true, false);
+ HitTestResult result(vPoint);
+ doc->renderer()->layer()->hitTest(request, result);
+ Node* node = result.innerNode();
+
+ if (node) {
+ // Figure out which view to send the event to.
+ RenderObject* target = node->renderer();
+
+ if (result.isOverWidget() && target && target->isWidget()) {
+ Widget* widget = static_cast<RenderWidget*>(target)->widget();
+
+ if (widget && passWheelEventToWidget(e, widget)) {
+ e.accept();
+ return true;
+ }
+ }
+
+ node = node->shadowAncestorNode();
+ EventTargetNodeCast(node)->dispatchWheelEvent(e);
+ if (e.isAccepted())
+ return true;
+
+ if (node->renderer()) {
+ // Just break up into two scrolls if we need to. Diagonal movement on
+ // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
+ scrollAndAcceptEvent(e.deltaX(), ScrollLeft, ScrollRight, e, node);
+ scrollAndAcceptEvent(e.deltaY(), ScrollUp, ScrollDown, e, node);
+ }
+ }
+
+ if (!e.isAccepted())
+ m_frame->view()->wheelEvent(e);
+
+ return e.isAccepted();
+}
+
+bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
+{
+ Document* doc = m_frame->document();
+ FrameView* v = m_frame->view();
+ if (!doc || !v)
+ return false;
+
+ bool swallowEvent;
+ IntPoint viewportPos = v->windowToContents(event.pos());
+ MouseEventWithHitTestResults mev = doc->prepareMouseEvent(HitTestRequest(false, true), viewportPos, event);
+
+ // Context menu events shouldn't select text in GTK+ applications.
+#if !PLATFORM(GTK)
+ if (!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);
+ }
+#endif
+
+ swallowEvent = dispatchMouseEvent(eventNames().contextmenuEvent, mev.targetNode(), true, 0, event, true);
+
+ return swallowEvent;
+}
+
+void EventHandler::scheduleHoverStateUpdate()
+{
+ if (!m_hoverTimer.isActive())
+ m_hoverTimer.startOneShot(0);
+}
+
+// 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;
+
+ for (RenderObject* curr = node->renderer(); curr; curr = curr->parent())
+ if (Node* node = curr->element())
+ return EventTargetNodeCast(node)->dispatchEventForType(eventNames().selectstartEvent, true, true);
+
+ return true;
+}
+
+bool EventHandler::canMouseDragExtendSelect(Node* node)
+{
+ if (!node || !node->renderer())
+ return true;
+
+ for (RenderObject* curr = node->renderer(); curr; curr = curr->parent())
+ if (Node* node = curr->element())
+ return EventTargetNodeCast(node)->dispatchEventForType(eventNames().selectstartEvent, true, true);
+
+ return true;
+}
+
+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 (RenderObject* renderer = m_frame->contentRenderer()) {
+ HitTestResult result(m_frame->view()->windowToContents(m_currentMousePosition));
+ renderer->layer()->hitTest(HitTestRequest(false, false, true), result);
+ m_frame->document()->updateRendering();
+ }
+}
+
+static EventTargetNode* eventTargetNodeForDocument(Document* doc)
+{
+ if (!doc)
+ return 0;
+ Node* node = doc->focusedNode();
+ if (!node) {
+ if (doc->isHTMLDocument())
+ node = doc->body();
+ else
+ node = doc->documentElement();
+ if (!node)
+ return 0;
+ }
+ return EventTargetNodeCast(node);
+}
+
+bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
+{
+ if ((evt.modifiers() & s_accessKeyModifiers) != s_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 (m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) {
+ String escKeyId = "U+001B";
+ // If a key is pressed while the autoscroll/panScroll is in progress then we want to stop
+ if (initialKeyEvent.keyIdentifier() == escKeyId && initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp)
+ 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<EventTargetNode> node = eventTargetNodeForDocument(m_frame->document());
+ if (!node)
+ return false;
+
+ // 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);
+ return keydown->defaultHandled() || keydown->defaultPrevented();
+ }
+
+ // 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);
+ bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented();
+ 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;
+
+ String key = event->keyIdentifier();
+ bool isShifted = event->getModifierState("Shift");
+ bool isOptioned = event->getModifierState("Alt");
+
+ if (key == "Up") {
+ m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true);
+ event->setDefaultHandled();
+ }
+ else if (key == "Down") {
+ m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true);
+ event->setDefaultHandled();
+ }
+ else if (key == "Left") {
+ m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::LEFT, (isOptioned) ? WordGranularity : CharacterGranularity, true);
+ event->setDefaultHandled();
+ }
+ else if (key == "Right") {
+ m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::RIGHT, (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);
+
+ // 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;
+ }
+}
+
+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
+{
+ IntPoint dragLocation = m_frame->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
+{
+ ASSERT(node);
+ if (node->hasChildNodes() || !m_frame->view())
+ return false;
+ return m_frame->page() && m_frame->page()->dragController()->mayStartDragAtEventLocation(m_frame, point);
+}
+
+void EventHandler::dragSourceMovedTo(const PlatformMouseEvent& event)
+{
+ if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML)
+ // for now we don't care if event handler cancels default behavior, since there is none
+ dispatchDragSrcEvent(eventNames().dragEvent, event);
+}
+
+void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
+{
+ if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
+ 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;
+}
+
+// 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(true, false);
+ 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
+ m_frame->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) {
+ int srcX, srcY;
+ if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
+ renderer->absolutePosition(srcX, srcY);
+ IntSize delta = m_mouseDownPos - IntPoint(srcX, srcY);
+ dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), IntPoint() + 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
+ dragState().m_dragClipboard->sourceOperation(srcOp);
+
+ // Yuck, dragSourceMovedTo() can be called as a result of kicking off the drag with
+ // dragImage! Because of that dumb reentrancy, we may think we've not started the
+ // drag when that happens. So we have to assume it's started before we kick it off.
+ dragState().m_dragClipboard->setDragHasStarted();
+ }
+ }
+
+ if (m_mouseDownMayStartDrag) {
+ DragController* dragController = m_frame->page() ? m_frame->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;
+}
+
+bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent,
+ bool isLineBreak, bool isBackTab)
+{
+ if (!m_frame)
+ return false;
+#ifndef NDEBUG
+ // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
+ // and avoid dispatching text input events from keydown default handlers.
+ if (underlyingEvent && underlyingEvent->isKeyboardEvent())
+ ASSERT(static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent);
+#endif
+ EventTarget* target;
+ if (underlyingEvent)
+ target = underlyingEvent->target();
+ else
+ target = eventTargetNodeForDocument(m_frame->document());
+ if (!target)
+ return false;
+ RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text);
+ event->setUnderlyingEvent(underlyingEvent);
+ event->setIsLineBreak(isLineBreak);
+ event->setIsBackTab(isBackTab);
+ ExceptionCode ec;
+ return target->dispatchEvent(event.release(), ec);
+}
+
+
+#if !PLATFORM(MAC) && !PLATFORM(QT)
+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)
+{
+ String data = event->data();
+ if (data == "\n") {
+ if (event->isLineBreak()) {
+ if (m_frame->editor()->insertLineBreak())
+ event->setDefaultHandled();
+ } else {
+ if (m_frame->editor()->insertParagraphSeparator())
+ event->setDefaultHandled();
+ }
+ } else {
+ if (m_frame->editor()->insertTextWithoutSendingTextEvent(data, false, 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()
+{
+ if (Document* d = m_frame->document())
+ if (Node* node = d->focusedNode())
+ if (RenderObject* r = node->renderer())
+ r->capsLockStateMayHaveChanged();
+}
+
+unsigned EventHandler::pendingFrameUnloadEventCount()
+{
+ return m_pendingFrameUnloadEventCount;
+}
+
+void EventHandler::addPendingFrameUnloadEventCount()
+{
+ m_pendingFrameUnloadEventCount += 1;
+ m_frame->page()->changePendingUnloadEventCount(1);
+ return;
+}
+
+void EventHandler::removePendingFrameUnloadEventCount()
+{
+ ASSERT( (-1 + (int)m_pendingFrameUnloadEventCount) >= 0 );
+ m_pendingFrameUnloadEventCount -= 1;
+ m_frame->page()->changePendingUnloadEventCount(-1);
+ return;
+}
+
+void EventHandler::clearPendingFrameUnloadEventCount()
+{
+ m_frame->page()->changePendingUnloadEventCount(-((int)m_pendingFrameUnloadEventCount));
+ m_pendingFrameUnloadEventCount = 0;
+ return;
+}
+
+unsigned EventHandler::pendingFrameBeforeUnloadEventCount()
+{
+ return m_pendingFrameBeforeUnloadEventCount;
+}
+
+void EventHandler::addPendingFrameBeforeUnloadEventCount()
+{
+ m_pendingFrameBeforeUnloadEventCount += 1;
+ m_frame->page()->changePendingBeforeUnloadEventCount(1);
+ return;
+}
+
+void EventHandler::removePendingFrameBeforeUnloadEventCount()
+{
+ ASSERT( (-1 + (int)m_pendingFrameBeforeUnloadEventCount) >= 0 );
+ m_pendingFrameBeforeUnloadEventCount -= 1;
+ m_frame->page()->changePendingBeforeUnloadEventCount(-1);
+ return;
+}
+
+ void EventHandler::clearPendingFrameBeforeUnloadEventCount()
+{
+ m_frame->page()->changePendingBeforeUnloadEventCount(-((int)m_pendingFrameBeforeUnloadEventCount));
+ m_pendingFrameBeforeUnloadEventCount = 0;
+ return;
+}
+
+bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
+{
+ if (!scrollbar || !scrollbar->enabled())
+ return false;
+ return scrollbar->mouseDown(mev.event());
+}
+
+#if ENABLE(TOUCH_EVENTS) // Android
+bool EventHandler::handleTouchEvent(const PlatformTouchEvent& e)
+{
+ // only handle the touch event in the top frame handler
+ if (m_frame->tree()->parent(true))
+ return m_frame->tree()->parent()->eventHandler()->handleTouchEvent(e);
+
+ Document* doc = m_frame->document();
+ if (!doc)
+ return false;
+
+ RenderObject* docRenderer = doc->renderer();
+ if (!docRenderer)
+ return false;
+
+ if (doc->touchEventListeners().size() == 0)
+ return false;
+
+ TouchEventType type = e.eventType();
+ if (type == TouchEventStart) {
+ Frame* frame = m_frame;
+ IntPoint vPoint = frame->view()->windowToContents(e.pos());
+ HitTestRequest request(true, false);
+ HitTestResult result(vPoint);
+ frame->contentRenderer()->layer()->hitTest(request, result);
+ Node* node = result.innerNode();
+ if (node) {
+ RenderObject* target = node->renderer();
+ while (target && target->isWidget()) {
+ Widget* widget = static_cast<RenderWidget*>(target)->widget();
+ if (widget->isFrameView()) {
+ frame = static_cast<FrameView*>(widget)->frame();
+ vPoint = frame->view()->windowToContents(e.pos());
+ HitTestResult ret(vPoint);
+ frame->contentRenderer()->layer()->hitTest(request, ret);
+ node = ret.innerNode();
+ if (!node)
+ break;
+ else
+ target = node->renderer();
+ } else
+ // plugin view??
+ break;
+ }
+ }
+
+ if (!node || !node->isEventTargetNode()) {
+ // reset to the top document node
+ node = doc;
+ frame = m_frame;
+ vPoint = frame->view()->windowToContents(e.pos());
+ }
+
+ m_touch = Touch::create(frame, EventTargetNodeCast(node), 0,
+ e.x(), e.y(), vPoint.x(), vPoint.y());
+ } else if (m_touch) {
+ if ((type == TouchEventMove) && (e.x() == m_touch->screenX()) &&
+ (e.y() == m_touch->screenY())) {
+ // don't trigger the event if it hasn't really moved
+ return false;
+ }
+
+ IntPoint vPoint = m_touch->frame()->view()->windowToContents(e.pos());
+ m_touch->updateLocation(e.x(), e.y(), vPoint.x(), vPoint.y());
+ } else {
+ return false;
+ }
+
+ RefPtr<TouchList> touchList = TouchList::create();
+ touchList->append(m_touch);
+ RefPtr<TouchEvent> te;
+ switch(type) {
+ case TouchEventStart:
+ te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
+ eventNames().touchstartEvent, m_touch->frame()->document()->defaultView(),
+ m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
+ break;
+
+ case TouchEventEnd:
+ te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
+ eventNames().touchendEvent, m_touch->frame()->document()->defaultView(),
+ m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
+ break;
+
+ case TouchEventMove:
+ te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
+ eventNames().touchmoveEvent, m_touch->frame()->document()->defaultView(),
+ m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
+ break;
+
+ case TouchEventCancel:
+ te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
+ eventNames().touchcancelEvent, m_touch->frame()->document()->defaultView(),
+ m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
+ break;
+
+ default:
+ return false;
+ }
+ ExceptionCode ec = 0;
+ static_cast<EventTargetNode*>(m_touch->target())->dispatchEvent(te.get(), ec);
+ if (type == TouchEventEnd || type == TouchEventCancel) {
+ m_touch = 0;
+ }
+ return te->defaultPrevented();
+}
+#endif
+
+}
diff --git a/WebCore/page/EventHandler.h b/WebCore/page/EventHandler.h
new file mode 100644
index 0000000..8035494
--- /dev/null
+++ b/WebCore/page/EventHandler.h
@@ -0,0 +1,364 @@
+/*
+ * 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 EventHandler_h
+#define EventHandler_h
+
+#include "DragActions.h"
+#include "FocusDirection.h"
+#include "PlatformMouseEvent.h"
+#include "ScrollTypes.h"
+#include "Timer.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Platform.h>
+#include <wtf/RefPtr.h>
+
+#if PLATFORM(MAC)
+#include "WebCoreKeyboardUIMode.h"
+#ifndef __OBJC__
+class NSEvent;
+class NSView;
+#endif
+#endif
+
+namespace WebCore {
+
+class AtomicString;
+class Clipboard;
+class Cursor;
+class EventTargetNode;
+class Event;
+class FloatPoint;
+class FloatRect;
+class Frame;
+class HitTestResult;
+class HTMLFrameSetElement;
+class KeyboardEvent;
+class MouseEventWithHitTestResults;
+class Node;
+class PlatformKeyboardEvent;
+class PlatformWheelEvent;
+class RenderLayer;
+class RenderObject;
+class RenderWidget;
+class Scrollbar;
+class String;
+class SVGElementInstance;
+class TextEvent;
+class VisiblePosition;
+class Widget;
+#if ENABLE(TOUCH_EVENTS) // Android
+class PlatformTouchEvent;
+class Touch;
+#endif
+
+struct HitTestRequest;
+
+extern const int LinkDragHysteresis;
+extern const int ImageDragHysteresis;
+extern const int TextDragHysteresis;
+extern const int GeneralDragHysteresis;
+
+class EventHandler : Noncopyable {
+public:
+ EventHandler(Frame*);
+ ~EventHandler();
+
+ void clear();
+
+ void updateSelectionForMouseDrag();
+
+ Node* mousePressNode() const;
+ void setMousePressNode(PassRefPtr<Node>);
+
+ bool panScrollInProgress() { return m_panScrollInProgress; }
+ void setPanScrollInProgress(bool inProgress) { m_panScrollInProgress = inProgress; }
+
+ void stopAutoscrollTimer(bool rendererIsBeingDestroyed = false);
+ RenderObject* autoscrollRenderer() const;
+ void updateAutoscrollRenderer();
+
+ HitTestResult hitTestResultAtPoint(const IntPoint&, bool allowShadowContent);
+
+ bool mousePressed() const { return m_mousePressed; }
+ void setMousePressed(bool pressed) { m_mousePressed = pressed; }
+
+ void setCapturingMouseEventsNode(PassRefPtr<Node>);
+
+ bool updateDragAndDrop(const PlatformMouseEvent&, Clipboard*);
+ void cancelDragAndDrop(const PlatformMouseEvent&, Clipboard*);
+ bool performDragAndDrop(const PlatformMouseEvent&, Clipboard*);
+
+ void scheduleHoverStateUpdate();
+
+ void setResizingFrameSet(HTMLFrameSetElement*);
+
+ void resizeLayerDestroyed();
+
+ IntPoint currentMousePosition() const;
+
+ void setIgnoreWheelEvents(bool);
+
+ bool scrollOverflow(ScrollDirection, ScrollGranularity);
+
+ bool shouldDragAutoNode(Node*, const IntPoint&) const; // -webkit-user-drag == auto
+
+ bool tabsToLinks(KeyboardEvent*) const;
+ bool tabsToAllControls(KeyboardEvent*) const;
+
+ bool mouseDownMayStartSelect() const { return m_mouseDownMayStartSelect; }
+
+ bool mouseMoved(const PlatformMouseEvent&);
+
+ bool handleMousePressEvent(const PlatformMouseEvent&);
+ bool handleMouseMoveEvent(const PlatformMouseEvent&, HitTestResult* hoveredNode = 0);
+ bool handleMouseReleaseEvent(const PlatformMouseEvent&);
+ bool handleWheelEvent(PlatformWheelEvent&);
+
+#if ENABLE(TOUCH_EVENTS) // Android
+ bool handleTouchEvent(const PlatformTouchEvent&);
+#endif
+
+ bool sendContextMenuEvent(const PlatformMouseEvent&);
+
+ void setMouseDownMayStartAutoscroll() { m_mouseDownMayStartAutoscroll = true; }
+
+ bool needsKeyboardEventDisambiguationQuirks() const;
+
+ static unsigned accessKeyModifiers() { return s_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*);
+
+ bool eventMayStartDrag(const PlatformMouseEvent&) const;
+
+ void dragSourceMovedTo(const PlatformMouseEvent&);
+ void dragSourceEndedAt(const PlatformMouseEvent&, DragOperation);
+
+ void focusDocumentView();
+
+ void capsLockStateMayHaveChanged();
+
+ unsigned pendingFrameUnloadEventCount();
+ void addPendingFrameUnloadEventCount();
+ void removePendingFrameUnloadEventCount();
+ void clearPendingFrameUnloadEventCount();
+ unsigned pendingFrameBeforeUnloadEventCount();
+ void addPendingFrameBeforeUnloadEventCount();
+ void removePendingFrameBeforeUnloadEventCount();
+ void clearPendingFrameBeforeUnloadEventCount();
+
+#if PLATFORM(MAC)
+ PassRefPtr<KeyboardEvent> currentKeyboardEvent() const;
+
+ void mouseDown(NSEvent*);
+ void mouseDragged(NSEvent*);
+ void mouseUp(NSEvent*);
+ void mouseMoved(NSEvent*);
+ bool keyEvent(NSEvent*);
+ bool wheelEvent(NSEvent*);
+
+ void sendFakeEventsAfterWidgetTracking(NSEvent* initiatingEvent);
+
+ void setActivationEventNumber(int num) { m_activationEventNumber = num; }
+
+ NSEvent *currentNSEvent();
+#endif
+
+private:
+ struct EventHandlerDragState {
+ 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;
+
+ PassRefPtr<Clipboard> createDraggingClipboard() const;
+
+ bool eventActivatedView(const PlatformMouseEvent&) const;
+ void selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& event);
+ void selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& event);
+
+ bool handleMouseDoubleClickEvent(const PlatformMouseEvent&);
+
+ bool handleMousePressEvent(const MouseEventWithHitTestResults&);
+ bool handleMousePressEventSingleClick(const MouseEventWithHitTestResults&);
+ bool handleMousePressEventDoubleClick(const MouseEventWithHitTestResults&);
+ bool handleMousePressEventTripleClick(const MouseEventWithHitTestResults&);
+ bool handleMouseDraggedEvent(const MouseEventWithHitTestResults&);
+ bool handleMouseReleaseEvent(const MouseEventWithHitTestResults&);
+
+ void handleKeyboardSelectionMovement(KeyboardEvent*);
+
+ Cursor selectCursor(const MouseEventWithHitTestResults&, Scrollbar*);
+ void setPanScrollCursor();
+
+ void hoverTimerFired(Timer<EventHandler>*);
+
+ static bool canMouseDownStartSelect(Node*);
+ static bool canMouseDragExtendSelect(Node*);
+
+ void handleAutoscroll(RenderObject*);
+ void startAutoscrollTimer();
+ void setAutoscrollRenderer(RenderObject*);
+ void autoscrollTimerFired(Timer<EventHandler>*);
+
+ 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);
+ bool dispatchDragEvent(const AtomicString& eventType, Node* target, const PlatformMouseEvent&, Clipboard*);
+
+ void freeClipboard();
+
+ bool handleDrag(const MouseEventWithHitTestResults&);
+ bool handleMouseUp(const MouseEventWithHitTestResults&);
+ void clearDragState();
+
+ bool dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent&);
+
+ bool dragHysteresisExceeded(const FloatPoint&) const;
+ bool dragHysteresisExceeded(const IntPoint&) const;
+
+ 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 defaultTabEventHandler(KeyboardEvent*);
+
+ void allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const;
+
+ // The following are called at the beginning of handleMouseUp and handleDrag.
+ // If they return true it indicates that they have consumed the event.
+#if PLATFORM(MAC)
+ bool eventLoopHandleMouseUp(const MouseEventWithHitTestResults&);
+ bool eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&);
+ NSView *mouseDownViewIfStillGood();
+#else
+ bool eventLoopHandleMouseUp(const MouseEventWithHitTestResults&) { return false; }
+ bool eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&) { return false; }
+#endif
+
+ bool invertSenseOfTabsToLinks(KeyboardEvent*) const;
+
+ void updateSelectionForMouseDrag(Node* targetNode, const IntPoint& localPoint);
+
+ Frame* m_frame;
+
+ bool m_mousePressed;
+ RefPtr<Node> m_mousePressNode;
+
+ bool m_mouseDownMayStartSelect;
+ bool m_mouseDownMayStartDrag;
+ bool m_mouseDownWasSingleClickInSelection;
+ bool m_beganSelectingText;
+
+ IntPoint m_dragStartPos;
+
+ IntPoint m_panScrollStartPos;
+ bool m_panScrollInProgress;
+
+ Timer<EventHandler> m_hoverTimer;
+
+ Timer<EventHandler> m_autoscrollTimer;
+ RenderObject* m_autoscrollRenderer;
+ bool m_autoscrollInProgress;
+ bool m_mouseDownMayStartAutoscroll;
+ bool m_mouseDownWasInSubframe;
+#if ENABLE(SVG)
+ bool m_svgPan;
+ RefPtr<SVGElementInstance> m_instanceUnderMouse;
+ RefPtr<SVGElementInstance> m_lastInstanceUnderMouse;
+#endif
+
+ RenderLayer* m_resizeLayer;
+
+ RefPtr<Node> m_capturingMouseEventsNode;
+
+ 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(TOUCH_EVENTS) // Android
+ RefPtr<Touch> m_touch;
+#endif
+
+ RefPtr<Node> m_dragTarget;
+
+ RefPtr<HTMLFrameSetElement> m_frameSetBeingResized;
+
+ IntSize m_offsetFromResizeCorner;
+
+ IntPoint m_currentMousePosition;
+ IntPoint m_mouseDownPos; // in our view's coords
+ double m_mouseDownTimestamp;
+ PlatformMouseEvent m_mouseDown;
+
+ static unsigned s_accessKeyModifiers;
+
+ unsigned m_pendingFrameUnloadEventCount;
+ unsigned m_pendingFrameBeforeUnloadEventCount;
+
+#if PLATFORM(MAC)
+ NSView *m_mouseDownView;
+ bool m_sendingEventToSubview;
+ int m_activationEventNumber;
+#endif
+
+};
+
+} // namespace WebCore
+
+#endif // EventHandler_h
diff --git a/WebCore/page/FocusController.cpp b/WebCore/page/FocusController.cpp
new file mode 100644
index 0000000..9b30362
--- /dev/null
+++ b/WebCore/page/FocusController.cpp
@@ -0,0 +1,307 @@
+/*
+ * 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.
+ */
+
+#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 "Frame.h"
+#include "FrameView.h"
+#include "FrameTree.h"
+#include "HTMLFrameOwnerElement.h"
+#include "HTMLNames.h"
+#include "KeyboardEvent.h"
+#include "Page.h"
+#include "Range.h"
+#include "RenderObject.h"
+#include "RenderWidget.h"
+#include "SelectionController.h"
+#include "Widget.h"
+#include <wtf/Platform.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+FocusController::FocusController(Page* page)
+ : m_page(page)
+ , m_isActive(false)
+{
+}
+
+void FocusController::setFocusedFrame(PassRefPtr<Frame> frame)
+{
+ if (m_focusedFrame == frame)
+ return;
+
+ if (m_focusedFrame && m_focusedFrame->view())
+ m_focusedFrame->selection()->setFocused(false);
+
+ m_focusedFrame = frame;
+
+ if (m_focusedFrame && m_focusedFrame->view())
+ m_focusedFrame->selection()->setFocused(true);
+}
+
+Frame* FocusController::focusedOrMainFrame()
+{
+ if (Frame* frame = focusedFrame())
+ return frame;
+ return m_page->mainFrame();
+}
+
+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();
+ if (!document)
+ break;
+
+ 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)
+{
+ Frame* frame = focusedOrMainFrame();
+ ASSERT(frame);
+ Document* document = frame->document();
+ if (!document)
+ return false;
+
+ Node* node = (direction == FocusDirectionForward)
+ ? document->nextFocusableNode(document->focusedNode(), event)
+ : document->previousFocusableNode(document->focusedNode(), 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();
+ if (!parentDocument)
+ break;
+
+ 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.
+ if (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());
+
+ 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;
+
+ 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())
+ if (Node* root = s->rootEditableElement())
+ if (Node* shadowAncestorNode = root->shadowAncestorNode())
+ // Don't do this for textareas and text fields, when they lose focus their selections should be cleared
+ // and then restored when they regain focus, to match other browsers.
+ 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;
+
+ if (oldFocusedNode && oldFocusedNode->rootEditableElement() == oldFocusedNode && !relinquishesEditingFocus(oldFocusedNode))
+ return false;
+
+ clearSelectionIfNeeded(oldFocusedFrame.get(), newFocusedFrame.get(), node);
+
+ if (!node) {
+ if (oldDocument)
+ oldDocument->setFocusedNode(0);
+ m_page->editorClient()->setInputMethodState(false);
+ return true;
+ }
+
+ RefPtr<Document> newDocument = node ? node->document() : 0;
+
+ if (newDocument && newDocument->focusedNode() == node) {
+ m_page->editorClient()->setInputMethodState(node->shouldUseInputMethod());
+ return true;
+ }
+
+ if (oldDocument && oldDocument != newDocument)
+ oldDocument->setFocusedNode(0);
+
+ setFocusedFrame(newFocusedFrame);
+
+ if (newDocument)
+ newDocument->setFocusedNode(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->layoutIfNeededRecursive();
+ view->updateControlTints();
+ }
+ }
+
+ focusedOrMainFrame()->selection()->pageActivationChanged();
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/FocusController.h b/WebCore/page/FocusController.h
new file mode 100644
index 0000000..f4a6632
--- /dev/null
+++ b/WebCore/page/FocusController.h
@@ -0,0 +1,64 @@
+/*
+ * 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 <wtf/Forward.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ class Frame;
+ class KeyboardEvent;
+ class Node;
+ class Page;
+
+ class FocusController {
+ public:
+ FocusController(Page*);
+
+ void setFocusedFrame(PassRefPtr<Frame>);
+ Frame* focusedFrame() const { return m_focusedFrame.get(); }
+ Frame* focusedOrMainFrame();
+
+ 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; }
+
+ private:
+ Page* m_page;
+ RefPtr<Frame> m_focusedFrame;
+ bool m_isActive;
+ };
+
+} // namespace WebCore
+
+#endif // FocusController_h
diff --git a/WebCore/page/FocusDirection.h b/WebCore/page/FocusDirection.h
new file mode 100644
index 0000000..261c745
--- /dev/null
+++ b/WebCore/page/FocusDirection.h
@@ -0,0 +1,36 @@
+/*
+ * 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 {
+ FocusDirectionForward = 0,
+ FocusDirectionBackward
+ };
+}
+
+#endif // FocusDirection_h
diff --git a/WebCore/page/Frame.cpp b/WebCore/page/Frame.cpp
new file mode 100644
index 0000000..d474c3b
--- /dev/null
+++ b/WebCore/page/Frame.cpp
@@ -0,0 +1,1847 @@
+/*
+ * 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 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 "FramePrivate.h"
+
+#include "ApplyStyleCommand.h"
+#include "BeforeUnloadEvent.h"
+#include "CSSComputedStyleDeclaration.h"
+#include "CSSProperty.h"
+#include "CSSPropertyNames.h"
+#include "CachedCSSStyleSheet.h"
+#include "DOMWindow.h"
+#include "DocLoader.h"
+#include "DocumentType.h"
+#include "EditingText.h"
+#include "EditorClient.h"
+#include "EventNames.h"
+#include "FocusController.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLDocument.h"
+#include "HTMLFormElement.h"
+#include "HTMLFrameElementBase.h"
+#include "HTMLFormControlElement.h"
+#include "HTMLNames.h"
+#include "HTMLTableCellElement.h"
+#include "HitTestResult.h"
+#include "JSDOMWindowShell.h"
+#include "Logging.h"
+#include "markup.h"
+#include "MediaFeatureNames.h"
+#include "Navigator.h"
+#include "NodeList.h"
+#include "Page.h"
+#include "RegularExpression.h"
+#include "RenderPart.h"
+#include "RenderTableCell.h"
+#include "RenderTextControl.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include "Settings.h"
+#include "SystemTime.h"
+#include "TextIterator.h"
+#include "TextResourceDecoder.h"
+#include "XMLNames.h"
+#include "ScriptController.h"
+#include "npruntime_impl.h"
+#include "runtime_root.h"
+#include "visible_units.h"
+#include <wtf/RefCountedLeakCounter.h>
+
+#if FRAME_LOADS_USER_STYLESHEET
+#include "UserStyleSheetLoader.h"
+#endif
+
+#if ENABLE(SVG)
+#include "SVGDocument.h"
+#include "SVGDocumentExtensions.h"
+#include "SVGNames.h"
+#include "XLinkNames.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();
+}
+
+Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
+ : d(new FramePrivate(page, parentFromOwnerElement(ownerElement), this, ownerElement, frameLoaderClient))
+{
+ AtomicString::init();
+ EventNames::init();
+ HTMLNames::init();
+ QualifiedName::init();
+ MediaFeatureNames::init();
+
+#if ENABLE(SVG)
+ SVGNames::init();
+ XLinkNames::init();
+#endif
+
+ XMLNames::init();
+
+ if (!ownerElement)
+ page->setMainFrame(this);
+ else {
+ page->incrementFrameCount();
+ // Make sure we will not end up with two frames referencing the same owner element.
+ ASSERT((!(ownerElement->m_contentFrame)) || (ownerElement->m_contentFrame->ownerElement() != ownerElement));
+ ownerElement->m_contentFrame = this;
+ }
+
+#ifndef NDEBUG
+ frameCounter.increment();
+#endif
+}
+
+Frame::~Frame()
+{
+ setView(0);
+ loader()->clearRecordedFormValues();
+ loader()->cancelAndClear();
+
+ // FIXME: We should not be doing all this work inside the destructor
+
+ ASSERT(!d->m_lifeSupportTimer.isActive());
+
+#ifndef NDEBUG
+ frameCounter.decrement();
+#endif
+
+ if (d->m_script.haveWindowShell())
+ d->m_script.windowShell()->disconnectFrame();
+
+ disconnectOwnerElement();
+
+ if (d->m_domWindow)
+ d->m_domWindow->disconnectFrame();
+
+ HashSet<DOMWindow*>::iterator end = d->m_liveFormerWindows.end();
+ for (HashSet<DOMWindow*>::iterator it = d->m_liveFormerWindows.begin(); it != end; ++it)
+ (*it)->disconnectFrame();
+
+ if (d->m_view) {
+ d->m_view->hide();
+ d->m_view->clearFrame();
+ }
+
+ ASSERT(!d->m_lifeSupportTimer.isActive());
+
+#if FRAME_LOADS_USER_STYLESHEET
+ delete d->m_userStyleSheetLoader;
+#endif
+
+ delete d;
+ d = 0;
+}
+
+void Frame::init()
+{
+ d->m_loader.init();
+}
+
+FrameLoader* Frame::loader() const
+{
+ return &d->m_loader;
+}
+
+FrameView* Frame::view() const
+{
+ return d->m_view.get();
+}
+
+void Frame::setView(FrameView* view)
+{
+#if PLATFORM(ANDROID)
+ if (!view && d->m_view) {
+ // FIXME(for Cary): This is moved from FrameAndroid destructor. Do we
+ // need to call removeFrameGeneration per Frame or per FrameView?
+ android::WebViewCore::getWebViewCore(d->m_view.get())->removeFrameGeneration(this);
+ }
+#endif
+
+ // 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 && d->m_doc && d->m_doc->attached() && !d->m_doc->inPageCache()) {
+ // FIXME: We don't call willRemove here. Why is that OK?
+ d->m_doc->detach();
+ if (d->m_view)
+ d->m_view->unscheduleRelayout();
+ }
+ eventHandler()->clear();
+
+ d->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();
+}
+
+ScriptController* Frame::script()
+{
+ return &d->m_script;
+}
+
+Document* Frame::document() const
+{
+ return d->m_doc.get();
+}
+
+void Frame::setDocument(PassRefPtr<Document> newDoc)
+{
+ if (d->m_doc && d->m_doc->attached() && !d->m_doc->inPageCache()) {
+ // FIXME: We don't call willRemove here. Why is that OK?
+ d->m_doc->detach();
+ }
+
+ d->m_doc = newDoc;
+ if (d->m_doc && selection()->isFocusedAndActive())
+ setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive());
+
+ if (d->m_doc && !d->m_doc->attached())
+ d->m_doc->attach();
+
+ // Update the cached 'document' property, which is now stale.
+ d->m_script.updateDocument();
+}
+
+Settings* Frame::settings() const
+{
+ return d->m_page ? d->m_page->settings() : 0;
+}
+
+String Frame::selectedText() const
+{
+ return plainText(selection()->toRange().get());
+}
+
+IntRect Frame::firstRectForRange(Range* range) const
+{
+ int extraWidthToEndOfLine = 0;
+ ExceptionCode ec = 0;
+ ASSERT(range->startContainer(ec));
+ ASSERT(range->endContainer(ec));
+ InlineBox* startInlineBox;
+ int startCaretOffset;
+ range->startPosition().getInlineBoxAndOffset(DOWNSTREAM, startInlineBox, startCaretOffset);
+ IntRect startCaretRect = range->startContainer(ec)->renderer()->caretRect(startInlineBox, startCaretOffset, &extraWidthToEndOfLine);
+
+ InlineBox* endInlineBox;
+ int endCaretOffset;
+ range->endPosition().getInlineBoxAndOffset(UPSTREAM, endInlineBox, endCaretOffset);
+ IntRect endCaretRect = range->endContainer(ec)->renderer()->caretRect(endInlineBox, endCaretOffset);
+
+ if (startCaretRect.y() == endCaretRect.y()) {
+ // start and end are on the same line
+ return IntRect(min(startCaretRect.x(), endCaretRect.x()),
+ startCaretRect.y(),
+ abs(endCaretRect.x() - startCaretRect.x()),
+ max(startCaretRect.height(), endCaretRect.height()));
+ }
+
+ // start and end aren't on the same line, so go from start to the end of its line
+ return IntRect(startCaretRect.x(),
+ startCaretRect.y(),
+ startCaretRect.width() + extraWidthToEndOfLine,
+ startCaretRect.height());
+}
+
+SelectionController* Frame::selection() const
+{
+ return &d->m_selectionController;
+}
+
+Editor* Frame::editor() const
+{
+ return &d->m_editor;
+}
+
+TextGranularity Frame::selectionGranularity() const
+{
+ return d->m_selectionGranularity;
+}
+
+void Frame::setSelectionGranularity(TextGranularity granularity) const
+{
+ d->m_selectionGranularity = granularity;
+}
+
+SelectionController* Frame::dragCaretController() const
+{
+ return d->m_page->dragCaretController();
+}
+
+
+AnimationController* Frame::animation() const
+{
+ return &d->m_animationController;
+}
+
+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.
+
+ static RegularExpression wordRegExp = RegularExpression("\\w");
+ 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() != 0) {
+ startsWithWordChar = wordRegExp.search(label.substring(0, 1)) >= 0;
+ endsWithWordChar = wordRegExp.search(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(")");
+ return new RegularExpression(pattern, false);
+}
+
+String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell)
+{
+ RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer());
+
+ if (cellRenderer && cellRenderer->isTableCell()) {
+ RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer);
+
+ if (cellAboveRenderer) {
+ HTMLTableCellElement* aboveCell =
+ static_cast<HTMLTableCellElement*>(cellAboveRenderer->element());
+
+ if (aboveCell) {
+ // search within the above cell we found for a match
+ 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)
+ return nodeString.substring(pos, regExp->matchedLength());
+ }
+ }
+ }
+ }
+ }
+ // Any reason in practice to search all cells in that are above cell?
+ return String();
+}
+
+String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element)
+{
+ 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;
+
+ // 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<HTMLElement*>(n)->isGenericFormElement()))
+ {
+ // 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);
+ if (!result.isEmpty())
+ 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)
+ 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) {
+ return searchForLabelsAboveCell(regExp.get(), startingTableCell);
+ }
+ return String();
+}
+
+String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
+{
+ String name = element->getAttribute(nameAttr);
+ if (name.isEmpty())
+ return String();
+
+ // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
+ replace(name, RegularExpression("\\d"), " ");
+ name.replace('_', ' ');
+
+ OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
+ // Use the largest match we can find in the whole name string
+ int pos;
+ int length;
+ int bestPos = -1;
+ int bestLength = -1;
+ int start = 0;
+ do {
+ pos = regExp->search(name, start);
+ if (pos != -1) {
+ length = regExp->matchedLength();
+ if (length >= bestLength) {
+ bestPos = pos;
+ bestLength = length;
+ }
+ start = pos + 1;
+ }
+ } while (pos != -1);
+
+ if (bestPos != -1)
+ return name.substring(bestPos, bestLength);
+ return String();
+}
+
+const Selection& Frame::mark() const
+{
+ return d->m_mark;
+}
+
+void Frame::setMark(const Selection& s)
+{
+ ASSERT(!s.base().node() || s.base().node()->document() == document());
+ ASSERT(!s.extent().node() || s.extent().node()->document() == document());
+ ASSERT(!s.start().node() || s.start().node()->document() == document());
+ ASSERT(!s.end().node() || s.end().node()->document() == document());
+
+ d->m_mark = s;
+}
+
+void Frame::notifyRendererOfSelectionChange(bool userTriggered)
+{
+ RenderObject* renderer = 0;
+ if (selection()->rootEditableElement())
+ renderer = selection()->rootEditableElement()->shadowAncestorNode()->renderer();
+
+ // If the current selection is in a textfield or textarea, notify the renderer that the selection has changed
+ if (renderer && (renderer->isTextArea() || renderer->isTextField()))
+ static_cast<RenderTextControl*>(renderer)->selectionChanged(userTriggered);
+}
+
+void Frame::invalidateSelection()
+{
+ selection()->setNeedsLayout();
+ selectionLayoutChanged();
+}
+
+void Frame::setCaretVisible(bool flag)
+{
+ if (d->m_caretVisible == flag)
+ return;
+ clearCaretRectIfNeeded();
+ d->m_caretVisible = flag;
+ selectionLayoutChanged();
+}
+
+void Frame::clearCaretRectIfNeeded()
+{
+#if ENABLE(TEXT_CARET)
+ if (d->m_caretPaint) {
+ d->m_caretPaint = false;
+ selection()->invalidateCaretRect();
+ }
+#endif
+}
+
+// Helper function that tells whether a particular node is an element that has an entire
+// Frame and FrameView, a <frame>, <iframe>, or <object>.
+static bool isFrameElement(const Node *n)
+{
+ if (!n)
+ return false;
+ RenderObject *renderer = n->renderer();
+ if (!renderer || !renderer->isWidget())
+ return false;
+ Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
+ return widget && widget->isFrameView();
+}
+
+void Frame::setFocusedNodeIfNeeded()
+{
+ if (!document() || selection()->isNone() || !selection()->isFocusedAndActive())
+ return;
+
+ Node* target = selection()->rootEditableElement();
+ if (target) {
+ RenderObject* renderer = target->renderer();
+
+ // Walk up the render tree to search for a node to focus.
+ // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
+ while (renderer) {
+ // We don't want to set focus on a subframe when selecting in a parent frame,
+ // so add the !isFrameElement check here. There's probably a better way to make this
+ // work in the long term, but this is the safest fix at this time.
+ if (target && target->isMouseFocusable() && !isFrameElement(target)) {
+ page()->focusController()->setFocusedNode(target, this);
+ return;
+ }
+ renderer = renderer->parent();
+ if (renderer)
+ target = renderer->element();
+ }
+ document()->setFocusedNode(0);
+ }
+}
+
+void Frame::selectionLayoutChanged()
+{
+ bool caretRectChanged = selection()->recomputeCaretRect();
+
+#if ENABLE(TEXT_CARET)
+ bool shouldBlink = d->m_caretVisible
+ && selection()->isCaret() && selection()->isContentEditable();
+
+ shouldBlink = false;
+ // If the caret moved, stop the blink timer so we can restart with a
+ // black caret in the new location.
+ if (caretRectChanged || !shouldBlink)
+ d->m_caretBlinkTimer.stop();
+
+ // Start blinking with a black caret. Be sure not to restart if we're
+ // already blinking in the right location.
+ if (shouldBlink && !d->m_caretBlinkTimer.isActive()) {
+ d->m_caretBlinkTimer.startRepeating(theme()->caretBlinkFrequency());
+ if (!d->m_caretPaint) {
+ d->m_caretPaint = true;
+ selection()->invalidateCaretRect();
+ }
+ }
+#else
+ if (!caretRectChanged)
+ return;
+#endif
+
+ RenderView* canvas = contentRenderer();
+ if (!canvas)
+ return;
+
+ Selection selection = this->selection()->selection();
+
+ if (!selection.isRange())
+ canvas->clearSelection();
+ else {
+ // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection.
+ // Example: foo <a>bar</a>. Imagine that a line wrap occurs after 'foo', and that 'bar' is selected. If we pass [foo, 3]
+ // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected
+ // and will fill the gap before 'bar'.
+ Position startPos = selection.start();
+ if (startPos.downstream().isCandidate())
+ startPos = startPos.downstream();
+ Position endPos = selection.end();
+ if (endPos.upstream().isCandidate())
+ endPos = endPos.upstream();
+
+ // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted
+ // because we don't yet notify the SelectionController of text removal.
+ if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) {
+ RenderObject *startRenderer = startPos.node()->renderer();
+ RenderObject *endRenderer = endPos.node()->renderer();
+ canvas->setSelection(startRenderer, startPos.offset(), endRenderer, endPos.offset());
+ }
+ }
+}
+
+void Frame::caretBlinkTimerFired(Timer<Frame>*)
+{
+#if ENABLE(TEXT_CARET)
+ ASSERT(d->m_caretVisible);
+ ASSERT(selection()->isCaret());
+ bool caretPaint = d->m_caretPaint;
+ if (selection()->isCaretBlinkingSuspended() && caretPaint)
+ return;
+ d->m_caretPaint = !caretPaint;
+ selection()->invalidateCaretRect();
+#endif
+}
+
+void Frame::paintCaret(GraphicsContext* p, const IntRect& rect) const
+{
+#if ENABLE(TEXT_CARET)
+ if (d->m_caretPaint && d->m_caretVisible)
+ selection()->paintCaret(p, rect);
+#endif
+}
+
+void Frame::paintDragCaret(GraphicsContext* p, const IntRect& rect) const
+{
+#if ENABLE(TEXT_CARET)
+ SelectionController* dragCaretController = d->m_page->dragCaretController();
+ ASSERT(dragCaretController->selection().isCaret());
+ if (dragCaretController->selection().start().node()->document()->frame() == this)
+ dragCaretController->paintCaret(p, rect);
+#endif
+}
+
+float Frame::zoomFactor() const
+{
+ return d->m_zoomFactor;
+}
+
+bool Frame::isZoomFactorTextOnly() const
+{
+ return d->m_page->settings()->zoomsTextOnly();
+}
+
+bool Frame::shouldApplyTextZoom() const
+{
+ if (d->m_zoomFactor == 1.0f || !isZoomFactorTextOnly())
+ return false;
+#if ENABLE(SVG)
+ if (d->m_doc && d->m_doc->isSVGDocument())
+ return false;
+#endif
+ return true;
+}
+
+bool Frame::shouldApplyPageZoom() const
+{
+ if (d->m_zoomFactor == 1.0f || isZoomFactorTextOnly())
+ return false;
+#if ENABLE(SVG)
+ if (d->m_doc && d->m_doc->isSVGDocument())
+ return false;
+#endif
+ return true;
+}
+
+void Frame::setZoomFactor(float percent, bool isTextOnly)
+{
+ if (d->m_zoomFactor == percent && isZoomFactorTextOnly())
+ return;
+
+#if ENABLE(SVG)
+ // SVG doesn't care if the zoom factor is text only. It will always apply a
+ // zoom to the whole SVG.
+ if (d->m_doc && d->m_doc->isSVGDocument()) {
+ if (!static_cast<SVGDocument*>(d->m_doc.get())->zoomAndPanEnabled())
+ return;
+ d->m_zoomFactor = percent;
+ d->m_page->settings()->setZoomsTextOnly(true); // We do this to avoid doing any scaling of CSS pixels, since the SVG has its own notion of zoom.
+ if (d->m_doc->renderer())
+ d->m_doc->renderer()->repaint();
+ return;
+ }
+#endif
+
+ d->m_zoomFactor = percent;
+ d->m_page->settings()->setZoomsTextOnly(isTextOnly);
+
+ if (d->m_doc)
+ d->m_doc->recalcStyle(Node::Force);
+
+ for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
+ child->setZoomFactor(d->m_zoomFactor, isTextOnly);
+
+ if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout() && view()->didFirstLayout())
+ view()->layout();
+}
+
+void Frame::setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize)
+{
+ if (!d->m_doc)
+ return;
+
+ d->m_doc->setPrinting(printing);
+ view()->setMediaType(printing ? "print" : "screen");
+ d->m_doc->updateStyleSelector();
+ forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, adjustViewSize);
+
+ for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
+ child->setPrinting(printing, minPageWidth, maxPageWidth, adjustViewSize);
+}
+
+void Frame::setJSStatusBarText(const String& text)
+{
+ d->m_kjsStatusBarText = text;
+ if (d->m_page)
+ d->m_page->chrome()->setStatusbarText(this, d->m_kjsStatusBarText);
+}
+
+void Frame::setJSDefaultStatusBarText(const String& text)
+{
+ d->m_kjsDefaultStatusBarText = text;
+ if (d->m_page)
+ d->m_page->chrome()->setStatusbarText(this, d->m_kjsDefaultStatusBarText);
+}
+
+String Frame::jsStatusBarText() const
+{
+ return d->m_kjsStatusBarText;
+}
+
+String Frame::jsDefaultStatusBarText() const
+{
+ return d->m_kjsDefaultStatusBarText;
+}
+
+void Frame::setNeedsReapplyStyles()
+{
+ if (d->m_needsReapplyStyles)
+ return;
+
+ d->m_needsReapplyStyles = true;
+
+ // Invalidate the FrameView so that FrameView::layout will get called,
+ // which calls reapplyStyles.
+ if (view())
+ view()->invalidate();
+}
+
+bool Frame::needsReapplyStyles() const
+{
+ return d->m_needsReapplyStyles;
+}
+
+void Frame::reapplyStyles()
+{
+ d->m_needsReapplyStyles = false;
+
+ // FIXME: This call doesn't really make sense in a method called
+ // "reapplyStyles". We should probably eventually move it into its own
+ // method.
+ if (d->m_doc)
+ d->m_doc->docLoader()->setAutoLoadImages(d->m_page && d->m_page->settings()->loadsImagesAutomatically());
+
+#if FRAME_LOADS_USER_STYLESHEET
+ const KURL userStyleSheetLocation = d->m_page ? d->m_page->settings()->userStyleSheetLocation() : KURL();
+ if (!userStyleSheetLocation.isEmpty())
+ setUserStyleSheetLocation(userStyleSheetLocation);
+ else
+ setUserStyleSheet(String());
+#endif
+
+ // FIXME: It's not entirely clear why the following is needed.
+ // The document automatically does this as required when you set the style sheet.
+ // But we had problems when this code was removed. Details are in
+ // <http://bugs.webkit.org/show_bug.cgi?id=8079>.
+ if (d->m_doc)
+ d->m_doc->updateStyleSelector();
+}
+
+bool Frame::shouldChangeSelection(const Selection& newSelection) const
+{
+ return shouldChangeSelection(selection()->selection(), newSelection, newSelection.affinity(), false);
+}
+
+bool Frame::shouldChangeSelection(const Selection& oldSelection, const Selection& newSelection, EAffinity affinity, bool stillSelecting) const
+{
+ return editor()->client()->shouldChangeSelectedRange(oldSelection.toRange().get(), newSelection.toRange().get(),
+ affinity, stillSelecting);
+}
+
+bool Frame::shouldDeleteSelection(const Selection& selection) const
+{
+ return editor()->client()->shouldDeleteRange(selection.toRange().get());
+}
+
+bool Frame::isContentEditable() const
+{
+ if (d->m_editor.clientIsEditable())
+ return true;
+ if (!d->m_doc)
+ return false;
+ return d->m_doc->inDesignMode();
+}
+
+#if !PLATFORM(MAC)
+
+void Frame::setUseSecureKeyboardEntry(bool)
+{
+}
+
+#endif
+
+void Frame::updateSecureKeyboardEntryIfActive()
+{
+ if (selection()->isFocusedAndActive())
+ setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive());
+}
+
+CSSMutableStyleDeclaration *Frame::typingStyle() const
+{
+ return d->m_typingStyle.get();
+}
+
+void Frame::setTypingStyle(CSSMutableStyleDeclaration *style)
+{
+ d->m_typingStyle = style;
+}
+
+void Frame::clearTypingStyle()
+{
+ d->m_typingStyle = 0;
+}
+
+void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction)
+{
+ if (!style || style->length() == 0) {
+ clearTypingStyle();
+ return;
+ }
+
+ // Calculate the current typing style.
+ RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
+ if (typingStyle()) {
+ typingStyle()->merge(mutableStyle.get());
+ mutableStyle = typingStyle();
+ }
+
+ Node* node = selection()->selection().visibleStart().deepEquivalent().node();
+ computedStyle(node)->diff(mutableStyle.get());
+
+ // Handle block styles, substracting these from the typing style.
+ RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties();
+ blockStyle->diff(mutableStyle.get());
+ if (document() && blockStyle->length() > 0)
+ applyCommand(ApplyStyleCommand::create(document(), blockStyle.get(), editingAction));
+
+ // Set the remaining style as the typing style.
+ d->m_typingStyle = mutableStyle.release();
+}
+
+String Frame::selectionStartStylePropertyValue(int stylePropertyID) const
+{
+ Node *nodeToRemove;
+ RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
+ if (!selectionStyle)
+ return String();
+
+ String value = selectionStyle->getPropertyValue(stylePropertyID);
+
+ if (nodeToRemove) {
+ ExceptionCode ec = 0;
+ nodeToRemove->remove(ec);
+ ASSERT(ec == 0);
+ }
+
+ return value;
+}
+
+PassRefPtr<CSSComputedStyleDeclaration> Frame::selectionComputedStyle(Node*& nodeToRemove) const
+{
+ nodeToRemove = 0;
+
+ if (!document())
+ return 0;
+
+ if (selection()->isNone())
+ return 0;
+
+ RefPtr<Range> range(selection()->toRange());
+ Position pos = range->editingStartPosition();
+
+ Element *elem = pos.element();
+ if (!elem)
+ return 0;
+
+ RefPtr<Element> styleElement = elem;
+ ExceptionCode ec = 0;
+
+ if (d->m_typingStyle) {
+ styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
+ ASSERT(ec == 0);
+
+ styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
+ ASSERT(ec == 0);
+
+ styleElement->appendChild(document()->createEditingTextNode(""), ec);
+ ASSERT(ec == 0);
+
+ if (elem->renderer() && elem->renderer()->canHaveChildren()) {
+ elem->appendChild(styleElement, ec);
+ } else {
+ Node *parent = elem->parent();
+ Node *next = elem->nextSibling();
+
+ if (next) {
+ parent->insertBefore(styleElement, next, ec);
+ } else {
+ parent->appendChild(styleElement, ec);
+ }
+ }
+ ASSERT(ec == 0);
+
+ nodeToRemove = styleElement.get();
+ }
+
+ return computedStyle(styleElement.release());
+}
+
+void Frame::textFieldDidBeginEditing(Element* e)
+{
+ if (editor()->client())
+ editor()->client()->textFieldDidBeginEditing(e);
+}
+
+void Frame::textFieldDidEndEditing(Element* e)
+{
+ if (editor()->client())
+ editor()->client()->textFieldDidEndEditing(e);
+}
+
+void Frame::textDidChangeInTextField(Element* e)
+{
+ if (editor()->client())
+ editor()->client()->textDidChangeInTextField(e);
+}
+
+bool Frame::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke)
+{
+ if (editor()->client())
+ return editor()->client()->doTextFieldCommandFromEvent(e, ke);
+
+ return false;
+}
+
+void Frame::textWillBeDeletedInTextField(Element* input)
+{
+ if (editor()->client())
+ editor()->client()->textWillBeDeletedInTextField(input);
+}
+
+void Frame::textDidChangeInTextArea(Element* e)
+{
+ if (editor()->client())
+ editor()->client()->textDidChangeInTextArea(e);
+}
+
+void Frame::applyEditingStyleToBodyElement() const
+{
+ if (!d->m_doc)
+ return;
+
+ RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
+ unsigned len = list->length();
+ for (unsigned i = 0; i < len; i++) {
+ applyEditingStyleToElement(static_cast<Element*>(list->item(i)));
+ }
+}
+
+void Frame::removeEditingStyleFromBodyElement() const
+{
+ if (!d->m_doc)
+ return;
+
+ RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
+ unsigned len = list->length();
+ for (unsigned i = 0; i < len; i++) {
+ removeEditingStyleFromElement(static_cast<Element*>(list->item(i)));
+ }
+}
+
+void Frame::applyEditingStyleToElement(Element* element) const
+{
+ if (!element)
+ return;
+
+ CSSStyleDeclaration* style = element->style();
+ ASSERT(style);
+
+ ExceptionCode ec = 0;
+ style->setProperty(CSSPropertyWordWrap, "break-word", false, ec);
+ ASSERT(ec == 0);
+ style->setProperty(CSSPropertyWebkitNbspMode, "space", false, ec);
+ ASSERT(ec == 0);
+ style->setProperty(CSSPropertyWebkitLineBreak, "after-white-space", false, ec);
+ ASSERT(ec == 0);
+}
+
+void Frame::removeEditingStyleFromElement(Element*) const
+{
+}
+
+#ifndef NDEBUG
+static HashSet<Frame*>& keepAliveSet()
+{
+ static HashSet<Frame*> staticKeepAliveSet;
+ return staticKeepAliveSet;
+}
+#endif
+
+void Frame::keepAlive()
+{
+ if (d->m_lifeSupportTimer.isActive())
+ return;
+#ifndef NDEBUG
+ keepAliveSet().add(this);
+#endif
+ ref();
+ d->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->d->m_lifeSupportTimer.stop();
+ frame->deref();
+ }
+ keepAliveSet().clear();
+}
+#endif
+
+void Frame::lifeSupportTimerFired(Timer<Frame>*)
+{
+#ifndef NDEBUG
+ keepAliveSet().remove(this);
+#endif
+ deref();
+}
+
+void Frame::clearDOMWindow()
+{
+ if (d->m_domWindow) {
+ d->m_liveFormerWindows.add(d->m_domWindow.get());
+ d->m_domWindow->clear();
+ }
+ d->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 static_cast<RenderView*>(object);
+}
+
+HTMLFrameOwnerElement* Frame::ownerElement() const
+{
+ return d->m_ownerElement;
+}
+
+RenderPart* Frame::ownerRenderer() const
+{
+ HTMLFrameOwnerElement* ownerElement = d->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 d->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 static_cast<RenderPart*>(object);
+}
+
+bool Frame::isDisconnected() const
+{
+ return d->m_isDisconnected;
+}
+
+void Frame::setIsDisconnected(bool isDisconnected)
+{
+ d->m_isDisconnected = isDisconnected;
+}
+
+bool Frame::excludeFromTextSearch() const
+{
+ return d->m_excludeFromTextSearch;
+}
+
+void Frame::setExcludeFromTextSearch(bool exclude)
+{
+ d->m_excludeFromTextSearch = exclude;
+}
+
+// returns FloatRect because going through IntRect would truncate any floats
+FloatRect Frame::selectionRect(bool clipToVisibleContent) const
+{
+ RenderView* root = contentRenderer();
+ FrameView* view = d->m_view.get();
+ if (!root || !view)
+ return IntRect();
+
+ IntRect selectionRect = root->selectionRect(clipToVisibleContent);
+ return clipToVisibleContent ? intersection(selectionRect, view->visibleContentRect()) : selectionRect;
+}
+
+void Frame::selectionTextRects(Vector<FloatRect>& rects, bool clipToVisibleContent) const
+{
+ RenderView* root = contentRenderer();
+ if (!root)
+ return;
+
+ RefPtr<Range> selectedRange = selection()->toRange();
+
+ Vector<IntRect> intRects;
+ selectedRange->addLineBoxRects(intRects, true);
+
+ unsigned size = intRects.size();
+ FloatRect visibleContentRect = d->m_view->visibleContentRect();
+ for (unsigned i = 0; i < size; ++i)
+ if (clipToVisibleContent)
+ rects.append(intersection(intRects[i], visibleContentRect));
+ else
+ rects.append(intRects[i]);
+}
+
+
+bool Frame::isFrameSet() const
+{
+ Document* document = d->m_doc.get();
+ if (!document || !document->isHTMLDocument())
+ return false;
+ Node *body = static_cast<HTMLDocument*>(document)->body();
+ return body && body->renderer() && body->hasTagName(framesetTag);
+}
+
+// Scans logically forward from "start", including any child frames
+static HTMLFormElement *scanForForm(Node *start)
+{
+ Node *n;
+ for (n = start; n; n = n->traverseNextNode()) {
+ if (n->hasTagName(formTag))
+ return static_cast<HTMLFormElement*>(n);
+ else if (n->isHTMLElement() && static_cast<HTMLElement*>(n)->isGenericFormElement())
+ return static_cast<HTMLFormControlElement*>(n)->form();
+ else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) {
+ Node *childDoc = static_cast<HTMLFrameElementBase*>(n)->contentDocument();
+ if (HTMLFormElement *frameResult = scanForForm(childDoc))
+ return frameResult;
+ }
+ }
+ return 0;
+}
+
+// We look for either the form containing the current focus, or for one immediately after it
+HTMLFormElement *Frame::currentForm() const
+{
+ // start looking either at the active (first responder) node, or where the selection is
+ Node *start = d->m_doc ? d->m_doc->focusedNode() : 0;
+ if (!start)
+ start = selection()->start().node();
+
+ // try walking up the node tree to find a form element
+ Node *n;
+ for (n = start; n; n = n->parentNode()) {
+ if (n->hasTagName(formTag))
+ return static_cast<HTMLFormElement*>(n);
+ else if (n->isHTMLElement()
+ && static_cast<HTMLElement*>(n)->isGenericFormElement())
+ return static_cast<HTMLFormControlElement*>(n)->form();
+ }
+
+ // try walking forward in the node tree to find a form element
+ return start ? scanForForm(start) : 0;
+}
+
+// FIXME: should this go in SelectionController?
+void Frame::revealSelection(const RenderLayer::ScrollAlignment& alignment) const
+{
+ IntRect rect;
+
+ switch (selection()->state()) {
+ case Selection::NONE:
+ return;
+
+ case Selection::CARET:
+ rect = selection()->caretRect();
+ break;
+
+ case Selection::RANGE:
+ rect = enclosingIntRect(selectionRect(false));
+ break;
+ }
+
+ Position start = selection()->start();
+
+ ASSERT(start.node());
+ if (start.node() && start.node()->renderer()) {
+ // FIXME: This code only handles scrolling the startContainer's layer, but
+ // the selection rect could intersect more than just that.
+ // See <rdar://problem/4799899>.
+ if (RenderLayer *layer = start.node()->renderer()->enclosingLayer())
+ layer->scrollRectToVisible(rect, false, alignment, alignment);
+ }
+}
+
+void Frame::revealCaret(const RenderLayer::ScrollAlignment& alignment) const
+{
+ if (selection()->isNone())
+ return;
+
+ Position extent = selection()->extent();
+ if (extent.node() && extent.node()->renderer()) {
+ IntRect extentRect = VisiblePosition(extent).caretRect();
+ RenderLayer* layer = extent.node()->renderer()->enclosingLayer();
+ if (layer)
+ layer->scrollRectToVisible(extentRect, false, alignment, alignment);
+ }
+}
+
+void Frame::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float bottomLimit)
+{
+ RenderView* root = 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->docWidth(), (int)ceilf(oldBottom - oldTop));
+ root->layer()->paint(&context, dirtyRect);
+ *newBottom = root->bestTruncatedAt();
+ if (*newBottom == 0)
+ *newBottom = oldBottom;
+ } else
+ *newBottom = oldBottom;
+}
+
+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::forceLayout(bool allowSubtree)
+{
+ FrameView *v = d->m_view.get();
+ if (v) {
+ v->layout(allowSubtree);
+ // We cannot unschedule a pending relayout, since the force can be called with
+ // a tiny rectangle from a drawRect update. By unscheduling we in effect
+ // "validate" and stop the necessary full repaint from occurring. Basically any basic
+ // append/remove DHTML is broken by this call. For now, I have removed the optimization
+ // until we have a better invalidation stategy. -dwh
+ //v->unscheduleRelayout();
+ }
+}
+
+void Frame::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth, bool adjustViewSize)
+{
+ // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
+ // the state of things before and after the layout
+ RenderView *root = static_cast<RenderView*>(document()->renderer());
+ if (root) {
+ // This magic is basically copied from khtmlview::print
+ int pageW = (int)ceilf(minPageWidth);
+ root->setWidth(pageW);
+ root->setNeedsLayoutAndPrefWidthsRecalc();
+ forceLayout();
+
+ // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the
+ // maximum page width, we will lay out to the maximum page width and clip extra content.
+ // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping
+ // implementation should not do this!
+ int rightmostPos = root->rightmostPosition();
+ if (rightmostPos > minPageWidth) {
+ pageW = min(rightmostPos, (int)ceilf(maxPageWidth));
+ root->setWidth(pageW);
+ root->setNeedsLayoutAndPrefWidthsRecalc();
+ forceLayout();
+ }
+ }
+
+ if (adjustViewSize && view())
+ view()->adjustViewSize();
+}
+
+void Frame::sendResizeEvent()
+{
+ if (Document* doc = document())
+ doc->dispatchWindowEvent(eventNames().resizeEvent, false, false);
+}
+
+void Frame::sendScrollEvent()
+{
+ FrameView* v = d->m_view.get();
+ if (!v)
+ return;
+ v->setWasScrolledByUser(true);
+ Document* doc = document();
+ if (!doc)
+ return;
+ doc->dispatchEventForType(eventNames().scrollEvent, true, false);
+}
+
+void Frame::clearTimers(FrameView *view, Document *document)
+{
+ if (view) {
+ view->unscheduleRelayout();
+ if (view->frame()) {
+ if (document && document->renderer() && document->renderer()->hasLayer())
+ document->renderer()->layer()->suspendMarquees();
+ view->frame()->animation()->suspendAnimations(document);
+ view->frame()->eventHandler()->stopAutoscrollTimer();
+ }
+ }
+}
+
+void Frame::clearTimers()
+{
+ clearTimers(d->m_view.get(), document());
+}
+
+RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const
+{
+ nodeToRemove = 0;
+
+ if (!document())
+ return 0;
+ if (selection()->isNone())
+ return 0;
+
+ Position pos = selection()->selection().visibleStart().deepEquivalent();
+ if (!pos.isCandidate())
+ return 0;
+ Node *node = pos.node();
+ if (!node)
+ return 0;
+
+ if (!d->m_typingStyle)
+ return node->renderer()->style();
+
+ ExceptionCode ec = 0;
+ RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
+ ASSERT(ec == 0);
+
+ String styleText = d->m_typingStyle->cssText() + " display: inline";
+ styleElement->setAttribute(styleAttr, styleText.impl(), ec);
+ ASSERT(ec == 0);
+
+ styleElement->appendChild(document()->createEditingTextNode(""), ec);
+ ASSERT(ec == 0);
+
+ node->parentNode()->appendChild(styleElement, ec);
+ ASSERT(ec == 0);
+
+ nodeToRemove = styleElement.get();
+ return styleElement->renderer() ? styleElement->renderer()->style() : 0;
+}
+
+void Frame::setSelectionFromNone()
+{
+ // Put a caret inside the body if the entire frame is editable (either the
+ // entire WebView is editable or designMode is on for this document).
+ Document *doc = document();
+ if (!doc || !selection()->isNone() || !isContentEditable())
+ return;
+
+ Node* node = doc->documentElement();
+ while (node && !node->hasTagName(bodyTag))
+ node = node->traverseNextNode();
+ if (node)
+ selection()->setSelection(Selection(Position(node, 0), DOWNSTREAM));
+}
+
+bool Frame::inViewSourceMode() const
+{
+ return d->m_inViewSourceMode;
+}
+
+void Frame::setInViewSourceMode(bool mode) const
+{
+ d->m_inViewSourceMode = mode;
+}
+
+UChar Frame::backslashAsCurrencySymbol() const
+{
+ Document *doc = document();
+ if (!doc)
+ return '\\';
+ TextResourceDecoder *decoder = doc->decoder();
+ if (!decoder)
+ return '\\';
+
+ return decoder->encoding().backslashAsCurrencySymbol();
+}
+
+// Searches from the beginning of the document if nothing is selected.
+bool Frame::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection)
+{
+ if (target.isEmpty() || !document())
+ return false;
+
+ if (excludeFromTextSearch())
+ return false;
+
+ // Start from an edge of the selection, if there's a selection that's not in shadow content. Which edge
+ // is used depends on whether we're searching forward or backward, and whether startInSelection is set.
+ RefPtr<Range> searchRange(rangeOfContents(document()));
+ Selection selection = this->selection()->selection();
+
+ if (forward)
+ setStart(searchRange.get(), startInSelection ? selection.visibleStart() : selection.visibleEnd());
+ else
+ setEnd(searchRange.get(), startInSelection ? selection.visibleEnd() : selection.visibleStart());
+
+ Node* shadowTreeRoot = selection.shadowTreeRootNode();
+ if (shadowTreeRoot) {
+ ExceptionCode ec = 0;
+ if (forward)
+ searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
+ else
+ searchRange->setStart(shadowTreeRoot, 0, ec);
+ }
+
+ RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag));
+ // If we started in the selection and the found range exactly matches the existing selection, find again.
+ // Build a selection with the found range to remove collapsed whitespace.
+ // Compare ranges instead of selection objects to ignore the way that the current selection was made.
+ if (startInSelection && *Selection(resultRange.get()).toRange() == *selection.toRange()) {
+ searchRange = rangeOfContents(document());
+ if (forward)
+ setStart(searchRange.get(), selection.visibleEnd());
+ else
+ setEnd(searchRange.get(), selection.visibleStart());
+
+ if (shadowTreeRoot) {
+ ExceptionCode ec = 0;
+ if (forward)
+ searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
+ else
+ searchRange->setStart(shadowTreeRoot, 0, ec);
+ }
+
+ resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
+ }
+
+ ExceptionCode exception = 0;
+
+ // If nothing was found in the shadow tree, search in main content following the shadow tree.
+ if (resultRange->collapsed(exception) && shadowTreeRoot) {
+ searchRange = rangeOfContents(document());
+ if (forward)
+ searchRange->setStartAfter(shadowTreeRoot->shadowParentNode(), exception);
+ else
+ searchRange->setEndBefore(shadowTreeRoot->shadowParentNode(), exception);
+
+ resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
+ }
+
+ if (!editor()->insideVisibleArea(resultRange.get())) {
+ resultRange = editor()->nextVisibleRange(resultRange.get(), target, forward, caseFlag, wrapFlag);
+ if (!resultRange)
+ return false;
+ }
+
+ // If we didn't find anything and we're wrapping, search again in the entire document (this will
+ // redundantly re-search the area already searched in some cases).
+ if (resultRange->collapsed(exception) && wrapFlag) {
+ searchRange = rangeOfContents(document());
+ resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
+ // We used to return false here if we ended up with the same range that we started with
+ // (e.g., the selection was already the only instance of this text). But we decided that
+ // this should be a success case instead, so we'll just fall through in that case.
+ }
+
+ if (resultRange->collapsed(exception))
+ return false;
+
+ this->selection()->setSelection(Selection(resultRange.get(), DOWNSTREAM));
+ revealSelection();
+ return true;
+}
+
+unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsigned limit)
+{
+ if (target.isEmpty() || !document())
+ return 0;
+
+ RefPtr<Range> searchRange(rangeOfContents(document()));
+
+ ExceptionCode exception = 0;
+ unsigned matchCount = 0;
+ do {
+ RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag));
+ if (resultRange->collapsed(exception)) {
+ if (!resultRange->startContainer()->isInShadowTree())
+ break;
+
+ searchRange = rangeOfContents(document());
+ searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), exception);
+ continue;
+ }
+
+ // A non-collapsed result range can in some funky whitespace cases still not
+ // advance the range's start position (4509328). Break to avoid infinite loop.
+ VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
+ if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
+ break;
+
+ // Only treat the result as a match if it is visible
+ if (editor()->insideVisibleArea(resultRange.get())) {
+ ++matchCount;
+ document()->addMarker(resultRange.get(), DocumentMarker::TextMatch);
+ }
+
+ // Stop looking if we hit the specified limit. A limit of 0 means no limit.
+ if (limit > 0 && matchCount >= limit)
+ break;
+
+ setStart(searchRange.get(), newStart);
+ Node* shadowTreeRoot = searchRange->shadowTreeRootNode();
+ if (searchRange->collapsed(exception) && shadowTreeRoot)
+ searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), exception);
+ } while (true);
+
+ // Do a "fake" paint in order to execute the code that computes the rendered rect for
+ // each text match.
+ Document* doc = document();
+ if (doc && d->m_view && contentRenderer()) {
+ doc->updateLayout(); // Ensure layout is up to date.
+ IntRect visibleRect = d->m_view->visibleContentRect();
+ if (!visibleRect.isEmpty()) {
+ GraphicsContext context((PlatformGraphicsContext*)0);
+ context.setPaintingDisabled(true);
+ d->m_view->paintContents(&context, visibleRect);
+ }
+ }
+
+ return matchCount;
+}
+
+bool Frame::markedTextMatchesAreHighlighted() const
+{
+ return d->m_highlightTextMatches;
+}
+
+void Frame::setMarkedTextMatchesAreHighlighted(bool flag)
+{
+ if (flag == d->m_highlightTextMatches || !document())
+ return;
+
+ d->m_highlightTextMatches = flag;
+ document()->repaintMarkers(DocumentMarker::TextMatch);
+}
+
+FrameTree* Frame::tree() const
+{
+ return &d->m_treeNode;
+}
+
+DOMWindow* Frame::domWindow() const
+{
+ if (!d->m_domWindow)
+ d->m_domWindow = DOMWindow::create(const_cast<Frame*>(this));
+
+ return d->m_domWindow.get();
+}
+
+void Frame::clearFormerDOMWindow(DOMWindow* window)
+{
+ d->m_liveFormerWindows.remove(window);
+}
+
+Page* Frame::page() const
+{
+ return d->m_page;
+}
+
+EventHandler* Frame::eventHandler() const
+{
+ return &d->m_eventHandler;
+}
+
+void Frame::pageDestroyed()
+{
+ if (Frame* parent = tree()->parent())
+ parent->loader()->checkLoadComplete();
+
+ // 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();
+
+ // This will stop any JS timers
+ if (script()->haveWindowShell())
+ script()->windowShell()->disconnectFrame();
+
+ script()->clearScriptObjects();
+
+ d->m_page = 0;
+}
+
+void Frame::disconnectOwnerElement()
+{
+ if (d->m_ownerElement) {
+ if (Document* doc = document())
+ doc->clearAXObjectCache();
+ d->m_ownerElement->m_contentFrame = 0;
+ if (d->m_page)
+ d->m_page->decrementFrameCount();
+ }
+ d->m_ownerElement = 0;
+}
+
+String Frame::documentTypeString() const
+{
+ if (Document* doc = document()) {
+ if (DocumentType* doctype = doc->doctype())
+ return createMarkup(doctype);
+ }
+
+ return String();
+}
+
+void Frame::focusWindow()
+{
+ if (!page())
+ return;
+
+ // If we're a top level window, bring the window to the front.
+ if (!tree()->parent())
+ page()->chrome()->focus();
+
+ eventHandler()->focusDocumentView();
+}
+
+void Frame::unfocusWindow()
+{
+ if (!page())
+ return;
+
+ // If we're a top level window, deactivate the window.
+ if (!tree()->parent())
+ page()->chrome()->unfocus();
+}
+
+bool Frame::shouldClose()
+{
+ Chrome* chrome = page() ? page()->chrome() : 0;
+ if (!chrome || !chrome->canRunBeforeUnloadConfirmPanel())
+ return true;
+
+ RefPtr<Document> doc = document();
+ if (!doc)
+ return true;
+ HTMLElement* body = doc->body();
+ if (!body)
+ return true;
+
+ RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
+ beforeUnloadEvent->setTarget(doc);
+ doc->handleWindowEvent(beforeUnloadEvent.get(), false);
+
+ if (!beforeUnloadEvent->defaultPrevented() && doc)
+ doc->defaultEventHandler(beforeUnloadEvent.get());
+ if (beforeUnloadEvent->result().isNull())
+ return true;
+
+ String text = beforeUnloadEvent->result();
+ text.replace('\\', backslashAsCurrencySymbol());
+ return chrome->runBeforeUnloadConfirmPanel(text, this);
+}
+
+
+void Frame::scheduleClose()
+{
+ if (!shouldClose())
+ return;
+
+ Chrome* chrome = page() ? page()->chrome() : 0;
+ if (chrome)
+ chrome->closeWindowSoon();
+}
+
+void Frame::respondToChangedSelection(const Selection& oldSelection, bool closeTyping)
+{
+ if (document()) {
+ bool isContinuousSpellCheckingEnabled = editor()->isContinuousSpellCheckingEnabled();
+ bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && editor()->isGrammarCheckingEnabled();
+ if (isContinuousSpellCheckingEnabled) {
+ Selection newAdjacentWords;
+ Selection newSelectedSentence;
+ if (selection()->selection().isContentEditable()) {
+ VisiblePosition newStart(selection()->selection().visibleStart());
+ newAdjacentWords = Selection(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary));
+ if (isContinuousGrammarCheckingEnabled)
+ newSelectedSentence = Selection(startOfSentence(newStart), endOfSentence(newStart));
+ }
+
+ // When typing we check spelling elsewhere, so don't redo it here.
+ // If this is a change in selection resulting from a delete operation,
+ // oldSelection may no longer be in the document.
+ if (closeTyping && oldSelection.isContentEditable() && oldSelection.start().node() && oldSelection.start().node()->inDocument()) {
+ VisiblePosition oldStart(oldSelection.visibleStart());
+ Selection oldAdjacentWords = Selection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));
+ if (oldAdjacentWords != newAdjacentWords) {
+ editor()->markMisspellings(oldAdjacentWords);
+ if (isContinuousGrammarCheckingEnabled) {
+ Selection oldSelectedSentence = Selection(startOfSentence(oldStart), endOfSentence(oldStart));
+ if (oldSelectedSentence != newSelectedSentence)
+ editor()->markBadGrammar(oldSelectedSentence);
+ }
+ }
+ }
+
+ // This only erases markers that are in the first unit (word or sentence) of the selection.
+ // Perhaps peculiar, but it matches AppKit.
+ if (RefPtr<Range> wordRange = newAdjacentWords.toRange())
+ document()->removeMarkers(wordRange.get(), DocumentMarker::Spelling);
+ if (RefPtr<Range> sentenceRange = newSelectedSentence.toRange())
+ document()->removeMarkers(sentenceRange.get(), DocumentMarker::Grammar);
+ }
+
+ // When continuous spell checking is off, existing markers disappear after the selection changes.
+ if (!isContinuousSpellCheckingEnabled)
+ document()->removeMarkers(DocumentMarker::Spelling);
+ if (!isContinuousGrammarCheckingEnabled)
+ document()->removeMarkers(DocumentMarker::Grammar);
+ }
+
+ editor()->respondToChangedSelection(oldSelection);
+}
+
+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->positionForCoordinates(result.localPoint().x(), result.localPoint().y());
+ 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;
+}
+
+FramePrivate::FramePrivate(Page* page, Frame* parent, Frame* thisFrame, HTMLFrameOwnerElement* ownerElement,
+ FrameLoaderClient* frameLoaderClient)
+ : m_page(page)
+ , m_treeNode(thisFrame, parent)
+ , m_loader(thisFrame, frameLoaderClient)
+ , m_ownerElement(ownerElement)
+ , m_script(thisFrame)
+ , m_zoomFactor(parent ? parent->d->m_zoomFactor : 1.0f)
+ , m_selectionGranularity(CharacterGranularity)
+ , m_selectionController(thisFrame)
+ , m_caretBlinkTimer(thisFrame, &Frame::caretBlinkTimerFired)
+ , m_editor(thisFrame)
+ , m_eventHandler(thisFrame)
+ , m_animationController(thisFrame)
+ , m_lifeSupportTimer(thisFrame, &Frame::lifeSupportTimerFired)
+ , m_caretVisible(false)
+ , m_caretPaint(true)
+ , m_highlightTextMatches(false)
+ , m_inViewSourceMode(false)
+ , m_needsReapplyStyles(false)
+ , m_isDisconnected(false)
+ , m_excludeFromTextSearch(false)
+#if FRAME_LOADS_USER_STYLESHEET
+ , m_userStyleSheetLoader(0)
+#endif
+{
+}
+
+FramePrivate::~FramePrivate()
+{
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/Frame.h b/WebCore/page/Frame.h
new file mode 100644
index 0000000..8f50062
--- /dev/null
+++ b/WebCore/page/Frame.h
@@ -0,0 +1,314 @@
+/*
+ * 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 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 "DragImage.h"
+#include "EditAction.h"
+#include "RenderLayer.h"
+#include "TextGranularity.h"
+
+#if PLATFORM(MAC)
+#ifndef __OBJC__
+class NSArray;
+class NSDictionary;
+class NSMutableDictionary;
+class NSString;
+typedef int NSWritingDirection;
+#endif
+#endif
+
+namespace WebCore {
+
+class Editor;
+class EventHandler;
+class FrameLoader;
+class FrameLoaderClient;
+class FramePrivate;
+class FrameTree;
+class HTMLFrameOwnerElement;
+class HTMLTableCellElement;
+class ScriptController;
+class RegularExpression;
+class RenderPart;
+class Selection;
+class SelectionController;
+class Widget;
+
+template <typename T> class Timer;
+
+class Frame : public RefCounted<Frame> {
+public:
+ static PassRefPtr<Frame> create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client)
+ {
+ return adoptRef(new Frame(page, ownerElement, client));
+ }
+ void setView(FrameView*);
+ ~Frame();
+
+ void init();
+
+ Page* page() const;
+ HTMLFrameOwnerElement* ownerElement() const;
+
+ void pageDestroyed();
+ void disconnectOwnerElement();
+
+ Document* document() const;
+ FrameView* view() const;
+
+ DOMWindow* domWindow() const;
+ void clearFormerDOMWindow(DOMWindow*);
+ Editor* editor() const;
+ EventHandler* eventHandler() const;
+ FrameLoader* loader() const;
+ SelectionController* selection() const;
+ FrameTree* tree() const;
+ AnimationController* animation() const;
+ ScriptController* script();
+
+ RenderView* contentRenderer() const; // root renderer for the document contained in this frame
+ RenderPart* ownerRenderer() const; // renderer for the element that contains this frame
+
+ bool isDisconnected() const;
+ void setIsDisconnected(bool);
+ bool excludeFromTextSearch() const;
+ void setExcludeFromTextSearch(bool);
+
+ friend class FramePrivate;
+
+private:
+ Frame(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*);
+
+ FramePrivate* d;
+
+// === undecided, would like to consider moving to another class
+
+public:
+ static Frame* frameForWidget(const Widget*);
+
+ Settings* settings() const; // can be NULL
+
+#if FRAME_LOADS_USER_STYLESHEET
+ void setUserStyleSheetLocation(const KURL&);
+ void setUserStyleSheet(const String& styleSheetData);
+#endif
+
+ void setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize);
+
+ bool inViewSourceMode() const;
+ void setInViewSourceMode(bool = true) const;
+
+ void keepAlive(); // Used to keep the frame alive when running a script that might destroy it.
+#ifndef NDEBUG
+ static void cancelAllKeepAlive();
+#endif
+
+ void setDocument(PassRefPtr<Document>);
+
+ void clearTimers();
+ static void clearTimers(FrameView*, Document*);
+
+ // Convenience, to avoid repeating the code to dig down to get this.
+ UChar backslashAsCurrencySymbol() const;
+
+ void setNeedsReapplyStyles();
+ bool needsReapplyStyles() const;
+ void reapplyStyles();
+
+ String documentTypeString() const;
+
+ // This method -- and the corresponding list of former DOM windows --
+ // should move onto ScriptController
+ void clearDOMWindow();
+
+private:
+ void lifeSupportTimerFired(Timer<Frame>*);
+
+// === to be moved into Document
+
+public:
+ bool isFrameSet() const;
+
+// === to be moved into EventHandler
+
+public:
+ void sendResizeEvent();
+ void sendScrollEvent();
+
+// === to be moved into FrameView
+
+public:
+ void forceLayout(bool allowSubtree = false);
+ void forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth, bool adjustViewSize);
+
+ void adjustPageHeight(float* newBottom, float oldTop, float oldBottom, float bottomLimit);
+
+ void setZoomFactor(float scale, bool isTextOnly);
+ float zoomFactor() const;
+ bool isZoomFactorTextOnly() const;
+ bool shouldApplyTextZoom() const;
+ bool shouldApplyPageZoom() const;
+ float pageZoomFactor() const { return shouldApplyPageZoom() ? zoomFactor() : 1.0f; }
+ float textZoomFactor() const { return shouldApplyTextZoom() ? zoomFactor() : 1.0f; }
+
+// === to be moved into Chrome
+
+public:
+ void focusWindow();
+ void unfocusWindow();
+ bool shouldClose();
+ void scheduleClose();
+
+ void setJSStatusBarText(const String&);
+ void setJSDefaultStatusBarText(const String&);
+ String jsStatusBarText() const;
+ String jsDefaultStatusBarText() const;
+
+// === to be moved into Editor
+
+public:
+ String selectedText() const;
+ bool findString(const String&, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection);
+
+ const Selection& mark() const; // Mark, to be used as emacs uses it.
+ void setMark(const Selection&);
+
+ void computeAndSetTypingStyle(CSSStyleDeclaration* , EditAction = EditActionUnspecified);
+ String selectionStartStylePropertyValue(int stylePropertyID) const;
+ void applyEditingStyleToBodyElement() const;
+ void removeEditingStyleFromBodyElement() const;
+ void applyEditingStyleToElement(Element*) const;
+ void removeEditingStyleFromElement(Element*) const;
+
+ IntRect firstRectForRange(Range*) const;
+
+ void respondToChangedSelection(const Selection& oldSelection, bool closeTyping);
+ bool shouldChangeSelection(const Selection& oldSelection, const Selection& newSelection, EAffinity, bool stillSelecting) const;
+
+ RenderStyle* styleForSelectionStart(Node*& nodeToRemove) const;
+
+ unsigned markAllMatchesForText(const String&, bool caseFlag, unsigned limit);
+ bool markedTextMatchesAreHighlighted() const;
+ void setMarkedTextMatchesAreHighlighted(bool flag);
+
+ PassRefPtr<CSSComputedStyleDeclaration> selectionComputedStyle(Node*& nodeToRemove) const;
+
+ void textFieldDidBeginEditing(Element*);
+ void textFieldDidEndEditing(Element*);
+ void textDidChangeInTextField(Element*);
+ bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*);
+ void textWillBeDeletedInTextField(Element* input);
+ void textDidChangeInTextArea(Element*);
+
+ DragImageRef dragImageForSelection();
+
+// === to be moved into SelectionController
+
+public:
+ TextGranularity selectionGranularity() const;
+ void setSelectionGranularity(TextGranularity) const;
+
+ bool shouldChangeSelection(const Selection&) const;
+ bool shouldDeleteSelection(const Selection&) const;
+ void clearCaretRectIfNeeded();
+ void setFocusedNodeIfNeeded();
+ void selectionLayoutChanged();
+ void notifyRendererOfSelectionChange(bool userTriggered);
+
+ void invalidateSelection();
+
+ void setCaretVisible(bool = true);
+ void paintCaret(GraphicsContext*, const IntRect&) const;
+ void paintDragCaret(GraphicsContext*, const IntRect&) const;
+
+ bool isContentEditable() const; // if true, everything in frame is editable
+
+ void updateSecureKeyboardEntryIfActive();
+
+ CSSMutableStyleDeclaration* typingStyle() const;
+ void setTypingStyle(CSSMutableStyleDeclaration*);
+ void clearTypingStyle();
+
+ FloatRect selectionRect(bool clipToVisibleContent = true) const;
+ void selectionTextRects(Vector<FloatRect>&, bool clipToVisibleContent = true) const;
+
+ HTMLFormElement* currentForm() const;
+
+ void revealSelection(const RenderLayer::ScrollAlignment& = RenderLayer::gAlignCenterIfNeeded) const;
+ void revealCaret(const RenderLayer::ScrollAlignment& = RenderLayer::gAlignCenterIfNeeded) const;
+ void setSelectionFromNone();
+
+ void setUseSecureKeyboardEntry(bool);
+
+private:
+ void caretBlinkTimerFired(Timer<Frame>*);
+
+public:
+ SelectionController* dragCaretController() const;
+
+ String searchForLabelsAboveCell(RegularExpression*, HTMLTableCellElement*);
+ String searchForLabelsBeforeElement(const Vector<String>& labels, Element*);
+ String matchLabelsAgainstElement(const Vector<String>& labels, Element*);
+
+ VisiblePosition visiblePositionForPoint(const IntPoint& framePoint);
+ Document* documentAtPoint(const IntPoint& windowPoint);
+
+#if PLATFORM(MAC)
+
+// === undecided, would like to consider moving to another class
+
+public:
+ NSString* searchForNSLabelsAboveCell(RegularExpression*, HTMLTableCellElement*);
+ NSString* searchForLabelsBeforeElement(NSArray* labels, Element*);
+ NSString* matchLabelsAgainstElement(NSArray* labels, Element*);
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ NSMutableDictionary* dashboardRegionsDictionary();
+#endif
+
+ NSImage* selectionImage(bool forceBlackText = false) const;
+ NSImage* snapshotDragImage(Node*, NSRect* imageRect, NSRect* elementRect) const;
+ NSImage* nodeImage(Node*) const;
+
+private:
+ NSImage* imageFromRect(NSRect) const;
+
+// === to be moved into Editor
+
+public:
+ NSDictionary* fontAttributesForSelectionStart() const;
+ NSWritingDirection baseWritingDirectionForSelectionStart() const;
+
+#endif
+
+};
+
+} // namespace WebCore
+
+#endif // Frame_h
diff --git a/WebCore/page/FrameLoadRequest.h b/WebCore/page/FrameLoadRequest.h
new file mode 100644
index 0000000..bfb750c
--- /dev/null
+++ b/WebCore/page/FrameLoadRequest.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2003, 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 FrameLoadRequest_h
+#define FrameLoadRequest_h
+
+#include "ResourceRequest.h"
+
+namespace WebCore {
+
+ struct FrameLoadRequest {
+ public:
+ FrameLoadRequest()
+ : m_lockHistory(false)
+#ifdef ANDROID_USER_GESTURE
+ , m_wasUserGesture(true)
+#endif
+ {
+ }
+
+ FrameLoadRequest(const ResourceRequest& resourceRequest)
+ : m_resourceRequest(resourceRequest)
+ , m_lockHistory(false)
+#ifdef ANDROID_USER_GESTURE
+ , m_wasUserGesture(true)
+#endif
+ {
+ }
+
+ FrameLoadRequest(const ResourceRequest& resourceRequest, const String& frameName)
+ : m_resourceRequest(resourceRequest)
+ , m_frameName(frameName)
+ , m_lockHistory(false)
+#ifdef ANDROID_USER_GESTURE
+ , m_wasUserGesture(true)
+#endif
+ {
+ }
+
+ bool isEmpty() const { return m_resourceRequest.isEmpty(); }
+
+ 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; }
+
+ bool lockHistory() const { return m_lockHistory; }
+ void setLockHistory(bool lock) { m_lockHistory = lock; }
+
+#ifdef ANDROID_USER_GESTURE
+ void setWasUserGesture(bool wasUserGesture) { m_wasUserGesture = wasUserGesture; }
+ bool wasUserGesture() const { return m_wasUserGesture; }
+#endif
+
+ private:
+ ResourceRequest m_resourceRequest;
+ String m_frameName;
+ bool m_lockHistory;
+#ifdef ANDROID_USER_GESTURE
+ bool m_wasUserGesture;
+#endif
+ };
+
+}
+
+#endif // FrameLoadRequest_h
+
diff --git a/WebCore/page/FramePrivate.h b/WebCore/page/FramePrivate.h
new file mode 100644
index 0000000..2f7c59a
--- /dev/null
+++ b/WebCore/page/FramePrivate.h
@@ -0,0 +1,99 @@
+/* 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 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.
+ */
+
+#ifndef FramePrivate_h
+#define FramePrivate_h
+
+#include "AnimationController.h"
+#include "Editor.h"
+#include "EventHandler.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "Range.h"
+#include "SelectionController.h"
+#include "StringHash.h"
+#include "ScriptController.h"
+
+#if PLATFORM(WIN)
+#include "FrameWin.h"
+#endif
+
+namespace WebCore {
+
+#if FRAME_LOADS_USER_STYLESHEET
+ class UserStyleSheetLoader;
+#endif
+
+ class FramePrivate {
+ public:
+ FramePrivate(Page*, Frame* parent, Frame* thisFrame, HTMLFrameOwnerElement*, FrameLoaderClient*);
+ ~FramePrivate();
+
+ Page* m_page;
+ FrameTree m_treeNode;
+ FrameLoader m_loader;
+ RefPtr<DOMWindow> m_domWindow;
+ HashSet<DOMWindow*> m_liveFormerWindows;
+
+ HTMLFrameOwnerElement* m_ownerElement;
+ RefPtr<FrameView> m_view;
+ RefPtr<Document> m_doc;
+
+ ScriptController m_script;
+
+ String m_kjsStatusBarText;
+ String m_kjsDefaultStatusBarText;
+
+ float m_zoomFactor;
+
+ TextGranularity m_selectionGranularity;
+
+ SelectionController m_selectionController;
+ Selection m_mark;
+ Timer<Frame> m_caretBlinkTimer;
+ Editor m_editor;
+ EventHandler m_eventHandler;
+ AnimationController m_animationController;
+
+ RefPtr<CSSMutableStyleDeclaration> m_typingStyle;
+
+ Timer<Frame> m_lifeSupportTimer;
+
+ bool m_caretVisible;
+ bool m_caretPaint;
+
+ bool m_highlightTextMatches;
+ bool m_inViewSourceMode;
+ bool m_needsReapplyStyles;
+ bool m_isDisconnected;
+ bool m_excludeFromTextSearch;
+
+#if FRAME_LOADS_USER_STYLESHEET
+ UserStyleSheetLoader* m_userStyleSheetLoader;
+#endif
+ };
+}
+
+#endif
diff --git a/WebCore/page/FrameTree.cpp b/WebCore/page/FrameTree.cpp
new file mode 100644
index 0000000..c9b4172
--- /dev/null
+++ b/WebCore/page/FrameTree.cpp
@@ -0,0 +1,314 @@
+/*
+ * 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 "Page.h"
+#include "PageGroup.h"
+#include <stdarg.h>
+#include <wtf/Platform.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)
+{
+ if (!parent()) {
+ m_name = name;
+ return;
+ }
+ m_name = AtomicString(); // Remove our old frame name so it's not considered in uniqueChildName.
+ m_name = parent()->tree()->uniqueChildName(name);
+}
+
+void FrameTree::clearName()
+{
+ m_name = AtomicString();
+}
+
+Frame* FrameTree::parent(bool checkForDisconnectedFrame) const
+{
+ if (checkForDisconnectedFrame && m_thisFrame->isDisconnected())
+ return 0;
+ return m_parent;
+}
+
+void FrameTree::appendChild(PassRefPtr<Frame> child)
+{
+ ASSERT(child->page() == m_thisFrame->page());
+ 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;
+ child->setView(0);
+ if (child->ownerElement())
+ child->page()->decrementFrameCount();
+ child->pageDestroyed();
+
+ // 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:: namepsace
+ 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()->name().startsWith(framePathPrefix))
+ break;
+ chain.append(frame);
+ }
+ String name;
+ name += framePathPrefix;
+ if (frame)
+ name += frame->tree()->name().string().substring(framePathPrefixLength,
+ frame->tree()->name().length() - framePathPrefixLength - framePathSuffixLength);
+ for (int i = chain.size() - 1; i >= 0; --i) {
+ frame = chain[i];
+ name += "/";
+ name += frame->tree()->name();
+ }
+
+ // Suffix buffer has more than enough space for:
+ // 10 characters before the number
+ // a number (3 digits for the highest this gets in practice, 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()->name() == 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()->name() == 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()->name() == 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()->name() == 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/WebCore/page/FrameTree.h b/WebCore/page/FrameTree.h
new file mode 100644
index 0000000..0952dcd
--- /dev/null
+++ b/WebCore/page/FrameTree.h
@@ -0,0 +1,86 @@
+/*
+ * 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 "AtomicString.h"
+#include "Frame.h"
+
+namespace WebCore {
+
+ class FrameTree : 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; }
+ 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>);
+ 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;
+
+ Frame* m_thisFrame;
+
+ Frame* m_parent;
+ AtomicString m_name;
+
+ // 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/WebCore/page/FrameView.cpp b/WebCore/page/FrameView.cpp
new file mode 100644
index 0000000..1d5ef9f
--- /dev/null
+++ b/WebCore/page/FrameView.cpp
@@ -0,0 +1,1258 @@
+/*
+ * 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)
+ *
+ * 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 "ChromeClient.h"
+#include "EventHandler.h"
+#include "FloatRect.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "GraphicsContext.h"
+#include "HTMLDocument.h"
+#include "HTMLFrameElement.h"
+#include "HTMLFrameSetElement.h"
+#include "HTMLNames.h"
+#include "OverflowEvent.h"
+#include "Page.h"
+#include "RenderPart.h"
+#include "RenderPartObject.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include "Settings.h"
+#include "SystemTime.h"
+
+#ifdef ANDROID_INSTRUMENT
+#include "FrameTree.h"
+#include "TimeCounter.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+double FrameView::sCurrentPaintTimeStamp = 0.0;
+
+struct ScheduledEvent {
+ RefPtr<Event> m_event;
+ RefPtr<EventTargetNode> m_eventTarget;
+};
+
+class FrameViewPrivate {
+public:
+ FrameViewPrivate(FrameView* view)
+ : m_slowRepaintObjectCount(0)
+ , m_layoutTimer(view, &FrameView::layoutTimerFired)
+ , m_layoutRoot(0)
+ , m_postLayoutTasksTimer(view, &FrameView::postLayoutTimerFired)
+ , m_mediaType("screen")
+ , m_enqueueEvents(0)
+ , m_overflowStatusDirty(true)
+ , m_viewportRenderer(0)
+ , m_wasScrolledByUser(false)
+ , m_inProgrammaticScroll(false)
+ , m_shouldUpdateWhileOffscreen(true)
+ {
+ m_isTransparent = false;
+ m_baseBackgroundColor = Color::white;
+ m_vmode = m_hmode = ScrollbarAuto;
+ m_needToInitScrollbars = true;
+ reset();
+ }
+ void reset()
+ {
+ m_useSlowRepaints = false;
+ m_borderX = 30;
+ m_borderY = 30;
+ m_layoutTimer.stop();
+ m_layoutRoot = 0;
+ m_delayedLayout = false;
+ m_doFullRepaint = true;
+ m_layoutSchedulingEnabled = true;
+ m_midLayout = 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_repaintRect = IntRect();
+ m_repaintRects.clear();
+ m_paintRestriction = PaintRestrictionNone;
+ m_isPainting = false;
+ }
+
+ bool m_doFullRepaint;
+
+ ScrollbarMode m_vmode;
+ ScrollbarMode m_hmode;
+ bool m_useSlowRepaints;
+ unsigned m_slowRepaintObjectCount;
+
+ int m_borderX, m_borderY;
+
+ Timer<FrameView> m_layoutTimer;
+ bool m_delayedLayout;
+ RenderObject* m_layoutRoot;
+
+ bool m_layoutSchedulingEnabled;
+ bool m_midLayout;
+ int m_layoutCount;
+ unsigned m_nestedLayoutCount;
+ Timer<FrameView> m_postLayoutTasksTimer;
+ bool m_firstLayoutCallbackPending;
+
+ bool m_firstLayout;
+ bool m_needToInitScrollbars;
+ bool m_isTransparent;
+ Color m_baseBackgroundColor;
+ IntSize m_lastLayoutSize;
+ float m_lastZoomFactor;
+
+ String m_mediaType;
+
+ 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;
+ IntRect m_repaintRect;
+ Vector<IntRect> m_repaintRects;
+
+ bool m_shouldUpdateWhileOffscreen;
+
+ RefPtr<Node> m_nodeToDraw;
+ PaintRestriction m_paintRestriction;
+ bool m_isPainting;
+};
+
+FrameView::FrameView(Frame* frame)
+ : m_refCount(1)
+ , m_frame(frame)
+ , d(new FrameViewPrivate(this))
+{
+ init();
+ show();
+}
+
+FrameView::FrameView(Frame* frame, const IntSize& initialSize)
+ : m_refCount(1)
+ , m_frame(frame)
+ , d(new FrameViewPrivate(this))
+{
+ init();
+ Widget::setFrameRect(IntRect(x(), y(), initialSize.width(), initialSize.height()));
+ show();
+}
+
+FrameView::~FrameView()
+{
+ if (d->m_postLayoutTasksTimer.isActive()) {
+ d->m_postLayoutTasksTimer.stop();
+ d->m_scheduledEvents.clear();
+ d->m_enqueueEvents = 0;
+ }
+
+ resetScrollbars();
+ setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
+ setHasVerticalScrollbar(false);
+
+ ASSERT(m_refCount == 0);
+ ASSERT(d->m_scheduledEvents.isEmpty());
+ ASSERT(!d->m_enqueueEvents);
+
+ if (m_frame) {
+ ASSERT(m_frame->view() != this || !m_frame->document() || !m_frame->contentRenderer());
+ RenderPart* renderer = m_frame->ownerRenderer();
+ if (renderer && renderer->widget() == this)
+ renderer->setWidget(0);
+ }
+
+ delete d;
+ d = 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.
+ d->m_firstLayout = true;
+ setScrollbarsSuppressed(true);
+ setScrollbarModes(d->m_hmode, d->m_vmode);
+ setScrollbarsSuppressed(false);
+}
+
+void FrameView::init()
+{
+ 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->getMarginWidth();
+ int marginHeight = frameElt->getMarginHeight();
+ if (marginWidth != -1)
+ setMarginWidth(marginWidth);
+ if (marginHeight != -1)
+ setMarginHeight(marginHeight);
+ }
+}
+
+void FrameView::clear()
+{
+ setCanBlitOnScroll(true);
+
+ d->reset();
+
+ if (m_frame)
+ if (RenderPart* renderer = m_frame->ownerRenderer())
+ renderer->viewCleared();
+
+ setScrollbarsSuppressed(true);
+}
+
+bool FrameView::didFirstLayout() const
+{
+ return !d->m_firstLayout;
+}
+
+void FrameView::initScrollbars()
+{
+ if (!d->m_needToInitScrollbars)
+ return;
+ d->m_needToInitScrollbars = false;
+ d->m_hmode = horizontalScrollbarMode();
+ d->m_vmode = verticalScrollbarMode();
+ setScrollbarModes(d->m_hmode, d->m_vmode);
+}
+
+void FrameView::invalidateRect(const IntRect& rect)
+{
+ if (!parent()) {
+ if (hostWindow())
+ hostWindow()->repaint(rect, true);
+ 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::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);
+}
+
+void FrameView::setCanHaveScrollbars(bool canScroll)
+{
+ ScrollView::setCanHaveScrollbars(canScroll);
+ scrollbarModes(d->m_hmode, d->m_vmode);
+}
+
+void FrameView::adjustViewSize()
+{
+ ASSERT(m_frame->view() == this);
+ RenderView* root = m_frame->contentRenderer();
+ if (!root)
+ return;
+ setContentsSize(IntSize(root->overflowWidth(), root->overflowHeight()));
+}
+
+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.
+ ;
+ }
+
+ d->m_viewportRenderer = o;
+}
+
+int FrameView::layoutCount() const
+{
+ return d->m_layoutCount;
+}
+
+bool FrameView::needsFullRepaint() const
+{
+ return d->m_doFullRepaint;
+}
+
+RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
+{
+ return onlyDuringLayout && layoutPending() ? 0 : d->m_layoutRoot;
+}
+
+void FrameView::layout(bool allowSubtree)
+{
+ if (d->m_midLayout)
+ return;
+
+ d->m_layoutTimer.stop();
+ d->m_delayedLayout = 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(visibleWidth());
+ return;
+ }
+
+ // we shouldn't enter layout() while painting
+ ASSERT(!isPainting());
+ if (isPainting())
+ return;
+
+ if (!allowSubtree && d->m_layoutRoot) {
+ d->m_layoutRoot->markContainingBlocksForLayout(false);
+ d->m_layoutRoot = 0;
+ }
+
+ ASSERT(m_frame->view() == this);
+ // This early return should be removed when rdar://5598072 is resolved. In the meantime, there is a
+ // gigantic CrashTracer because of this issue, and the early return will hopefully cause graceful
+ // failure instead.
+ if (m_frame->view() != this)
+ return;
+
+ Document* document = m_frame->document();
+ if (!document) {
+ // FIXME: Should we set m_size.height here too?
+ m_size.setWidth(visibleWidth());
+ return;
+ }
+
+ d->m_layoutSchedulingEnabled = false;
+
+ if (!d->m_nestedLayoutCount && d->m_postLayoutTasksTimer.isActive()) {
+ // This is a new top-level layout. If there are any remaining tasks from the previous
+ // layout, finish them now.
+ d->m_postLayoutTasksTimer.stop();
+ performPostLayoutTasks();
+ }
+
+ // Viewport-dependent media queries may cause us to need completely different style information.
+ // Check that here.
+ if (document->styleSelector()->affectedByViewportChange())
+ document->updateStyleSelector();
+
+ // 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.
+ if (m_frame->needsReapplyStyles())
+ m_frame->reapplyStyles();
+ else if (document->hasChangedChild())
+ document->recalcStyle();
+
+ bool subtree = d->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 ? d->m_layoutRoot : document->renderer();
+ if (!root) {
+ // FIXME: Do we need to set m_size here?
+ d->m_layoutSchedulingEnabled = true;
+ return;
+ }
+
+#ifdef ANDROID_INSTRUMENT
+ if (!m_frame->tree() || !m_frame->tree()->parent())
+ android::TimeCounter::start(android::TimeCounter::LayoutTimeCounter);
+#endif
+
+ d->m_nestedLayoutCount++;
+
+ ScrollbarMode hMode = d->m_hmode;
+ ScrollbarMode vMode = d->m_vmode;
+
+ if (!subtree) {
+ RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0;
+ Node* body = document->body();
+ if (body && body->renderer()) {
+ if (body->hasTagName(framesetTag)) {
+ body->renderer()->setChildNeedsLayout(true);
+ vMode = ScrollbarAlwaysOff;
+ hMode = ScrollbarAlwaysOff;
+ } else if (body->hasTagName(bodyTag)) {
+ if (!d->m_firstLayout && m_size.height() != visibleHeight()
+ && static_cast<RenderBox*>(body->renderer())->stretchesToViewHeight())
+ body->renderer()->setChildNeedsLayout(true);
+ // 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)
+ applyOverflowToViewport(rootRenderer, hMode, vMode);
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (d->m_firstLayout && !document->ownerElement())
+ printf("Elapsed time before first layout: %d\n", document->elapsedTime());
+#endif
+ }
+
+ d->m_doFullRepaint = !subtree && (d->m_firstLayout || static_cast<RenderView*>(root)->printing());
+
+ if (!subtree) {
+ // Now set our scrollbar state for the layout.
+ ScrollbarMode currentHMode = horizontalScrollbarMode();
+ ScrollbarMode currentVMode = verticalScrollbarMode();
+
+ if (d->m_firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
+ setScrollbarsSuppressed(true);
+ if (d->m_firstLayout) {
+ d->m_firstLayout = false;
+ d->m_firstLayoutCallbackPending = true;
+ d->m_lastLayoutSize = IntSize(width(), height());
+ d->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);
+ }
+
+ IntSize oldSize = m_size;
+
+ m_size = IntSize(visibleWidth(), visibleHeight());
+
+ if (oldSize != m_size)
+ d->m_doFullRepaint = true;
+ }
+
+ RenderLayer* layer = root->enclosingLayer();
+
+ pauseScheduledEvents();
+
+ if (subtree)
+ root->view()->pushLayoutState(root);
+
+ d->m_midLayout = true;
+ beginDeferredRepaints();
+ root->layout();
+ endDeferredRepaints();
+ d->m_midLayout = false;
+
+ if (subtree)
+ root->view()->popLayoutState();
+ d->m_layoutRoot = 0;
+
+ m_frame->invalidateSelection();
+
+ d->m_layoutSchedulingEnabled = true;
+
+ if (!subtree && !static_cast<RenderView*>(root)->printing())
+ adjustViewSize();
+
+ // Now update the positions of all layers.
+ beginDeferredRepaints();
+ layer->updateLayerPositions(d->m_doFullRepaint);
+ endDeferredRepaints();
+
+ d->m_layoutCount++;
+
+#if PLATFORM(MAC)
+ if (AXObjectCache::accessibilityEnabled())
+ root->document()->axObjectCache()->postNotificationToElement(root, "AXLayoutComplete");
+#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());
+
+ setCanBlitOnScroll(!useSlowRepaints());
+
+ if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
+ updateOverflowStatus(visibleWidth() < contentsWidth(),
+ visibleHeight() < contentsHeight());
+
+ if (!d->m_postLayoutTasksTimer.isActive()) {
+ // Calls resumeScheduledEvents()
+ performPostLayoutTasks();
+
+ if (needsLayout()) {
+ // Post-layout widget updates or an event handler made us need layout again.
+ // Lay out again, but this time defer widget updates and event dispatch until after
+ // we return.
+ d->m_postLayoutTasksTimer.startOneShot(0);
+ pauseScheduledEvents();
+ layout();
+ }
+ } else {
+ resumeScheduledEvents();
+ ASSERT(d->m_enqueueEvents);
+ }
+
+ d->m_nestedLayoutCount--;
+}
+
+void FrameView::addWidgetToUpdate(RenderPartObject* object)
+{
+ if (!m_widgetUpdateSet)
+ m_widgetUpdateSet.set(new HashSet<RenderPartObject*>);
+
+ m_widgetUpdateSet->add(object);
+}
+
+void FrameView::removeWidgetToUpdate(RenderPartObject* object)
+{
+ if (!m_widgetUpdateSet)
+ return;
+
+ m_widgetUpdateSet->remove(object);
+}
+
+void FrameView::setMediaType(const String& mediaType)
+{
+ d->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 d->m_mediaType;
+}
+
+bool FrameView::useSlowRepaints() const
+{
+ return d->m_useSlowRepaints || d->m_slowRepaintObjectCount > 0;
+}
+
+void FrameView::setUseSlowRepaints()
+{
+ d->m_useSlowRepaints = true;
+ setCanBlitOnScroll(false);
+}
+
+void FrameView::addSlowRepaintObject()
+{
+ if (!d->m_slowRepaintObjectCount)
+ setCanBlitOnScroll(false);
+ d->m_slowRepaintObjectCount++;
+}
+
+void FrameView::removeSlowRepaintObject()
+{
+ ASSERT(d->m_slowRepaintObjectCount > 0);
+ d->m_slowRepaintObjectCount--;
+ if (!d->m_slowRepaintObjectCount)
+ setCanBlitOnScroll(!d->m_useSlowRepaints);
+}
+
+void FrameView::restoreScrollbar()
+{
+ setScrollbarsSuppressed(false);
+}
+
+void FrameView::scrollRectIntoViewRecursively(const IntRect& r)
+{
+ bool wasInProgrammaticScroll = d->m_inProgrammaticScroll;
+ d->m_inProgrammaticScroll = true;
+ ScrollView::scrollRectIntoViewRecursively(r);
+ d->m_inProgrammaticScroll = wasInProgrammaticScroll;
+}
+
+void FrameView::setScrollPosition(const IntPoint& scrollPoint)
+{
+ bool wasInProgrammaticScroll = d->m_inProgrammaticScroll;
+ d->m_inProgrammaticScroll = true;
+ ScrollView::setScrollPosition(scrollPoint);
+ d->m_inProgrammaticScroll = wasInProgrammaticScroll;
+}
+
+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());
+
+ if (d->m_deferringRepaints && !immediate) {
+ IntRect visibleContent = visibleContentRect();
+ visibleContent.intersect(r);
+ if (!visibleContent.isEmpty()) {
+ d->m_repaintCount++;
+ d->m_repaintRect.unite(r);
+ if (d->m_repaintCount == cRepaintRectUnionThreshold)
+ d->m_repaintRects.clear();
+ else if (d->m_repaintCount < cRepaintRectUnionThreshold)
+ d->m_repaintRects.append(r);
+ }
+#ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS
+ else
+ ScrollView::platformOffscreenContentRectangle(r);
+#endif
+ return;
+ }
+
+ if (!immediate && isOffscreen() && !shouldUpdateWhileOffscreen())
+ return;
+
+ ScrollView::repaintContentRectangle(r, immediate);
+}
+
+void FrameView::beginDeferredRepaints()
+{
+ Page* page = m_frame->page();
+ if (page->mainFrame() != m_frame)
+ return page->mainFrame()->view()->beginDeferredRepaints();
+
+ d->m_deferringRepaints++;
+#ifdef ANDROID_FIX // This allows sub frames to accumulate deferred repaints
+ if (d->m_deferringRepaints == 1) {
+#endif
+ d->m_repaintCount = 0;
+ d->m_repaintRect = IntRect();
+ d->m_repaintRects.clear();
+#ifdef ANDROID_FIX
+ }
+#endif
+}
+
+
+void FrameView::endDeferredRepaints()
+{
+ Page* page = m_frame->page();
+ if (page->mainFrame() != m_frame)
+ return page->mainFrame()->view()->endDeferredRepaints();
+
+ ASSERT(d->m_deferringRepaints > 0);
+ if (--d->m_deferringRepaints == 0) {
+ if (d->m_repaintCount >= cRepaintRectUnionThreshold)
+ repaintContentRectangle(d->m_repaintRect, false);
+ else {
+ unsigned size = d->m_repaintRects.size();
+ for (unsigned i = 0; i < size; i++)
+ repaintContentRectangle(d->m_repaintRects[i], false);
+ d->m_repaintRects.clear();
+ }
+ }
+}
+
+void FrameView::layoutTimerFired(Timer<FrameView>*)
+{
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (m_frame->document() && !m_frame->document()->ownerElement())
+ printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime());
+#endif
+ layout();
+}
+
+void FrameView::scheduleRelayout()
+{
+ ASSERT(!m_frame->document() || !m_frame->document()->inPageCache());
+ ASSERT(m_frame->view() == this);
+
+ if (d->m_layoutRoot) {
+ d->m_layoutRoot->markContainingBlocksForLayout(false);
+ d->m_layoutRoot = 0;
+ }
+ if (!d->m_layoutSchedulingEnabled)
+ return;
+
+ if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout())
+ return;
+
+#if defined(FLATTEN_IFRAME) || defined(FLATTEN_FRAMESET)
+ if (m_frame->ownerRenderer())
+ m_frame->ownerRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
+#endif
+
+#ifdef ANDROID_MOBILE
+ int delay = m_frame->document()->minimumLayoutDelay() + m_frame->document()->extraLayoutDelay();
+#else
+ int delay = m_frame->document()->minimumLayoutDelay();
+#endif
+ if (d->m_layoutTimer.isActive() && d->m_delayedLayout && !delay)
+ unscheduleRelayout();
+ if (d->m_layoutTimer.isActive())
+ return;
+
+ d->m_delayedLayout = delay != 0;
+
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (!m_frame->document()->ownerElement())
+ printf("Scheduling layout for %d\n", delay);
+#endif
+
+ d->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 (!d->m_layoutSchedulingEnabled || (m_frame->contentRenderer()
+ && m_frame->contentRenderer()->needsLayout())) {
+ if (relayoutRoot)
+ relayoutRoot->markContainingBlocksForLayout(false);
+ return;
+ }
+
+ if (layoutPending()) {
+ if (d->m_layoutRoot != relayoutRoot) {
+ if (isObjectAncestorContainerOf(d->m_layoutRoot, relayoutRoot)) {
+ // Keep the current root
+ relayoutRoot->markContainingBlocksForLayout(false, d->m_layoutRoot);
+ } else if (d->m_layoutRoot && isObjectAncestorContainerOf(relayoutRoot, d->m_layoutRoot)) {
+ // Re-root at relayoutRoot
+ d->m_layoutRoot->markContainingBlocksForLayout(false, relayoutRoot);
+ d->m_layoutRoot = relayoutRoot;
+ } else {
+ // Just do a full relayout
+ if (d->m_layoutRoot)
+ d->m_layoutRoot->markContainingBlocksForLayout(false);
+ d->m_layoutRoot = 0;
+ relayoutRoot->markContainingBlocksForLayout(false);
+ }
+ }
+ } else {
+#ifdef ANDROID_MOBILE
+ int delay = m_frame->document()->minimumLayoutDelay() + m_frame->document()->extraLayoutDelay();
+#else
+ int delay = m_frame->document()->minimumLayoutDelay();
+#endif
+ d->m_layoutRoot = relayoutRoot;
+ d->m_delayedLayout = delay != 0;
+ d->m_layoutTimer.startOneShot(delay * 0.001);
+ }
+}
+
+bool FrameView::layoutPending() const
+{
+ return d->m_layoutTimer.isActive();
+}
+
+bool FrameView::needsLayout() const
+{
+ // It is possible that our document will not have a body yet. If this is the case,
+ // then we are not allowed to schedule layouts yet, so we won't be pending layout.
+ if (!m_frame)
+ return false;
+ RenderView* root = m_frame->contentRenderer();
+ Document * doc = m_frame->document();
+ // doc->hasChangedChild() condition can occur when using WebKit ObjC interface
+ return layoutPending() || (root && root->needsLayout()) || d->m_layoutRoot || (doc && doc->hasChangedChild()) || m_frame->needsReapplyStyles();
+}
+
+void FrameView::setNeedsLayout()
+{
+ RenderView* root = m_frame->contentRenderer();
+ if (root)
+ root->setNeedsLayout(true);
+}
+
+void FrameView::unscheduleRelayout()
+{
+ if (!d->m_layoutTimer.isActive())
+ return;
+
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (m_frame->document() && !m_frame->document()->ownerElement())
+ printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime());
+#endif
+
+ d->m_layoutTimer.stop();
+ d->m_delayedLayout = false;
+}
+
+bool FrameView::isTransparent() const
+{
+ return d->m_isTransparent;
+}
+
+void FrameView::setTransparent(bool isTransparent)
+{
+ d->m_isTransparent = isTransparent;
+}
+
+Color FrameView::baseBackgroundColor() const
+{
+ return d->m_baseBackgroundColor;
+}
+
+void FrameView::setBaseBackgroundColor(Color bc)
+{
+ if (!bc.isValid())
+ bc = Color::white;
+ d->m_baseBackgroundColor = bc;
+}
+
+bool FrameView::shouldUpdateWhileOffscreen() const
+{
+ return d->m_shouldUpdateWhileOffscreen;
+}
+
+void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
+{
+ d->m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
+}
+
+void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<EventTargetNode> eventTarget)
+{
+ if (!d->m_enqueueEvents) {
+ ExceptionCode ec = 0;
+ eventTarget->dispatchEvent(event, ec);
+ return;
+ }
+
+ ScheduledEvent* scheduledEvent = new ScheduledEvent;
+ scheduledEvent->m_event = event;
+ scheduledEvent->m_eventTarget = eventTarget;
+ d->m_scheduledEvents.append(scheduledEvent);
+}
+
+void FrameView::pauseScheduledEvents()
+{
+ ASSERT(d->m_scheduledEvents.isEmpty() || d->m_enqueueEvents);
+ d->m_enqueueEvents++;
+}
+
+void FrameView::resumeScheduledEvents()
+{
+ d->m_enqueueEvents--;
+ if (!d->m_enqueueEvents)
+ dispatchScheduledEvents();
+ ASSERT(d->m_scheduledEvents.isEmpty() || d->m_enqueueEvents);
+}
+
+void FrameView::performPostLayoutTasks()
+{
+ if (d->m_firstLayoutCallbackPending) {
+ d->m_firstLayoutCallbackPending = false;
+ m_frame->loader()->didFirstLayout();
+ }
+
+ RenderView* root = m_frame->contentRenderer();
+
+ root->updateWidgetPositions();
+ if (m_widgetUpdateSet && d->m_nestedLayoutCount <= 1) {
+ Vector<RenderPartObject*> objectVector;
+ copyToVector(*m_widgetUpdateSet, objectVector);
+ size_t size = objectVector.size();
+ for (size_t i = 0; i < size; ++i) {
+ RenderPartObject* object = objectVector[i];
+ object->updateWidget(false);
+
+ // updateWidget() can destroy the RenderPartObject, so we need to make sure it's
+ // alive by checking if it's still in m_widgetUpdateSet.
+ if (m_widgetUpdateSet->contains(object))
+ object->updateWidgetPosition();
+ }
+ m_widgetUpdateSet->clear();
+ }
+
+ resumeScheduledEvents();
+
+ if (!root->printing()) {
+ IntSize currentSize = IntSize(width(), height());
+ float currentZoomFactor = root->style()->zoom();
+ bool resized = !d->m_firstLayout && (currentSize != d->m_lastLayoutSize || currentZoomFactor != d->m_lastZoomFactor);
+ d->m_lastLayoutSize = currentSize;
+ d->m_lastZoomFactor = currentZoomFactor;
+ if (resized)
+ m_frame->sendResizeEvent();
+ }
+}
+
+void FrameView::postLayoutTimerFired(Timer<FrameView>*)
+{
+ performPostLayoutTasks();
+}
+
+void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
+{
+ if (!d->m_viewportRenderer)
+ return;
+
+ if (d->m_overflowStatusDirty) {
+ d->m_horizontalOverflow = horizontalOverflow;
+ d->m_verticalOverflow = verticalOverflow;
+ d->m_overflowStatusDirty = false;
+ return;
+ }
+
+ bool horizontalOverflowChanged = (d->m_horizontalOverflow != horizontalOverflow);
+ bool verticalOverflowChanged = (d->m_verticalOverflow != verticalOverflow);
+
+ if (horizontalOverflowChanged || verticalOverflowChanged) {
+ d->m_horizontalOverflow = horizontalOverflow;
+ d->m_verticalOverflow = verticalOverflow;
+
+ scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow,
+ verticalOverflowChanged, verticalOverflow),
+ EventTargetNodeCast(d->m_viewportRenderer->element()));
+ }
+
+}
+
+void FrameView::dispatchScheduledEvents()
+{
+ if (d->m_scheduledEvents.isEmpty())
+ return;
+
+ Vector<ScheduledEvent*> scheduledEventsCopy = d->m_scheduledEvents;
+ d->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);
+
+ // 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())
+ frame()->sendScrollEvent();
+}
+
+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);
+}
+
+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->renderer()->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::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 (theme()->supportsControlTints() && m_frame->contentRenderer()) {
+ 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 d->m_wasScrolledByUser;
+}
+
+void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
+{
+ if (d->m_inProgrammaticScroll)
+ return;
+ d->m_wasScrolledByUser = wasScrolledByUser;
+}
+
+void FrameView::paintContents(GraphicsContext* p, const IntRect& rect)
+{
+ if (!frame())
+ return;
+
+ Document* document = frame()->document();
+ if (!document)
+ return;
+
+#ifndef NDEBUG
+ bool fillWithRed;
+ if (document || 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 (d->m_paintRestriction == PaintRestrictionSelectionOnly || d->m_paintRestriction == PaintRestrictionSelectionOnlyBlackText)
+ fillWithRed = false; // Selections are transparent, don't fill with red.
+ else if (d->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));
+#endif
+
+ bool isTopLevelPainter = !sCurrentPaintTimeStamp;
+ if (isTopLevelPainter)
+ sCurrentPaintTimeStamp = currentTime();
+
+ RenderView* contentRenderer = frame()->contentRenderer();
+ if (!contentRenderer) {
+ LOG_ERROR("called Frame::paint with nil renderer");
+ return;
+ }
+
+ ASSERT(!needsLayout());
+ ASSERT(!d->m_isPainting);
+
+ d->m_isPainting = true;
+
+ // m_nodeToDraw is used to draw only one element (and its descendants)
+ RenderObject* eltRenderer = d->m_nodeToDraw ? d->m_nodeToDraw->renderer() : 0;
+ if (d->m_paintRestriction == PaintRestrictionNone)
+ document->invalidateRenderedRectsForMarkersInRect(rect);
+ contentRenderer->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer);
+
+ d->m_isPainting = false;
+
+#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;
+}
+
+void FrameView::setPaintRestriction(PaintRestriction pr)
+{
+ d->m_paintRestriction = pr;
+}
+
+bool FrameView::isPainting() const
+{
+ return d->m_isPainting;
+}
+
+void FrameView::setNodeToDraw(Node* node)
+{
+ d->m_nodeToDraw = node;
+}
+
+void FrameView::layoutIfNeededRecursive()
+{
+ // 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.
+
+ if (needsLayout())
+ layout();
+
+ const HashSet<Widget*>* viewChildren = children();
+ HashSet<Widget*>::const_iterator end = viewChildren->end();
+ for (HashSet<Widget*>::const_iterator current = viewChildren->begin(); current != end; ++current)
+ if ((*current)->isFrameView())
+ static_cast<FrameView*>(*current)->layoutIfNeededRecursive();
+}
+
+}
diff --git a/WebCore/page/FrameView.h b/WebCore/page/FrameView.h
new file mode 100644
index 0000000..84a829f
--- /dev/null
+++ b/WebCore/page/FrameView.h
@@ -0,0 +1,191 @@
+/*
+ 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 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 "IntSize.h"
+#include "RenderLayer.h"
+#include "ScrollView.h"
+#include <wtf/Forward.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class Color;
+class Event;
+class EventTargetNode;
+class Frame;
+class FrameViewPrivate;
+class IntRect;
+class PlatformMouseEvent;
+class Node;
+class RenderLayer;
+class RenderObject;
+class RenderPartObject;
+class String;
+
+template <typename T> class Timer;
+
+class FrameView : public ScrollView {
+public:
+ friend class RenderView;
+
+ FrameView(Frame*);
+ FrameView(Frame*, const IntSize& initialSize);
+
+ virtual ~FrameView();
+
+ virtual HostWindow* hostWindow() const;
+
+ virtual void invalidateRect(const IntRect&);
+
+ Frame* frame() const { return m_frame.get(); }
+ void clearFrame();
+
+ void ref() { ++m_refCount; }
+ void deref() { if (!--m_refCount) delete this; }
+ bool hasOneRef() { return m_refCount == 1; }
+
+ 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 layout(bool allowSubtree = true);
+ bool didFirstLayout() const;
+ void layoutTimerFired(Timer<FrameView>*);
+ void scheduleRelayout();
+ void scheduleRelayoutOfSubtree(RenderObject*);
+ void unscheduleRelayout();
+ bool layoutPending() const;
+
+ RenderObject* layoutRoot(bool onlyDuringLayout = false) const;
+ int layoutCount() const;
+
+ // These two helper functions just pass through to the RenderView.
+ bool needsLayout() const;
+ void setNeedsLayout();
+
+ bool needsFullRepaint() const;
+
+ void resetScrollbars();
+
+ void clear();
+
+ bool isTransparent() const;
+ void setTransparent(bool isTransparent);
+
+ Color baseBackgroundColor() const;
+ void setBaseBackgroundColor(Color);
+
+ bool shouldUpdateWhileOffscreen() const;
+ void setShouldUpdateWhileOffscreen(bool);
+
+ void adjustViewSize();
+ void initScrollbars();
+
+ virtual IntRect windowClipRect(bool clipToContents = true) const;
+ IntRect windowClipRectForLayer(const RenderLayer*, bool clipToLayerContents) const;
+
+ virtual bool isActive() const;
+ virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&);
+ virtual void valueChanged(Scrollbar*);
+
+ virtual IntRect windowResizerRect() const;
+
+ virtual void scrollRectIntoViewRecursively(const IntRect&);
+ virtual void setScrollPosition(const IntPoint&);
+
+ String mediaType() const;
+ void setMediaType(const String&);
+
+ void setUseSlowRepaints();
+
+ void addSlowRepaintObject();
+ void removeSlowRepaintObject();
+
+ void beginDeferredRepaints();
+ void endDeferredRepaints();
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ void updateDashboardRegions();
+#endif
+ void updateControlTints();
+
+ void restoreScrollbar();
+
+ void scheduleEvent(PassRefPtr<Event>, PassRefPtr<EventTargetNode>);
+ void pauseScheduledEvents();
+ void resumeScheduledEvents();
+ void postLayoutTimerFired(Timer<FrameView>*);
+
+ bool wasScrolledByUser() const;
+ void setWasScrolledByUser(bool);
+
+ void addWidgetToUpdate(RenderPartObject*);
+ void removeWidgetToUpdate(RenderPartObject*);
+
+ virtual void paintContents(GraphicsContext*, const IntRect& damageRect);
+ void setPaintRestriction(PaintRestriction);
+ bool isPainting() const;
+ void setNodeToDraw(Node*);
+
+ static double currentPaintTimeStamp() { return sCurrentPaintTimeStamp; } // returns 0 if not painting
+
+ void layoutIfNeededRecursive();
+
+private:
+ void init();
+
+ virtual bool isFrameView() const;
+
+ bool useSlowRepaints() const;
+
+ 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() { layout(); }
+
+ static double sCurrentPaintTimeStamp; // used for detecting decoded resource thrash in the cache
+
+ unsigned m_refCount;
+ IntSize m_size;
+ IntSize m_margins;
+ OwnPtr<HashSet<RenderPartObject*> > m_widgetUpdateSet;
+ RefPtr<Frame> m_frame;
+ FrameViewPrivate* d;
+};
+
+}
+
+#endif
diff --git a/WebCore/page/Geolocation.cpp b/WebCore/page/Geolocation.cpp
new file mode 100644
index 0000000..a0c9694
--- /dev/null
+++ b/WebCore/page/Geolocation.cpp
@@ -0,0 +1,222 @@
+/*
+ * 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 "Geolocation.h"
+
+#include "Document.h"
+#include "Frame.h"
+#include "PositionError.h"
+
+namespace WebCore {
+
+Geolocation::GeoNotifier::GeoNotifier(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PositionOptions* options)
+ : m_successCallback(successCallback)
+ , m_errorCallback(errorCallback)
+ , m_timer(this, &Geolocation::GeoNotifier::timerFired)
+{
+ if (m_errorCallback && options)
+ m_timer.startOneShot(options->timeout() / 1000.0);
+}
+
+void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*)
+{
+ ASSERT(m_errorCallback);
+
+ m_timer.stop();
+
+ RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT_ERROR, "Timed out");
+ m_errorCallback->handleEvent(error.get());
+}
+
+Geolocation::Geolocation(Frame* frame)
+ : m_frame(frame)
+ , m_service(GeolocationService::create(this))
+{
+ ASSERT(m_frame->document());
+ m_frame->document()->setUsingGeolocation(true);
+}
+
+void Geolocation::disconnectFrame()
+{
+ m_service->stopUpdating();
+ if (m_frame->document())
+ m_frame->document()->setUsingGeolocation(false);
+ m_frame = 0;
+}
+
+void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PositionOptions* options)
+{
+ RefPtr<GeoNotifier> notifier = GeoNotifier::create(successCallback, errorCallback, options);
+
+ if (!m_service->startUpdating(options)) {
+ if (notifier->m_errorCallback) {
+ RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_ERROR, "Unable to Start");
+ notifier->m_errorCallback->handleEvent(error.get());
+ }
+ return;
+ }
+
+ m_oneShots.add(notifier);
+}
+
+int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PositionOptions* options)
+{
+ RefPtr<GeoNotifier> notifier = GeoNotifier::create(successCallback, errorCallback, options);
+
+ if (!m_service->startUpdating(options)) {
+ if (notifier->m_errorCallback) {
+ RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_ERROR, "Unable to Start");
+ notifier->m_errorCallback->handleEvent(error.get());
+ }
+ return 0;
+ }
+
+ static int sIdentifier = 0;
+
+ m_watchers.set(++sIdentifier, notifier);
+
+ return sIdentifier;
+}
+
+void Geolocation::clearWatch(int watchId)
+{
+ m_watchers.remove(watchId);
+
+ if (!hasListeners())
+ m_service->stopUpdating();
+}
+
+void Geolocation::suspend()
+{
+ if (hasListeners())
+ m_service->suspend();
+}
+
+void Geolocation::resume()
+{
+ if (hasListeners())
+ m_service->resume();
+}
+
+void Geolocation::sendErrorToOneShots(PositionError* error)
+{
+ Vector<RefPtr<GeoNotifier> > copy;
+ copyToVector(m_oneShots, copy);
+
+ Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end();
+ for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) {
+ RefPtr<GeoNotifier> notifier = *it;
+
+ if (notifier->m_errorCallback)
+ notifier->m_errorCallback->handleEvent(error);
+ }
+}
+
+void Geolocation::sendErrorToWatchers(PositionError* error)
+{
+ Vector<RefPtr<GeoNotifier> > copy;
+ copyValuesToVector(m_watchers, copy);
+
+ Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end();
+ for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) {
+ RefPtr<GeoNotifier> notifier = *it;
+
+ if (notifier->m_errorCallback)
+ notifier->m_errorCallback->handleEvent(error);
+ }
+}
+
+void Geolocation::sendPositionToOneShots(Geoposition* position)
+{
+ Vector<RefPtr<GeoNotifier> > copy;
+ copyToVector(m_oneShots, copy);
+
+ Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end();
+ for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) {
+ RefPtr<GeoNotifier> notifier = *it;
+ ASSERT(notifier->m_successCallback);
+
+ notifier->m_timer.stop();
+ bool shouldCallErrorCallback = false;
+ notifier->m_successCallback->handleEvent(position, shouldCallErrorCallback);
+ if (shouldCallErrorCallback) {
+ RefPtr<PositionError> error = PositionError::create(PositionError::UNKNOWN_ERROR, "An exception was thrown");
+ handleError(error.get());
+ }
+ }
+}
+
+void Geolocation::sendPositionToWatchers(Geoposition* position)
+{
+ Vector<RefPtr<GeoNotifier> > copy;
+ copyValuesToVector(m_watchers, copy);
+
+ Vector<RefPtr<GeoNotifier> >::const_iterator end = copy.end();
+ for (Vector<RefPtr<GeoNotifier> >::const_iterator it = copy.begin(); it != end; ++it) {
+ RefPtr<GeoNotifier> notifier = *it;
+ ASSERT(notifier->m_successCallback);
+
+ notifier->m_timer.stop();
+ bool shouldCallErrorCallback = false;
+ notifier->m_successCallback->handleEvent(position, shouldCallErrorCallback);
+ if (shouldCallErrorCallback) {
+ RefPtr<PositionError> error = PositionError::create(PositionError::UNKNOWN_ERROR, "An exception was thrown");
+ handleError(error.get());
+ }
+ }
+}
+
+void Geolocation::handleError(PositionError* error)
+{
+ ASSERT(error);
+
+ sendErrorToOneShots(error);
+ sendErrorToWatchers(error);
+
+ m_oneShots.clear();
+}
+
+void Geolocation::geolocationServicePositionChanged(GeolocationService* service)
+{
+ ASSERT(service->lastPosition());
+
+ sendPositionToOneShots(service->lastPosition());
+ sendPositionToWatchers(service->lastPosition());
+
+ m_oneShots.clear();
+
+ if (!hasListeners())
+ m_service->stopUpdating();
+}
+
+void Geolocation::geolocationServiceErrorOccurred(GeolocationService* service)
+{
+ ASSERT(service->lastError());
+
+ handleError(service->lastError());
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/Geolocation.h b/WebCore/page/Geolocation.h
new file mode 100644
index 0000000..572cbd8
--- /dev/null
+++ b/WebCore/page/Geolocation.h
@@ -0,0 +1,104 @@
+/*
+ * 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 Geolocation_h
+#define Geolocation_h
+
+#include "GeolocationService.h"
+#include "PositionCallback.h"
+#include "PositionErrorCallback.h"
+#include "PositionOptions.h"
+#include "Timer.h"
+#include <wtf/Platform.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class Frame;
+class Geoposition;
+
+class Geolocation : public RefCounted<Geolocation>, public GeolocationServiceClient {
+public:
+ static PassRefPtr<Geolocation> create(Frame* frame) { return adoptRef(new Geolocation(frame)); }
+
+ virtual ~Geolocation() {}
+
+ void disconnectFrame();
+
+ Geoposition* lastPosition() const { return m_service->lastPosition(); }
+
+ void getCurrentPosition(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PositionOptions*);
+ int watchPosition(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PositionOptions*);
+ void clearWatch(int watchId);
+
+ void suspend();
+ void resume();
+
+private:
+ Geolocation(Frame*);
+
+ class GeoNotifier : public RefCounted<GeoNotifier> {
+ public:
+ static PassRefPtr<GeoNotifier> create(PassRefPtr<PositionCallback> positionCallback, PassRefPtr<PositionErrorCallback> positionErrorCallback, PositionOptions* options) { return adoptRef(new GeoNotifier(positionCallback, positionErrorCallback, options)); }
+
+ void timerFired(Timer<GeoNotifier>*);
+
+ RefPtr<PositionCallback> m_successCallback;
+ RefPtr<PositionErrorCallback> m_errorCallback;
+ Timer<GeoNotifier> m_timer;
+
+ private:
+ GeoNotifier(PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PositionOptions*);
+ };
+
+ bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); }
+
+ void sendErrorToOneShots(PositionError*);
+ void sendErrorToWatchers(PositionError*);
+ void sendPositionToOneShots(Geoposition*);
+ void sendPositionToWatchers(Geoposition*);
+
+ void handleError(PositionError*);
+
+ virtual void geolocationServicePositionChanged(GeolocationService*);
+ virtual void geolocationServiceErrorOccurred(GeolocationService*);
+
+ typedef HashSet<RefPtr<GeoNotifier> > GeoNotifierSet;
+ typedef HashMap<int, RefPtr<GeoNotifier> > GeoNotifierMap;
+
+ GeoNotifierSet m_oneShots;
+ GeoNotifierMap m_watchers;
+ Frame* m_frame;
+ OwnPtr<GeolocationService> m_service;
+};
+
+} // namespace WebCore
+
+#endif // Geolocation_h
diff --git a/WebCore/page/Geolocation.idl b/WebCore/page/Geolocation.idl
new file mode 100644
index 0000000..e125118
--- /dev/null
+++ b/WebCore/page/Geolocation.idl
@@ -0,0 +1,38 @@
+/*
+ * 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 Geolocation {
+ readonly attribute Geoposition lastPosition;
+
+ [Custom] void getCurrentPosition(in PositionCallback successCallback, in PositionErrorCallback errorCallback, in PositionOptions options);
+
+ [Custom] long watchPosition(in PositionCallback successCallback, in PositionErrorCallback errorCallback, in PositionOptions options);
+
+ void clearWatch(in long watchId);
+ };
+
+}
diff --git a/WebCore/page/Geoposition.cpp b/WebCore/page/Geoposition.cpp
new file mode 100644
index 0000000..1792a1f
--- /dev/null
+++ b/WebCore/page/Geoposition.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 "Geoposition.h"
+
+namespace WebCore {
+
+String Geoposition::toString() const
+{
+ return String::format("position(%.6lg, %.6lg, %.6lg, %.6lg, %.6lg, %.6lg, %.6lg, %.lld)",
+ m_latitude, m_longitude, m_altitude, m_accuracy,
+ m_altitudeAccuracy, m_heading, m_speed, m_timestamp);
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/Geoposition.h b/WebCore/page/Geoposition.h
new file mode 100644
index 0000000..9ce50e5
--- /dev/null
+++ b/WebCore/page/Geoposition.h
@@ -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.
+ *
+ * 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 "Event.h"
+#include "PlatformString.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+typedef int ExceptionCode;
+
+class Geoposition : public RefCounted<Geoposition> {
+public:
+ static PassRefPtr<Geoposition> create(double latitude, double longitude, double altitude, double accuracy, double altitudeAccuracy, double heading, double speed, DOMTimeStamp timestamp) { return adoptRef(new Geoposition(latitude, longitude, altitude, accuracy, altitudeAccuracy, heading, speed, timestamp)); }
+
+ 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; }
+ DOMTimeStamp timestamp() const { return m_timestamp; }
+
+ String toString() const;
+
+private:
+ Geoposition(double latitude, double longitude, double altitude, double accuracy, double altitudeAccuracy, double heading, double speed, DOMTimeStamp timestamp)
+ : m_latitude(latitude)
+ , m_longitude(longitude)
+ , m_altitude(altitude)
+ , m_accuracy(accuracy)
+ , m_altitudeAccuracy(altitudeAccuracy)
+ , m_heading(heading)
+ , m_speed(speed)
+ , m_timestamp(timestamp)
+ {
+ }
+
+ double m_latitude;
+ double m_longitude;
+ double m_altitude;
+ double m_accuracy;
+ double m_altitudeAccuracy;
+ double m_heading;
+ double m_speed;
+ DOMTimeStamp m_timestamp;
+};
+
+} // namespace WebCore
+
+#endif // Geoposition_h
diff --git a/WebCore/page/Geoposition.idl b/WebCore/page/Geoposition.idl
new file mode 100644
index 0000000..554bb30
--- /dev/null
+++ b/WebCore/page/Geoposition.idl
@@ -0,0 +1,42 @@
+/*
+ * 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 Geoposition {
+ readonly attribute double latitude;
+ readonly attribute double longitude;
+ readonly attribute double altitude;
+ readonly attribute double accuracy;
+ readonly attribute double altitudeAccuracy;
+ readonly attribute double heading;
+ readonly attribute double speed;
+ readonly attribute DOMTimeStamp timestamp;
+
+#if defined(LANGUAGE_JAVASCRIPT)
+ [DontEnum] DOMString toString();
+#endif
+ };
+}
diff --git a/WebCore/page/History.cpp b/WebCore/page/History.cpp
new file mode 100644
index 0000000..2527132
--- /dev/null
+++ b/WebCore/page/History.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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 "Frame.h"
+#include "FrameLoader.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;
+ return m_frame->loader()->getHistoryLength();
+}
+
+void History::back()
+{
+ if (!m_frame)
+ return;
+ m_frame->loader()->scheduleHistoryNavigation(-1);
+}
+
+void History::forward()
+{
+ if (!m_frame)
+ return;
+ m_frame->loader()->scheduleHistoryNavigation(1);
+}
+
+void History::go(int distance)
+{
+ if (!m_frame)
+ return;
+ m_frame->loader()->scheduleHistoryNavigation(distance);
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/History.h b/WebCore/page/History.h
new file mode 100644
index 0000000..f0df2de
--- /dev/null
+++ b/WebCore/page/History.h
@@ -0,0 +1,56 @@
+/*
+ * 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 <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class Frame;
+
+ 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);
+
+ private:
+ History(Frame*);
+
+ Frame* m_frame;
+ };
+
+} // namespace WebCore
+
+#endif // History_h
diff --git a/WebCore/page/History.idl b/WebCore/page/History.idl
new file mode 100644
index 0000000..e86cf92
--- /dev/null
+++ b/WebCore/page/History.idl
@@ -0,0 +1,41 @@
+/*
+ * 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 [
+ CustomGetOwnPropertySlot,
+ CustomPutFunction,
+ CustomDeleteProperty,
+ CustomGetPropertyNames
+ ] History {
+ readonly attribute unsigned long length;
+
+ void back();
+ void forward();
+ void go(in long distance);
+ };
+
+}
diff --git a/WebCore/page/Location.cpp b/WebCore/page/Location.cpp
new file mode 100644
index 0000000..454aa78
--- /dev/null
+++ b/WebCore/page/Location.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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 "Location.h"
+
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "KURL.h"
+#include "PlatformString.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);
+ return m_frame->loader()->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((static_cast<int>(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(static_cast<int>(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();
+
+ return url().query();
+}
+
+String Location::hash() const
+{
+ if (!m_frame)
+ return String();
+
+ const KURL& url = this->url();
+ return url.ref().isNull() ? "" : "#" + url.ref();
+}
+
+String Location::toString() const
+{
+ if (!m_frame)
+ return String();
+
+ const KURL& url = this->url();
+ return url.hasPath() ? url.prettyURL() : url.prettyURL() + "/";
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/Location.h b/WebCore/page/Location.h
new file mode 100644
index 0000000..065bde1
--- /dev/null
+++ b/WebCore/page/Location.h
@@ -0,0 +1,71 @@
+/*
+ * 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 Location_h
+#define Location_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class Frame;
+ class KURL;
+ class String;
+
+ 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();
+
+ String href() const;
+
+ // URI decomposition attributes
+ String protocol() const;
+ String host() const;
+ String hostname() const;
+ String port() const;
+ String pathname() const;
+ String search() const;
+ String hash() const;
+
+ String toString() const;
+
+ private:
+ Location(Frame*);
+
+ const KURL& url() const;
+
+ Frame* m_frame;
+ };
+
+} // namespace WebCore
+
+#endif // Location_h
diff --git a/WebCore/page/Location.idl b/WebCore/page/Location.idl
new file mode 100644
index 0000000..91822ab
--- /dev/null
+++ b/WebCore/page/Location.idl
@@ -0,0 +1,57 @@
+/*
+ * 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 [
+ CustomGetOwnPropertySlot,
+ CustomPutFunction,
+ CustomDeleteProperty,
+ CustomGetPropertyNames
+ ] Location {
+ attribute [CustomSetter] DOMString href;
+
+ [Custom] void assign(in DOMString url);
+ [Custom] void replace(in DOMString url);
+ [Custom] void reload();
+
+ // URI decomposition attributes
+ 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;
+
+#if defined(LANGUAGE_JAVASCRIPT)
+ [DontEnum, Custom] DOMString toString();
+#endif
+ };
+
+}
diff --git a/WebCore/page/MouseEventWithHitTestResults.cpp b/WebCore/page/MouseEventWithHitTestResults.cpp
new file mode 100644
index 0000000..0fc8c17
--- /dev/null
+++ b/WebCore/page/MouseEventWithHitTestResults.cpp
@@ -0,0 +1,74 @@
+/*
+ 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 {
+
+static inline Element* targetElement(Node* node)
+{
+ if (!node)
+ return 0;
+ Node* parent = node->parent();
+ if (!parent || !parent->isElementNode())
+ return 0;
+ return static_cast<Element*>(parent);
+}
+
+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 && node->inDocument())
+ return node;
+
+ Element* element = targetElement(node);
+ 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/WebCore/page/MouseEventWithHitTestResults.h b/WebCore/page/MouseEventWithHitTestResults.h
new file mode 100644
index 0000000..c4e419c
--- /dev/null
+++ b/WebCore/page/MouseEventWithHitTestResults.h
@@ -0,0 +1,51 @@
+/* This file is part of the KDE project
+ 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;
+
+// FIXME: Why doesn't this class just cache a HitTestResult instead of copying all of HitTestResult's fields over?
+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;
+};
+
+}
+
+#endif
diff --git a/WebCore/page/Navigator.cpp b/WebCore/page/Navigator.cpp
new file mode 100644
index 0000000..6045062
--- /dev/null
+++ b/WebCore/page/Navigator.cpp
@@ -0,0 +1,218 @@
+/*
+ * 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 "CookieJar.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "Geolocation.h"
+#include "Language.h"
+#include "MimeTypeArray.h"
+#include "NetworkStateNotifier.h"
+#include "Page.h"
+#include "PlatformString.h"
+#include "PluginArray.h"
+#include "PluginData.h"
+#include "ScriptController.h"
+#include "Settings.h"
+
+#ifndef WEBCORE_NAVIGATOR_PLATFORM
+#if PLATFORM(MAC) && PLATFORM(PPC)
+#define WEBCORE_NAVIGATOR_PLATFORM "MacPPC"
+#elif PLATFORM(MAC) && PLATFORM(X86)
+#define WEBCORE_NAVIGATOR_PLATFORM "MacIntel"
+#elif PLATFORM(WIN_OS)
+#define WEBCORE_NAVIGATOR_PLATFORM "Win32"
+#elif PLATFORM(ANDROID)
+#define WEBCORE_NAVIGATOR_PLATFORM "Android"
+#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 {
+
+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;
+}
+
+String Navigator::appCodeName() const
+{
+ return "Mozilla";
+}
+
+String Navigator::appName() const
+{
+ return "Netscape";
+}
+
+// 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")))
+ return false;
+ Settings* settings = frame->settings();
+ if (!settings)
+ return false;
+ return settings->needsSiteSpecificQuirks();
+}
+
+String Navigator::appVersion() const
+{
+ if (!m_frame)
+ return String();
+ // Version is everything in the user agent string past the "Mozilla/" prefix.
+ const String& userAgent = m_frame->loader()->userAgent(m_frame->document() ? m_frame->document()->url() : KURL());
+ String appVersion = userAgent.substring(userAgent.find('/') + 1);
+ 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();
+ return m_frame->loader()->userAgent(m_frame->document() ? m_frame->document()->url() : KURL());
+}
+
+String Navigator::platform() const
+{
+ return WEBCORE_NAVIGATOR_PLATFORM;
+}
+
+PluginArray* Navigator::plugins() const
+{
+ if (!m_plugins)
+ m_plugins = PluginArray::create(m_frame);
+ return m_plugins.get();
+}
+
+MimeTypeArray* Navigator::mimeTypes() const
+{
+ if (!m_mimeTypes)
+ m_mimeTypes = MimeTypeArray::create(m_frame);
+ return m_mimeTypes.get();
+}
+
+String Navigator::product() const
+{
+ return WEBCORE_NAVIGATOR_PRODUCT;
+}
+
+String Navigator::productSub() const
+{
+ return WEBCORE_NAVIGATOR_PRODUCT_SUB;
+}
+
+String Navigator::vendor() const
+{
+ return WEBCORE_NAVIGATOR_VENDOR;
+}
+
+String Navigator::vendorSub() const
+{
+ return WEBCORE_NAVIGATOR_VENDOR_SUB;
+}
+
+bool Navigator::cookieEnabled() const
+{
+ if (m_frame->page() && !m_frame->page()->cookieEnabled())
+ return false;
+
+ return cookiesEnabled(m_frame->document());
+}
+
+bool Navigator::javaEnabled() const
+{
+ if (!m_frame)
+ return false;
+ return m_frame->settings()->isJavaEnabled();
+}
+
+bool Navigator::onLine() const
+{
+ return networkStateNotifier().onLine();
+}
+
+Geolocation* Navigator::geolocation() const
+{
+ if (!m_geolocation)
+ m_geolocation = Geolocation::create(m_frame);
+ return m_geolocation.get();
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/Navigator.h b/WebCore/page/Navigator.h
new file mode 100644
index 0000000..ea5d780
--- /dev/null
+++ b/WebCore/page/Navigator.h
@@ -0,0 +1,74 @@
+/*
+ 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 <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ class Frame;
+ class Geolocation;
+ class MimeTypeArray;
+ class PluginData;
+ class PluginArray;
+ class String;
+
+ class Navigator : public RefCounted<Navigator> {
+ public:
+ static PassRefPtr<Navigator> create(Frame* frame) { return adoptRef(new Navigator(frame)); }
+ ~Navigator();
+
+ void disconnectFrame();
+ Frame* frame() const { return m_frame; }
+
+ String appCodeName() const;
+ String appName() const;
+ String appVersion() const;
+ String language() const;
+ String userAgent() const;
+ String platform() const;
+ PluginArray* plugins() const;
+ MimeTypeArray* mimeTypes() const;
+ String product() const;
+ String productSub() const;
+ String vendor() const;
+ String vendorSub() const;
+ bool cookieEnabled() const;
+ bool javaEnabled() const;
+
+ bool onLine() const;
+ Geolocation* geolocation() const;
+ // This is used for GC marking.
+ Geolocation* optionalGeolocation() const { return m_geolocation.get(); }
+
+ private:
+ Navigator(Frame*);
+ Frame* m_frame;
+ mutable RefPtr<PluginArray> m_plugins;
+ mutable RefPtr<MimeTypeArray> m_mimeTypes;
+ mutable RefPtr<Geolocation> m_geolocation;
+ };
+
+}
+
+#endif
diff --git a/WebCore/page/Navigator.idl b/WebCore/page/Navigator.idl
new file mode 100644
index 0000000..905159c
--- /dev/null
+++ b/WebCore/page/Navigator.idl
@@ -0,0 +1,46 @@
+/*
+ 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
+ ] Navigator {
+ readonly attribute DOMString appCodeName;
+ readonly attribute DOMString appName;
+ readonly attribute [CustomGetter] DOMString appVersion;
+ readonly attribute DOMString language;
+ readonly attribute DOMString userAgent;
+ readonly attribute DOMString platform;
+ readonly attribute PluginArray plugins;
+ readonly attribute MimeTypeArray 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 ENABLE_GEOLOCATION
+ readonly attribute Geolocation geolocation;
+#endif
+ };
+
+}
diff --git a/WebCore/page/Page.cpp b/WebCore/page/Page.cpp
new file mode 100644
index 0000000..3c573d6
--- /dev/null
+++ b/WebCore/page/Page.cpp
@@ -0,0 +1,582 @@
+/*
+ * Copyright (C) 2006, 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.
+ */
+
+#include "config.h"
+#include "Page.h"
+
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "ContextMenuClient.h"
+#include "ContextMenuController.h"
+#include "CSSStyleSelector.h"
+#include "EditorClient.h"
+#include "DOMWindow.h"
+#include "DragController.h"
+#include "EventNames.h"
+#include "FileSystem.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "HistoryItem.h"
+#include "InspectorController.h"
+#include "Logging.h"
+#include "NetworkStateNotifier.h"
+#include "Navigator.h"
+#include "PageGroup.h"
+#include "PluginData.h"
+#include "ProgressTracker.h"
+#include "RenderWidget.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "StringHash.h"
+#include "TextResourceDecoder.h"
+#include "Widget.h"
+#include "ScriptController.h"
+#include <kjs/collector.h>
+#include <runtime/JSLock.h>
+#include <wtf/HashMap.h>
+#include <wtf/RefCountedLeakCounter.h>
+
+#if ENABLE(DOM_STORAGE)
+#include "LocalStorage.h"
+#include "SessionStorage.h"
+#include "StorageArea.h"
+#endif
+
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+#include "JavaScriptDebugServer.h"
+#endif
+
+namespace WebCore {
+
+static HashSet<Page*>* allPages;
+
+#ifndef NDEBUG
+static WTF::RefCountedLeakCounter pageCounter("Page");
+#endif
+
+static void networkStateChanged()
+{
+ Vector<RefPtr<Frame> > frames;
+
+ // 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);
+ }
+
+ AtomicString eventName = networkStateNotifier().onLine() ? eventNames().onlineEvent : eventNames().offlineEvent;
+
+ for (unsigned i = 0; i < frames.size(); i++) {
+ Document* document = frames[i]->document();
+
+ if (!document)
+ continue;
+
+ // If the document does not have a body the event should be dispatched to the document
+ EventTargetNode* eventTarget = document->body();
+ if (!eventTarget)
+ eventTarget = document;
+
+ eventTarget->dispatchEventForType(eventName, false, false);
+ }
+}
+
+Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, EditorClient* editorClient, DragClient* dragClient, InspectorClient* inspectorClient)
+ : m_chrome(new Chrome(this, chromeClient))
+ , m_dragCaretController(new SelectionController(0, true))
+ , m_dragController(new DragController(this, dragClient))
+ , m_focusController(new FocusController(this))
+ , m_contextMenuController(new ContextMenuController(this, contextMenuClient))
+ , m_inspectorController(new InspectorController(this, inspectorClient))
+ , m_settings(new Settings(this))
+ , m_progress(new ProgressTracker)
+ , m_backForwardList(BackForwardList::create(this))
+ , m_editorClient(editorClient)
+ , m_frameCount(0)
+ , m_tabKeyCyclesThroughElements(true)
+ , m_defersLoading(false)
+ , m_inLowQualityInterpolationMode(false)
+ , m_cookieEnabled(true)
+ , m_parentInspectorController(0)
+ , m_didLoadUserStyleSheet(false)
+ , m_userStyleSheetModificationTime(0)
+ , m_group(0)
+ , m_debugger(0)
+ , m_pendingUnloadEventCount(0)
+ , m_pendingBeforeUnloadEventCount(0)
+ , m_customHTMLTokenizerTimeDelay(-1)
+ , m_customHTMLTokenizerChunkSize(-1)
+{
+ if (!allPages) {
+ allPages = new HashSet<Page*>;
+
+ networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged);
+ }
+
+ ASSERT(!allPages->contains(this));
+ allPages->add(this);
+
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+ JavaScriptDebugServer::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()) {
+ if (frame->document())
+ frame->document()->documentWillBecomeInactive();
+ frame->pageDestroyed();
+ }
+ m_editorClient->pageDestroyed();
+ if (m_parentInspectorController)
+ m_parentInspectorController->pageDestroyed();
+ m_inspectorController->inspectedPageDestroyed();
+
+ m_backForwardList->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
+}
+
+void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
+{
+ ASSERT(!m_mainFrame); // Should only be called during initialization
+ m_mainFrame = mainFrame;
+}
+
+BackForwardList* Page::backForwardList()
+{
+ return m_backForwardList.get();
+}
+
+bool Page::goBack()
+{
+ HistoryItem* item = m_backForwardList->backItem();
+
+ if (item) {
+ goToItem(item, FrameLoadTypeBack);
+ return true;
+ }
+ return false;
+}
+
+bool Page::goForward()
+{
+ HistoryItem* item = m_backForwardList->forwardItem();
+
+ if (item) {
+ goToItem(item, FrameLoadTypeForward);
+ return true;
+ }
+ return false;
+}
+
+void Page::goToItem(HistoryItem* item, FrameLoadType type)
+{
+ // Abort any current load if we're going to a history item
+ m_mainFrame->loader()->stopAllLoaders();
+ m_mainFrame->loader()->goToItem(item, type);
+}
+
+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 = 0;
+ else {
+ m_singlePageGroup.clear();
+ m_group = PageGroup::pageGroup(name);
+ m_group->addPage(this);
+ }
+}
+
+const String& Page::groupName() const
+{
+ static 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::setNeedsReapplyStyles()
+{
+ 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->setNeedsReapplyStyles();
+}
+
+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) {
+ (*it)->m_pluginData = 0;
+
+ if (reload) {
+ for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (frame->loader()->containsPlugins())
+ framesNeedingReload.append(frame);
+ }
+ }
+ }
+
+ for (size_t i = 0; i < framesNeedingReload.size(); ++i)
+ framesNeedingReload[i]->loader()->reload();
+}
+
+PluginData* Page::pluginData() const
+{
+ if (!m_pluginData)
+ m_pluginData = PluginData::create(this);
+ return m_pluginData.get();
+}
+
+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)
+{
+ if (target.isEmpty() || !mainFrame())
+ return false;
+
+ Frame* frame = focusController()->focusedOrMainFrame();
+ Frame* startFrame = frame;
+ do {
+ if (frame->findString(target, direction == FindDirectionForward, caseSensitivity == TextCaseSensitive, false, true)) {
+ if (frame != startFrame)
+ startFrame->selection()->clear();
+ focusController()->setFocusedFrame(frame);
+ return true;
+ }
+ frame = incrementFrame(frame, direction == FindDirectionForward, 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->findString(target, direction == FindDirectionForward, caseSensitivity == TextCaseSensitive, true, true);
+ focusController()->setFocusedFrame(frame);
+ return found;
+ }
+
+ return false;
+}
+
+unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit)
+{
+ if (target.isEmpty() || !mainFrame())
+ return 0;
+
+ unsigned matches = 0;
+
+ Frame* frame = mainFrame();
+ do {
+ frame->setMarkedTextMatchesAreHighlighted(shouldHighlight);
+ matches += frame->markAllMatchesForText(target, caseSensitivity == TextCaseSensitive, (limit == 0) ? 0 : (limit - matches));
+ frame = incrementFrame(frame, true, false);
+ } while (frame);
+
+ return matches;
+}
+
+void Page::unmarkAllTextMatches()
+{
+ if (!mainFrame())
+ return;
+
+ Frame* frame = mainFrame();
+ do {
+ if (Document* document = frame->document())
+ document->removeMarkers(DocumentMarker::TextMatch);
+ frame = incrementFrame(frame, true, false);
+ } while (frame);
+}
+
+const Selection& Page::selection() const
+{
+ return focusController()->focusedOrMainFrame()->selection()->selection();
+}
+
+void Page::setDefersLoading(bool defers)
+{
+ 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::userStyleSheetLocationChanged()
+{
+#if !FRAME_LOADS_USER_STYLESHEET
+ // FIXME: We should provide a way to load other types of URLs than just
+ // file: (e.g., http:, data:).
+ if (m_settings->userStyleSheetLocation().isLocalFile())
+ m_userStyleSheetPath = m_settings->userStyleSheetLocation().fileSystemPath();
+ else
+ m_userStyleSheetPath = String();
+
+ m_didLoadUserStyleSheet = false;
+ m_userStyleSheet = String();
+ m_userStyleSheetModificationTime = 0;
+#endif
+}
+
+const String& Page::userStyleSheet() const
+{
+ if (m_userStyleSheetPath.isEmpty()) {
+ ASSERT(m_userStyleSheet.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;
+
+ m_userStyleSheet = TextResourceDecoder::create("text/css")->decode(data->data(), data->size());
+
+ 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);
+ ASSERT(allPages);
+ 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, unsigned visitedLinkHash)
+{
+ ASSERT(group);
+ ASSERT(allPages);
+ 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);
+}
+
+#if ENABLE(DOM_STORAGE)
+SessionStorage* Page::sessionStorage(bool optionalCreate)
+{
+ if (!m_sessionStorage && optionalCreate)
+ m_sessionStorage = SessionStorage::create(this);
+
+ return m_sessionStorage.get();
+}
+
+void Page::setSessionStorage(PassRefPtr<SessionStorage> newStorage)
+{
+ ASSERT(newStorage->page() == this);
+ m_sessionStorage = newStorage;
+}
+#endif
+
+unsigned Page::pendingUnloadEventCount()
+{
+ return m_pendingUnloadEventCount;
+}
+
+void Page::changePendingUnloadEventCount(int delta)
+{
+ if (!delta)
+ return;
+ ASSERT( (delta + (int)m_pendingUnloadEventCount) >= 0 );
+
+ if (m_pendingUnloadEventCount == 0)
+ m_chrome->disableSuddenTermination();
+ else if ((m_pendingUnloadEventCount + delta) == 0)
+ m_chrome->enableSuddenTermination();
+
+ m_pendingUnloadEventCount += delta;
+ return;
+}
+
+unsigned Page::pendingBeforeUnloadEventCount()
+{
+ return m_pendingBeforeUnloadEventCount;
+}
+
+void Page::changePendingBeforeUnloadEventCount(int delta)
+{
+ if (!delta)
+ return;
+ ASSERT( (delta + (int)m_pendingBeforeUnloadEventCount) >= 0 );
+
+ if (m_pendingBeforeUnloadEventCount == 0)
+ m_chrome->disableSuddenTermination();
+ else if ((m_pendingBeforeUnloadEventCount + delta) == 0)
+ m_chrome->enableSuddenTermination();
+
+ m_pendingBeforeUnloadEventCount += delta;
+ return;
+}
+
+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;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/Page.h b/WebCore/page/Page.h
new file mode 100644
index 0000000..9c00ba7
--- /dev/null
+++ b/WebCore/page/Page.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2006, 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.
+ */
+
+#ifndef Page_h
+#define Page_h
+
+#include "BackForwardList.h"
+#include "Chrome.h"
+#include "ContextMenuController.h"
+#include "FrameLoaderTypes.h"
+#include "PlatformString.h"
+#if PLATFORM(MAC)
+#include "SchedulePair.h"
+#endif
+#include <wtf/HashSet.h>
+#include <wtf/OwnPtr.h>
+
+#if PLATFORM(WIN) || (PLATFORM(WX) && PLATFORM(WIN_OS)) || (PLATFORM(QT) && defined(Q_WS_WIN))
+typedef struct HINSTANCE__* HINSTANCE;
+#endif
+
+namespace JSC {
+ class Debugger;
+}
+
+namespace WebCore {
+
+ class Chrome;
+ class ChromeClient;
+ class ContextMenuClient;
+ class ContextMenuController;
+ class Document;
+ class DragClient;
+ class DragController;
+ class EditorClient;
+ class FocusController;
+ class Frame;
+ class InspectorClient;
+ class InspectorController;
+ class Node;
+ class PageGroup;
+ class PluginData;
+ class ProgressTracker;
+ class Selection;
+ class SelectionController;
+#if ENABLE(DOM_STORAGE)
+ class SessionStorage;
+#endif
+ class Settings;
+
+ enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive };
+ enum FindDirection { FindDirectionForward, FindDirectionBackward };
+
+ class Page : Noncopyable {
+ public:
+ static void setNeedsReapplyStyles();
+
+ Page(ChromeClient*, ContextMenuClient*, EditorClient*, DragClient*, InspectorClient*);
+ ~Page();
+
+ static void refreshPlugins(bool reload);
+ PluginData* pluginData() const;
+
+ EditorClient* editorClient() const { return m_editorClient; }
+
+ void setMainFrame(PassRefPtr<Frame>);
+ Frame* mainFrame() const { return m_mainFrame.get(); }
+
+ BackForwardList* backForwardList();
+
+ // FIXME: The following three methods don't fall under the responsibilities of the Page object
+ // They seem to fit a hypothetical Page-controller object that would be akin to the
+ // Frame-FrameLoader relationship. They have to live here now, but should move somewhere that
+ // makes more sense when that class exists.
+ bool goBack();
+ bool goForward();
+ void goToItem(HistoryItem*, FrameLoadType);
+
+ 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() { --m_frameCount; }
+ int frameCount() const { return m_frameCount; }
+
+ Chrome* chrome() const { return m_chrome.get(); }
+ SelectionController* dragCaretController() const { return m_dragCaretController.get(); }
+ DragController* dragController() const { return m_dragController.get(); }
+ FocusController* focusController() const { return m_focusController.get(); }
+ ContextMenuController* contextMenuController() const { return m_contextMenuController.get(); }
+ InspectorController* inspectorController() const { return m_inspectorController.get(); }
+ Settings* settings() const { return m_settings.get(); }
+ ProgressTracker* progress() const { return m_progress.get(); }
+
+ void setParentInspectorController(InspectorController* controller) { m_parentInspectorController = controller; }
+ InspectorController* parentInspectorController() const { return m_parentInspectorController; }
+
+ void setTabKeyCyclesThroughElements(bool b) { m_tabKeyCyclesThroughElements = b; }
+ bool tabKeyCyclesThroughElements() const { return m_tabKeyCyclesThroughElements; }
+
+ bool findString(const String&, TextCaseSensitivity, FindDirection, bool shouldWrap);
+ unsigned int 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 Selection& 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; }
+
+ void userStyleSheetLocationChanged();
+ const String& userStyleSheet() const;
+
+ void changePendingUnloadEventCount(int delta);
+ unsigned pendingUnloadEventCount();
+ void changePendingBeforeUnloadEventCount(int delta);
+ unsigned pendingBeforeUnloadEventCount();
+
+ static void setDebuggerForAllPages(JSC::Debugger*);
+ void setDebugger(JSC::Debugger*);
+ JSC::Debugger* debugger() const { return m_debugger; }
+
+#if PLATFORM(WIN) || (PLATFORM(WX) && PLATFORM(WIN_OS)) || (PLATFORM(QT) && defined(Q_WS_WIN))
+ // The global DLL or application instance used for all windows.
+ static void setInstanceHandle(HINSTANCE instanceHandle) { s_instanceHandle = instanceHandle; }
+ static HINSTANCE instanceHandle() { return s_instanceHandle; }
+#endif
+
+ static void removeAllVisitedLinks();
+
+ static void allVisitedStateChanged(PageGroup*);
+ static void visitedStateChanged(PageGroup*, unsigned visitedHash);
+
+#if ENABLE(DOM_STORAGE)
+ SessionStorage* sessionStorage(bool optionalCreate = true);
+ void setSessionStorage(PassRefPtr<SessionStorage>);
+#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; }
+
+ private:
+ void initGroup();
+
+ OwnPtr<Chrome> m_chrome;
+ OwnPtr<SelectionController> m_dragCaretController;
+ OwnPtr<DragController> m_dragController;
+ OwnPtr<FocusController> m_focusController;
+ OwnPtr<ContextMenuController> m_contextMenuController;
+ OwnPtr<InspectorController> m_inspectorController;
+ OwnPtr<Settings> m_settings;
+ OwnPtr<ProgressTracker> m_progress;
+
+ RefPtr<BackForwardList> m_backForwardList;
+ RefPtr<Frame> m_mainFrame;
+
+ mutable RefPtr<PluginData> m_pluginData;
+
+ EditorClient* m_editorClient;
+
+ int m_frameCount;
+ String m_groupName;
+
+ bool m_tabKeyCyclesThroughElements;
+ bool m_defersLoading;
+
+ bool m_inLowQualityInterpolationMode;
+ bool m_cookieEnabled;
+
+ InspectorController* m_parentInspectorController;
+
+ 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;
+
+ unsigned m_pendingUnloadEventCount;
+ unsigned m_pendingBeforeUnloadEventCount;
+
+ double m_customHTMLTokenizerTimeDelay;
+ int m_customHTMLTokenizerChunkSize;
+
+#if ENABLE(DOM_STORAGE)
+ RefPtr<SessionStorage> m_sessionStorage;
+#endif
+#if PLATFORM(WIN) || (PLATFORM(WX) && defined(__WXMSW__)) || (PLATFORM(QT) && defined(Q_WS_WIN))
+ static HINSTANCE s_instanceHandle;
+#endif
+ };
+
+} // namespace WebCore
+
+#endif // Page_h
diff --git a/WebCore/page/PageGroup.cpp b/WebCore/page/PageGroup.cpp
new file mode 100644
index 0000000..6b72be2
--- /dev/null
+++ b/WebCore/page/PageGroup.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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 "ChromeClient.h"
+#include "Document.h"
+#include "Page.h"
+#include "Settings.h"
+
+#if ENABLE(DOM_STORAGE)
+#include "LocalStorage.h"
+#include "StorageArea.h"
+#endif
+
+namespace WebCore {
+
+static unsigned getUniqueIdentifier()
+{
+ static unsigned currentIdentifier = 0;
+ return ++currentIdentifier;
+}
+
+// --------
+
+static bool shouldTrackVisitedLinks;
+
+PageGroup::PageGroup(const String& name)
+ : m_name(name)
+ , m_visitedLinksPopulated(false)
+ , m_identifier(getUniqueIdentifier())
+{
+}
+
+PageGroup::PageGroup(Page* page)
+ : m_visitedLinksPopulated(false)
+ , m_identifier(getUniqueIdentifier())
+{
+ ASSERT(page);
+ addPage(page);
+}
+
+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 (LocalStorage* localStorage = it->second->localStorage())
+ localStorage->close();
+ }
+#endif
+}
+
+void PageGroup::addPage(Page* page)
+{
+ ASSERT(page);
+ ASSERT(!m_pages.contains(page));
+ m_pages.add(page);
+#if ENABLE(DOM_STORAGE)
+ if (!m_localStorage)
+ m_localStorage = LocalStorage::localStorage(page->settings()->localStorageDatabasePath());
+#endif
+}
+
+void PageGroup::removePage(Page* page)
+{
+ ASSERT(page);
+ ASSERT(m_pages.contains(page));
+ m_pages.remove(page);
+}
+
+bool PageGroup::isLinkVisited(unsigned visitedLinkHash)
+{
+ if (!m_visitedLinksPopulated) {
+ m_visitedLinksPopulated = true;
+ ASSERT(!m_pages.isEmpty());
+ (*m_pages.begin())->chrome()->client()->populateVisitedLinks();
+ }
+ return m_visitedLinkHashes.contains(visitedLinkHash);
+}
+
+inline void PageGroup::addVisitedLink(unsigned stringHash)
+{
+ ASSERT(shouldTrackVisitedLinks);
+ unsigned visitedLinkHash = AlreadyHashed::avoidDeletedValue(stringHash);
+ if (!m_visitedLinkHashes.add(visitedLinkHash).second)
+ return;
+ Page::visitedStateChanged(this, visitedLinkHash);
+}
+
+void PageGroup::addVisitedLink(const KURL& url)
+{
+ if (!shouldTrackVisitedLinks)
+ return;
+ ASSERT(!url.isEmpty());
+ addVisitedLink(url.string().impl()->hash());
+}
+
+void PageGroup::addVisitedLink(const UChar* characters, size_t length)
+{
+ if (!shouldTrackVisitedLinks)
+ return;
+ addVisitedLink(StringImpl::computeHash(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)
+LocalStorage* PageGroup::localStorage()
+{
+ return m_localStorage.get();
+}
+#endif
+
+} // namespace WebCore
diff --git a/WebCore/page/PageGroup.h b/WebCore/page/PageGroup.h
new file mode 100644
index 0000000..b25892d
--- /dev/null
+++ b/WebCore/page/PageGroup.h
@@ -0,0 +1,85 @@
+/*
+ * 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 "StringHash.h"
+
+namespace WebCore {
+
+ class KURL;
+ class LocalStorage;
+ class Page;
+
+ class PageGroup : Noncopyable {
+ public:
+ PageGroup(const String& name);
+ PageGroup(Page*);
+
+ static PageGroup* pageGroup(const String& groupName);
+ static void closeLocalStorage();
+
+ const HashSet<Page*>& pages() const { return m_pages; }
+
+ void addPage(Page*);
+ void removePage(Page*);
+
+ bool isLinkVisited(unsigned visitedLinkHash);
+
+ void addVisitedLink(const KURL&);
+ void addVisitedLink(const UChar*, size_t);
+ void removeVisitedLinks();
+
+ static void setShouldTrackVisitedLinks(bool);
+ static void removeAllVisitedLinks();
+
+ const String& name() { return m_name; }
+ unsigned identifier() { return m_identifier; }
+
+#if ENABLE(DOM_STORAGE)
+ LocalStorage* localStorage();
+#endif
+
+ private:
+ void addVisitedLink(unsigned stringHash);
+
+ String m_name;
+
+ HashSet<Page*> m_pages;
+ HashSet<unsigned, AlreadyHashed> m_visitedLinkHashes;
+ bool m_visitedLinksPopulated;
+
+ unsigned m_identifier;
+#if ENABLE(DOM_STORAGE)
+ RefPtr<LocalStorage> m_localStorage;
+#endif
+ };
+
+} // namespace WebCore
+
+#endif // PageGroup_h
diff --git a/WebCore/page/PositionCallback.h b/WebCore/page/PositionCallback.h
new file mode 100644
index 0000000..5f32c75
--- /dev/null
+++ b/WebCore/page/PositionCallback.h
@@ -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.
+ *
+ * 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 <wtf/Platform.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class Geoposition;
+
+ class PositionCallback : public RefCounted<PositionCallback> {
+ public:
+ virtual ~PositionCallback() { }
+ virtual void handleEvent(Geoposition* position, bool& raisedException) = 0;
+ };
+
+} // namespace WebCore
+
+#endif // PositionCallback_h
diff --git a/WebCore/page/PositionCallback.idl b/WebCore/page/PositionCallback.idl
new file mode 100644
index 0000000..e862538
--- /dev/null
+++ b/WebCore/page/PositionCallback.idl
@@ -0,0 +1,34 @@
+/*
+ * 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 [
+ GenerateConstructor
+ ] PositionCallback {
+ void handleEvent(in Geoposition position);
+ };
+
+}
diff --git a/WebCore/page/PositionError.h b/WebCore/page/PositionError.h
new file mode 100644
index 0000000..1d68bde
--- /dev/null
+++ b/WebCore/page/PositionError.h
@@ -0,0 +1,63 @@
+/*
+ * 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_ERROR = 1,
+ LOCATION_PROVIDER_ERROR,
+ POSITION_NOT_FOUND_ERROR,
+ TIMEOUT_ERROR,
+ UNKNOWN_ERROR
+ };
+
+ 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; }
+
+private:
+ PositionError(ErrorCode code, const String& message)
+ : m_code(code)
+ , m_message(message)
+ {
+ }
+
+ ErrorCode m_code;
+ String m_message;
+};
+
+} // namespace WebCore
+
+#endif // PositionError_h
diff --git a/WebCore/page/PositionError.idl b/WebCore/page/PositionError.idl
new file mode 100644
index 0000000..8c8c335
--- /dev/null
+++ b/WebCore/page/PositionError.idl
@@ -0,0 +1,35 @@
+/*
+ * 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 [
+ GenerateConstructor
+ ] PositionError {
+ readonly attribute long code;
+ readonly attribute DOMString message;
+ };
+
+}
diff --git a/WebCore/page/PositionErrorCallback.h b/WebCore/page/PositionErrorCallback.h
new file mode 100644
index 0000000..c23e883
--- /dev/null
+++ b/WebCore/page/PositionErrorCallback.h
@@ -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.
+ *
+ * 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 <wtf/Platform.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class PositionError;
+
+ class PositionErrorCallback : public RefCounted<PositionErrorCallback> {
+ public:
+ virtual ~PositionErrorCallback() { }
+ virtual void handleEvent(PositionError*) = 0;
+ };
+
+} // namespace WebCore
+
+#endif // PositionErrorCallback_h
diff --git a/WebCore/page/PositionErrorCallback.idl b/WebCore/page/PositionErrorCallback.idl
new file mode 100644
index 0000000..07edfa6
--- /dev/null
+++ b/WebCore/page/PositionErrorCallback.idl
@@ -0,0 +1,34 @@
+/*
+ * 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 [
+ GenerateConstructor
+ ] PositionErrorCallback {
+ void handleEvent(in PositionError error);
+ };
+
+}
diff --git a/WebCore/page/PositionOptions.h b/WebCore/page/PositionOptions.h
new file mode 100644
index 0000000..dc9c167
--- /dev/null
+++ b/WebCore/page/PositionOptions.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 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(bool highAccuracy, unsigned timeout) { return adoptRef(new PositionOptions(highAccuracy, timeout)); }
+
+ bool enableHighAccuracy() const { return m_highAccuracy; }
+ void setEnableHighAccuracy(bool enable) { m_highAccuracy = enable; }
+ unsigned timeout() const { return m_timeout; }
+ void setTimeout(unsigned t) { m_timeout = t; }
+
+private:
+ PositionOptions(bool highAccuracy, unsigned timeout)
+ : m_highAccuracy(highAccuracy)
+ , m_timeout(timeout)
+ {
+ }
+
+ bool m_highAccuracy;
+ unsigned m_timeout;
+};
+
+} // namespace WebCore
+
+#endif // PositionOptions_h
diff --git a/WebCore/page/PositionOptions.idl b/WebCore/page/PositionOptions.idl
new file mode 100644
index 0000000..29253df
--- /dev/null
+++ b/WebCore/page/PositionOptions.idl
@@ -0,0 +1,35 @@
+/*
+ * 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 [
+ GenerateConstructor
+ ] PositionOptions {
+ attribute boolean enableHighAccuracy;
+ attribute unsigned long timeout;
+ };
+
+}
diff --git a/WebCore/page/PrintContext.cpp b/WebCore/page/PrintContext.cpp
new file mode 100644
index 0000000..79672a3
--- /dev/null
+++ b/WebCore/page/PrintContext.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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 "RenderView.h"
+
+using namespace WebCore;
+
+namespace WebCore {
+
+PrintContext::PrintContext(Frame* frame)
+ : m_frame(frame)
+{
+}
+
+PrintContext::~PrintContext()
+{
+ m_pageRects.clear();
+}
+
+int PrintContext::pageCount() const
+{
+ return m_pageRects.size();
+}
+
+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;
+
+ RenderView* root = static_cast<RenderView*>(m_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 = printRect.height() / printRect.width();
+
+ float pageWidth = (float)root->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;
+ }
+
+ float currPageHeight = pageHeight / userScaleFactor;
+ float docHeight = root->layer()->height();
+ 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 = std::min(docHeight, printedPagesHeight + pageHeight);
+ m_frame->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight);
+ currPageHeight = max(1.0f, proposedBottom - printedPagesHeight);
+
+ m_pageRects.append(IntRect(0, (int)printedPagesHeight, (int)currPageWidth, (int)currPageHeight));
+ printedPagesHeight += currPageHeight;
+ } while (printedPagesHeight < docHeight);
+}
+
+void PrintContext::begin(float width)
+{
+ // 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 maxLayoutWidth = width * PrintingMaximumShrinkFactor;
+
+ // FIXME: This will modify the rendering of the on-screen frame.
+ // Could lead to flicker during printing.
+ m_frame->setPrinting(true, minLayoutWidth, maxLayoutWidth, true);
+}
+
+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()
+{
+ m_frame->setPrinting(false, 0, 0, true);
+}
+
+}
diff --git a/WebCore/page/PrintContext.h b/WebCore/page/PrintContext.h
new file mode 100644
index 0000000..0b3b303
--- /dev/null
+++ b/WebCore/page/PrintContext.h
@@ -0,0 +1,57 @@
+/*
+ * 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/Vector.h>
+
+namespace WebCore {
+
+class Frame;
+class FloatRect;
+class GraphicsContext;
+class IntRect;
+
+class PrintContext {
+public:
+ PrintContext(Frame*);
+ ~PrintContext();
+
+ int pageCount() const;
+
+ void computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight);
+
+ // TODO: eliminate width param
+ void begin(float width);
+
+ // TODO: eliminate width param
+ void spoolPage(GraphicsContext& ctx, int pageNumber, float width);
+
+ void end();
+
+protected:
+ Frame* m_frame;
+ Vector<IntRect> m_pageRects;
+};
+
+}
+
+#endif
diff --git a/WebCore/page/Screen.cpp b/WebCore/page/Screen.cpp
new file mode 100644
index 0000000..396a6f4
--- /dev/null
+++ b/WebCore/page/Screen.cpp
@@ -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.
+ */
+
+
+#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)
+{
+}
+
+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()));
+}
+
+unsigned Screen::availLeft() const
+{
+ if (!m_frame)
+ return 0;
+ return static_cast<unsigned>(screenAvailableRect(m_frame->view()).x());
+}
+
+unsigned Screen::availTop() const
+{
+ if (!m_frame)
+ return 0;
+ return static_cast<unsigned>(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/WebCore/page/Screen.h b/WebCore/page/Screen.h
new file mode 100644
index 0000000..a740ccb
--- /dev/null
+++ b/WebCore/page/Screen.h
@@ -0,0 +1,65 @@
+/*
+ * 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)); }
+ void disconnectFrame();
+
+ unsigned height() const;
+ unsigned width() const;
+ unsigned colorDepth() const;
+ unsigned pixelDepth() const;
+ unsigned availLeft() const;
+ unsigned availTop() const;
+ unsigned availHeight() const;
+ unsigned availWidth() const;
+#ifdef ANDROID_ORIENTATION_SUPPORT
+ int orientation() const;
+#endif
+
+ private:
+ Screen(Frame*);
+
+ Frame* m_frame;
+ };
+
+} // namespace WebCore
+
+#endif // Screen_h
diff --git a/WebCore/page/Screen.idl b/WebCore/page/Screen.idl
new file mode 100644
index 0000000..ca7d20d
--- /dev/null
+++ b/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 Screen {
+ readonly attribute unsigned long height;
+ readonly attribute unsigned long width;
+ readonly attribute unsigned long colorDepth;
+ readonly attribute unsigned long pixelDepth;
+ readonly attribute unsigned long availLeft;
+ readonly attribute unsigned long availTop;
+ readonly attribute unsigned long availHeight;
+ readonly attribute unsigned long availWidth;
+ };
+
+}
diff --git a/WebCore/page/SecurityOrigin.cpp b/WebCore/page/SecurityOrigin.cpp
new file mode 100644
index 0000000..6de7508
--- /dev/null
+++ b/WebCore/page/SecurityOrigin.cpp
@@ -0,0 +1,295 @@
+/*
+ * 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 "CString.h"
+#include "FrameLoader.h"
+#include "KURL.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+static bool isDefaultPortForProtocol(unsigned short port, const String& protocol)
+{
+ if (protocol.isEmpty())
+ return false;
+
+ static HashMap<String, unsigned> defaultPorts;
+ if (defaultPorts.isEmpty()) {
+ defaultPorts.set("http", 80);
+ defaultPorts.set("https", 443);
+ defaultPorts.set("ftp", 21);
+ defaultPorts.set("ftps", 990);
+ }
+ return defaultPorts.get(protocol) == port;
+}
+
+SecurityOrigin::SecurityOrigin(const KURL& url)
+ : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower())
+ , m_host(url.host().isNull() ? "" : url.host().lower())
+ , m_port(url.port())
+ , m_noAccess(false)
+ , m_domainWasSetInDOM(false)
+{
+ // These protocols do not create security origins; the owner frame provides the origin
+ if (m_protocol == "about" || m_protocol == "javascript")
+ m_protocol = "";
+
+ // data: URLs are not allowed access to anything other than themselves.
+ if (m_protocol == "data")
+ m_noAccess = 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 (isDefaultPortForProtocol(m_port, m_protocol))
+ m_port = 0;
+}
+
+SecurityOrigin::SecurityOrigin(const SecurityOrigin* other)
+ : m_protocol(other->m_protocol.copy())
+ , m_host(other->m_host.copy())
+ , m_domain(other->m_domain.copy())
+ , m_port(other->m_port)
+ , m_noAccess(other->m_noAccess)
+ , m_domainWasSetInDOM(other->m_domainWasSetInDOM)
+ , m_canLoadLocalResources(other->m_canLoadLocalResources)
+{
+}
+
+bool SecurityOrigin::isEmpty() const
+{
+ return m_protocol.isEmpty();
+}
+
+PassRefPtr<SecurityOrigin> SecurityOrigin::create(const KURL& url)
+{
+ return adoptRef(new SecurityOrigin(url));
+}
+
+PassRefPtr<SecurityOrigin> SecurityOrigin::createEmpty()
+{
+ return create(KURL());
+}
+
+PassRefPtr<SecurityOrigin> SecurityOrigin::copy()
+{
+ return adoptRef(new SecurityOrigin(this));
+}
+
+void SecurityOrigin::setDomainFromDOM(const String& newDomain)
+{
+ m_domainWasSetInDOM = true;
+ m_domain = newDomain.lower();
+}
+
+bool SecurityOrigin::canAccess(const SecurityOrigin* other) const
+{
+ if (isLocal())
+ return true;
+
+ if (m_noAccess || other->m_noAccess)
+ 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.
+
+ if (m_protocol == other->m_protocol) {
+ if (!m_domainWasSetInDOM && !other->m_domainWasSetInDOM) {
+ if (m_host == other->m_host && m_port == other->m_port)
+ return true;
+ } else if (m_domainWasSetInDOM && other->m_domainWasSetInDOM) {
+ if (m_domain == other->m_domain)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool SecurityOrigin::canRequest(const KURL& url) const
+{
+ if (isLocal())
+ return true;
+
+ if (m_noAccess)
+ return false;
+
+ RefPtr<SecurityOrigin> targetOrigin = SecurityOrigin::create(url);
+
+ // We call isSameSchemeHostPort here instead of canAccess because we want
+ // to ignore document.domain effects.
+ return isSameSchemeHostPort(targetOrigin.get());
+}
+
+void SecurityOrigin::grantLoadLocalResources()
+{
+ // This method 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(FrameLoader::allowSubstituteDataAccessToLocal());
+ m_canLoadLocalResources = true;
+}
+
+bool SecurityOrigin::isLocal() const
+{
+ return FrameLoader::shouldTreatSchemeAsLocal(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 (m_noAccess)
+ return "null";
+
+ if (m_protocol == "file")
+ return String("file://");
+
+ Vector<UChar> result;
+ result.reserveCapacity(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(originString));
+}
+
+static const char SeparatorCharacter = '_';
+
+PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const String& databaseIdentifier)
+{
+ // Make sure there's a first separator
+ int separator1 = databaseIdentifier.find(SeparatorCharacter);
+ if (separator1 == -1)
+ return create(KURL());
+
+ // Make sure there's a second separator
+ int separator2 = databaseIdentifier.find(SeparatorCharacter, separator1 + 1);
+ if (separator2 == -1)
+ return create(KURL());
+
+ // Make sure there's not a third separator
+ if (databaseIdentifier.reverseFind(SeparatorCharacter) != 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);
+ if (!portOkay && separator2 + 1 == static_cast<int>(databaseIdentifier.length()))
+ return create(KURL());
+
+ if (port < 0 || port > 65535)
+ 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);
+ return create(KURL(protocol + "://" + host + ":" + String::number(port)));
+}
+
+String SecurityOrigin::databaseIdentifier() const
+{
+ static String separatorString = String(&SeparatorCharacter, 1);
+ return m_protocol + separatorString + m_host + separatorString + String::number(m_port);
+}
+
+bool SecurityOrigin::equal(const SecurityOrigin* other) const
+{
+ 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;
+
+ return true;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/SecurityOrigin.h b/WebCore/page/SecurityOrigin.h
new file mode 100644
index 0000000..1f2624e
--- /dev/null
+++ b/WebCore/page/SecurityOrigin.h
@@ -0,0 +1,141 @@
+/*
+ * 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 <wtf/RefCounted.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/Threading.h>
+
+#include "PlatformString.h"
+
+namespace WebCore {
+
+ 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 KURL&);
+ static PassRefPtr<SecurityOrigin> createEmpty();
+
+ // Create a deep copy of this SecurityOrigin. This method is useful
+ // when marshalling a SecurityOrigin to another thread.
+ PassRefPtr<SecurityOrigin> copy();
+
+ // 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; }
+
+ 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 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();
+
+ 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;
+
+ // Convert this SecurityOrigin into a string. The string
+ // representation of a SecurityOrigin is similar to a URL, except it
+ // lacks a path component. The string representation does not encode
+ // the value of the SecurityOrigin's domain property. The empty
+ // SecurityOrigin is represented with the string "null".
+ String toString() const;
+
+ // Serialize the security origin for storage in the database. This format is
+ // deprecated and should be used only for compatibility with old databases;
+ // use toString() and createFromString() instead.
+ 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;
+
+ private:
+ explicit SecurityOrigin(const KURL&);
+ explicit SecurityOrigin(const SecurityOrigin*);
+
+ String m_protocol;
+ String m_host;
+ String m_domain;
+ unsigned short m_port;
+ bool m_noAccess;
+ bool m_domainWasSetInDOM;
+ bool m_canLoadLocalResources;
+ };
+
+} // namespace WebCore
+
+#endif // SecurityOrigin_h
diff --git a/WebCore/page/SecurityOriginHash.h b/WebCore/page/SecurityOriginHash.h
new file mode 100644
index 0000000..1915fc7
--- /dev/null
+++ b/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 StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
+ }
+ 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/WebCore/page/Settings.cpp b/WebCore/page/Settings.cpp
new file mode 100644
index 0000000..b9b3925
--- /dev/null
+++ b/WebCore/page/Settings.cpp
@@ -0,0 +1,512 @@
+/*
+ * 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 "Settings.h"
+
+#include "Frame.h"
+#include "FrameTree.h"
+#include "HistoryItem.h"
+#include "Page.h"
+#include "PageCache.h"
+#include <limits>
+
+#if ENABLE(DATABASE)
+#include "DatabaseTracker.h"
+#endif
+
+namespace WebCore {
+
+static void setNeedsReapplyStylesInAllFrames(Page* page)
+{
+ for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
+ frame->setNeedsReapplyStyles();
+}
+
+#if USE(SAFARI_THEME)
+bool Settings::gShouldPaintNativeControls = false;
+#endif
+
+Settings::Settings(Page* page)
+ : m_page(page)
+#ifdef ANDROID_LAYOUT
+ , m_layoutAlgorithm(kLayoutFitColumnToScreen)
+#endif
+ , m_editableLinkBehavior(EditableLinkDefaultBehavior)
+ , 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_isJavaEnabled(false)
+ , m_loadsImagesAutomatically(false)
+ , m_privateBrowsingEnabled(false)
+ , m_arePluginsEnabled(false)
+ , m_isJavaScriptEnabled(false)
+ , m_javaScriptCanOpenWindowsAutomatically(false)
+ , m_shouldPrintBackgrounds(false)
+ , m_textAreasAreResizable(false)
+#if ENABLE(DASHBOARD_SUPPORT)
+ , m_usesDashboardBackwardCompatibilityMode(false)
+#endif
+ , m_needsAdobeFrameReloadingQuirk(false)
+ , m_needsKeyboardEventDisambiguationQuirks(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_webArchiveDebugModeEnabled(false)
+ , m_inApplicationChromeMode(false)
+ , m_offlineWebApplicationCacheEnabled(false)
+ , m_rangeMutationDisabledForOldAppleMail(false)
+ , m_shouldPaintCustomScrollbars(false)
+ , m_zoomsTextOnly(false)
+ , m_enforceCSSMIMETypeInStrictMode(true)
+ , m_maximumDecodedImageSize(std::numeric_limits<size_t>::max())
+{
+ // 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
+ resetMetadataSettings();
+#endif
+}
+
+void Settings::setStandardFontFamily(const AtomicString& standardFontFamily)
+{
+ if (standardFontFamily == m_standardFontFamily)
+ return;
+
+ m_standardFontFamily = standardFontFamily;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+void Settings::setFixedFontFamily(const AtomicString& fixedFontFamily)
+{
+ if (m_fixedFontFamily == fixedFontFamily)
+ return;
+
+ m_fixedFontFamily = fixedFontFamily;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+void Settings::setSerifFontFamily(const AtomicString& serifFontFamily)
+{
+ if (m_serifFontFamily == serifFontFamily)
+ return;
+
+ m_serifFontFamily = serifFontFamily;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+void Settings::setSansSerifFontFamily(const AtomicString& sansSerifFontFamily)
+{
+ if (m_sansSerifFontFamily == sansSerifFontFamily)
+ return;
+
+ m_sansSerifFontFamily = sansSerifFontFamily;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+void Settings::setCursiveFontFamily(const AtomicString& cursiveFontFamily)
+{
+ if (m_cursiveFontFamily == cursiveFontFamily)
+ return;
+
+ m_cursiveFontFamily = cursiveFontFamily;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+void Settings::setFantasyFontFamily(const AtomicString& fantasyFontFamily)
+{
+ if (m_fantasyFontFamily == fantasyFontFamily)
+ return;
+
+ m_fantasyFontFamily = fantasyFontFamily;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+void Settings::setMinimumFontSize(int minimumFontSize)
+{
+ if (m_minimumFontSize == minimumFontSize)
+ return;
+
+ m_minimumFontSize = minimumFontSize;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+void Settings::setMinimumLogicalFontSize(int minimumLogicalFontSize)
+{
+ if (m_minimumLogicalFontSize == minimumLogicalFontSize)
+ return;
+
+ m_minimumLogicalFontSize = minimumLogicalFontSize;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+void Settings::setDefaultFontSize(int defaultFontSize)
+{
+ if (m_defaultFontSize == defaultFontSize)
+ return;
+
+ m_defaultFontSize = defaultFontSize;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+void Settings::setDefaultFixedFontSize(int defaultFontSize)
+{
+ if (m_defaultFixedFontSize == defaultFontSize)
+ return;
+
+ m_defaultFixedFontSize = defaultFontSize;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+void Settings::setBlockNetworkImage(bool blockNetworkImage)
+{
+ m_blockNetworkImage = blockNetworkImage;
+}
+#endif
+
+void Settings::setLoadsImagesAutomatically(bool loadsImagesAutomatically)
+{
+ m_loadsImagesAutomatically = loadsImagesAutomatically;
+}
+
+void Settings::setJavaScriptEnabled(bool isJavaScriptEnabled)
+{
+ m_isJavaScriptEnabled = isJavaScriptEnabled;
+}
+
+void Settings::setJavaEnabled(bool isJavaEnabled)
+{
+ m_isJavaEnabled = isJavaEnabled;
+}
+
+void Settings::setPluginsEnabled(bool arePluginsEnabled)
+{
+ m_arePluginsEnabled = arePluginsEnabled;
+}
+
+#ifdef ANDROID_PLUGINS
+void Settings::setPluginsPath(const String& pluginsPath)
+{
+ m_pluginsPath = pluginsPath;
+}
+#endif
+
+void Settings::setPrivateBrowsingEnabled(bool privateBrowsingEnabled)
+{
+ m_privateBrowsingEnabled = privateBrowsingEnabled;
+}
+
+void Settings::setJavaScriptCanOpenWindowsAutomatically(bool javaScriptCanOpenWindowsAutomatically)
+{
+ m_javaScriptCanOpenWindowsAutomatically = javaScriptCanOpenWindowsAutomatically;
+}
+
+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();
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+void Settings::setShouldPrintBackgrounds(bool shouldPrintBackgrounds)
+{
+ m_shouldPrintBackgrounds = shouldPrintBackgrounds;
+}
+
+void Settings::setTextAreasAreResizable(bool textAreasAreResizable)
+{
+ if (m_textAreasAreResizable == textAreasAreResizable)
+ return;
+
+ m_textAreasAreResizable = textAreasAreResizable;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+void Settings::setEditableLinkBehavior(EditableLinkBehavior editableLinkBehavior)
+{
+ m_editableLinkBehavior = editableLinkBehavior;
+}
+
+#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::setDOMPasteAllowed(bool DOMPasteAllowed)
+{
+ m_isDOMPasteAllowed = DOMPasteAllowed;
+}
+
+void Settings::setUsesPageCache(bool usesPageCache)
+{
+ if (m_usesPageCache == usesPageCache)
+ return;
+
+ m_usesPageCache = usesPageCache;
+ if (!m_usesPageCache) {
+ HistoryItemVector& historyItems = m_page->backForwardList()->entries();
+ for (unsigned i = 0; i < historyItems.size(); i++)
+ pageCache()->remove(historyItems[i].get());
+ 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_format_detection_telephone = true;
+ m_format_detection_address = true;
+ m_format_detection_email = true;
+}
+
+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 >= 200 && 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 prtrait 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 == "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;
+ }
+ }
+}
+#endif
+
+void Settings::setAuthorAndUserStylesEnabled(bool authorAndUserStylesEnabled)
+{
+ if (m_authorAndUserStylesEnabled == authorAndUserStylesEnabled)
+ return;
+
+ m_authorAndUserStylesEnabled = authorAndUserStylesEnabled;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+void Settings::setFontRenderingMode(FontRenderingMode mode)
+{
+ if (fontRenderingMode() == mode)
+ return;
+ m_fontRenderingMode = mode;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+FontRenderingMode Settings::fontRenderingMode() const
+{
+ return static_cast<FontRenderingMode>(m_fontRenderingMode);
+}
+
+void Settings::setNeedsSiteSpecificQuirks(bool needsQuirks)
+{
+ m_needsSiteSpecificQuirks = needsQuirks;
+}
+
+void Settings::setWebArchiveDebugModeEnabled(bool enabled)
+{
+ m_webArchiveDebugModeEnabled = enabled;
+}
+
+void Settings::setLocalStorageDatabasePath(const String& path)
+{
+ m_localStorageDatabasePath = path;
+}
+
+void Settings::disableRangeMutationForOldAppleMail(bool disable)
+{
+ m_rangeMutationDisabledForOldAppleMail = disable;
+}
+
+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::setZoomsTextOnly(bool zoomsTextOnly)
+{
+ if (zoomsTextOnly == m_zoomsTextOnly)
+ return;
+
+ m_zoomsTextOnly = zoomsTextOnly;
+ setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+void Settings::setEnforceCSSMIMETypeInStrictMode(bool enforceCSSMIMETypeInStrictMode)
+{
+ m_enforceCSSMIMETypeInStrictMode = enforceCSSMIMETypeInStrictMode;
+}
+
+#if USE(SAFARI_THEME)
+void Settings::setShouldPaintNativeControls(bool shouldPaintNativeControls)
+{
+ gShouldPaintNativeControls = shouldPaintNativeControls;
+}
+#endif
+
+} // namespace WebCore
diff --git a/WebCore/page/Settings.h b/WebCore/page/Settings.h
new file mode 100644
index 0000000..8acc998
--- /dev/null
+++ b/WebCore/page/Settings.h
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2003, 2006, 2007, 2008 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 "AtomicString.h"
+#include "FontDescription.h"
+#include "KURL.h"
+
+namespace WebCore {
+
+ class Page;
+
+ enum EditableLinkBehavior {
+ EditableLinkDefaultBehavior = 0,
+ EditableLinkAlwaysLive,
+ EditableLinkOnlyLiveWithShiftKey,
+ EditableLinkLiveWhenNotFocused,
+ EditableLinkNeverLive
+ };
+
+ class Settings {
+ 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; }
+
+ 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);
+ bool isJavaScriptEnabled() const { return m_isJavaScriptEnabled; }
+
+ void setJavaScriptCanOpenWindowsAutomatically(bool);
+ bool JavaScriptCanOpenWindowsAutomatically() const { return m_javaScriptCanOpenWindowsAutomatically; }
+
+ void setJavaEnabled(bool);
+ bool isJavaEnabled() const { return m_isJavaEnabled; }
+
+ void setPluginsEnabled(bool);
+ bool arePluginsEnabled() const { return m_arePluginsEnabled; }
+
+#ifdef ANDROID_PLUGINS
+ void setPluginsPath(const String& pluginsPath);
+ const String& pluginsPath() const { return m_pluginsPath; }
+#endif
+
+ void setPrivateBrowsingEnabled(bool);
+ bool privateBrowsingEnabled() const { return m_privateBrowsingEnabled; }
+
+ void setDefaultTextEncodingName(const String&);
+ const String& defaultTextEncodingName() const { return m_defaultTextEncodingName; }
+
+ 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; }
+
+#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 setDOMPasteAllowed(bool);
+ bool isDOMPasteAllowed() const { return m_isDOMPasteAllowed; }
+
+ 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; }
+
+#ifdef ANDROID_META_SUPPORT
+ void resetMetadataSettings();
+ void setMetadataSettings(const String& key, const String& value);
+
+ int viewportWidth() const { return m_viewport_width; }
+ int viewportHeight() const { return m_viewport_height; }
+ int viewportInitialScale() const { return m_viewport_initial_scale; }
+ int viewportMinimumScale() const { return m_viewport_minimum_scale; }
+ int viewportMaximumScale() const { return m_viewport_maximum_scale; }
+ bool viewportUserScalable() const { return m_viewport_user_scalable; }
+ bool formatDetectionAddress() const { return m_format_detection_address; }
+ bool formatDetectionEmail() const { return m_format_detection_email; }
+ bool formatDetectionTelephone() const { return m_format_detection_telephone; }
+#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 setLocalStorageDatabasePath(const String&);
+ const String& localStorageDatabasePath() const { return m_localStorageDatabasePath; }
+
+ void disableRangeMutationForOldAppleMail(bool);
+ bool rangeMutationDisabledForOldAppleMail() const { return m_rangeMutationDisabledForOldAppleMail; }
+
+ 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 setZoomsTextOnly(bool);
+ bool zoomsTextOnly() const { return m_zoomsTextOnly; }
+
+ void setEnforceCSSMIMETypeInStrictMode(bool);
+ bool enforceCSSMIMETypeInStrictMode() { return m_enforceCSSMIMETypeInStrictMode; }
+
+ 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
+
+ private:
+ Page* m_page;
+
+ String m_defaultTextEncodingName;
+ String m_ftpDirectoryTemplatePath;
+#ifdef ANDROID_PLUGINS
+ String m_pluginsPath;
+#endif
+ 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;
+ 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;
+ // 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;
+#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
+ bool m_isJavaEnabled : 1;
+ bool m_loadsImagesAutomatically : 1;
+ bool m_privateBrowsingEnabled : 1;
+ bool m_arePluginsEnabled : 1;
+ bool m_isJavaScriptEnabled : 1;
+ bool m_javaScriptCanOpenWindowsAutomatically : 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_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_webArchiveDebugModeEnabled : 1;
+ bool m_inApplicationChromeMode : 1;
+ bool m_offlineWebApplicationCacheEnabled : 1;
+ bool m_rangeMutationDisabledForOldAppleMail : 1;
+ bool m_shouldPaintCustomScrollbars : 1;
+ bool m_zoomsTextOnly : 1;
+ bool m_enforceCSSMIMETypeInStrictMode : 1;
+ size_t m_maximumDecodedImageSize;
+
+#if USE(SAFARI_THEME)
+ static bool gShouldPaintNativeControls;
+#endif
+ };
+
+} // namespace WebCore
+
+#endif // Settings_h
diff --git a/WebCore/page/WindowFeatures.cpp b/WebCore/page/WindowFeatures.cpp
new file mode 100644
index 0000000..c499a4a
--- /dev/null
+++ b/WebCore/page/WindowFeatures.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006 Jon Shier (jshier@iastate.edu)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 "PlatformString.h"
+#include "StringHash.h"
+#include <wtf/Assertions.h>
+#include <wtf/HashMap.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+// Though isspace() considers \t and \v to be whitespace, Win IE doesn't.
+static bool isSeparator(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 (isSeparator(buffer[i])) {
+ if (i >= length)
+ break;
+ i++;
+ }
+ keyBegin = i;
+
+ // skip to first separator
+ while (!isSeparator(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 (isSeparator(buffer[i])) {
+ if (buffer[i] == ',' || i >= length)
+ break;
+ i++;
+ }
+ valueBegin = i;
+
+ // skip to first separator
+ while (!isSeparator(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.length() == 0 || valueString == "yes")
+ value = 1;
+ else
+ value = valueString.toInt();
+
+ // We ignore a keyString of "resizable", which is consistent with Firefox.
+ 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;
+}
+
+bool WindowFeatures::boolFeature(const HashMap<String, String>& features, const char* key, bool defaultValue)
+{
+ HashMap<String, String>::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 HashMap<String, String>& features, const char* key, float min, float max, float defaultValue)
+{
+ HashMap<String, String>::const_iterator it = features.find(key);
+ if (it == features.end())
+ return defaultValue;
+ // FIXME: Can't distinguish "0q" from string with no digits in it -- both return d == 0 and ok == false.
+ // Would be good to tell them apart somehow since string with no digits should be default value and
+ // "0q" should be minimum value.
+ bool ok;
+ double d = it->second.toDouble(&ok);
+ if ((d == 0 && !ok) || isnan(d))
+ return defaultValue;
+ if (d < min || max <= min)
+ return min;
+ if (d > max)
+ return max;
+ return static_cast<int>(d);
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/WindowFeatures.h b/WebCore/page/WindowFeatures.h
new file mode 100644
index 0000000..a12cf05
--- /dev/null
+++ b/WebCore/page/WindowFeatures.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2003, 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 WindowFeatures_h
+#define WindowFeatures_h
+
+#include "PlatformString.h"
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+ struct WindowFeatures {
+ 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& features);
+
+ void setWindowFeature(const String& keyString, const String& valueString);
+
+ static bool boolFeature(const HashMap<String, String>& features, const char* key, bool defaultValue = false);
+ static float floatFeature(const HashMap<String, String>& features, const char* key, float min, float max, float defaultValue);
+
+ 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;
+ };
+
+} // namespace WebCore
+
+#endif // WindowFeatures_h
diff --git a/WebCore/page/android/DragControllerAndroid.cpp b/WebCore/page/android/DragControllerAndroid.cpp
new file mode 100644
index 0000000..ae87f02
--- /dev/null
+++ b/WebCore/page/android/DragControllerAndroid.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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"
+
+namespace WebCore {
+
+bool DragController::isCopyKeyDown()
+{
+ return false;
+}
+
+DragOperation DragController::dragOperation(DragData* dragData)
+{
+ //FIXME: This logic is incomplete
+ ASSERT(0);
+ if (dragData->containsURL())
+ return DragOperationCopy;
+
+ return DragOperationNone;
+}
+
+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/WebCore/page/android/EventHandlerAndroid.cpp b/WebCore/page/android/EventHandlerAndroid.cpp
new file mode 100644
index 0000000..62ccd2e
--- /dev/null
+++ b/WebCore/page/android/EventHandlerAndroid.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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 {
+
+unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::AltKey;
+
+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(static_cast<RenderWidget*>(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 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&, Frame*, 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&, Widget*)
+{
+ notImplemented();
+ return false;
+}
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ return passSubframeEventToSubframe(mev, subframe);
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev,
+ Frame* subframe, HitTestResult*)
+{
+ return passSubframeEventToSubframe(mev, subframe);
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ return passSubframeEventToSubframe(mev, subframe);
+}
+
+class Clipboard : public RefCounted<Clipboard> {
+};
+
+PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
+{
+ return PassRefPtr<Clipboard>(0);
+}
+
+const double EventHandler::TextDragDelay = 0.0;
+
+} // namespace WebCore
diff --git a/WebCore/page/android/InspectorControllerAndroid.cpp b/WebCore/page/android/InspectorControllerAndroid.cpp
new file mode 100644
index 0000000..4f55ec4
--- /dev/null
+++ b/WebCore/page/android/InspectorControllerAndroid.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InspectorController.h"
+
+#include "InspectorClient.h"
+
+#include "Frame.h"
+#include "Node.h"
+#include "Profile.h"
+
+// This stub file was created to avoid building and linking in all the
+// Inspector codebase. If you would like to enable the Inspector, do the
+// following steps:
+// 1. Replace this file in WebCore/Android.mk with the common
+// implementation, ie page/InsepctorController.cpp
+// 2. Add the JS API files to JavaScriptCore/Android.mk:
+// ? API/JSBase.cpp \
+// API/JSCallbackConstructor.cpp \
+// API/JSCallbackFunction.cpp \
+// API/JSCallbackObject.cpp \
+// API/JSClassRef.cpp \
+// API/JSContextRef.cpp \
+// API/JSObjectRef.cpp \
+// API/JSStringRef.cpp \
+// API/JSValueRef.cpp
+// 3. Add the following LOCAL_C_INCLUDES to JavaScriptCore/Android.mk:
+// ?$(LOCAL_PATH)/API \
+// $(LOCAL_PATH)/ForwardingHeaders \
+// $(LOCAL_PATH)/../../WebKit \
+// 4. Rebuild WebKit
+//
+// Note, for a functional Inspector, you must implement InspectorClientAndroid.
+
+namespace WebCore {
+
+struct InspectorResource : public RefCounted<InspectorResource> {
+};
+
+struct InspectorDatabaseResource : public RefCounted<InspectorDatabaseResource> {
+};
+
+InspectorController::InspectorController(Page*, InspectorClient* client)
+ : m_startProfiling(this, 0)
+{
+ m_client = client;
+}
+
+InspectorController::~InspectorController() { m_client->inspectorDestroyed(); }
+
+void InspectorController::windowScriptObjectAvailable() {}
+void InspectorController::didCommitLoad(DocumentLoader*) {}
+void InspectorController::identifierForInitialRequest(unsigned long, DocumentLoader*, ResourceRequest const&) {}
+void InspectorController::willSendRequest(DocumentLoader*, unsigned long, ResourceRequest&, ResourceResponse const&) {}
+void InspectorController::didReceiveResponse(DocumentLoader*, unsigned long, ResourceResponse const&) {}
+void InspectorController::didReceiveContentLength(DocumentLoader*, unsigned long, int) {}
+void InspectorController::didFinishLoading(DocumentLoader*, unsigned long) {}
+void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader*, ResourceRequest const&, ResourceResponse const&, int) {}
+void InspectorController::frameDetachedFromParent(Frame*) {}
+
+void InspectorController::addMessageToConsole(MessageSource, MessageLevel, JSC::ExecState*, JSC::ArgList const&, unsigned int, String const&) {}
+void InspectorController::addMessageToConsole(MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String& sourceID) {}
+#if ENABLE(DATABASE)
+void InspectorController::didOpenDatabase(Database*, String const&, String const&, String const&) {}
+#endif
+bool InspectorController::enabled() const { return false; }
+void InspectorController::inspect(Node*) {}
+bool InspectorController::windowVisible() { return false; }
+void InspectorController::addProfile(PassRefPtr<JSC::Profile>, unsigned int, const JSC::UString&) {}
+void InspectorController::inspectedPageDestroyed() {}
+void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, JSC::UString& sourceString) {}
+
+void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame) {}
+void InspectorController::startGroup(MessageSource source, JSC::ExecState* exec, const JSC::ArgList& arguments, unsigned lineNumber, const String& sourceURL) {}
+void InspectorController::endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL) {}
+void InspectorController::startTiming(const JSC::UString& title) {}
+bool InspectorController::stopTiming(const JSC::UString& title, double& elapsed) { return false; }
+void InspectorController::count(const JSC::UString& title, unsigned lineNumber, const String& sourceID) {}
+
+void InspectorController::mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags) {}
+void InspectorController::handleMousePressOnNode(Node*) {}
+void InspectorController::failedToParseSource(JSC::ExecState* exec, const JSC::SourceCode& source, int errorLine, const JSC::UString& errorMessage) {}
+void InspectorController::didParseSource(JSC::ExecState* exec, const JSC::SourceCode& source) {}
+void InspectorController::didPause() {}
+
+} // namespace WebCore
diff --git a/WebCore/page/animation/AnimationBase.cpp b/WebCore/page/animation/AnimationBase.cpp
new file mode 100644
index 0000000..fc28469
--- /dev/null
+++ b/WebCore/page/animation/AnimationBase.cpp
@@ -0,0 +1,815 @@
+/*
+ * 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 "AnimationBase.h"
+
+#include "AnimationController.h"
+#include "CSSPropertyNames.h"
+#include "CString.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 "RenderObject.h"
+#include "RenderStyle.h"
+#include "SystemTime.h"
+#include "UnitBezier.h"
+
+namespace WebCore {
+
+static const double cAnimationTimerDelay = 0.025;
+
+// 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));
+}
+
+void AnimationTimerCallback::timerFired(Timer<AnimationTimerBase>*)
+{
+ m_anim->animationTimerCallbackFired(m_eventType, m_elapsedTime);
+}
+
+static inline int blendFunc(const AnimationBase* anim, int from, int to, double progress)
+{
+ return int(from + (to - from) * progress);
+}
+
+static inline double blendFunc(const AnimationBase* anim, double from, double to, double progress)
+{
+ return from + (to - from) * progress;
+}
+
+static inline float blendFunc(const AnimationBase* anim, 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)
+{
+ return Color(blendFunc(anim, from.red(), to.red(), progress),
+ blendFunc(anim, from.green(), to.green(), progress),
+ blendFunc(anim, from.blue(), to.blue(), progress),
+ blendFunc(anim, from.alpha(), to.alpha(), progress));
+}
+
+static inline Length blendFunc(const AnimationBase* anim, const Length& from, const Length& to, double progress)
+{
+ return to.blend(from, 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 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->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()->borderBox().size();
+ AffineTransform fromT;
+ AffineTransform toT;
+ from.apply(size, fromT);
+ to.apply(size, toT);
+
+ toT.blend(fromT, progress);
+
+ // Append the result
+ result.operations().append(MatrixTransformOperation::create(toT.a(), toT.b(), toT.c(), toT.d(), toT.e(), toT.f()));
+ }
+ 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);
+}
+
+class PropertyWrapperBase {
+public:
+ PropertyWrapperBase(int prop)
+ : m_prop(prop)
+ {
+ }
+
+ virtual ~PropertyWrapperBase() { }
+ 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; }
+
+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);
+};
+
+class PropertyWrapperShadow : public PropertyWrapperGetter<ShadowData*> {
+public:
+ PropertyWrapperShadow(int prop, ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(ShadowData*, bool))
+ : PropertyWrapperGetter<ShadowData*>(prop, getter)
+ , m_setter(setter)
+ {
+ }
+
+ virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ {
+ ShadowData* shadowA = (a->*m_getter)();
+ ShadowData* shadowB = (b->*m_getter)();
+
+ if (!shadowA && shadowB || shadowA && !shadowB)
+ return false;
+ if (shadowA && shadowB && (*shadowA != *shadowB))
+ return false;
+ return true;
+ }
+
+ virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ {
+ ShadowData* shadowA = (a->*m_getter)();
+ ShadowData* shadowB = (b->*m_getter)();
+ ShadowData defaultShadowData(0, 0, 0, Color::transparent);
+
+ if (!shadowA)
+ shadowA = &defaultShadowData;
+ if (!shadowB)
+ shadowB = &defaultShadowData;
+
+ (dst->*m_setter)(blendFunc(anim, shadowA, shadowB, progress), false);
+ }
+
+private:
+ 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())
+ 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())
+ 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&);
+};
+
+static Vector<PropertyWrapperBase*>* gPropertyWrappers = 0;
+static int gPropertyWrapperMap[numCSSProperties];
+
+static void 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>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight));
+ 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<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity));
+ gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor));
+ gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor));
+ gPropertyWrappers->append(new PropertyWrapper<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<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX));
+ gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY));
+ gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius));
+ gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius));
+ gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius));
+ gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyWebkitBorderBottomRightRadius, &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 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));
+
+ // These are for shadows
+ 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
+
+ // Make sure unused slots have a value
+ for (unsigned int i = 0; i < (unsigned int) numCSSProperties; ++i)
+ gPropertyWrapperMap[i] = CSSPropertyInvalid;
+
+ 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;
+ }
+ }
+}
+
+AnimationBase::AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim)
+ : m_animState(AnimationStateNew)
+ , m_iteration(0)
+ , m_isAnimating(false)
+ , m_waitedForResponse(false)
+ , m_startTime(0)
+ , m_pauseTime(-1)
+ , m_object(renderer)
+ , m_animationTimerCallback(const_cast<AnimationBase*>(this))
+ , m_animation(const_cast<Animation*>(transition))
+ , m_compAnim(compAnim)
+ , m_transformFunctionListValid(false)
+{
+}
+
+AnimationBase::~AnimationBase()
+{
+ if (m_animState == AnimationStateStartWaitStyleAvailable)
+ m_compAnim->setWaitingForStyleAvailable(false);
+}
+
+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) {
+ if (!(*gPropertyWrappers)[i]->equals(a, b))
+ return false;
+ }
+ } else {
+ int propIndex = prop - firstCSSProperty;
+
+ if (propIndex >= 0 && propIndex < numCSSProperties) {
+ int i = gPropertyWrapperMap[propIndex];
+ return i >= 0 ? (*gPropertyWrappers)[i]->equals(a, b) : true;
+ }
+ }
+ return true;
+}
+
+int AnimationBase::getPropertyAtIndex(int i)
+{
+ ensurePropertyMap();
+ if (i < 0 || i >= static_cast<int>(gPropertyWrappers->size()))
+ return CSSPropertyInvalid;
+
+ return (*gPropertyWrappers)[i]->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);
+ // FIXME: Why can this happen?
+
+ ensurePropertyMap();
+ if (prop == cAnimateAll) {
+ bool needsTimer = false;
+
+ size_t n = gPropertyWrappers->size();
+ for (unsigned int i = 0; i < n; ++i) {
+ PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i];
+ if (!wrapper->equals(a, b)) {
+ wrapper->blend(anim, dst, a, b, progress);
+ needsTimer = true;
+ }
+ }
+ return needsTimer;
+ }
+
+ int propIndex = prop - firstCSSProperty;
+ if (propIndex >= 0 && propIndex < numCSSProperties) {
+ int i = gPropertyWrapperMap[propIndex];
+ if (i >= 0) {
+ PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i];
+ wrapper->blend(anim, dst, a, b, progress);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void AnimationBase::setChanged(Node* node)
+{
+ ASSERT(!node || (node->document() && !node->document()->inPageCache()));
+ node->setChanged(AnimationStyleChange);
+}
+
+double AnimationBase::duration() const
+{
+ return m_animation->duration();
+}
+
+bool AnimationBase::playStatePlaying() const
+{
+ return m_animation && 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->setWaitingForStyleAvailable(false);
+ m_animState = AnimationStateNew;
+ m_startTime = 0;
+ m_pauseTime = -1;
+ m_waitedForResponse = false;
+ endAnimation(false);
+ return;
+ }
+
+ if (input == AnimationStateInputRestartAnimation) {
+ cancelTimers();
+ if (m_animState == AnimationStateStartWaitStyleAvailable)
+ m_compAnim->setWaitingForStyleAvailable(false);
+ m_animState = AnimationStateNew;
+ m_startTime = 0;
+ m_pauseTime = -1;
+ endAnimation(false);
+
+ if (!paused())
+ updateStateMachine(AnimationStateInputStartAnimation, -1);
+ return;
+ }
+
+ if (input == AnimationStateInputEndAnimation) {
+ cancelTimers();
+ if (m_animState == AnimationStateStartWaitStyleAvailable)
+ m_compAnim->setWaitingForStyleAvailable(false);
+ m_animState = AnimationStateDone;
+ endAnimation(true);
+ 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(false);
+ updateStateMachine(AnimationStateInputStartTimeSet, currentTime());
+ }
+ return;
+ }
+
+ if (input == AnimationStateInputResumeOverride) {
+ if (m_animState == AnimationStateLooping || m_animState == AnimationStateEnding) {
+ // Start the animation
+ startAnimation(m_startTime);
+ }
+ return;
+ }
+
+ // Execute state machine
+ switch(m_animState) {
+ case AnimationStateNew:
+ ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning || input == AnimationStateInputPlayStatePaused);
+ if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning) {
+ // Set the start timer to the initial delay (0 if no delay)
+ m_waitedForResponse = false;
+ m_animState = AnimationStateStartWaitTimer;
+ m_animationTimerCallback.startTimer(m_animation->delay(), eventNames().webkitAnimationStartEvent, m_animation->delay());
+ }
+ 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->setWaitingForStyleAvailable(true);
+
+ // Trigger a render so we can start the animation
+ setChanged(m_object->element());
+ m_object->animation()->startUpdateRenderingDispatcher();
+ } 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 = currentTime();
+ cancelTimers();
+ m_animState = AnimationStatePausedWaitTimer;
+ }
+ break;
+ case AnimationStateStartWaitStyleAvailable:
+ ASSERT(input == AnimationStateInputStyleAvailable || input == AnimationStateInputPlayStatePaused);
+
+ m_compAnim->setWaitingForStyleAvailable(false);
+
+ 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();
+
+ // Send start event, if needed
+ onAnimationStart(0); // The elapsedTime is always 0 here
+
+ // Start the animation
+ if (overridden() || !startAnimation(0)) {
+ // We're not going to get a startTime callback, so fire the start time here
+ m_animState = AnimationStateStartWaitResponse;
+ updateStateMachine(AnimationStateInputStartTimeSet, currentTime());
+ } else
+ m_waitedForResponse = true;
+ } else {
+ ASSERT(!paused());
+ // We're waiting for the a notification that the style has been setup. If we're asked to wait
+ // at this point, the style must have been processed, so we can deal with this like we would
+ // for WAIT_RESPONSE, except that we don't need to do an endAnimation().
+ m_pauseTime = 0;
+ m_animState = AnimationStateStartWaitResponse;
+ }
+ 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;
+
+ // Decide when the end or loop event needs to fire
+ primeEventTimers();
+
+ // Trigger a render so we can start the animation
+ setChanged(m_object->element());
+ m_object->animation()->startUpdateRenderingDispatcher();
+ } 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 = 0;
+ endAnimation(false);
+ 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);
+ primeEventTimers();
+ } else {
+ // We are pausing while running. Cancel the animation and wait
+ m_pauseTime = currentTime();
+ cancelTimers();
+ endAnimation(false);
+ m_animState = AnimationStatePausedRun;
+ }
+ break;
+ case AnimationStateEnding:
+ ASSERT(input == AnimationStateInputEndTimerFired || input == AnimationStateInputPlayStatePaused);
+
+ if (input == AnimationStateInputEndTimerFired) {
+ ASSERT(param >= 0);
+ // End timer fired, finish up
+ onAnimationEnd(param);
+
+ resumeOverriddenAnimations();
+
+ // Fire off another style change so we can set the final value
+ setChanged(m_object->element());
+ m_animState = AnimationStateDone;
+ m_object->animation()->startUpdateRenderingDispatcher();
+ // |this| may be deleted here when we've been called from timerFired()
+ } else {
+ // We are pausing while running. Cancel the animation and wait
+ m_pauseTime = currentTime();
+ cancelTimers();
+ endAnimation(false);
+ m_animState = AnimationStatePausedRun;
+ }
+ // |this| may be deleted here
+ break;
+ case AnimationStatePausedWaitTimer:
+ ASSERT(input == AnimationStateInputPlayStateRunnning);
+ ASSERT(paused());
+ // Update the times
+ m_startTime += currentTime() - 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 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 == AnimationStateInputPlayStateRunnning);
+ ASSERT(paused());
+ // Update the times
+ if (m_animState == AnimationStatePausedRun)
+ m_startTime += currentTime() - m_pauseTime;
+ else
+ m_startTime = 0;
+ m_pauseTime = -1;
+
+ // We were waiting for a begin time response from the animation, go back and wait again
+ m_animState = AnimationStateStartWaitResponse;
+
+ // Start the animation
+ if (overridden() || !startAnimation(m_startTime)) {
+ // We're not going to get a startTime callback, so fire the start time here
+ updateStateMachine(AnimationStateInputStartTimeSet, currentTime());
+ } else
+ m_waitedForResponse = true;
+ break;
+ case AnimationStateDone:
+ // We're done. Stay in this state until we are deleted
+ break;
+ }
+ // |this| may be deleted here if we came out of AnimationStateEnding when we've been called from timerFired()
+}
+
+void AnimationBase::animationTimerCallbackFired(const AtomicString& eventType, double elapsedTime)
+{
+ ASSERT(m_object->document() && !m_object->document()->inPageCache());
+
+ // FIXME: use an enum
+ if (eventType == eventNames().webkitAnimationStartEvent)
+ updateStateMachine(AnimationStateInputStartTimerFired, elapsedTime);
+ else if (eventType == eventNames().webkitAnimationIterationEvent)
+ updateStateMachine(AnimationStateInputLoopTimerFired, elapsedTime);
+ else if (eventType == eventNames().webkitAnimationEndEvent) {
+ updateStateMachine(AnimationStateInputEndTimerFired, elapsedTime);
+ // |this| may be deleted here
+ }
+}
+
+void AnimationBase::updatePlayState(bool run)
+{
+ if (paused() == run || isNew())
+ updateStateMachine(run ? AnimationStateInputPlayStateRunnning : AnimationStateInputPlayStatePaused, -1);
+}
+
+double AnimationBase::progress(double scale, double offset, const TimingFunction* tf) const
+{
+ if (preActive())
+ return 0;
+
+ double elapsedTime = running() ? (currentTime() - m_startTime) : (m_pauseTime - m_startTime);
+ if (running() && elapsedTime < 0)
+ return 0;
+
+ double dur = m_animation->duration();
+ if (m_animation->iterationCount() > 0)
+ dur *= m_animation->iterationCount();
+
+ if (postActive() || !m_animation->duration() || (m_animation->iterationCount() > 0 && elapsedTime >= dur))
+ return 1.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() && (integralTime & 1))
+ fractionalTime = 1 - fractionalTime;
+
+ if (scale != 1 || offset)
+ fractionalTime = (fractionalTime - offset) * scale;
+
+ if (!tf)
+ tf = &m_animation->timingFunction();
+
+ if (tf->type() == LinearTimingFunction)
+ return fractionalTime;
+
+ // Cubic bezier.
+ double result = solveCubicBezierFunction(tf->x1(),
+ tf->y1(),
+ tf->x2(),
+ tf->y2(),
+ fractionalTime, m_animation->duration());
+ return result;
+}
+
+void AnimationBase::primeEventTimers()
+{
+ // Decide when the end or loop event needs to fire
+ double ct = currentTime();
+ const double elapsedDuration = ct - m_startTime;
+ ASSERT(elapsedDuration >= 0);
+
+ double totalDuration = -1;
+ if (m_animation->iterationCount() > 0)
+ totalDuration = m_animation->duration() * m_animation->iterationCount();
+
+ double durationLeft = 0;
+ double nextIterationTime = totalDuration;
+ if (totalDuration < 0 || elapsedDuration < totalDuration) {
+ durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
+ nextIterationTime = elapsedDuration + durationLeft;
+ }
+
+ // At this point, we may have 0 durationLeft, if we've gotten the event late and we are already
+ // past totalDuration. In this case we still fire an end timer before processing the end.
+ // This defers the call to sendAnimationEvents to avoid re-entrant calls that destroy
+ // the RenderObject, and therefore |this| before we're done with it.
+ if (totalDuration < 0 || nextIterationTime < totalDuration) {
+ // We are not at the end yet, send a loop event
+ ASSERT(nextIterationTime > 0);
+ m_animState = AnimationStateLooping;
+ m_animationTimerCallback.startTimer(durationLeft, eventNames().webkitAnimationIterationEvent, nextIterationTime);
+ } else {
+ // We are at the end, send an end event
+ m_animState = AnimationStateEnding;
+ m_animationTimerCallback.startTimer(durationLeft, eventNames().webkitAnimationEndEvent, nextIterationTime);
+ }
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/animation/AnimationBase.h b/WebCore/page/animation/AnimationBase.h
new file mode 100644
index 0000000..925c0d5
--- /dev/null
+++ b/WebCore/page/animation/AnimationBase.h
@@ -0,0 +1,254 @@
+/*
+ * 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 "AtomicString.h"
+#include "Timer.h"
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class Animation;
+class AnimationBase;
+class AnimationController;
+class CompositeAnimation;
+class Element;
+class Node;
+class RenderObject;
+class RenderStyle;
+class TimingFunction;
+
+class AnimationTimerBase {
+public:
+ AnimationTimerBase(AnimationBase* anim)
+ : m_timer(this, &AnimationTimerBase::timerFired)
+ , m_anim(anim)
+ {
+ m_timer.startOneShot(0);
+ }
+
+ virtual ~AnimationTimerBase() { }
+
+ void startTimer(double timeout = 0)
+ {
+ m_timer.startOneShot(timeout);
+ }
+
+ void cancelTimer()
+ {
+ m_timer.stop();
+ }
+
+ virtual void timerFired(Timer<AnimationTimerBase>*) = 0;
+
+private:
+ Timer<AnimationTimerBase> m_timer;
+
+protected:
+ AnimationBase* m_anim;
+};
+
+class AnimationTimerCallback : public AnimationTimerBase {
+public:
+ AnimationTimerCallback(AnimationBase* anim)
+ : AnimationTimerBase(anim)
+ , m_elapsedTime(0)
+ {
+ }
+
+ virtual ~AnimationTimerCallback() { }
+
+ virtual void timerFired(Timer<AnimationTimerBase>*);
+
+ void startTimer(double timeout, const AtomicString& eventType, double elapsedTime)
+ {
+ m_eventType = eventType;
+ m_elapsedTime = elapsedTime;
+ AnimationTimerBase::startTimer(timeout);
+ }
+
+private:
+ AtomicString m_eventType;
+ double m_elapsedTime;
+};
+
+class AnimationBase : public RefCounted<AnimationBase> {
+ friend class CompositeAnimationPrivate;
+
+public:
+ AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim);
+ virtual ~AnimationBase();
+
+ RenderObject* renderer() const { return m_object; }
+ double startTime() const { return m_startTime; }
+ double duration() const;
+
+ void cancelTimers()
+ {
+ m_animationTimerCallback.cancelTimer();
+ }
+
+ // 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
+ AnimationStatePausedWaitResponse, // animation paused when in STARTING state
+ AnimationStatePausedRun, // animation paused when in LOOPING or ENDING state
+ AnimationStateDone // end timer fired, animation finished and removed
+ };
+
+ 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
+ AnimationStateInputPlayStateRunnning, // 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);
+
+ // Called to change to or from paused state
+ void updatePlayState(bool running);
+ 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; }
+ bool isAnimating() const { return m_isAnimating; }
+
+ double progress(double scale, double offset, const TimingFunction*) const;
+
+ virtual void animate(CompositeAnimation*, RenderObject*, const RenderStyle* currentStyle,
+ const RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) { }
+
+ virtual bool shouldFireEvents() const { return false; }
+
+ void animationTimerCallbackFired(const AtomicString& eventType, double elapsedTime);
+
+ 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 isRunningNow) const
+ {
+ if (isRunningNow)
+ return (!waitingToStart() && !postActive()) && affectsProperty(property);
+
+ return !postActive() && affectsProperty(property);
+ }
+
+ bool isTransformFunctionListValid() const { return m_transformFunctionListValid; }
+
+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) { }
+ virtual bool startAnimation(double beginTime) { return false; }
+ virtual void endAnimation(bool reset) { }
+
+ void primeEventTimers();
+
+ static bool propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b);
+ static int getPropertyAtIndex(int);
+ 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 setChanged(Node*);
+
+protected:
+ AnimState m_animState;
+ int m_iteration;
+
+ bool m_isAnimating; // transition/animation requires continual timer firing
+ bool m_waitedForResponse;
+ double m_startTime;
+ double m_pauseTime;
+ RenderObject* m_object;
+
+ AnimationTimerCallback m_animationTimerCallback;
+ RefPtr<Animation> m_animation;
+ CompositeAnimation* m_compAnim;
+ bool m_transformFunctionListValid;
+};
+
+} // namespace WebCore
+
+#endif // AnimationBase_h
diff --git a/WebCore/page/animation/AnimationController.cpp b/WebCore/page/animation/AnimationController.cpp
new file mode 100644
index 0000000..d449afe
--- /dev/null
+++ b/WebCore/page/animation/AnimationController.cpp
@@ -0,0 +1,298 @@
+/*
+ * 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 "AnimationController.h"
+#include "CompositeAnimation.h"
+#include "Frame.h"
+#include "Timer.h"
+
+namespace WebCore {
+
+static const double cAnimationTimerDelay = 0.025;
+
+class AnimationControllerPrivate {
+public:
+ AnimationControllerPrivate(Frame*);
+ ~AnimationControllerPrivate();
+
+ CompositeAnimation* accessCompositeAnimation(RenderObject*);
+ bool clear(RenderObject*);
+
+ void animationTimerFired(Timer<AnimationControllerPrivate>*);
+ void updateAnimationTimer();
+
+ void updateRenderingDispatcherFired(Timer<AnimationControllerPrivate>*);
+ void startUpdateRenderingDispatcher();
+
+ bool hasAnimations() const { return !m_compositeAnimations.isEmpty(); }
+
+ void suspendAnimations(Document*);
+ void resumeAnimations(Document*);
+
+ void styleAvailable();
+
+ bool isAnimatingPropertyOnRenderer(RenderObject*, int property, bool isRunningNow) const;
+
+private:
+ typedef HashMap<RenderObject*, CompositeAnimation*> RenderObjectAnimationMap;
+
+ RenderObjectAnimationMap m_compositeAnimations;
+ Timer<AnimationControllerPrivate> m_animationTimer;
+ Timer<AnimationControllerPrivate> m_updateRenderingDispatcher;
+ Frame* m_frame;
+};
+
+AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame)
+ : m_animationTimer(this, &AnimationControllerPrivate::animationTimerFired)
+ , m_updateRenderingDispatcher(this, &AnimationControllerPrivate::updateRenderingDispatcherFired)
+ , m_frame(frame)
+{
+}
+
+AnimationControllerPrivate::~AnimationControllerPrivate()
+{
+ deleteAllValues(m_compositeAnimations);
+}
+
+CompositeAnimation* AnimationControllerPrivate::accessCompositeAnimation(RenderObject* renderer)
+{
+ CompositeAnimation* animation = m_compositeAnimations.get(renderer);
+ if (!animation) {
+ animation = new CompositeAnimation(m_frame->animation());
+ 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 setChanged() when suspended).
+ CompositeAnimation* animation = m_compositeAnimations.take(renderer);
+ if (!animation)
+ return false;
+ animation->resetTransitions(renderer);
+ bool wasSuspended = animation->isSuspended();
+ delete animation;
+ return !wasSuspended;
+}
+
+void AnimationControllerPrivate::styleAvailable()
+{
+ RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
+ for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it)
+ it->second->styleAvailable();
+}
+
+void AnimationControllerPrivate::updateAnimationTimer()
+{
+ bool isAnimating = false;
+
+ RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
+ for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
+ CompositeAnimation* compAnim = it->second;
+ if (!compAnim->isSuspended() && compAnim->isAnimating()) {
+ isAnimating = true;
+ break;
+ }
+ }
+
+ if (isAnimating) {
+ if (!m_animationTimer.isActive())
+ m_animationTimer.startRepeating(cAnimationTimerDelay);
+ } else if (m_animationTimer.isActive())
+ m_animationTimer.stop();
+}
+
+void AnimationControllerPrivate::updateRenderingDispatcherFired(Timer<AnimationControllerPrivate>*)
+{
+ if (m_frame && m_frame->document())
+ m_frame->document()->updateRendering();
+}
+
+void AnimationControllerPrivate::startUpdateRenderingDispatcher()
+{
+ if (!m_updateRenderingDispatcher.isActive())
+ m_updateRenderingDispatcher.startOneShot(0);
+}
+
+void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPrivate>* timer)
+{
+ // When the timer fires, all we do is call setChanged on all DOM nodes with running animations and then do an immediate
+ // updateRendering. It will then call back to us with new information.
+ bool isAnimating = false;
+ RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
+ for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
+ CompositeAnimation* compAnim = it->second;
+ if (!compAnim->isSuspended() && compAnim->isAnimating()) {
+ isAnimating = true;
+ compAnim->setAnimating(false);
+
+ Node* node = it->first->element();
+ ASSERT(!node || (node->document() && !node->document()->inPageCache()));
+ node->setChanged(AnimationStyleChange);
+ }
+ }
+
+ m_frame->document()->updateRendering();
+
+ updateAnimationTimer();
+}
+
+bool AnimationControllerPrivate::isAnimatingPropertyOnRenderer(RenderObject* renderer, int property, bool isRunningNow) const
+{
+ CompositeAnimation* animation = m_compositeAnimations.get(renderer);
+ if (!animation)
+ return false;
+
+ return animation->isAnimatingProperty(property, isRunningNow);
+}
+
+void AnimationControllerPrivate::suspendAnimations(Document* document)
+{
+ RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
+ for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
+ RenderObject* renderer = it->first;
+ CompositeAnimation* compAnim = it->second;
+ if (renderer->document() == document)
+ compAnim->suspendAnimations();
+ }
+
+ updateAnimationTimer();
+}
+
+void AnimationControllerPrivate::resumeAnimations(Document* document)
+{
+ RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
+ for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
+ RenderObject* renderer = it->first;
+ CompositeAnimation* compAnim = it->second;
+ if (renderer->document() == document)
+ compAnim->resumeAnimations();
+ }
+
+ updateAnimationTimer();
+}
+
+AnimationController::AnimationController(Frame* frame)
+ : m_data(new AnimationControllerPrivate(frame))
+ , m_numStyleAvailableWaiters(0)
+{
+}
+
+AnimationController::~AnimationController()
+{
+ delete m_data;
+}
+
+void AnimationController::cancelAnimations(RenderObject* renderer)
+{
+ if (!m_data->hasAnimations())
+ return;
+
+ if (m_data->clear(renderer)) {
+ Node* node = renderer->element();
+ ASSERT(!node || (node->document() && !node->document()->inPageCache()));
+ node->setChanged(AnimationStyleChange);
+ }
+}
+
+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;
+
+ // 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->element()); // FIXME: We do not animate generated content yet.
+
+ 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 neeed 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();
+}
+
+void AnimationController::setAnimationStartTime(RenderObject* renderer, double t)
+{
+ CompositeAnimation* rendererAnimations = m_data->accessCompositeAnimation(renderer);
+ rendererAnimations->setAnimationStartTime(t);
+}
+
+void AnimationController::setTransitionStartTime(RenderObject* renderer, int property, double t)
+{
+ CompositeAnimation* rendererAnimations = m_data->accessCompositeAnimation(renderer);
+ rendererAnimations->setTransitionStartTime(property, t);
+}
+
+bool AnimationController::isAnimatingPropertyOnRenderer(RenderObject* renderer, int property, bool isRunningNow) const
+{
+ return m_data->isAnimatingPropertyOnRenderer(renderer, property, isRunningNow);
+}
+
+void AnimationController::suspendAnimations(Document* document)
+{
+ m_data->suspendAnimations(document);
+}
+
+void AnimationController::resumeAnimations(Document* document)
+{
+ m_data->resumeAnimations(document);
+}
+
+void AnimationController::startUpdateRenderingDispatcher()
+{
+ m_data->startUpdateRenderingDispatcher();
+}
+
+void AnimationController::styleAvailable()
+{
+ if (!m_numStyleAvailableWaiters)
+ return;
+
+ m_data->styleAvailable();
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/animation/AnimationController.h b/WebCore/page/animation/AnimationController.h
new file mode 100644
index 0000000..bc13a2a
--- /dev/null
+++ b/WebCore/page/animation/AnimationController.h
@@ -0,0 +1,78 @@
+/*
+ * 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 <wtf/Forward.h>
+
+namespace WebCore {
+
+class AnimationControllerPrivate;
+class Document;
+class Frame;
+class RenderObject;
+class RenderStyle;
+
+class AnimationController {
+public:
+ AnimationController(Frame*);
+ ~AnimationController();
+
+ void cancelAnimations(RenderObject*);
+ PassRefPtr<RenderStyle> updateAnimations(RenderObject*, RenderStyle* newStyle);
+
+ void setAnimationStartTime(RenderObject*, double t);
+ void setTransitionStartTime(RenderObject*, int property, double t);
+
+ bool isAnimatingPropertyOnRenderer(RenderObject*, int property, bool isRunningNow) const;
+
+ void suspendAnimations(Document*);
+ void resumeAnimations(Document*);
+ void updateAnimationTimer();
+
+ void startUpdateRenderingDispatcher();
+
+ void styleAvailable();
+
+ void setWaitingForStyleAvailable(bool waiting)
+ {
+ if (waiting)
+ m_numStyleAvailableWaiters++;
+ else
+ m_numStyleAvailableWaiters--;
+ }
+
+private:
+ AnimationControllerPrivate* m_data;
+ unsigned m_numStyleAvailableWaiters;
+};
+
+} // namespace WebCore
+
+#endif // AnimationController_h
diff --git a/WebCore/page/animation/CompositeAnimation.cpp b/WebCore/page/animation/CompositeAnimation.cpp
new file mode 100644
index 0000000..2ae68d9
--- /dev/null
+++ b/WebCore/page/animation/CompositeAnimation.cpp
@@ -0,0 +1,594 @@
+/*
+ * 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 "AnimationController.h"
+#include "CSSPropertyNames.h"
+#include "ImplicitAnimation.h"
+#include "KeyframeAnimation.h"
+#include "RenderObject.h"
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+class CompositeAnimationPrivate {
+public:
+ CompositeAnimationPrivate(AnimationController* animationController, CompositeAnimation* compositeAnimation)
+ : m_isSuspended(false)
+ , m_animationController(animationController)
+ , m_compositeAnimation(compositeAnimation)
+ , m_numStyleAvailableWaiters(0)
+ {
+ }
+
+ ~CompositeAnimationPrivate();
+
+ PassRefPtr<RenderStyle> animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
+
+ void setAnimating(bool);
+ bool isAnimating() const;
+
+ const KeyframeAnimation* getAnimationForProperty(int property) const;
+
+ void resetTransitions(RenderObject*);
+ void resetAnimations(RenderObject*);
+
+ void cleanupFinishedAnimations(RenderObject*);
+
+ void setAnimationStartTime(double t);
+ void setTransitionStartTime(int property, double t);
+
+ void suspendAnimations();
+ void resumeAnimations();
+ bool isSuspended() const { return m_isSuspended; }
+
+ void overrideImplicitAnimations(int property);
+ void resumeOverriddenImplicitAnimations(int property);
+
+ void styleAvailable();
+
+ bool isAnimatingProperty(int property, bool isRunningNow) const;
+
+ void setWaitingForStyleAvailable(bool);
+
+protected:
+ void updateTransitions(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
+ void updateKeyframeAnimations(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
+
+private:
+ typedef HashMap<int, RefPtr<ImplicitAnimation> > CSSPropertyTransitionsMap;
+ typedef HashMap<AtomicStringImpl*, RefPtr<KeyframeAnimation> > AnimationNameMap;
+
+ CSSPropertyTransitionsMap m_transitions;
+ AnimationNameMap m_keyframeAnimations;
+ bool m_isSuspended;
+ AnimationController* m_animationController;
+ CompositeAnimation* m_compositeAnimation;
+ unsigned m_numStyleAvailableWaiters;
+};
+
+CompositeAnimationPrivate::~CompositeAnimationPrivate()
+{
+ m_transitions.clear();
+ m_keyframeAnimations.clear();
+}
+
+void CompositeAnimationPrivate::updateTransitions(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
+{
+ // If currentStyle is null, we don't do transitions
+ if (!currentStyle || !targetStyle->transitions())
+ return;
+
+ // Check to see if we need to update the active 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
+ prop = AnimationBase::getPropertyAtIndex(propertyIndex);
+ }
+
+ // 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.
+ const 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) {
+ // This implAnim might 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 (!isActiveTransition)
+ m_transitions.remove(prop);
+ else if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) {
+ 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);
+ }
+
+ if (!equal) {
+ // Add the new transition
+ m_transitions.set(prop, ImplicitAnimation::create(const_cast<Animation*>(anim), prop, renderer, m_compositeAnimation, fromStyle));
+ }
+
+ // We only need one pass for the single prop case
+ if (!all)
+ break;
+ }
+ }
+}
+
+void CompositeAnimationPrivate::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;
+
+ // Nothing to do if the current and target animations are the same
+ if (currentStyle && currentStyle->hasAnimations() && targetStyle->hasAnimations() && *(currentStyle->animations()) == *(targetStyle->animations()))
+ return;
+
+ // Mark all existing animations as no longer active
+ AnimationNameMap::const_iterator kfend = m_keyframeAnimations.end();
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it)
+ it->second->setIndex(-1);
+
+ // 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) {
+ // There is one so it is still active
+
+ // Animations match, but play states may differ. update if needed
+ keyframeAnim->updatePlayState(anim->playState() == AnimPlayStatePlaying);
+
+ // 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()) {
+ keyframeAnim = KeyframeAnimation::create(const_cast<Animation*>(anim), renderer, i, m_compositeAnimation, currentStyle ? currentStyle : targetStyle);
+ m_keyframeAnimations.set(keyframeAnim->name().impl(), keyframeAnim);
+ }
+ }
+ }
+
+ // 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> CompositeAnimationPrivate::animate(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
+{
+ RefPtr<RenderStyle> resultStyle;
+
+ // Update animations first so we can see if any transitions are overridden
+ updateKeyframeAnimations(renderer, currentStyle, targetStyle);
+
+ // We don't do any transitions if we don't have a currentStyle (on startup)
+ updateTransitions(renderer, currentStyle, targetStyle);
+
+ 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.
+ 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(m_compositeAnimation, 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.
+ if (targetStyle->hasAnimations()) {
+ for (size_t i = 0; i < targetStyle->animations()->size(); ++i) {
+ const Animation* anim = targetStyle->animations()->animation(i);
+
+ if (anim->isValidAnimation()) {
+ AtomicString animationName(anim->name());
+ RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(animationName.impl());
+ if (keyframeAnim)
+ keyframeAnim->animate(m_compositeAnimation, renderer, currentStyle, targetStyle, resultStyle);
+ }
+ }
+ }
+
+ cleanupFinishedAnimations(renderer);
+
+ return resultStyle ? resultStyle.release() : targetStyle;
+}
+
+// "animating" means that something is running that requires the timer to keep firing
+void CompositeAnimationPrivate::setAnimating(bool animating)
+{
+ 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);
+ }
+
+ 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);
+ }
+}
+
+bool CompositeAnimationPrivate::isAnimating() const
+{
+ CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
+ for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
+ ImplicitAnimation* transition = it->second.get();
+ if (transition && transition->isAnimating() && transition->running())
+ return true;
+ }
+
+ 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->paused() && anim->isAnimating() && anim->active())
+ return true;
+ }
+
+ return false;
+}
+
+const KeyframeAnimation* CompositeAnimationPrivate::getAnimationForProperty(int property) const
+{
+ const KeyframeAnimation* retval = 0;
+
+ // We want to send back the last animation with the property if there are multiples.
+ // So we need to iterate through all animations
+ AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
+ const KeyframeAnimation* anim = it->second.get();
+ if (anim->hasAnimationForProperty(property))
+ retval = anim;
+ }
+
+ return retval;
+}
+
+void CompositeAnimationPrivate::resetTransitions(RenderObject* renderer)
+{
+ m_transitions.clear();
+}
+
+void CompositeAnimationPrivate::resetAnimations(RenderObject*)
+{
+ m_keyframeAnimations.clear();
+}
+
+void CompositeAnimationPrivate::cleanupFinishedAnimations(RenderObject* renderer)
+{
+ if (isSuspended())
+ return;
+
+ // Make a list of transitions to be deleted
+ Vector<int> finishedTransitions;
+ 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)
+ continue;
+ if (anim->postActive())
+ finishedTransitions.append(anim->animatingProperty());
+ }
+
+ // Delete them
+ size_t finishedTransitionCount = finishedTransitions.size();
+ for (size_t i = 0; i < finishedTransitionCount; ++i)
+ m_transitions.remove(finishedTransitions[i]);
+
+ // Make a list of animations to be deleted
+ Vector<AtomicStringImpl*> finishedAnimations;
+ 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)
+ continue;
+ if (anim->postActive())
+ finishedAnimations.append(anim->name().impl());
+ }
+
+ // Delete them
+ size_t finishedAnimationCount = finishedAnimations.size();
+ for (size_t i = 0; i < finishedAnimationCount; ++i)
+ m_keyframeAnimations.remove(finishedAnimations[i]);
+}
+
+void CompositeAnimationPrivate::setAnimationStartTime(double t)
+{
+ // Set start time on all animations waiting for it
+ AnimationNameMap::const_iterator end = m_keyframeAnimations.end();
+ for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != end; ++it) {
+ KeyframeAnimation* anim = it->second.get();
+ if (anim && anim->waitingForStartTime())
+ anim->updateStateMachine(AnimationBase::AnimationStateInputStartTimeSet, t);
+ }
+}
+
+void CompositeAnimationPrivate::setTransitionStartTime(int property, double t)
+{
+ // Set the start time for given property transition
+ 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->waitingForStartTime() && anim->animatingProperty() == property)
+ anim->updateStateMachine(AnimationBase::AnimationStateInputStartTimeSet, t);
+ }
+}
+
+void CompositeAnimationPrivate::suspendAnimations()
+{
+ if (m_isSuspended)
+ return;
+
+ m_isSuspended = true;
+
+ 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(false);
+ }
+
+ 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(false);
+ }
+}
+
+void CompositeAnimationPrivate::resumeAnimations()
+{
+ if (!m_isSuspended)
+ return;
+
+ m_isSuspended = false;
+
+ 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(true);
+ }
+
+ 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(true);
+ }
+}
+
+void CompositeAnimationPrivate::overrideImplicitAnimations(int property)
+{
+ 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(true);
+ }
+}
+
+void CompositeAnimationPrivate::resumeOverriddenImplicitAnimations(int property)
+{
+ 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);
+ }
+}
+
+static inline bool compareAnimationIndices(RefPtr<KeyframeAnimation> a, const RefPtr<KeyframeAnimation> b)
+{
+ return a->index() < b->index();
+}
+
+void CompositeAnimationPrivate::styleAvailable()
+{
+ if (m_numStyleAvailableWaiters == 0)
+ return;
+
+ // We have to go through animations in the order in which they appear in
+ // the style, because order matters for additivity.
+ Vector<RefPtr<KeyframeAnimation> > animations(m_keyframeAnimations.size());
+ copyValuesToVector(m_keyframeAnimations, animations);
+
+ if (animations.size() > 1)
+ std::stable_sort(animations.begin(), animations.end(), compareAnimationIndices);
+
+ for (size_t i = 0; i < animations.size(); ++i) {
+ KeyframeAnimation* anim = animations[i].get();
+ if (anim && anim->waitingForStyleAvailable())
+ anim->updateStateMachine(AnimationBase::AnimationStateInputStyleAvailable, -1);
+ }
+
+ 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->waitingForStyleAvailable())
+ anim->updateStateMachine(AnimationBase::AnimationStateInputStyleAvailable, -1);
+ }
+}
+
+bool CompositeAnimationPrivate::isAnimatingProperty(int property, bool isRunningNow) const
+{
+ 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, isRunningNow))
+ return true;
+ }
+
+ 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, isRunningNow))
+ return true;
+ }
+ return false;
+}
+
+void CompositeAnimationPrivate::setWaitingForStyleAvailable(bool waiting)
+{
+ if (waiting)
+ m_numStyleAvailableWaiters++;
+ else
+ m_numStyleAvailableWaiters--;
+ m_animationController->setWaitingForStyleAvailable(waiting);
+}
+
+CompositeAnimation::CompositeAnimation(AnimationController* animationController)
+ : m_data(new CompositeAnimationPrivate(animationController, this))
+{
+}
+
+CompositeAnimation::~CompositeAnimation()
+{
+ delete m_data;
+}
+
+PassRefPtr<RenderStyle> CompositeAnimation::animate(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
+{
+ return m_data->animate(renderer, currentStyle, targetStyle);
+}
+
+bool CompositeAnimation::isAnimating() const
+{
+ return m_data->isAnimating();
+}
+
+void CompositeAnimation::setWaitingForStyleAvailable(bool b)
+{
+ m_data->setWaitingForStyleAvailable(b);
+}
+
+void CompositeAnimation::resetTransitions(RenderObject* renderer)
+{
+ m_data->resetTransitions(renderer);
+}
+
+void CompositeAnimation::suspendAnimations()
+{
+ m_data->suspendAnimations();
+}
+
+void CompositeAnimation::resumeAnimations()
+{
+ m_data->resumeAnimations();
+}
+
+bool CompositeAnimation::isSuspended() const
+{
+ return m_data->isSuspended();
+}
+
+void CompositeAnimation::styleAvailable()
+{
+ m_data->styleAvailable();
+}
+
+void CompositeAnimation::setAnimating(bool b)
+{
+ m_data->setAnimating(b);
+}
+
+bool CompositeAnimation::isAnimatingProperty(int property, bool isRunningNow) const
+{
+ return m_data->isAnimatingProperty(property, isRunningNow);
+}
+
+void CompositeAnimation::setAnimationStartTime(double t)
+{
+ m_data->setAnimationStartTime(t);
+}
+
+void CompositeAnimation::setTransitionStartTime(int property, double t)
+{
+ m_data->setTransitionStartTime(property, t);
+}
+
+void CompositeAnimation::overrideImplicitAnimations(int property)
+{
+ m_data->overrideImplicitAnimations(property);
+}
+
+void CompositeAnimation::resumeOverriddenImplicitAnimations(int property)
+{
+ m_data->resumeOverriddenImplicitAnimations(property);
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/animation/CompositeAnimation.h b/WebCore/page/animation/CompositeAnimation.h
new file mode 100644
index 0000000..13f1179
--- /dev/null
+++ b/WebCore/page/animation/CompositeAnimation.h
@@ -0,0 +1,77 @@
+/*
+ * 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 "AtomicString.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class CompositeAnimationPrivate;
+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 Noncopyable {
+public:
+ CompositeAnimation(AnimationController* animationController);
+ ~CompositeAnimation();
+
+ PassRefPtr<RenderStyle> animate(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
+ bool isAnimating() const;
+
+ void setWaitingForStyleAvailable(bool);
+ void resetTransitions(RenderObject*);
+
+ void suspendAnimations();
+ void resumeAnimations();
+ bool isSuspended() const;
+
+ void styleAvailable();
+ void setAnimating(bool);
+ bool isAnimatingProperty(int property, bool isRunningNow) const;
+
+ void setAnimationStartTime(double t);
+ void setTransitionStartTime(int property, double t);
+
+ void overrideImplicitAnimations(int property);
+ void resumeOverriddenImplicitAnimations(int property);
+
+private:
+ CompositeAnimationPrivate* m_data;
+};
+
+} // namespace WebCore
+
+#endif // CompositeAnimation_h
diff --git a/WebCore/page/animation/ImplicitAnimation.cpp b/WebCore/page/animation/ImplicitAnimation.cpp
new file mode 100644
index 0000000..4d470e4
--- /dev/null
+++ b/WebCore/page/animation/ImplicitAnimation.cpp
@@ -0,0 +1,203 @@
+/*
+ * 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 "CSSPropertyNames.h"
+#include "EventNames.h"
+#include "ImplicitAnimation.h"
+#include "RenderObject.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_fromStyle(fromStyle)
+{
+ ASSERT(animatingProperty != cAnimateAll);
+}
+
+ImplicitAnimation::~ImplicitAnimation()
+{
+ // Do the cleanup here instead of in the base class so the specialized methods get called
+ if (!postActive())
+ updateStateMachine(AnimationStateInputEndAnimation, -1);
+}
+
+bool ImplicitAnimation::shouldSendEventForListener(Document::ListenerType inListenerType)
+{
+ return m_object->document()->hasListenerType(inListenerType);
+}
+
+void ImplicitAnimation::animate(CompositeAnimation* animation, RenderObject* renderer, RenderStyle* currentStyle,
+ RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
+{
+ if (paused())
+ return;
+
+ // 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);
+
+ if (blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0)))
+ setAnimating();
+}
+
+void ImplicitAnimation::onAnimationEnd(double elapsedTime)
+{
+ if (!sendTransitionEvent(eventNames().webkitTransitionEndEvent, elapsedTime)) {
+ // We didn't dispatch an event, which would call endAnimation(), so we'll just call it here.
+ endAnimation(true);
+ }
+}
+
+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;
+
+ // Keep a reference to this ImplicitAnimation so it doesn't go away in the handler
+ RefPtr<ImplicitAnimation> retainer(this);
+
+ // Call the event handler
+ element->dispatchWebKitTransitionEvent(eventType, propertyName, elapsedTime);
+
+ // Restore the original (unanimated) style
+ if (eventType == eventNames().webkitAnimationEndEvent && element->renderer())
+ setChanged(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)
+{
+ return propertiesEqual(prop, m_toStyle.get(), targetStyle);
+}
+
+void ImplicitAnimation::blendPropertyValueInStyle(int prop, RenderStyle* currentStyle)
+{
+ 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;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/animation/ImplicitAnimation.h b/WebCore/page/animation/ImplicitAnimation.h
new file mode 100644
index 0000000..7c9d50f
--- /dev/null
+++ b/WebCore/page/animation/ImplicitAnimation.h
@@ -0,0 +1,88 @@
+/*
+ * 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 void animate(CompositeAnimation*, RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle);
+ virtual void reset(RenderStyle* to);
+
+ void setOverridden(bool);
+ virtual bool overridden() const { return m_overridden; }
+
+ virtual bool shouldFireEvents() const { return true; }
+
+ virtual bool affectsProperty(int) const;
+
+ bool hasStyle() const { return m_fromStyle && m_toStyle; }
+
+ bool isTargetPropertyEqual(int, const RenderStyle* targetStyle);
+
+ void blendPropertyValueInStyle(int, RenderStyle* currentStyle);
+
+protected:
+ bool shouldSendEventForListener(Document::ListenerType);
+ 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
+
+ // The two styles that we are blending.
+ RefPtr<RenderStyle> m_fromStyle;
+ RefPtr<RenderStyle> m_toStyle;
+};
+
+} // namespace WebCore
+
+#endif // ImplicitAnimation_h
diff --git a/WebCore/page/animation/KeyframeAnimation.cpp b/WebCore/page/animation/KeyframeAnimation.cpp
new file mode 100644
index 0000000..69fdd11
--- /dev/null
+++ b/WebCore/page/animation/KeyframeAnimation.cpp
@@ -0,0 +1,293 @@
+/*
+ * 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 "CSSPropertyNames.h"
+#include "CSSStyleSelector.h"
+#include "CompositeAnimation.h"
+#include "EventNames.h"
+#include "RenderObject.h"
+#include "SystemTime.h"
+
+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_unanimatedStyle(unanimatedStyle)
+{
+ // Get the keyframe RenderStyles
+ if (m_object && m_object->element() && m_object->element()->isElementNode())
+ m_object->document()->styleSelector()->keyframeStylesForAnimation(static_cast<Element*>(m_object->element()), unanimatedStyle, m_keyframes);
+
+ // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match.
+ validateTransformFunctionList();
+}
+
+KeyframeAnimation::~KeyframeAnimation()
+{
+ // Do the cleanup here instead of in the base class so the specialized methods get called
+ if (!postActive())
+ updateStateMachine(AnimationStateInputEndAnimation, -1);
+}
+
+void KeyframeAnimation::animate(CompositeAnimation* animation, RenderObject* renderer, const RenderStyle* currentStyle,
+ const RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
+{
+ // 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 - if the delay time is 0, then we do want to set the first frame of the
+ // animation right away. This avoids a flash when the animation starts.
+ if (waitingToStart() && m_animation->delay() > 0)
+ return;
+
+ // FIXME: we need to be more efficient about determining which keyframes we are animating between.
+ // We should cache the last pair or something.
+
+ // Find the first key
+ double elapsedTime = (m_startTime > 0) ? ((!paused() ? currentTime() : m_pauseTime) - m_startTime) : 0;
+ if (elapsedTime < 0)
+ elapsedTime = 0;
+
+ double t = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1;
+ int i = static_cast<int>(t);
+ t -= i;
+ if (m_animation->direction() && (i & 1))
+ t = 1 - t;
+
+ const RenderStyle* fromStyle = 0;
+ const RenderStyle* toStyle = 0;
+ double scale = 1;
+ double offset = 0;
+ Vector<KeyframeValue>::const_iterator endKeyframes = m_keyframes.endKeyframes();
+ for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != endKeyframes; ++it) {
+ if (t < it->key()) {
+ // The first key should always be 0, so we should never succeed on the first key
+ if (!fromStyle)
+ break;
+ scale = 1.0 / (it->key() - offset);
+ toStyle = it->style();
+ break;
+ }
+
+ offset = it->key();
+ fromStyle = it->style();
+ }
+
+ // If either style is 0 we have an invalid case, just stop the animation.
+ if (!fromStyle || !toStyle) {
+ 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);
+
+ const TimingFunction* timingFunction = 0;
+ if (fromStyle->animations() && fromStyle->animations()->size() > 0)
+ timingFunction = &(fromStyle->animations()->animation(0)->timingFunction());
+
+ double prog = progress(scale, offset, timingFunction);
+
+ HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
+ for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
+ if (blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, prog))
+ setAnimating();
+ }
+}
+
+bool KeyframeAnimation::hasAnimationForProperty(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::endAnimation(bool)
+{
+ // Restore the original (unanimated) style
+ if (m_object)
+ setChanged(m_object->element());
+}
+
+bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType)
+{
+ 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)
+{
+ if (!sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime)) {
+ // We didn't dispatch an event, which would call endAnimation(), so we'll just call it here.
+ endAnimation(true);
+ }
+}
+
+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);
+ 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;
+
+ // Keep a reference to this ImplicitAnimation so it doesn't go away in the handler
+ RefPtr<KeyframeAnimation> retainer(this);
+
+ // Call the event handler
+ element->dispatchWebKitAnimationEvent(eventType, m_keyframes.animationName(), elapsedTime);
+
+ // Restore the original (unanimated) style
+ if (eventType == eventNames().webkitAnimationEndEvent && element->renderer())
+ setChanged(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;
+
+ Vector<KeyframeValue>::const_iterator end = m_keyframes.endKeyframes();
+
+ // Empty transforms match anything, so find the first non-empty entry as the reference
+ size_t firstIndex = 0;
+ Vector<KeyframeValue>::const_iterator firstIt = end;
+
+ for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != end; ++it, ++firstIndex) {
+ if (it->style()->transform().operations().size() > 0) {
+ firstIt = it;
+ break;
+ }
+ }
+
+ if (firstIt == end)
+ return;
+
+ const TransformOperations* firstVal = &firstIt->style()->transform();
+
+ // See if the keyframes are valid
+ for (Vector<KeyframeValue>::const_iterator it = firstIt+1; it != end; ++it) {
+ const TransformOperations* val = &it->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;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/animation/KeyframeAnimation.h b/WebCore/page/animation/KeyframeAnimation.h
new file mode 100644
index 0000000..55b429a
--- /dev/null
+++ b/WebCore/page/animation/KeyframeAnimation.h
@@ -0,0 +1,92 @@
+/*
+ * 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"
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+// 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, const RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle);
+
+ const AtomicString& name() const { return m_keyframes.animationName(); }
+ int index() const { return m_index; }
+ void setIndex(int i) { m_index = i; }
+
+ virtual bool shouldFireEvents() const { return true; }
+
+ bool hasAnimationForProperty(int property) const;
+
+ RenderStyle* unanimatedStyle() const { return m_unanimatedStyle.get(); }
+
+protected:
+ virtual void onAnimationStart(double elapsedTime);
+ virtual void onAnimationIteration(double elapsedTime);
+ virtual void onAnimationEnd(double elapsedTime);
+ virtual void endAnimation(bool reset);
+
+ virtual void overrideAnimations();
+ virtual void resumeOverriddenAnimations();
+
+ bool shouldSendEventForListener(Document::ListenerType inListenerType);
+ 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();
+
+ // The keyframes that we are blending.
+ KeyframeList m_keyframes;
+
+ // The order in which this animation appears in the animation-name style.
+ int m_index;
+
+ // The style just before we started animation
+ RefPtr<RenderStyle> m_unanimatedStyle;
+};
+
+} // namespace WebCore
+
+#endif // KeyframeAnimation_h
diff --git a/WebCore/page/gtk/AXObjectCacheAtk.cpp b/WebCore/page/gtk/AXObjectCacheAtk.cpp
new file mode 100644
index 0000000..3535cf1
--- /dev/null
+++ b/WebCore/page/gtk/AXObjectCacheAtk.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ *
+ * 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 "AXObjectCache.h"
+
+#include "AccessibilityObject.h"
+#include "AccessibilityObjectWrapperAtk.h"
+
+namespace WebCore {
+
+void AXObjectCache::detachWrapper(AccessibilityObject* obj)
+{
+ webkit_accessible_detach(WEBKIT_ACCESSIBLE(obj->wrapper()));
+}
+
+void AXObjectCache::attachWrapper(AccessibilityObject* obj)
+{
+ AtkObject* atkObj = ATK_OBJECT(webkit_accessible_new(obj));
+ obj->setWrapper(atkObj);
+ g_object_unref(atkObj);
+}
+
+void AXObjectCache::postNotification(RenderObject*, const String&)
+{
+}
+
+void AXObjectCache::postNotificationToElement(RenderObject*, const String&)
+{
+}
+
+void AXObjectCache::handleFocusedUIElementChanged()
+{
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/gtk/AccessibilityObjectAtk.cpp b/WebCore/page/gtk/AccessibilityObjectAtk.cpp
new file mode 100644
index 0000000..b755645
--- /dev/null
+++ b/WebCore/page/gtk/AccessibilityObjectAtk.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 Apple Ltd.
+ *
+ * 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 "AccessibilityObject.h"
+
+namespace WebCore {
+
+bool AccessibilityObject::accessibilityIgnoreAttachment() const
+{
+ return false;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/gtk/AccessibilityObjectWrapperAtk.cpp b/WebCore/page/gtk/AccessibilityObjectWrapperAtk.cpp
new file mode 100644
index 0000000..b46fb60
--- /dev/null
+++ b/WebCore/page/gtk/AccessibilityObjectWrapperAtk.cpp
@@ -0,0 +1,676 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ *
+ * 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 "AccessibilityObjectWrapperAtk.h"
+
+#include "AXObjectCache.h"
+#include "AccessibilityListBox.h"
+#include "AccessibilityRenderObject.h"
+#include "AtomicString.h"
+#include "CString.h"
+#include "Document.h"
+#include "Editor.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+
+#include <atk/atk.h>
+
+using namespace WebCore;
+
+// Used to provide const char* returns.
+static const char* returnString(const String& str)
+{
+ static CString returnedString;
+ returnedString = str.utf8();
+ return returnedString.data();
+}
+
+static AccessibilityObject* core(WebKitAccessible* accessible)
+{
+ if (!accessible)
+ return 0;
+
+ return accessible->m_object;
+}
+
+static AccessibilityObject* core(AtkObject* object)
+{
+ if (!WEBKIT_IS_ACCESSIBLE(object))
+ return 0;
+
+ return core(WEBKIT_ACCESSIBLE(object));
+}
+
+static AccessibilityObject* core(AtkAction* action)
+{
+ return core(ATK_OBJECT(action));
+}
+
+static AccessibilityObject* core(AtkStreamableContent* streamable)
+{
+ return core(ATK_OBJECT(streamable));
+}
+
+static AccessibilityObject* core(AtkText* text)
+{
+ return core(ATK_OBJECT(text));
+}
+
+static AccessibilityObject* core(AtkEditableText* text)
+{
+ return core(ATK_OBJECT(text));
+}
+
+extern "C" {
+
+static gpointer parent_class = NULL;
+
+static void webkit_accessible_init(AtkObject* object, gpointer data)
+{
+ g_return_if_fail(WEBKIT_IS_ACCESSIBLE(object));
+ g_return_if_fail(data);
+
+ if (ATK_OBJECT_CLASS(parent_class)->initialize)
+ ATK_OBJECT_CLASS(parent_class)->initialize(object, data);
+
+ WEBKIT_ACCESSIBLE(object)->m_object = reinterpret_cast<AccessibilityObject*>(data);
+}
+
+static void webkit_accessible_finalize(GObject* object)
+{
+ // This is a good time to clear the return buffer.
+ returnString(String());
+
+ if (G_OBJECT_CLASS(parent_class)->finalize)
+ G_OBJECT_CLASS(parent_class)->finalize(object);
+}
+
+static const gchar* webkit_accessible_get_name(AtkObject* object)
+{
+ // TODO: Deal with later changes.
+ if (!object->name)
+ atk_object_set_name(object, core(object)->title().utf8().data());
+ return object->name;
+}
+
+static const gchar* webkit_accessible_get_description(AtkObject* object)
+{
+ // TODO: the Mozilla MSAA implementation prepends "Description: "
+ // Should we do this too?
+
+ // TODO: Deal with later changes.
+ if (!object->description)
+ atk_object_set_description(object, core(object)->accessibilityDescription().utf8().data());
+ return object->description;
+}
+
+static AtkObject* webkit_accessible_get_parent(AtkObject* object)
+{
+ AccessibilityObject* coreParent = core(object)->parentObject();
+
+ if (!coreParent)
+ return NULL;
+
+ return coreParent->wrapper();
+}
+
+static gint webkit_accessible_get_n_children(AtkObject* object)
+{
+ return core(object)->children().size();
+}
+
+static AtkObject* webkit_accessible_ref_child(AtkObject* object, gint index)
+{
+ AccessibilityObject* coreObject = core(object);
+
+ g_return_val_if_fail(index >= 0, NULL);
+ g_return_val_if_fail(static_cast<size_t>(index) < coreObject->children().size(), NULL);
+
+ AccessibilityObject* coreChild = coreObject->children().at(index).get();
+
+ if (!coreChild)
+ return NULL;
+
+ AtkObject* child = coreChild->wrapper();
+ // TODO: Should we call atk_object_set_parent() here?
+ //atk_object_set_parent(child, object);
+ g_object_ref(child);
+
+ return child;
+}
+
+static gint webkit_accessible_get_index_in_parent(AtkObject* object)
+{
+ // FIXME: This needs to be implemented.
+ notImplemented();
+ return 0;
+}
+
+static AtkRole atkRole(AccessibilityRole role)
+{
+ switch (role) {
+ case WebCore::ButtonRole:
+ return ATK_ROLE_PUSH_BUTTON;
+ case WebCore::RadioButtonRole:
+ return ATK_ROLE_RADIO_BUTTON;
+ case WebCore::CheckBoxRole:
+ return ATK_ROLE_CHECK_BOX;
+ case WebCore::SliderRole:
+ return ATK_ROLE_SLIDER;
+ case WebCore::TabGroupRole:
+ return ATK_ROLE_PAGE_TAB_LIST;
+ case WebCore::TextFieldRole:
+ case WebCore::TextAreaRole:
+ case WebCore::ListMarkerRole:
+ return ATK_ROLE_ENTRY;
+ case WebCore::StaticTextRole:
+ return ATK_ROLE_TEXT; //?
+ case WebCore::OutlineRole:
+ return ATK_ROLE_TREE;
+ case WebCore::ColumnRole:
+ return ATK_ROLE_UNKNOWN; //?
+ case WebCore::RowRole:
+ return ATK_ROLE_LIST_ITEM;
+ case WebCore::GroupRole:
+ return ATK_ROLE_UNKNOWN; //?
+ case WebCore::ListRole:
+ return ATK_ROLE_LIST;
+ case WebCore::TableRole:
+ return ATK_ROLE_TABLE;
+ case WebCore::LinkRole:
+ case WebCore::WebCoreLinkRole:
+ return ATK_ROLE_LINK;
+ case WebCore::ImageMapRole:
+ case WebCore::ImageRole:
+ return ATK_ROLE_IMAGE;
+ default:
+ return ATK_ROLE_UNKNOWN;
+ }
+}
+
+static AtkRole webkit_accessible_get_role(AtkObject* object)
+{
+ return atkRole(core(object)->roleValue());
+}
+
+static void webkit_accessible_class_init(AtkObjectClass* klass)
+{
+ GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
+
+ parent_class = g_type_class_peek_parent(klass);
+
+ klass->initialize = webkit_accessible_init;
+
+ gobject_class->finalize = webkit_accessible_finalize;
+
+ klass->get_name = webkit_accessible_get_name;
+ klass->get_description = webkit_accessible_get_description;
+ klass->get_parent = webkit_accessible_get_parent;
+ klass->get_n_children = webkit_accessible_get_n_children;
+ klass->ref_child = webkit_accessible_ref_child;
+ //klass->get_index_in_parent = webkit_accessible_get_index_in_parent;
+ klass->get_role = webkit_accessible_get_role;
+ //klass->get_attributes = webkit_accessible_get_attributes;
+ //klass->ref_state_set = webkit_accessible_ref_state_set;
+ //klass->ref_relation_set = webkit_accessible_ref_relation_set;
+}
+
+static gboolean webkit_accessible_action_do_action(AtkAction* action, gint i)
+{
+ g_return_val_if_fail(i == 0, FALSE);
+ return core(action)->performDefaultAction();
+}
+
+static gint webkit_accessible_action_get_n_actions(AtkAction* action)
+{
+ return 1;
+}
+
+static const gchar* webkit_accessible_action_get_description(AtkAction* action, gint i)
+{
+ g_return_val_if_fail(i == 0, NULL);
+ // TODO: Need a way to provide/localize action descriptions.
+ notImplemented();
+ return "";
+}
+
+static const gchar* webkit_accessible_action_get_keybinding(AtkAction* action, gint i)
+{
+ g_return_val_if_fail(i == 0, NULL);
+ // FIXME: Construct a proper keybinding string.
+ return returnString(core(action)->accessKey().string());
+}
+
+static const gchar* webkit_accessible_action_get_name(AtkAction* action, gint i)
+{
+ g_return_val_if_fail(i == 0, NULL);
+ return returnString(core(action)->actionVerb());
+}
+
+static void atk_action_interface_init(AtkActionIface* iface)
+{
+ g_return_if_fail(iface);
+
+ iface->do_action = webkit_accessible_action_do_action;
+ iface->get_n_actions = webkit_accessible_action_get_n_actions;
+ iface->get_description = webkit_accessible_action_get_description;
+ iface->get_keybinding = webkit_accessible_action_get_keybinding;
+ iface->get_name = webkit_accessible_action_get_name;
+}
+
+// Text
+
+static gchar* webkit_accessible_text_get_text(AtkText* text, gint start_offset, gint end_offset)
+{
+ String ret = core(text)->doAXStringForRange(PlainTextRange(start_offset, end_offset - start_offset));
+ // TODO: Intentionally copied?
+ return g_strdup(ret.utf8().data());
+}
+
+static gchar* webkit_accessible_text_get_text_after_offset(AtkText* text, gint offset, AtkTextBoundary boundary_type, gint* start_offset, gint* end_offset)
+{
+ notImplemented();
+ return NULL;
+}
+
+static gchar* webkit_accessible_text_get_text_at_offset(AtkText* text, gint offset, AtkTextBoundary boundary_type, gint* start_offset, gint* end_offset)
+{
+ notImplemented();
+ return NULL;
+}
+
+static gunichar webkit_accessible_text_get_character_at_offset(AtkText* text, gint offset)
+{
+ notImplemented();
+ return 0;
+}
+
+static gchar* webkit_accessible_text_get_text_before_offset(AtkText* text, gint offset, AtkTextBoundary boundary_type, gint* start_offset, gint* end_offset)
+{
+ notImplemented();
+ return NULL;
+}
+
+static gint webkit_accessible_text_get_caret_offset(AtkText* text)
+{
+ // TODO: Verify this, especially for RTL text.
+ return core(text)->selectionStart();
+}
+
+static AtkAttributeSet* webkit_accessible_text_get_run_attributes(AtkText* text, gint offset, gint* start_offset, gint* end_offset)
+{
+ notImplemented();
+ return NULL;
+}
+
+static AtkAttributeSet* webkit_accessible_text_get_default_attributes(AtkText* text)
+{
+ notImplemented();
+ return NULL;
+}
+
+static void webkit_accessible_text_get_character_extents(AtkText* text, gint offset, gint* x, gint* y, gint* width, gint* height, AtkCoordType coords)
+{
+ IntRect extents = core(text)->doAXBoundsForRange(PlainTextRange(offset, 1));
+ // FIXME: Use the AtkCoordType
+ // Requires WebCore::ScrollView::contentsToScreen() to be implemented
+
+#if 0
+ switch(coords) {
+ case ATK_XY_SCREEN:
+ extents = core(text)->document()->view()->contentsToScreen(extents);
+ break;
+ case ATK_XY_WINDOW:
+ // No-op
+ break;
+ }
+#endif
+
+ *x = extents.x();
+ *y = extents.y();
+ *width = extents.width();
+ *height = extents.height();
+}
+
+static gint webkit_accessible_text_get_character_count(AtkText* text)
+{
+ return core(text)->textLength();
+}
+
+static gint webkit_accessible_text_get_offset_at_point(AtkText* text, gint x, gint y, AtkCoordType coords)
+{
+ // FIXME: Use the AtkCoordType
+ // TODO: Is it correct to ignore range.length?
+ IntPoint pos(x, y);
+ PlainTextRange range = core(text)->doAXRangeForPosition(pos);
+ return range.start;
+}
+
+static gint webkit_accessible_text_get_n_selections(AtkText* text)
+{
+ notImplemented();
+ return 0;
+}
+
+static gchar* webkit_accessible_text_get_selection(AtkText* text, gint selection_num, gint* start_offset, gint* end_offset)
+{
+ notImplemented();
+ return NULL;
+}
+
+static gboolean webkit_accessible_text_add_selection(AtkText* text, gint start_offset, gint end_offset)
+{
+ notImplemented();
+ return FALSE;
+}
+
+static gboolean webkit_accessible_text_remove_selection(AtkText* text, gint selection_num)
+{
+ notImplemented();
+ return FALSE;
+}
+
+static gboolean webkit_accessible_text_set_selection(AtkText* text, gint selection_num, gint start_offset, gint end_offset)
+{
+ notImplemented();
+ return FALSE;
+}
+
+static gboolean webkit_accessible_text_set_caret_offset(AtkText* text, gint offset)
+{
+ // TODO: Verify
+ //core(text)->setSelectedTextRange(PlainTextRange(offset, 0));
+ AccessibilityObject* coreObject = core(text);
+ coreObject->setSelectedVisiblePositionRange(coreObject->visiblePositionRangeForRange(PlainTextRange(offset, 0)));
+ return TRUE;
+}
+
+#if 0
+// Signal handlers
+static void webkit_accessible_text_text_changed(AtkText* text, gint position, gint length)
+{
+}
+
+static void webkit_accessible_text_text_caret_moved(AtkText* text, gint location)
+{
+}
+
+static void webkit_accessible_text_text_selection_changed(AtkText* text)
+{
+}
+
+static void webkit_accessible_text_text_attributes_changed(AtkText* text)
+{
+}
+
+static void webkit_accessible_text_get_range_extents(AtkText* text, gint start_offset, gint end_offset, AtkCoordType coord_type, AtkTextRectangle* rect)
+{
+}
+
+static AtkTextRange** webkit_accessible_text_get_bounded_ranges(AtkText* text, AtkTextRectangle* rect, AtkCoordType coord_type, AtkTextClipType x_clip_type, AtkTextClipType y_clip_type)
+{
+}
+#endif
+
+static void atk_text_interface_init(AtkTextIface* iface)
+{
+ g_return_if_fail(iface);
+
+ iface->get_text = webkit_accessible_text_get_text;
+ iface->get_text_after_offset = webkit_accessible_text_get_text_after_offset;
+ iface->get_text_at_offset = webkit_accessible_text_get_text_at_offset;
+ iface->get_character_at_offset = webkit_accessible_text_get_character_at_offset;
+ iface->get_text_before_offset = webkit_accessible_text_get_text_before_offset;
+ iface->get_caret_offset = webkit_accessible_text_get_caret_offset;
+ iface->get_run_attributes = webkit_accessible_text_get_run_attributes;
+ iface->get_default_attributes = webkit_accessible_text_get_default_attributes;
+ iface->get_character_extents = webkit_accessible_text_get_character_extents;
+ //iface->get_range_extents = ;
+ iface->get_character_count = webkit_accessible_text_get_character_count;
+ iface->get_offset_at_point = webkit_accessible_text_get_offset_at_point;
+ iface->get_n_selections = webkit_accessible_text_get_n_selections;
+ iface->get_selection = webkit_accessible_text_get_selection;
+
+ // set methods
+ iface->add_selection = webkit_accessible_text_add_selection;
+ iface->remove_selection = webkit_accessible_text_remove_selection;
+ iface->set_selection = webkit_accessible_text_set_selection;
+ iface->set_caret_offset = webkit_accessible_text_set_caret_offset;
+}
+
+// EditableText
+
+static gboolean webkit_accessible_editable_text_set_run_attributes(AtkEditableText* text, AtkAttributeSet* attrib_set, gint start_offset, gint end_offset)
+{
+ notImplemented();
+ return FALSE;
+}
+
+static void webkit_accessible_editable_text_set_text_contents(AtkEditableText* text, const gchar* string)
+{
+ // FIXME: string nullcheck?
+ core(text)->setValue(String::fromUTF8(string));
+}
+
+static void webkit_accessible_editable_text_insert_text(AtkEditableText* text, const gchar* string, gint length, gint* position)
+{
+ // FIXME: string nullcheck?
+
+ AccessibilityObject* coreObject = core(text);
+ // FIXME: Not implemented in WebCore
+ //coreObject->setSelectedTextRange(PlainTextRange(*position, 0));
+ //coreObject->setSelectedText(String::fromUTF8(string));
+
+ if (!coreObject->document() || !coreObject->document()->frame())
+ return;
+ coreObject->setSelectedVisiblePositionRange(coreObject->visiblePositionRangeForRange(PlainTextRange(*position, 0)));
+ coreObject->setFocused(true);
+ // FIXME: We should set position to the actual inserted text length, which may be less than that requested.
+ if (coreObject->document()->frame()->editor()->insertTextWithoutSendingTextEvent(String::fromUTF8(string), false, 0))
+ *position += length;
+}
+
+static void webkit_accessible_editable_text_copy_text(AtkEditableText* text, gint start_pos, gint end_pos)
+{
+ notImplemented();
+}
+
+static void webkit_accessible_editable_text_cut_text(AtkEditableText* text, gint start_pos, gint end_pos)
+{
+ notImplemented();
+}
+
+static void webkit_accessible_editable_text_delete_text(AtkEditableText* text, gint start_pos, gint end_pos)
+{
+ AccessibilityObject* coreObject = core(text);
+ // FIXME: Not implemented in WebCore
+ //coreObject->setSelectedTextRange(PlainTextRange(start_pos, end_pos - start_pos));
+ //coreObject->setSelectedText(String());
+
+ if (!coreObject->document() || !coreObject->document()->frame())
+ return;
+ coreObject->setSelectedVisiblePositionRange(coreObject->visiblePositionRangeForRange(PlainTextRange(start_pos, end_pos - start_pos)));
+ coreObject->setFocused(true);
+ coreObject->document()->frame()->editor()->performDelete();
+}
+
+static void webkit_accessible_editable_text_paste_text(AtkEditableText* text, gint position)
+{
+ notImplemented();
+}
+
+static void atk_editable_text_interface_init(AtkEditableTextIface* iface)
+{
+ g_return_if_fail(iface);
+
+ iface->set_run_attributes = webkit_accessible_editable_text_set_run_attributes;
+ iface->set_text_contents = webkit_accessible_editable_text_set_text_contents;
+ iface->insert_text = webkit_accessible_editable_text_insert_text;
+ iface->copy_text = webkit_accessible_editable_text_copy_text;
+ iface->cut_text = webkit_accessible_editable_text_cut_text;
+ iface->delete_text = webkit_accessible_editable_text_delete_text;
+ iface->paste_text = webkit_accessible_editable_text_paste_text;
+}
+
+// StreamableContent
+
+static gint webkit_accessible_streamable_content_get_n_mime_types(AtkStreamableContent* streamable)
+{
+ notImplemented();
+ return 0;
+}
+
+static G_CONST_RETURN gchar* webkit_accessible_streamable_content_get_mime_type(AtkStreamableContent* streamable, gint i)
+{
+ notImplemented();
+ return "";
+}
+
+static GIOChannel* webkit_accessible_streamable_content_get_stream(AtkStreamableContent* streamable, const gchar* mime_type)
+{
+ notImplemented();
+ return NULL;
+}
+
+static G_CONST_RETURN gchar* webkit_accessible_streamable_content_get_uri(AtkStreamableContent* streamable, const gchar* mime_type)
+{
+ notImplemented();
+ return NULL;
+}
+
+static void atk_streamable_content_interface_init(AtkStreamableContentIface* iface)
+{
+ g_return_if_fail(iface);
+
+ iface->get_n_mime_types = webkit_accessible_streamable_content_get_n_mime_types;
+ iface->get_mime_type = webkit_accessible_streamable_content_get_mime_type;
+ iface->get_stream = webkit_accessible_streamable_content_get_stream;
+ iface->get_uri = webkit_accessible_streamable_content_get_uri;
+}
+
+GType webkit_accessible_get_type()
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo tinfo = {
+ sizeof(WebKitAccessibleClass),
+ (GBaseInitFunc)NULL,
+ (GBaseFinalizeFunc)NULL,
+ (GClassInitFunc)webkit_accessible_class_init,
+ (GClassFinalizeFunc)NULL,
+ NULL, /* class data */
+ sizeof(WebKitAccessible), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc)NULL,
+ NULL /* value table */
+ };
+
+ type = g_type_register_static(ATK_TYPE_OBJECT, "WebKitAccessible", &tinfo, static_cast<GTypeFlags>(0));
+
+ // TODO: Only implement interfaces when necessary, not for all objects.
+ static const GInterfaceInfo atk_action_info =
+ {
+ (GInterfaceInitFunc) atk_action_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+ g_type_add_interface_static(type, ATK_TYPE_ACTION, &atk_action_info);
+
+ static const GInterfaceInfo atk_text_info =
+ {
+ (GInterfaceInitFunc) atk_text_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+ g_type_add_interface_static(type, ATK_TYPE_TEXT, &atk_text_info);
+
+ static const GInterfaceInfo atk_editable_text_info =
+ {
+ (GInterfaceInitFunc) atk_editable_text_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+ g_type_add_interface_static(type, ATK_TYPE_EDITABLE_TEXT, &atk_editable_text_info);
+
+ static const GInterfaceInfo atk_streamable_content_info =
+ {
+ (GInterfaceInitFunc) atk_streamable_content_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+ g_type_add_interface_static(type, ATK_TYPE_STREAMABLE_CONTENT, &atk_streamable_content_info);
+ }
+ return type;
+}
+
+WebKitAccessible* webkit_accessible_new(AccessibilityObject* coreObject)
+{
+ GType type = WEBKIT_TYPE_ACCESSIBLE;
+ AtkObject* object = static_cast<AtkObject*>(g_object_new(type, NULL));
+ atk_object_initialize(object, coreObject);
+ return WEBKIT_ACCESSIBLE(object);
+}
+
+AccessibilityObject* webkit_accessible_get_accessibility_object(WebKitAccessible* accessible)
+{
+ return accessible->m_object;
+}
+
+// FIXME: Remove this static initialization.
+static AXObjectCache* fallbackCache = new AXObjectCache();
+
+void webkit_accessible_detach(WebKitAccessible* accessible)
+{
+ ASSERT(accessible->m_object);
+
+ // We replace the WebCore AccessibilityObject with a fallback object that
+ // provides default implementations to avoid repetitive null-checking after
+ // detachment.
+
+ // FIXME: Using fallbackCache->get(ListBoxOptionRole) is a hack.
+ accessible->m_object = fallbackCache->get(ListBoxOptionRole);
+}
+
+}
+
+namespace WebCore {
+
+// AccessibilityObject implementations
+
+AccessibilityObjectWrapper* AccessibilityObject::wrapper() const
+{
+ return m_wrapper;
+}
+
+void AccessibilityObject::setWrapper(AccessibilityObjectWrapper* wrapper)
+{
+ if (m_wrapper)
+ g_object_unref(m_wrapper);
+
+ m_wrapper = wrapper;
+
+ if (m_wrapper)
+ g_object_ref(m_wrapper);
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/gtk/AccessibilityObjectWrapperAtk.h b/WebCore/page/gtk/AccessibilityObjectWrapperAtk.h
new file mode 100644
index 0000000..ecfb99e
--- /dev/null
+++ b/WebCore/page/gtk/AccessibilityObjectWrapperAtk.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ *
+ * 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 AccessibilityObjectWrapperAtk_h
+#define AccessibilityObjectWrapperAtk_h
+
+#include <atk/atk.h>
+
+namespace WebCore {
+ class AccessibilityObject;
+}
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_ACCESSIBLE (webkit_accessible_get_type ())
+#define WEBKIT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), WEBKIT_TYPE_ACCESSIBLE, WebKitAccessible))
+#define WEBKIT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_ACCESSIBLE, WebKitAccessibleClass))
+#define WEBKIT_IS_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), WEBKIT_TYPE_ACCESSIBLE))
+#define WEBKIT_IS_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), WEBKIT_TYPE_ACCESSIBLE))
+#define WEBKIT_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), WEBKIT_TYPE_ACCESSIBLE, WebKitAccessibleClass))
+
+typedef struct _WebKitAccessible WebKitAccessible;
+typedef struct _WebKitAccessibleClass WebKitAccessibleClass;
+
+struct _WebKitAccessible
+{
+ AtkObject parent;
+ WebCore::AccessibilityObject* m_object;
+};
+
+struct _WebKitAccessibleClass
+{
+ AtkObjectClass parent_class;
+};
+
+GType webkit_accessible_get_type (void) G_GNUC_CONST;
+
+WebKitAccessible* webkit_accessible_new (WebCore::AccessibilityObject* core_object);
+
+WebCore::AccessibilityObject* webkit_accessible_get_accessibility_object (WebKitAccessible* accessible);
+
+void webkit_accessible_detach (WebKitAccessible* accessible);
+
+G_END_DECLS
+
+#endif // AccessibilityObjectWrapperAtk_h
diff --git a/WebCore/page/gtk/DragControllerGtk.cpp b/WebCore/page/gtk/DragControllerGtk.cpp
new file mode 100644
index 0000000..62f4421
--- /dev/null
+++ b/WebCore/page/gtk/DragControllerGtk.cpp
@@ -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.
+ */
+
+#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(400, 400);
+
+ return maxDragImageSize;
+}
+
+}
diff --git a/WebCore/page/gtk/EventHandlerGtk.cpp b/WebCore/page/gtk/EventHandlerGtk.cpp
new file mode 100644
index 0000000..bb650b4
--- /dev/null
+++ b/WebCore/page/gtk/EventHandlerGtk.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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 {
+
+unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::AltKey;
+
+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(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
+{
+ //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, true);
+}
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMousePressEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
+{
+ subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
+ return true;
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
+ return true;
+}
+
+}
diff --git a/WebCore/page/gtk/FrameGtk.cpp b/WebCore/page/gtk/FrameGtk.cpp
new file mode 100644
index 0000000..3cab5a0
--- /dev/null
+++ b/WebCore/page/gtk/FrameGtk.cpp
@@ -0,0 +1,37 @@
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Frame.h"
+
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+DragImageRef Frame::dragImageForSelection()
+{
+ notImplemented();
+ return 0;
+}
+
+}
diff --git a/WebCore/page/mac/AXObjectCacheMac.mm b/WebCore/page/mac/AXObjectCacheMac.mm
new file mode 100644
index 0000000..10ae1cc
--- /dev/null
+++ b/WebCore/page/mac/AXObjectCacheMac.mm
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 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.
+ */
+
+#import "config.h"
+#import "AXObjectCache.h"
+
+#import "AccessibilityObject.h"
+#import "AccessibilityObjectWrapper.h"
+#import "RenderObject.h"
+#import "WebCoreViewFactory.h"
+
+#import <wtf/PassRefPtr.h>
+
+// The simple Cocoa calls in this file don't throw exceptions.
+
+namespace WebCore {
+
+void AXObjectCache::detachWrapper(AccessibilityObject* obj)
+{
+ [obj->wrapper() detach];
+ [obj->wrapper() release];
+ obj->setWrapper(0);
+}
+
+void AXObjectCache::attachWrapper(AccessibilityObject* obj)
+{
+ obj->setWrapper([[AccessibilityObjectWrapper alloc] initWithAccessibilityObject:obj]);
+}
+
+void AXObjectCache::postNotification(RenderObject* renderer, const String& message)
+{
+ if (!renderer)
+ return;
+
+ // notifications for text input objects are sent to that object
+ // all others are sent to the top WebArea
+ RefPtr<AccessibilityObject> obj = get(renderer)->observableObject();
+ if (!obj)
+ obj = get(renderer->document()->renderer());
+
+ if (!obj)
+ return;
+
+ NSAccessibilityPostNotification(obj->wrapper(), message);
+}
+
+void AXObjectCache::postNotificationToElement(RenderObject* renderer, const String& message)
+{
+ // send the notification to the specified element itself, not one of its ancestors
+ if (!renderer)
+ return;
+
+ RefPtr<AccessibilityObject> obj = get(renderer);
+ if (!obj)
+ return;
+
+ NSAccessibilityPostNotification(obj->wrapper(), message);
+}
+
+void AXObjectCache::handleFocusedUIElementChanged()
+{
+ [[WebCoreViewFactory sharedFactory] accessibilityHandleFocusChanged];
+}
+
+}
diff --git a/WebCore/page/mac/AccessibilityObjectMac.mm b/WebCore/page/mac/AccessibilityObjectMac.mm
new file mode 100644
index 0000000..872e108
--- /dev/null
+++ b/WebCore/page/mac/AccessibilityObjectMac.mm
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#import "config.h"
+#import "AccessibilityObject.h"
+
+#import "AccessibilityObjectWrapper.h"
+
+namespace WebCore {
+
+bool AccessibilityObject::accessibilityIgnoreAttachment() const
+{
+ return [[wrapper() attachmentView] accessibilityIsIgnored];
+}
+
+} // WebCore
diff --git a/WebCore/page/mac/AccessibilityObjectWrapper.h b/WebCore/page/mac/AccessibilityObjectWrapper.h
new file mode 100644
index 0000000..5a55fe0
--- /dev/null
+++ b/WebCore/page/mac/AccessibilityObjectWrapper.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#import <wtf/RefPtr.h>
+
+#ifdef __OBJC__
+@class WebCoreTextMarker;
+@class WebCoreTextMarkerRange;
+#else
+class WebCoreTextMarker;
+class WebCoreTextMarkerRange;
+#endif
+
+namespace WebCore {
+ class AccessibilityObject;
+ class VisiblePosition;
+}
+
+@interface AccessibilityObjectWrapper : NSObject
+{
+ WebCore::AccessibilityObject* m_object;
+}
+
+- (id)initWithAccessibilityObject:(WebCore::AccessibilityObject*)axObject;
+- (void)detach;
+- (WebCore::AccessibilityObject*)accessibilityObject;
+
+- (NSView*)attachmentView;
+
+@end
diff --git a/WebCore/page/mac/AccessibilityObjectWrapper.mm b/WebCore/page/mac/AccessibilityObjectWrapper.mm
new file mode 100644
index 0000000..2104ca9
--- /dev/null
+++ b/WebCore/page/mac/AccessibilityObjectWrapper.mm
@@ -0,0 +1,1996 @@
+/*
+ * 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.
+ */
+
+#import "config.h"
+#import "AccessibilityObjectWrapper.h"
+
+#import "AXObjectCache.h"
+#import "AccessibilityListBox.h"
+#import "AccessibilityList.h"
+#import "AccessibilityRenderObject.h"
+#import "AccessibilityTable.h"
+#import "AccessibilityTableCell.h"
+#import "AccessibilityTableRow.h"
+#import "AccessibilityTableColumn.h"
+#import "ColorMac.h"
+#import "Frame.h"
+#import "HTMLAnchorElement.h"
+#import "HTMLAreaElement.h"
+#import "HTMLImageElement.h"
+#import "HTMLInputElement.h"
+#import "HTMLTextAreaElement.h"
+#import "LocalizedStrings.h"
+#import "RenderTextControl.h"
+#import "RenderView.h"
+#import "RenderWidget.h"
+#import "SelectionController.h"
+#import "SimpleFontData.h"
+#import "TextIterator.h"
+#import "WebCoreFrameView.h"
+#import "WebCoreObjCExtras.h"
+#import "WebCoreViewFactory.h"
+#import "htmlediting.h"
+#import "visible_units.h"
+
+using namespace WebCore;
+using namespace HTMLNames;
+using namespace std;
+
+// Cell Tables
+#ifndef NSAccessibilitySelectedCellsAttribute
+#define NSAccessibilitySelectedCellsAttribute @"AXSelectedCells"
+#endif
+
+#ifndef NSAccessibilityVisibleCellsAttribute
+#define NSAccessibilityVisibleCellsAttribute @"AXVisibleCells"
+#endif
+
+#ifndef NSAccessibilityRowHeaderUIElementsAttribute
+#define NSAccessibilityRowHeaderUIElementsAttribute @"AXRowHeaderUIElements"
+#endif
+
+#ifndef NSAccessibilityRowIndexRangeAttribute
+#define NSAccessibilityRowIndexRangeAttribute @"AXRowIndexRange"
+#endif
+
+#ifndef NSAccessibilityColumnIndexRangeAttribute
+#define NSAccessibilityColumnIndexRangeAttribute @"AXColumnIndexRange"
+#endif
+
+#ifndef NSAccessibilityCellForColumnAndRowParameterizedAttribute
+#define NSAccessibilityCellForColumnAndRowParameterizedAttribute @"AXCellForColumnAndRow"
+#endif
+
+#ifndef NSAccessibilityCellRole
+#define NSAccessibilityCellRole @"AXCell"
+#endif
+
+// Lists
+#ifndef NSAccessibilityContentListSubrole
+#define NSAccessibilityContentListSubrole @"AXContentList"
+#endif
+
+#ifndef NSAccessibilityDefinitionListSubrole
+#define NSAccessibilityDefinitionListSubrole @"AXDefinitionList"
+#endif
+
+#ifdef BUILDING_ON_TIGER
+typedef unsigned NSUInteger;
+#endif
+
+@interface NSObject (WebKitAccessibilityArrayCategory)
+
+- (NSUInteger)accessibilityIndexOfChild:(id)child;
+- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute;
+- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
+
+@end
+
+@implementation AccessibilityObjectWrapper
+
+#ifndef BUILDING_ON_TIGER
++ (void)initialize
+{
+ WebCoreObjCFinalizeOnMainThread(self);
+}
+#endif
+
+- (id)initWithAccessibilityObject:(AccessibilityObject*)axObject
+{
+ [super init];
+
+ m_object = axObject;
+ return self;
+}
+
+- (void)unregisterUniqueIdForUIElement
+{
+ [[WebCoreViewFactory sharedFactory] unregisterUniqueIdForUIElement:self];
+}
+
+- (void)detach
+{
+ // Send unregisterUniqueIdForUIElement unconditionally because if it is
+ // ever accidently not done (via other bugs in our AX implementation) you
+ // end up with a crash like <rdar://problem/4273149>. It is safe and not
+ // expensive to send even if the object is not registered.
+ [self unregisterUniqueIdForUIElement];
+ m_object = 0;
+}
+
+- (AccessibilityObject*)accessibilityObject
+{
+ return m_object;
+}
+
+- (NSView*)attachmentView
+{
+ ASSERT(m_object->isAttachment());
+ Widget* widget = m_object->widgetForAttachmentView();
+ if (!widget)
+ return nil;
+ return widget->platformWidget();
+}
+
+static WebCoreTextMarker* textMarkerForVisiblePosition(const VisiblePosition& visiblePos)
+{
+ if (visiblePos.isNull())
+ return nil;
+
+ Position deepPos = visiblePos.deepEquivalent();
+ Node* domNode = deepPos.node();
+ ASSERT(domNode);
+ if (!domNode)
+ return nil;
+
+ if (domNode->isHTMLElement())
+ if (static_cast<HTMLElement*>(domNode)->isPasswordField())
+ return nil;
+
+ // locate the renderer, which must exist for a visible dom node
+ RenderObject* renderer = domNode->renderer();
+ ASSERT(renderer);
+
+ // find or create an accessibility object for this renderer
+ AXObjectCache* cache = renderer->document()->axObjectCache();
+ RefPtr<AccessibilityObject> obj = cache->get(renderer);
+
+ // create a text marker, adding an ID for the AccessibilityObject if needed
+ TextMarkerData textMarkerData;
+
+ // The compiler can add padding to this struct.
+ // This memory must be bzero'd so instances of TextMarkerData can be tested for byte-equivalence.
+ bzero(&textMarkerData, sizeof(TextMarkerData));
+ textMarkerData.axID = obj.get()->axObjectID();
+ textMarkerData.node = domNode;
+ textMarkerData.offset = deepPos.offset();
+ textMarkerData.affinity = visiblePos.affinity();
+ return [[WebCoreViewFactory sharedFactory] textMarkerWithBytes:&textMarkerData length:sizeof(textMarkerData)];
+}
+
+static VisiblePosition visiblePositionForTextMarker(WebCoreTextMarker* textMarker)
+{
+ TextMarkerData textMarkerData;
+
+ if (![[WebCoreViewFactory sharedFactory] getBytes:&textMarkerData fromTextMarker:textMarker length:sizeof(textMarkerData)])
+ return VisiblePosition();
+
+ VisiblePosition visiblePos = VisiblePosition(textMarkerData.node, textMarkerData.offset, textMarkerData.affinity);
+ Position deepPos = visiblePos.deepEquivalent();
+ if (deepPos.isNull())
+ return VisiblePosition();
+
+ RenderObject* renderer = deepPos.node()->renderer();
+ if (!renderer)
+ return VisiblePosition();
+
+ AXObjectCache* cache = renderer->document()->axObjectCache();
+ if (!cache->isIDinUse(textMarkerData.axID))
+ return VisiblePosition();
+
+ if (deepPos.node() != textMarkerData.node || deepPos.offset() != textMarkerData.offset)
+ return VisiblePosition();
+
+ return visiblePos;
+}
+
+static VisiblePosition visiblePositionForStartOfTextMarkerRange(WebCoreTextMarkerRange* textMarkerRange)
+{
+ return visiblePositionForTextMarker([[WebCoreViewFactory sharedFactory] startOfTextMarkerRange:textMarkerRange]);
+}
+
+static VisiblePosition visiblePositionForEndOfTextMarkerRange(WebCoreTextMarkerRange* textMarkerRange)
+{
+ return visiblePositionForTextMarker([[WebCoreViewFactory sharedFactory] endOfTextMarkerRange:textMarkerRange]);
+}
+
+static WebCoreTextMarkerRange* textMarkerRangeFromMarkers(WebCoreTextMarker* textMarker1, WebCoreTextMarker* textMarker2)
+{
+ if (!textMarker1 || !textMarker2)
+ return nil;
+
+ return [[WebCoreViewFactory sharedFactory] textMarkerRangeWithStart:textMarker1 end:textMarker2];
+}
+
+static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, NSString* attribute, NSFont* font, NSRange range)
+{
+ NSDictionary* dict;
+
+ if (font) {
+ dict = [NSDictionary dictionaryWithObjectsAndKeys:
+ [font fontName] , NSAccessibilityFontNameKey,
+ [font familyName] , NSAccessibilityFontFamilyKey,
+ [font displayName] , NSAccessibilityVisibleNameKey,
+ [NSNumber numberWithFloat:[font pointSize]] , NSAccessibilityFontSizeKey,
+ nil];
+
+ [attrString addAttribute:attribute value:dict range:range];
+ } else
+ [attrString removeAttribute:attribute range:range];
+
+}
+
+static CGColorRef CreateCGColorIfDifferent(NSColor* nsColor, CGColorRef existingColor)
+{
+ // get color information assuming NSDeviceRGBColorSpace
+ NSColor* rgbColor = [nsColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
+ if (rgbColor == nil)
+ rgbColor = [NSColor blackColor];
+ CGFloat components[4];
+ [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
+
+ // create a new CGColorRef to return
+ CGColorSpaceRef cgColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+ CGColorRef cgColor = CGColorCreate(cgColorSpace, components);
+ CGColorSpaceRelease(cgColorSpace);
+ CFMakeCollectable(cgColor);
+
+ // check for match with existing color
+ if (existingColor && CGColorEqualToColor(cgColor, existingColor))
+ cgColor = nil;
+
+ return cgColor;
+}
+
+static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range)
+{
+ if (color) {
+ CGColorRef existingColor = (CGColorRef) [attrString attribute:attribute atIndex:range.location effectiveRange:nil];
+ CGColorRef cgColor = CreateCGColorIfDifferent(color, existingColor);
+ if (cgColor) {
+ [attrString addAttribute:attribute value:(id)cgColor range:range];
+ CGColorRelease(cgColor);
+ }
+ } else
+ [attrString removeAttribute:attribute range:range];
+}
+
+static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
+{
+ if (number)
+ [attrString addAttribute:attribute value:number range:range];
+ else
+ [attrString removeAttribute:attribute range:range];
+}
+
+static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
+{
+ RenderStyle* style = renderer->style();
+
+ // set basic font info
+ AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style->font().primaryFont()->getNSFont(), range);
+
+ // set basic colors
+ AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style->color()), range);
+ AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style->backgroundColor()), range);
+
+ // set super/sub scripting
+ EVerticalAlign alignment = style->verticalAlign();
+ if (alignment == SUB)
+ AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range);
+ else if (alignment == SUPER)
+ AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range);
+ else
+ [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range];
+
+ // set shadow
+ if (style->textShadow())
+ AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range);
+ else
+ [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range];
+
+ // set underline and strikethrough
+ int decor = style->textDecorationsInEffect();
+ if ((decor & UNDERLINE) == 0) {
+ [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range];
+ [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range];
+ }
+
+ if ((decor & LINE_THROUGH) == 0) {
+ [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range];
+ [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range];
+ }
+
+ if ((decor & (UNDERLINE | LINE_THROUGH)) != 0) {
+ // find colors using quirk mode approach (strict mode would use current
+ // color for all but the root line box, which would use getTextDecorationColors)
+ Color underline, overline, linethrough;
+ renderer->getTextDecorationColors(decor, underline, overline, linethrough);
+
+ if ((decor & UNDERLINE) != 0) {
+ AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range);
+ AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underline), range);
+ }
+
+ if ((decor & LINE_THROUGH) != 0) {
+ AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range);
+ AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethrough), range);
+ }
+ }
+}
+
+static int blockquoteLevel(RenderObject* renderer)
+{
+ int result = 0;
+ for (Node* node = renderer->element(); node; node = node->parent()) {
+ if (node->hasTagName(blockquoteTag))
+ result += 1;
+ }
+
+ return result;
+}
+
+static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
+{
+ int quoteLevel = blockquoteLevel(renderer);
+
+ if (quoteLevel)
+ [attrString addAttribute:@"AXBlockQuoteLevel" value:[NSNumber numberWithInt:quoteLevel] range:range];
+ else
+ [attrString removeAttribute:@"AXBlockQuoteLevel" range:range];
+}
+
+static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, int offset, NSRange range)
+{
+ Vector<DocumentMarker> markers = node->renderer()->document()->markersForNode(node);
+ Vector<DocumentMarker>::iterator markerIt = markers.begin();
+
+ unsigned endOffset = (unsigned)offset + range.length;
+ for ( ; markerIt != markers.end(); markerIt++) {
+ DocumentMarker marker = *markerIt;
+
+ if (marker.type != DocumentMarker::Spelling)
+ continue;
+
+ if (marker.endOffset <= (unsigned)offset)
+ continue;
+
+ if (marker.startOffset > endOffset)
+ break;
+
+ // add misspelling attribute for the intersection of the marker and the range
+ int rStart = range.location + (marker.startOffset - offset);
+ int rLength = MIN(marker.endOffset, endOffset) - marker.startOffset;
+ NSRange spellRange = NSMakeRange(rStart, rLength);
+ AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
+
+ if (marker.endOffset > endOffset + 1)
+ break;
+ }
+}
+
+static void AXAttributeStringSetHeadingLevel(AccessibilityObject* object, NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
+{
+ int parentHeadingLevel = AccessibilityRenderObject::headingLevel(renderer->parent()->element());
+
+ if (parentHeadingLevel)
+ [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
+ else
+ [attrString removeAttribute:@"AXHeadingLevel" range:range];
+}
+
+static AccessibilityObject* AXLinkElementForNode(Node* node)
+{
+ RenderObject* obj = node->renderer();
+ if (!obj)
+ return 0;
+
+ RefPtr<AccessibilityObject> axObj = obj->document()->axObjectCache()->get(obj);
+ Element* anchor = axObj->anchorElement();
+ if (!anchor)
+ return 0;
+
+ RenderObject* anchorRenderer = anchor->renderer();
+ if (!anchorRenderer)
+ return 0;
+
+ return anchorRenderer->document()->axObjectCache()->get(anchorRenderer);
+}
+
+static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range)
+{
+ if (object && object->isAccessibilityRenderObject()) {
+ // make a serialiazable AX object
+
+ RenderObject* renderer = static_cast<AccessibilityRenderObject*>(object)->renderer();
+ if (!renderer)
+ return;
+
+ Document* doc = renderer->document();
+ if (!doc)
+ return;
+
+ AXObjectCache* cache = doc->axObjectCache();
+ if (!cache)
+ return;
+
+ AXUIElementRef axElement = [[WebCoreViewFactory sharedFactory] AXUIElementForElement:object->wrapper()];
+ if (axElement) {
+ [attrString addAttribute:attribute value:(id)axElement range:range];
+ CFRelease(axElement);
+ }
+ } else
+ [attrString removeAttribute:attribute range:range];
+}
+
+static void AXAttributedStringAppendText(AccessibilityObject* object, NSMutableAttributedString* attrString, Node* node, int offset, const UChar* chars, int length)
+{
+ // skip invisible text
+ if (!node->renderer())
+ return;
+
+ // easier to calculate the range before appending the string
+ NSRange attrStringRange = NSMakeRange([attrString length], length);
+
+ // append the string from this node
+ [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]];
+
+ // add new attributes and remove irrelevant inherited ones
+ // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge
+ // identical colors. Workaround is to not replace an existing color attribute if it matches what we are adding. This also means
+ // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually.
+
+ // remove inherited attachment from prior AXAttributedStringAppendReplaced
+ [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange];
+
+ // set new attributes
+ AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange);
+ AXAttributeStringSetHeadingLevel(object, attrString, node->renderer(), attrStringRange);
+ AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange);
+ AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AXLinkElementForNode(node), attrStringRange);
+
+ // do spelling last because it tends to break up the range
+ AXAttributeStringSetSpelling(attrString, node, offset, attrStringRange);
+}
+
+static NSString* nsStringForReplacedNode(Node* replacedNode)
+{
+ // we should always be given a rendered node and a replaced node, but be safe
+ // replaced nodes are either attachments (widgets) or images
+ if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) {
+ ASSERT_NOT_REACHED();
+ return nil;
+ }
+
+ // create an AX object, but skip it if it is not supposed to be seen
+ RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer());
+ if (obj->accessibilityIsIgnored())
+ return nil;
+
+ // use the attachmentCharacter to represent the replaced node
+ const UniChar attachmentChar = NSAttachmentCharacter;
+ return [NSString stringWithCharacters:&attachmentChar length:1];
+}
+
+- (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(WebCoreTextMarkerRange*)textMarkerRange
+{
+ // extract the start and end VisiblePosition
+ VisiblePosition startVisiblePosition = visiblePositionForStartOfTextMarkerRange(textMarkerRange);
+ if (startVisiblePosition.isNull())
+ return nil;
+
+ VisiblePosition endVisiblePosition = visiblePositionForEndOfTextMarkerRange(textMarkerRange);
+ if (endVisiblePosition.isNull())
+ return nil;
+
+ // iterate over the range to build the AX attributed string
+ NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
+ TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
+ while (!it.atEnd()) {
+ // locate the node and starting offset for this range
+ int exception = 0;
+ Node* node = it.range()->startContainer(exception);
+ ASSERT(node == it.range()->endContainer(exception));
+ int offset = it.range()->startOffset(exception);
+
+ // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
+ if (it.length() != 0) {
+ AXAttributedStringAppendText(m_object, attrString, node, offset, it.characters(), it.length());
+ } else {
+ Node* replacedNode = node->childNode(offset);
+ NSString *attachmentString = nsStringForReplacedNode(replacedNode);
+ if (attachmentString) {
+ NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]);
+
+ // append the placeholder string
+ [[attrString mutableString] appendString:attachmentString];
+
+ // remove all inherited attributes
+ [attrString setAttributes:nil range:attrStringRange];
+
+ // add the attachment attribute
+ AccessibilityObject* obj = replacedNode->renderer()->document()->axObjectCache()->get(replacedNode->renderer());
+ AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange);
+ }
+ }
+ it.advance();
+ }
+
+ return [attrString autorelease];
+}
+
+static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePosition startPosition, VisiblePosition endPosition)
+{
+ WebCoreTextMarker* startTextMarker = textMarkerForVisiblePosition(startPosition);
+ WebCoreTextMarker* endTextMarker = textMarkerForVisiblePosition(endPosition);
+ return textMarkerRangeFromMarkers(startTextMarker, endTextMarker);
+}
+
+- (NSArray*)accessibilityActionNames
+{
+ static NSArray* actionElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil];
+ static NSArray* defaultElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityShowMenuAction, nil];
+ static NSArray* menuElementActions = [[NSArray alloc] initWithObjects: NSAccessibilityCancelAction, NSAccessibilityPressAction, nil];
+
+ NSArray *actions;
+ if (m_object->actionElement())
+ actions = actionElementActions;
+ else if (m_object->isMenuRelated())
+ actions = menuElementActions;
+ else if (m_object->isAttachment())
+ actions = [[self attachmentView] accessibilityActionNames];
+ else
+ actions = defaultElementActions;
+
+ return actions;
+}
+
+- (NSArray*)accessibilityAttributeNames
+{
+ if (m_object->isAttachment())
+ return [[self attachmentView] accessibilityAttributeNames];
+
+ static NSArray* attributes = nil;
+ static NSArray* anchorAttrs = nil;
+ static NSArray* webAreaAttrs = nil;
+ static NSArray* textAttrs = nil;
+ static NSArray* listBoxAttrs = nil;
+ static NSArray* rangeAttrs = nil;
+ static NSArray* commonMenuAttrs = nil;
+ static NSArray* menuAttrs = nil;
+ static NSArray* menuBarAttrs = nil;
+ static NSArray* menuItemAttrs = nil;
+ static NSArray* menuButtonAttrs = nil;
+ static NSArray* controlAttrs = nil;
+ static NSArray* tableAttrs = nil;
+ static NSArray* tableRowAttrs = nil;
+ static NSArray* tableColAttrs = nil;
+ static NSArray* tableCellAttrs = nil;
+ NSMutableArray* tempArray;
+ if (attributes == nil) {
+ attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
+ NSAccessibilitySubroleAttribute,
+ NSAccessibilityRoleDescriptionAttribute,
+ NSAccessibilityChildrenAttribute,
+ NSAccessibilityHelpAttribute,
+ NSAccessibilityParentAttribute,
+ NSAccessibilityPositionAttribute,
+ NSAccessibilitySizeAttribute,
+ NSAccessibilityTitleAttribute,
+ NSAccessibilityDescriptionAttribute,
+ NSAccessibilityValueAttribute,
+ NSAccessibilityFocusedAttribute,
+ NSAccessibilityEnabledAttribute,
+ NSAccessibilityWindowAttribute,
+ @"AXSelectedTextMarkerRange",
+ @"AXStartTextMarker",
+ @"AXEndTextMarker",
+ @"AXVisited",
+ NSAccessibilityLinkedUIElementsAttribute,
+ NSAccessibilitySelectedAttribute,
+ @"AXBlockQuoteLevel",
+ NSAccessibilityTopLevelUIElementAttribute,
+ nil];
+ }
+ if (commonMenuAttrs == nil) {
+ commonMenuAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
+ NSAccessibilityRoleDescriptionAttribute,
+ NSAccessibilityChildrenAttribute,
+ NSAccessibilityParentAttribute,
+ NSAccessibilityEnabledAttribute,
+ NSAccessibilityPositionAttribute,
+ NSAccessibilitySizeAttribute,
+ nil];
+ }
+ if (anchorAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+ [tempArray addObject:NSAccessibilityURLAttribute];
+ anchorAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (webAreaAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+ [tempArray addObject:@"AXLinkUIElements"];
+ [tempArray addObject:@"AXLoaded"];
+ [tempArray addObject:@"AXLayoutCount"];
+ [tempArray addObject:NSAccessibilityURLAttribute];
+ webAreaAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (textAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+ [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute];
+ [tempArray addObject:NSAccessibilitySelectedTextAttribute];
+ [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
+ [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute];
+ [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute];
+ [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
+ textAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (listBoxAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+ [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
+ [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
+ [tempArray addObject:NSAccessibilityOrientationAttribute];
+ [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
+ listBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (rangeAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+ [tempArray addObject:NSAccessibilityTopLevelUIElementAttribute];
+ [tempArray addObject:NSAccessibilityValueAttribute];
+ [tempArray addObject:NSAccessibilityMinValueAttribute];
+ [tempArray addObject:NSAccessibilityMaxValueAttribute];
+ rangeAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (menuBarAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
+ [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
+ [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
+ [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
+ menuBarAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (menuAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
+ [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
+ [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
+ [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
+ menuAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (menuItemAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
+ [tempArray addObject:NSAccessibilityTitleAttribute];
+ [tempArray addObject:NSAccessibilityHelpAttribute];
+ [tempArray addObject:NSAccessibilitySelectedAttribute];
+ [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute];
+ [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute];
+ [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute];
+ [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute];
+ [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute];
+ [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute];
+ [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute];
+ menuItemAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (menuButtonAttrs == nil) {
+ menuButtonAttrs = [[NSArray alloc] initWithObjects:NSAccessibilityRoleAttribute,
+ NSAccessibilityRoleDescriptionAttribute,
+ NSAccessibilityParentAttribute,
+ NSAccessibilityPositionAttribute,
+ NSAccessibilitySizeAttribute,
+ NSAccessibilityWindowAttribute,
+ NSAccessibilityTopLevelUIElementAttribute,
+ NSAccessibilityEnabledAttribute,
+ NSAccessibilityFocusedAttribute,
+ NSAccessibilityTitleAttribute,
+ NSAccessibilityChildrenAttribute, nil];
+ }
+ if (controlAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+ [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
+ controlAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (tableAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+ [tempArray addObject:NSAccessibilityRowsAttribute];
+ [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
+ [tempArray addObject:NSAccessibilityColumnsAttribute];
+ [tempArray addObject:NSAccessibilityVisibleColumnsAttribute];
+ [tempArray addObject:NSAccessibilityVisibleCellsAttribute];
+ [tempArray addObject:(NSString *)kAXColumnHeaderUIElementsAttribute];
+ [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
+ [tempArray addObject:NSAccessibilityHeaderAttribute];
+ tableAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (tableRowAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+ [tempArray addObject:NSAccessibilityIndexAttribute];
+ tableRowAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (tableColAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+ [tempArray addObject:NSAccessibilityIndexAttribute];
+ [tempArray addObject:NSAccessibilityHeaderAttribute];
+ [tempArray addObject:NSAccessibilityRowsAttribute];
+ [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
+ tableColAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (tableCellAttrs == nil) {
+ tempArray = [[NSMutableArray alloc] initWithArray:attributes];
+ [tempArray addObject:NSAccessibilityRowIndexRangeAttribute];
+ [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute];
+ tableCellAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+
+ if (m_object->isPasswordField())
+ return attributes;
+
+ if (m_object->isWebArea())
+ return webAreaAttrs;
+
+ if (m_object->isTextControl())
+ return textAttrs;
+
+ if (m_object->isAnchor() || m_object->isImage())
+ return anchorAttrs;
+
+ if (m_object->isDataTable())
+ return tableAttrs;
+ if (m_object->isTableRow())
+ return tableRowAttrs;
+ if (m_object->isTableColumn())
+ return tableColAttrs;
+ if (m_object->isTableCell())
+ return tableCellAttrs;
+
+ if (m_object->isListBox() || m_object->isList())
+ return listBoxAttrs;
+
+ if (m_object->isProgressIndicator() || m_object->isSlider())
+ return rangeAttrs;
+
+ if (m_object->isControl())
+ return controlAttrs;
+
+ if (m_object->isMenu())
+ return menuAttrs;
+ if (m_object->isMenuBar())
+ return menuBarAttrs;
+ if (m_object->isMenuButton())
+ return menuButtonAttrs;
+ if (m_object->isMenuItem())
+ return menuItemAttrs;
+
+ return attributes;
+}
+
+- (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(WebCoreTextMarkerRange*) textMarkerRange
+{
+ return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(textMarkerRange), visiblePositionForEndOfTextMarkerRange(textMarkerRange));
+}
+
+- (NSArray*)renderWidgetChildren
+{
+ Widget* widget = m_object->widget();
+ if (!widget)
+ return nil;
+ return [(widget->getOuterView()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute];
+}
+
+static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector)
+{
+ unsigned length = [array count];
+ vector.reserveCapacity(length);
+ for (unsigned i = 0; i < length; ++i) {
+ AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject];
+ if (obj)
+ vector.append(obj);
+ }
+}
+
+static NSMutableArray* convertToNSArray(const AccessibilityObject::AccessibilityChildrenVector& vector)
+{
+ unsigned length = vector.size();
+ NSMutableArray* array = [NSMutableArray arrayWithCapacity: length];
+ for (unsigned i = 0; i < length; ++i) {
+ ASSERT(vector[i]->wrapper());
+ if (vector[i]->wrapper())
+ [array addObject:vector[i]->wrapper()];
+ }
+ return array;
+}
+
+- (WebCoreTextMarkerRange*)textMarkerRangeForSelection
+{
+ Selection selection = m_object->selection();
+ if (selection.isNone())
+ return nil;
+ return textMarkerRangeFromVisiblePositions(selection.visibleStart(), selection.visibleEnd());
+}
+
+- (NSValue*)position
+{
+ IntRect rect = m_object->elementRect();
+
+ // The Cocoa accessibility API wants the lower-left corner.
+ NSPoint point = NSMakePoint(rect.x(), rect.bottom());
+ FrameView* frameView = m_object->documentFrameView();
+ if (frameView) {
+ NSView* view = frameView->documentView();
+ point = [[view window] convertBaseToScreen: [view convertPoint: point toView:nil]];
+ }
+
+ return [NSValue valueWithPoint: point];
+}
+
+typedef HashMap<int, NSString*> AccessibilityRoleMap;
+
+static const AccessibilityRoleMap& createAccessibilityRoleMap()
+{
+ struct RoleEntry {
+ AccessibilityRole value;
+ NSString* string;
+ };
+
+ static const RoleEntry roles[] = {
+ { UnknownRole, NSAccessibilityUnknownRole },
+ { ButtonRole, NSAccessibilityButtonRole },
+ { RadioButtonRole, NSAccessibilityRadioButtonRole },
+ { CheckBoxRole, NSAccessibilityCheckBoxRole },
+ { SliderRole, NSAccessibilitySliderRole },
+ { TabGroupRole, NSAccessibilityTabGroupRole },
+ { TextFieldRole, NSAccessibilityTextFieldRole },
+ { StaticTextRole, NSAccessibilityStaticTextRole },
+ { TextAreaRole, NSAccessibilityTextAreaRole },
+ { ScrollAreaRole, NSAccessibilityScrollAreaRole },
+ { PopUpButtonRole, NSAccessibilityPopUpButtonRole },
+ { MenuButtonRole, NSAccessibilityMenuButtonRole },
+ { TableRole, NSAccessibilityTableRole },
+ { ApplicationRole, NSAccessibilityApplicationRole },
+ { GroupRole, NSAccessibilityGroupRole },
+ { RadioGroupRole, NSAccessibilityRadioGroupRole },
+ { ListRole, NSAccessibilityListRole },
+ { ScrollBarRole, NSAccessibilityScrollBarRole },
+ { ValueIndicatorRole, NSAccessibilityValueIndicatorRole },
+ { ImageRole, NSAccessibilityImageRole },
+ { MenuBarRole, NSAccessibilityMenuBarRole },
+ { MenuRole, NSAccessibilityMenuRole },
+ { MenuItemRole, NSAccessibilityMenuItemRole },
+ { ColumnRole, NSAccessibilityColumnRole },
+ { RowRole, NSAccessibilityRowRole },
+ { ToolbarRole, NSAccessibilityToolbarRole },
+ { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole },
+ { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole },
+ { WindowRole, NSAccessibilityWindowRole },
+ { DrawerRole, NSAccessibilityDrawerRole },
+ { SystemWideRole, NSAccessibilitySystemWideRole },
+ { OutlineRole, NSAccessibilityOutlineRole },
+ { IncrementorRole, NSAccessibilityIncrementorRole },
+ { BrowserRole, NSAccessibilityBrowserRole },
+ { ComboBoxRole, NSAccessibilityComboBoxRole },
+ { SplitGroupRole, NSAccessibilitySplitGroupRole },
+ { SplitterRole, NSAccessibilitySplitterRole },
+ { ColorWellRole, NSAccessibilityColorWellRole },
+ { GrowAreaRole, NSAccessibilityGrowAreaRole },
+ { SheetRole, NSAccessibilitySheetRole },
+ { HelpTagRole, NSAccessibilityHelpTagRole },
+ { MatteRole, NSAccessibilityMatteRole },
+ { RulerRole, NSAccessibilityRulerRole },
+ { RulerMarkerRole, NSAccessibilityRulerMarkerRole },
+ { LinkRole, NSAccessibilityLinkRole },
+#ifndef BUILDING_ON_TIGER
+ { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole },
+ { GridRole, NSAccessibilityGridRole },
+#endif
+ { WebCoreLinkRole, NSAccessibilityLinkRole },
+ { ImageMapLinkRole, NSAccessibilityLinkRole },
+ { ImageMapRole, @"AXImageMap" },
+ { ListMarkerRole, @"AXListMarker" },
+ { WebAreaRole, @"AXWebArea" },
+ { HeadingRole, @"AXHeading" },
+ { ListBoxRole, NSAccessibilityListRole },
+ { ListBoxOptionRole, NSAccessibilityStaticTextRole },
+ // cells don't exist on tiger or leopard
+#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
+ { CellRole, NSAccessibilityGroupRole },
+#else
+ { CellRole, NSAccessibilityCellRole },
+#endif
+ { TableHeaderContainerRole, NSAccessibilityGroupRole },
+ { DefinitionListDefinitionRole, NSAccessibilityGroupRole },
+ { DefinitionListTermRole, NSAccessibilityGroupRole }
+
+ };
+ AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
+
+ const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
+ for (unsigned i = 0; i < numRoles; ++i)
+ roleMap.set(roles[i].value, roles[i].string);
+ return roleMap;
+}
+
+static NSString* roleValueToNSString(AccessibilityRole value)
+{
+ ASSERT(value);
+ static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap();
+ return roleMap.get(value);
+}
+
+- (NSString*)role
+{
+ if (m_object->isAttachment())
+ return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
+ NSString* string = roleValueToNSString(m_object->roleValue());
+ if (string != nil)
+ return string;
+ return NSAccessibilityUnknownRole;
+}
+
+- (NSString*)subrole
+{
+ if (m_object->isPasswordField())
+ return NSAccessibilitySecureTextFieldSubrole;
+
+ if (m_object->isAttachment()) {
+ NSView* attachView = [self attachmentView];
+ if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) {
+ return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute];
+ }
+ }
+
+ if (m_object->isList()) {
+ AccessibilityList* listObject = static_cast<AccessibilityList*>(m_object);
+ if (listObject->isUnorderedList() || listObject->isOrderedList())
+ return NSAccessibilityContentListSubrole;
+ if (listObject->isDefinitionList())
+ return NSAccessibilityDefinitionListSubrole;
+ }
+
+ return nil;
+}
+
+- (NSString*)roleDescription
+{
+ if (!m_object)
+ return nil;
+
+ // attachments have the AXImage role, but a different subrole
+ if (m_object->isAttachment())
+ return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
+
+ // FIXME 3447564: It would be better to call some AppKit API to get these strings
+ // (which would be the best way to localize them)
+
+ NSString* axRole = [self role];
+ if ([axRole isEqualToString:NSAccessibilityButtonRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityButtonRole, [self subrole]);
+
+ if ([axRole isEqualToString:NSAccessibilityPopUpButtonRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityPopUpButtonRole, [self subrole]);
+
+ if ([axRole isEqualToString:NSAccessibilityStaticTextRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityStaticTextRole, [self subrole]);
+
+ if ([axRole isEqualToString:NSAccessibilityImageRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityImageRole, [self subrole]);
+
+ if ([axRole isEqualToString:NSAccessibilityGroupRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
+
+ if ([axRole isEqualToString:NSAccessibilityCheckBoxRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityCheckBoxRole, [self subrole]);
+
+ if ([axRole isEqualToString:NSAccessibilityRadioButtonRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityRadioButtonRole, [self subrole]);
+
+ if ([axRole isEqualToString:NSAccessibilityTextFieldRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityTextFieldRole, [self subrole]);
+
+ if ([axRole isEqualToString:NSAccessibilityTextAreaRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityTextAreaRole, [self subrole]);
+
+ if ([axRole isEqualToString:NSAccessibilityListRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityListRole, [self subrole]);
+
+ if ([axRole isEqualToString:NSAccessibilityTableRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityTableRole, [self subrole]);
+
+ if ([axRole isEqualToString:NSAccessibilityRowRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityRowRole, [self subrole]);
+
+ if ([axRole isEqualToString:NSAccessibilityColumnRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityColumnRole, [self subrole]);
+
+ if ([axRole isEqualToString:NSAccessibilityCellRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityCellRole, [self subrole]);
+
+ if ([axRole isEqualToString:@"AXWebArea"])
+ return AXWebAreaText();
+
+ if ([axRole isEqualToString:@"AXLink"])
+ return AXLinkText();
+
+ if ([axRole isEqualToString:@"AXListMarker"])
+ return AXListMarkerText();
+
+ if ([axRole isEqualToString:@"AXImageMap"])
+ return AXImageMapText();
+
+ if ([axRole isEqualToString:@"AXHeading"])
+ return AXHeadingText();
+
+ if ([axRole isEqualToString:(NSString*)kAXMenuBarItemRole] ||
+ [axRole isEqualToString:NSAccessibilityMenuRole])
+ return nil;
+
+ if ([axRole isEqualToString:NSAccessibilityMenuButtonRole])
+ return NSAccessibilityRoleDescription(NSAccessibilityMenuButtonRole, [self subrole]);
+
+ return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
+}
+
+// FIXME: split up this function in a better way.
+// suggestions: Use a hash table that maps attribute names to function calls,
+// or maybe pointers to member functions
+- (id)accessibilityAttributeValue:(NSString*)attributeName
+{
+ if (!m_object)
+ return nil;
+
+ if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
+ return [self role];
+
+ if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
+ return [self subrole];
+
+ if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
+ return [self roleDescription];
+
+ if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
+ if (m_object->isAccessibilityRenderObject()) {
+ FrameView* fv = static_cast<AccessibilityRenderObject*>(m_object)->frameViewIfRenderView();
+ if (fv)
+ return fv->platformWidget();
+ }
+
+ return m_object->parentObjectUnignored()->wrapper();
+ }
+
+ if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
+ if (m_object->children().isEmpty()) {
+ NSArray* children = [self renderWidgetChildren];
+ if (children != nil)
+ return children;
+ }
+ return convertToNSArray(m_object->children());
+ }
+
+ if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
+ if (m_object->isListBox()) {
+ AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
+ m_object->selectedChildren(selectedChildrenCopy);
+ return convertToNSArray(selectedChildrenCopy);
+ }
+ return nil;
+ }
+
+ if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) {
+ if (m_object->isListBox()) {
+ AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
+ m_object->visibleChildren(visibleChildrenCopy);
+ return convertToNSArray(visibleChildrenCopy);
+ }
+ else if (m_object->isList())
+ return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
+
+ return nil;
+ }
+
+
+ if (m_object->isWebArea()) {
+ if ([attributeName isEqualToString: @"AXLinkUIElements"]) {
+ AccessibilityObject::AccessibilityChildrenVector links;
+ static_cast<AccessibilityRenderObject*>(m_object)->getDocumentLinks(links);
+ return convertToNSArray(links);
+ }
+ if ([attributeName isEqualToString: @"AXLoaded"])
+ return [NSNumber numberWithBool: m_object->isLoaded()];
+ if ([attributeName isEqualToString: @"AXLayoutCount"])
+ return [NSNumber numberWithInt: m_object->layoutCount()];
+ }
+
+ if (m_object->isTextControl()) {
+ if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) {
+ int length = m_object->textLength();
+ if (length < 0)
+ return nil;
+ return [NSNumber numberWithUnsignedInt:length];
+ }
+ if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
+ String selectedText = m_object->selectedText();
+ if (selectedText.isNull())
+ return nil;
+ return (NSString*)selectedText;
+ }
+ if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
+ PlainTextRange textRange = m_object->selectedTextRange();
+ if (textRange.isNull())
+ return nil;
+ return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
+ }
+ // TODO: Get actual visible range. <rdar://problem/4712101>
+ if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
+ return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())];
+ if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
+ // if selectionEnd > 0, then there is selected text and this question should not be answered
+ if (m_object->isPasswordField() || m_object->selectionEnd() > 0)
+ return nil;
+ int lineNumber = m_object->lineForPosition(m_object->visiblePositionForIndex(m_object->selectionStart(), true));
+ if (lineNumber < 0)
+ return nil;
+ return [NSNumber numberWithInt:lineNumber];
+ }
+ }
+
+ if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
+ KURL url = m_object->url();
+ if (url.isNull())
+ return nil;
+ return (NSURL*)url;
+ }
+
+ if ([attributeName isEqualToString: @"AXVisited"])
+ return [NSNumber numberWithBool: m_object->isVisited()];
+
+ if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
+ if (m_object->isAttachment()) {
+ if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute])
+ return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
+ }
+ return m_object->title();
+ }
+
+ if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) {
+ if (m_object->isAttachment()) {
+ if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
+ return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
+ }
+ return m_object->accessibilityDescription();
+ }
+
+ if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
+ if (m_object->isAttachment()) {
+ if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute])
+ return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
+ }
+ if (m_object->isProgressIndicator() || m_object->isSlider())
+ return [NSNumber numberWithFloat:m_object->valueForRange()];
+ if (m_object->hasIntValue())
+ return [NSNumber numberWithInt:m_object->intValue()];
+ return m_object->stringValue();
+ }
+
+ if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute])
+ return [NSNumber numberWithFloat:m_object->minValueForRange()];
+
+ if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute])
+ return [NSNumber numberWithFloat:m_object->maxValueForRange()];
+
+ if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
+ return m_object->helpText();
+
+ if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
+ return [NSNumber numberWithBool: m_object->isFocused()];
+
+ if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
+ return [NSNumber numberWithBool: m_object->isEnabled()];
+
+ if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) {
+ IntSize s = m_object->size();
+ return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())];
+ }
+
+ if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
+ return [self position];
+
+ if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] ||
+ [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) {
+ FrameView* fv = m_object->documentFrameView();
+ if (fv)
+ return [fv->platformWidget() window];
+ return nil;
+ }
+
+ if (m_object->isDataTable()) {
+ // TODO: distinguish between visible and non-visible rows
+ if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
+ [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
+ return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->rows());
+ }
+ // TODO: distinguish between visible and non-visible columns
+ if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute] ||
+ [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute]) {
+ return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->columns());
+ }
+
+ // HTML tables don't support these
+ if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute] ||
+ [attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute] ||
+ [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute])
+ return nil;
+
+ if ([attributeName isEqualToString:(NSString *)kAXColumnHeaderUIElementsAttribute]) {
+ AccessibilityObject::AccessibilityChildrenVector columnHeaders;
+ static_cast<AccessibilityTable*>(m_object)->columnHeaders(columnHeaders);
+ return convertToNSArray(columnHeaders);
+ }
+
+ if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
+ AccessibilityObject* headerContainer = static_cast<AccessibilityTable*>(m_object)->headerContainer();
+ if (headerContainer)
+ return headerContainer->wrapper();
+ return nil;
+ }
+
+ if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
+ AccessibilityObject::AccessibilityChildrenVector rowHeaders;
+ static_cast<AccessibilityTable*>(m_object)->rowHeaders(rowHeaders);
+ return convertToNSArray(rowHeaders);
+ }
+
+ if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute]) {
+ AccessibilityObject::AccessibilityChildrenVector cells;
+ static_cast<AccessibilityTable*>(m_object)->cells(cells);
+ return convertToNSArray(cells);
+ }
+ }
+
+ if (m_object->isTableRow()) {
+ if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
+ return [NSNumber numberWithInt:static_cast<AccessibilityTableRow*>(m_object)->rowIndex()];
+ }
+
+ if (m_object->isTableColumn()) {
+ if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
+ return [NSNumber numberWithInt:static_cast<AccessibilityTableColumn*>(m_object)->columnIndex()];
+
+ // rows attribute for a column is the list of all the elements in that column at each row
+ if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
+ [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
+ return convertToNSArray(static_cast<AccessibilityTableColumn*>(m_object)->children());
+ }
+ if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
+ AccessibilityObject* header = static_cast<AccessibilityTableColumn*>(m_object)->headerObject();
+ if (!header)
+ return nil;
+ return header->wrapper();
+ }
+ }
+
+ if (m_object->isTableCell()) {
+ if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) {
+ pair<int, int> rowRange;
+ static_cast<AccessibilityTableCell*>(m_object)->rowIndexRange(rowRange);
+ return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)];
+ }
+ if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) {
+ pair<int, int> columnRange;
+ static_cast<AccessibilityTableCell*>(m_object)->columnIndexRange(columnRange);
+ return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)];
+ }
+ }
+
+ if ((m_object->isListBox() ||m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
+ return NSAccessibilityVerticalOrientationValue;
+
+ if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
+ return [self textMarkerRangeForSelection];
+
+ if (m_object->isAccessibilityRenderObject()) {
+ RenderObject* renderer = static_cast<AccessibilityRenderObject*>(m_object)->renderer();
+ if (!renderer)
+ return nil;
+
+ if ([attributeName isEqualToString: @"AXStartTextMarker"])
+ return textMarkerForVisiblePosition(startOfDocument(renderer->document()));
+ if ([attributeName isEqualToString: @"AXEndTextMarker"])
+ return textMarkerForVisiblePosition(endOfDocument(renderer->document()));
+
+ if ([attributeName isEqualToString: @"AXBlockQuoteLevel"])
+ return [NSNumber numberWithInt:blockquoteLevel(renderer)];
+ }
+
+ if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
+ AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
+ m_object->linkedUIElements(linkedUIElements);
+ if (linkedUIElements.size() == 0)
+ return nil;
+ return convertToNSArray(linkedUIElements);
+ }
+
+ if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
+ return [NSNumber numberWithBool:m_object->isSelected()];
+
+ if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) {
+ AccessibilityObject* uiElement = static_cast<AccessibilityRenderObject*>(m_object)->menuForMenuButton();
+ if (uiElement)
+ return [NSArray arrayWithObject:uiElement->wrapper()];
+ }
+
+ if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
+ AccessibilityObject* obj = m_object->titleUIElement();
+ if (obj)
+ return obj->wrapper();
+ return nil;
+ }
+
+ return nil;
+}
+
+- (id)accessibilityFocusedUIElement
+{
+ RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement();
+
+ if (!focusedObj)
+ return nil;
+
+ return focusedObj->wrapper();
+}
+
+- (id)accessibilityHitTest:(NSPoint)point
+{
+ RefPtr<AccessibilityObject> axObject = m_object->doAccessibilityHitTest(IntPoint(point));
+ if (axObject)
+ return NSAccessibilityUnignoredAncestor(axObject->wrapper());
+ return NSAccessibilityUnignoredAncestor(self);
+}
+
+- (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
+{
+ if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
+ return YES;
+
+ if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
+ return m_object->canSetFocusAttribute();
+
+ if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
+ return m_object->canSetValueAttribute();
+
+ if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
+ return m_object->canSetSelectedAttribute();
+
+ if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute])
+ return m_object->canSetSelectedChildrenAttribute();
+
+ if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
+ [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
+ [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
+ return m_object->canSetTextRangeAttributes();
+
+ return NO;
+}
+
+// accessibilityShouldUseUniqueId is an AppKit method we override so that
+// objects will be given a unique ID, and therefore allow AppKit to know when they
+// become obsolete (e.g. when the user navigates to a new web page, making this one
+// unrendered but not deallocated because it is in the back/forward cache).
+// It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
+// appropriate place (e.g. dealloc) to remove these non-retained references from
+// AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
+//
+// Registering an object is also required for observing notifications. Only registered objects can be observed.
+- (BOOL)accessibilityIsIgnored
+{
+ if (m_object->isAttachment())
+ return [[self attachmentView] accessibilityIsIgnored];
+ return m_object->accessibilityIsIgnored();
+}
+
+- (NSArray* )accessibilityParameterizedAttributeNames
+{
+ if (m_object->isAttachment())
+ return nil;
+
+ static NSArray* paramAttrs = nil;
+ static NSArray* textParamAttrs = nil;
+ static NSArray* tableParamAttrs = nil;
+ if (paramAttrs == nil) {
+ paramAttrs = [[NSArray alloc] initWithObjects:
+ @"AXUIElementForTextMarker",
+ @"AXTextMarkerRangeForUIElement",
+ @"AXLineForTextMarker",
+ @"AXTextMarkerRangeForLine",
+ @"AXStringForTextMarkerRange",
+ @"AXTextMarkerForPosition",
+ @"AXBoundsForTextMarkerRange",
+ @"AXAttributedStringForTextMarkerRange",
+ @"AXTextMarkerRangeForUnorderedTextMarkers",
+ @"AXNextTextMarkerForTextMarker",
+ @"AXPreviousTextMarkerForTextMarker",
+ @"AXLeftWordTextMarkerRangeForTextMarker",
+ @"AXRightWordTextMarkerRangeForTextMarker",
+ @"AXLeftLineTextMarkerRangeForTextMarker",
+ @"AXRightLineTextMarkerRangeForTextMarker",
+ @"AXSentenceTextMarkerRangeForTextMarker",
+ @"AXParagraphTextMarkerRangeForTextMarker",
+ @"AXNextWordEndTextMarkerForTextMarker",
+ @"AXPreviousWordStartTextMarkerForTextMarker",
+ @"AXNextLineEndTextMarkerForTextMarker",
+ @"AXPreviousLineStartTextMarkerForTextMarker",
+ @"AXNextSentenceEndTextMarkerForTextMarker",
+ @"AXPreviousSentenceStartTextMarkerForTextMarker",
+ @"AXNextParagraphEndTextMarkerForTextMarker",
+ @"AXPreviousParagraphStartTextMarkerForTextMarker",
+ @"AXStyleTextMarkerRangeForTextMarker",
+ @"AXLengthForTextMarkerRange",
+ NSAccessibilityBoundsForRangeParameterizedAttribute,
+ nil];
+ }
+
+ if (textParamAttrs == nil) {
+ NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
+ [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute];
+ [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute];
+ [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute];
+ [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute];
+ [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute];
+ [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute];
+ [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute];
+ [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute];
+ [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute];
+ textParamAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+ if (tableParamAttrs == nil) {
+ NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
+ [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute];
+ tableParamAttrs = [[NSArray alloc] initWithArray:tempArray];
+ [tempArray release];
+ }
+
+ if (m_object->isPasswordField())
+ return [NSArray array];
+
+ if (!m_object->isAccessibilityRenderObject())
+ return paramAttrs;
+
+ if (m_object->isTextControl())
+ return textParamAttrs;
+
+ if (m_object->isDataTable())
+ return tableParamAttrs;
+
+ if (m_object->isMenuRelated())
+ return nil;
+
+ return paramAttrs;
+}
+
+- (void)accessibilityPerformPressAction
+{
+ if (m_object->isAttachment())
+ [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
+
+ m_object->press();
+}
+
+- (void)accessibilityPerformShowMenuAction
+{
+ // This needs to be performed in an iteration of the run loop that did not start from an AX call.
+ // If it's the same run loop iteration, the menu open notification won't be sent
+ [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0];
+}
+
+- (void)accessibilityShowContextMenu
+{
+ FrameView* frameView = m_object->documentFrameView();
+ if (!frameView)
+ return;
+
+ // simulate a click in the middle of the object
+ IntPoint clickPoint = m_object->clickPoint();
+ NSPoint nsClickPoint = NSMakePoint(clickPoint.x(), clickPoint.y());
+
+ NSView* view = nil;
+ if (m_object->isAttachment())
+ view = [self attachmentView];
+ else
+ view = frameView->documentView();
+
+ if (!view)
+ return;
+
+ NSPoint nsScreenPoint = [view convertPoint:nsClickPoint toView:nil];
+
+ // Show the contextual menu for this event.
+ NSEvent* event = [NSEvent mouseEventWithType:NSRightMouseDown location:nsScreenPoint modifierFlags:0 timestamp:0 windowNumber:[[view window] windowNumber] context:0 eventNumber:0 clickCount:1 pressure:1];
+ NSMenu* menu = [view menuForEvent:event];
+
+ if (menu)
+ [NSMenu popUpContextMenu:menu withEvent:event forView:view];
+}
+
+- (void)accessibilityPerformAction:(NSString*)action
+{
+ if ([action isEqualToString:NSAccessibilityPressAction])
+ [self accessibilityPerformPressAction];
+
+ else if ([action isEqualToString:NSAccessibilityShowMenuAction])
+ [self accessibilityPerformShowMenuAction];
+}
+
+- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
+{
+ WebCoreTextMarkerRange* textMarkerRange = nil;
+ NSNumber* number = nil;
+ NSString* string = nil;
+ NSRange range = {0, 0};
+ NSArray* array = nil;
+
+ // decode the parameter
+ if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:value])
+ textMarkerRange = (WebCoreTextMarkerRange*) value;
+
+ else if ([value isKindOfClass:[NSNumber self]])
+ number = value;
+
+ else if ([value isKindOfClass:[NSString self]])
+ string = value;
+
+ else if ([value isKindOfClass:[NSValue self]])
+ range = [value rangeValue];
+
+ else if ([value isKindOfClass:[NSArray self]])
+ array = value;
+
+ // handle the command
+ if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
+ ASSERT(textMarkerRange);
+ m_object->setSelectedVisiblePositionRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]);
+ } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
+ ASSERT(number);
+ m_object->setFocused([number intValue] != 0);
+ } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
+ if (!string)
+ return;
+ m_object->setValue(string);
+ } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) {
+ if (!number)
+ return;
+ m_object->setSelected([number boolValue]);
+ } else if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
+ if (!array || m_object->roleValue() != ListBoxRole)
+ return;
+ AccessibilityObject::AccessibilityChildrenVector selectedChildren;
+ convertToVector(array, selectedChildren);
+ static_cast<AccessibilityListBox*>(m_object)->setSelectedChildren(selectedChildren);
+ } else if (m_object->isTextControl()) {
+ if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
+ m_object->setSelectedText(string);
+ } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
+ m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
+ } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
+ m_object->makeRangeVisible(PlainTextRange(range.location, range.length));
+ }
+ }
+}
+
+static RenderObject* rendererForView(NSView* view)
+{
+ if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
+ return 0;
+
+ NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
+ Frame* frame = [frameView _web_frame];
+ if (!frame)
+ return 0;
+
+ Node* node = frame->document()->ownerElement();
+ if (!node)
+ return 0;
+
+ return node->renderer();
+}
+
+- (id)_accessibilityParentForSubview:(NSView*)subview
+{
+ RenderObject* renderer = rendererForView(subview);
+ if (!renderer)
+ return nil;
+
+ AccessibilityObject* obj = renderer->document()->axObjectCache()->get(renderer);
+ if (obj)
+ return obj->parentObjectUnignored()->wrapper();
+ return nil;
+}
+
+- (NSString*)accessibilityActionDescription:(NSString*)action
+{
+ // we have no custom actions
+ return NSAccessibilityActionDescription(action);
+}
+
+// The CFAttributedStringType representation of the text associated with this accessibility
+// object that is specified by the given range.
+- (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range
+{
+ PlainTextRange textRange = PlainTextRange(range.location, range.length);
+ VisiblePositionRange visiblePosRange = m_object->visiblePositionRangeForRange(textRange);
+ return [self doAXAttributedStringForTextMarkerRange:textMarkerRangeFromVisiblePositions(visiblePosRange.start, visiblePosRange.end)];
+}
+
+// The RTF representation of the text associated with this accessibility object that is
+// specified by the given range.
+- (NSData*)doAXRTFForRange:(NSRange)range
+{
+ NSAttributedString* attrString = [self doAXAttributedStringForRange:range];
+ return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil];
+}
+
+- (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
+{
+ WebCoreTextMarker* textMarker = nil;
+ WebCoreTextMarkerRange* textMarkerRange = nil;
+ NSNumber* number = nil;
+ NSArray* array = nil;
+ RefPtr<AccessibilityObject> uiElement = 0;
+ NSPoint point = NSZeroPoint;
+ bool pointSet = false;
+ NSRange range = {0, 0};
+ bool rangeSet = false;
+
+ // basic parameter validation
+ if (!m_object || !attribute || !parameter)
+ return nil;
+
+ // common parameter type check/casting. Nil checks in handlers catch wrong type case.
+ // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
+ // a parameter of the wrong type.
+ if ([[WebCoreViewFactory sharedFactory] objectIsTextMarker:parameter])
+ textMarker = (WebCoreTextMarker*) parameter;
+
+ else if ([[WebCoreViewFactory sharedFactory] objectIsTextMarkerRange:parameter])
+ textMarkerRange = (WebCoreTextMarkerRange*) parameter;
+
+ else if ([parameter isKindOfClass:[AccessibilityObjectWrapper self]])
+ uiElement = [(AccessibilityObjectWrapper*)parameter accessibilityObject];
+
+ else if ([parameter isKindOfClass:[NSNumber self]])
+ number = parameter;
+
+ else if ([parameter isKindOfClass:[NSArray self]])
+ array = parameter;
+
+ else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) {
+ pointSet = true;
+ point = [(NSValue*)parameter pointValue];
+
+ } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) {
+ rangeSet = true;
+ range = [(NSValue*)parameter rangeValue];
+
+ } else {
+ // got a parameter of a type we never use
+ // NOTE: No ASSERT_NOT_REACHED because this can happen accidentally
+ // while using accesstool (e.g.), forcing you to start over
+ return nil;
+ }
+
+ // Convert values to WebCore types
+ // FIXME: prepping all of these values as WebCore types is unnecessary in many
+ // cases. Re-organization of this function or performing the conversion on a
+ // need basis are possible improvements.
+ VisiblePosition visiblePos;
+ if (textMarker)
+ visiblePos = visiblePositionForTextMarker(textMarker);
+ int intNumber = [number intValue];
+ VisiblePositionRange visiblePosRange;
+ if (textMarkerRange)
+ visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
+ IntPoint webCorePoint = IntPoint(point);
+ PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
+
+ // dispatch
+ if ([attribute isEqualToString: @"AXUIElementForTextMarker"])
+ return m_object->accessibilityObjectForPosition(visiblePos)->wrapper();
+
+ if ([attribute isEqualToString: @"AXTextMarkerRangeForUIElement"]) {
+ VisiblePositionRange vpRange = uiElement.get()->visiblePositionRange();
+ return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
+ }
+
+ if ([attribute isEqualToString: @"AXLineForTextMarker"])
+ return [NSNumber numberWithUnsignedInt:m_object->lineForPosition(visiblePos)];
+
+ if ([attribute isEqualToString: @"AXTextMarkerRangeForLine"]) {
+ VisiblePositionRange vpRange = m_object->visiblePositionRangeForLine(intNumber);
+ return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
+ }
+
+ if ([attribute isEqualToString: @"AXStringForTextMarkerRange"])
+ return m_object->stringForVisiblePositionRange(visiblePosRange);
+
+ if ([attribute isEqualToString: @"AXTextMarkerForPosition"])
+ return pointSet ? textMarkerForVisiblePosition(m_object->visiblePositionForPoint(webCorePoint)) : nil;
+
+ if ([attribute isEqualToString: @"AXBoundsForTextMarkerRange"]) {
+ NSRect rect = m_object->boundsForVisiblePositionRange(visiblePosRange);
+ return [NSValue valueWithRect:rect];
+ }
+
+ if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) {
+ VisiblePosition start = m_object->visiblePositionForIndex(range.location);
+ VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
+ if (start.isNull() || end.isNull())
+ return nil;
+ NSRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange(start, end));
+ return [NSValue valueWithRect:rect];
+ }
+
+ if ([attribute isEqualToString: @"AXAttributedStringForTextMarkerRange"])
+ return [self doAXAttributedStringForTextMarkerRange:textMarkerRange];
+
+ if ([attribute isEqualToString: @"AXTextMarkerRangeForUnorderedTextMarkers"]) {
+ if ([array count] < 2)
+ return nil;
+
+ WebCoreTextMarker* textMarker1 = (WebCoreTextMarker*) [array objectAtIndex:0];
+ WebCoreTextMarker* textMarker2 = (WebCoreTextMarker*) [array objectAtIndex:1];
+ if (![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker1]
+ || ![[WebCoreViewFactory sharedFactory] objectIsTextMarker:textMarker2])
+ return nil;
+
+ VisiblePosition visiblePos1 = visiblePositionForTextMarker(textMarker1);
+ VisiblePosition visiblePos2 = visiblePositionForTextMarker(textMarker2);
+ VisiblePositionRange vpRange = m_object->visiblePositionRangeForUnorderedPositions(visiblePos1, visiblePos2);
+ return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
+ }
+
+ if ([attribute isEqualToString: @"AXNextTextMarkerForTextMarker"])
+ return textMarkerForVisiblePosition(m_object->nextVisiblePosition(visiblePos));
+
+ if ([attribute isEqualToString: @"AXPreviousTextMarkerForTextMarker"])
+ return textMarkerForVisiblePosition(m_object->previousVisiblePosition(visiblePos));
+
+ if ([attribute isEqualToString: @"AXLeftWordTextMarkerRangeForTextMarker"]) {
+ VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos);
+ return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
+ }
+
+ if ([attribute isEqualToString: @"AXRightWordTextMarkerRangeForTextMarker"]) {
+ VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos);
+ return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
+ }
+
+ if ([attribute isEqualToString: @"AXLeftLineTextMarkerRangeForTextMarker"]) {
+ VisiblePositionRange vpRange = m_object->leftLineVisiblePositionRange(visiblePos);
+ return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
+ }
+
+ if ([attribute isEqualToString: @"AXRightLineTextMarkerRangeForTextMarker"]) {
+ VisiblePositionRange vpRange = m_object->rightLineVisiblePositionRange(visiblePos);
+ return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
+ }
+
+ if ([attribute isEqualToString: @"AXSentenceTextMarkerRangeForTextMarker"]) {
+ VisiblePositionRange vpRange = m_object->sentenceForPosition(visiblePos);
+ return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
+ }
+
+ if ([attribute isEqualToString: @"AXParagraphTextMarkerRangeForTextMarker"]) {
+ VisiblePositionRange vpRange = m_object->paragraphForPosition(visiblePos);
+ return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
+ }
+
+ if ([attribute isEqualToString: @"AXNextWordEndTextMarkerForTextMarker"])
+ return textMarkerForVisiblePosition(m_object->nextWordEnd(visiblePos));
+
+ if ([attribute isEqualToString: @"AXPreviousWordStartTextMarkerForTextMarker"])
+ return textMarkerForVisiblePosition(m_object->previousWordStart(visiblePos));
+
+ if ([attribute isEqualToString: @"AXNextLineEndTextMarkerForTextMarker"])
+ return textMarkerForVisiblePosition(m_object->nextLineEndPosition(visiblePos));
+
+ if ([attribute isEqualToString: @"AXPreviousLineStartTextMarkerForTextMarker"])
+ return textMarkerForVisiblePosition(m_object->previousLineStartPosition(visiblePos));
+
+ if ([attribute isEqualToString: @"AXNextSentenceEndTextMarkerForTextMarker"])
+ return textMarkerForVisiblePosition(m_object->nextSentenceEndPosition(visiblePos));
+
+ if ([attribute isEqualToString: @"AXPreviousSentenceStartTextMarkerForTextMarker"])
+ return textMarkerForVisiblePosition(m_object->previousSentenceStartPosition(visiblePos));
+
+ if ([attribute isEqualToString: @"AXNextParagraphEndTextMarkerForTextMarker"])
+ return textMarkerForVisiblePosition(m_object->nextParagraphEndPosition(visiblePos));
+
+ if ([attribute isEqualToString: @"AXPreviousParagraphStartTextMarkerForTextMarker"])
+ return textMarkerForVisiblePosition(m_object->previousParagraphStartPosition(visiblePos));
+
+ if ([attribute isEqualToString: @"AXStyleTextMarkerRangeForTextMarker"]) {
+ VisiblePositionRange vpRange = m_object->styleRangeForPosition(visiblePos);
+ return (id)textMarkerRangeFromVisiblePositions(vpRange.start, vpRange.end);
+ }
+
+ if ([attribute isEqualToString: @"AXLengthForTextMarkerRange"]) {
+ int length = m_object->lengthForVisiblePositionRange(visiblePosRange);
+ if (length < 0)
+ return nil;
+ return [NSNumber numberWithInt:length];
+ }
+
+ if (m_object->isDataTable()) {
+ if ([attribute isEqualToString:NSAccessibilityCellForColumnAndRowParameterizedAttribute]) {
+ if (array == nil || [array count] != 2)
+ return nil;
+ AccessibilityTableCell* cell = static_cast<AccessibilityTable*>(m_object)->cellForColumnAndRow([[array objectAtIndex:0] unsignedIntValue], [[array objectAtIndex:1] unsignedIntValue]);
+ if (!cell)
+ return nil;
+
+ return cell->wrapper();
+ }
+ }
+
+ if (m_object->isTextControl()) {
+ if ([attribute isEqualToString: (NSString *)kAXLineForIndexParameterizedAttribute]) {
+ int lineNumber = m_object->doAXLineForIndex(intNumber);
+ if (lineNumber < 0)
+ return nil;
+ return [NSNumber numberWithUnsignedInt:lineNumber];
+ }
+
+ if ([attribute isEqualToString: (NSString *)kAXRangeForLineParameterizedAttribute]) {
+ PlainTextRange textRange = m_object->doAXRangeForLine(intNumber);
+ return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
+ }
+
+ if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute])
+ return rangeSet ? (id)(m_object->doAXStringForRange(plainTextRange)) : nil;
+
+ if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute]) {
+ if (!pointSet)
+ return nil;
+ PlainTextRange textRange = m_object->doAXRangeForPosition(webCorePoint);
+ return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
+ }
+
+ if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute]) {
+ PlainTextRange textRange = m_object->doAXRangeForIndex(intNumber);
+ return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
+ }
+
+ if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute]) {
+ if (!rangeSet)
+ return nil;
+ NSRect rect = m_object->doAXBoundsForRange(plainTextRange);
+ return [NSValue valueWithRect:rect];
+ }
+
+ if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute])
+ return rangeSet ? [self doAXRTFForRange:range] : nil;
+
+ if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute])
+ return rangeSet ? [self doAXAttributedStringForRange:range] : nil;
+
+ if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) {
+ PlainTextRange textRange = m_object->doAXStyleRangeForIndex(intNumber);
+ return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
+ }
+ }
+
+ return nil;
+}
+
+- (BOOL)accessibilityShouldUseUniqueId
+{
+ return m_object->accessibilityShouldUseUniqueId();
+}
+
+// API that AppKit uses for faster access
+- (NSUInteger)accessibilityIndexOfChild:(id)child
+{
+ const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
+
+ if (children.isEmpty())
+ return [[self renderWidgetChildren] indexOfObject:child];
+
+ unsigned count = children.size();
+ for (unsigned k = 0; k < count; ++k) {
+ if (children[k]->wrapper() == child)
+ return k;
+ }
+
+ return NSNotFound;
+}
+
+- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute
+{
+ if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
+ const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
+ if (children.isEmpty())
+ return [[self renderWidgetChildren] count];
+
+ return children.size();
+ }
+
+ return [super accessibilityArrayAttributeCount:attribute];
+}
+
+- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount
+{
+ if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
+ if (m_object->children().isEmpty()) {
+ NSArray *children = [self renderWidgetChildren];
+ if (!children)
+ return nil;
+
+ NSUInteger childCount = [children count];
+ if (index >= childCount)
+ return nil;
+
+ NSUInteger arrayLength = min(childCount - index, maxCount);
+ return [children subarrayWithRange:NSMakeRange(index, arrayLength)];
+ }
+
+ const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
+ unsigned childCount = children.size();
+ if (index >= childCount)
+ return nil;
+
+ unsigned available = min(childCount - index, maxCount);
+
+ NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:available];
+ for (unsigned added = 0; added < available; ++index, ++added)
+ [subarray addObject:children[index]->wrapper()];
+
+ return subarray;
+ }
+
+ return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
+}
+
+@end
diff --git a/WebCore/page/mac/ChromeMac.mm b/WebCore/page/mac/ChromeMac.mm
new file mode 100644
index 0000000..aba3449
--- /dev/null
+++ b/WebCore/page/mac/ChromeMac.mm
@@ -0,0 +1,51 @@
+/*
+ * 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/WebCore/page/mac/DragControllerMac.mm b/WebCore/page/mac/DragControllerMac.mm
new file mode 100644
index 0000000..2ab9d41
--- /dev/null
+++ b/WebCore/page/mac/DragControllerMac.mm
@@ -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.
+ */
+
+#import "config.h"
+#import "DragController.h"
+
+#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_document || ![[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;
+}
+
+}
diff --git a/WebCore/page/mac/EventHandlerMac.mm b/WebCore/page/mac/EventHandlerMac.mm
new file mode 100644
index 0000000..562c1dd
--- /dev/null
+++ b/WebCore/page/mac/EventHandlerMac.mm
@@ -0,0 +1,646 @@
+/*
+ * 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 "EventHandler.h"
+
+#include "BlockExceptions.h"
+#include "ChromeClient.h"
+#include "ClipboardMac.h"
+#include "EventNames.h"
+#include "FocusController.h"
+#include "FrameLoader.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "KeyboardEvent.h"
+#include "MouseEventWithHitTestResults.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "RenderWidget.h"
+#include "Scrollbar.h"
+#include "Settings.h"
+
+namespace WebCore {
+
+unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey;
+
+const double EventHandler::TextDragDelay = 0.15;
+
+static RetainPtr<NSEvent>& currentEvent()
+{
+ static RetainPtr<NSEvent> event;
+ return event;
+}
+
+NSEvent *EventHandler::currentNSEvent()
+{
+ return currentEvent().get();
+}
+
+bool EventHandler::wheelEvent(NSEvent *event)
+{
+ RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
+ currentEvent() = event;
+
+ PlatformWheelEvent wheelEvent(event);
+ handleWheelEvent(wheelEvent);
+
+ ASSERT(currentEvent() == event);
+ currentEvent() = oldCurrentEvent;
+
+ 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() ? m_frame->document()->defaultView() : 0);
+ }
+ case NSKeyUp:
+ return KeyboardEvent::create(event, m_frame->document() ? m_frame->document()->defaultView() : 0);
+ default:
+ return 0;
+ }
+}
+
+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
+{
+ static BOOL checkedSafari = NO;
+ static BOOL isSafari = NO;
+
+ if (!checkedSafari) {
+ isSafari = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Safari"];
+ checkedSafari = YES;
+ }
+
+ Document* document = m_frame->document();
+ if (!document)
+ return false;
+
+ // RSS view needs arrow key keypress events.
+ if (isSafari && document->url().protocolIs("feed") || document->url().protocolIs("feeds"))
+ return true;
+ Settings* settings = m_frame->settings();
+ if (!settings)
+ return false;
+
+#if ENABLE(DASHBOARD_SUPPORT)
+ if (settings->usesDashboardBackwardCompatibilityMode())
+ return true;
+#endif
+
+ if (settings->needsKeyboardEventDisambiguationQuirks())
+ return true;
+
+ return false;
+}
+
+bool EventHandler::keyEvent(NSEvent *event)
+{
+ bool result;
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
+
+ RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
+ currentEvent() = event;
+
+ result = keyEvent(PlatformKeyboardEvent(event));
+
+ ASSERT(currentEvent() == event);
+ currentEvent() = oldCurrentEvent;
+
+ return result;
+
+ 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(static_cast<RenderWidget*>(target)->widget());
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
+{
+ return passMouseDownEventToWidget(renderWidget->widget());
+}
+
+static bool lastEventIsMouseUp()
+{
+ // Many AK 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 khtml state with this mouseUp, which khtml never saw. This method lets us detect
+ // that state.
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
+ if (currentEvent() != currentEventAfterHandlingMouseDown &&
+ [currentEventAfterHandlingMouseDown type] == NSLeftMouseUp &&
+ [currentEventAfterHandlingMouseDown timestamp] >= [currentEvent().get() timestamp])
+ return true;
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return false;
+}
+
+bool EventHandler::passMouseDownEventToWidget(Widget* widget)
+{
+ // FIXME: this method always returns true
+
+ if (!widget) {
+ LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
+ return true;
+ }
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ NSView *nodeView = widget->platformWidget();
+ ASSERT(nodeView);
+ ASSERT([nodeView superview]);
+ NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentEvent().get() 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 ([currentEvent().get() 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;
+ [view mouseDown:currentEvent().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;
+}
+
+bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
+{
+ return m_activationEventNumber == event.eventNumber();
+}
+
+bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
+{
+ NSView *view = mouseDownViewIfStillGood();
+
+ if (!view)
+ return false;
+
+ if (!m_mouseDownWasInSubframe) {
+ m_sendingEventToSubview = true;
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ [view mouseDragged:currentEvent().get()];
+ END_BLOCK_OBJC_EXCEPTIONS;
+ m_sendingEventToSubview = false;
+ }
+
+ return true;
+}
+
+PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
+{
+ NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
+ // Must be done before ondragstart adds types and data to the pboard,
+ // also done for security, as it erases data from the last drag
+ [pasteboard declareTypes:[NSArray array] owner:nil];
+ return ClipboardMac::create(true, pasteboard, ClipboardWritable, m_frame);
+}
+
+bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
+{
+ NSView *view = mouseDownViewIfStillGood();
+ if (!view)
+ return false;
+
+ if (!m_mouseDownWasInSubframe) {
+ m_sendingEventToSubview = true;
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ [view mouseUp:currentEvent().get()];
+ END_BLOCK_OBJC_EXCEPTIONS;
+ m_sendingEventToSubview = false;
+ }
+
+ return true;
+}
+
+bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult* hoveredNode)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ switch ([currentEvent().get() type]) {
+ case NSMouseMoved:
+ // Since we're passing in currentEvent() here, we can call
+ // handleMouseMoveEvent() directly, since the save/restore of
+ // currentEvent() that mouseMoved() does would have no effect.
+ subframe->eventHandler()->handleMouseMoveEvent(currentEvent().get(), hoveredNode);
+ return true;
+
+ case NSLeftMouseDown: {
+ Node* node = event.targetNode();
+ if (!node)
+ return false;
+ RenderObject* renderer = node->renderer();
+ if (!renderer || !renderer->isWidget())
+ return false;
+ Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
+ if (!widget || !widget->isFrameView())
+ return false;
+ if (!passWidgetMouseDownEventToWidget(static_cast<RenderWidget*>(renderer)))
+ return false;
+ m_mouseDownWasInSubframe = true;
+ return true;
+ }
+ case NSLeftMouseUp: {
+ if (!m_mouseDownWasInSubframe)
+ return false;
+ NSView *view = mouseDownViewIfStillGood();
+ if (!view)
+ return false;
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ [view mouseUp:currentEvent().get()];
+ m_sendingEventToSubview = false;
+ return true;
+ }
+ case NSLeftMouseDragged: {
+ if (!m_mouseDownWasInSubframe)
+ return false;
+ NSView *view = mouseDownViewIfStillGood();
+ if (!view)
+ return false;
+ ASSERT(!m_sendingEventToSubview);
+ m_sendingEventToSubview = true;
+ [view mouseDragged:currentEvent().get()];
+ m_sendingEventToSubview = false;
+ return true;
+ }
+ default:
+ return false;
+ }
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return false;
+}
+
+bool EventHandler::passWheelEventToWidget(PlatformWheelEvent&, Widget* widget)
+{
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ if ([currentEvent().get() type] != NSScrollWheel || m_sendingEventToSubview || !widget)
+ return false;
+
+ NSView* nodeView = widget->platformWidget();
+ ASSERT(nodeView);
+ ASSERT([nodeView superview]);
+ NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentEvent().get() locationInWindow] fromView:nil]];
+ if (!view)
+ // We probably hit the border of a RenderWidget
+ return false;
+
+ m_sendingEventToSubview = true;
+ [view scrollWheel:currentEvent().get()];
+ 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;
+
+ RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
+ currentEvent() = event;
+ m_mouseDown = PlatformMouseEvent(event);
+
+ handleMousePressEvent(event);
+
+ ASSERT(currentEvent() == event);
+ currentEvent() = oldCurrentEvent;
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+void EventHandler::mouseDragged(NSEvent *event)
+{
+ FrameView* v = m_frame->view();
+ if (!v || m_sendingEventToSubview)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
+ currentEvent() = event;
+
+ handleMouseMoveEvent(event);
+
+ ASSERT(currentEvent() == event);
+ currentEvent() = oldCurrentEvent;
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+void EventHandler::mouseUp(NSEvent *event)
+{
+ FrameView* v = m_frame->view();
+ if (!v || m_sendingEventToSubview)
+ return;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
+ currentEvent() = 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(event);
+ else
+ handleMouseReleaseEvent(event);
+
+ ASSERT(currentEvent() == event);
+ currentEvent() = oldCurrentEvent;
+
+ 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;
+
+ RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
+ currentEvent() = event;
+
+ mouseMoved(PlatformMouseEvent(event));
+
+ ASSERT(currentEvent() == event);
+ currentEvent() = oldCurrentEvent;
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+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);
+}
+
+}
diff --git a/WebCore/page/mac/FrameMac.mm b/WebCore/page/mac/FrameMac.mm
new file mode 100644
index 0000000..66e2d04
--- /dev/null
+++ b/WebCore/page/mac/FrameMac.mm
@@ -0,0 +1,553 @@
+/*
+ * 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 "DocumentLoader.h"
+#import "EditorClient.h"
+#import "Event.h"
+#import "FrameLoaderClient.h"
+#import "FramePrivate.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 "UserStyleSheetLoader.h"
+#import "WebCoreViewFactory.h"
+#import "visible_units.h"
+
+#import <Carbon/Carbon.h>
+#import <runtime/JSLock.h>
+
+#if ENABLE(DASHBOARD_SUPPORT)
+#import "WebDashboardRegion.h"
+#endif
+
+@interface NSView (WebCoreHTMLDocumentView)
+- (void)drawSingleRect:(NSRect)rect;
+@end
+
+using namespace std;
+
+using JSC::JSLock;
+
+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)
+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;
+ static Vector<RegularExpression*> regExps;
+ static RegularExpression wordRegExp = RegularExpression("\\w");
+
+ 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.search(label.substring(0, 1)) >= 0;
+ endsWithWordChar = wordRegExp.search(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, false);
+ }
+
+ // 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::searchForNSLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell)
+{
+ RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer());
+
+ if (cellRenderer && cellRenderer->isTableCell()) {
+ RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer);
+
+ if (cellAboveRenderer) {
+ HTMLTableCellElement* aboveCell =
+ static_cast<HTMLTableCellElement*>(cellAboveRenderer->element());
+
+ if (aboveCell) {
+ // search within the above cell we found for a match
+ 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)
+ return nodeString.substring(pos, regExp->matchedLength());
+ }
+ }
+ }
+ }
+ }
+ // Any reason in practice to search all cells in that are above cell?
+ return nil;
+}
+
+NSString* Frame::searchForLabelsBeforeElement(NSArray* labels, Element* element)
+{
+ 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;
+
+ // 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<HTMLElement*>(n)->isGenericFormElement()))
+ {
+ // 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);
+ if (result && [result length] > 0)
+ 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)
+ 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);
+ if (result && [result length] > 0)
+ return result;
+ }
+
+ return nil;
+}
+
+NSString* Frame::matchLabelsAgainstElement(NSArray* labels, Element* element)
+{
+ String name = element->getAttribute(nameAttr);
+ if (name.isEmpty())
+ return nil;
+
+ // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
+ replace(name, RegularExpression("\\d"), " ");
+ name.replace('_', ' ');
+
+ RegularExpression* regExp = regExpForLabels(labels);
+ // Use the largest match we can find in the whole name string
+ int pos;
+ int length;
+ int bestPos = -1;
+ int bestLength = -1;
+ int start = 0;
+ do {
+ pos = regExp->search(name, start);
+ if (pos != -1) {
+ length = regExp->matchedLength();
+ if (length >= bestLength) {
+ bestPos = pos;
+ bestLength = length;
+ }
+ start = pos + 1;
+ }
+ } while (pos != -1);
+
+ if (bestPos != -1)
+ return name.substring(bestPos, bestLength);
+ return nil;
+}
+
+NSImage* Frame::imageFromRect(NSRect rect) const
+{
+ NSView* view = d->m_view->documentView();
+ if (!view)
+ return nil;
+ if (![view respondsToSelector:@selector(drawSingleRect:)])
+ return nil;
+
+ NSImage* resultImage;
+ 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];
+
+ 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];
+ }
+
+ return resultImage;
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return nil;
+}
+
+NSImage* Frame::selectionImage(bool forceBlackText) const
+{
+ d->m_view->setPaintRestriction(forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly);
+ d->m_doc->updateLayout();
+ NSImage* result = imageFromRect(selectionRect());
+ d->m_view->setPaintRestriction(PaintRestrictionNone);
+ 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)
+ d->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);
+
+ d->m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode
+ NSImage* result = imageFromRect(paintingRect);
+ renderer->updateDragState(false);
+ d->m_doc->updateLayout();
+ d->m_view->setNodeToDraw(0);
+
+ if (elementRect)
+ *elementRect = topLevelRect;
+ if (imageRect)
+ *imageRect = paintingRect;
+ return result;
+}
+
+NSImage* Frame::nodeImage(Node* node) const
+{
+ RenderObject* renderer = node->renderer();
+ if (!renderer)
+ return nil;
+
+ d->m_doc->updateLayout(); // forces style recalc
+
+ IntRect topLevelRect;
+ NSRect paintingRect = renderer->paintingRootRect(topLevelRect);
+
+ d->m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode
+ NSImage* result = imageFromRect(paintingRect);
+ d->m_view->setNodeToDraw(0);
+
+ return result;
+}
+
+NSDictionary* Frame::fontAttributesForSelectionStart() const
+{
+ Node* nodeToRemove;
+ RenderStyle* style = styleForSelectionStart(nodeToRemove);
+ if (!style)
+ return nil;
+
+ NSMutableDictionary* result = [NSMutableDictionary dictionary];
+
+ if (style->backgroundColor().isValid() && style->backgroundColor().alpha() != 0)
+ [result setObject:nsColor(style->backgroundColor()) forKey:NSBackgroundColorAttributeName];
+
+ if (style->font().primaryFont()->getNSFont())
+ [result setObject:style->font().primaryFont()->getNSFont() forKey:NSFontAttributeName];
+
+ if (style->color().isValid() && style->color() != Color::black)
+ [result setObject:nsColor(style->color()) forKey:NSForegroundColorAttributeName];
+
+ ShadowData* shadow = style->textShadow();
+ if (shadow) {
+ NSShadow* s = [[NSShadow alloc] init];
+ [s setShadowOffset:NSMakeSize(shadow->x, shadow->y)];
+ [s setShadowBlurRadius:shadow->blur];
+ [s setShadowColor:nsColor(shadow->color)];
+ [result setObject:s forKey:NSShadowAttributeName];
+ }
+
+ int decoration = style->textDecorationsInEffect();
+ if (decoration & LINE_THROUGH)
+ [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
+
+ int superscriptInt = 0;
+ switch (style->verticalAlign()) {
+ case BASELINE:
+ case BOTTOM:
+ case BASELINE_MIDDLE:
+ case LENGTH:
+ case MIDDLE:
+ case TEXT_BOTTOM:
+ case TEXT_TOP:
+ case TOP:
+ break;
+ case SUB:
+ superscriptInt = -1;
+ break;
+ case SUPER:
+ superscriptInt = 1;
+ break;
+ }
+ if (superscriptInt)
+ [result setObject:[NSNumber numberWithInt:superscriptInt] forKey:NSSuperscriptAttributeName];
+
+ if (decoration & UNDERLINE)
+ [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
+
+ if (nodeToRemove) {
+ ExceptionCode ec = 0;
+ nodeToRemove->remove(ec);
+ ASSERT(ec == 0);
+ }
+
+ return result;
+}
+
+NSWritingDirection Frame::baseWritingDirectionForSelectionStart() const
+{
+ NSWritingDirection result = NSWritingDirectionLeftToRight;
+
+ Position pos = selection()->selection().visibleStart().deepEquivalent();
+ Node* node = pos.node();
+ if (!node)
+ return result;
+
+ RenderObject* renderer = node->renderer();
+ if (!renderer)
+ return result;
+
+ if (!renderer->isBlockFlow()) {
+ renderer = renderer->containingBlock();
+ if (!renderer)
+ return result;
+ }
+
+ RenderStyle* style = renderer->style();
+ if (!style)
+ return result;
+
+ switch (style->direction()) {
+ case LTR:
+ result = NSWritingDirectionLeftToRight;
+ break;
+ case RTL:
+ result = NSWritingDirectionRightToLeft;
+ break;
+ }
+
+ return result;
+}
+
+const short enableRomanKeyboardsOnly = -23;
+void Frame::setUseSecureKeyboardEntry(bool enable)
+{
+ if (enable == IsSecureEventInputEnabled())
+ return;
+ if (enable) {
+ EnableSecureEventInput();
+#ifdef BUILDING_ON_TIGER
+ KeyScript(enableRomanKeyboardsOnly);
+#else
+ CFArrayRef inputSources = TISCreateASCIICapableInputSourceList();
+ TSMSetDocumentProperty(TSMGetActiveDocument(), kTSMDocumentEnabledInputSourcesPropertyTag, sizeof(CFArrayRef), &inputSources);
+ CFRelease(inputSources);
+#endif
+ } else {
+ DisableSecureEventInput();
+#ifdef BUILDING_ON_TIGER
+ KeyScript(smKeyEnableKybds);
+#else
+ TSMRemoveDocumentProperty(TSMGetActiveDocument(), kTSMDocumentEnabledInputSourcesPropertyTag);
+#endif
+ }
+}
+
+#if ENABLE(DASHBOARD_SUPPORT)
+NSMutableDictionary* Frame::dashboardRegionsDictionary()
+{
+ Document* doc = document();
+ if (!doc)
+ return nil;
+
+ const Vector<DashboardRegionValue>& regions = doc->dashboardRegions();
+ size_t n = regions.size();
+
+ // Convert the Vector<DashboardRegionValue> into a NSDictionary of WebDashboardRegions
+ NSMutableDictionary* webRegions = [NSMutableDictionary dictionaryWithCapacity:n];
+ for (size_t i = 0; i < n; i++) {
+ const DashboardRegionValue& region = regions[i];
+
+ if (region.type == StyleDashboardRegion::None)
+ continue;
+
+ NSString *label = region.label;
+ WebDashboardRegionType type = WebDashboardRegionTypeNone;
+ if (region.type == StyleDashboardRegion::Circle)
+ type = WebDashboardRegionTypeCircle;
+ else if (region.type == StyleDashboardRegion::Rectangle)
+ type = WebDashboardRegionTypeRectangle;
+ NSMutableArray *regionValues = [webRegions objectForKey:label];
+ if (!regionValues) {
+ regionValues = [[NSMutableArray alloc] initWithCapacity:1];
+ [webRegions setObject:regionValues forKey:label];
+ [regionValues release];
+ }
+
+ WebDashboardRegion *webRegion = [[WebDashboardRegion alloc] initWithRect:region.bounds clip:region.clip type:type];
+ [regionValues addObject:webRegion];
+ [webRegion release];
+ }
+
+ return webRegions;
+}
+#endif
+
+DragImageRef Frame::dragImageForSelection()
+{
+ if (!selection()->isRange())
+ return nil;
+ return selectionImage();
+}
+
+void Frame::setUserStyleSheetLocation(const KURL& url)
+{
+ delete d->m_userStyleSheetLoader;
+ d->m_userStyleSheetLoader = 0;
+ if (d->m_doc && d->m_doc->docLoader())
+ d->m_userStyleSheetLoader = new UserStyleSheetLoader(d->m_doc, url.string());
+}
+
+void Frame::setUserStyleSheet(const String& styleSheet)
+{
+ delete d->m_userStyleSheetLoader;
+ d->m_userStyleSheetLoader = 0;
+ if (d->m_doc)
+ d->m_doc->setUserStyleSheet(styleSheet);
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/mac/PageMac.cpp b/WebCore/page/mac/PageMac.cpp
new file mode 100644
index 0000000..7386eea
--- /dev/null
+++ b/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/WebCore/page/mac/WebCoreFrameView.h b/WebCore/page/mac/WebCoreFrameView.h
new file mode 100644
index 0000000..977b1a7
--- /dev/null
+++ b/WebCore/page/mac/WebCoreFrameView.h
@@ -0,0 +1,40 @@
+/*
+ * 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;
+@end
+
+@protocol WebCoreFrameView
+- (WebCore::Frame*)_web_frame;
+@end
diff --git a/WebCore/page/mac/WebCoreKeyboardUIMode.h b/WebCore/page/mac/WebCoreKeyboardUIMode.h
new file mode 100644
index 0000000..187cf09
--- /dev/null
+++ b/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/WebCore/page/mac/WebCoreViewFactory.h b/WebCore/page/mac/WebCoreViewFactory.h
new file mode 100644
index 0000000..4caef54
--- /dev/null
+++ b/WebCore/page/mac/WebCoreViewFactory.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2003, 2005 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.
+ */
+
+@class WebCoreTextMarker;
+@class WebCoreTextMarkerRange;
+
+@protocol WebCoreViewFactory
+
+- (NSArray *)pluginsInfo; // array of id <WebCorePluginInfo>
+- (void)refreshPlugins;
+
+- (NSString *)inputElementAltText;
+- (NSString *)resetButtonDefaultLabel;
+- (NSString *)searchableIndexIntroduction;
+- (NSString *)submitButtonDefaultLabel;
+- (NSString *)fileButtonChooseFileLabel;
+- (NSString *)fileButtonNoFileSelectedLabel;
+- (NSString *)copyImageUnknownFileLabel;
+
+// Context menu item titles
+- (NSString *)contextMenuItemTagOpenLinkInNewWindow;
+- (NSString *)contextMenuItemTagDownloadLinkToDisk;
+- (NSString *)contextMenuItemTagCopyLinkToClipboard;
+- (NSString *)contextMenuItemTagOpenImageInNewWindow;
+- (NSString *)contextMenuItemTagDownloadImageToDisk;
+- (NSString *)contextMenuItemTagCopyImageToClipboard;
+- (NSString *)contextMenuItemTagOpenFrameInNewWindow;
+- (NSString *)contextMenuItemTagCopy;
+- (NSString *)contextMenuItemTagGoBack;
+- (NSString *)contextMenuItemTagGoForward;
+- (NSString *)contextMenuItemTagStop;
+- (NSString *)contextMenuItemTagReload;
+- (NSString *)contextMenuItemTagCut;
+- (NSString *)contextMenuItemTagPaste;
+- (NSString *)contextMenuItemTagNoGuessesFound;
+- (NSString *)contextMenuItemTagIgnoreSpelling;
+- (NSString *)contextMenuItemTagLearnSpelling;
+- (NSString *)contextMenuItemTagSearchInSpotlight;
+- (NSString *)contextMenuItemTagSearchWeb;
+- (NSString *)contextMenuItemTagLookUpInDictionary;
+- (NSString *)contextMenuItemTagOpenLink;
+- (NSString *)contextMenuItemTagIgnoreGrammar;
+- (NSString *)contextMenuItemTagSpellingMenu;
+- (NSString *)contextMenuItemTagShowSpellingPanel:(bool)show;
+- (NSString *)contextMenuItemTagCheckSpelling;
+- (NSString *)contextMenuItemTagCheckSpellingWhileTyping;
+- (NSString *)contextMenuItemTagCheckGrammarWithSpelling;
+- (NSString *)contextMenuItemTagFontMenu;
+- (NSString *)contextMenuItemTagShowFonts;
+- (NSString *)contextMenuItemTagBold;
+- (NSString *)contextMenuItemTagItalic;
+- (NSString *)contextMenuItemTagUnderline;
+- (NSString *)contextMenuItemTagOutline;
+- (NSString *)contextMenuItemTagStyles;
+- (NSString *)contextMenuItemTagShowColors;
+- (NSString *)contextMenuItemTagSpeechMenu;
+- (NSString *)contextMenuItemTagStartSpeaking;
+- (NSString *)contextMenuItemTagStopSpeaking;
+- (NSString *)contextMenuItemTagWritingDirectionMenu;
+- (NSString *)contextMenuItemTagDefaultDirection;
+- (NSString *)contextMenuItemTagLeftToRight;
+- (NSString *)contextMenuItemTagRightToLeft;
+- (NSString *)contextMenuItemTagInspectElement;
+
+- (NSString *)searchMenuNoRecentSearchesText;
+- (NSString *)searchMenuRecentSearchesText;
+- (NSString *)searchMenuClearRecentSearchesText;
+
+- (NSString *)defaultLanguageCode;
+
+- (NSString *)imageTitleForFilename:(NSString *)filename width:(int)width height:(int)height;
+
+- (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;
+
+- (AXUIElementRef)AXUIElementForElement:(id)element;
+- (void)unregisterUniqueIdForUIElement:(id)element;
+
+- (NSString *)AXWebAreaText;
+- (NSString *)AXLinkText;
+- (NSString *)AXListMarkerText;
+- (NSString *)AXImageMapText;
+- (NSString *)AXHeadingText;
+- (NSString *)AXDefinitionListTermText;
+- (NSString *)AXDefinitionListDefinitionText;
+
+- (NSString *)AXButtonActionVerb;
+- (NSString *)AXRadioButtonActionVerb;
+- (NSString *)AXTextFieldActionVerb;
+- (NSString *)AXCheckedCheckBoxActionVerb;
+- (NSString *)AXUncheckedCheckBoxActionVerb;
+- (NSString *)AXLinkActionVerb;
+
+- (NSString *)multipleFileUploadTextForNumberOfFiles:(unsigned)numberOfFiles;
+// FTP Directory Related
+- (NSString *)unknownFileSizeText;
+
+@end
+
+@interface WebCoreViewFactory : NSObject
++ (WebCoreViewFactory *)sharedFactory;
+@end
+
+@interface WebCoreViewFactory (SubclassResponsibility) <WebCoreViewFactory>
+@end
+
+@protocol WebCorePluginInfo <NSObject>
+- (NSString *)name;
+- (NSString *)filename;
+- (NSString *)pluginDescription;
+- (NSEnumerator *)MIMETypeEnumerator;
+- (NSString *)descriptionForMIMEType:(NSString *)MIMEType;
+- (NSArray *)extensionsForMIMEType:(NSString *)MIMEType;
+@end
+
diff --git a/WebCore/page/mac/WebCoreViewFactory.m b/WebCore/page/mac/WebCoreViewFactory.m
new file mode 100644
index 0000000..5398989
--- /dev/null
+++ b/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/WebCore/page/mac/WebDashboardRegion.h b/WebCore/page/mac/WebDashboardRegion.h
new file mode 100644
index 0000000..4963d04
--- /dev/null
+++ b/WebCore/page/mac/WebDashboardRegion.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2004 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.
+ */
+
+#if !defined(ENABLE_DASHBOARD_SUPPORT)
+#define ENABLE_DASHBOARD_SUPPORT 1
+#endif
+
+#if ENABLE_DASHBOARD_SUPPORT
+
+typedef enum {
+ WebDashboardRegionTypeNone,
+ WebDashboardRegionTypeCircle,
+ WebDashboardRegionTypeRectangle,
+ WebDashboardRegionTypeScrollerRectangle
+} WebDashboardRegionType;
+
+@interface WebDashboardRegion : NSObject <NSCopying>
+{
+ NSRect rect;
+ NSRect clip;
+ WebDashboardRegionType type;
+}
+- initWithRect:(NSRect)rect clip:(NSRect)clip type:(WebDashboardRegionType)type;
+- (NSRect)dashboardRegionClip;
+- (NSRect)dashboardRegionRect;
+- (WebDashboardRegionType)dashboardRegionType;
+@end
+
+#endif
diff --git a/WebCore/page/mac/WebDashboardRegion.m b/WebCore/page/mac/WebDashboardRegion.m
new file mode 100644
index 0000000..d2eb07f
--- /dev/null
+++ b/WebCore/page/mac/WebDashboardRegion.m
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2004 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 "WebDashboardRegion.h"
+
+#if ENABLE(DASHBOARD_SUPPORT)
+@implementation WebDashboardRegion
+- initWithRect:(NSRect)r clip:(NSRect)c type:(WebDashboardRegionType)t
+{
+ self = [super init];
+ rect = r;
+ clip = c;
+ type = t;
+ return self;
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+ return [self retain];
+}
+
+- (NSRect)dashboardRegionClip
+{
+ return clip;
+}
+
+- (NSRect)dashboardRegionRect
+{
+ return rect;
+}
+
+- (WebDashboardRegionType)dashboardRegionType
+{
+ return type;
+}
+
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"rect:%@ clip:%@ type:%s",
+ NSStringFromRect(rect),
+ NSStringFromRect(clip),
+ type == WebDashboardRegionTypeNone ? "None" :
+ (type == WebDashboardRegionTypeCircle ? "Circle" :
+ (type == WebDashboardRegionTypeRectangle ? "Rectangle" :
+ (type == WebDashboardRegionTypeScrollerRectangle ? "ScrollerRectangle" :
+ "Unknown")))];
+}
+
+- (BOOL)isEqual:(id)other
+{
+ return NSEqualRects (rect, [other dashboardRegionRect]) && NSEqualRects (clip, [other dashboardRegionClip]) && type == [other dashboardRegionType];
+}
+
+@end
+#endif
diff --git a/WebCore/page/qt/AccessibilityObjectQt.cpp b/WebCore/page/qt/AccessibilityObjectQt.cpp
new file mode 100644
index 0000000..b755645
--- /dev/null
+++ b/WebCore/page/qt/AccessibilityObjectQt.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 Apple Ltd.
+ *
+ * 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 "AccessibilityObject.h"
+
+namespace WebCore {
+
+bool AccessibilityObject::accessibilityIgnoreAttachment() const
+{
+ return false;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/qt/DragControllerQt.cpp b/WebCore/page/qt/DragControllerQt.cpp
new file mode 100644
index 0000000..62372d0
--- /dev/null
+++ b/WebCore/page/qt/DragControllerQt.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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;
+}
+
+}
diff --git a/WebCore/page/qt/EventHandlerQt.cpp b/WebCore/page/qt/EventHandlerQt.cpp
new file mode 100644
index 0000000..421caaf
--- /dev/null
+++ b/WebCore/page/qt/EventHandlerQt.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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 "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformWheelEvent.h"
+#include "RenderWidget.h"
+#include "Scrollbar.h"
+#include "NotImplemented.h"
+
+QT_BEGIN_NAMESPACE
+extern Q_GUI_EXPORT bool qt_tab_all_widgets; // from qapplication.cpp
+QT_END_NAMESPACE
+
+namespace WebCore {
+
+unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::CtrlKey;
+
+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 (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, true);
+}
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMousePressEvent(mev.event());
+ return true;
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
+{
+ subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
+ return true;
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
+ return true;
+}
+
+}
diff --git a/WebCore/page/qt/FrameQt.cpp b/WebCore/page/qt/FrameQt.cpp
new file mode 100644
index 0000000..1bbbff5
--- /dev/null
+++ b/WebCore/page/qt/FrameQt.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 "FramePrivate.h"
+#include "UserStyleSheetLoader.h"
+
+namespace WebCore {
+
+DragImageRef Frame::dragImageForSelection()
+{
+ return 0;
+}
+
+void Frame::setUserStyleSheetLocation(const KURL& url)
+{
+ delete d->m_userStyleSheetLoader;
+ d->m_userStyleSheetLoader = 0;
+ if (d->m_doc && d->m_doc->docLoader())
+ d->m_userStyleSheetLoader = new UserStyleSheetLoader(d->m_doc, url.string());
+}
+
+void Frame::setUserStyleSheet(const String& styleSheet)
+{
+ delete d->m_userStyleSheetLoader;
+ d->m_userStyleSheetLoader = 0;
+ if (d->m_doc)
+ d->m_doc->setUserStyleSheet(styleSheet);
+}
+
+}
+// vim: ts=4 sw=4 et
diff --git a/WebCore/page/win/AXObjectCacheWin.cpp b/WebCore/page/win/AXObjectCacheWin.cpp
new file mode 100644
index 0000000..da30ac5
--- /dev/null
+++ b/WebCore/page/win/AXObjectCacheWin.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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 "AXObjectCache.h"
+
+#include "AccessibilityObject.h"
+
+namespace WebCore {
+
+void AXObjectCache::detachWrapper(AccessibilityObject* obj)
+{
+ // On Windows, AccessibilityObjects are created when get_accChildCount is
+ // called, but they are not wrapped until get_accChild is called, so this
+ // object may not have a wrapper.
+ if (AccessibilityObjectWrapper* wrapper = obj->wrapper())
+ wrapper->detach();
+}
+
+void AXObjectCache::attachWrapper(AccessibilityObject*)
+{
+ // On Windows, AccessibilityObjects are wrapped when the accessibility
+ // software requests them via get_accChild.
+}
+
+void AXObjectCache::postNotification(RenderObject*, const String&)
+{
+}
+
+void AXObjectCache::postNotificationToElement(RenderObject*, const String&)
+{
+}
+
+void AXObjectCache::handleFocusedUIElementChanged()
+{
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/win/AccessibilityObjectWin.cpp b/WebCore/page/win/AccessibilityObjectWin.cpp
new file mode 100644
index 0000000..e309ac8
--- /dev/null
+++ b/WebCore/page/win/AccessibilityObjectWin.cpp
@@ -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.
+ */
+
+
+#include "config.h"
+#include "AccessibilityObject.h"
+
+namespace WebCore {
+
+bool AccessibilityObject::accessibilityIgnoreAttachment() const
+{
+ return false;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/win/AccessibilityObjectWrapperWin.h b/WebCore/page/win/AccessibilityObjectWrapperWin.h
new file mode 100644
index 0000000..779443c
--- /dev/null
+++ b/WebCore/page/win/AccessibilityObjectWrapperWin.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 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 AccessibilityObjectWrapperWin_h
+#define AccessibilityObjectWrapperWin_h
+
+namespace WebCore {
+
+ class AccessibilityObject;
+
+ class AccessibilityObjectWrapper : public IUnknown {
+ public:
+ // IUnknown
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) = 0;
+ virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
+ virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
+
+ virtual void detach() = 0;
+ bool attached() const { return m_object; }
+ AccessibilityObject* accessibilityObject() const { return m_object; }
+
+ protected:
+ AccessibilityObjectWrapper(AccessibilityObject* obj) : m_object(obj) { }
+ AccessibilityObjectWrapper() : m_object(0) { }
+
+ AccessibilityObject* m_object;
+ };
+
+} // namespace WebCore
+
+#endif // AccessibilityObjectWrapperWin_h
diff --git a/WebCore/page/win/DragControllerWin.cpp b/WebCore/page/win/DragControllerWin.cpp
new file mode 100644
index 0000000..41f3008
--- /dev/null
+++ b/WebCore/page/win/DragControllerWin.cpp
@@ -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.
+ *
+ * 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;
+}
+
+}
diff --git a/WebCore/page/win/EventHandlerWin.cpp b/WebCore/page/win/EventHandlerWin.cpp
new file mode 100644
index 0000000..bfd2b02
--- /dev/null
+++ b/WebCore/page/win/EventHandlerWin.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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 "EventHandler.h"
+
+#include "ClipboardWin.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"
+
+namespace WebCore {
+
+unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::AltKey;
+
+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.activatedWebView();
+}
+
+PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
+{
+ COMPtr<WCDataObject> dataObject;
+ WCDataObject::createInstance(&dataObject);
+ return ClipboardWin::create(true, dataObject.get(), ClipboardWritable);
+}
+
+void EventHandler::focusDocumentView()
+{
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+ page->focusController()->setFocusedFrame(m_frame);
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults&)
+{
+ notImplemented();
+ return false;
+}
+
+}
diff --git a/WebCore/page/win/FrameCGWin.cpp b/WebCore/page/win/FrameCGWin.cpp
new file mode 100644
index 0000000..ad22967
--- /dev/null
+++ b/WebCore/page/win/FrameCGWin.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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 "FrameView.h"
+#include "GraphicsContext.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);
+}
+
+HBITMAP imageFromSelection(Frame* frame, bool forceBlackText)
+{
+ frame->view()->setPaintRestriction(forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly);
+ FloatRect fr = frame->selectionRect();
+ IntRect ir(static_cast<int>(fr.x()), static_cast<int>(fr.y()),
+ static_cast<int>(fr.width()), static_cast<int>(fr.height()));
+
+ void* bits;
+ HDC hdc = CreateCompatibleDC(0);
+ int w = ir.width();
+ int h = ir.height();
+ BITMAPINFO bmp = { { sizeof(BITMAPINFOHEADER), w, h, 1, 32 } };
+
+ HBITMAP hbmp = CreateDIBSection(0, &bmp, DIB_RGB_COLORS, static_cast<void**>(&bits), 0, 0);
+ HBITMAP hbmpOld = static_cast<HBITMAP>(SelectObject(hdc, hbmp));
+ CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
+ CGContextRef context = CGBitmapContextCreate(static_cast<void*>(bits), w, h,
+ 8, w * sizeof(RGBQUAD), deviceRGB, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
+ CGColorSpaceRelease(deviceRGB);
+ CGContextSaveGState(context);
+
+ GraphicsContext gc(context);
+
+ frame->document()->updateLayout();
+ drawRectIntoContext(ir, frame->view(), &gc);
+
+ CGContextRelease(context);
+ SelectObject(hdc, hbmpOld);
+ DeleteDC(hdc);
+
+ frame->view()->setPaintRestriction(PaintRestrictionNone);
+
+ return hbmp;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/win/FrameCairoWin.cpp b/WebCore/page/win/FrameCairoWin.cpp
new file mode 100644
index 0000000..a645a10
--- /dev/null
+++ b/WebCore/page/win/FrameCairoWin.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 "FrameWin.h"
+
+#include "EditorClient.h"
+#include "NotImplemented.h"
+
+using std::min;
+
+namespace WebCore {
+
+HBITMAP imageFromSelection(Frame* frame, bool forceBlackText)
+{
+ notImplemented();
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/win/FrameWin.cpp b/WebCore/page/win/FrameWin.cpp
new file mode 100644
index 0000000..536f5d8
--- /dev/null
+++ b/WebCore/page/win/FrameWin.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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 "runtime.h"
+#include "FrameWin.h"
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "Document.h"
+#include "FramePrivate.h"
+#include "RenderView.h"
+#include "Settings.h"
+
+using std::min;
+
+namespace WebCore {
+
+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 = static_cast<RenderView*>(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 = static_cast<float>(printRect.height()) / static_cast<float>(printRect.width());
+
+ float pageWidth = static_cast<float>(root->docWidth());
+ float pageHeight = pageWidth * ratio;
+ outPageHeight = static_cast<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.0f;
+ do {
+ float proposedBottom = min(docHeight, printedPagesHeight + pageHeight);
+ frame->adjustPageHeight(&proposedBottom, printedPagesHeight, proposedBottom, printedPagesHeight);
+ currPageHeight = max(1.0f, proposedBottom - printedPagesHeight);
+
+ pages.append(IntRect(0, printedPagesHeight, currPageWidth, currPageHeight));
+ printedPagesHeight += currPageHeight;
+ } while (printedPagesHeight < docHeight);
+}
+
+DragImageRef Frame::dragImageForSelection()
+{
+ if (selection()->isRange())
+ return imageFromSelection(this, false);
+
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/win/FrameWin.h b/WebCore/page/win/FrameWin.h
new file mode 100644
index 0000000..405c7b2
--- /dev/null
+++ b/WebCore/page/win/FrameWin.h
@@ -0,0 +1,41 @@
+/*
+ * 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 "Frame.h"
+
+// Forward declared so we don't need wingdi.h.
+typedef struct HBITMAP__* HBITMAP;
+
+namespace WebCore {
+
+ HBITMAP imageFromSelection(Frame* frame, bool forceWhiteText);
+ void computePageRectsForFrame(Frame*, const IntRect& printRect, float headerHeight, float footerHeight, float userScaleFactor,Vector<IntRect>& pages, int& pageHeight);
+
+}
+
+#endif
diff --git a/WebCore/page/win/PageWin.cpp b/WebCore/page/win/PageWin.cpp
new file mode 100644
index 0000000..f4c744a
--- /dev/null
+++ b/WebCore/page/win/PageWin.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "Page.h"
+
+#include "Frame.h"
+#include "FrameView.h"
+#include "FloatRect.h"
+#include <windows.h>
+
+namespace WebCore {
+
+HINSTANCE Page::s_instanceHandle = 0;
+
+} // namespace WebCore
diff --git a/WebCore/page/wx/AccessibilityObjectWx.cpp b/WebCore/page/wx/AccessibilityObjectWx.cpp
new file mode 100644
index 0000000..b755645
--- /dev/null
+++ b/WebCore/page/wx/AccessibilityObjectWx.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 Apple Ltd.
+ *
+ * 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 "AccessibilityObject.h"
+
+namespace WebCore {
+
+bool AccessibilityObject::accessibilityIgnoreAttachment() const
+{
+ return false;
+}
+
+} // namespace WebCore
diff --git a/WebCore/page/wx/DragControllerWx.cpp b/WebCore/page/wx/DragControllerWx.cpp
new file mode 100644
index 0000000..659364f
--- /dev/null
+++ b/WebCore/page/wx/DragControllerWx.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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;
+}
+
+}
diff --git a/WebCore/page/wx/EventHandlerWx.cpp b/WebCore/page/wx/EventHandlerWx.cpp
new file mode 100644
index 0000000..ce4473f
--- /dev/null
+++ b/WebCore/page/wx/EventHandlerWx.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "RenderWidget.h"
+#include "Scrollbar.h"
+
+namespace WebCore {
+
+unsigned EventHandler::s_accessKeyModifiers = PlatformKeyboardEvent::AltKey;
+
+const double EventHandler::TextDragDelay = 0.0;
+
+bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ return passSubframeEventToSubframe(mev, subframe);
+}
+
+bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, WebCore::HitTestResult* hittest)
+{
+ return passSubframeEventToSubframe(mev, subframe);
+}
+
+bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
+{
+ return passSubframeEventToSubframe(mev, subframe);
+}
+
+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(static_cast<RenderWidget*>(event.targetNode()->renderer())->widget());
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
+{
+ return passMouseDownEventToWidget(renderWidget->widget());
+}
+
+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, true);
+}
+
+}