Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / web / tests / WebViewTest.cpp
index 9a9bf9f..af2752f 100644 (file)
  */
 
 #include "config.h"
-#include "WebView.h"
+#include "public/web/WebView.h"
 
-#include <gtest/gtest.h>
-#include "FrameTestHelpers.h"
-#include "URLTestHelpers.h"
-#include "WebAutofillClient.h"
-#include "WebContentDetectionResult.h"
-#include "WebDateTimeChooserCompletion.h"
-#include "WebDocument.h"
-#include "WebElement.h"
-#include "WebFrame.h"
-#include "WebFrameClient.h"
-#include "WebFrameImpl.h"
-#include "WebHelperPlugin.h"
-#include "WebHitTestResult.h"
-#include "WebInputEvent.h"
-#include "WebSettings.h"
-#include "WebViewClient.h"
-#include "WebViewImpl.h"
-#include "WebWidget.h"
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
+#include "core/frame/FrameView.h"
+#include "core/frame/LocalFrame.h"
+#include "core/frame/Settings.h"
 #include "core/html/HTMLDocument.h"
+#include "core/html/HTMLIFrameElement.h"
 #include "core/html/HTMLInputElement.h"
+#include "core/html/HTMLTextAreaElement.h"
 #include "core/loader/FrameLoadRequest.h"
-#include "core/frame/FrameView.h"
 #include "core/page/Chrome.h"
-#include "core/frame/Settings.h"
+#include "core/rendering/RenderLayer.h"
+#include "core/rendering/RenderView.h"
 #include "platform/KeyboardCodes.h"
-#include "platform/Timer.h"
+#include "platform/geometry/IntSize.h"
 #include "platform/graphics/Color.h"
 #include "public/platform/Platform.h"
+#include "public/platform/WebDragData.h"
 #include "public/platform/WebSize.h"
 #include "public/platform/WebThread.h"
 #include "public/platform/WebUnitTestSupport.h"
+#include "public/web/WebAutofillClient.h"
+#include "public/web/WebContentDetectionResult.h"
+#include "public/web/WebDateTimeChooserCompletion.h"
+#include "public/web/WebDocument.h"
+#include "public/web/WebDragOperation.h"
+#include "public/web/WebElement.h"
+#include "public/web/WebFrame.h"
+#include "public/web/WebFrameClient.h"
+#include "public/web/WebHitTestResult.h"
+#include "public/web/WebInputEvent.h"
+#include "public/web/WebSettings.h"
+#include "public/web/WebViewClient.h"
+#include "public/web/WebWidget.h"
 #include "public/web/WebWidgetClient.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkBitmapDevice.h"
 #include "third_party/skia/include/core/SkCanvas.h"
+#include "web/WebLocalFrameImpl.h"
+#include "web/WebSettingsImpl.h"
+#include "web/WebViewImpl.h"
+#include "web/tests/FrameTestHelpers.h"
+#include "web/tests/URLTestHelpers.h"
+#include <gtest/gtest.h>
 
 using namespace blink;
 using blink::FrameTestHelpers::runPendingTasks;
@@ -105,7 +112,7 @@ private:
     WebViewImpl* m_webView;
 };
 
