[iOS] Upstream WebCore/page changes
https://bugs.webkit.org/show_bug.cgi?id=126180

Reviewed by Darin Adler.

Source/WebCore:

* WebCore.xcodeproj/project.pbxproj:
* dom/EventNames.h:
(WebCore::EventNames::isGestureEventType): Added.
* page/AlternativeTextClient.h: Do not define WTF_USE_DICTATION_ALTERNATIVES when building for iOS.
* page/Chrome.cpp:
(WebCore::Chrome::Chrome):
(WebCore::Chrome::dispatchViewportPropertiesDidChange): Added; guarded by PLATFORM(IOS).
(WebCore::Chrome::setCursor): Make this an empty function when building for iOS.
(WebCore::Chrome::setCursorHiddenUntilMouseMoves): Ditto.
(WebCore::Chrome::didReceiveDocType): Added; iOS-specific.
* page/Chrome.h:
(WebCore::Chrome::setDispatchViewportDataDidChangeSuppressed): Added; guarded by PLATFORM(IOS).
* page/ChromeClient.h:
(WebCore::ChromeClient::didFlushCompositingLayers): Added; guarded by PLATFORM(IOS).
(WebCore::ChromeClient::fetchCustomFixedPositionLayoutRect): Added; guarded by PLATFORM(IOS).
(WebCore::ChromeClient::updateViewportConstrainedLayers): Added; guarded by PLATFORM(IOS).
* page/DOMTimer.cpp:
(WebCore::DOMTimer::install): Added iOS-specific code.
(WebCore::DOMTimer::fired): Ditto.
* page/DOMWindow.cpp:
(WebCore::DOMWindow::DOMWindow): Ditto.
(WebCore::DOMWindow::innerHeight): Ditto.
(WebCore::DOMWindow::innerWidth): Ditto.
(WebCore::DOMWindow::scrollX): Ditto.
(WebCore::DOMWindow::scrollY): Ditto.
(WebCore::DOMWindow::scrollBy): Ditto.
(WebCore::DOMWindow::scrollTo): Ditto.
(WebCore::DOMWindow::clearTimeout): Ditto.
(WebCore::DOMWindow::addEventListener): Ditto.
(WebCore::DOMWindow::incrementScrollEventListenersCount): Added; guarded by PLATFORM(IOS).
(WebCore::DOMWindow::decrementScrollEventListenersCount): Added; guarded by PLATFORM(IOS).
(WebCore::DOMWindow::resetAllGeolocationPermission): Added; Also added FIXME comment.
(WebCore::DOMWindow::removeEventListener): Added iOS-specific code.
(WebCore::DOMWindow::dispatchEvent): Modified to prevent dispatching duplicate pageshow and pagehide
events per <http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#event-pageshow>.
(WebCore::DOMWindow::removeAllEventListeners): Added iOS-specific code.
* page/DOMWindow.h:
* page/DOMWindow.idl: Added IOS_GESTURE_EVENTS-guarded attributes: ongesture{change, end, start}. Also
added IOS_TOUCH_EVENTS-guarded attributes: {Touch, TouchList}Constructor.
* page/EditorClient.h:
* page/EventHandler.cpp:
(WebCore::EventHandler::EventHandler): Added iOS-specific code.
(WebCore::EventHandler::clear): Ditto.
(WebCore::EventHandler::startPanScrolling): Make this an empty function when building for iOS.
(WebCore::EventHandler::handleMousePressEvent): Modified to invalidate a click when the clicked node is
null. Also, opt out of code for updating the scrollbars as UIKit manages scrollbars on iOS.
(WebCore::EventHandler::handleMouseMoveEvent): Opt of code for updating the scrollbars and cursor when building on iOS.
(WebCore::hitTestResultInFrame): Made this a file-local static function since it's only used in EventHandler.cpp.
(WebCore::EventHandler::dispatchSyntheticTouchEventIfEnabled): Added iOS-specific code.
* page/EventHandler.h:
* page/FocusController.h:
* page/Frame.cpp:
(WebCore::Frame::Frame): Added iOS-specific code.
(WebCore::Frame::scrollOverflowLayer): Added; iOS-specific.
(WebCore::Frame::overflowAutoScrollTimerFired): Added; iOS-specific.
(WebCore::Frame::startOverflowAutoScroll): Added; iOS-specific.
(WebCore::Frame::checkOverflowScroll): Added; iOS-specific.
(WebCore::Frame::willDetachPage): Added iOS-specific code.
(WebCore::Frame::createView): Ditto.
(WebCore::Frame::setSelectionChangeCallbacksDisabled): Added; iOS-specific.
(WebCore::Frame::selectionChangeCallbacksDisabled): Added; iOS-specific.
* page/Frame.h:
(WebCore::Frame::timersPaused): Added; guarded by PLATFORM(IOS).
* page/FrameView.cpp:
(WebCore::FrameView::FrameView): Added iOS-specific code.
(WebCore::FrameView::clear): Ditto.
(WebCore::FrameView::flushCompositingStateForThisFrame): Ditto.
(WebCore::FrameView::graphicsLayerForPlatformWidget): Added.
(WebCore::FrameView::scheduleLayerFlushAllowingThrottling): Added.
(WebCore::FrameView::layout): Added iOS-specific code.
(WebCore::countRenderedCharactersInRenderObjectWithThreshold): Added; helper function used by FrameView::renderedCharactersExceed().
Also added FIXME comment.
(WebCore::FrameView::renderedCharactersExceed): Added.
(WebCore::FrameView::visibleContentsResized): Added iOS-specific code.
(WebCore::FrameView::adjustTiledBackingCoverage): Ditto.
(WebCore::FrameView::performPostLayoutTasks): Ditto.
(WebCore::FrameView::sendResizeEventIfNeeded): Ditto.
(WebCore::FrameView::paintContents): Added iOS-specific code. Also added FIXME comments.
(WebCore::FrameView::setUseCustomFixedPositionLayoutRect): Added; iOS-specific.
(WebCore::FrameView::setCustomFixedPositionLayoutRect): Added; iOS-specific.
(WebCore::FrameView::updateFixedPositionLayoutRect): Added; iOS-specific.
* page/FrameView.h:
* page/Navigator.cpp:
(WebCore::Navigator::standalone): Added; iOS-specific.
* page/Navigator.h:
* page/Navigator.idl: Added WTF_PLATFORM_IOS-guarded attribute: standalone. Also added FIXME comment.
* page/NavigatorBase.cpp:
(WebCore::NavigatorBase::platform): Added iOS-specific code.
* page/Page.h:
(WebCore::Page::hasCustomHTMLTokenizerTimeDelay): Added; guarded by PLATFORM(IOS). Also added FIXME comment
to remove this method.
(WebCore::Page::customHTMLTokenizerTimeDelay): Added; guarded by PLATFORM(IOS). Also added FIXME comment
to remove this method.
* page/PageGroup.cpp:
(WebCore::PageGroup::removeVisitedLink): Added.
* page/PageGroup.h:
* page/Settings.cpp:
(WebCore::Settings::Settings):
(WebCore::Settings::setScriptEnabled): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::setStandalone): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::setAudioSessionCategoryOverride): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::audioSessionCategoryOverride): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::setNetworkDataUsageTrackingEnabled): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::networkDataUsageTrackingEnabled): Added; guarded by PLATFORM(IOS).
(WebCore::sharedNetworkInterfaceNameGlobal): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::setNetworkInterfaceName): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::networkInterfaceName): Added; guarded by PLATFORM(IOS).
* page/Settings.h:
(WebCore::Settings::setMaxParseDuration): Added; guarded by PLATFORM(IOS). Also added FIXME comment.
(WebCore::Settings::maxParseDuration): Added; guarded by PLATFORM(IOS). Also added FIXME comment.
(WebCore::Settings::standalone): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::setTelephoneNumberParsingEnabled): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::telephoneNumberParsingEnabled): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::setMediaDataLoadsAutomatically): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::mediaDataLoadsAutomatically): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::setShouldTransformsAffectOverflow): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::shouldTransformsAffectOverflow): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::setShouldDispatchJavaScriptWindowOnErrorEvents): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::shouldDispatchJavaScriptWindowOnErrorEvents): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::setAlwaysUseBaselineOfPrimaryFont): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::alwaysUseBaselineOfPrimaryFont): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::setAlwaysUseAcceleratedOverflowScroll): Added; guarded by PLATFORM(IOS).
(WebCore::Settings::alwaysUseAcceleratedOverflowScroll): Added; guarded by PLATFORM(IOS).
* page/Settings.in: Added IOS_AIRPLAY-guarded setting: mediaPlaybackAllowsAirPlay.
* page/animation/CSSPropertyAnimation.cpp:
(WebCore::CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap): Added iOS-specific code and FIXME comment.
* page/ios/EventHandlerIOS.mm: Added.
* page/ios/FrameIOS.mm: Added.
* page/mac/ChromeMac.mm:
* page/mac/PageMac.cpp:
(WebCore::Page::addSchedulePair): Opt out of code when building for iOS.
(WebCore::Page::removeSchedulePair): Ditto.
* page/mac/SettingsMac.mm:
(WebCore::Settings::shouldEnableScreenFontSubstitutionByDefault): Added iOS-specific code.
* page/mac/WebCoreFrameView.h:

Source/WebKit/ios:

* WebCoreSupport/WebChromeClientIOS.mm: Substitute ENABLE(IOS_TOUCH_EVENTS) for ENABLE(TOUCH_EVENTS).

Source/WebKit2:

* WebProcess/WebCoreSupport/WebChromeClient.h:
* WebProcess/WebCoreSupport/ios/WebChromeClientIOS.mm: Added.
* WebProcess/WebPage/WebPage.cpp: Include header <WebCore/HitTestResult.h>.

Source/WTF:

* wtf/FeatureDefines.h: Define ENABLE_IOS_TOUCH_EVENTS to be enabled by default
when building iOS with ENABLE(TOUCH_EVENTS).

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@161106 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog
index fe42280..fe85b05 100644
--- a/Source/WTF/ChangeLog
+++ b/Source/WTF/ChangeLog
@@ -1,3 +1,13 @@
+2013-12-27  Daniel Bates  <dabates@apple.com>
+
+        [iOS] Upstream WebCore/page changes
+        https://bugs.webkit.org/show_bug.cgi?id=126180
+
+        Reviewed by Darin Adler.
+
+        * wtf/FeatureDefines.h: Define ENABLE_IOS_TOUCH_EVENTS to be enabled by default
+        when building iOS with ENABLE(TOUCH_EVENTS).
+
 2013-12-25  Thiago de Barros Lacerda  <thiago.lacerda@openbossa.org>
 
         [Nix] Building with DRAG_SUPPORT enabled
diff --git a/Source/WTF/wtf/FeatureDefines.h b/Source/WTF/wtf/FeatureDefines.h
index 8a6fa53..f8532aa 100644
--- a/Source/WTF/wtf/FeatureDefines.h
+++ b/Source/WTF/wtf/FeatureDefines.h
@@ -68,6 +68,10 @@
 #define ENABLE_CSS_IMAGE_SET 1
 #endif
 
+#if !defined(ENABLE_CURSOR_SUPPORT)
+#define ENABLE_CURSOR_SUPPORT 0
+#endif
+
 #if !defined(ENABLE_DISK_IMAGE_CACHE)
 #define ENABLE_DISK_IMAGE_CACHE 1
 #endif
@@ -84,6 +88,10 @@
 #define ENABLE_ICONDATABASE 0
 #endif
 
+#if !defined(ENABLE_LETTERPRESS)
+#define ENABLE_LETTERPRESS 1
+#endif
+
 #if !defined(ENABLE_IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
 #define ENABLE_IOS_AUTOCORRECT_AND_AUTOCAPITALIZE 1
 #endif
@@ -92,14 +100,14 @@
 #define ENABLE_IOS_GESTURE_EVENTS 1
 #endif
 
-#if !defined(ENABLE_LETTERPRESS)
-#define ENABLE_LETTERPRESS 1
-#endif
-
 #if !defined(ENABLE_IOS_TEXT_AUTOSIZING)
 #define ENABLE_IOS_TEXT_AUTOSIZING 1
 #endif
 
+#if !defined(ENABLE_IOS_TOUCH_EVENTS)
+#define ENABLE_IOS_TOUCH_EVENTS 1
+#endif
+
 #if !defined(ENABLE_METER_ELEMENT)
 #define ENABLE_METER_ELEMENT 0
 #endif
@@ -430,6 +438,10 @@
 #define ENABLE_CSS_TRANSFORMS_ANIMATIONS_TRANSITIONS_UNPREFIXED 0
 #endif
 
+#if !defined(ENABLE_CURSOR_SUPPORT)
+#define ENABLE_CURSOR_SUPPORT 1
+#endif
+
 #if !defined(ENABLE_CUSTOM_SCHEME_HANDLER)
 #define ENABLE_CUSTOM_SCHEME_HANDLER 0
 #endif
@@ -894,4 +906,8 @@
 #error "ENABLE(REMOTE_INSPECTOR) requires ENABLE(INSPECTOR)"
 #endif
 
+#if ENABLE(IOS_TOUCH_EVENTS) && !ENABLE(TOUCH_EVENTS)
+#error "ENABLE(IOS_TOUCH_EVENTS) requires ENABLE(TOUCH_EVENTS)"
+#endif
+
 #endif /* WTF_FeatureDefines_h */
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index b0a3ca3..db5b0a8 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,146 @@
+2013-12-27  Daniel Bates  <dabates@apple.com>
+
+        [iOS] Upstream WebCore/page changes
+        https://bugs.webkit.org/show_bug.cgi?id=126180
+
+        Reviewed by Darin Adler.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/EventNames.h:
+        (WebCore::EventNames::isGestureEventType): Added.
+        * page/AlternativeTextClient.h: Do not define WTF_USE_DICTATION_ALTERNATIVES when building for iOS.
+        * page/Chrome.cpp:
+        (WebCore::Chrome::Chrome):
+        (WebCore::Chrome::dispatchViewportPropertiesDidChange): Added; guarded by PLATFORM(IOS).
+        (WebCore::Chrome::setCursor): Make this an empty function when building for iOS.
+        (WebCore::Chrome::setCursorHiddenUntilMouseMoves): Ditto.
+        (WebCore::Chrome::didReceiveDocType): Added; iOS-specific.
+        * page/Chrome.h:
+        (WebCore::Chrome::setDispatchViewportDataDidChangeSuppressed): Added; guarded by PLATFORM(IOS).
+        * page/ChromeClient.h:
+        (WebCore::ChromeClient::didFlushCompositingLayers): Added; guarded by PLATFORM(IOS).
+        (WebCore::ChromeClient::fetchCustomFixedPositionLayoutRect): Added; guarded by PLATFORM(IOS).
+        (WebCore::ChromeClient::updateViewportConstrainedLayers): Added; guarded by PLATFORM(IOS).
+        * page/DOMTimer.cpp:
+        (WebCore::DOMTimer::install): Added iOS-specific code.
+        (WebCore::DOMTimer::fired): Ditto.
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::DOMWindow): Ditto.
+        (WebCore::DOMWindow::innerHeight): Ditto.
+        (WebCore::DOMWindow::innerWidth): Ditto.
+        (WebCore::DOMWindow::scrollX): Ditto.
+        (WebCore::DOMWindow::scrollY): Ditto.
+        (WebCore::DOMWindow::scrollBy): Ditto.
+        (WebCore::DOMWindow::scrollTo): Ditto.
+        (WebCore::DOMWindow::clearTimeout): Ditto.
+        (WebCore::DOMWindow::addEventListener): Ditto.
+        (WebCore::DOMWindow::incrementScrollEventListenersCount): Added; guarded by PLATFORM(IOS).
+        (WebCore::DOMWindow::decrementScrollEventListenersCount): Added; guarded by PLATFORM(IOS).
+        (WebCore::DOMWindow::resetAllGeolocationPermission): Added; Also added FIXME comment.
+        (WebCore::DOMWindow::removeEventListener): Added iOS-specific code.
+        (WebCore::DOMWindow::dispatchEvent): Modified to prevent dispatching duplicate pageshow and pagehide
+        events per <http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#event-pageshow>.
+        (WebCore::DOMWindow::removeAllEventListeners): Added iOS-specific code.
+        * page/DOMWindow.h:
+        * page/DOMWindow.idl: Added IOS_GESTURE_EVENTS-guarded attributes: ongesture{change, end, start}. Also
+        added IOS_TOUCH_EVENTS-guarded attributes: {Touch, TouchList}Constructor.
+        * page/EditorClient.h:
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::EventHandler): Added iOS-specific code.
+        (WebCore::EventHandler::clear): Ditto.
+        (WebCore::EventHandler::startPanScrolling): Make this an empty function when building for iOS.
+        (WebCore::EventHandler::handleMousePressEvent): Modified to invalidate a click when the clicked node is
+        null. Also, opt out of code for updating the scrollbars as UIKit manages scrollbars on iOS.
+        (WebCore::EventHandler::handleMouseMoveEvent): Opt of code for updating the scrollbars and cursor when building on iOS.
+        (WebCore::hitTestResultInFrame): Made this a file-local static function since it's only used in EventHandler.cpp.
+        (WebCore::EventHandler::dispatchSyntheticTouchEventIfEnabled): Added iOS-specific code.
+        * page/EventHandler.h:
+        * page/FocusController.h:
+        * page/Frame.cpp:
+        (WebCore::Frame::Frame): Added iOS-specific code.
+        (WebCore::Frame::scrollOverflowLayer): Added; iOS-specific.
+        (WebCore::Frame::overflowAutoScrollTimerFired): Added; iOS-specific.
+        (WebCore::Frame::startOverflowAutoScroll): Added; iOS-specific.
+        (WebCore::Frame::checkOverflowScroll): Added; iOS-specific.
+        (WebCore::Frame::willDetachPage): Added iOS-specific code.
+        (WebCore::Frame::createView): Ditto.
+        (WebCore::Frame::setSelectionChangeCallbacksDisabled): Added; iOS-specific.
+        (WebCore::Frame::selectionChangeCallbacksDisabled): Added; iOS-specific.
+        * page/Frame.h:
+        (WebCore::Frame::timersPaused): Added; guarded by PLATFORM(IOS).
+        * page/FrameView.cpp:
+        (WebCore::FrameView::FrameView): Added iOS-specific code.
+        (WebCore::FrameView::clear): Ditto.
+        (WebCore::FrameView::flushCompositingStateForThisFrame): Ditto.
+        (WebCore::FrameView::graphicsLayerForPlatformWidget): Added.
+        (WebCore::FrameView::scheduleLayerFlushAllowingThrottling): Added.
+        (WebCore::FrameView::layout): Added iOS-specific code.
+        (WebCore::countRenderedCharactersInRenderObjectWithThreshold): Added; helper function used by FrameView::renderedCharactersExceed().
+        Also added FIXME comment.
+        (WebCore::FrameView::renderedCharactersExceed): Added.
+        (WebCore::FrameView::visibleContentsResized): Added iOS-specific code.
+        (WebCore::FrameView::adjustTiledBackingCoverage): Ditto.
+        (WebCore::FrameView::performPostLayoutTasks): Ditto.
+        (WebCore::FrameView::sendResizeEventIfNeeded): Ditto.
+        (WebCore::FrameView::paintContents): Added iOS-specific code. Also added FIXME comments.
+        (WebCore::FrameView::setUseCustomFixedPositionLayoutRect): Added; iOS-specific.
+        (WebCore::FrameView::setCustomFixedPositionLayoutRect): Added; iOS-specific.
+        (WebCore::FrameView::updateFixedPositionLayoutRect): Added; iOS-specific.
+        * page/FrameView.h:
+        * page/Navigator.cpp:
+        (WebCore::Navigator::standalone): Added; iOS-specific.
+        * page/Navigator.h:
+        * page/Navigator.idl: Added WTF_PLATFORM_IOS-guarded attribute: standalone. Also added FIXME comment.
+        * page/NavigatorBase.cpp:
+        (WebCore::NavigatorBase::platform): Added iOS-specific code.
+        * page/Page.h:
+        (WebCore::Page::hasCustomHTMLTokenizerTimeDelay): Added; guarded by PLATFORM(IOS). Also added FIXME comment
+        to remove this method.
+        (WebCore::Page::customHTMLTokenizerTimeDelay): Added; guarded by PLATFORM(IOS). Also added FIXME comment
+        to remove this method.
+        * page/PageGroup.cpp:
+        (WebCore::PageGroup::removeVisitedLink): Added.
+        * page/PageGroup.h:
+        * page/Settings.cpp:
+        (WebCore::Settings::Settings):
+        (WebCore::Settings::setScriptEnabled): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::setStandalone): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::setAudioSessionCategoryOverride): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::audioSessionCategoryOverride): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::setNetworkDataUsageTrackingEnabled): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::networkDataUsageTrackingEnabled): Added; guarded by PLATFORM(IOS).
+        (WebCore::sharedNetworkInterfaceNameGlobal): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::setNetworkInterfaceName): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::networkInterfaceName): Added; guarded by PLATFORM(IOS).
+        * page/Settings.h:
+        (WebCore::Settings::setMaxParseDuration): Added; guarded by PLATFORM(IOS). Also added FIXME comment.
+        (WebCore::Settings::maxParseDuration): Added; guarded by PLATFORM(IOS). Also added FIXME comment.
+        (WebCore::Settings::standalone): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::setTelephoneNumberParsingEnabled): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::telephoneNumberParsingEnabled): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::setMediaDataLoadsAutomatically): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::mediaDataLoadsAutomatically): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::setShouldTransformsAffectOverflow): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::shouldTransformsAffectOverflow): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::setShouldDispatchJavaScriptWindowOnErrorEvents): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::shouldDispatchJavaScriptWindowOnErrorEvents): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::setAlwaysUseBaselineOfPrimaryFont): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::alwaysUseBaselineOfPrimaryFont): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::setAlwaysUseAcceleratedOverflowScroll): Added; guarded by PLATFORM(IOS).
+        (WebCore::Settings::alwaysUseAcceleratedOverflowScroll): Added; guarded by PLATFORM(IOS).
+        * page/Settings.in: Added IOS_AIRPLAY-guarded setting: mediaPlaybackAllowsAirPlay.
+        * page/animation/CSSPropertyAnimation.cpp:
+        (WebCore::CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap): Added iOS-specific code and FIXME comment.
+        * page/ios/EventHandlerIOS.mm: Added.
+        * page/ios/FrameIOS.mm: Added.
+        * page/mac/ChromeMac.mm:
+        * page/mac/PageMac.cpp:
+        (WebCore::Page::addSchedulePair): Opt out of code when building for iOS.
+        (WebCore::Page::removeSchedulePair): Ditto.
+        * page/mac/SettingsMac.mm:
+        (WebCore::Settings::shouldEnableScreenFontSubstitutionByDefault): Added iOS-specific code.
+        * page/mac/WebCoreFrameView.h:
+
 2013-12-27  Gavin Barraclough  <barraclough@apple.com>
 
         Merge PageVisibilityState & ViewState::IsVisible in WebKit2
diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
index da88ff9..4a73693 100644
--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -5466,6 +5466,8 @@
 		CE057FA61220731100A476D5 /* DocumentMarkerController.h in Headers */ = {isa = PBXBuildFile; fileRef = CE057FA41220731100A476D5 /* DocumentMarkerController.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		CE08C3D1152B599A0021B8C2 /* AlternativeTextController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE08C3CF152B599A0021B8C2 /* AlternativeTextController.cpp */; };
 		CE08C3D2152B599A0021B8C2 /* AlternativeTextController.h in Headers */ = {isa = PBXBuildFile; fileRef = CE08C3D0152B599A0021B8C2 /* AlternativeTextController.h */; settings = {ATTRIBUTES = (); }; };
+		FE6938B61045D67E008EABB6 /* EventHandlerIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = FE6938B51045D67E008EABB6 /* EventHandlerIOS.mm */; };
+		FED13D3D0CEA936A00D89466 /* FrameIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = FED13D3B0CEA936A00D89466 /* FrameIOS.mm */; };
 		CE7B2DB31586ABAD0098B3FA /* AlternativeTextUIController.h in Headers */ = {isa = PBXBuildFile; fileRef = CE7B2DAF1586ABAD0098B3FA /* AlternativeTextUIController.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		CE7B2DB41586ABAD0098B3FA /* AlternativeTextUIController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CE7B2DB01586ABAD0098B3FA /* AlternativeTextUIController.mm */; };
 		CE7B2DB51586ABAD0098B3FA /* TextAlternativeWithRange.h in Headers */ = {isa = PBXBuildFile; fileRef = CE7B2DB11586ABAD0098B3FA /* TextAlternativeWithRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -12621,6 +12623,8 @@
 		CE057FA41220731100A476D5 /* DocumentMarkerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DocumentMarkerController.h; sourceTree = "<group>"; };
 		CE08C3CF152B599A0021B8C2 /* AlternativeTextController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AlternativeTextController.cpp; sourceTree = "<group>"; };
 		CE08C3D0152B599A0021B8C2 /* AlternativeTextController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AlternativeTextController.h; sourceTree = "<group>"; };
+		FE6938B51045D67E008EABB6 /* EventHandlerIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EventHandlerIOS.mm; sourceTree = "<group>"; };
+		FED13D3B0CEA936A00D89466 /* FrameIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FrameIOS.mm; sourceTree = "<group>"; };
 		CE5CB1B314EDAB6F00BB2795 /* EventSender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventSender.h; sourceTree = "<group>"; };
 		CE7B2DAF1586ABAD0098B3FA /* AlternativeTextUIController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AlternativeTextUIController.h; path = mac/AlternativeTextUIController.h; sourceTree = "<group>"; };
 		CE7B2DB01586ABAD0098B3FA /* AlternativeTextUIController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AlternativeTextUIController.mm; path = mac/AlternativeTextUIController.mm; sourceTree = "<group>"; };
@@ -15731,6 +15735,7 @@
 			isa = PBXGroup;
 			children = (
 				316FE1060E6E1D8400BF6088 /* animation */,
+				18A6CD6F0D8F2025001DC3CE /* ios */,
 				93C09A820B064F05005ABD4D /* mac */,
 				1AF62EE114DA22A70041556C /* scrolling */,
 				8538F0000AD71770006A81D1 /* AbstractView.idl */,
@@ -20538,6 +20543,15 @@
 			path = mediasource;
 			sourceTree = "<group>";
 		};
+		18A6CD6F0D8F2025001DC3CE /* ios */ = {
+			isa = PBXGroup;
+			children = (
+				FE6938B51045D67E008EABB6 /* EventHandlerIOS.mm */,
+				FED13D3B0CEA936A00D89466 /* FrameIOS.mm */,
+			);
+			path = ios;
+			sourceTree = "<group>";
+		};
 		CE79D68617F220ED00815C00 /* ios */ = {
 			isa = PBXGroup;
 			children = (
@@ -26350,6 +26364,7 @@
 				850657010AAB4763002D15C0 /* DOMStyleSheet.mm in Sources */,
 				850657030AAB4763002D15C0 /* DOMStyleSheetList.mm in Sources */,
 				85ACA99D0A9B575900671E90 /* DOMText.mm in Sources */,
+				FED13D3D0CEA936A00D89466 /* FrameIOS.mm in Sources */,
 				933A14AA0B7D1D0900A53FFD /* DOMTextEvent.mm in Sources */,
 				188604B30F2E654A000B6443 /* DOMTimer.cpp in Sources */,
 				76FC2B0B12370DA0006A991A /* DOMTokenList.cpp in Sources */,
@@ -28461,6 +28476,7 @@
 				49C7B9E51042D32F0009D447 /* WebGLTexture.cpp in Sources */,
 				0C3F1F5A10C8871200D72CE1 /* WebGLUniformLocation.cpp in Sources */,
 				77A17A7712F28642004E02F6 /* WebGLVertexArrayObjectOES.cpp in Sources */,
+				FE6938B61045D67E008EABB6 /* EventHandlerIOS.mm in Sources */,
 				31C0FF210E4CEB6E007D6FE5 /* WebKitAnimationEvent.cpp in Sources */,
 				976D6C7B122B8A3D001FD1F7 /* WebKitBlobBuilder.cpp in Sources */,
 				150B923915F08DC400E10986 /* WebKitCSSArrayFunctionValue.cpp in Sources */,
diff --git a/Source/WebCore/dom/EventNames.h b/Source/WebCore/dom/EventNames.h
index 048839a..294f239 100644
--- a/Source/WebCore/dom/EventNames.h
+++ b/Source/WebCore/dom/EventNames.h
@@ -290,6 +290,11 @@
     DOM_EVENT_NAMES_FOR_EACH(DOM_EVENT_NAMES_DECLARE)
     #undef DOM_EVENT_NAMES_DECLARE
 
+    inline bool isGestureEventType(const AtomicString& eventType) const
+    {
+        return eventType == gesturestartEvent || eventType == gesturechangeEvent || eventType == gestureendEvent;
+    }
+
     inline bool isTouchEventType(const AtomicString& eventType) const
     {
         return eventType == touchstartEvent
diff --git a/Source/WebCore/page/AlternativeTextClient.h b/Source/WebCore/page/AlternativeTextClient.h
index 54477b6..a7e991d 100644
--- a/Source/WebCore/page/AlternativeTextClient.h
+++ b/Source/WebCore/page/AlternativeTextClient.h
@@ -31,10 +31,10 @@
 #include <wtf/Vector.h>
 #include <wtf/text/WTFString.h>
 
-#if PLATFORM(MAC) && (PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
+#if !PLATFORM(IOS) && PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
 // Some platforms provide UI for suggesting alternative dictation text.
 #define WTF_USE_DICTATION_ALTERNATIVES 1
-#endif // PLATFORM(MAC) && (PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
+#endif // !PLATFORM(IOS) && PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
 
 namespace WebCore {
 
diff --git a/Source/WebCore/page/Chrome.cpp b/Source/WebCore/page/Chrome.cpp
index 6fc9adff..493fdad 100644
--- a/Source/WebCore/page/Chrome.cpp
+++ b/Source/WebCore/page/Chrome.cpp
@@ -26,6 +26,7 @@
 #include "DNS.h"
 #include "DateTimeChooser.h"
 #include "Document.h"
+#include "DocumentType.h"
 #include "FileIconLoader.h"
 #include "FileChooser.h"
 #include "FileList.h"
@@ -65,6 +66,9 @@
     : m_page(page)
     , m_client(client)
     , m_displayID(0)
+#if PLATFORM(IOS)
+    , m_isDispatchViewportDataDidChangeSuppressed(false)
+#endif
 {
 }
 
@@ -477,7 +481,7 @@
 }
 #endif
 
-#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
+#if ENABLE(DATE_AND_TIME_INPUT_TYPES) && !PLATFORM(IOS)
 PassRefPtr<DateTimeChooser> Chrome::openDateTimeChooser(DateTimeChooserClient* client, const DateTimeChooserParameters& parameters)
 {
     notifyPopupOpeningObservers();
@@ -498,17 +502,29 @@
 
 void Chrome::dispatchViewportPropertiesDidChange(const ViewportArguments& arguments) const
 {
+#if PLATFORM(IOS)
+    if (m_isDispatchViewportDataDidChangeSuppressed)
+        return;
+#endif
     m_client.dispatchViewportPropertiesDidChange(arguments);
 }
 
 void Chrome::setCursor(const Cursor& cursor)
 {
+#if ENABLE(CURSOR_SUPPORT)
     m_client.setCursor(cursor);
+#else
+    UNUSED_PARAM(cursor);
+#endif
 }
 
 void Chrome::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves)
 {
+#if ENABLE(CURSOR_SUPPORT)
     m_client.setCursorHiddenUntilMouseMoves(hiddenUntilMouseMoves);
+#else
+    UNUSED_PARAM(hiddenUntilMouseMoves);
+#endif
 }
 
 #if ENABLE(REQUEST_ANIMATION_FRAME)
@@ -602,6 +618,26 @@
     return m_client.requiresFullscreenForVideoPlayback();
 }
 
+#if PLATFORM(IOS)
+// FIXME: Make argument, frame, a reference.
+void Chrome::didReceiveDocType(Frame* frame)
+{
+    ASSERT(frame);
+    if (!frame->isMainFrame())
+        return;
+
+    DocumentType* documentType = frame->document()->doctype();
+    if (!documentType) {
+        // FIXME: We should notify the client when <!DOCTYPE> is removed so that
+        // it can adjust the viewport accordingly. See <rdar://problem/15417894>.
+        return;
+    }
+
+    if (documentType->publicId().contains("xhtml mobile", false))
+        m_client.didReceiveMobileDocType();
+}
+#endif
+
 void Chrome::registerPopupOpeningObserver(PopupOpeningObserver* observer)
 {
     ASSERT(observer);
diff --git a/Source/WebCore/page/Chrome.h b/Source/WebCore/page/Chrome.h
index 464400f..529c152 100644
--- a/Source/WebCore/page/Chrome.h
+++ b/Source/WebCore/page/Chrome.h
@@ -155,8 +155,9 @@
 #if ENABLE(INPUT_TYPE_COLOR)
     PassOwnPtr<ColorChooser> createColorChooser(ColorChooserClient*, const Color& initialColor);
 #endif
-#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
-    PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&);
+
+#if ENABLE(DATE_AND_TIME_INPUT_TYPES) && !PLATFORM(IOS)
+    PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&)
 #endif
 
     void runOpenPanel(Frame*, PassRefPtr<FileChooser>);
@@ -179,6 +180,13 @@
     PassRefPtr<PopupMenu> createPopupMenu(PopupMenuClient*) const;
     PassRefPtr<SearchPopupMenu> createSearchPopupMenu(PopupMenuClient*) const;
 
+#if PLATFORM(IOS)
+    // FIXME: Can we come up with a better name for this setter?
+    void setDispatchViewportDataDidChangeSuppressed(bool dispatchViewportDataDidChangeSuppressed) { m_isDispatchViewportDataDidChangeSuppressed = dispatchViewportDataDidChangeSuppressed; }
+
+    void didReceiveDocType(Frame*);
+#endif
+
     void registerPopupOpeningObserver(PopupOpeningObserver*);
     void unregisterPopupOpeningObserver(PopupOpeningObserver*);
 
@@ -189,6 +197,9 @@
     ChromeClient& m_client;
     PlatformDisplayID m_displayID;
     Vector<PopupOpeningObserver*> m_popupOpeningObservers;
+#if PLATFORM(IOS)
+    bool m_isDispatchViewportDataDidChangeSuppressed;
+#endif
 };
 
 }
diff --git a/Source/WebCore/page/ChromeClient.h b/Source/WebCore/page/ChromeClient.h
index ee94476..ba87c70 100644
--- a/Source/WebCore/page/ChromeClient.h
+++ b/Source/WebCore/page/ChromeClient.h
@@ -40,6 +40,16 @@
 #include <wtf/PassOwnPtr.h>
 #include <wtf/Vector.h>
 
+#if PLATFORM(IOS)
+#include "PlatformLayer.h"
+#define NSResponder WAKResponder
+#ifndef __OBJC__
+class WAKResponder;
+#else
+@class WAKResponder;
+#endif
+#endif
+
 #if ENABLE(SQL_DATABASE)
 #include "DatabaseDetails.h"
 #endif
@@ -62,14 +72,15 @@
 class GraphicsContext3D;
 class GraphicsLayer;
 class GraphicsLayerFactory;
-class HitTestResult;
 class HTMLInputElement;
+class HitTestResult;
 class IntRect;
 class NavigationAction;
 class Node;
 class Page;
 class PopupMenuClient;
 class SecurityOrigin;
+class ViewportConstraints;
 class Widget;
 
 struct DateTimeChooserParameters;
@@ -156,8 +167,10 @@
     virtual IntRect rootViewToScreen(const IntRect&) const = 0;
     virtual PlatformPageClient platformPageClient() const = 0;
     virtual void scrollbarsModeDidChange() const = 0;
+#if ENABLE(CURSOR_SUPPORT)
     virtual void setCursor(const Cursor&) = 0;
     virtual void setCursorHiddenUntilMouseMoves(bool) = 0;
+#endif
 #if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER)
     virtual void scheduleAnimation() = 0;
 #endif
@@ -212,11 +225,46 @@
     virtual bool shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename);
     virtual String generateReplacementFile(const String& path);
 
+#if ENABLE(IOS_TOUCH_EVENTS)
+    virtual void didPreventDefaultForEvent() = 0;
+#endif
+
+#if PLATFORM(IOS)
+    virtual void didReceiveMobileDocType() = 0;
+    virtual void setNeedsScrollNotifications(Frame*, bool) = 0;
+    virtual void observedContentChange(Frame*) = 0;
+    virtual void clearContentChangeObservers(Frame*) = 0;
+    virtual void notifyRevealedSelectionByScrollingFrame(Frame*) = 0;
+
+    enum LayoutType { NormalLayout, Scroll };
+    virtual void didLayout(LayoutType = NormalLayout) = 0;
+    virtual void didStartOverflowScroll() = 0;
+    virtual void didEndOverflowScroll() = 0;
+
+    // FIXME: Remove this functionality. This functionality was added to workaround an issue (<rdar://problem/5973875>)
+    // where the unconfirmed text in a text area would be removed when a person clicks in the text area before a
+    // suggestion is shown. We should fix this issue in <rdar://problem/5975559>.
+    virtual void suppressFormNotifications() = 0;
+    virtual void restoreFormNotifications() = 0;
+
+    virtual void didFlushCompositingLayers() { }
+
+    virtual bool fetchCustomFixedPositionLayoutRect(IntRect&) { return false; }
+
+    // FIXME: Use std::unique_ptr instead of OwnPtr.
+    virtual void updateViewportConstrainedLayers(HashMap<PlatformLayer*, OwnPtr<ViewportConstraints>>&, HashMap<PlatformLayer*, PlatformLayer*>&) { }
+
+    virtual void addOrUpdateScrollingLayer(Node*, PlatformLayer* scrollingLayer, PlatformLayer* contentsLayer, const IntSize& scrollSize, bool allowHorizontalScrollbar, bool allowVerticalScrollbar) = 0;
+    virtual void removeScrollingLayer(Node*, PlatformLayer* scrollingLayer, PlatformLayer* contentsLayer) = 0;
+
+    virtual void webAppOrientationsUpdated() = 0;
+#endif
+
 #if ENABLE(INPUT_TYPE_COLOR)
     virtual PassOwnPtr<ColorChooser> createColorChooser(ColorChooserClient*, const Color&) = 0;
 #endif
 
-#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
+#if ENABLE(DATE_AND_TIME_INPUT_TYPES) && !PLATFORM(IOS)
     virtual PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) = 0;
 #endif
 
diff --git a/Source/WebCore/page/DOMTimer.cpp b/Source/WebCore/page/DOMTimer.cpp
index 6527a06..0c99e0d 100644
--- a/Source/WebCore/page/DOMTimer.cpp
+++ b/Source/WebCore/page/DOMTimer.cpp
@@ -35,6 +35,14 @@
 #include <wtf/HashSet.h>
 #include <wtf/StdLibExtras.h>
 
+#if PLATFORM(IOS)
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "Frame.h"
+#include "Page.h"
+#include "WKContentObservation.h"
+#endif
+
 namespace WebCore {
 
 static const int maxIntervalForUserGestureForwarding = 1000; // One second matches Gecko.
@@ -81,6 +89,16 @@
     // The timer is deleted when context is deleted (DOMTimer::contextDestroyed) or explicitly via DOMTimer::removeById(),
     // or if it is a one-time timer and it has fired (DOMTimer::fired).
     DOMTimer* timer = new DOMTimer(context, action, timeout, singleShot);
+#if PLATFORM(IOS)
+    if (context->isDocument()) {
+        Document& document = toDocument(*context);
+        bool didDeferTimeout = document.frame() && document.frame()->timersPaused();
+        if (!didDeferTimeout && timeout <= 100 && singleShot) {
+            WKSetObservedContentChange(WKContentIndeterminateChange);
+            WebThreadAddObservedContentModifier(timer); // Will only take affect if not already visibility change.
+        }
+    }
+#endif
 
     timer->suspendIfNeeded();
     InspectorInstrumentation::didInstallTimer(context, timer->m_timeoutId, timeout, singleShot);
@@ -104,6 +122,14 @@
 void DOMTimer::fired()
 {
     ScriptExecutionContext* context = scriptExecutionContext();
+    ASSERT(context);
+#if PLATFORM(IOS)
+    Document* document = nullptr;
+    if (!context->isDocument()) {
+        document = toDocument(context);
+        ASSERT(!document->frame()->timersPaused());
+    }
+#endif
     timerNestingLevel = m_nestingLevel;
     ASSERT(!isSuspended());
     ASSERT(!context->activeDOMObjectsAreSuspended());
@@ -136,8 +162,35 @@
     // No access to member variables after this point.
     delete this;
 
+#if PLATFORM(IOS)
+    bool shouldReportLackOfChanges;
+    bool shouldBeginObservingChanges;
+    if (document) {
+        shouldReportLackOfChanges = WebThreadCountOfObservedContentModifiers() == 1;
+        shouldBeginObservingChanges = WebThreadContainsObservedContentModifier(this);
+    } else {
+        shouldReportLackOfChanges = false;
+        shouldBeginObservingChanges = false;
+    }
+
+    if (shouldBeginObservingChanges) {
+        WKBeginObservingContentChanges(false);
+        WebThreadRemoveObservedContentModifier(this);
+    }
+#endif
+
     action->execute(context);
 
+#if PLATFORM(IOS)
+    if (shouldBeginObservingChanges) {
+        WKStopObservingContentChanges();
+
+        if (WKObservedContentChange() == WKContentVisibilityChange || shouldReportLackOfChanges)
+            if (document && document->page())
+                document->page()->chrome().client().observedContentChange(document->frame());
+    }
+#endif
+
     InspectorInstrumentation::didFireTimer(cookie);
 
     timerNestingLevel = 0;
diff --git a/Source/WebCore/page/DOMWindow.cpp b/Source/WebCore/page/DOMWindow.cpp
index 966030c..c795b1b 100644
--- a/Source/WebCore/page/DOMWindow.cpp
+++ b/Source/WebCore/page/DOMWindow.cpp
@@ -117,6 +117,13 @@
 #include "RequestAnimationFrameCallback.h"
 #endif
 
+#if PLATFORM(IOS)
+#if ENABLE(GEOLOCATION)
+#include "NavigatorGeolocation.h"
+#endif
+#include "WKContentObservation.h"
+#endif
+
 namespace WebCore {
 
 class PostMessageTimer : public TimerBase {
@@ -371,6 +378,13 @@
     , FrameDestructionObserver(document->frame())
     , m_shouldPrintWhenFinishedLoading(false)
     , m_suspendedForPageCache(false)
+    , m_lastPageStatus(PageStatusNone)
+#if PLATFORM(IOS)
+    , m_scrollEventListenerCount(0)
+#endif
+#if ENABLE(IOS_TOUCH_EVENTS) || ENABLE(IOS_GESTURE_EVENTS)
+    , m_touchEventListenerCount(0)
+#endif
 {
     ASSERT(frame());
     ASSERT(DOMWindow::document());
@@ -1139,9 +1153,13 @@
     if (!view)
         return 0;
 
+#if PLATFORM(IOS)
+    return view->mapFromLayoutToCSSUnits(static_cast<int>(view->actualVisibleContentRect().height()));
+#else
     // If the device height is overridden, do not include the horizontal scrollbar into the innerHeight (since it is absent on the real device).
     bool includeScrollbars = !InspectorInstrumentation::shouldApplyScreenHeightOverride(m_frame);
     return view->mapFromLayoutToCSSUnits(static_cast<int>(view->visibleContentRect(includeScrollbars ? ScrollableArea::IncludeScrollbars : ScrollableArea::ExcludeScrollbars).height()));
+#endif
 }
 
 int DOMWindow::innerWidth() const
@@ -1153,9 +1171,13 @@
     if (!view)
         return 0;
 
+#if PLATFORM(IOS)
+    return view->mapFromLayoutToCSSUnits(static_cast<int>(view->actualVisibleContentRect().width()));
+#else
     // If the device width is overridden, do not include the vertical scrollbar into the innerWidth (since it is absent on the real device).
     bool includeScrollbars = !InspectorInstrumentation::shouldApplyScreenWidthOverride(m_frame);
     return view->mapFromLayoutToCSSUnits(static_cast<int>(view->visibleContentRect(includeScrollbars ? ScrollableArea::IncludeScrollbars : ScrollableArea::ExcludeScrollbars).width()));
+#endif
 }
 
 int DOMWindow::screenX() const
@@ -1196,7 +1218,11 @@
 
     m_frame->document()->updateLayoutIgnorePendingStylesheets();
 
+#if PLATFORM(IOS)
+    return static_cast<int>(view->actualVisibleContentRect().x() / (m_frame->pageZoomFactor() * m_frame->frameScaleFactor()));
+#else
     return view->mapFromLayoutToCSSUnits(view->scrollX());
+#endif
 }
 
 int DOMWindow::scrollY() const
@@ -1213,7 +1239,11 @@
 
     m_frame->document()->updateLayoutIgnorePendingStylesheets();
 
+#if PLATFORM(IOS)
+    return static_cast<int>(view->actualVisibleContentRect().y() / (m_frame->pageZoomFactor() * m_frame->frameScaleFactor()));
+#else
     return view->mapFromLayoutToCSSUnits(view->scrollY());
+#endif
 }
 
 bool DOMWindow::closed() const
@@ -1425,7 +1455,11 @@
         return;
 
     IntSize scaledOffset(view->mapFromCSSToLayoutUnits(x), view->mapFromCSSToLayoutUnits(y));
+#if PLATFORM(IOS)
+    view->setActualScrollPosition(view->actualVisibleContentRect().location() + scaledOffset);
+#else
     view->scrollBy(scaledOffset);
+#endif
 }
 
 void DOMWindow::scrollTo(int x, int y) const