-class AutoResizeWebViewClient : public WebViewClient {
+class AutoResizeWebViewClient : public FrameTestHelpers::TestWebViewClient {
 public:
     // WebViewClient methods
     virtual void didAutoResize(const WebSize& newSize) { m_testData.setSize(newSize); }
@@ -117,7 +124,7 @@ private:
     TestData m_testData;
 };
 
-class TapHandlingWebViewClient : public WebViewClient {
+class TapHandlingWebViewClient : public FrameTestHelpers::TestWebViewClient {
 public:
     // WebViewClient methods
     virtual void didHandleGestureEvent(const WebGestureEvent& event, bool eventCancelled)
@@ -151,55 +158,7 @@ private:
     int m_longpressY;
 };
 
-class HelperPluginCreatingWebViewClient : public WebViewClient {
-public:
-    // WebViewClient methods
-    virtual blink::WebWidget* createPopupMenu(blink::WebPopupType popupType) OVERRIDE
-    {
-        EXPECT_EQ(WebPopupTypeHelperPlugin, popupType);
-        // The caller owns the object, but we retain a pointer for use in closeWidgetNow().
-        m_helperPluginWebWidget = blink::WebHelperPlugin::create(this);
-        return m_helperPluginWebWidget;
-    }
-
-    virtual void initializeHelperPluginWebFrame(blink::WebHelperPlugin* plugin) OVERRIDE
-    {
-        ASSERT_TRUE(m_webFrameClient);
-        plugin->initializeFrame(m_webFrameClient);
-    }
-
-    // WebWidgetClient methods
-    virtual void closeWidgetSoon() OVERRIDE
-    {
-        ASSERT_TRUE(m_helperPluginWebWidget);
-        // m_helperPluginWebWidget->close() must be called asynchronously.
-        if (!m_closeTimer.isActive())
-            m_closeTimer.startOneShot(0);
-    }
-
-    void closeWidgetNow(WebCore::Timer<HelperPluginCreatingWebViewClient>* timer)
-    {
-        m_helperPluginWebWidget->close();
-        m_helperPluginWebWidget = 0;
-    }
-
-    // Local methods
-    HelperPluginCreatingWebViewClient()
-        : m_helperPluginWebWidget(0)
-        , m_webFrameClient(0)
-        , m_closeTimer(this, &HelperPluginCreatingWebViewClient::closeWidgetNow)
-    {
-    }
-
-    void setWebFrameClient(WebFrameClient* client) { m_webFrameClient = client; }
-
-private:
-    WebWidget* m_helperPluginWebWidget;
-    WebFrameClient* m_webFrameClient;
-    WebCore::Timer<HelperPluginCreatingWebViewClient> m_closeTimer;
-};
-
-class DateTimeChooserWebViewClient : public WebViewClient {
+class DateTimeChooserWebViewClient : public FrameTestHelpers::TestWebViewClient {
 public:
     WebDateTimeChooserCompletion* chooserCompletion()
     {
@@ -236,6 +195,11 @@ public:
     }
 
 protected:
+    void registerMockedHttpURLLoad(const std::string& fileName)
+    {
+        URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str()));
+    }
+
     void testAutoResize(const WebSize& minAutoResize, const WebSize& maxAutoResize,
                         const std::string& pageWidth, const std::string& pageHeight,
                         int expectedWidth, int expectedHeight,
@@ -243,6 +207,7 @@ protected:
 
     void testTextInputType(WebTextInputType expectedType, const std::string& htmlFile);
     void testInputMode(const WebString& expectedInputMode, const std::string& htmlFile);
+    void testSelectionRootBounds(const char* htmlFile, float pageScaleFactor);
 
     std::string m_baseURL;
     FrameTestHelpers::WebViewHelper m_webViewHelper;
@@ -254,28 +219,40 @@ TEST_F(WebViewTest, SetBaseBackgroundColor)
     const WebColor kBlue     = 0xFF0000FF;
     const WebColor kDarkCyan = 0xFF227788;
     const WebColor kTranslucentPutty = 0x80BFB196;
+    const WebColor kTransparent = 0x00000000;
 
-    WebView* webView = m_webViewHelper.initialize();
+    WebViewImpl* webView = m_webViewHelper.initialize();
     EXPECT_EQ(kWhite, webView->backgroundColor());
 
     webView->setBaseBackgroundColor(kBlue);
     EXPECT_EQ(kBlue, webView->backgroundColor());
 
     WebURL baseURL = URLTestHelpers::toKURL("http://example.com/");
-    webView->mainFrame()->loadHTMLString(
-        "<html><head><style>body {background-color:#227788}</style></head></html>", baseURL);
-    Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
+    FrameTestHelpers::loadHTMLString(webView->mainFrame(), "<html><head><style>body {background-color:#227788}</style></head></html>", baseURL);
     EXPECT_EQ(kDarkCyan, webView->backgroundColor());
 
-    webView->mainFrame()->loadHTMLString(
-        "<html><head><style>body {background-color:rgba(255,0,0,0.5)}</style></head></html>", baseURL);
-    Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
+    FrameTestHelpers::loadHTMLString(webView->mainFrame(), "<html><head><style>body {background-color:rgba(255,0,0,0.5)}</style></head></html>", baseURL);
     // Expected: red (50% alpha) blended atop base of kBlue.
     EXPECT_EQ(0xFF7F0080, webView->backgroundColor());
 
     webView->setBaseBackgroundColor(kTranslucentPutty);
     // Expected: red (50% alpha) blended atop kTranslucentPutty. Note the alpha.
     EXPECT_EQ(0xBFE93B32, webView->backgroundColor());
+
+    webView->setBaseBackgroundColor(kTransparent);
+    FrameTestHelpers::loadHTMLString(webView->mainFrame(), "<html><head><style>body {background-color:transparent}</style></head></html>", baseURL);
+    // Expected: transparent on top of kTransparent will still be transparent.
+    EXPECT_EQ(kTransparent, webView->backgroundColor());
+
+    WebCore::LocalFrame* frame = webView->mainFrameImpl()->frame();
+
+    // Creating a new frame view with the background color having 0 alpha.
+    frame->createView(WebCore::IntSize(1024, 768), WebCore::Color::transparent, true);
+    EXPECT_EQ(kTransparent, frame->view()->baseBackgroundColor());
+
+    WebCore::Color kTransparentRed(100, 0, 0, 0);
+    frame->createView(WebCore::IntSize(1024, 768), kTransparentRed, true);
+    EXPECT_EQ(kTransparentRed, frame->view()->baseBackgroundColor());
 }
 
 TEST_F(WebViewTest, SetBaseBackgroundColorBeforeMainFrame)
@@ -286,6 +263,8 @@ TEST_F(WebViewTest, SetBaseBackgroundColorBeforeMainFrame)
     // webView does not have a frame yet, but we should still be able to set the background color.
     webView->setBaseBackgroundColor(kBlue);
     EXPECT_EQ(kBlue, webView->backgroundColor());
+    webView->setMainFrame(WebLocalFrameImpl::create(0));
+    webView->close();
 }
 
 TEST_F(WebViewTest, SetBaseBackgroundColorAndBlendWithExistingContent)
@@ -295,8 +274,9 @@ TEST_F(WebViewTest, SetBaseBackgroundColorAndBlendWithExistingContent)
     const int kWidth = 100;
     const int kHeight = 100;
 
-    // Set WebView background to green with alpha.
     WebView* webView = m_webViewHelper.initialize();
+
+    // Set WebView background to green with alpha.
     webView->setBaseBackgroundColor(kAlphaGreen);
     webView->settings()->setShouldClearDocumentBackground(false);
     webView->resize(WebSize(kWidth, kHeight));
@@ -304,12 +284,18 @@ TEST_F(WebViewTest, SetBaseBackgroundColorAndBlendWithExistingContent)
 
     // Set canvas background to red with alpha.
     SkBitmap bitmap;
-    bitmap.setConfig(SkBitmap::kARGB_8888_Config, kWidth, kHeight);
-    bitmap.allocPixels();
-    SkBitmapDevice device(bitmap);
-    SkCanvas canvas(&device);
+    ASSERT_TRUE(bitmap.allocN32Pixels(kWidth, kHeight));
+    SkCanvas canvas(bitmap);
     canvas.clear(kAlphaRed);
-    webView->paint(&canvas, WebRect(0, 0, kWidth, kHeight));
+
+    WebCore::GraphicsContext context(&canvas);
+
+    // Paint the root of the main frame in the way that CompositedLayerMapping would.
+    WebCore::FrameView* view = m_webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
+    WebCore::RenderLayer* rootLayer = view->renderView()->layer();
+    WebCore::IntRect paintRect(0, 0, kWidth, kHeight);
+    WebCore::LayerPaintingInfo paintingInfo(rootLayer, paintRect, WebCore::PaintBehaviorNormal, WebCore::LayoutSize());
+    rootLayer->paintLayerContents(&context, paintingInfo, WebCore::PaintLayerPaintingCompositingAllPhases);
 
     // The result should be a blend of red and green.
     SkColor color = bitmap.getColor(kWidth / 2, kHeight / 2);
@@ -324,7 +310,7 @@ TEST_F(WebViewTest, FocusIsInactive)
 
     webView->setFocus(true);
     webView->setIsActive(true);
-    WebFrameImpl* frame = toWebFrameImpl(webView->mainFrame());
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
     EXPECT_TRUE(frame->frame()->document()->isHTMLDocument());
 
     WebCore::HTMLDocument* document = WebCore::toHTMLDocument(frame->frame()->document());
@@ -375,7 +361,7 @@ TEST_F(WebViewTest, HitTestResultAtWithPageScale)
     negativeResult.reset();
 
     // Scale page up 2x so image should occupy the whole viewport.
-    webView->setPageScaleFactor(2.0f, WebPoint(0, 0));
+    webView->setPageScaleFactor(2.0f);
     WebHitTestResult positiveResult = webView->hitTestResultAt(hitPoint);
     ASSERT_EQ(WebNode::ElementNode, positiveResult.node().nodeType());
     EXPECT_TRUE(positiveResult.node().to<WebElement>().hasTagName("img"));
@@ -393,7 +379,7 @@ void WebViewTest::testAutoResize(const WebSize& minAutoResize, const WebSize& ma
     WebView* webView = m_webViewHelper.initializeAndLoad(url, true, 0, &client);
     client.testData().setWebView(webView);
 
-    WebFrameImpl* frame = toWebFrameImpl(webView->mainFrame());
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
     WebCore::FrameView* frameView = frame->frame()->view();
     frameView->layout();
     EXPECT_FALSE(frameView->layoutPending());
@@ -526,13 +512,24 @@ TEST_F(WebViewTest, InputMode)
     testInputMode(WebString("verbatim"), "input_mode_textarea_verbatim.html");
 }
 
+TEST_F(WebViewTest, TextInputInfoWithReplacedElements)
+{
+    std::string url = m_baseURL + "div_with_image.html";
+    URLTestHelpers::registerMockedURLLoad(toKURL(url), "div_with_image.html");
+    WebView* webView = m_webViewHelper.initializeAndLoad(url);
+    webView->setInitialFocus(false);
+    WebTextInputInfo info = webView->textInputInfo();
+
+    EXPECT_EQ("foo\xef\xbf\xbc", info.value.utf8());
+}
+
 TEST_F(WebViewTest, SetEditableSelectionOffsetsAndTextInputInfo)
 {
     URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html"));
     WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html");
     webView->setInitialFocus(false);
-    webView->setEditableSelectionOffsets(5, 13);
-    WebFrameImpl* frame = toWebFrameImpl(webView->mainFrame());
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
+    frame->setEditableSelectionOffsets(5, 13);
     EXPECT_EQ("56789abc", frame->selectionAsText());
     WebTextInputInfo info = webView->textInputInfo();
     EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", info.value);
@@ -544,8 +541,8 @@ TEST_F(WebViewTest, SetEditableSelectionOffsetsAndTextInputInfo)
     URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("content_editable_populated.html"));
     webView = m_webViewHelper.initializeAndLoad(m_baseURL + "content_editable_populated.html");
     webView->setInitialFocus(false);
-    webView->setEditableSelectionOffsets(8, 19);
-    frame = toWebFrameImpl(webView->mainFrame());
+    frame = toWebLocalFrameImpl(webView->mainFrame());
+    frame->setEditableSelectionOffsets(8, 19);
     EXPECT_EQ("89abcdefghi", frame->selectionAsText());
     info = webView->textInputInfo();
     EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", info.value);
@@ -605,8 +602,9 @@ TEST_F(WebViewTest, InsertNewLinePlacementAfterConfirmComposition)
 
     WebVector<WebCompositionUnderline> emptyUnderlines;
 
-    webView->setEditableSelectionOffsets(4, 4);
-    webView->setCompositionFromExistingText(8, 12, emptyUnderlines);
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
+    frame->setEditableSelectionOffsets(4, 4);
+    frame->setCompositionFromExistingText(8, 12, emptyUnderlines);
 
     WebTextInputInfo info = webView->textInputInfo();
     EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", std::string(info.value.utf8().data()));
@@ -636,14 +634,15 @@ TEST_F(WebViewTest, ExtendSelectionAndDelete)
 {
     URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html"));
     WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html");
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
     webView->setInitialFocus(false);
-    webView->setEditableSelectionOffsets(10, 10);
-    webView->extendSelectionAndDelete(5, 8);
+    frame->setEditableSelectionOffsets(10, 10);
+    frame->extendSelectionAndDelete(5, 8);
     WebTextInputInfo info = webView->textInputInfo();
     EXPECT_EQ("01234ijklmnopqrstuvwxyz", std::string(info.value.utf8().data()));
     EXPECT_EQ(5, info.selectionStart);
     EXPECT_EQ(5, info.selectionEnd);
-    webView->extendSelectionAndDelete(10, 0);
+    frame->extendSelectionAndDelete(10, 0);
     info = webView->textInputInfo();
     EXPECT_EQ("ijklmnopqrstuvwxyz", std::string(info.value.utf8().data()));
 }
@@ -654,9 +653,10 @@ TEST_F(WebViewTest, SetCompositionFromExistingText)
     WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html");
     webView->setInitialFocus(false);
     WebVector<WebCompositionUnderline> underlines(static_cast<size_t>(1));
-    underlines[0] = blink::WebCompositionUnderline(0, 4, 0, false);
-    webView->setEditableSelectionOffsets(4, 10);
-    webView->setCompositionFromExistingText(8, 12, underlines);
+    underlines[0] = blink::WebCompositionUnderline(0, 4, 0, false, 0);
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
+    frame->setEditableSelectionOffsets(4, 10);
+    frame->setCompositionFromExistingText(8, 12, underlines);
     WebVector<WebCompositionUnderline> underlineResults = toWebViewImpl(webView)->compositionUnderlines();
     EXPECT_EQ(8u, underlineResults[0].startOffset);
     EXPECT_EQ(12u, underlineResults[0].endOffset);
@@ -666,7 +666,7 @@ TEST_F(WebViewTest, SetCompositionFromExistingText)
     EXPECT_EQ(8, info.compositionStart);
     EXPECT_EQ(12, info.compositionEnd);
     WebVector<WebCompositionUnderline> emptyUnderlines;
-    webView->setCompositionFromExistingText(0, 0, emptyUnderlines);
+    frame->setCompositionFromExistingText(0, 0, emptyUnderlines);
     info = webView->textInputInfo();
     EXPECT_EQ(4, info.selectionStart);
     EXPECT_EQ(10, info.selectionEnd);
@@ -680,15 +680,16 @@ TEST_F(WebViewTest, SetCompositionFromExistingTextInTextArea)
     WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "text_area_populated.html");
     webView->setInitialFocus(false);
     WebVector<WebCompositionUnderline> underlines(static_cast<size_t>(1));