@@ -1439,8 +1473,15 @@
     if (!view)
         return;
 
+
+#if PLATFORM(IOS)
+    int zoomedX = static_cast<int>(x * m_frame->pageZoomFactor() * m_frame->frameScaleFactor());
+    int zoomedY = static_cast<int>(y * m_frame->pageZoomFactor() * m_frame->frameScaleFactor());
+    view->setActualScrollPosition(IntPoint(zoomedX, zoomedY));
+#else
     IntPoint layoutPos(view->mapFromCSSToLayoutUnits(x), view->mapFromCSSToLayoutUnits(y));
     view->setScrollPosition(layoutPos);
+#endif
 }
 
 bool DOMWindow::allowedToChangeWindowGeometry() const
@@ -1521,6 +1562,22 @@
 
 void DOMWindow::clearTimeout(int timeoutId)
 {
+#if PLATFORM(IOS)
+    if (m_frame) {
+        Document* document = m_frame->document();
+        if (timeoutId > 0 && document) {
+            DOMTimer* timer = document->findTimeout(timeoutId);
+            if (timer && WebThreadContainsObservedContentModifier(timer)) {
+                WebThreadRemoveObservedContentModifier(timer);
+
+                if (!WebThreadCountOfObservedContentModifiers()) {
+                    if (Page* page = m_frame->page())
+                        page->chrome().client().observedContentChange(m_frame);
+                }
+            }
+        }
+    }
+#endif
     ScriptExecutionContext* context = scriptExecutionContext();
     if (!context)
         return;
@@ -1608,6 +1665,12 @@
     else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this))
         addBeforeUnloadEventListener(this);
 #if ENABLE(DEVICE_ORIENTATION)
+#if PLATFORM(IOS)
+    else if (eventType == eventNames().devicemotionEvent && document())
+        document()->deviceMotionController()->addDeviceEventListener(this);
+    else if (eventType == eventNames().deviceorientationEvent && document())
+        document()->deviceOrientationController()->addDeviceEventListener(this);
+#else
     else if (eventType == eventNames().devicemotionEvent && RuntimeEnabledFeatures::sharedFeatures().deviceMotionEnabled()) {
         if (DeviceMotionController* controller = DeviceMotionController::from(page()))
             controller->addDeviceEventListener(this);
@@ -1615,6 +1678,19 @@
         if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
             controller->addDeviceEventListener(this);
     }
+#endif // PLATFORM(IOS)
+#endif // ENABLE(DEVICE_ORIENTATION)
+#if PLATFORM(IOS)
+    else if (eventType == eventNames().scrollEvent)
+        incrementScrollEventListenersCount();
+#endif
+#if ENABLE(IOS_TOUCH_EVENTS)
+    else if (eventNames().isTouchEventType(eventType))
+        ++m_touchEventListenerCount;
+#endif
+#if ENABLE(IOS_GESTURE_EVENTS)
+    else if (eventNames().isGestureEventType(eventType))
+        ++m_touchEventListenerCount;
 #endif
 
 #if ENABLE(PROXIMITY_EVENTS)
@@ -1627,6 +1703,37 @@
     return true;
 }
 
+#if PLATFORM(IOS)
+void DOMWindow::incrementScrollEventListenersCount()
+{
+    Document* document = this->document();
+    if (++m_scrollEventListenerCount == 1 && document == document->topDocument()) {
+        Frame* frame = this->frame();
+        if (frame && frame->page())
+            frame->page()->chrome().client().setNeedsScrollNotifications(frame, true);
+    }
+}
+
+void DOMWindow::decrementScrollEventListenersCount()
+{
+    Document* document = this->document();
+    if (!--m_scrollEventListenerCount && document == document->topDocument()) {
+        Frame* frame = this->frame();
+        if (frame && frame->page() && !document->inPageCache())
+            frame->page()->chrome().client().setNeedsScrollNotifications(frame, false);
+    }
+}
+#endif
+
+void DOMWindow::resetAllGeolocationPermission()
+{
+    // FIXME: Remove PLATFORM(IOS)-guard once we upstream the iOS changes to Geolocation.cpp.
+#if ENABLE(GEOLOCATION) && PLATFORM(IOS)
+    if (m_navigator)
+        NavigatorGeolocation::from(m_navigator.get())->resetAllGeolocationPermission();
+#endif
+}
+
 bool DOMWindow::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
 {
     if (!EventTarget::removeEventListener(eventType, listener, useCapture))
@@ -1644,6 +1751,12 @@
     else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this))
         removeBeforeUnloadEventListener(this);
 #if ENABLE(DEVICE_ORIENTATION)
+#if PLATFORM(IOS)
+    else if (eventType == eventNames().devicemotionEvent && document())
+        document()->deviceMotionController()->removeDeviceEventListener(this);
+    else if (eventType == eventNames().deviceorientationEvent && document())
+        document()->deviceOrientationController()->removeDeviceEventListener(this);
+#else
     else if (eventType == eventNames().devicemotionEvent) {
         if (DeviceMotionController* controller = DeviceMotionController::from(page()))
             controller->removeDeviceEventListener(this);
@@ -1651,6 +1764,23 @@
         if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
             controller->removeDeviceEventListener(this);
     }
+#endif // PLATFORM(IOS)
+#endif // ENABLE(DEVICE_ORIENTATION)
+#if PLATFORM(IOS)
+    else if (eventType == eventNames().scrollEvent)
+        decrementScrollEventListenersCount();
+#endif
+#if ENABLE(IOS_TOUCH_EVENTS)
+    else if (eventNames().isTouchEventType(eventType)) {
+        ASSERT(m_touchEventListenerCount > 0);
+        --m_touchEventListenerCount;
+    }
+#endif
+#if ENABLE(IOS_GESTURE_EVENTS)
+    else if (eventNames().isGestureEventType(eventType)) {
+        ASSERT(m_touchEventListenerCount > 0);
+        --m_touchEventListenerCount;
+    }
 #endif
 
 #if ENABLE(PROXIMITY_EVENTS)
@@ -1692,6 +1822,22 @@
     Ref<EventTarget> protect(*this);
     RefPtr<Event> event = prpEvent;
 
+    // Pausing a page may trigger pagehide and pageshow events. WebCore also implicitly fires these
+    // events when closing a WebView. Here we keep track of the state of the page to prevent duplicate,
+    // unbalanced events per the definition of the pageshow event:
+    // <http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#event-pageshow>.
+    if (event->eventInterface() == PageTransitionEventInterfaceType) {
+        if (event->type() == eventNames().pageshowEvent) {
+            if (m_lastPageStatus == PageStatusShown)
+                return true; // Event was previously dispatched; do not fire a duplicate event.
+            m_lastPageStatus = PageStatusShown;
+        } else if (event->type() == eventNames().pagehideEvent) {
+            if (m_lastPageStatus == PageStatusHidden)
+                return true; // Event was previously dispatched; do not fire a duplicate event.
+            m_lastPageStatus = PageStatusHidden;
+        }
+    }
+
     event->setTarget(prpTarget ? prpTarget : this);
     event->setCurrentTarget(this);
     event->setEventPhase(Event::AT_TARGET);
@@ -1710,11 +1856,30 @@
     EventTarget::removeAllEventListeners();
 
 #if ENABLE(DEVICE_ORIENTATION)
+#if PLATFORM(IOS)
+    if (Document* document = this->document()) {
+        document->deviceMotionController()->removeAllDeviceEventListeners(this);
+        document->deviceOrientationController()->removeAllDeviceEventListeners(this);
+    }
+#else
     if (DeviceMotionController* controller = DeviceMotionController::from(page()))
         controller->removeAllDeviceEventListeners(this);
     if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
         controller->removeAllDeviceEventListeners(this);
+#endif // PLATFORM(IOS)
+#endif // ENABLE(DEVICE_ORIENTATION)
+
+#if PLATFORM(IOS)
+    if (m_scrollEventListenerCount) {
+        m_scrollEventListenerCount = 1;
+        decrementScrollEventListenersCount();
+    }
 #endif
+
+#if ENABLE(IOS_TOUCH_EVENTS) || ENABLE(IOS_GESTURE_EVENTS)
+    m_touchEventListenerCount = 0;
+#endif
+
 #if ENABLE(TOUCH_EVENTS)
     if (Document* document = this->document())
         document->didRemoveEventTargetNode(document);
diff --git a/Source/WebCore/page/DOMWindow.h b/Source/WebCore/page/DOMWindow.h
index c8b7062..fe7dc7f 100644
--- a/Source/WebCore/page/DOMWindow.h
+++ b/Source/WebCore/page/DOMWindow.h
@@ -397,10 +397,28 @@
         DEFINE_ATTRIBUTE_EVENT_LISTENER(touchcancel);
 #endif
 
+#if ENABLE(IOS_GESTURE_EVENTS)
+        DEFINE_ATTRIBUTE_EVENT_LISTENER(gesturestart);
+        DEFINE_ATTRIBUTE_EVENT_LISTENER(gesturechange);
+        DEFINE_ATTRIBUTE_EVENT_LISTENER(gestureend);
+#endif
+
 #if ENABLE(WEB_TIMING)
         Performance* performance() const;
 #endif
 
+#if PLATFORM(IOS)
+        void incrementScrollEventListenersCount();
+        void decrementScrollEventListenersCount();
+        unsigned scrollEventListenerCount() const { return m_scrollEventListenerCount; }
+#endif
+
+        void resetAllGeolocationPermission();
+
+#if ENABLE(IOS_TOUCH_EVENTS) || ENABLE(IOS_GESTURE_EVENTS)
+        bool hasTouchEventListeners() const { return m_touchEventListenerCount > 0; }
+#endif
+
         // FIXME: When this DOMWindow is no longer the active DOMWindow (i.e.,
         // when its document is no longer the document that is displayed in its
         // frame), we would like to zero out m_frame to avoid being confused
@@ -457,6 +475,17 @@
         String m_status;
         String m_defaultStatus;
 
+        enum PageStatus { PageStatusNone, PageStatusShown, PageStatusHidden };
+        PageStatus m_lastPageStatus;
+
+#if PLATFORM(IOS)
+        unsigned m_scrollEventListenerCount;
+#endif
+
+#if ENABLE(IOS_TOUCH_EVENTS) || ENABLE(IOS_GESTURE_EVENTS)
+        unsigned m_touchEventListenerCount;
+#endif
+
         mutable RefPtr<Storage> m_sessionStorage;
         mutable RefPtr<Storage> m_localStorage;
         mutable RefPtr<DOMApplicationCache> m_applicationCache;
diff --git a/Source/WebCore/page/DOMWindow.idl b/Source/WebCore/page/DOMWindow.idl
index 74b4a6f..a067f54 100644
--- a/Source/WebCore/page/DOMWindow.idl
+++ b/Source/WebCore/page/DOMWindow.idl
@@ -285,6 +285,10 @@
     [Conditional=TOUCH_EVENTS] attribute EventListener ontouchend;
     [Conditional=TOUCH_EVENTS] attribute EventListener ontouchcancel;
 
+    [Conditional=IOS_GESTURE_EVENTS] attribute EventListener ongesturestart;
+    [Conditional=IOS_GESTURE_EVENTS] attribute EventListener ongesturechange;
+    [Conditional=IOS_GESTURE_EVENTS] attribute EventListener ongestureend;
+
     [Conditional=DEVICE_ORIENTATION] attribute EventListener ondevicemotion;
     [Conditional=DEVICE_ORIENTATION] attribute EventListener ondeviceorientation;
 
@@ -308,6 +312,10 @@
     // Mozilla has a separate XMLDocument object for XML documents.
     // We just use Document for this.
     attribute DocumentConstructor XMLDocument;
+
+    [Conditional=IOS_TOUCH_EVENTS, CustomGetter] attribute TouchConstructor Touch; // Usable with the new operator
+    [Conditional=IOS_TOUCH_EVENTS, CustomGetter] attribute TouchListConstructor TouchList; // Usable with the new operator
+
     [Conditional=BLOB] attribute DOMURLConstructor webkitURL; // FIXME: deprecate this.
     attribute MutationObserverConstructor WebKitMutationObserver; // FIXME: Add metrics to determine when we can remove this.
     [Conditional=INDEXED_DATABASE] attribute IDBCursorConstructor webkitIDBCursor;
diff --git a/Source/WebCore/page/EditorClient.h b/Source/WebCore/page/EditorClient.h
index 6fbad7d..8623994 100644
--- a/Source/WebCore/page/EditorClient.h
+++ b/Source/WebCore/page/EditorClient.h
@@ -41,6 +41,11 @@
 OBJC_CLASS NSURL;
 #endif
 
+#if PLATFORM(IOS)
+OBJC_CLASS NSArray;
+OBJC_CLASS NSDictionary;
+#endif
+
 namespace WebCore {
 
 class ArchiveResource;
@@ -113,6 +118,21 @@
     virtual void textWillBeDeletedInTextField(Element*) = 0;
     virtual void textDidChangeInTextArea(Element*) = 0;
 
+#if PLATFORM(IOS)
+    virtual void suppressSelectionNotifications() = 0;
+    virtual void restoreSelectionNotifications() = 0;
+    virtual void startDelayingAndCoalescingContentChangeNotifications() = 0;
+    virtual void stopDelayingAndCoalescingContentChangeNotifications() = 0;
+    virtual void writeDataToPasteboard(NSDictionary*) = 0;
+    virtual NSArray* supportedPasteboardTypesForCurrentSelection() = 0;
+    virtual NSArray* readDataFromPasteboard(NSString* type, int index) = 0;
+    virtual bool hasRichlyEditableSelection() = 0;
+    virtual int getPasteboardItemsCount() = 0;
+    virtual DocumentFragment* documentFragmentFromDelegate(int index) = 0;
+    virtual bool performsTwoStepPaste(DocumentFragment*) = 0;
+    virtual int pasteboardChangeCount() = 0;
+#endif
+
 #if PLATFORM(MAC)
     virtual NSString* userVisibleString(NSURL*) = 0;
     virtual DocumentFragment* documentFragmentFromAttributedString(NSAttributedString*, Vector< RefPtr<ArchiveResource>>&) = 0;
diff --git a/Source/WebCore/page/EventHandler.cpp b/Source/WebCore/page/EventHandler.cpp
index a6bab3a..bdbdab8 100644
--- a/Source/WebCore/page/EventHandler.cpp
+++ b/Source/WebCore/page/EventHandler.cpp
@@ -104,7 +104,11 @@
 #endif
 
 #if ENABLE(TOUCH_EVENTS)
+#if ENABLE(IOS_TOUCH_EVENTS)
+#include "PlatformTouchEventIOS.h"
+#else
 #include "PlatformTouchEvent.h"
+#endif
 #include "TouchEvent.h"
 #include "TouchList.h"
 #endif
@@ -127,6 +131,15 @@
 const int GeneralDragHysteresis = 3;
 #endif // ENABLE(DRAG_SUPPORT)
 
+#if ENABLE(IOS_GESTURE_EVENTS)
+const float GestureUnknown = 0;
+#endif
+
+#if ENABLE(IOS_TOUCH_EVENTS)
+// FIXME: Share this constant with EventHandler and SliderThumbElement.
+const unsigned InvalidTouchIdentifier = 0;
+#endif
+
 // Match key code of composition keydown event on windows.
 // IE sends VK_PROCESSKEY which has value 229;
 const int CompositionEventKeyCode = 229;
@@ -142,7 +155,7 @@
 const double fakeMouseMoveShortInterval = 0.1;
 const double fakeMouseMoveLongInterval = 0.25;
 
-#if !PLATFORM(IOS)
+#if ENABLE(CURSOR_SUPPORT)
 // The amount of time to wait for a cursor update on style and layout changes
 // Set to 50Hz, no need to be faster than common screen refresh rate
 const double cursorUpdateInterval = 0.02;
@@ -190,7 +203,7 @@
     double m_start;
 };
 
-#if ENABLE(TOUCH_EVENTS)
+#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
 class SyntheticTouchPoint : public PlatformTouchPoint {
 public:
 
@@ -255,7 +268,7 @@
         m_touchPoints.append(SyntheticTouchPoint(event));
     }
 };
-#endif
+#endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
 
 static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode)
 {
@@ -320,7 +333,9 @@
     , m_mouseDownWasSingleClickInSelection(false)
     , m_selectionInitiationState(HaveNotStartedSelection)
     , m_hoverTimer(this, &EventHandler::hoverTimerFired)
+#if ENABLE(CURSOR_SUPPORT)
     , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired)
+#endif
     , m_autoscrollController(adoptPtr(new AutoscrollController))
     , m_mouseDownMayStartAutoscroll(false)
     , m_mouseDownWasInSubframe(false)
@@ -331,6 +346,15 @@
     , m_resizeLayer(0)
     , m_eventHandlerWillResetCapturingMouseEventsElement(nullptr)
     , m_clickCount(0)
+#if ENABLE(IOS_GESTURE_EVENTS)
+    , m_gestureInitialDiameter(GestureUnknown)
+    , m_gestureLastDiameter(GestureUnknown)
+    , m_gestureInitialRotation(GestureUnknown)
+    , m_gestureLastRotation(GestureUnknown)
+#endif
+#if ENABLE(IOS_TOUCH_EVENTS)
+    , m_firstTouchID(InvalidTouchIdentifier)
+#endif
     , m_mousePositionIsUnknown(true)
     , m_mouseDownTimestamp(0)
     , m_inTrackingScrollGesturePhase(false)
@@ -338,9 +362,11 @@
 #if PLATFORM(MAC)
     , m_mouseDownView(nil)
     , m_sendingEventToSubview(false)
+#if !PLATFORM(IOS)
     , m_activationEventNumber(-1)
+#endif // !PLATFORM(IOS)
 #endif
-#if ENABLE(TOUCH_EVENTS)
+#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
     , m_originatingTouchPointTargetKey(0)
     , m_touchPressed(false)
 #endif
@@ -374,7 +400,9 @@
 void EventHandler::clear()
 {
     m_hoverTimer.stop();
+#if ENABLE(CURSOR_SUPPORT)
     m_cursorUpdateTimer.stop();
+#endif
     m_fakeMouseMoveEventTimer.stop();
 #if ENABLE(CURSOR_VISIBILITY)
     cancelAutoHideCursorTimer();
@@ -390,6 +418,18 @@
     m_lastScrollbarUnderMouse = 0;
     m_clickCount = 0;
     m_clickNode = 0;
+#if ENABLE(IOS_GESTURE_EVENTS)
+    m_gestureInitialDiameter = GestureUnknown;
+    m_gestureLastDiameter = GestureUnknown;
+    m_gestureInitialRotation = GestureUnknown;
+    m_gestureLastRotation = GestureUnknown;
+    m_gestureTargets.clear();
+#endif
+#if ENABLE(IOS_TOUCH_EVENTS)
+    m_touches.clear();
+    m_firstTouchID = InvalidTouchIdentifier;
+    m_touchEventTargetSubframe = 0;
+#endif
     m_frameSetBeingResized = 0;
 #if ENABLE(DRAG_SUPPORT)
     m_dragTarget = 0;
@@ -404,7 +444,7 @@
     m_capturingMouseEventsElement = nullptr;
     m_latchedWheelEventElement = nullptr;
     m_previousWheelScrolledElement = nullptr;
-#if ENABLE(TOUCH_EVENTS)
+#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
     m_originatingTouchPointTargets.clear();
     m_originatingTouchPointDocument.clear();
     m_originatingTouchPointTargetKey = 0;
@@ -973,10 +1013,12 @@
 
 void EventHandler::startPanScrolling(RenderElement* renderer)
 {
+#if !PLATFORM(IOS)
     if (!renderer->isBox())
         return;
     m_autoscrollController->startPanScrolling(toRenderBox(renderer), lastKnownMousePosition());
     invalidateClick();
+#endif
 }
 
 #endif // ENABLE(PAN_SCROLLING)
@@ -1178,6 +1220,7 @@
     return &toFrameView(widget)->frame();
 }
 
+#if ENABLE(CURSOR_SUPPORT)
 static bool isSubmitImage(Node* node)
 {
     return node && isHTMLInputElement(node) && toHTMLInputElement(node)->isImageButton();
@@ -1444,6 +1487,7 @@
     }
     return pointerCursor();
 }
+#endif // ENABLE(CURSOR_SUPPORT)
 
 #if ENABLE(CURSOR_VISIBILITY)
 void EventHandler::startAutoHideCursorTimer()
@@ -1564,6 +1608,11 @@
     m_clickCount = mouseEvent.clickCount();
     m_clickNode = mev.targetNode();
 
+    if (!m_clickNode) {
+        invalidateClick();
+        return false;
+    }
+
     if (FrameView* view = m_frame.view()) {
         RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
         IntPoint p = view->windowToContents(mouseEvent.position());
@@ -1726,7 +1775,9 @@
     if (m_hoverTimer.isActive())
         m_hoverTimer.stop();
 
+#if ENABLE(CURSOR_SUPPORT)
     m_cursorUpdateTimer.stop();
+#endif
 
     cancelFakeMouseMoveEvent();
 
@@ -1740,9 +1791,12 @@
     if (m_frameSetBeingResized)
         return !dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
 
+    // On iOS, our scrollbars are managed by UIKit.
+#if !PLATFORM(IOS)
     // Send events right to a scrollbar if the mouse is pressed.
     if (m_lastScrollbarUnderMouse && m_mousePressed)
         return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
+#endif
 
     HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::DisallowShadowContent | HitTestRequest::AllowFrameScrollbars;
     if (m_mousePressed)
@@ -1755,7 +1809,7 @@
         hitType |= HitTestRequest::ReadOnly;
     }
 
-#if ENABLE(TOUCH_EVENTS)
+#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
     // Treat any mouse move events as readonly if the user is currently touching the screen.
     if (m_touchPressed)
         hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
@@ -1770,8 +1824,12 @@
     else {
         Scrollbar* scrollbar = mev.scrollbar();
         updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
+
+        // On iOS, our scrollbars are managed by UIKit.
+#if !PLATFORM(IOS)
         if (!m_mousePressed && scrollbar)
             scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
+#endif
         if (onlyUpdateScrollbars)
             return true;
     }
@@ -1791,6 +1849,7 @@
         // 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);
+#if ENABLE(CURSOR_SUPPORT)
     } else {
         if (FrameView* view = m_frame.view()) {
             OptionalCursor optionalCursor = selectCursor(mev.hitTestResult(), mouseEvent.shiftKey());
@@ -1799,6 +1858,7 @@
                 view->setCursor(m_currentMouseCursor);
             }
         }