-    underlines[0] = blink::WebCompositionUnderline(0, 4, 0, false);
-    webView->setEditableSelectionOffsets(27, 27);
+    underlines[0] = blink::WebCompositionUnderline(0, 4, 0, false, 0);
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
+    frame->setEditableSelectionOffsets(27, 27);
     std::string newLineText("\n");
     webView->confirmComposition(WebString::fromUTF8(newLineText.c_str()));
     WebTextInputInfo info = webView->textInputInfo();
     EXPECT_EQ("0123456789abcdefghijklmnopq\nrstuvwxyz", std::string(info.value.utf8().data()));
 
-    webView->setEditableSelectionOffsets(31, 31);
-    webView->setCompositionFromExistingText(30, 34, underlines);
+    frame->setEditableSelectionOffsets(31, 31);
+    frame->setCompositionFromExistingText(30, 34, underlines);
     WebVector<WebCompositionUnderline> underlineResults = toWebViewImpl(webView)->compositionUnderlines();
     EXPECT_EQ(2u, underlineResults[0].startOffset);
     EXPECT_EQ(6u, underlineResults[0].endOffset);
@@ -729,7 +730,8 @@ TEST_F(WebViewTest, SetEditableSelectionOffsetsKeepsComposition)
     EXPECT_EQ(6, info.compositionStart);
     EXPECT_EQ(11, info.compositionEnd);
 
-    webView->setEditableSelectionOffsets(6, 6);
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
+    frame->setEditableSelectionOffsets(6, 6);
     info = webView->textInputInfo();
     EXPECT_EQ("hello world", std::string(info.value.utf8().data()));
     EXPECT_EQ(6, info.selectionStart);
@@ -737,7 +739,7 @@ TEST_F(WebViewTest, SetEditableSelectionOffsetsKeepsComposition)
     EXPECT_EQ(6, info.compositionStart);
     EXPECT_EQ(11, info.compositionEnd);
 
-    webView->setEditableSelectionOffsets(8, 8);
+    frame->setEditableSelectionOffsets(8, 8);
     info = webView->textInputInfo();
     EXPECT_EQ("hello world", std::string(info.value.utf8().data()));
     EXPECT_EQ(8, info.selectionStart);
@@ -745,7 +747,7 @@ TEST_F(WebViewTest, SetEditableSelectionOffsetsKeepsComposition)
     EXPECT_EQ(6, info.compositionStart);
     EXPECT_EQ(11, info.compositionEnd);
 
-    webView->setEditableSelectionOffsets(11, 11);
+    frame->setEditableSelectionOffsets(11, 11);
     info = webView->textInputInfo();
     EXPECT_EQ("hello world", std::string(info.value.utf8().data()));
     EXPECT_EQ(11, info.selectionStart);
@@ -753,7 +755,7 @@ TEST_F(WebViewTest, SetEditableSelectionOffsetsKeepsComposition)
     EXPECT_EQ(6, info.compositionStart);
     EXPECT_EQ(11, info.compositionEnd);
 
-    webView->setEditableSelectionOffsets(6, 11);
+    frame->setEditableSelectionOffsets(6, 11);
     info = webView->textInputInfo();
     EXPECT_EQ("hello world", std::string(info.value.utf8().data()));
     EXPECT_EQ(6, info.selectionStart);
@@ -761,7 +763,7 @@ TEST_F(WebViewTest, SetEditableSelectionOffsetsKeepsComposition)
     EXPECT_EQ(6, info.compositionStart);
     EXPECT_EQ(11, info.compositionEnd);
 
-    webView->setEditableSelectionOffsets(2, 2);
+    frame->setEditableSelectionOffsets(2, 2);
     info = webView->textInputInfo();
     EXPECT_EQ("hello world", std::string(info.value.utf8().data()));
     EXPECT_EQ(2, info.selectionStart);
@@ -776,8 +778,9 @@ TEST_F(WebViewTest, IsSelectionAnchorFirst)
     WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html");
     WebFrame* frame = webView->mainFrame();
 
+    webView->setPageScaleFactorLimits(1, 1);
     webView->setInitialFocus(false);
-    webView->setEditableSelectionOffsets(4, 10);
+    frame->setEditableSelectionOffsets(4, 10);
     EXPECT_TRUE(webView->isSelectionAnchorFirst());
     WebRect anchor;
     WebRect focus;
@@ -796,27 +799,16 @@ TEST_F(WebViewTest, HistoryResetScrollAndScaleState)
     EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().height);
 
     // Make the page scale and scroll with the given paremeters.
-    webViewImpl->setPageScaleFactor(2.0f, WebPoint(116, 84));
+    webViewImpl->setPageScaleFactor(2.0f);
+    webViewImpl->setMainFrameScrollOffset(WebPoint(116, 84));
     EXPECT_EQ(2.0f, webViewImpl->pageScaleFactor());
     EXPECT_EQ(116, webViewImpl->mainFrame()->scrollOffset().width);
     EXPECT_EQ(84, webViewImpl->mainFrame()->scrollOffset().height);
-    webViewImpl->page()->mainFrame()->loader().saveDocumentAndScrollState();
-
-    // Confirm that restoring the page state restores the parameters.
-    webViewImpl->setPageScaleFactor(1.5f, WebPoint(16, 24));
-    EXPECT_EQ(1.5f, webViewImpl->pageScaleFactor());
-    EXPECT_EQ(16, webViewImpl->mainFrame()->scrollOffset().width);
-    EXPECT_EQ(24, webViewImpl->mainFrame()->scrollOffset().height);
-    // WebViewImpl::setPageScaleFactor is performing user scrolls, which will set the
-    // wasScrolledByUser flag on the main frame, and prevent restoreScrollPositionAndViewState
-    // from restoring the scrolling position.
-    webViewImpl->page()->mainFrame()->view()->setWasScrolledByUser(false);
-    webViewImpl->page()->mainFrame()->loader().setLoadType(WebCore::FrameLoadTypeBackForward);
-    webViewImpl->page()->mainFrame()->loader().restoreScrollPositionAndViewState();
-    EXPECT_EQ(2.0f, webViewImpl->pageScaleFactor());
-    EXPECT_EQ(116, webViewImpl->mainFrame()->scrollOffset().width);
-    EXPECT_EQ(84, webViewImpl->mainFrame()->scrollOffset().height);
-    webViewImpl->page()->mainFrame()->loader().saveDocumentAndScrollState();
+    WebCore::LocalFrame* mainFrameLocal = toLocalFrame(webViewImpl->page()->mainFrame());
+    mainFrameLocal->loader().saveScrollState();
+    EXPECT_EQ(2.0f, mainFrameLocal->loader().currentItem()->pageScaleFactor());
+    EXPECT_EQ(116, mainFrameLocal->loader().currentItem()->scrollPoint().x());
+    EXPECT_EQ(84, mainFrameLocal->loader().currentItem()->scrollPoint().y());
 
     // Confirm that resetting the page state resets the saved scroll position.
     // The HistoryController treats a page scale factor of 0.0f as special and avoids