+#endif
     }
     
     m_lastMouseMoveEventSubframe = newSubframe;
@@ -2714,11 +2774,13 @@
         m_hoverTimer.startOneShot(0);
 }
 
+#if ENABLE(CURSOR_SUPPORT)
 void EventHandler::scheduleCursorUpdate()
 {
     if (!m_cursorUpdateTimer.isActive())
         m_cursorUpdateTimer.startOneShot(cursorUpdateInterval);
 }
+#endif
 
 void EventHandler::dispatchFakeMouseMoveEventSoon()
 {
@@ -2830,7 +2892,7 @@
     return true;
 }
 
-#if !PLATFORM(MAC)
+#if !PLATFORM(MAC) || PLATFORM(IOS)
 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
 {
     return false;
@@ -3507,8 +3569,7 @@
     }
 }
 
-#if ENABLE(TOUCH_EVENTS)
-
+#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
 {
     switch (state) {
@@ -3528,7 +3589,7 @@
     }
 }
 
-HitTestResult EventHandler::hitTestResultInFrame(Frame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType)
+static HitTestResult hitTestResultInFrame(Frame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType)
 {
     HitTestResult result(point);
 
@@ -3744,9 +3805,15 @@
 
     return swallowedEvent;
 }
+#endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
 
+#if ENABLE(TOUCH_EVENTS)
 bool EventHandler::dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent& event)
 {
+#if ENABLE(IOS_TOUCH_EVENTS)
+    UNUSED_PARAM(event);
+    return false;
+#else
     if (!m_frame.settings().isTouchEventEmulationEnabled())
         return false;
 
@@ -3765,9 +3832,9 @@
 
     SyntheticSingleTouchEvent touchEvent(event);
     return handleTouchEvent(touchEvent);
-}
-
 #endif
+}
+#endif // ENABLE(TOUCH_EVENTS)
 
 void EventHandler::setLastKnownMousePosition(const PlatformMouseEvent& event)
 {
diff --git a/Source/WebCore/page/EventHandler.h b/Source/WebCore/page/EventHandler.h
index 34c0095..8ed5d96 100644
--- a/Source/WebCore/page/EventHandler.h
+++ b/Source/WebCore/page/EventHandler.h
@@ -42,6 +42,16 @@
 #include <wtf/OwnPtr.h>
 #include <wtf/RefPtr.h>
 
+#if PLATFORM(IOS)
+#ifdef __OBJC__
+@class WebEvent;
+@class WAKView;
+#include "WAKAppKitStubs.h"
+#else
+class WebEvent;
+#endif
+#endif // PLATFORM(IOS)
+
 #if PLATFORM(MAC) && !defined(__OBJC__)
 class NSView;
 #endif
@@ -50,6 +60,11 @@
 #include <wtf/HashMap.h>
 #endif
 
+#if ENABLE(IOS_TOUCH_EVENTS)
+#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
+#endif
+
 namespace WebCore {
 
 class AutoscrollController;
@@ -78,6 +93,7 @@
 class SVGElementInstance;
 class Scrollbar;
 class TextEvent;
+class Touch;
 class TouchEvent;
 class VisibleSelection;
 class WheelEvent;
@@ -92,6 +108,10 @@
 extern const int GeneralDragHysteresis;
 #endif // ENABLE(DRAG_SUPPORT)
 
+#if ENABLE(IOS_GESTURE_EVENTS)
+extern const float GestureUnknown;
+#endif
+
 enum AppendTrailingWhitespace { ShouldAppendTrailingWhitespace, DontAppendTrailingWhitespace };
 enum CheckDragHysteresis { ShouldCheckDragHysteresis, DontCheckDragHysteresis };
 
@@ -144,7 +164,9 @@
 #endif
 
     void scheduleHoverStateUpdate();
+#if ENABLE(CURSOR_SUPPORT)
     void scheduleCursorUpdate();
+#endif
 
     void setResizingFrameSet(HTMLFrameSetElement*);
 
@@ -175,6 +197,24 @@
     void defaultWheelEventHandler(Node*, WheelEvent*);
     bool handlePasteGlobalSelection(const PlatformMouseEvent&);
 
+#if ENABLE(IOS_TOUCH_EVENTS) || ENABLE(IOS_GESTURE_EVENTS)
+    typedef Vector<RefPtr<Touch>> TouchArray;
+    typedef HashMap<EventTarget*, TouchArray*> EventTargetTouchMap;
+    typedef HashSet<RefPtr<EventTarget>> EventTargetSet;
+#endif
+
+#if ENABLE(IOS_TOUCH_EVENTS)
+    bool dispatchTouchEvent(const PlatformTouchEvent&, const AtomicString&, const EventTargetTouchMap&, float, float);
+#endif
+
+#if ENABLE(IOS_GESTURE_EVENTS)
+    bool dispatchGestureEvent(const PlatformTouchEvent&, const AtomicString&, const EventTargetSet&, float, float);
+#endif
+
+#if PLATFORM(IOS)
+    void defaultTouchEventHandler(Node*, TouchEvent*);
+#endif
+
 #if ENABLE(TOUCH_ADJUSTMENT)
     bool bestClickableNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode);
     bool bestContextMenuNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode);
@@ -213,20 +253,42 @@
     void sendScrollEvent(); // Ditto
 
 #if PLATFORM(MAC) && defined(__OBJC__)
+#if !PLATFORM(IOS)
     void mouseDown(NSEvent *);
     void mouseDragged(NSEvent *);
     void mouseUp(NSEvent *);
     void mouseMoved(NSEvent *);
     bool keyEvent(NSEvent *);
     bool wheelEvent(NSEvent *);
+#else
+    void mouseDown(WebEvent *);
+    void mouseUp(WebEvent *);
+    void mouseMoved(WebEvent *);
+    bool keyEvent(WebEvent *);
+    bool wheelEvent(WebEvent *);
+#endif
 
+#if ENABLE(IOS_TOUCH_EVENTS)
+    void touchEvent(WebEvent *);
+#endif
+
+#if !PLATFORM(IOS)
     void passMouseMovedEventToScrollbars(NSEvent *);
 
     void sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent);
+#endif
 
+#if !PLATFORM(IOS)
     void setActivationEventNumber(int num) { m_activationEventNumber = num; }
 
     static NSEvent *currentNSEvent();
+#else
+    static WebEvent *currentEvent();
+#endif // !PLATFORM(IOS)
+#endif // PLATFORM(MAC) && defined(__OBJC__)
+
+#if PLATFORM(IOS)
+    void invalidateClick();
 #endif
 
 #if ENABLE(TOUCH_EVENTS)
@@ -266,7 +328,9 @@
     OptionalCursor selectCursor(const HitTestResult&, bool shiftKey);
 
     void hoverTimerFired(Timer<EventHandler>*);
+#if ENABLE(CURSOR_SUPPORT)
     void cursorUpdateTimerFired(Timer<EventHandler>*);
+#endif
 
     bool logicalScrollOverflow(ScrollLogicalDirection, ScrollGranularity, Node* startingNode = 0);
     
@@ -291,10 +355,11 @@
 
 #if ENABLE(TOUCH_EVENTS)
     bool dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent&);
-    HitTestResult hitTestResultInFrame(Frame*, const LayoutPoint&, HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
 #endif
 
+#if !PLATFORM(IOS)
     void invalidateClick();
+#endif
 
     Node* nodeUnderMouse() const;
     
@@ -401,7 +466,9 @@
     bool m_panScrollButtonPressed;
 
     Timer<EventHandler> m_hoverTimer;
+#if ENABLE(CURSOR_SUPPORT)
     Timer<EventHandler> m_cursorUpdateTimer;
+#endif
 
     OwnPtr<AutoscrollController> m_autoscrollController;
     bool m_mouseDownMayStartAutoscroll;
@@ -429,6 +496,21 @@
     int m_clickCount;
     RefPtr<Node> m_clickNode;
 
+#if ENABLE(IOS_GESTURE_EVENTS)
+    float m_gestureInitialDiameter;
+    float m_gestureLastDiameter;
+    float m_gestureInitialRotation;
+    float m_gestureLastRotation;
+#endif
+
+#if ENABLE(IOS_TOUCH_EVENTS)
+    unsigned m_firstTouchID;
+
+    TouchArray m_touches;
+    EventTargetSet m_gestureTargets;
+    RefPtr<Frame> m_touchEventTargetSubframe;
+#endif
+
 #if ENABLE(DRAG_SUPPORT)
     RefPtr<Element> m_dragTarget;
     bool m_shouldOnlyFireDragOverEvent;
@@ -452,12 +534,14 @@
 
     RefPtr<Element> m_previousWheelScrolledElement;
 
-#if PLATFORM(MAC)
+#if PLATFORM(MAC) || PLATFORM(IOS)
     NSView *m_mouseDownView;
     bool m_sendingEventToSubview;
+#if !PLATFORM(IOS)
     int m_activationEventNumber;
 #endif
-#if ENABLE(TOUCH_EVENTS)
+#endif
+#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
     typedef HashMap<int, RefPtr<EventTarget>> TouchTargetMap;
     TouchTargetMap m_originatingTouchPointTargets;
     RefPtr<Document> m_originatingTouchPointDocument;
diff --git a/Source/WebCore/page/FocusController.h b/Source/WebCore/page/FocusController.h
index b894da6..b449d9c 100644
--- a/Source/WebCore/page/FocusController.h
+++ b/Source/WebCore/page/FocusController.h
@@ -82,6 +82,10 @@
     void setContainingWindowIsVisible(bool);
     bool containingWindowIsVisible() const { return m_containingWindowIsVisible; }
 
+    // These methods are used in WebCore/bindings/objc/DOM.mm.
+    Element* nextFocusableElement(FocusNavigationScope, Node* start, KeyboardEvent*);
+    Element* previousFocusableElement(FocusNavigationScope, Node* start, KeyboardEvent*);
+
 private:
     bool advanceFocusDirectionally(FocusDirection, KeyboardEvent*);
     bool advanceFocusInDocumentOrder(FocusDirection, KeyboardEvent*, bool initialFocus);
@@ -101,9 +105,6 @@
     // See http://www.w3.org/TR/html4/interact/forms.html#h-17.11.1
     Element* findFocusableElement(FocusDirection, FocusNavigationScope, Node* start, KeyboardEvent*);
 
-    Element* nextFocusableElement(FocusNavigationScope, Node* start, KeyboardEvent*);
-    Element* previousFocusableElement(FocusNavigationScope, Node* start, KeyboardEvent*);
-
     Element* findElementWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent*, FocusDirection);
 
     bool advanceFocusDirectionallyInContainer(Node* container, const LayoutRect& startingRect, FocusDirection, KeyboardEvent*);
diff --git a/Source/WebCore/page/Frame.cpp b/Source/WebCore/page/Frame.cpp
index f91806e..d8440ea 100644
--- a/Source/WebCore/page/Frame.cpp
+++ b/Source/WebCore/page/Frame.cpp
@@ -121,10 +121,18 @@
 #include "TiledBackingStore.h"
 #endif
 
+#if PLATFORM(IOS)
+#include "WKContentObservation.h"
+#endif
+
 namespace WebCore {
 
 using namespace HTMLNames;
 
+#if PLATFORM(IOS)
+const unsigned scrollFrequency = 1000 / 60;
+#endif
+
 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, frameCounter, ("Frame"));
 
 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
@@ -163,6 +171,11 @@
     , m_selection(adoptPtr(new FrameSelection(this)))
     , m_eventHandler(adoptPtr(new EventHandler(*this)))
     , m_animationController(std::make_unique<AnimationController>(*this))
+#if PLATFORM(IOS)
+    , m_overflowAutoScrollTimer(this, &Frame::overflowAutoScrollTimerFired)
+    , m_selectionChangeCallbacksDisabled(false)
+    , m_timersPausedCount(0)
+#endif
     , m_pageZoomFactor(parentPageZoomFactor(this))
     , m_textZoomFactor(parentTextZoomFactor(this))
 #if ENABLE(ORIENTATION_EVENTS)
@@ -197,10 +210,17 @@
     frameCounter.increment();
 #endif
 
-    // Pause future ActiveDOMObjects if this frame is being created while the page is in a paused state.
+    // FIXME: We should reconcile the iOS and OpenSource code below.
     Frame* parent = parentFromOwnerElement(ownerElement);
+#if PLATFORM(IOS)
+    // Pause future timers if this frame is created when page is in pending state.
+    if (parent && parent->timersPaused())
+        setTimersPaused(true);
+#else
+    // Pause future ActiveDOMObjects if this frame is being created while the page is in a paused state.
     if (parent && parent->activeDOMObjectsAndAnimationsSuspended())
         suspendActiveDOMObjectsAndAnimations();
+#endif
 }
 
 PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client)
@@ -471,6 +491,160 @@
     return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
 }
 
+#if PLATFORM(IOS)
+void Frame::scrollOverflowLayer(RenderLayer* layer, const IntRect& visibleRect, const IntRect& exposeRect)
+{
+    if (!layer)
+        return;
+
+    RenderBox* box = layer->renderBox();
+    if (!box)
+        return;
+
+    if (visibleRect.intersects(exposeRect))
+        return;
+
+    int x = layer->scrollXOffset();
+    int exposeLeft = exposeRect.x();
+    int exposeRight = exposeLeft + exposeRect.width();
+    int clientWidth = box->clientWidth();
+    if (exposeLeft <= 0)
+        x = std::max(0, x + exposeLeft - clientWidth / 2);
+    else if (exposeRight >= clientWidth)
+        x = std::min(box->scrollWidth() - clientWidth, x + clientWidth / 2);
+
+    int y = layer->scrollYOffset();
+    int exposeTop = exposeRect.y();
+    int exposeBottom = exposeTop + exposeRect.height();
+    int clientHeight = box->clientHeight();
+    if (exposeTop <= 0)
+        y = std::max(0, y + exposeTop - clientHeight / 2);
+    else if (exposeBottom >= clientHeight)
+        y = std::min(box->scrollHeight() - clientHeight, y + clientHeight / 2);
+
+    layer->scrollToOffset(IntSize(x, y));
+    selection().setCaretRectNeedsUpdate();
+    selection().updateAppearance();
+}
+
+void Frame::overflowAutoScrollTimerFired(Timer<Frame>*)
+{
+    if (!eventHandler().mousePressed() || checkOverflowScroll(PerformOverflowScroll) == OverflowScrollNone) {
+        if (m_overflowAutoScrollTimer.isActive())
+            m_overflowAutoScrollTimer.stop();
+    }
+}
+
+void Frame::startOverflowAutoScroll(const IntPoint& mousePosition)
+{
+    m_overflowAutoScrollPos = mousePosition;
+
+    if (m_overflowAutoScrollTimer.isActive())
+        return;
+
+    if (checkOverflowScroll(DoNotPerformOverflowScroll) == OverflowScrollNone)
+        return;
+
+    m_overflowAutoScrollTimer.startRepeating(scrollFrequency);
+    m_overflowAutoScrollDelta = 3;
+}
+
+int Frame::checkOverflowScroll(OverflowScrollAction action)
+{
+    Position extent = selection().selection().extent();
+    if (extent.isNull())
+        return OverflowScrollNone;
+
+    RenderObject* renderer = extent.deprecatedNode()->renderer();
+    if (!renderer)
+        return OverflowScrollNone;
+
+    FrameView* view = this->view();
+    if (!view)
+        return OverflowScrollNone;
+
+    RenderBlock* containingBlock = renderer->containingBlock();
+    if (!containingBlock || !containingBlock->hasOverflowClip())
+        return OverflowScrollNone;
+    RenderLayer* layer = containingBlock->layer();
+    ASSERT(layer);
+
+    IntRect visibleRect = IntRect(view->scrollX(), view->scrollY(), view->visibleWidth(), view->visibleHeight());
+    IntPoint position = m_overflowAutoScrollPos;
+    if (visibleRect.contains(position.x(), position.y()))
+        return OverflowScrollNone;
+
+    int scrollType = 0;
+    int deltaX = 0;
+    int deltaY = 0;
+    IntPoint selectionPosition;
+
+    // This constant will make the selection draw a little bit beyond the edge of the visible area.
+    // This prevents a visual glitch, in that you can fail to select a portion of a character that
+    // is being rendered right at the edge of the visible rectangle.
+    // FIXME: This probably needs improvement, and may need to take the font size into account.
+    static const int scrollBoundsAdjustment = 3;
+
+    // FIXME: Make a small buffer at the end of a visible rectangle so that autoscrolling works 
+    // even if the visible extends to the limits of the screen.
+    if (position.x() < visibleRect.x()) {
+        scrollType |= OverflowScrollLeft;
+        if (action == PerformOverflowScroll) {
+            deltaX -= static_cast<int>(m_overflowAutoScrollDelta);
+            selectionPosition.setX(view->scrollX() - scrollBoundsAdjustment);
+        }
+    } else if (position.x() > visibleRect.maxX()) {
+        scrollType |= OverflowScrollRight;
+        if (action == PerformOverflowScroll) {
+            deltaX += static_cast<int>(m_overflowAutoScrollDelta);
+            selectionPosition.setX(view->scrollX() + view->visibleWidth() + scrollBoundsAdjustment);
+        }
+    }
+
+    if (position.y() < visibleRect.y()) {
+        scrollType |= OverflowScrollUp;
+        if (action == PerformOverflowScroll) {
+            deltaY -= static_cast<int>(m_overflowAutoScrollDelta);
+            selectionPosition.setY(view->scrollY() - scrollBoundsAdjustment);
+        }
+    } else if (position.y() > visibleRect.maxY()) {
+        scrollType |= OverflowScrollDown;
+        if (action == PerformOverflowScroll) {
+            deltaY += static_cast<int>(m_overflowAutoScrollDelta);
+            selectionPosition.setY(view->scrollY() + view->visibleHeight() + scrollBoundsAdjustment);
+        }
+    }
+
+    if (action == PerformOverflowScroll && (deltaX || deltaY)) {
+        layer->scrollToOffset(IntSize(layer->scrollXOffset() + deltaX, layer->scrollYOffset() + deltaY));
+
+        // Handle making selection.
+        VisiblePosition visiblePosition(renderer->positionForPoint(selectionPosition));
+        if (visiblePosition.isNotNull()) {
+            VisibleSelection visibleSelection = selection().selection();
+            visibleSelection.setExtent(visiblePosition);
+            if (selection().granularity() != CharacterGranularity)
+                visibleSelection.expandUsingGranularity(selection().granularity());
+            if (selection().shouldChangeSelection(visibleSelection))
+                selection().setSelection(visibleSelection);
+        }
+
+        m_overflowAutoScrollDelta *= 1.02f; // Accelerate the scroll
+    }
+    return scrollType;
+}
+
+void Frame::setSelectionChangeCallbacksDisabled(bool selectionChangeCallbacksDisabled)
+{
+    m_selectionChangeCallbacksDisabled = selectionChangeCallbacksDisabled;
+}
+
+bool Frame::selectionChangeCallbacksDisabled() const
+{
+    return m_selectionChangeCallbacksDisabled;
+}
+#endif // PLATFORM(IOS)
+
 void Frame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio, AdjustViewSizeOrNot shouldAdjustViewSize)
 {
     // In setting printing, we should not validate resources already cached for the document.
@@ -624,6 +798,11 @@
     if (page() && page()->scrollingCoordinator() && m_view)
         page()->scrollingCoordinator()->willDestroyScrollableArea(m_view.get());
 
+#if PLATFORM(IOS)
+    if (WebThreadCountOfObservedContentModifiers() > 0 && m_page)
+        m_page->chrome().client().clearContentChangeObservers(this);
+#endif
+
     script().clearScriptObjects();
     script().updatePlatformScriptObjects();
 }
@@ -708,7 +887,7 @@
 }
 
 void Frame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent,
-    const IntSize& fixedLayoutSize, const IntRect& fixedVisibleContentRect ,
+    const IntSize& fixedLayoutSize, const IntRect& fixedVisibleContentRect,
     bool useFixedLayout, ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
     ScrollbarMode verticalScrollbarMode, bool verticalLock)
 {
@@ -726,7 +905,11 @@
     if (isMainFrame) {
         frameView = FrameView::create(*this, viewportSize);
         frameView->setFixedLayoutSize(fixedLayoutSize);
+#if !PLATFORM(IOS)
         frameView->setFixedVisibleContentRect(fixedVisibleContentRect);
+#else
+        UNUSED_PARAM(fixedVisibleContentRect);
+#endif
         frameView->setUseFixedLayout(useFixedLayout);
     } else
         frameView = FrameView::create(*this);
diff --git a/Source/WebCore/page/Frame.h b/Source/WebCore/page/Frame.h
index 5f1866f..f55eaaf 100644
--- a/Source/WebCore/page/Frame.h
+++ b/Source/WebCore/page/Frame.h
@@ -37,6 +37,11 @@
 #include "UserScriptTypes.h"
 #include <wtf/RefCounted.h>
 
+#if PLATFORM(IOS)
+#include "ViewportArguments.h"
+#include "VisibleSelection.h"
+#endif
+
 #if PLATFORM(WIN)
 #include "FrameWin.h"
 #endif
@@ -45,6 +50,13 @@
 #include "TiledBackingStoreClient.h"
 #endif
 
+#if PLATFORM(IOS)
+OBJC_CLASS DOMCSSStyleDeclaration;
+OBJC_CLASS DOMNode;
+OBJC_CLASS NSArray;
+OBJC_CLASS NSString;
+#endif
+
 #if PLATFORM(WIN)
 typedef struct HBITMAP__* HBITMAP;
 #endif
@@ -63,12 +75,14 @@
     class FrameView;
     class HTMLFrameOwnerElement;
     class HTMLTableCellElement;
+    class HitTestResult;
     class ImageBuffer;
     class IntRect;
     class MainFrame;
     class Node;
     class Range;
     class RegularExpression;
+    class RenderLayer;
     class RenderView;
     class RenderWidget;
     class ScriptController;
@@ -77,6 +91,19 @@
     class VisiblePosition;
     class Widget;
 
+#if PLATFORM(IOS)
+    enum {
+        OverflowScrollNone = 0,
+        OverflowScrollLeft = 1 << 0,
+        OverflowScrollRight = 1 << 1,
+        OverflowScrollUp = 1 << 2,
+        OverflowScrollDown = 1 << 3
+    };
+
+    enum OverflowScrollAction { DoNotPerformOverflowScroll, PerformOverflowScroll };
+    typedef Node* (*NodeQualifier)(const HitTestResult&, Node* terminationNode, IntRect* nodeBounds);
+#endif
+
 #if !USE(TILED_BACKING_STORE)
     class TiledBackingStoreClient { };
 #endif
@@ -96,6 +123,10 @@
         static PassRefPtr<Frame> create(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*);
 
         void init();
+#if PLATFORM(IOS)
+        // Creates <html><body style="..."></body></html> doing minimal amount of work.
+        void initWithSimpleHTMLDocument(const String& style, const URL&);
+#endif
         void setView(PassRefPtr<FrameView>);
         void createView(const IntSize&, const Color&, bool,
             const IntSize& fixedLayoutSize = IntSize(), const IntRect& fixedVisibleContentRect = IntRect(),
@@ -165,6 +196,30 @@
         void deviceOrPageScaleFactorChanged();
 #endif
 
+#if PLATFORM(IOS)
+        const ViewportArguments& viewportArguments() const;
+        void setViewportArguments(const ViewportArguments&);
+
+        Node* deepestNodeAtLocation(const FloatPoint& viewportLocation);
+        Node* nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation);
+        Node* nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation);
+
+        int indexCountOfWordPrecedingSelection(NSString* word) const;
+        NSArray* wordsInCurrentParagraph() const;
+        CGRect renderRectForPoint(CGPoint, bool* isReplaced, float* fontSize) const;
+
+        void setSelectionChangeCallbacksDisabled(bool = true);
+        bool selectionChangeCallbacksDisabled() const;
+
+        enum ViewportOffsetChangeType { IncrementalScrollOffset, CompletedScrollOffset };
+        void viewportOffsetChanged(ViewportOffsetChangeType);
+        bool containsTiledBackingLayers() const;
+
+        void overflowScrollPositionChangedForNode(const IntPoint&, Node*, bool isUserScroll);
+
+        void resetAllGeolocationPermission();
+#endif
+
 #if ENABLE(ORIENTATION_EVENTS)
         // Orientation is the interface orientation in degrees. Some examples are:
         //  0 is straight up; -90 is when the device is rotated 90 clockwise;