@@ -825,13 +817,44 @@ TEST_F(WebViewTest, HistoryResetScrollAndScaleState)
     EXPECT_EQ(1.0f, webViewImpl->pageScaleFactor());
     EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().width);
     EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().height);
-    webViewImpl->page()->mainFrame()->loader().restoreScrollPositionAndViewState();
-    EXPECT_EQ(1.0f, webViewImpl->pageScaleFactor());
+    EXPECT_EQ(0.0f, mainFrameLocal->loader().currentItem()->pageScaleFactor());
+    EXPECT_EQ(0, mainFrameLocal->loader().currentItem()->scrollPoint().x());
+    EXPECT_EQ(0, mainFrameLocal->loader().currentItem()->scrollPoint().y());
+}
+
+TEST_F(WebViewTest, BackForwardRestoreScroll)
+{
+    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("back_forward_restore_scroll.html"));
+    WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(m_baseURL + "back_forward_restore_scroll.html");
+    webViewImpl->resize(WebSize(640, 480));
+    webViewImpl->layout();
+
+    // Emulate a user scroll
+    webViewImpl->setMainFrameScrollOffset(WebPoint(0, 900));
+    WebCore::LocalFrame* mainFrameLocal = toLocalFrame(webViewImpl->page()->mainFrame());
+    RefPtr<WebCore::HistoryItem> item1 = mainFrameLocal->loader().currentItem();
+
+    // Click an anchor
+    mainFrameLocal->loader().load(WebCore::FrameLoadRequest(mainFrameLocal->document(), WebCore::ResourceRequest(mainFrameLocal->document()->completeURL("#a"))));
+    RefPtr<WebCore::HistoryItem> item2 = mainFrameLocal->loader().currentItem();
+
+    // Go back, then forward, then back again.
+    mainFrameLocal->loader().loadHistoryItem(item1.get(), WebCore::HistorySameDocumentLoad);
+    mainFrameLocal->loader().loadHistoryItem(item2.get(), WebCore::HistorySameDocumentLoad);
+    mainFrameLocal->loader().loadHistoryItem(item1.get(), WebCore::HistorySameDocumentLoad);
+
+    // Click a different anchor
+    mainFrameLocal->loader().load(WebCore::FrameLoadRequest(mainFrameLocal->document(), WebCore::ResourceRequest(mainFrameLocal->document()->completeURL("#b"))));
+    RefPtr<WebCore::HistoryItem> item3 = mainFrameLocal->loader().currentItem();
+
+    // Go back, then forward. The scroll position should be properly set on the forward navigation.
+    mainFrameLocal->loader().loadHistoryItem(item1.get(), WebCore::HistorySameDocumentLoad);
+    mainFrameLocal->loader().loadHistoryItem(item3.get(), WebCore::HistorySameDocumentLoad);
     EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().width);
-    EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().height);
+    EXPECT_GT(webViewImpl->mainFrame()->scrollOffset().height, 2000);
 }
 
-class EnterFullscreenWebViewClient : public WebViewClient {
+class EnterFullscreenWebViewClient : public FrameTestHelpers::TestWebViewClient {
 public:
     // WebViewClient methods
     virtual bool enterFullScreen() { return true; }
@@ -844,19 +867,19 @@ TEST_F(WebViewTest, EnterFullscreenResetScrollAndScaleState)
     EnterFullscreenWebViewClient client;
     URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("hello_world.html"));
     WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(m_baseURL + "hello_world.html", true, 0, &client);
-    webViewImpl->settings()->setFullScreenEnabled(true);
     webViewImpl->resize(WebSize(640, 480));
     webViewImpl->layout();
     EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().width);
     EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().height);
 
     // Make the page scale and scroll with the given paremeters.
-    webViewImpl->setPageScaleFactor(2.0f, WebPoint(116, 84));
+    webViewImpl->setPageScaleFactor(2.0f);
+    webViewImpl->setMainFrameScrollOffset(WebPoint(116, 84));
     EXPECT_EQ(2.0f, webViewImpl->pageScaleFactor());
     EXPECT_EQ(116, webViewImpl->mainFrame()->scrollOffset().width);
     EXPECT_EQ(84, webViewImpl->mainFrame()->scrollOffset().height);
 
-    RefPtr<WebCore::Element> element = static_cast<PassRefPtr<WebCore::Element> >(webViewImpl->mainFrame()->document().body());
+    RefPtrWillBeRawPtr<WebCore::Element> element = static_cast<PassRefPtrWillBeRawPtr<WebCore::Element> >(webViewImpl->mainFrame()->document().body());
     webViewImpl->enterFullScreenForElement(element.get());
     webViewImpl->willEnterFullScreen();
     webViewImpl->didEnterFullScreen();
@@ -866,7 +889,7 @@ TEST_F(WebViewTest, EnterFullscreenResetScrollAndScaleState)
     EXPECT_EQ(1.0f, webViewImpl->pageScaleFactor());
 
     // Make sure fullscreen nesting doesn't disrupt scroll/scale saving.
-    RefPtr<WebCore::Element> otherElement = static_cast<PassRefPtr<WebCore::Element> >(webViewImpl->mainFrame()->document().head());
+    RefPtrWillBeRawPtr<WebCore::Element> otherElement = static_cast<PassRefPtrWillBeRawPtr<WebCore::Element> >(webViewImpl->mainFrame()->document().head());
     webViewImpl->enterFullScreenForElement(otherElement.get());
 
     // Confirm that exiting fullscreen restores the parameters.
@@ -879,7 +902,100 @@ TEST_F(WebViewTest, EnterFullscreenResetScrollAndScaleState)
     m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client.
 }
 