@@ -191,6 +246,33 @@
         float textAutosizingWidth() const;
 #endif
 
+#if PLATFORM(IOS)
+        // Scroll the selection in an overflow layer on iOS.
+        void scrollOverflowLayer(RenderLayer* , const IntRect& visibleRect, const IntRect& exposeRect);
+
+        int preferredHeight() const;
+        int innerLineHeight(DOMNode*) const;
+        void updateLayout() const;
+        NSRect caretRect() const;
+        NSRect rectForScrollToVisible() const;
+        NSRect rectForSelection(VisibleSelection&) const;
+        DOMCSSStyleDeclaration* styleAtSelectionStart() const;
+        unsigned formElementsCharacterCount() const;
+        void setTimersPaused(bool);
+        bool timersPaused() const { return m_timersPausedCount; }
+        void dispatchPageHideEventBeforePause();
+        void dispatchPageShowEventBeforeResume();
+        void setRangedSelectionBaseToCurrentSelection();
+        void setRangedSelectionBaseToCurrentSelectionStart();
+        void setRangedSelectionBaseToCurrentSelectionEnd();
+        void clearRangedSelectionInitialExtent();
+        void setRangedSelectionInitialExtentToCurrentSelectionStart();
+        void setRangedSelectionInitialExtentToCurrentSelectionEnd();
+        VisibleSelection rangedSelectionBase() const;
+        VisibleSelection rangedSelectionInitialExtent() const;
+        void recursiveSetUpdateAppearanceEnabled(bool);
+        NSArray* interpretationsForCurrentRoot() const;
+#endif
         void suspendActiveDOMObjectsAndAnimations();
         void resumeActiveDOMObjectsAndAnimations();
         bool activeDOMObjectsAndAnimationsSuspended() const { return m_activeDOMObjectsAndAnimationsSuspendedCount > 0; }
@@ -224,6 +306,27 @@
         const OwnPtr<EventHandler> m_eventHandler;
         const std::unique_ptr<AnimationController> m_animationController;
 
+#if PLATFORM(IOS)
+        void betterApproximateNode(const IntPoint& testPoint, NodeQualifier, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect);
+        bool hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult&, IntPoint& center);
+        Node* qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, NodeQualifier, bool shouldApproximate);
+
+        void overflowAutoScrollTimerFired(Timer<Frame>*);
+        void startOverflowAutoScroll(const IntPoint&);
+        int checkOverflowScroll(OverflowScrollAction);
+
+        void setTimersPausedInternal(bool);
+
+        Timer<Frame> m_overflowAutoScrollTimer;
+        float m_overflowAutoScrollDelta;
+        IntPoint m_overflowAutoScrollPos;
+        ViewportArguments m_viewportArguments;
+        bool m_selectionChangeCallbacksDisabled;
+        int m_timersPausedCount;
+        VisibleSelection m_rangedSelectionBase;
+        VisibleSelection m_rangedSelectionInitialExtent;
+#endif
+
 #if ENABLE(IOS_TEXT_AUTOSIZING)
         float m_textAutosizingWidth;
 #endif
diff --git a/Source/WebCore/page/FrameView.cpp b/Source/WebCore/page/FrameView.cpp
index 1fe2f2e..bdcaa75 100644
--- a/Source/WebCore/page/FrameView.cpp
+++ b/Source/WebCore/page/FrameView.cpp
@@ -65,6 +65,7 @@
 #include "RenderScrollbar.h"
 #include "RenderScrollbarPart.h"
 #include "RenderStyle.h"
+#include "RenderText.h"
 #include "RenderTheme.h"
 #include "RenderView.h"
 #include "RenderWidget.h"
@@ -98,6 +99,19 @@
 #include "TextAutosizer.h"
 #endif
 
+#if PLATFORM(IOS)
+#include "DocumentLoader.h"
+#include "Logging.h"
+#include "MemoryCache.h"
+#include "MemoryPressureHandler.h"
+#include "SystemMemory.h"
+#include "TileCache.h"
+#endif
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "HTMLMediaElement.h"
+#endif
+
 namespace WebCore {
 
 using namespace HTMLNames;
@@ -190,6 +204,9 @@
     , m_deferSetNeedsLayouts(0)
     , m_setNeedsLayoutWasDeferred(false)
     , m_scrollCorner(0)
+#if PLATFORM(IOS)
+    , m_useCustomFixedPositionLayoutRect(false)
+#endif
     , m_shouldAutoSize(false)
     , m_inAutoSize(false)
     , m_didRunAutosize(false)
@@ -392,6 +409,13 @@
     reset();
 
     setScrollbarsSuppressed(true);
+
+#if PLATFORM(IOS)
+    // To avoid flashes of white, disable tile updates immediately when view is cleared at the beginning of a page load.
+    // Tiling will be re-enabled from UIKit via [WAKWindow setTilingMode:] when we have content to draw.
+    if (TileCache* tileCache = this->tileCache())
+        tileCache->setTilingMode(TileCache::Disabled);
+#endif
 }
 
 bool FrameView::didFirstLayout() const
@@ -883,6 +907,11 @@
     // visible flash to occur. Instead, stop the deferred repaint timer and repaint immediately.
     flushDeferredRepaints();
 
+#if PLATFORM(IOS)
+    if (TileCache* tileCache = this->tileCache())
+        tileCache->doPendingRepaints();
+#endif
+
     renderView->compositor().flushPendingLayerChanges(rootFrameForFlush == &frame());
 
     return true;
@@ -894,6 +923,39 @@
         page->chrome().client().setNeedsOneShotDrawingSynchronization();
 }
 
+GraphicsLayer* FrameView::graphicsLayerForPlatformWidget(PlatformWidget platformWidget)
+{
+    // To find the Widget that corresponds with platformWidget we have to do a linear
+    // search of our child widgets.
+    Widget* foundWidget = nullptr;
+    for (auto& widget : children()) {
+        if (widget->platformWidget() != platformWidget)
+            continue;
+        foundWidget = widget.get();
+        break;
+    }
+
+    if (!foundWidget)
+        return nullptr;
+
+    auto* renderWidget = RenderWidget::find(foundWidget);
+    if (!renderWidget)
+        return nullptr;
+
+    RenderLayer* widgetLayer = renderWidget->layer();
+    if (!widgetLayer || !widgetLayer->isComposited())
+        return nullptr;
+
+    return widgetLayer->backing()->parentForSublayers();
+}
+
+void FrameView::scheduleLayerFlushAllowingThrottling()
+{
+    RenderView* view = this->renderView();
+    if (!view)
+        return;
+    view->compositor().scheduleLayerFlush(true /* canThrottle */);
+}
 #endif // USE(ACCELERATED_COMPOSITING)
 
 void FrameView::setHeaderHeight(int headerHeight)
@@ -1082,6 +1144,11 @@
             return;
     }
 
+#if PLATFORM(IOS)
+    if (updateFixedPositionLayoutRect())
+        allowSubtree = false;
+#endif
+
     m_layoutTimer.stop();
     m_delayedLayout = false;
     m_setNeedsLayoutWasDeferred = false;
@@ -1198,7 +1265,11 @@
                     if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling())
                         m_lastViewportSize = fixedLayoutSize();
                     else
+#if PLATFORM(IOS)
+                        m_lastViewportSize = actualVisibleContentRect().size();
+#else
                         m_lastViewportSize = visibleContentRect(IncludeScrollbars).size();
+#endif
 
                     m_lastZoomFactor = root->style().zoom();
 
@@ -1313,6 +1384,10 @@
     updateAnnotatedRegions();
 #endif
 
+#if ENABLE(IOS_TOUCH_EVENTS)
+    document.dirtyTouchEventRects();
+#endif
+
     ASSERT(!root->needsLayout());
 
     updateCanBlitOnScrollRecursively();
@@ -1902,6 +1977,7 @@
 #endif
 }
 
+#if !PLATFORM(IOS)
 void FrameView::setFixedVisibleContentRect(const IntRect& visibleContentRect)
 {
     bool visibleContentSizeDidChange = false;
@@ -1927,6 +2003,7 @@
     }
     frame().loader().client().didChangeScrollOffset();
 }
+#endif
 
 void FrameView::setViewportConstrainedObjectsNeedLayout()
 {
@@ -2120,6 +2197,27 @@
     ScrollView::repaintContentRectangle(r, immediate);
 }
 
+static unsigned countRenderedCharactersInRenderObjectWithThreshold(const RenderObject& renderer, unsigned countSoFar, unsigned threshold)
+{
+    // FIXME: Consider writing this using RenderObject::nextInPreOrder() instead of using recursion.
+    if (renderer.isText())
+        countSoFar += toRenderText(renderer).text()->length();
+
+    for (RenderObject* child = renderer.firstChildSlow(); child; child = child->nextSibling()) {
+        if (countSoFar >= threshold)
+            break;
+        countSoFar = countRenderedCharactersInRenderObjectWithThreshold(*child, countSoFar, threshold);
+    }
+    return countSoFar;
+}
+
+bool FrameView::renderedCharactersExceed(unsigned threshold)
+{
+    if (!m_frame->contentRenderer())
+        return false;
+    return countRenderedCharactersInRenderObjectWithThreshold(*m_frame->contentRenderer(), 0, threshold) >= threshold;
+}
+
 void FrameView::contentsResized()
 {
     ScrollView::contentsResized();
@@ -2144,6 +2242,18 @@
     if (!frame().view())
         return;
 
+#if PLATFORM(IOS)
+    if (RenderView* root = m_frame->contentRenderer()) {
+        if (useCustomFixedPositionLayoutRect() && hasViewportConstrainedObjects()) {
+            setViewportConstrainedObjectsNeedLayout();
+            // We must eagerly enter compositing mode because fixed position elements
+            // will not have been made compositing via a preceding style change before
+            // m_useCustomFixedPositionLayoutRect was true.
+            root->compositor().enableCompositingMode();
+        }
+    }
+#endif
+
     if (!useFixedLayout() && needsLayout())
         layout();
 
@@ -2320,6 +2430,10 @@
     if (renderView && renderView->layer()->backing())
         renderView->layer()->backing()->adjustTiledBackingCoverage();
 #endif
+#if PLATFORM(IOS)
+    if (TileCache* tileCache = this->tileCache())
+        tileCache->setSpeculativeTileCreationEnabled(!m_frame->page()->progress().isMainLoadProgressing());
+#endif
 }
 
 void FrameView::layoutTimerFired(Timer<FrameView>*)
@@ -2681,6 +2795,14 @@
         }
     }
 
+#if PLATFORM(IOS)
+    // Only send layout-related delegate callbacks synchronously for the main frame to
+    // avoid re-entering layout for the main frame while delivering a layout-related delegate
+    // callback for a subframe.
+    if (frame().isMainFrame())
+        page->chrome().client().didLayout();
+#endif
+
     if (milestonesAchieved && frame().isMainFrame())
         frame().loader().didLayout(milestonesAchieved);
 
@@ -2733,7 +2855,11 @@
     if (useFixedLayout() && !fixedLayoutSize().isEmpty() && delegatesScrolling())
         currentSize = fixedLayoutSize();
     else
+#if PLATFORM(IOS)
+        currentSize = actualVisibleContentRect().size();
+#else
         currentSize = visibleContentRect(IncludeScrollbars).size();
+#endif
 
     float currentZoomFactor = renderView->style().zoom();
     bool shouldSendResizeEvent = !m_firstLayout && (currentSize != m_lastViewportSize || currentZoomFactor != m_lastZoomFactor);
@@ -2744,6 +2870,16 @@
     if (!shouldSendResizeEvent)
         return;
 
+#if PLATFORM(IOS)
+    // Don't send the resize event if the document is loading. Some pages automatically reload
+    // when the window is resized; Safari on iOS often resizes the window while setting up its
+    // viewport. This obviously can cause problems.
+    if (DocumentLoader* documentLoader = frame().loader().documentLoader()) {
+        if (documentLoader->isLoadingInAPISense())
+            return;
+    }
+#endif
+
     bool isMainFrame = frame().isMainFrame();
     bool canSendResizeEventSynchronously = isMainFrame && !isInLayout();
 
@@ -3423,6 +3559,16 @@
         InspectorInstrumentation::willPaint(renderView);
 
     bool isTopLevelPainter = !sCurrentPaintTimeStamp;
+#if PLATFORM(IOS)
+    // FIXME: Remove PLATFORM(IOS)-guard once we upstream the iOS changes to MemoryPressureHandler.h.
+    if (isTopLevelPainter && memoryPressureHandler().hasReceivedMemoryPressure()) {
+        LOG(MemoryPressure, "Under memory pressure: %s", __PRETTY_FUNCTION__);
+
+        // To avoid unnecessary image decoding, we don't prune recently-decoded live resources here since
+        // we might need some live bitmaps on painting.
+        memoryCache()->prune();
+    }
+#endif
     if (isTopLevelPainter)
         sCurrentPaintTimeStamp = monotonicallyIncreasingTime();
 
@@ -3475,6 +3621,14 @@
     m_paintBehavior = oldPaintBehavior;
     m_lastPaintTime = monotonicallyIncreasingTime();
 
+#if PLATFORM(IOS)
+    // Painting can lead to decoding of large amounts of bitmaps
+    // If we are low on memory, wipe them out after the paint.
+    // FIXME: Remove PLATFORM(IOS)-guard once we upstream the iOS changes to MemoryPressureHandler.h.
+    if (isTopLevelPainter && memoryPressureHandler().hasReceivedMemoryPressure())
+        memoryCache()->pruneLiveResources(true);
+#endif
+
     // Regions may have changed as a result of the visibility/z-index of element changing.
 #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
     if (document->annotatedRegionsDirty())
@@ -4049,6 +4203,43 @@
     return 0;
 }
     
+#if PLATFORM(IOS)
+void FrameView::setUseCustomFixedPositionLayoutRect(bool useCustomFixedPositionLayoutRect)
+{
+    if (m_useCustomFixedPositionLayoutRect == useCustomFixedPositionLayoutRect)
+        return;
+    m_useCustomFixedPositionLayoutRect = useCustomFixedPositionLayoutRect;
+    visibleContentsResized();
+}
+
+void FrameView::setCustomFixedPositionLayoutRect(const IntRect& rect)
+{
+    if (m_useCustomFixedPositionLayoutRect && m_customFixedPositionLayoutRect == rect)
+        return;
+    m_useCustomFixedPositionLayoutRect = true;
+    m_customFixedPositionLayoutRect = rect;
+    visibleContentsResized();
+}
+
+bool FrameView::updateFixedPositionLayoutRect()
+{
+    if (!m_useCustomFixedPositionLayoutRect)
+        return false;
+
+    IntRect newRect;
+    Page* page = frame().page();
+    if (!page || !page->chrome().client().fetchCustomFixedPositionLayoutRect(newRect))
+        return false;
+
+    if (newRect != m_customFixedPositionLayoutRect) {
+        m_customFixedPositionLayoutRect = newRect;
+        setViewportConstrainedObjectsNeedLayout();
+        return true;
+    }
+    return false;
+}
+#endif // PLATFORM(IOS)
+
 void FrameView::setScrollingPerformanceLoggingEnabled(bool flag)
 {
 #if USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/page/FrameView.h b/Source/WebCore/page/FrameView.h
index d657ae4..b320f9c 100644
--- a/Source/WebCore/page/FrameView.h
+++ b/Source/WebCore/page/FrameView.h
@@ -120,6 +120,16 @@
 
     bool needsFullRepaint() const { return m_needsFullRepaint; }
 
+    bool renderedCharactersExceed(unsigned threshold);
+
+#if PLATFORM(IOS)
+    bool useCustomFixedPositionLayoutRect() const { return m_useCustomFixedPositionLayoutRect; }
+    void setUseCustomFixedPositionLayoutRect(bool);
+    IntRect customFixedPositionLayoutRect() const { return m_customFixedPositionLayoutRect; }
+    void setCustomFixedPositionLayoutRect(const IntRect&);
+    bool updateFixedPositionLayoutRect();
+#endif
+
 #if ENABLE(REQUEST_ANIMATION_FRAME)
     void serviceScriptedAnimations(double monotonicAnimationStartTime);
 #endif
@@ -136,6 +146,9 @@
     // content rendered via the normal painting path.
     void setNeedsOneShotDrawingSynchronization();
 
+    GraphicsLayer* graphicsLayerForPlatformWidget(PlatformWidget);
+    void scheduleLayerFlushAllowingThrottling();
+
     virtual TiledBacking* tiledBacking() OVERRIDE;
 
     // In the future when any ScrollableArea can have a node in th ScrollingTree, this should
@@ -192,7 +205,9 @@
 
     virtual float visibleContentScaleFactor() const OVERRIDE;
 
+#if !PLATFORM(IOS)
     virtual void setFixedVisibleContentRect(const IntRect&) OVERRIDE;
+#endif
     virtual void setScrollPosition(const IntPoint&) OVERRIDE;
     void scrollPositionChangedViaPlatformWidget();
     virtual void updateLayerPositionsAfterScrolling() OVERRIDE;
@@ -631,6 +646,11 @@
     // Renderer to hold our custom scroll corner.
     RenderScrollbarPart* m_scrollCorner;
 
+#if PLATFORM(IOS)
+    bool m_useCustomFixedPositionLayoutRect;
+    IntRect m_customFixedPositionLayoutRect;
+#endif
+
     // If true, automatically resize the frame view around its content.
     bool m_shouldAutoSize;
     bool m_inAutoSize;
diff --git a/Source/WebCore/page/Navigator.cpp b/Source/WebCore/page/Navigator.cpp
index ab58a68..b88015b 100644
--- a/Source/WebCore/page/Navigator.cpp
+++ b/Source/WebCore/page/Navigator.cpp
@@ -132,6 +132,13 @@
     return true;
 }
 
+#if PLATFORM(IOS)
+bool Navigator::standalone() const
+{
+    return m_frame && m_frame->settings().standalone();
+}
+#endif
+
 void Navigator::getStorageUpdates()
 {
     // FIXME: Remove this method or rename to yieldForStorageUpdates.
diff --git a/Source/WebCore/page/Navigator.h b/Source/WebCore/page/Navigator.h
index 9315213..044485e 100644
--- a/Source/WebCore/page/Navigator.h
+++ b/Source/WebCore/page/Navigator.h
@@ -53,6 +53,10 @@
 
     virtual String userAgent() const;
 
+#if PLATFORM(IOS)
+    bool standalone() const;
+#endif
+
     // Relinquishes the storage lock, if one exists.
     void getStorageUpdates();
 
diff --git a/Source/WebCore/page/Navigator.idl b/Source/WebCore/page/Navigator.idl
index acc51ac..638d5a5 100644
--- a/Source/WebCore/page/Navigator.idl
+++ b/Source/WebCore/page/Navigator.idl
@@ -37,6 +37,11 @@
 
     readonly attribute boolean onLine;
 
+    // FIXME: Convert this #if'def to an IDL conditional attribute.
+#if defined(WTF_PLATFORM_IOS) && WTF_PLATFORM_IOS
+    readonly attribute boolean standalone;
+#endif
+
     void getStorageUpdates(); // FIXME: Remove this method or rename to yieldForStorageUpdates.
 };
 
diff --git a/Source/WebCore/page/NavigatorBase.cpp b/Source/WebCore/page/NavigatorBase.cpp
index 7febae4..c89137d 100644
--- a/Source/WebCore/page/NavigatorBase.cpp
+++ b/Source/WebCore/page/NavigatorBase.cpp
@@ -35,8 +35,14 @@
 #include <wtf/StdLibExtras.h>
 #endif
 
+#if PLATFORM(IOS)
+#include "WebCoreSystemInterface.h"
+#endif
+
 #ifndef WEBCORE_NAVIGATOR_PLATFORM
-#if OS(MAC_OS_X) && (CPU(PPC) || CPU(PPC64))
+#if PLATFORM(IOS)
+#define WEBCORE_NAVIGATOR_PLATFORM ""
+#elif OS(MAC_OS_X) && (CPU(PPC) || CPU(PPC64))
 #define WEBCORE_NAVIGATOR_PLATFORM "MacPPC"
 #elif OS(MAC_OS_X) && (CPU(X86) || CPU(X86_64))
 #define WEBCORE_NAVIGATOR_PLATFORM "MacIntel"
diff --git a/Source/WebCore/page/Page.h b/Source/WebCore/page/Page.h
index 87d0d4a..ced968f 100644
--- a/Source/WebCore/page/Page.h
+++ b/Source/WebCore/page/Page.h
@@ -48,6 +48,10 @@
 #include <wtf/SchedulePair.h>
 #endif
 
+#if PLATFORM(IOS)
+#include "Settings.h"
+#endif
+
 namespace JSC {
 class Debugger;
 }
@@ -321,9 +325,16 @@
     StorageNamespace* sessionStorage(bool optionalCreate = true);
     void setSessionStorage(PassRefPtr<StorageNamespace>);
 
+    // FIXME: We should make Settings::maxParseDuration() platform-independent, remove {has, set}CustomHTMLTokenizerTimeDelay()
+    // and customHTMLTokenizerTimeDelay() and modify theirs callers to update or query Settings::maxParseDuration().
     void setCustomHTMLTokenizerTimeDelay(double);
+#if PLATFORM(IOS)
+    bool hasCustomHTMLTokenizerTimeDelay() const { return m_settings->maxParseDuration() != -1; }
+    double customHTMLTokenizerTimeDelay() const { ASSERT(m_settings->maxParseDuration() != -1); return m_settings->maxParseDuration(); }
+#else
     bool hasCustomHTMLTokenizerTimeDelay() const { return m_customHTMLTokenizerTimeDelay != -1; }
     double customHTMLTokenizerTimeDelay() const { ASSERT(m_customHTMLTokenizerTimeDelay != -1); return m_customHTMLTokenizerTimeDelay; }
+#endif
 
     void setCustomHTMLTokenizerChunkSize(int);
     bool hasCustomHTMLTokenizerChunkSize() const { return m_customHTMLTokenizerChunkSize != -1; }
diff --git a/Source/WebCore/page/PageGroup.cpp b/Source/WebCore/page/PageGroup.cpp
index a6aa775..e435576 100644
--- a/Source/WebCore/page/PageGroup.cpp
+++ b/Source/WebCore/page/PageGroup.cpp
@@ -217,6 +217,16 @@
     addVisitedLink(visitedLinkHash(characters, length));
 }
 
+void PageGroup::removeVisitedLink(const URL& url)
+{
+    LinkHash hash = visitedLinkHash(url.string());
+    ASSERT(m_visitedLinkHashes.contains(hash));
+    m_visitedLinkHashes.remove(hash);
+
+    Page::allVisitedStateChanged(this);
+    pageCache()->markPagesForVistedLinkStyleRecalc();
+}
+
 void PageGroup::removeVisitedLinks()
 {
     m_visitedLinksPopulated = false;
diff --git a/Source/WebCore/page/PageGroup.h b/Source/WebCore/page/PageGroup.h
index 08fa74a..2551ec0 100644
--- a/Source/WebCore/page/PageGroup.h
+++ b/Source/WebCore/page/PageGroup.h
@@ -77,6 +77,7 @@
         void addVisitedLink(const URL&);
         void addVisitedLink(const UChar*, size_t);
         void addVisitedLinkHash(LinkHash);
+        void removeVisitedLink(const URL&);
         void removeVisitedLinks();
 
         static void setShouldTrackVisitedLinks(bool);
diff --git a/Source/WebCore/page/Settings.cpp b/Source/WebCore/page/Settings.cpp
index c5fad49..18c08e4 100644
--- a/Source/WebCore/page/Settings.cpp
+++ b/Source/WebCore/page/Settings.cpp
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "Settings.h"
 
+#include "AudioSession.h"
 #include "BackForwardController.h"
 #include "CachedResourceLoader.h"
 #include "CookieStorage.h"
@@ -45,6 +46,8 @@
 #include "StorageMap.h"
 #include "TextAutosizer.h"
 #include <limits>
+#include <wtf/NeverDestroyed.h>
+
 
 namespace WebCore {
 
@@ -93,6 +96,10 @@
 bool Settings::gShouldRespectPriorityInCSSAttributeSetters = false;
 bool Settings::gLowPowerVideoAudioBufferSizeEnabled = false;
 
+#if PLATFORM(IOS)
+bool Settings::gNetworkDataUsageTrackingEnabled = false;
+#endif
+
 // NOTEs
 //  1) EditingMacBehavior comprises Tiger, Leopard, SnowLeopard and iOS builds, as well as QtWebKit when built on Mac;
 //  2) EditingWindowsBehavior comprises Win32 and WinCE builds, as well as QtWebKit and Chromium when built on Windows;
@@ -146,6 +153,9 @@
     , m_fontGenericFamilies(std::make_unique<FontGenericFamilies>())
     , m_storageBlockingPolicy(SecurityOrigin::AllowAllStorage)
     , m_layoutInterval(layoutScheduleThreshold)
+#if PLATFORM(IOS)
+    , m_maxParseDuration(-1)
+#endif
 #if ENABLE(TEXT_AUTOSIZING)
     , m_textAutosizingFontScaleFactor(1)
 #if HACK_FORCE_TEXT_AUTOSIZING_ON_DESKTOP
@@ -168,6 +178,15 @@
     , m_usesPageCache(false)
     , m_fontRenderingMode(0)
     , m_isCSSCustomFilterEnabled(false)
+#if PLATFORM(IOS)
+    , m_standalone(false)
+    , m_telephoneNumberParsingEnabled(false)
+    , m_mediaDataLoadsAutomatically(false)
+    , m_shouldTransformsAffectOverflow(true)
+    , m_shouldDispatchJavaScriptWindowOnErrorEvents(false)
+    , m_alwaysUseBaselineOfPrimaryFont(false)
+    , m_alwaysUseAcceleratedOverflowScroll(false)
+#endif
 #if ENABLE(CSS_STICKY_POSITION)
     , m_cssStickyPositionEnabled(true)
 #endif
@@ -382,7 +401,15 @@
 
 void Settings::setScriptEnabled(bool isScriptEnabled)
 {
+#if PLATFORM(IOS)
+    if (m_isScriptEnabled == isScriptEnabled)
+        return;
+#endif
+
     m_isScriptEnabled = isScriptEnabled;
+#if PLATFORM(IOS)
+    m_page->setNeedsRecalcStyleInAllFrames();
+#endif
     InspectorInstrumentation::scriptsEnabled(m_page, m_isScriptEnabled);
 }
 
@@ -681,4 +708,47 @@
     gLowPowerVideoAudioBufferSizeEnabled = flag;
 }
 
+#if PLATFORM(IOS)
+void Settings::setStandalone(bool standalone)
+{
+    m_standalone = standalone;
+}
+
+void Settings::setAudioSessionCategoryOverride(unsigned sessionCategory)
+{
+    AudioSession::sharedSession().setCategoryOverride(static_cast<AudioSession::CategoryType>(sessionCategory));
+}
+
+unsigned Settings::audioSessionCategoryOverride()
+{
+    return AudioSession::sharedSession().categoryOverride();
+}
+
+void Settings::setNetworkDataUsageTrackingEnabled(bool trackingEnabled)
+{
+    gNetworkDataUsageTrackingEnabled = trackingEnabled;
+}
+
+bool Settings::networkDataUsageTrackingEnabled()
+{
+    return gNetworkDataUsageTrackingEnabled;
+}
+
+static String& sharedNetworkInterfaceNameGlobal()
+{
+    static NeverDestroyed<String> networkInterfaceName;
+    return networkInterfaceName;
+}
+
+void Settings::setNetworkInterfaceName(const String& networkInterfaceName)
+{
+    sharedNetworkInterfaceNameGlobal() = networkInterfaceName;
+}
+
+const String& Settings::networkInterfaceName()
+{
+    return sharedNetworkInterfaceNameGlobal();
+}
+#endif
+
 } // namespace WebCore
diff --git a/Source/WebCore/page/Settings.h b/Source/WebCore/page/Settings.h
index 0501141..96205fd 100644
--- a/Source/WebCore/page/Settings.h
+++ b/Source/WebCore/page/Settings.h
@@ -180,6 +180,33 @@
     void setHiddenPageDOMTimerThrottlingEnabled(bool);
 #endif
 
+#if PLATFORM(IOS)
+    // FIXME: This setting isn't specific to iOS.
+    void setMaxParseDuration(double maxParseDuration) { m_maxParseDuration = maxParseDuration; }
+    double maxParseDuration() const { return m_maxParseDuration; }
+
+    void setStandalone(bool);
+    bool standalone() const { return m_standalone; }
+
+    void setTelephoneNumberParsingEnabled(bool flag) { m_telephoneNumberParsingEnabled = flag; }
+    bool telephoneNumberParsingEnabled() const { return m_telephoneNumberParsingEnabled; }
+
+    void setMediaDataLoadsAutomatically(bool flag) { m_mediaDataLoadsAutomatically = flag; }
+    bool mediaDataLoadsAutomatically() const { return m_mediaDataLoadsAutomatically; }
+
+    void setShouldTransformsAffectOverflow(bool flag) { m_shouldTransformsAffectOverflow = flag; }
+    bool shouldTransformsAffectOverflow() const { return m_shouldTransformsAffectOverflow; }
+
+    void setShouldDispatchJavaScriptWindowOnErrorEvents(bool flag) { m_shouldDispatchJavaScriptWindowOnErrorEvents = flag; }
+    bool shouldDispatchJavaScriptWindowOnErrorEvents() const { return m_shouldDispatchJavaScriptWindowOnErrorEvents; }
+
+    void setAlwaysUseBaselineOfPrimaryFont(bool flag) { m_alwaysUseBaselineOfPrimaryFont = flag; }
+    bool alwaysUseBaselineOfPrimaryFont() const { return m_alwaysUseBaselineOfPrimaryFont; }
+
+    void setAlwaysUseAcceleratedOverflowScroll(bool flag) { m_alwaysUseAcceleratedOverflowScroll = flag; }
+    bool alwaysUseAcceleratedOverflowScroll() const { return m_alwaysUseAcceleratedOverflowScroll; }
+#endif
+
     void setUsesPageCache(bool);
     bool usesPageCache() const { return m_usesPageCache; }
         
@@ -268,6 +295,17 @@
     static bool isVideoPluginProxyEnabled() { return gVideoPluginProxyEnabled; }
 #endif
 
+#if PLATFORM(IOS)
+    static void setAudioSessionCategoryOverride(unsigned);
+    static unsigned audioSessionCategoryOverride();
+
+    static void setNetworkDataUsageTrackingEnabled(bool);
+    static bool networkDataUsageTrackingEnabled();
+
+    static void setNetworkInterfaceName(const String&);
+    static const String& networkInterfaceName();
+#endif
+
 private:
     explicit Settings(Page*);
 
@@ -281,6 +319,9 @@
     const std::unique_ptr<FontGenericFamilies> m_fontGenericFamilies;
     SecurityOrigin::StorageBlockingPolicy m_storageBlockingPolicy;
     int m_layoutInterval;
+#if PLATFORM(IOS)
+    double m_maxParseDuration;
+#endif
 #if ENABLE(TEXT_AUTOSIZING)
     float m_textAutosizingFontScaleFactor;
     IntSize m_textAutosizingWindowSizeOverride;
@@ -301,6 +342,16 @@
     bool m_usesPageCache : 1;
     unsigned m_fontRenderingMode : 1;
     bool m_isCSSCustomFilterEnabled : 1;
+#if PLATFORM(IOS)
+    bool m_standalone : 1;
+    bool m_telephoneNumberParsingEnabled : 1;
+    bool m_mediaDataLoadsAutomatically : 1;
+    bool m_shouldTransformsAffectOverflow : 1;
+    bool m_shouldDispatchJavaScriptWindowOnErrorEvents : 1;
+    bool m_alwaysUseBaselineOfPrimaryFont : 1;
+    bool m_allowMultiElementImplicitFormSubmission : 1;
+    bool m_alwaysUseAcceleratedOverflowScroll : 1;
+#endif
 #if ENABLE(CSS_STICKY_POSITION)
     bool m_cssStickyPositionEnabled : 1;
 #endif
@@ -348,6 +399,9 @@
     static bool gShouldUseHighResolutionTimers;
 #endif
     static bool gShouldRespectPriorityInCSSAttributeSetters;
+#if PLATFORM(IOS)
+    static bool gNetworkDataUsageTrackingEnabled;
+#endif
 
     static double gHiddenPageDOMTimerAlignmentInterval;
 
diff --git a/Source/WebCore/page/Settings.in b/Source/WebCore/page/Settings.in
index f48b4cd..4632606 100644
--- a/Source/WebCore/page/Settings.in
+++ b/Source/WebCore/page/Settings.in
@@ -217,3 +217,5 @@
 
 # FIXME: Rename to allowMultiElementImplicitFormSubmission once we upstream the iOS changes to WebView.mm.
 allowMultiElementImplicitSubmission initial=false
+
+mediaPlaybackAllowsAirPlay initial=true, conditional=IOS_AIRPLAY
diff --git a/Source/WebCore/page/animation/CSSPropertyAnimation.cpp b/Source/WebCore/page/animation/CSSPropertyAnimation.cpp
index 801eaa3..c28c134 100644
--- a/Source/WebCore/page/animation/CSSPropertyAnimation.cpp
+++ b/Source/WebCore/page/animation/CSSPropertyAnimation.cpp
@@ -1212,8 +1212,16 @@
         new LengthPropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::specifiedLineHeight, &RenderStyle::setLineHeight),
         new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset),
         new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth),
+
+        // FIXME: We should reconcile the difference in datatype between iOS and OpenSource. On iOS we want these properties to
+        // be float for sub-pixel kerning. See <rdar://problem/5020763>.
+#if !PLATFORM(IOS)
         new PropertyWrapper<int>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing),
         new PropertyWrapper<int>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing),
+#else
+        new PropertyWrapper<float>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing),
+        new PropertyWrapper<float>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing),
+#endif
         new LengthPropertyWrapper<Length>(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent),
 
         new PropertyWrapper<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective),