-class ContentDetectorClient : public WebViewClient {
+class PrintWebViewClient : public FrameTestHelpers::TestWebViewClient {
+public:
+    PrintWebViewClient()
+        : m_printCalled(false)
+    {
+    }
+
+    // WebViewClient methods
+    virtual void printPage(WebLocalFrame*) OVERRIDE
+    {
+        m_printCalled = true;
+    }
+
+    bool printCalled() const { return m_printCalled; }
+
+private:
+    bool m_printCalled;
+};
+
+
+TEST_F(WebViewTest, PrintWithXHRInFlight)
+{
+    PrintWebViewClient client;
+    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("print_with_xhr_inflight.html"));
+    WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(m_baseURL + "print_with_xhr_inflight.html", true, 0, &client);
+
+    ASSERT_EQ(WebCore::FrameStateComplete, toLocalFrame(webViewImpl->page()->mainFrame())->loader().state());
+    EXPECT_TRUE(client.printCalled());
+    m_webViewHelper.reset();
+}
+
+class DropTask : public WebThread::Task {
+public:
+    explicit DropTask(WebView* webView) : m_webView(webView)
+    {
+    }
+
+    virtual void run() OVERRIDE
+    {
+        const WebPoint clientPoint(0, 0);
+        const WebPoint screenPoint(0, 0);
+        m_webView->dragTargetDrop(clientPoint, screenPoint, 0);
+    }
+
+private:
+    WebView* const m_webView;
+};
+static void DragAndDropURL(WebViewImpl* webView, const std::string& url)
+{
+    blink::WebDragData dragData;
+    dragData.initialize();
+
+    WebDragData::Item item;
+    item.storageType = WebDragData::Item::StorageTypeString;
+    item.stringType = "text/uri-list";
+    item.stringData = WebString::fromUTF8(url);
+    dragData.addItem(item);
+
+    const WebPoint clientPoint(0, 0);
+    const WebPoint screenPoint(0, 0);
+    webView->dragTargetDragEnter(dragData, clientPoint, screenPoint, blink::WebDragOperationCopy, 0);
+    Platform::current()->currentThread()->postTask(new DropTask(webView));
+    FrameTestHelpers::pumpPendingRequestsDoNotUse(webView->mainFrame());
+}
+
+TEST_F(WebViewTest, DragDropURL)
+{
+    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), "foo.html");
+    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), "bar.html");
+
+    const std::string fooUrl = m_baseURL + "foo.html";
+    const std::string barUrl = m_baseURL + "bar.html";
+
+    WebViewImpl* webView = m_webViewHelper.initializeAndLoad(fooUrl);
+
+    ASSERT_TRUE(webView);
+
+    // Drag and drop barUrl and verify that we've navigated to it.
+    DragAndDropURL(webView, barUrl);
+    EXPECT_EQ(barUrl, webView->mainFrame()->document().url().string().utf8());
+
+    // Drag and drop fooUrl and verify that we've navigated back to it.
+    DragAndDropURL(webView, fooUrl);
+    EXPECT_EQ(fooUrl, webView->mainFrame()->document().url().string().utf8());
+
+    // Disable navigation on drag-and-drop.
+    webView->settingsImpl()->setNavigateOnDragDrop(false);
+
+    // Attempt to drag and drop to barUrl and verify that no navigation has occurred.
+    DragAndDropURL(webView, barUrl);
+    EXPECT_EQ(fooUrl, webView->mainFrame()->document().url().string().utf8());
+}
+
+class ContentDetectorClient : public FrameTestHelpers::TestWebViewClient {
 public:
     ContentDetectorClient() { reset(); }
 
@@ -922,7 +1038,7 @@ private:
 static bool tapElementById(WebView* webView, WebInputEvent::Type type, const WebString& id)
 {
     ASSERT(webView);
-    RefPtr<WebCore::Element> element = static_cast<PassRefPtr<WebCore::Element> >(webView->mainFrame()->document().getElementById(id));
+    RefPtrWillBeRawPtr<WebCore::Element> element = static_cast<PassRefPtrWillBeRawPtr<WebCore::Element> >(webView->mainFrame()->document().getElementById(id));
     if (!element)
         return false;
 
@@ -986,6 +1102,8 @@ TEST_F(WebViewTest, DetectContentAroundPosition)
     webView->handleInputEvent(event);
     runPendingTasks();
     EXPECT_TRUE(client.pendingIntentsCancelled());
+
+    m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client.
 }
 
 TEST_F(WebViewTest, ClientTapHandling)
@@ -1025,7 +1143,7 @@ TEST_F(WebViewTest, LongPressSelection)
 
     WebString target = WebString::fromUTF8("target");
     WebString onselectstartfalse = WebString::fromUTF8("onselectstartfalse");
-    WebFrameImpl* frame = toWebFrameImpl(webView->mainFrame());
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
 
     EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureLongPress, onselectstartfalse));
     EXPECT_EQ("", std::string(frame->selectionAsText().utf8().data()));
@@ -1044,7 +1162,7 @@ TEST_F(WebViewTest, SelectionOnDisabledInput)
 
     std::string testWord = "This text should be selected.";
 
-    WebFrameImpl* frame = toWebFrameImpl(webView->mainFrame());
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
     EXPECT_EQ(testWord, std::string(frame->selectionAsText().utf8().data()));
 
     size_t location;
@@ -1064,7 +1182,7 @@ TEST_F(WebViewTest, SelectionOnReadOnlyInput)
 
     std::string testWord = "This text should be selected.";
 
-    WebFrameImpl* frame = toWebFrameImpl(webView->mainFrame());
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
     EXPECT_EQ(testWord, std::string(frame->selectionAsText().utf8().data()));
 
     size_t location;
@@ -1074,23 +1192,55 @@ TEST_F(WebViewTest, SelectionOnReadOnlyInput)
     EXPECT_EQ(length, testWord.length());
 }
 
+static void configueCompositingWebView(WebSettings* settings)
+{
+    settings->setAcceleratedCompositingEnabled(true);
+    settings->setAcceleratedCompositingForFixedPositionEnabled(true);
+    settings->setAcceleratedCompositingForOverflowScrollEnabled(true);
+    settings->setCompositedScrollingForFramesEnabled(true);
+}
+
+TEST_F(WebViewTest, ShowPressOnTransformedLink)
+{
+    OwnPtr<FrameTestHelpers::TestWebViewClient> fakeCompositingWebViewClient = adoptPtr(new FrameTestHelpers::TestWebViewClient());
+    FrameTestHelpers::WebViewHelper webViewHelper;
+    WebViewImpl* webViewImpl = webViewHelper.initialize(true, 0, fakeCompositingWebViewClient.get(), &configueCompositingWebView);
+
+    int pageWidth = 640;
+    int pageHeight = 480;
+    webViewImpl->resize(WebSize(pageWidth, pageHeight));
+
+    WebURL baseURL = URLTestHelpers::toKURL("http://example.com/");
+    FrameTestHelpers::loadHTMLString(webViewImpl->mainFrame(), "<a href='http://www.test.com' style='position: absolute; left: 20px; top: 20px; width: 200px; -webkit-transform:translateZ(0);'>A link to highlight</a>", baseURL);
+
+    WebGestureEvent event;
+    event.type = WebInputEvent::GestureShowPress;
+    event.x = 20;
+    event.y = 20;
+
+    // Just make sure we don't hit any asserts.
+    webViewImpl->handleInputEvent(event);
+}
+
 class MockAutofillClient : public WebAutofillClient {
 public:
     MockAutofillClient()
         : m_ignoreTextChanges(false)
         , m_textChangesWhileIgnored(0)
-        , m_textChangesWhileNotIgnored(0) { }
+        , m_textChangesWhileNotIgnored(0)
+        , m_userGestureNotificationsCount(0) { }
 
     virtual ~MockAutofillClient() { }
 
     virtual void setIgnoreTextChanges(bool ignore) OVERRIDE { m_ignoreTextChanges = ignore; }
-    virtual void textFieldDidChange(const WebInputElement&) OVERRIDE
+    virtual void textFieldDidChange(const WebFormControlElement&) OVERRIDE
     {
         if (m_ignoreTextChanges)
             ++m_textChangesWhileIgnored;
         else
             ++m_textChangesWhileNotIgnored;
     }
+    virtual void firstUserGestureObserved() OVERRIDE { ++m_userGestureNotificationsCount; }
 
     void clearChangeCounts()
     {
@@ -1100,11 +1250,13 @@ public:
 
     int textChangesWhileIgnored() { return m_textChangesWhileIgnored; }
     int textChangesWhileNotIgnored() { return m_textChangesWhileNotIgnored; }
+    int getUserGestureNotificationsCount() { return m_userGestureNotificationsCount; }
 
 private:
     bool m_ignoreTextChanges;
     int m_textChangesWhileIgnored;
     int m_textChangesWhileNotIgnored;
+    int m_userGestureNotificationsCount;
 };
 
 
@@ -1118,8 +1270,9 @@ TEST_F(WebViewTest, LosingFocusDoesNotTriggerAutofillTextChange)
 
     // Set up a composition that needs to be committed.
     WebVector<WebCompositionUnderline> emptyUnderlines;
-    webView->setEditableSelectionOffsets(4, 10);
-    webView->setCompositionFromExistingText(8, 12, emptyUnderlines);
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
+    frame->setEditableSelectionOffsets(4, 10);
+    frame->setCompositionFromExistingText(8, 12, emptyUnderlines);
     WebTextInputInfo info = webView->textInputInfo();
     EXPECT_EQ(4, info.selectionStart);
     EXPECT_EQ(10, info.selectionEnd);
@@ -1175,7 +1328,8 @@ TEST_F(WebViewTest, SetCompositionFromExistingTextTriggersAutofillTextChange)
     WebVector<WebCompositionUnderline> emptyUnderlines;
 
     client.clearChangeCounts();
-    webView->setCompositionFromExistingText(8, 12, emptyUnderlines);
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
+    frame->setCompositionFromExistingText(8, 12, emptyUnderlines);
 
     WebTextInputInfo info = webView->textInputInfo();
     EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", std::string(info.value.utf8().data()));
@@ -1211,26 +1365,7 @@ TEST_F(WebViewTest, ShadowRoot)
     }
 }
 