diff --git a/Source/WebCore/page/ios/EventHandlerIOS.mm b/Source/WebCore/page/ios/EventHandlerIOS.mm
new file mode 100644
index 0000000..1c37a34
--- /dev/null
+++ b/Source/WebCore/page/ios/EventHandlerIOS.mm
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#import "config.h"
+#import "EventHandler.h"
+
+#import "AXObjectCache.h"
+#import "BlockExceptions.h"
+#import "Chrome.h"
+#import "ChromeClient.h"
+#import "FocusController.h"
+#import "Frame.h"
+#import "FrameView.h"
+#import "KeyboardEvent.h"
+#import "MouseEventWithHitTestResults.h"
+#import "Page.h"
+#import "PlatformEventFactoryIOS.h"
+#import "PlatformKeyboardEvent.h"
+#import "RenderWidget.h"
+#import "WAKView.h"
+#import "WAKWindow.h"
+#import "WebEvent.h"
+#import <wtf/NeverDestroyed.h>
+#import <wtf/Noncopyable.h>
+
+#if ENABLE(IOS_TOUCH_EVENTS)
+#import <WebKitAdditions/EventHandlerIOSTouch.cpp>
+#endif
+
+namespace WebCore {
+
+static RetainPtr<WebEvent>& currentEventSlot()
+{
+    NeverDestroyed<RetainPtr<WebEvent>> event;
+    return event;
+}
+
+WebEvent *EventHandler::currentEvent()
+{
+    return currentEventSlot().get();
+}
+
+class CurrentEventScope {
+    WTF_MAKE_NONCOPYABLE(CurrentEventScope);
+public:
+    CurrentEventScope(WebEvent *);
+    ~CurrentEventScope();
+
+private:
+    RetainPtr<WebEvent> m_savedCurrentEvent;
+#ifndef NDEBUG
+    RetainPtr<WebEvent> m_event;
+#endif
+};
+
+inline CurrentEventScope::CurrentEventScope(WebEvent *event)
+    : m_savedCurrentEvent(currentEventSlot())
+#ifndef NDEBUG
+    , m_event(event)
+#endif
+{
+    currentEventSlot() = event;
+}
+
+inline CurrentEventScope::~CurrentEventScope()
+{
+    ASSERT(currentEventSlot() == m_event);
+    currentEventSlot() = m_savedCurrentEvent;
+}
+
+bool EventHandler::wheelEvent(WebEvent *event)
+{
+    Page* page = m_frame.page();
+    if (!page)
+        return false;
+
+    CurrentEventScope scope(event);
+
+    bool eventWasHandled = handleWheelEvent(PlatformEventFactory::createPlatformWheelEvent(event));
+    event.wasHandled = eventWasHandled;
+    return eventWasHandled;
+}
+
+#if ENABLE(IOS_TOUCH_EVENTS)
+void EventHandler::touchEvent(WebEvent *event)
+{
+    CurrentEventScope scope(event);
+
+    event.wasHandled = handleTouchEvent(PlatformEventFactory::createPlatformTouchEvent(event));
+}
+#endif
+
+bool EventHandler::tabsToAllFormControls(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::keyEvent(WebEvent *event)
+{
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+    ASSERT(event.type == WebEventKeyDown || event.type == WebEventKeyUp);
+
+    CurrentEventScope scope(event);
+    bool eventWasHandled = keyEvent(PlatformEventFactory::createPlatformKeyboardEvent(event));
+    event.wasHandled = eventWasHandled;
+    return eventWasHandled;
+
+    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() : nullptr;
+    if (!target || !target->isWidget())
+        return false;
+
+    // Double-click events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget() will
+    // just pass currentEvent down to the widget, we don't want to call it for events that
+    // don't correspond to Cocoa events. The mousedown/ups will have already been passed on as
+    // part of the pressed/released handling.
+    return passMouseDownEventToWidget(toRenderWidget(target)->widget());
+}
+
+bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
+{
+    return passMouseDownEventToWidget(renderWidget->widget());
+}
+
+static bool lastEventIsMouseUp()
+{
+    // Many AppKit widgets run their own event loops and consume events while the mouse is down.
+    // When they finish, currentEvent is the mouseUp that they exited on. We need to update
+    // the WebCore state with this mouseUp, which we never saw. This method lets us detect
+    // that state. Handling this was critical when we used AppKit widgets for form elements.
+    // It's not clear in what cases this is helpful now -- it's possible it can be removed. 
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+    WebEvent *currentEventAfterHandlingMouseDown = [WAKWindow currentEvent];
+    return currentEventAfterHandlingMouseDown
+        && EventHandler::currentEvent() != currentEventAfterHandlingMouseDown
+        && currentEventAfterHandlingMouseDown.type == WebEventMouseUp
+        && currentEventAfterHandlingMouseDown.timestamp >= EventHandler::currentEvent().timestamp;
+    END_BLOCK_OBJC_EXCEPTIONS;
+
+    return false;
+}
+
+bool EventHandler::passMouseDownEventToWidget(Widget* pWidget)
+{
+    // FIXME: This function always returns true. It should be changed either to return
+    // false in some cases or the return value should be removed.
+
+    RefPtr<Widget> widget = pWidget;
+
+    if (!widget) {
+        LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
+        return true;
+    }
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+    NSView *nodeView = widget->platformWidget();
+    ASSERT(nodeView);
+    ASSERT([nodeView superview]);
+    NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:currentEvent().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 ([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()];
+    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&) const
+{
+    return false;
+}
+
+bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
+{
+    NSView *view = mouseDownViewIfStillGood();
+    if (!view)
+        return false;
+
+    if (!m_mouseDownWasInSubframe) {
+        ASSERT(!m_sendingEventToSubview);
+        m_sendingEventToSubview = true;
+        BEGIN_BLOCK_OBJC_EXCEPTIONS;
+        [view mouseUp:currentEvent()];
+        END_BLOCK_OBJC_EXCEPTIONS;
+        m_sendingEventToSubview = false;
+    }
+ 
+    return true;
+}
+    
+bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult* hoveredNode)
+{
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+    WebEventType currentEventType = currentEvent().type;
+    switch (currentEventType) {
+        case WebEventMouseMoved: {
+            // Since we're passing in currentNSEvent() here, we can call
+            // handleMouseMoveEvent() directly, since the save/restore of
+            // currentNSEvent() that mouseMoved() does would have no effect.
+            ASSERT(!m_sendingEventToSubview);
+            m_sendingEventToSubview = true;
+            subframe->eventHandler().handleMouseMoveEvent(currentPlatformMouseEvent(), hoveredNode);
+            m_sendingEventToSubview = false;
+            return true;
+        }
+        case WebEventMouseDown: {
+            Node* node = event.targetNode();
+            if (!node)
+                return false;
+            RenderObject* renderer = node->renderer();
+            if (!renderer || !renderer->isWidget())
+                return false;
+            Widget* widget = toRenderWidget(renderer)->widget();
+            if (!widget || !widget->isFrameView())
+                return false;
+            if (!passWidgetMouseDownEventToWidget(toRenderWidget(renderer)))
+                return false;
+            m_mouseDownWasInSubframe = true;
+            return true;
+        }
+        case WebEventMouseUp: {
+            if (!m_mouseDownWasInSubframe)
+                return false;
+            ASSERT(!m_sendingEventToSubview);
+            m_sendingEventToSubview = true;
+            subframe->eventHandler().handleMouseReleaseEvent(currentPlatformMouseEvent());
+            m_sendingEventToSubview = false;
+            return true;
+        }
+        case WebEventKeyDown:
+        case WebEventKeyUp:
+        case WebEventScrollWheel:
+        case WebEventTouchBegin:
+        case WebEventTouchCancel:
+        case WebEventTouchChange:
+        case WebEventTouchEnd:
+            return false;
+    }
+    END_BLOCK_OBJC_EXCEPTIONS;
+
+    return false;
+}
+
+bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent&, Widget* widget)
+{
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+    if (currentEvent().type != WebEventScrollWheel || m_sendingEventToSubview || !widget)
+        return false;
+
+    NSView* nodeView = widget->platformWidget();
+    ASSERT(nodeView);
+    ASSERT([nodeView superview]);
+    NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:currentEvent().locationInWindow fromView:nil]];
+    if (!view) {
+        // We probably hit the border of a RenderWidget
+        return false;
+    }
+
+    ASSERT(!m_sendingEventToSubview);
+    m_sendingEventToSubview = true;
+    [view scrollWheel:currentEvent()];
+    m_sendingEventToSubview = false;
+    return true;
+
+    END_BLOCK_OBJC_EXCEPTIONS;
+    return false;
+}
+
+void EventHandler::mouseDown(WebEvent *event)
+{
+    FrameView* v = m_frame.view();
+    if (!v || m_sendingEventToSubview)
+        return;
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+    m_frame.loader().resetMultipleFormSubmissionProtection();
+
+    m_mouseDownView = nil;
+
+    CurrentEventScope scope(event);
+
+    event.wasHandled = handleMousePressEvent(currentPlatformMouseEvent());
+
+    END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+void EventHandler::mouseUp(WebEvent *event)
+{
+    FrameView* v = m_frame.view();
+    if (!v || m_sendingEventToSubview)
+        return;
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+    CurrentEventScope scope(event);
+
+    event.wasHandled = handleMouseReleaseEvent(currentPlatformMouseEvent());
+
+    m_mouseDownView = nil;
+
+    END_BLOCK_OBJC_EXCEPTIONS;
+}
+
+void EventHandler::mouseMoved(WebEvent *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;
+
+    m_frame.document()->updateStyleIfNeeded();
+
+    WKBeginObservingContentChanges(true);
+    CurrentEventScope scope(event);
+    event.wasHandled = mouseMoved(currentPlatformMouseEvent());
+    m_frame.document()->updateStyleIfNeeded();
+    WKStopObservingContentChanges();
+
+    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);
+}
+
+unsigned EventHandler::accessKeyModifiers()
+{
+    // Control+Option key combinations are usually unused on Mac OS X, but not when VoiceOver is enabled.
+    // So, we use Control in this case, even though it conflicts with Emacs-style key bindings.
+    // See <https://bugs.webkit.org/show_bug.cgi?id=21107> for more detail.
+    if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
+        return PlatformKeyboardEvent::CtrlKey;
+
+    return PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey;
+}
+
+PlatformMouseEvent EventHandler::currentPlatformMouseEvent() const
+{
+    return PlatformEventFactory::createPlatformMouseEvent(currentEvent());
+}
+
+}
diff --git a/Source/WebCore/page/ios/FrameIOS.mm b/Source/WebCore/page/ios/FrameIOS.mm
new file mode 100644
index 0000000..94a4dbb
--- /dev/null
+++ b/Source/WebCore/page/ios/FrameIOS.mm
@@ -0,0 +1,930 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "Frame.h"
+
+#if PLATFORM(IOS)
+
+#import "AnimationController.h"
+#import "BlockExceptions.h"
+#import "DOMCSSStyleDeclarationInternal.h"
+#import "DOMCore.h"
+#import "DOMInternal.h"
+#import "DOMNodeInternal.h"
+#import "DOMWindow.h"
+#import "Document.h"
+#import "DocumentMarker.h"
+#import "DocumentMarkerController.h"
+#import "Editor.h"
+#import "EditorClient.h"
+#import "EventHandler.h"
+#import "EventNames.h"
+#import "FormController.h"
+#import "FrameSelection.h"
+#import "FrameSnapshottingMac.h"
+#import "FrameView.h"
+#import "HTMLAreaElement.h"
+#import "HTMLDocument.h"
+#import "HTMLElement.h"
+#import "HTMLNames.h"
+#import "HTMLObjectElement.h"
+#import "HitTestRequest.h"
+#import "HitTestResult.h"
+#import "JSDOMWindowBase.h"
+#import "MainFrame.h"
+#import "NodeRenderStyle.h"
+#import "NodeTraversal.h"
+#import "Page.h"
+#import "PageTransitionEvent.h"
+#import "PropertySetCSSStyleDeclaration.h"
+#import "RenderLayer.h"
+#import "RenderLayerCompositor.h"
+#import "RenderTextControl.h"
+#import "RenderView.h"
+#import "TextBoundaries.h"
+#import "TextIterator.h"
+#import "VisiblePosition.h"
+#import "VisibleUnits.h"
+#import "WAKWindow.h"
+#import "WebCoreSystemInterface.h"
+#import <runtime/JSLock.h>
+
+using namespace WebCore::HTMLNames;
+using namespace WTF::Unicode;
+
+using JSC::JSLockHolder;
+
+namespace WebCore {
+
+// Create <html><body (style="...")></body></html> doing minimal amount of work.
+void Frame::initWithSimpleHTMLDocument(const String& style, const URL& url)
+{
+    m_loader.initForSynthesizedDocument(url);
+
+    RefPtr<HTMLDocument> document = HTMLDocument::createSynthesizedDocument(this, url);
+    document->setCompatibilityMode(Document::LimitedQuirksMode);
+    document->createDOMWindow();
+    setDocument(document);
+
+    ExceptionCode ec;
+    RefPtr<Element> rootElement = document->createElementNS(xhtmlNamespaceURI, ASCIILiteral("html"), ec);
+
+    RefPtr<Element> body = document->createElementNS(xhtmlNamespaceURI, ASCIILiteral("body"), ec);
+    if (!style.isEmpty())
+        body->setAttribute(HTMLNames::styleAttr, style);
+
+    rootElement->appendChild(body, ec);
+    document->appendChild(rootElement, ec);
+}
+
+// FIXME: Extract the common code in indexCountOfWordPrecedingSelection() and wordsInCurrentParagraph() into a shared function.
+int Frame::indexCountOfWordPrecedingSelection(NSString *word) const
+{
+    int result = -1;
+
+    if (!page() || page()->selection().isNone())
+        return result;
+
+    RefPtr<Range> searchRange(rangeOfContents(*document()));
+    VisiblePosition start(page()->selection().start(), page()->selection().affinity());
+    VisiblePosition oneBeforeStart = start.previous();
+
+    setEnd(searchRange.get(), oneBeforeStart.isNotNull() ? oneBeforeStart : start);
+
+    int exception = 0;
+    if (searchRange->collapsed(exception))
+        return result;
+
+    WordAwareIterator it(searchRange.get());
+    while (!it.atEnd()) {
+        const UChar* chars = it.characters();
+        int length = it.length();
+        if (length > 1 || !isSpaceOrNewline(chars[0])) {
+            int startOfWordBoundary = 0;
+            for (int i = 1; i < length; i++) {
+                if (isSpaceOrNewline(chars[i]) || chars[i] == 0xA0) {
+                    int wordLength = i - startOfWordBoundary;
+                    NSString *chunk = [[NSString alloc] initWithCharactersNoCopy:const_cast<unichar*>(chars) + startOfWordBoundary length:wordLength freeWhenDone:NO];
+                    if ([chunk isEqualToString:word])
+                        ++result;
+                    [chunk release];
+                    startOfWordBoundary += wordLength + 1;
+                }
+            }
+            if (startOfWordBoundary < length) {
+                NSString *chunk = [[NSString alloc] initWithCharactersNoCopy:const_cast<unichar*>(chars) + startOfWordBoundary length:length - startOfWordBoundary freeWhenDone:NO];
+                if ([chunk isEqualToString:word])
+                    ++result;
+                [chunk release];
+            }
+        }
+        it.advance();
+    }
+
+    return result + 1;
+}
+
+// FIXME: Extract the common code in indexCountOfWordPrecedingSelection() and wordsInCurrentParagraph() into a shared function.
+NSArray *Frame::wordsInCurrentParagraph() const
+{
+    document()->updateLayout();
+
+    if (!page() || !page()->selection().isCaret())
+        return nil;
+
+    VisiblePosition position(page()->selection().start(), page()->selection().affinity());
+    VisiblePosition end(position);
+    if (!isStartOfParagraph(end)) {
+        VisiblePosition previous = end.previous();
+        UChar c(previous.characterAfter());
+        if (!iswpunct(c) && !isSpaceOrNewline(c) && c != 0xA0)
+            end = startOfWord(end);
+    }
+    VisiblePosition start(startOfParagraph(end));
+
+    RefPtr<Range> searchRange(rangeOfContents(*document()));
+    setStart(searchRange.get(), start);
+    setEnd(searchRange.get(), end);
+
+    int exception = 0;
+    if (searchRange->collapsed(exception))
+        return nil;
+
+    NSMutableArray *words = [NSMutableArray array];
+
+    WordAwareIterator it(searchRange.get());
+    while (!it.atEnd()) {
+        const UChar* chars = it.characters();
+        int length = it.length();
+        if (length > 1 || !isSpaceOrNewline(chars[0])) {
+            int startOfWordBoundary = 0;
+            for (int i = 1; i < length; i++) {
+                if (isSpaceOrNewline(chars[i]) || chars[i] == 0xA0) {
+                    int wordLength = i - startOfWordBoundary;
+                    if (wordLength > 0) {
+                        NSString *chunk = [[NSString alloc] initWithCharactersNoCopy:const_cast<unichar*>(chars) + startOfWordBoundary length:wordLength freeWhenDone:NO];
+                        [words addObject:chunk];
+                        [chunk release];
+                    }
+                    startOfWordBoundary += wordLength + 1;
+                }
+            }
+            if (startOfWordBoundary < length) {
+                NSString *chunk = [[NSString alloc] initWithCharactersNoCopy:const_cast<unichar*>(chars) + startOfWordBoundary length:length - startOfWordBoundary freeWhenDone:NO];
+                [words addObject:chunk];
+                [chunk release];
+            }
+        }
+        it.advance();
+    }
+
+    if ([words count] > 0 && isEndOfParagraph(position) && !isStartOfParagraph(position)) {
+        VisiblePosition previous = position.previous();
+        UChar c(previous.characterAfter());
+        if (!isSpaceOrNewline(c) && c != 0xA0)
+            [words removeLastObject];
+    }
+
+    return words;
+}
+
+#define CHECK_FONT_SIZE 0
+#define RECT_LOGGING 0
+
+CGRect Frame::renderRectForPoint(CGPoint point, bool* isReplaced, float* fontSize) const
+{
+    *isReplaced = false;
+    *fontSize = 0;
+
+    if (!m_doc || !m_doc->renderBox())
+        return CGRectZero;
+
+    // FIXME: why this layer check?
+    RenderLayer* layer = m_doc->renderBox()->layer();
+    if (!layer)
+        return CGRectZero;
+
+    HitTestResult result = eventHandler().hitTestResultAtPoint(IntPoint(roundf(point.x), roundf(point.y)));
+
+    Node* node = result.innerNode();
+    if (!node)
+        return CGRectZero;
+
+    RenderObject* hitRenderer = node->renderer();
+    RenderObject* renderer = hitRenderer;
+#if RECT_LOGGING
+    printf("\n%f %f\n", point.x, point.y);
+#endif
+    while (renderer && !renderer->isBody() && !renderer->isRoot()) {
+#if RECT_LOGGING
+        CGRect rect = renderer->absoluteBoundingBoxRect(true);
+        if (renderer->node()) {
+            const char *nodeName = renderer->node()->nodeName().ascii().data();
+            printf("%s %f %f %f %f\n", nodeName, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
+        }
+#endif
+        if (renderer->isRenderBlock() || renderer->isInlineBlockOrInlineTable() || renderer->isReplaced()) {
+            *isReplaced = renderer->isReplaced();
+#if CHECK_FONT_SIZE
+            for (RenderObject* textRenderer = hitRenderer; textRenderer; textRenderer = textRenderer->traverseNext(hitRenderer)) {
+                if (textRenderer->isText()) {
+                    *fontSize = textRenderer->font(true).pixelSize();
+                    break;
+                }
+            }
+#endif
+            IntRect targetRect = renderer->absoluteBoundingBoxRect(true);
+            for (Widget* currView = &(renderer->view().frameView()); currView && currView != view(); currView = currView->parent())
+                targetRect = currView->convertToContainingView(targetRect);
+
+            return targetRect;
+        }
+        renderer = renderer->parent();
+    }
+
+    return CGRectZero;
+}
+
+#define ALLOW_SCROLL_LISTENERS 0
+
+static Node* ancestorRespondingToScrollWheelEvents(const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds)
+{
+    if (nodeBounds)
+        *nodeBounds = IntRect();
+
+    Node* scrollingAncestor = nullptr;
+    for (Node* node = hitTestResult.innerNode(); node && node != terminationNode && !node->hasTagName(HTMLNames::bodyTag); node = node->parentNode()) {
+#if ALLOW_SCROLL_LISTENERS
+        if (node->willRespondToMouseWheelEvents()) {
+            scrollingAncestor = node;
+            continue;
+        }
+#endif
+
+        RenderObject* renderer = node->renderer();
+        if (!renderer)
+            continue;
+
+        if ((renderer->isTextField() || renderer->isTextArea()) && toRenderTextControl(renderer)->canScroll()) {
+            scrollingAncestor = node;
+            continue;
+        }
+
+        RenderStyle& style = renderer->style();
+
+        if (renderer->hasOverflowClip() &&
+            (style.overflowY() == OAUTO || style.overflowY() == OSCROLL || style.overflowY() == OOVERLAY ||
+             style.overflowX() == OAUTO || style.overflowX() == OSCROLL || style.overflowX() == OOVERLAY))
+            scrollingAncestor = node;
+    }
+
+    return scrollingAncestor;
+}
+
+static Node* ancestorRespondingToClickEvents(const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds)
+{
+    bool bodyHasBeenReached = false;
+    bool pointerCursorStillValid = true;
+
+    if (nodeBounds)
+        *nodeBounds = IntRect();
+
+    Node* pointerCursorNode = nullptr;
+    for (Node* node = hitTestResult.innerNode(); node && node != terminationNode; node = node->parentNode()) {
+        ASSERT(!node->isInShadowTree());
+
+        // We only accept pointer nodes before reaching the body tag.
+        if (node->hasTagName(HTMLNames::bodyTag)) {
+#if USE(UIKIT_EDITING)
+            // Make sure we cover the case of an empty editable body.
+            if (!pointerCursorNode && node->isContentEditable())
+                pointerCursorNode = node;
+#endif
+            bodyHasBeenReached = true;
+            pointerCursorStillValid = false;
+        }
+
+        // If we already have a pointer, and we reach a table, don't accept it.
+        if (pointerCursorNode && (node->hasTagName(HTMLNames::tableTag) || node->hasTagName(HTMLNames::tbodyTag)))
+            pointerCursorStillValid = false;
+
+        // If we haven't reached the body, and we are still paying attention to pointer cursors, and the node has a pointer cursor...
+        if (pointerCursorStillValid && node->renderStyle() && node->renderStyle()->cursor() == CURSOR_POINTER)
+            pointerCursorNode = node;
+        // We want the lowest unbroken chain of pointer cursors.
+        else if (pointerCursorNode)
+            pointerCursorStillValid = false;
+
+        if (node->willRespondToMouseClickEvents() || node->willRespondToMouseMoveEvents()) {
+            // If we're at the body or higher, use the pointer cursor node (which may be null).
+            if (bodyHasBeenReached)
+                node = pointerCursorNode;
+
+            // If we are interested about the frame, use it.
+            if (nodeBounds) {
+                // This is a check to see whether this node is an area element.  The only way this can happen is if this is the first check.
+                if (node == hitTestResult.innerNode() && node != hitTestResult.innerNonSharedNode() && node->hasTagName(HTMLNames::areaTag))
+                    *nodeBounds = pixelSnappedIntRect(toHTMLAreaElement(node)->computeRect(hitTestResult.innerNonSharedNode()->renderer()));
+                else if (node && node->renderer())
+                    *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true);
+            }
+
+            return node;
+        }
+    }
+
+    return nullptr;
+}
+
+void Frame::betterApproximateNode(const IntPoint& testPoint, NodeQualifier nodeQualifierFunction, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect)
+{
+    IntRect candidateRect;
+    Node* candidate = nodeQualifierFunction(eventHandler().hitTestResultAtPoint(testPoint), failedNode, &candidateRect);
+
+    // Bail if we have no candidate, or the candidate is already equal to our current best node,
+    // or our candidate is the avoidedNode and there is a current best node.
+    if (!candidate || candidate == best)
+        return;
+
+    // The document should never be considered the best alternative.
+    if (candidate->isDocumentNode())
+        return;
+
+    if (best) {
+        IntRect bestIntersect = intersection(testRect, bestRect);
+        IntRect candidateIntersect = intersection(testRect, candidateRect);
+        // if the candidate intersection is smaller than the current best intersection, bail.
+        if (candidateIntersect.width() * candidateIntersect.height() <= bestIntersect.width() * bestIntersect.height())
+            return;
+    }
+
+    // At this point we either don't have a previous best, or our current candidate has a better intersection.
+    best = candidate;
+    bestPoint = testPoint;
+    bestRect = candidateRect;
+}
+
+bool Frame::hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult& hitTestResult, IntPoint& center)
+{
+    if (!m_doc || !m_doc->renderView())
+        return false;
+
+    FrameView* view = m_view.get();
+    if (!view)
+        return false;
+
+    center = view->windowToContents(roundedIntPoint(viewportLocation));
+    hitTestResult = eventHandler().hitTestResultAtPoint(center);
+    return true;
+}
+
+Node* Frame::qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, NodeQualifier nodeQualifierFunction, bool shouldApproximate)
+{
+    adjustedViewportLocation = viewportLocation;
+
+    IntPoint testCenter;
+    HitTestResult candidateInfo;
+    if (!hitTestResultAtViewportLocation(viewportLocation, candidateInfo, testCenter))
+        return nullptr;
+
+    IntPoint bestPoint = testCenter;
+
+    // We have the candidate node at the location, check whether it or one of its ancestors passes
+    // the qualifier function, which typically checks if the node responds to a particular event type.
+    Node* approximateNode = nodeQualifierFunction(candidateInfo, 0, 0);
+
+#if USE(UIKIT_EDITING)
+    if (approximateNode && approximateNode->isContentEditable()) {
+        // If we are in editable content, we look for the root editable element.
+        approximateNode = approximateNode->rootEditableElement();
+        // If we have a focusable node, there is no need to approximate.
+        if (approximateNode)
+            shouldApproximate = false;
+    }
+#endif
+    if (approximateNode && shouldApproximate) {
+        float scale = page() ? page()->pageScaleFactor() : 1;
+
+        const int defaultMaxRadius = 15;
+        int maxRadius = scale < 1 ? static_cast<int>(defaultMaxRadius / scale) : defaultMaxRadius;
+
+        const float testOffsets[] = {
+            -.3f, -.3f,
+            -.6f, -.6f,
+            +.3f, +.3f,
+            -.9f, -.9f,
+        };
+
+        Node* originalApproximateNode = approximateNode;
+        for (unsigned n = 0; n < WTF_ARRAY_LENGTH(testOffsets); n += 2) {
+            IntSize testOffset(testOffsets[n] * maxRadius, testOffsets[n + 1] * maxRadius);
+            IntPoint testPoint = testCenter + testOffset;
+
+            HitTestResult candidateInfo = eventHandler().hitTestResultAtPoint(testPoint);
+            Node* candidateNode = nodeQualifierFunction(candidateInfo, 0, 0);
+            if (candidateNode && candidateNode->isDescendantOf(originalApproximateNode)) {
+                approximateNode = candidateNode;
+                bestPoint = testPoint;
+                break;
+            }
+        }
+    } else if (!approximateNode && shouldApproximate) {
+        // Grab the closest parent element of our failed candidate node.
+        Node* candidate = candidateInfo.innerNode();
+        Node* failedNode = candidate;
+
+        while (candidate && !candidate->isElementNode())
+            candidate = candidate->parentNode();
+
+        if (candidate)
+            failedNode = candidate;
+
+        // We don't approximate the node if we are dragging, we instead force the user to be precise.
+        float scale = page() ? page()->pageScaleFactor() : 1;
+
+        const int defaultMaxRadius = 15;
+        int maxRadius = (scale < 1.0) ? static_cast<int>(defaultMaxRadius / scale) : defaultMaxRadius;
+
+        // The center point was tested earlier.
+        const float testOffsets[] = {
+            -.3f, -.3f,
+            +.3f, -.3f,
+            -.3f, +.3f,
+            +.3f, +.3f,
+            -.6f, -.6f,
+            +.6f, -.6f,
+            -.6f, +.6f,
+            +.6f, +.6f,
+            -1.f, 0,
+            +1.f, 0,
+            0, +1.f,
+            0, -1.f,
+        };
+        IntRect bestFrame;
+        IntRect testRect(testCenter, IntSize());
+        testRect.inflate(maxRadius);
+        int currentTestRadius = 0;
+        for (unsigned n = 0; n < WTF_ARRAY_LENGTH(testOffsets); n += 2) {
+            IntSize testOffset(testOffsets[n] * maxRadius, testOffsets[n + 1] * maxRadius);
+            IntPoint testPoint = testCenter + testOffset;
+            int testRadius = std::max(abs(testOffset.width()), abs(testOffset.height()));
+            if (testRadius > currentTestRadius) {
+                // Bail out with the best match within a radius
+                currentTestRadius = testRadius;
+                if (approximateNode)
+                    break;
+            }
+            betterApproximateNode(testPoint, nodeQualifierFunction, approximateNode, failedNode, bestPoint, bestFrame, testRect);
+        }
+    }
+
+    if (approximateNode) {
+        IntPoint p = m_view->contentsToWindow(bestPoint);
+        adjustedViewportLocation = p;
+#if USE(UIKIT_EDITING)
+        if (approximateNode->isContentEditable()) {
+            // When in editable content, look for the root editable node again,
+            // since this could be the node found with the approximation.
+            approximateNode = approximateNode->rootEditableElement();
+        }
+#endif
+    }
+
+    return approximateNode;
+}
+
+Node* Frame::deepestNodeAtLocation(const FloatPoint& viewportLocation)
+{
+    IntPoint center;
+    HitTestResult hitTestResult;
+    if (!hitTestResultAtViewportLocation(viewportLocation, hitTestResult, center))
+        return nullptr;
+
+    return hitTestResult.innerNode();
+}
+
+Node* Frame::nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation)
+{
+    return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, &ancestorRespondingToClickEvents, true);
+}
+
+Node* Frame::nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation)
+{
+    FloatPoint adjustedViewportLocation;
+    return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, &ancestorRespondingToScrollWheelEvents, false);
+}
+
+int Frame::preferredHeight() const
+{
+    Document* document = this->document();
+    if (!document)
+        return 0;
+
+    document->updateLayout();
+
+    Node* body = document->body();
+    if (!body)
+        return 0;
+
+    RenderObject* renderer = body->renderer();
+    if (!renderer || !renderer->isRenderBlock())
+        return 0;
+
+    RenderBlock* block = toRenderBlock(renderer);
+    return block->height() + block->marginTop() + block->marginBottom();
+}
+
+int Frame::innerLineHeight(DOMNode* domNode) const
+{
+    if (!domNode)
+        return 0;
+
+    Document* document = this->document();
+    if (!document)
+        return 0;
+
+    document->updateLayout();
+
+    Node* node = core(domNode);
+    if (!node)
+        return 0;
+
+    RenderObject* renderer = node->renderer();
+    if (!renderer)
+        return 0;
+
+    return renderer->innerLineHeight();
+}
+
+void Frame::updateLayout() const
+{
+    Document* document = this->document();
+    if (!document)
+        return;
+
+    document->updateLayout();
+
+    if (FrameView* view = this->view())
+        view->adjustViewSize();
+}
+
+NSRect Frame::caretRect() const
+{
+    if (selection().isNone())
+        return CGRectZero;
+    return selection().isCaret() ? selection().absoluteCaretBounds() : VisiblePosition(selection().end()).absoluteCaretBounds();
+}
+
+NSRect Frame::rectForScrollToVisible() const
+{
+    VisibleSelection selection(this->selection().selection());
+    return rectForSelection(selection);
+}
+
+NSRect Frame::rectForSelection(VisibleSelection& selection) const
+{
+    if (selection.isNone())
+        return CGRectZero;
+
+    if (selection.isCaret())
+        return caretRect();
+
+    EditorClient* client = editor().client();
+    if (client)
+        client->suppressSelectionNotifications();
+
+    VisibleSelection originalSelection(selection);
+    Position position;
+
+    // The selection controllers below need to be associated with a frame in order
+    // to calculate geometry. This causes them to do more work here than we would
+    // like. Ideally, we would have a sort offline geometry-only mode for selection
+    // controllers so we could do this kind of work as cheaply as possible.
+
+    position = originalSelection.start();
+    selection.setBase(position);
+    selection.setExtent(position);
+    FrameSelection startFrameSelection(const_cast<Frame*>(this));
+    startFrameSelection.suppressCloseTyping();
+    startFrameSelection.setSelection(selection);
+    FloatRect startRect(startFrameSelection.absoluteCaretBounds());
+    startFrameSelection.restoreCloseTyping();
+
+    position = originalSelection.end();
+    selection.setBase(position);
+    selection.setExtent(position);
+    FrameSelection endFrameSelection(const_cast<Frame*>(this));
+    endFrameSelection.suppressCloseTyping();
+    endFrameSelection.setSelection(selection);
+    FloatRect endRect(endFrameSelection.absoluteCaretBounds());
+    endFrameSelection.restoreCloseTyping();
+
+    if (client)
+        client->restoreSelectionNotifications();
+
+    return unionRect(startRect, endRect);
+}
+
+DOMCSSStyleDeclaration* Frame::styleAtSelectionStart() const
+{
+    Position start = selection().start();
+    RefPtr<EditingStyle> editingStyle = EditingStyle::styleAtSelectionStart(selection().selection());
+    if (!editingStyle)
+        return nullptr;
+    PropertySetCSSStyleDeclaration* propertySetCSSStyleDeclaration = new PropertySetCSSStyleDeclaration(editingStyle->style());
+    // The auto-generated code for DOMCSSStyleDeclaration derefs its pointer when it is deallocated.
+    return kit(static_cast<CSSStyleDeclaration*>(propertySetCSSStyleDeclaration));
+}
+
+unsigned Frame::formElementsCharacterCount() const
+{
+    Document* document = this->document();
+    if (!document)
+        return 0;
+    return document->formController().formElementsCharacterCount();
+}
+
+void Frame::setTimersPaused(bool paused)
+{
+    JSLockHolder lock(JSDOMWindowBase::commonVM());
+    setTimersPausedInternal(paused);
+}
+
+void Frame::setTimersPausedInternal(bool paused)
+{
+    if (paused) {
+        ++m_timersPausedCount;
+        if (m_timersPausedCount == 1) {
+            clearTimers();
+            if (document())
+                document()->suspendScheduledTasks(ActiveDOMObject::DocumentWillBePaused);
+        }
+    } else {
+        --m_timersPausedCount;
+        ASSERT(m_timersPausedCount >= 0);
+        if (m_timersPausedCount == 0) {
+            if (document())
+                document()->resumeScheduledTasks(ActiveDOMObject::DocumentWillBePaused);
+
+            // clearTimers() suspended animations and pending relayouts, reschedule if needed.
+            animation().resumeAnimationsForDocument(document());
+
+            if (view())
+                view()->scheduleRelayout();
+        }
+    }
+
+    // We need to make sure all subframes' states are up to date.
+    for (Frame* frame = tree().firstChild(); frame; frame = frame->tree().nextSibling())
+        frame->setTimersPausedInternal(paused);
+}
+
+void Frame::dispatchPageHideEventBeforePause()
+{
+    ASSERT(isMainFrame());
+    if (!isMainFrame())
+        return;
+
+    for (Frame* frame = this; frame; frame = frame->tree().traverseNext(this))
+        frame->document()->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pagehideEvent, true), document());
+}
+
+void Frame::dispatchPageShowEventBeforeResume()
+{
+    ASSERT(isMainFrame());
+    if (!isMainFrame())
+        return;
+
+    for (Frame* frame = this; frame; frame = frame->tree().traverseNext(this))
+        frame->document()->domWindow()->dispatchEvent(PageTransitionEvent::create(eventNames().pageshowEvent, true), document());
+}
+
+void Frame::setRangedSelectionBaseToCurrentSelection()
+{
+    m_rangedSelectionBase = selection().selection();
+}
+
+void Frame::setRangedSelectionBaseToCurrentSelectionStart()
+{
+    FrameSelection& frameSelection = selection();
+    m_rangedSelectionBase = VisibleSelection(frameSelection.selection().start(), frameSelection.affinity());
+}
+
+void Frame::setRangedSelectionBaseToCurrentSelectionEnd()
+{
+    FrameSelection& frameSelection = selection();
+    m_rangedSelectionBase = VisibleSelection(frameSelection.selection().end(), frameSelection.affinity());
+}
+
+VisibleSelection Frame::rangedSelectionBase() const
+{
+    return m_rangedSelectionBase;
+}
+
+void Frame::clearRangedSelectionInitialExtent()
+{
+    m_rangedSelectionInitialExtent = VisibleSelection();
+}
+
+void Frame::setRangedSelectionInitialExtentToCurrentSelectionStart()
+{
+    FrameSelection& frameSelection = selection();
+    m_rangedSelectionInitialExtent = VisibleSelection(frameSelection.selection().start(), frameSelection.affinity());
+}
+
+void Frame::setRangedSelectionInitialExtentToCurrentSelectionEnd()
+{
+    FrameSelection& frameSelection = selection();
+    m_rangedSelectionInitialExtent = VisibleSelection(frameSelection.selection().end(), frameSelection.affinity());
+}
+
+VisibleSelection Frame::rangedSelectionInitialExtent() const
+{
+    return m_rangedSelectionInitialExtent;
+}
+
+void Frame::recursiveSetUpdateAppearanceEnabled(bool enabled)
+{
+    selection().setUpdateAppearanceEnabled(enabled);
+    for (Frame* child = tree().firstChild(); child; child = child->tree().nextSibling())
+        child->recursiveSetUpdateAppearanceEnabled(enabled);
+}
+
+// FIXME: Break this function up into pieces with descriptive function names so that it's easier to follow.
+NSArray *Frame::interpretationsForCurrentRoot() const
+{
+    if (!document())
+        return nil;
+
+    Element* root = selection().selectionType() == VisibleSelection::NoSelection ? document()->body() : selection().rootEditableElement();
+    unsigned rootChildCount = root->childNodeCount();
+    RefPtr<Range> rangeOfRootContents = Range::create(*document(), createLegacyEditingPosition(root, 0), createLegacyEditingPosition(root, rootChildCount));
+
+    Vector<DocumentMarker*> markersInRoot = document()->markers().markersInRange(rangeOfRootContents.get(), DocumentMarker::DictationPhraseWithAlternatives);
+
+    // There are no phrases with alternatives, so there is just one interpretation.
+    if (markersInRoot.isEmpty())
+        return [NSArray arrayWithObject:plainText(rangeOfRootContents.get())];
+
+    // The number of interpretations will be i1 * i2 * ... * iN, where iX is the number of interpretations for the Xth phrase with alternatives.
+    size_t interpretationsCount = 1;
+
+    for (auto marker : markersInRoot)
+        interpretationsCount *= marker->alternatives().size() + 1;
+
+    Vector<Vector<UChar>> interpretations;
+    interpretations.grow(interpretationsCount);
+
+    Position precedingTextStartPosition = createLegacyEditingPosition(root, 0);
+
+    unsigned combinationsSoFar = 1;
+
+    Node* pastLastNode = rangeOfRootContents->pastLastNode();
+    for (Node* node = rangeOfRootContents->firstNode(); node != pastLastNode; node = NodeTraversal::next(node)) {
+        const Vector<DocumentMarker*>& markers = document()->markers().markersFor(node, DocumentMarker::MarkerTypes(DocumentMarker::DictationPhraseWithAlternatives));
+        for (auto marker : markers) {
+            // First, add text that precede the marker.
+            if (precedingTextStartPosition != createLegacyEditingPosition(node, marker->startOffset())) {
+                RefPtr<Range> precedingTextRange = Range::create(*document(), precedingTextStartPosition, createLegacyEditingPosition(node, marker->startOffset()));
+                String precedingText = plainText(precedingTextRange.get());
+                if (unsigned length = precedingText.length()) {
+                    const UChar* characters = precedingText.characters();
+                    for (size_t i = 0; i < interpretationsCount; ++i)
+                        interpretations.at(i).append(characters, length);
+                }
+            }
+
+            RefPtr<Range> rangeForMarker = Range::create(*document(), createLegacyEditingPosition(node, marker->startOffset()), createLegacyEditingPosition(node, marker->endOffset()));
+            String visibleTextForMarker = plainText(rangeForMarker.get());
+            size_t interpretationsCountForCurrentMarker = marker->alternatives().size() + 1;
+            unsigned visibleTextForMarkerLength = visibleTextForMarker.length();
+            const UChar* visibleTextForMarkerCharacters = visibleTextForMarker.characters();
+            for (size_t i = 0; i < interpretationsCount; ++i) {
+                // Determine text for the ith interpretation. It will either be the visible text, or one of its
+                // alternatives stored in the marker.
+
+                size_t indexOfInterpretationForCurrentMarker = (i / combinationsSoFar) % interpretationsCountForCurrentMarker;
+                if (!indexOfInterpretationForCurrentMarker)
+                    interpretations.at(i).append(visibleTextForMarkerCharacters, visibleTextForMarkerLength);
+                else {
+                    const String& alternative = marker->alternatives().at(i % marker->alternatives().size());
+                    interpretations.at(i).append(alternative.characters(), alternative.length());
+                }
+            }
+
+            combinationsSoFar *= interpretationsCountForCurrentMarker;
+
+            precedingTextStartPosition = createLegacyEditingPosition(node, marker->endOffset());
+        }
+    }
+
+    // Finally, add any text after the last marker.
+    RefPtr<Range> afterLastMarkerRange = Range::create(*document(), precedingTextStartPosition, createLegacyEditingPosition(root, rootChildCount));
+    String textAfterLastMarker = plainText(afterLastMarkerRange.get());
+    const UChar* textAfterLastMarkerCharacters = textAfterLastMarker.characters();
+    if (unsigned length = textAfterLastMarker.length()) {
+        for (size_t i = 0; i < interpretationsCount; ++i)
+            interpretations.at(i).append(textAfterLastMarkerCharacters, length);
+    }
+
+    NSMutableArray *result = [NSMutableArray array];
+    for (size_t i = 0; i < interpretationsCount; ++i)
+        [result addObject:static_cast<NSString *>(String(interpretations.at(i)))];
+
+    return result;
+}
+
+static bool anyFrameHasTiledLayers(Frame* rootFrame)
+{
+    for (Frame* frame = rootFrame; frame; frame = frame->tree().traverseNext(rootFrame)) {
+        if (frame->containsTiledBackingLayers())
+            return true;
+    }
+    return false;
+}
+
+void Frame::viewportOffsetChanged(ViewportOffsetChangeType changeType)
+{
+#if USE(ACCELERATED_COMPOSITING)
+    if (changeType == IncrementalScrollOffset) {
+        if (anyFrameHasTiledLayers(this)) {
+            if (RenderView* root = contentRenderer())
+                root->compositor().didChangeVisibleRect();
+        }
+    }
+
+    if (changeType == CompletedScrollOffset) {
+        if (RenderView* root = contentRenderer())
+            root->compositor().updateCompositingLayers(CompositingUpdateOnScroll);
+    }
+#endif
+}
+
+bool Frame::containsTiledBackingLayers() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+    if (RenderView* root = contentRenderer())
+        return root->compositor().hasNonMainLayersWithTiledBacking();
+#endif
+    return false;
+}
+
+void Frame::overflowScrollPositionChangedForNode(const IntPoint& position, Node* node, bool isUserScroll)
+{
+    RenderObject* renderer = node->renderer();
+    if (!renderer || !renderer->hasLayer())
+        return;
+
+    RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
+
+    layer->setIsUserScroll(isUserScroll);
+    layer->scrollToOffsetWithoutAnimation(position);
+    layer->setIsUserScroll(false);
+    layer->didEndScroll(); // FIXME: Should we always call this?
+}
+
+void Frame::resetAllGeolocationPermission()
+{
+    if (document()->domWindow())
+        document()->domWindow()->resetAllGeolocationPermission();
+
+    for (Frame* child = tree().firstChild(); child; child = child->tree().nextSibling())
+        child->resetAllGeolocationPermission();
+}
+
+#if ENABLE(IOS_TEXT_AUTOSIZING)
+float Frame::textAutosizingWidth() const
+{
+    return m_textAutosizingWidth;
+}
+
+void Frame::setTextAutosizingWidth(float width)
+{
+    m_textAutosizingWidth = width;
+}
+#endif
+
+} // namespace WebCore
+#endif // PLATFORM(IOS)
diff --git a/Source/WebCore/page/mac/ChromeMac.mm b/Source/WebCore/page/mac/ChromeMac.mm
index afa9e68..1d67236 100644
--- a/Source/WebCore/page/mac/ChromeMac.mm
+++ b/Source/WebCore/page/mac/ChromeMac.mm
@@ -23,6 +23,11 @@
 #import "BlockExceptions.h"
 #import "ChromeClient.h"
 