-TEST_F(WebViewTest, HelperPlugin)
-{
-    HelperPluginCreatingWebViewClient client;
-    WebViewImpl* webViewImpl = m_webViewHelper.initialize(true, 0, &client);
-
-    WebFrameImpl* frame = toWebFrameImpl(webViewImpl->mainFrame());
-    client.setWebFrameClient(frame->client());
-
-    OwnPtr<WebHelperPlugin> helperPlugin = webViewImpl->createHelperPlugin("dummy-plugin-type", frame->document());
-    EXPECT_TRUE(helperPlugin);
-    EXPECT_EQ(0, helperPlugin->getPlugin()); // Invalid plugin type means no plugin.
-
-    helperPlugin.clear();
-    runPendingTasks();
-
-    m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client.
-}
-
-
-class ViewCreatingWebViewClient : public WebViewClient {
+class ViewCreatingWebViewClient : public FrameTestHelpers::TestWebViewClient {
 public:
     ViewCreatingWebViewClient()
         : m_didFocusCalled(false)
@@ -1238,7 +1373,7 @@ public:
     }
 
     // WebViewClient methods
-    virtual WebView* createView(WebFrame*, const WebURLRequest&, const WebWindowFeatures&, const WebString& name, WebNavigationPolicy, bool) OVERRIDE
+    virtual WebView* createView(WebLocalFrame*, const WebURLRequest&, const WebWindowFeatures&, const WebString& name, WebNavigationPolicy, bool) OVERRIDE
     {
         return m_webViewHelper.initialize(true, 0, 0);
     }
@@ -1263,14 +1398,14 @@ TEST_F(WebViewTest, FocusExistingFrameOnNavigate)
     FrameTestHelpers::WebViewHelper m_webViewHelper;
     WebViewImpl* webViewImpl = m_webViewHelper.initialize(true, 0, &client);
     webViewImpl->page()->settings().setJavaScriptCanOpenWindowsAutomatically(true);
-    WebFrameImpl* frame = toWebFrameImpl(webViewImpl->mainFrame());
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewImpl->mainFrame());
     frame->setName("_start");
 
     // Make a request that will open a new window
     WebURLRequest webURLRequest;
     webURLRequest.initialize();
     WebCore::FrameLoadRequest request(0, webURLRequest.toResourceRequest(), "_blank");
-    webViewImpl->page()->mainFrame()->loader().load(request);
+    toLocalFrame(webViewImpl->page()->mainFrame())->loader().load(request);
     ASSERT_TRUE(client.createdWebView());
     EXPECT_FALSE(client.didFocusCalled());
 
@@ -1278,7 +1413,7 @@ TEST_F(WebViewTest, FocusExistingFrameOnNavigate)
     WebURLRequest webURLRequestWithTargetStart;
     webURLRequestWithTargetStart.initialize();
     WebCore::FrameLoadRequest requestWithTargetStart(0, webURLRequestWithTargetStart.toResourceRequest(), "_start");
-    toWebViewImpl(client.createdWebView())->page()->mainFrame()->loader().load(requestWithTargetStart);
+    toLocalFrame(toWebViewImpl(client.createdWebView())->page()->mainFrame())->loader().load(requestWithTargetStart);
     EXPECT_TRUE(client.didFocusCalled());
 
     m_webViewHelper.reset(); // Remove dependency on locally scoped client.
@@ -1390,6 +1525,10 @@ TEST_F(WebViewTest, ChooseValueFromDateTimeChooser)
     client.chooserCompletion()->didChooseValue(std::numeric_limits<double>::quiet_NaN());
     client.clearChooserCompletion();
     EXPECT_STREQ("", inputElement->value().utf8().data());
+
+    // Clear the WebViewClient from the webViewHelper to avoid use-after-free in the
+    // WebViewHelper destructor.
+    m_webViewHelper.reset();
 }
 #endif
 
@@ -1409,21 +1548,42 @@ TEST_F(WebViewTest, DispatchesFocusBlurOnViewToggle)
 
 TEST_F(WebViewTest, SmartClipData)
 {
+    static const char* kExpectedClipText = "\nPrice 10,000,000won";
+    static const char* kExpectedClipHtml =
+        "<div id=\"div4\" style=\"padding: 10px; margin: 10px; border: 2px "
+        "solid rgb(135, 206, 235); float: left; width: 190px; height: 30px; "
+        "color: rgb(0, 0, 0); font-family: myahem; font-size: 8px; font-style: "
+        "normal; font-variant: normal; font-weight: normal; letter-spacing: "
+        "normal; line-height: normal; orphans: auto; text-align: start; "
+        "text-indent: 0px; text-transform: none; white-space: normal; widows: "
+        "auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;\">Air "
+        "conditioner</div><div id=\"div5\" style=\"padding: 10px; margin: "
+        "10px; border: 2px solid rgb(135, 206, 235); float: left; width: "
+        "190px; height: 30px; color: rgb(0, 0, 0); font-family: myahem; "
+        "font-size: 8px; font-style: normal; font-variant: normal; "
+        "font-weight: normal; letter-spacing: normal; line-height: normal; "
+        "orphans: auto; text-align: start; text-indent: 0px; text-transform: "
+        "none; white-space: normal; widows: auto; word-spacing: 0px; "
+        "-webkit-text-stroke-width: 0px;\">Price 10,000,000won</div>";
+    WebString clipText;
+    WebString clipHtml;
+    WebRect clipRect;
     URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("Ahem.ttf"));
     URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("smartclip.html"));
     WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "smartclip.html");
+    webView->setPageScaleFactorLimits(1, 1);
     webView->resize(WebSize(500, 500));
     webView->layout();
     WebRect cropRect(300, 125, 100, 50);
-
-    // FIXME: We should test the structure of the data we get back.
-    EXPECT_FALSE(webView->getSmartClipData(cropRect).isEmpty());
+    webView->extractSmartClipData(cropRect, clipText, clipHtml, clipRect);
+    EXPECT_STREQ(kExpectedClipText, clipText.utf8().c_str());
+    EXPECT_STREQ(kExpectedClipHtml, clipHtml.utf8().c_str());
 }
 
 class CreateChildCounterFrameClient : public FrameTestHelpers::TestWebFrameClient {
 public:
     CreateChildCounterFrameClient() : m_count(0) { }
-    virtual WebFrame* createChildFrame(WebFrame* parent, const WebString& frameName) OVERRIDE;
+    virtual WebFrame* createChildFrame(WebLocalFrame* parent, const WebString& frameName) OVERRIDE;
 
     int count() const { return m_count; }
 
@@ -1431,7 +1591,7 @@ private:
     int m_count;
 };
 
-WebFrame* CreateChildCounterFrameClient::createChildFrame(WebFrame* parent, const WebString& frameName)
+WebFrame* CreateChildCounterFrameClient::createChildFrame(WebLocalFrame* parent, const WebString& frameName)
 {
     ++m_count;
     return TestWebFrameClient::createChildFrame(parent, frameName);
@@ -1451,7 +1611,7 @@ TEST_F(WebViewTest, AddFrameInCloseURLUnload)
     CreateChildCounterFrameClient frameClient;
     URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("add_frame_in_unload.html"));
     m_webViewHelper.initializeAndLoad(m_baseURL + "add_frame_in_unload.html", true, &frameClient);
-    m_webViewHelper.webViewImpl()->dispatchUnloadEvent();
+    m_webViewHelper.webViewImpl()->mainFrame()->dispatchUnloadEvent();
     EXPECT_EQ(0, frameClient.count());
     m_webViewHelper.reset();
 }
@@ -1477,4 +1637,432 @@ TEST_F(WebViewTest, AddFrameInChildInNavigateUnload)
     m_webViewHelper.reset();
 }
 