+#if PLATFORM(IOS)
+#include "WAKResponder.h"
+#include "WAKView.h"
+#endif
+
 namespace WebCore {
 
 
diff --git a/Source/WebCore/page/mac/PageMac.cpp b/Source/WebCore/page/mac/PageMac.cpp
index 212b117..d4c0d1d 100644
--- a/Source/WebCore/page/mac/PageMac.cpp
+++ b/Source/WebCore/page/mac/PageMac.cpp
@@ -44,12 +44,14 @@
         m_scheduledRunLoopPairs = adoptPtr(new SchedulePairHashSet);
     m_scheduledRunLoopPairs->add(pair);
 
+#if !PLATFORM(IOS)
     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.
 }
@@ -63,12 +65,14 @@
     RefPtr<SchedulePair> pair = prpPair;
     m_scheduledRunLoopPairs->remove(pair);
 
+#if !PLATFORM(IOS)
     for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree().traverseNext()) {
         if (DocumentLoader* documentLoader = frame->loader().documentLoader())
             documentLoader->unschedule(pair.get());
         if (DocumentLoader* documentLoader = frame->loader().provisionalDocumentLoader())
             documentLoader->unschedule(pair.get());
     }
+#endif
 }
 
 } // namespace
diff --git a/Source/WebCore/page/mac/SettingsMac.mm b/Source/WebCore/page/mac/SettingsMac.mm
index 0a51c30..8cdeee9 100644
--- a/Source/WebCore/page/mac/SettingsMac.mm
+++ b/Source/WebCore/page/mac/SettingsMac.mm
@@ -30,7 +30,7 @@
 
 bool Settings::shouldEnableScreenFontSubstitutionByDefault()
 {
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+#if !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
     return false;
 #else
     return true;
diff --git a/Source/WebCore/page/mac/WebCoreFrameView.h b/Source/WebCore/page/mac/WebCoreFrameView.h
index 93a0296..738d39b 100644
--- a/Source/WebCore/page/mac/WebCoreFrameView.h
+++ b/Source/WebCore/page/mac/WebCoreFrameView.h
@@ -25,18 +25,30 @@
 
 #include "ScrollTypes.h"
 
+// WTF_PLATFORM_IOS
+#ifdef __cplusplus
 namespace WebCore {
     class Frame;
 }
+#endif
 
 @protocol WebCoreFrameScrollView
+// WTF_PLATFORM_IOS
+#ifdef __cplusplus
 - (void)setScrollingModes:(WebCore::ScrollbarMode)hMode vertical:(WebCore::ScrollbarMode)vMode andLock:(BOOL)lock;
 - (void)scrollingModes:(WebCore::ScrollbarMode*)hMode vertical:(WebCore::ScrollbarMode*)vMode;
+#else
+- (void)setScrollingModes:(int)hMode vertical:(int)vMode andLock:(BOOL)lock;
+- (void)scrollingModes:(int*)hMode vertical:(int*)vMode;
+#endif
 - (void)setScrollBarsSuppressed:(BOOL)suppressed repaintOnUnsuppress:(BOOL)repaint;
 - (void)setScrollOrigin:(NSPoint)origin updatePositionAtAll:(BOOL)updatePositionAtAll immediately:(BOOL)updatePositionImmediately;
 - (NSPoint)scrollOrigin;
 @end
 
 @protocol WebCoreFrameView
+// WTF_PLATFORM_IOS
+#ifdef __cplusplus
 - (WebCore::Frame*)_web_frame;
+#endif
 @end
diff --git a/Source/WebKit/ios/ChangeLog b/Source/WebKit/ios/ChangeLog
index 75be90f..c1ecaa7 100644
--- a/Source/WebKit/ios/ChangeLog
+++ b/Source/WebKit/ios/ChangeLog
@@ -1,3 +1,12 @@
+2013-12-27  Daniel Bates  <dabates@apple.com>
+
+        [iOS] Upstream WebCore/page changes
+        https://bugs.webkit.org/show_bug.cgi?id=126180
+
+        Reviewed by Darin Adler.
+
+        * WebCoreSupport/WebChromeClientIOS.mm: Substitute ENABLE(IOS_TOUCH_EVENTS) for ENABLE(TOUCH_EVENTS).
+
 2013-12-23  Andy Estes  <aestes@apple.com>
 
         Roll out r161043. It broke 32-bit Mac builds.
diff --git a/Source/WebKit/ios/WebCoreSupport/WebChromeClientIOS.mm b/Source/WebKit/ios/WebCoreSupport/WebChromeClientIOS.mm
index bff59fa..7755331 100644
--- a/Source/WebKit/ios/WebCoreSupport/WebChromeClientIOS.mm
+++ b/Source/WebKit/ios/WebCoreSupport/WebChromeClientIOS.mm
@@ -124,7 +124,7 @@
     [listener release];
 }
 
-#if ENABLE(TOUCH_EVENTS)
+#if ENABLE(IOS_TOUCH_EVENTS)
 void WebChromeClientIOS::didPreventDefaultForEvent()
 {
     [[webView() _UIKitDelegateForwarder] webViewDidPreventDefaultForEvent:webView()];
diff --git a/Source/WebKit/ios/WebView/WebPDFViewIOS.mm b/Source/WebKit/ios/WebView/WebPDFViewIOS.mm
index e86156a..30e2c7c 100644
--- a/Source/WebKit/ios/WebView/WebPDFViewIOS.mm
+++ b/Source/WebKit/ios/WebView/WebPDFViewIOS.mm
@@ -28,18 +28,11 @@
 #import "WebPDFViewIOS.h"
 #import "WebDataSourceInternal.h"
 
-#import <WebKit/WebFrameLoadDelegate.h>
-#import <WebKit/WebFrame.h>
-#import <WebKit/WebFramePrivate.h>
-#import <WebKit/WebFrameView.h>
-#import <WebKit/WebNSViewExtras.h>
-#import <WebKit/WebViewPrivate.h>
 #import "WebFrameInternal.h"
 #import "WebJSPDFDoc.h"
+#import "WebKitVersionChecks.h"
 #import "WebPDFDocumentExtras.h"
 #import "WebPDFViewPlaceholder.h"
-#import "WebKitVersionChecks.h"
-
 #import <JavaScriptCore/JSContextRef.h>
 #import <JavaScriptCore/JSStringRef.h>
 #import <JavaScriptCore/JSStringRefCF.h>
@@ -48,7 +41,14 @@
 #import <WebCore/FrameLoader.h>
 #import <WebCore/FrameLoaderClient.h>
 #import <WebCore/GraphicsContext.h>
+#import <WebCore/StringWithDirection.h>
 #import <WebCore/WKGraphics.h>
+#import <WebKit/WebFrame.h>
+#import <WebKit/WebFrameLoadDelegate.h>
+#import <WebKit/WebFramePrivate.h>
+#import <WebKit/WebFrameView.h>
+#import <WebKit/WebNSViewExtras.h>
+#import <WebKit/WebViewPrivate.h>
 #import <wtf/Assertions.h>
 #import <wtf/RetainPtr.h>
 #import <wtf/StdLibExtras.h>
diff --git a/Source/WebKit2/ChangeLog b/Source/WebKit2/ChangeLog
index 5ad10f1..6b6fc7e 100644
--- a/Source/WebKit2/ChangeLog
+++ b/Source/WebKit2/ChangeLog
@@ -1,3 +1,14 @@
+2013-12-27  Daniel Bates  <dabates@apple.com>
+
+        [iOS] Upstream WebCore/page changes
+        https://bugs.webkit.org/show_bug.cgi?id=126180
+
+        Reviewed by Darin Adler.
+
+        * WebProcess/WebCoreSupport/WebChromeClient.h:
+        * WebProcess/WebCoreSupport/ios/WebChromeClientIOS.mm: Added.
+        * WebProcess/WebPage/WebPage.cpp: Include header <WebCore/HitTestResult.h>.
+
 2013-12-27  Gavin Barraclough  <barraclough@apple.com>
 
         Merge PageVisibilityState & ViewState::IsVisible in WebKit2
diff --git a/Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.h b/Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.h
index 7041e9a..8790231 100644
--- a/Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.h
+++ b/Source/WebKit2/WebProcess/WebCoreSupport/WebChromeClient.h
@@ -155,10 +155,11 @@
     virtual PassOwnPtr<WebCore::ColorChooser> createColorChooser(WebCore::ColorChooserClient*, const WebCore::Color&) OVERRIDE;
 #endif
 
-#if PLATFORM(IOS)
-#if ENABLE(TOUCH_EVENTS)
+#if ENABLE(IOS_TOUCH_EVENTS)
     virtual void didPreventDefaultForEvent() OVERRIDE;
 #endif
+
+#if PLATFORM(IOS)
     virtual void didReceiveMobileDocType() OVERRIDE;
     virtual void setNeedsScrollNotifications(WebCore::Frame*, bool) OVERRIDE;
     virtual void observedContentChange(WebCore::Frame*) OVERRIDE;
diff --git a/Source/WebKit2/WebProcess/WebCoreSupport/ios/WebChromeClientIOS.mm b/Source/WebKit2/WebProcess/WebCoreSupport/ios/WebChromeClientIOS.mm
index 9f02b2f..4fdca17 100644
--- a/Source/WebKit2/WebProcess/WebCoreSupport/ios/WebChromeClientIOS.mm
+++ b/Source/WebKit2/WebProcess/WebCoreSupport/ios/WebChromeClientIOS.mm
@@ -34,7 +34,7 @@
 
 namespace WebKit {
 
-#if ENABLE(TOUCH_EVENTS)
+#if ENABLE(IOS_TOUCH_EVENTS)
 void WebChromeClient::didPreventDefaultForEvent()
 {
     notImplemented();
diff --git a/Source/WebKit2/WebProcess/WebPage/WebPage.cpp b/Source/WebKit2/WebProcess/WebPage/WebPage.cpp
index 0e702dd..535a9c4 100644
--- a/Source/WebKit2/WebProcess/WebPage/WebPage.cpp
+++ b/Source/WebKit2/WebProcess/WebPage/WebPage.cpp
@@ -108,6 +108,7 @@
 #include <WebCore/HTMLPlugInImageElement.h>
 #include <WebCore/HistoryController.h>
 #include <WebCore/HistoryItem.h>
+#include <WebCore/HitTestResult.h>
 #include <WebCore/JSDOMWindow.h>
 #include <WebCore/KeyboardEvent.h>
 #include <WebCore/MIMETypeRegistry.h>