+class TouchEventHandlerWebViewClient : public FrameTestHelpers::TestWebViewClient {
+public:
+    // WebWidgetClient methods
+    virtual void hasTouchEventHandlers(bool state) OVERRIDE
+    {
+        m_hasTouchEventHandlerCount[state]++;
+    }
+
+    // Local methods
+    TouchEventHandlerWebViewClient() : m_hasTouchEventHandlerCount()
+    {
+    }
+
+    int getAndResetHasTouchEventHandlerCallCount(bool state)
+    {
+        int value = m_hasTouchEventHandlerCount[state];
+        m_hasTouchEventHandlerCount[state] = 0;
+        return value;
+    }
+
+private:
+    int m_hasTouchEventHandlerCount[2];
+};
+
+// This test verifies that WebWidgetClient::hasTouchEventHandlers is called accordingly for various
+// calls to Document::did{Add|Remove|Clear}TouchEventHandler. Verifying that those calls are made
+// correctly is the job of LayoutTests/fast/events/touch/touch-handler-count.html.
+TEST_F(WebViewTest, HasTouchEventHandlers)
+{
+    TouchEventHandlerWebViewClient client;
+    std::string url = m_baseURL + "has_touch_event_handlers.html";
+    URLTestHelpers::registerMockedURLLoad(toKURL(url), "has_touch_event_handlers.html");
+    WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(url, true, 0, &client);
+
+    // The page is initialized with at least one no-handlers call.
+    // In practice we get two such calls because WebViewHelper::initializeAndLoad first
+    // initializes and empty frame, and then loads a document into it, so there are two
+    // FrameLoader::commitProvisionalLoad calls.
+    EXPECT_GE(client.getAndResetHasTouchEventHandlerCallCount(false), 1);
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Adding the first document handler results in a has-handlers call.
+    WebCore::Document* document = webViewImpl->mainFrameImpl()->frame()->document();
+    document->didAddTouchEventHandler(document);
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Adding another handler has no effect.
+    document->didAddTouchEventHandler(document);
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Removing the duplicate handler has no effect.
+    document->didRemoveTouchEventHandler(document);
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Removing the final handler results in a no-handlers call.
+    document->didRemoveTouchEventHandler(document);
+    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Adding a handler on a div results in a has-handlers call.
+    WebCore::Element* parentDiv = document->getElementById("parentdiv");
+    ASSERT(parentDiv);
+    document->didAddTouchEventHandler(parentDiv);
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Adding a duplicate handler on the div, clearing all document handlers
+    // (of which there are none) and removing the extra handler on the div
+    // all have no effect.
+    document->didAddTouchEventHandler(parentDiv);
+    document->didClearTouchEventHandlers(document);
+    document->didRemoveTouchEventHandler(parentDiv);
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Removing the final handler on the div results in a no-handlers call.
+    document->didRemoveTouchEventHandler(parentDiv);
+    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Adding two handlers then clearing them in a single call results in a
+    // has-handlers then no-handlers call.
+    document->didAddTouchEventHandler(parentDiv);
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(true));
+    document->didAddTouchEventHandler(parentDiv);
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
+    document->didClearTouchEventHandlers(parentDiv);
+    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Adding a handler inside of a child iframe results in a has-handlers call.
+    WebCore::Element* childFrame = document->getElementById("childframe");
+    ASSERT(childFrame);
+    WebCore::Document* childDocument = toHTMLIFrameElement(childFrame)->contentDocument();
+    WebCore::Element* childDiv = childDocument->getElementById("childdiv");
+    ASSERT(childDiv);
+    childDocument->didAddTouchEventHandler(childDiv);
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Adding and clearing handlers in the parent doc or elsewhere in the child doc
+    // has no impact.
+    document->didAddTouchEventHandler(document);
+    document->didAddTouchEventHandler(childFrame);
+    childDocument->didAddTouchEventHandler(childDocument);
+    document->didClearTouchEventHandlers(document);
+    document->didClearTouchEventHandlers(childFrame);
+    childDocument->didClearTouchEventHandlers(childDocument);
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Removing the final handler inside the child frame results in a no-handlers call.
+    childDocument->didRemoveTouchEventHandler(childDiv);
+    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Adding a handler inside the child frame results in a has-handlers call.
+    childDocument->didAddTouchEventHandler(childDocument);
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Adding a handler in the parent document and removing the one in the frame
+    // has no effect.
+    document->didAddTouchEventHandler(childFrame);
+    childDocument->didRemoveTouchEventHandler(childDocument);
+    childDocument->didClearTouchEventHandlers(childDocument);
+    document->didClearTouchEventHandlers(document);
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Now removing the handler in the parent document results in a no-handlers call.
+    document->didRemoveTouchEventHandler(childFrame);
+    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(false));
+    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
+
+    // Free the webView before the TouchEventHandlerWebViewClient gets freed.
+    m_webViewHelper.reset();
+}
+
+static WebRect ExpectedRootBounds(WebCore::Document* document, float scaleFactor)
+{
+    WebCore::Element* element = document->getElementById("root");
+    if (!element)
+        element = document->getElementById("target");
+    if (element->hasTagName(WebCore::HTMLNames::iframeTag))
+        return ExpectedRootBounds(toHTMLIFrameElement(element)->contentDocument(), scaleFactor);
+
+    WebCore::IntRect boundingBox;
+    if (element->hasTagName(WebCore::HTMLNames::htmlTag))
+        boundingBox = WebCore::IntRect(WebCore::IntPoint(0, 0), document->frame()->view()->contentsSize());
+    else
+        boundingBox = element->pixelSnappedBoundingBox();
+    boundingBox = document->frame()->view()->contentsToWindow(boundingBox);
+    boundingBox.scale(scaleFactor);
+    return boundingBox;
+}
+
+void WebViewTest::testSelectionRootBounds(const char* htmlFile, float pageScaleFactor)
+{
+    std::string url = m_baseURL + htmlFile;
+
+    WebView* webView = m_webViewHelper.initializeAndLoad(url, true);
+    webView->resize(WebSize(640, 480));
+    webView->setPageScaleFactor(pageScaleFactor);
+    webView->layout();
+    runPendingTasks();
+
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
+    EXPECT_TRUE(frame->frame()->document()->isHTMLDocument());
+    WebCore::HTMLDocument* document = WebCore::toHTMLDocument(frame->frame()->document());
+
+    WebRect expectedRootBounds = ExpectedRootBounds(document, webView->pageScaleFactor());
+    WebRect actualRootBounds;
+    webView->getSelectionRootBounds(actualRootBounds);
+    ASSERT_EQ(expectedRootBounds, actualRootBounds);
+
+    WebRect anchor, focus;
+    webView->selectionBounds(anchor, focus);
+    WebCore::IntRect expectedIntRect = expectedRootBounds;
+    ASSERT_TRUE(expectedIntRect.contains(anchor));
+    // The "overflow" tests have the focus boundary outside of the element box.
+    ASSERT_EQ(url.find("overflow") == std::string::npos, expectedIntRect.contains(focus));
+}
+
+TEST_F(WebViewTest, GetSelectionRootBounds)
+{
+    // Register all the pages we will be using.
+    registerMockedHttpURLLoad("select_range_basic.html");
+    registerMockedHttpURLLoad("select_range_div_editable.html");
+    registerMockedHttpURLLoad("select_range_scroll.html");
+    registerMockedHttpURLLoad("select_range_span_editable.html");
+    registerMockedHttpURLLoad("select_range_input.html");
+    registerMockedHttpURLLoad("select_range_input_overflow.html");
+    registerMockedHttpURLLoad("select_range_textarea.html");
+    registerMockedHttpURLLoad("select_range_textarea_overflow.html");
+    registerMockedHttpURLLoad("select_range_iframe.html");
+    registerMockedHttpURLLoad("select_range_iframe_div_editable.html");
+    registerMockedHttpURLLoad("select_range_iframe_scroll.html");
+    registerMockedHttpURLLoad("select_range_iframe_span_editable.html");
+    registerMockedHttpURLLoad("select_range_iframe_input.html");
+    registerMockedHttpURLLoad("select_range_iframe_input_overflow.html");
+    registerMockedHttpURLLoad("select_range_iframe_textarea.html");
+    registerMockedHttpURLLoad("select_range_iframe_textarea_overflow.html");
+
+    // Test with simple pages.
+    testSelectionRootBounds("select_range_basic.html", 1.0f);
+    testSelectionRootBounds("select_range_div_editable.html", 1.0f);
+    testSelectionRootBounds("select_range_scroll.html", 1.0f);
+    testSelectionRootBounds("select_range_span_editable.html", 1.0f);
+    testSelectionRootBounds("select_range_input.html", 1.0f);
+    testSelectionRootBounds("select_range_input_overflow.html", 1.0f);
+    testSelectionRootBounds("select_range_textarea.html", 1.0f);
+    testSelectionRootBounds("select_range_textarea_overflow.html", 1.0f);
+
+    // Test with the same pages as above in iframes.
+    testSelectionRootBounds("select_range_iframe.html", 1.0f);
+    testSelectionRootBounds("select_range_iframe_div_editable.html", 1.0f);
+    testSelectionRootBounds("select_range_iframe_scroll.html", 1.0f);
+    testSelectionRootBounds("select_range_iframe_span_editable.html", 1.0f);
+    testSelectionRootBounds("select_range_iframe_input.html", 1.0f);
+    testSelectionRootBounds("select_range_iframe_input_overflow.html", 1.0f);
+    testSelectionRootBounds("select_range_iframe_textarea.html", 1.0f);
+    testSelectionRootBounds("select_range_iframe_textarea_overflow.html", 1.0f);
+
+    // Basic page with scale factor.
+    testSelectionRootBounds("select_range_basic.html", 0.0f);
+    testSelectionRootBounds("select_range_basic.html", 0.1f);
+    testSelectionRootBounds("select_range_basic.html", 1.5f);
+    testSelectionRootBounds("select_range_basic.html", 2.0f);
+}
+
+TEST_F(WebViewTest, GetSelectionRootBoundsBrokenHeight)
+{
+    WebSize contentSize = WebSize(640, 480);
+
+    registerMockedHttpURLLoad("select_range_basic_broken_height.html");
+
+    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "select_range_basic_broken_height.html", true);
+    webView->resize(contentSize);
+    webView->setPageScaleFactor(1.0f, WebPoint(0, 0));
+    webView->layout();
+    runPendingTasks();
+
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
+    EXPECT_TRUE(frame->frame()->document()->isHTMLDocument());
+
+    WebRect expectedRootBounds = WebRect(0, 0, contentSize.width, contentSize.height);
+    WebRect actualRootBounds;
+    webView->getSelectionRootBounds(actualRootBounds);
+    ASSERT_EQ(expectedRootBounds, actualRootBounds);
+}
+
+class NonUserInputTextUpdateWebViewClient : public FrameTestHelpers::TestWebViewClient {
+public:
+    NonUserInputTextUpdateWebViewClient() : m_textIsUpdated(false) { }
+
+    // WebWidgetClient methods
+    virtual void didUpdateTextOfFocusedElementByNonUserInput() OVERRIDE
+    {
+        m_textIsUpdated = true;
+    }
+
+    void reset()
+    {
+        m_textIsUpdated = false;
+    }
+
+    bool textIsUpdated() const
+    {
+        return m_textIsUpdated;
+    }
+
+private:
+    int m_textIsUpdated;
+};
+
+// This test verifies that WebWidgetClient::didUpdateTextOfFocusedElementByNonUserInput is
+// called iff value of a focused element is modified via script.
+TEST_F(WebViewTest, NonUserInputTextUpdate)
+{
+    NonUserInputTextUpdateWebViewClient client;
+    std::string url = m_baseURL + "non_user_input_text_update.html";
+    URLTestHelpers::registerMockedURLLoad(toKURL(url), "non_user_input_text_update.html");
+    WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(url, true, 0, &client);
+    webViewImpl->setInitialFocus(false);
+
+    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewImpl->mainFrame());
+    WebCore::HTMLDocument* document = WebCore::toHTMLDocument(frame->frame()->document());
+
+    // (A) <input>
+    // (A.1) Focused and value is changed by script.
+    client.reset();
+    EXPECT_FALSE(client.textIsUpdated());
+
+    WebCore::HTMLInputElement* inputElement = toHTMLInputElement(document->getElementById("input"));
+    document->setFocusedElement(inputElement);
+    webViewImpl->setFocus(true);
+    EXPECT_EQ(document->focusedElement(), static_cast<WebCore::Element*>(inputElement));
+
+    // Emulate value change from script.
+    inputElement->setValue("testA");
+    EXPECT_TRUE(client.textIsUpdated());
+    WebTextInputInfo info = webViewImpl->textInputInfo();
+    EXPECT_EQ("testA", std::string(info.value.utf8().data()));
+
+    // (A.2) Focused and user input modifies value.
+    client.reset();
+    EXPECT_FALSE(client.textIsUpdated());
+
+    WebVector<WebCompositionUnderline> emptyUnderlines;
+    webViewImpl->setComposition(WebString::fromUTF8("2"), emptyUnderlines, 1, 1);
+    webViewImpl->confirmComposition(WebWidget::KeepSelection);
+    EXPECT_FALSE(client.textIsUpdated());
+    info = webViewImpl->textInputInfo();
+    EXPECT_EQ("testA2", std::string(info.value.utf8().data()));
+
+    // (A.3) Unfocused and value is changed by script.
+    client.reset();
+    EXPECT_FALSE(client.textIsUpdated());
+    document->setFocusedElement(nullptr);
+    webViewImpl->setFocus(false);
+    EXPECT_NE(document->focusedElement(), static_cast<WebCore::Element*>(inputElement));
+    inputElement->setValue("testA3");
+    EXPECT_FALSE(client.textIsUpdated());
+
+    // (B) <textarea>
+    // (B.1) Focused and value is changed by script.
+    client.reset();
+    EXPECT_FALSE(client.textIsUpdated());
+    WebCore::HTMLTextAreaElement* textAreaElement = toHTMLTextAreaElement(document->getElementById("textarea"));
+    document->setFocusedElement(textAreaElement);
+    webViewImpl->setFocus(true);
+    EXPECT_EQ(document->focusedElement(), static_cast<WebCore::Element*>(textAreaElement));
+    textAreaElement->setValue("testB");
+    EXPECT_TRUE(client.textIsUpdated());
+    info = webViewImpl->textInputInfo();
+    EXPECT_EQ("testB", std::string(info.value.utf8().data()));
+
+    // (B.2) Focused and user input modifies value.
+    client.reset();
+    EXPECT_FALSE(client.textIsUpdated());
+    webViewImpl->setComposition(WebString::fromUTF8("2"), emptyUnderlines, 1, 1);
+    webViewImpl->confirmComposition(WebWidget::KeepSelection);
+    info = webViewImpl->textInputInfo();
+    EXPECT_EQ("testB2", std::string(info.value.utf8().data()));
+
+    // (B.3) Unfocused and value is changed by script.
+    client.reset();
+    EXPECT_FALSE(client.textIsUpdated());
+    document->setFocusedElement(nullptr);
+    webViewImpl->setFocus(false);
+    EXPECT_NE(document->focusedElement(), static_cast<WebCore::Element*>(textAreaElement));
+    inputElement->setValue("testB3");
+    EXPECT_FALSE(client.textIsUpdated());
+
+    // Free the webView before freeing the NonUserInputTextUpdateWebViewClient.
+    m_webViewHelper.reset();
+}
+
+// Check that the WebAutofillClient is correctly notified about first user
+// gestures after load, following various input events.
+TEST_F(WebViewTest, FirstUserGestureObservedKeyEvent)
+{
+    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("form.html"));
+    MockAutofillClient client;
+    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "form.html", true);
+    webView->setAutofillClient(&client);
+    webView->setInitialFocus(false);
+
+    EXPECT_EQ(0, client.getUserGestureNotificationsCount());
+
+    WebKeyboardEvent keyEvent;
+    keyEvent.windowsKeyCode = WebCore::VKEY_SPACE;
+    keyEvent.type = WebInputEvent::RawKeyDown;
+    keyEvent.setKeyIdentifierFromWindowsKeyCode();
+    webView->handleInputEvent(keyEvent);
+    keyEvent.type = WebInputEvent::KeyUp;
+    webView->handleInputEvent(keyEvent);
+
+    EXPECT_EQ(1, client.getUserGestureNotificationsCount());
+    webView->setAutofillClient(0);
+}
+
+TEST_F(WebViewTest, FirstUserGestureObservedMouseEvent)
+{
+    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("form.html"));
+    MockAutofillClient client;
+    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "form.html", true);
+    webView->setAutofillClient(&client);
+    webView->setInitialFocus(false);
+
+    EXPECT_EQ(0, client.getUserGestureNotificationsCount());
+
+    WebMouseEvent mouseEvent;
+    mouseEvent.button = WebMouseEvent::ButtonLeft;
+    mouseEvent.x = 1;
+    mouseEvent.y = 1;
+    mouseEvent.clickCount = 1;
+    mouseEvent.type = WebInputEvent::MouseDown;
+    webView->handleInputEvent(mouseEvent);
+    mouseEvent.type = WebInputEvent::MouseUp;
+    webView->handleInputEvent(mouseEvent);
+
+    EXPECT_EQ(1, client.getUserGestureNotificationsCount());
+    webView->setAutofillClient(0);
+}
+
+TEST_F(WebViewTest, FirstUserGestureObservedGestureTap)
+{
+    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("longpress_selection.html"));
+    MockAutofillClient client;
+    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "longpress_selection.html", true);
+    webView->setAutofillClient(&client);
+    webView->setInitialFocus(false);
+
+    EXPECT_EQ(0, client.getUserGestureNotificationsCount());
+
+    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, WebString::fromUTF8("target")));
+
+    EXPECT_EQ(1, client.getUserGestureNotificationsCount());
+    webView->setAutofillClient(0);
+}
+
 } // namespace