1/*
2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "public/web/WebView.h"
33
34#include "core/dom/Document.h"
35#include "core/dom/Element.h"
36#include "core/editing/FrameSelection.h"
37#include "core/frame/EventHandlerRegistry.h"
38#include "core/frame/FrameView.h"
39#include "core/frame/LocalFrame.h"
40#include "core/frame/Settings.h"
41#include "core/html/HTMLDocument.h"
42#include "core/html/HTMLIFrameElement.h"
43#include "core/html/HTMLInputElement.h"
44#include "core/html/HTMLTextAreaElement.h"
45#include "core/loader/FrameLoadRequest.h"
46#include "core/page/Chrome.h"
47#include "core/page/Page.h"
48#include "core/rendering/RenderLayer.h"
49#include "core/rendering/RenderView.h"
50#include "core/testing/URLTestHelpers.h"
51#include "platform/KeyboardCodes.h"
52#include "platform/geometry/IntSize.h"
53#include "platform/graphics/Color.h"
54#include "public/platform/Platform.h"
55#include "public/platform/WebClipboard.h"
56#include "public/platform/WebDragData.h"
57#include "public/platform/WebSize.h"
58#include "public/platform/WebThread.h"
59#include "public/platform/WebUnitTestSupport.h"
60#include "public/web/WebAutofillClient.h"
61#include "public/web/WebContentDetectionResult.h"
62#include "public/web/WebDateTimeChooserCompletion.h"
63#include "public/web/WebDocument.h"
64#include "public/web/WebDragOperation.h"
65#include "public/web/WebElement.h"
66#include "public/web/WebFrame.h"
67#include "public/web/WebFrameClient.h"
68#include "public/web/WebHitTestResult.h"
69#include "public/web/WebInputEvent.h"
70#include "public/web/WebScriptSource.h"
71#include "public/web/WebSettings.h"
72#include "public/web/WebViewClient.h"
73#include "public/web/WebWidget.h"
74#include "public/web/WebWidgetClient.h"
75#include "third_party/skia/include/core/SkBitmap.h"
76#include "third_party/skia/include/core/SkBitmapDevice.h"
77#include "third_party/skia/include/core/SkCanvas.h"
78#include "web/WebLocalFrameImpl.h"
79#include "web/WebSettingsImpl.h"
80#include "web/WebViewImpl.h"
81#include "web/tests/FrameTestHelpers.h"
82#include <gtest/gtest.h>
83
84using namespace blink;
85using blink::FrameTestHelpers::loadFrame;
86using blink::FrameTestHelpers::runPendingTasks;
87using blink::URLTestHelpers::toKURL;
88
89namespace {
90
91enum HorizontalScrollbarState {
92    NoHorizontalScrollbar,
93    VisibleHorizontalScrollbar,
94};
95
96enum VerticalScrollbarState {
97    NoVerticalScrollbar,
98    VisibleVerticalScrollbar,
99};
100
101class TestData {
102public:
103    void setWebView(WebView* webView) { m_webView = toWebViewImpl(webView); }
104    void setSize(const WebSize& newSize) { m_size = newSize; }
105    HorizontalScrollbarState horizontalScrollbarState() const
106    {
107        return m_webView->hasHorizontalScrollbar() ? VisibleHorizontalScrollbar: NoHorizontalScrollbar;
108    }
109    VerticalScrollbarState verticalScrollbarState() const
110    {
111        return m_webView->hasVerticalScrollbar() ? VisibleVerticalScrollbar : NoVerticalScrollbar;
112    }
113    int width() const { return m_size.width; }
114    int height() const { return m_size.height; }
115
116private:
117    WebSize m_size;
118    WebViewImpl* m_webView;
119};
120
121class AutoResizeWebViewClient : public FrameTestHelpers::TestWebViewClient {
122public:
123    // WebViewClient methods
124    virtual void didAutoResize(const WebSize& newSize) { m_testData.setSize(newSize); }
125
126    // Local methods
127    TestData& testData() { return m_testData; }
128
129private:
130    TestData m_testData;
131};
132
133class SaveImageFromDataURLWebViewClient : public FrameTestHelpers::TestWebViewClient {
134public:
135    // WebViewClient methods
136    virtual void saveImageFromDataURL(const WebString& dataURL) { m_dataURL = dataURL; }
137
138    // Local methods
139    const WebString& result() const { return m_dataURL; }
140    void reset() { m_dataURL = WebString(); }
141
142private:
143    WebString m_dataURL;
144};
145
146class TapHandlingWebViewClient : public FrameTestHelpers::TestWebViewClient {
147public:
148    // WebViewClient methods
149    virtual void didHandleGestureEvent(const WebGestureEvent& event, bool eventCancelled)
150    {
151        if (event.type == WebInputEvent::GestureTap) {
152            m_tapX = event.x;
153            m_tapY = event.y;
154        } else if (event.type == WebInputEvent::GestureLongPress) {
155            m_longpressX = event.x;
156            m_longpressY = event.y;
157        }
158    }
159
160    // Local methods
161    void reset()
162    {
163        m_tapX = -1;
164        m_tapY = -1;
165        m_longpressX = -1;
166        m_longpressY = -1;
167    }
168    int tapX() { return m_tapX; }
169    int tapY() { return m_tapY; }
170    int longpressX() { return m_longpressX; }
171    int longpressY() { return m_longpressY; }
172
173private:
174    int m_tapX;
175    int m_tapY;
176    int m_longpressX;
177    int m_longpressY;
178};
179
180class DateTimeChooserWebViewClient : public FrameTestHelpers::TestWebViewClient {
181public:
182    WebDateTimeChooserCompletion* chooserCompletion()
183    {
184        return m_chooserCompletion;
185    }
186
187    void clearChooserCompletion()
188    {
189        m_chooserCompletion = 0;
190    }
191
192    // WebViewClient methods
193    virtual bool openDateTimeChooser(const WebDateTimeChooserParams&, WebDateTimeChooserCompletion* chooser_completion) OVERRIDE
194    {
195        m_chooserCompletion = chooser_completion;
196        return true;
197    }
198
199private:
200    WebDateTimeChooserCompletion* m_chooserCompletion;
201
202};
203
204class WebViewTest : public testing::Test {
205public:
206    WebViewTest()
207        : m_baseURL("http://www.test.com/")
208    {
209    }
210
211    virtual void TearDown()
212    {
213        Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
214    }
215
216protected:
217    void registerMockedHttpURLLoad(const std::string& fileName)
218    {
219        URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str()));
220    }
221
222    void testAutoResize(const WebSize& minAutoResize, const WebSize& maxAutoResize,
223                        const std::string& pageWidth, const std::string& pageHeight,
224                        int expectedWidth, int expectedHeight,
225                        HorizontalScrollbarState expectedHorizontalState, VerticalScrollbarState expectedVerticalState);
226
227    void testTextInputType(WebTextInputType expectedType, const std::string& htmlFile);
228    void testInputMode(const WebString& expectedInputMode, const std::string& htmlFile);
229    void testSelectionRootBounds(const char* htmlFile, float pageScaleFactor);
230
231    std::string m_baseURL;
232    FrameTestHelpers::WebViewHelper m_webViewHelper;
233};
234
235TEST_F(WebViewTest, SaveImageAt)
236{
237    SaveImageFromDataURLWebViewClient client;
238
239    std::string url = m_baseURL + "image-with-data-url.html";
240    URLTestHelpers::registerMockedURLLoad(toKURL(url), "image-with-data-url.html");
241    WebView* webView = m_webViewHelper.initializeAndLoad(url, true, 0, &client);
242    webView->resize(WebSize(400, 400));
243
244    client.reset();
245    webView->saveImageAt(WebPoint(1, 1));
246    EXPECT_EQ(WebString::fromUTF8("data:image/gif;base64"
247        ",R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="), client.result());
248
249    client.reset();
250    webView->saveImageAt(WebPoint(1, 2));
251    EXPECT_EQ(WebString(), client.result());
252
253    m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client.
254};
255
256TEST_F(WebViewTest, CopyImageAt)
257{
258    std::string url = m_baseURL + "canvas-copy-image.html";
259    URLTestHelpers::registerMockedURLLoad(toKURL(url), "canvas-copy-image.html");
260    WebView* webView = m_webViewHelper.initializeAndLoad(url, true, 0);
261    webView->resize(WebSize(400, 400));
262    webView->copyImageAt(WebPoint(50, 50));
263
264    WebData data = Platform::current()->clipboard()->readImage(WebClipboard::Buffer());
265    WebImage image = WebImage::fromData(data, WebSize());
266
267    SkAutoLockPixels autoLock(image.getSkBitmap());
268    EXPECT_EQ(SkColorSetARGB(255, 255, 0, 0), image.getSkBitmap().getColor(0, 0));
269};
270
271TEST_F(WebViewTest, SetBaseBackgroundColor)
272{
273    const WebColor kWhite    = 0xFFFFFFFF;
274    const WebColor kBlue     = 0xFF0000FF;
275    const WebColor kDarkCyan = 0xFF227788;
276    const WebColor kTranslucentPutty = 0x80BFB196;
277    const WebColor kTransparent = 0x00000000;
278
279    WebViewImpl* webView = m_webViewHelper.initialize();
280    EXPECT_EQ(kWhite, webView->backgroundColor());
281
282    webView->setBaseBackgroundColor(kBlue);
283    EXPECT_EQ(kBlue, webView->backgroundColor());
284
285    WebURL baseURL = URLTestHelpers::toKURL("http://example.com/");
286    FrameTestHelpers::loadHTMLString(webView->mainFrame(), "<html><head><style>body {background-color:#227788}</style></head></html>", baseURL);
287    EXPECT_EQ(kDarkCyan, webView->backgroundColor());
288
289    FrameTestHelpers::loadHTMLString(webView->mainFrame(), "<html><head><style>body {background-color:rgba(255,0,0,0.5)}</style></head></html>", baseURL);
290    // Expected: red (50% alpha) blended atop base of kBlue.
291    EXPECT_EQ(0xFF7F0080, webView->backgroundColor());
292
293    webView->setBaseBackgroundColor(kTranslucentPutty);
294    // Expected: red (50% alpha) blended atop kTranslucentPutty. Note the alpha.
295    EXPECT_EQ(0xBFE93B32, webView->backgroundColor());
296
297    webView->setBaseBackgroundColor(kTransparent);
298    FrameTestHelpers::loadHTMLString(webView->mainFrame(), "<html><head><style>body {background-color:transparent}</style></head></html>", baseURL);
299    // Expected: transparent on top of kTransparent will still be transparent.
300    EXPECT_EQ(kTransparent, webView->backgroundColor());
301
302    LocalFrame* frame = webView->mainFrameImpl()->frame();
303
304    // Creating a new frame view with the background color having 0 alpha.
305    frame->createView(IntSize(1024, 768), Color::transparent, true);
306    EXPECT_EQ(kTransparent, frame->view()->baseBackgroundColor());
307
308    Color kTransparentRed(100, 0, 0, 0);
309    frame->createView(IntSize(1024, 768), kTransparentRed, true);
310    EXPECT_EQ(kTransparentRed, frame->view()->baseBackgroundColor());
311}
312
313TEST_F(WebViewTest, SetBaseBackgroundColorBeforeMainFrame)
314{
315    const WebColor kBlue = 0xFF0000FF;
316    FrameTestHelpers::TestWebViewClient webViewClient;
317    WebView* webView = WebViewImpl::create(&webViewClient);
318    EXPECT_NE(kBlue, webView->backgroundColor());
319    // webView does not have a frame yet, but we should still be able to set the background color.
320    webView->setBaseBackgroundColor(kBlue);
321    EXPECT_EQ(kBlue, webView->backgroundColor());
322    WebLocalFrameImpl* frame = WebLocalFrameImpl::create(0);
323    webView->setMainFrame(frame);
324    webView->close();
325    frame->close();
326}
327
328TEST_F(WebViewTest, SetBaseBackgroundColorAndBlendWithExistingContent)
329{
330    const WebColor kAlphaRed = 0x80FF0000;
331    const WebColor kAlphaGreen = 0x8000FF00;
332    const int kWidth = 100;
333    const int kHeight = 100;
334
335    WebView* webView = m_webViewHelper.initialize();
336
337    // Set WebView background to green with alpha.
338    webView->setBaseBackgroundColor(kAlphaGreen);
339    webView->settings()->setShouldClearDocumentBackground(false);
340    webView->resize(WebSize(kWidth, kHeight));
341    webView->layout();
342
343    // Set canvas background to red with alpha.
344    SkBitmap bitmap;
345    bitmap.allocN32Pixels(kWidth, kHeight);
346    SkCanvas canvas(bitmap);
347    canvas.clear(kAlphaRed);
348
349    GraphicsContext context(&canvas);
350
351    // Paint the root of the main frame in the way that CompositedLayerMapping would.
352    FrameView* view = m_webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
353    RenderLayer* rootLayer = view->renderView()->layer();
354    IntRect paintRect(0, 0, kWidth, kHeight);
355    LayerPaintingInfo paintingInfo(rootLayer, paintRect, PaintBehaviorNormal, LayoutSize());
356    rootLayer->paintLayerContents(&context, paintingInfo, PaintLayerPaintingCompositingAllPhases);
357
358    // The result should be a blend of red and green.
359    SkColor color = bitmap.getColor(kWidth / 2, kHeight / 2);
360    EXPECT_TRUE(redChannel(color));
361    EXPECT_TRUE(greenChannel(color));
362}
363
364TEST_F(WebViewTest, FocusIsInactive)
365{
366    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), "visible_iframe.html");
367    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "visible_iframe.html");
368
369    webView->setFocus(true);
370    webView->setIsActive(true);
371    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
372    EXPECT_TRUE(frame->frame()->document()->isHTMLDocument());
373
374    HTMLDocument* document = toHTMLDocument(frame->frame()->document());
375    EXPECT_TRUE(document->hasFocus());
376    webView->setFocus(false);
377    webView->setIsActive(false);
378    EXPECT_FALSE(document->hasFocus());
379    webView->setFocus(true);
380    webView->setIsActive(true);
381    EXPECT_TRUE(document->hasFocus());
382    webView->setFocus(true);
383    webView->setIsActive(false);
384    EXPECT_FALSE(document->hasFocus());
385    webView->setFocus(false);
386    webView->setIsActive(true);
387    EXPECT_FALSE(document->hasFocus());
388}
389
390TEST_F(WebViewTest, ActiveState)
391{
392    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), "visible_iframe.html");
393    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "visible_iframe.html");
394
395    ASSERT_TRUE(webView);
396
397    webView->setIsActive(true);
398    EXPECT_TRUE(webView->isActive());
399
400    webView->setIsActive(false);
401    EXPECT_FALSE(webView->isActive());
402
403    webView->setIsActive(true);
404    EXPECT_TRUE(webView->isActive());
405}
406
407TEST_F(WebViewTest, HitTestResultAtWithPageScale)
408{
409    std::string url = m_baseURL + "specify_size.html?" + "50px" + ":" + "50px";
410    URLTestHelpers::registerMockedURLLoad(toKURL(url), "specify_size.html");
411    WebView* webView = m_webViewHelper.initializeAndLoad(url, true, 0);
412    webView->resize(WebSize(100, 100));
413    WebPoint hitPoint(75, 75);
414
415    // Image is at top left quandrant, so should not hit it.
416    WebHitTestResult negativeResult = webView->hitTestResultAt(hitPoint);
417    ASSERT_EQ(WebNode::ElementNode, negativeResult.node().nodeType());
418    EXPECT_FALSE(negativeResult.node().to<WebElement>().hasHTMLTagName("img"));
419    negativeResult.reset();
420
421    // Scale page up 2x so image should occupy the whole viewport.
422    webView->setPageScaleFactor(2.0f);
423    WebHitTestResult positiveResult = webView->hitTestResultAt(hitPoint);
424    ASSERT_EQ(WebNode::ElementNode, positiveResult.node().nodeType());
425    EXPECT_TRUE(positiveResult.node().to<WebElement>().hasHTMLTagName("img"));
426    positiveResult.reset();
427}
428
429void WebViewTest::testAutoResize(const WebSize& minAutoResize, const WebSize& maxAutoResize,
430                                 const std::string& pageWidth, const std::string& pageHeight,
431                                 int expectedWidth, int expectedHeight,
432                                 HorizontalScrollbarState expectedHorizontalState, VerticalScrollbarState expectedVerticalState)
433{
434    AutoResizeWebViewClient client;
435    std::string url = m_baseURL + "specify_size.html?" + pageWidth + ":" + pageHeight;
436    URLTestHelpers::registerMockedURLLoad(toKURL(url), "specify_size.html");
437    WebView* webView = m_webViewHelper.initializeAndLoad(url, true, 0, &client);
438    client.testData().setWebView(webView);
439
440    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
441    FrameView* frameView = frame->frame()->view();
442    frameView->layout();
443    EXPECT_FALSE(frameView->layoutPending());
444    EXPECT_FALSE(frameView->needsLayout());
445
446    webView->enableAutoResizeMode(minAutoResize, maxAutoResize);
447    EXPECT_TRUE(frameView->layoutPending());
448    EXPECT_TRUE(frameView->needsLayout());
449    frameView->layout();
450
451    EXPECT_TRUE(frame->frame()->document()->isHTMLDocument());
452
453    EXPECT_EQ(expectedWidth, client.testData().width());
454    EXPECT_EQ(expectedHeight, client.testData().height());
455    EXPECT_EQ(expectedHorizontalState, client.testData().horizontalScrollbarState());
456    EXPECT_EQ(expectedVerticalState, client.testData().verticalScrollbarState());
457
458    m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client.
459}
460
461TEST_F(WebViewTest, AutoResizeMinimumSize)
462{
463    WebSize minAutoResize(91, 56);
464    WebSize maxAutoResize(403, 302);
465    std::string pageWidth = "91px";
466    std::string pageHeight = "56px";
467    int expectedWidth = 91;
468    int expectedHeight = 56;
469    testAutoResize(minAutoResize, maxAutoResize, pageWidth, pageHeight,
470                   expectedWidth, expectedHeight, NoHorizontalScrollbar, NoVerticalScrollbar);
471}
472
473TEST_F(WebViewTest, AutoResizeHeightOverflowAndFixedWidth)
474{
475    WebSize minAutoResize(90, 95);
476    WebSize maxAutoResize(90, 100);
477    std::string pageWidth = "60px";
478    std::string pageHeight = "200px";
479    int expectedWidth = 90;
480    int expectedHeight = 100;
481    testAutoResize(minAutoResize, maxAutoResize, pageWidth, pageHeight,
482                   expectedWidth, expectedHeight, NoHorizontalScrollbar, VisibleVerticalScrollbar);
483}
484
485TEST_F(WebViewTest, AutoResizeFixedHeightAndWidthOverflow)
486{
487    WebSize minAutoResize(90, 100);
488    WebSize maxAutoResize(200, 100);
489    std::string pageWidth = "300px";
490    std::string pageHeight = "80px";
491    int expectedWidth = 200;
492    int expectedHeight = 100;
493    testAutoResize(minAutoResize, maxAutoResize, pageWidth, pageHeight,
494                   expectedWidth, expectedHeight, VisibleHorizontalScrollbar, NoVerticalScrollbar);
495}
496
497// Next three tests disabled for https://bugs.webkit.org/show_bug.cgi?id=92318 .
498// It seems we can run three AutoResize tests, then the next one breaks.
499TEST_F(WebViewTest, AutoResizeInBetweenSizes)
500{
501    WebSize minAutoResize(90, 95);
502    WebSize maxAutoResize(200, 300);
503    std::string pageWidth = "100px";
504    std::string pageHeight = "200px";
505    int expectedWidth = 100;
506    int expectedHeight = 200;
507    testAutoResize(minAutoResize, maxAutoResize, pageWidth, pageHeight,
508                   expectedWidth, expectedHeight, NoHorizontalScrollbar, NoVerticalScrollbar);
509}
510
511TEST_F(WebViewTest, AutoResizeOverflowSizes)
512{
513    WebSize minAutoResize(90, 95);
514    WebSize maxAutoResize(200, 300);
515    std::string pageWidth = "300px";
516    std::string pageHeight = "400px";
517    int expectedWidth = 200;
518    int expectedHeight = 300;
519    testAutoResize(minAutoResize, maxAutoResize, pageWidth, pageHeight,
520                   expectedWidth, expectedHeight, VisibleHorizontalScrollbar, VisibleVerticalScrollbar);
521}
522
523TEST_F(WebViewTest, AutoResizeMaxSize)
524{
525    WebSize minAutoResize(90, 95);
526    WebSize maxAutoResize(200, 300);
527    std::string pageWidth = "200px";
528    std::string pageHeight = "300px";
529    int expectedWidth = 200;
530    int expectedHeight = 300;
531    testAutoResize(minAutoResize, maxAutoResize, pageWidth, pageHeight,
532                   expectedWidth, expectedHeight, NoHorizontalScrollbar, NoVerticalScrollbar);
533}
534
535void WebViewTest::testTextInputType(WebTextInputType expectedType, const std::string& htmlFile)
536{
537    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(htmlFile.c_str()));
538    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + htmlFile);
539    webView->setInitialFocus(false);
540    EXPECT_EQ(expectedType, webView->textInputInfo().type);
541}
542
543TEST_F(WebViewTest, TextInputType)
544{
545    testTextInputType(WebTextInputTypeText, "input_field_default.html");
546    testTextInputType(WebTextInputTypePassword, "input_field_password.html");
547    testTextInputType(WebTextInputTypeEmail, "input_field_email.html");
548    testTextInputType(WebTextInputTypeSearch, "input_field_search.html");
549    testTextInputType(WebTextInputTypeNumber, "input_field_number.html");
550    testTextInputType(WebTextInputTypeTelephone, "input_field_tel.html");
551    testTextInputType(WebTextInputTypeURL, "input_field_url.html");
552}
553
554void WebViewTest::testInputMode(const WebString& expectedInputMode, const std::string& htmlFile)
555{
556    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(htmlFile.c_str()));
557    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + htmlFile);
558    webView->setInitialFocus(false);
559    EXPECT_EQ(expectedInputMode, webView->textInputInfo().inputMode);
560}
561
562TEST_F(WebViewTest, InputMode)
563{
564    testInputMode(WebString(), "input_mode_default.html");
565    testInputMode(WebString("unknown"), "input_mode_default_unknown.html");
566    testInputMode(WebString("verbatim"), "input_mode_default_verbatim.html");
567    testInputMode(WebString("verbatim"), "input_mode_type_text_verbatim.html");
568    testInputMode(WebString("verbatim"), "input_mode_type_search_verbatim.html");
569    testInputMode(WebString(), "input_mode_type_url_verbatim.html");
570    testInputMode(WebString("verbatim"), "input_mode_textarea_verbatim.html");
571}
572
573TEST_F(WebViewTest, TextInputInfoWithReplacedElements)
574{
575    std::string url = m_baseURL + "div_with_image.html";
576    URLTestHelpers::registerMockedURLLoad(toKURL(url), "div_with_image.html");
577    WebView* webView = m_webViewHelper.initializeAndLoad(url);
578    webView->setInitialFocus(false);
579    WebTextInputInfo info = webView->textInputInfo();
580
581    EXPECT_EQ("foo\xef\xbf\xbc", info.value.utf8());
582}
583
584TEST_F(WebViewTest, SetEditableSelectionOffsetsAndTextInputInfo)
585{
586    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html"));
587    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html");
588    webView->setInitialFocus(false);
589    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
590    frame->setEditableSelectionOffsets(5, 13);
591    EXPECT_EQ("56789abc", frame->selectionAsText());
592    WebTextInputInfo info = webView->textInputInfo();
593    EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", info.value);
594    EXPECT_EQ(5, info.selectionStart);
595    EXPECT_EQ(13, info.selectionEnd);
596    EXPECT_EQ(-1, info.compositionStart);
597    EXPECT_EQ(-1, info.compositionEnd);
598
599    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("content_editable_populated.html"));
600    webView = m_webViewHelper.initializeAndLoad(m_baseURL + "content_editable_populated.html");
601    webView->setInitialFocus(false);
602    frame = toWebLocalFrameImpl(webView->mainFrame());
603    frame->setEditableSelectionOffsets(8, 19);
604    EXPECT_EQ("89abcdefghi", frame->selectionAsText());
605    info = webView->textInputInfo();
606    EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", info.value);
607    EXPECT_EQ(8, info.selectionStart);
608    EXPECT_EQ(19, info.selectionEnd);
609    EXPECT_EQ(-1, info.compositionStart);
610    EXPECT_EQ(-1, info.compositionEnd);
611}
612
613TEST_F(WebViewTest, ConfirmCompositionCursorPositionChange)
614{
615    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html"));
616    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html");
617    webView->setInitialFocus(false);
618
619    // Set up a composition that needs to be committed.
620    std::string compositionText("hello");
621
622    WebVector<WebCompositionUnderline> emptyUnderlines;
623    webView->setComposition(WebString::fromUTF8(compositionText.c_str()), emptyUnderlines, 3, 3);
624
625    WebTextInputInfo info = webView->textInputInfo();
626    EXPECT_EQ("hello", std::string(info.value.utf8().data()));
627    EXPECT_EQ(3, info.selectionStart);
628    EXPECT_EQ(3, info.selectionEnd);
629    EXPECT_EQ(0, info.compositionStart);
630    EXPECT_EQ(5, info.compositionEnd);
631
632    webView->confirmComposition(WebWidget::KeepSelection);
633    info = webView->textInputInfo();
634    EXPECT_EQ(3, info.selectionStart);
635    EXPECT_EQ(3, info.selectionEnd);
636    EXPECT_EQ(-1, info.compositionStart);
637    EXPECT_EQ(-1, info.compositionEnd);
638
639    webView->setComposition(WebString::fromUTF8(compositionText.c_str()), emptyUnderlines, 3, 3);
640    info = webView->textInputInfo();
641    EXPECT_EQ("helhellolo", std::string(info.value.utf8().data()));
642    EXPECT_EQ(6, info.selectionStart);
643    EXPECT_EQ(6, info.selectionEnd);
644    EXPECT_EQ(3, info.compositionStart);
645    EXPECT_EQ(8, info.compositionEnd);
646
647    webView->confirmComposition(WebWidget::DoNotKeepSelection);
648    info = webView->textInputInfo();
649    EXPECT_EQ(8, info.selectionStart);
650    EXPECT_EQ(8, info.selectionEnd);
651    EXPECT_EQ(-1, info.compositionStart);
652    EXPECT_EQ(-1, info.compositionEnd);
653}
654
655TEST_F(WebViewTest, InsertNewLinePlacementAfterConfirmComposition)
656{
657    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("text_area_populated.html"));
658    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "text_area_populated.html");
659    webView->setInitialFocus(false);
660
661    WebVector<WebCompositionUnderline> emptyUnderlines;
662
663    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
664    frame->setEditableSelectionOffsets(4, 4);
665    frame->setCompositionFromExistingText(8, 12, emptyUnderlines);
666
667    WebTextInputInfo info = webView->textInputInfo();
668    EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", std::string(info.value.utf8().data()));
669    EXPECT_EQ(4, info.selectionStart);
670    EXPECT_EQ(4, info.selectionEnd);
671    EXPECT_EQ(8, info.compositionStart);
672    EXPECT_EQ(12, info.compositionEnd);
673
674    webView->confirmComposition(WebWidget::KeepSelection);
675    info = webView->textInputInfo();
676    EXPECT_EQ(4, info.selectionStart);
677    EXPECT_EQ(4, info.selectionEnd);
678    EXPECT_EQ(-1, info.compositionStart);
679    EXPECT_EQ(-1, info.compositionEnd);
680
681    std::string compositionText("\n");
682    webView->confirmComposition(WebString::fromUTF8(compositionText.c_str()));
683    info = webView->textInputInfo();
684    EXPECT_EQ(5, info.selectionStart);
685    EXPECT_EQ(5, info.selectionEnd);
686    EXPECT_EQ(-1, info.compositionStart);
687    EXPECT_EQ(-1, info.compositionEnd);
688    EXPECT_EQ("0123\n456789abcdefghijklmnopqrstuvwxyz", std::string(info.value.utf8().data()));
689}
690
691TEST_F(WebViewTest, ExtendSelectionAndDelete)
692{
693    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html"));
694    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html");
695    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
696    webView->setInitialFocus(false);
697    frame->setEditableSelectionOffsets(10, 10);
698    frame->extendSelectionAndDelete(5, 8);
699    WebTextInputInfo info = webView->textInputInfo();
700    EXPECT_EQ("01234ijklmnopqrstuvwxyz", std::string(info.value.utf8().data()));
701    EXPECT_EQ(5, info.selectionStart);
702    EXPECT_EQ(5, info.selectionEnd);
703    frame->extendSelectionAndDelete(10, 0);
704    info = webView->textInputInfo();
705    EXPECT_EQ("ijklmnopqrstuvwxyz", std::string(info.value.utf8().data()));
706}
707
708TEST_F(WebViewTest, SetCompositionFromExistingText)
709{
710    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html"));
711    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html");
712    webView->setInitialFocus(false);
713    WebVector<WebCompositionUnderline> underlines(static_cast<size_t>(1));
714    underlines[0] = WebCompositionUnderline(0, 4, 0, false, 0);
715    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
716    frame->setEditableSelectionOffsets(4, 10);
717    frame->setCompositionFromExistingText(8, 12, underlines);
718    WebVector<WebCompositionUnderline> underlineResults = toWebViewImpl(webView)->compositionUnderlines();
719    EXPECT_EQ(8u, underlineResults[0].startOffset);
720    EXPECT_EQ(12u, underlineResults[0].endOffset);
721    WebTextInputInfo info = webView->textInputInfo();
722    EXPECT_EQ(4, info.selectionStart);
723    EXPECT_EQ(10, info.selectionEnd);
724    EXPECT_EQ(8, info.compositionStart);
725    EXPECT_EQ(12, info.compositionEnd);
726    WebVector<WebCompositionUnderline> emptyUnderlines;
727    frame->setCompositionFromExistingText(0, 0, emptyUnderlines);
728    info = webView->textInputInfo();
729    EXPECT_EQ(4, info.selectionStart);
730    EXPECT_EQ(10, info.selectionEnd);
731    EXPECT_EQ(-1, info.compositionStart);
732    EXPECT_EQ(-1, info.compositionEnd);
733}
734
735TEST_F(WebViewTest, SetCompositionFromExistingTextInTextArea)
736{
737    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("text_area_populated.html"));
738    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "text_area_populated.html");
739    webView->setInitialFocus(false);
740    WebVector<WebCompositionUnderline> underlines(static_cast<size_t>(1));
741    underlines[0] = WebCompositionUnderline(0, 4, 0, false, 0);
742    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
743    frame->setEditableSelectionOffsets(27, 27);
744    std::string newLineText("\n");
745    webView->confirmComposition(WebString::fromUTF8(newLineText.c_str()));
746    WebTextInputInfo info = webView->textInputInfo();
747    EXPECT_EQ("0123456789abcdefghijklmnopq\nrstuvwxyz", std::string(info.value.utf8().data()));
748
749    frame->setEditableSelectionOffsets(31, 31);
750    frame->setCompositionFromExistingText(30, 34, underlines);
751    WebVector<WebCompositionUnderline> underlineResults = toWebViewImpl(webView)->compositionUnderlines();
752    EXPECT_EQ(2u, underlineResults[0].startOffset);
753    EXPECT_EQ(6u, underlineResults[0].endOffset);
754    info = webView->textInputInfo();
755    EXPECT_EQ("0123456789abcdefghijklmnopq\nrstuvwxyz", std::string(info.value.utf8().data()));
756    EXPECT_EQ(31, info.selectionStart);
757    EXPECT_EQ(31, info.selectionEnd);
758    EXPECT_EQ(30, info.compositionStart);
759    EXPECT_EQ(34, info.compositionEnd);
760
761    std::string compositionText("yolo");
762    webView->confirmComposition(WebString::fromUTF8(compositionText.c_str()));
763    info = webView->textInputInfo();
764    EXPECT_EQ("0123456789abcdefghijklmnopq\nrsyoloxyz", std::string(info.value.utf8().data()));
765    EXPECT_EQ(34, info.selectionStart);
766    EXPECT_EQ(34, info.selectionEnd);
767    EXPECT_EQ(-1, info.compositionStart);
768    EXPECT_EQ(-1, info.compositionEnd);
769}
770
771TEST_F(WebViewTest, SetEditableSelectionOffsetsKeepsComposition)
772{
773    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html"));
774    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html");
775    webView->setInitialFocus(false);
776
777    std::string compositionTextFirst("hello ");
778    std::string compositionTextSecond("world");
779    WebVector<WebCompositionUnderline> emptyUnderlines;
780
781    webView->confirmComposition(WebString::fromUTF8(compositionTextFirst.c_str()));
782    webView->setComposition(WebString::fromUTF8(compositionTextSecond.c_str()), emptyUnderlines, 5, 5);
783
784    WebTextInputInfo info = webView->textInputInfo();
785    EXPECT_EQ("hello world", std::string(info.value.utf8().data()));
786    EXPECT_EQ(11, info.selectionStart);
787    EXPECT_EQ(11, info.selectionEnd);
788    EXPECT_EQ(6, info.compositionStart);
789    EXPECT_EQ(11, info.compositionEnd);
790
791    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
792    frame->setEditableSelectionOffsets(6, 6);
793    info = webView->textInputInfo();
794    EXPECT_EQ("hello world", std::string(info.value.utf8().data()));
795    EXPECT_EQ(6, info.selectionStart);
796    EXPECT_EQ(6, info.selectionEnd);
797    EXPECT_EQ(6, info.compositionStart);
798    EXPECT_EQ(11, info.compositionEnd);
799
800    frame->setEditableSelectionOffsets(8, 8);
801    info = webView->textInputInfo();
802    EXPECT_EQ("hello world", std::string(info.value.utf8().data()));
803    EXPECT_EQ(8, info.selectionStart);
804    EXPECT_EQ(8, info.selectionEnd);
805    EXPECT_EQ(6, info.compositionStart);
806    EXPECT_EQ(11, info.compositionEnd);
807
808    frame->setEditableSelectionOffsets(11, 11);
809    info = webView->textInputInfo();
810    EXPECT_EQ("hello world", std::string(info.value.utf8().data()));
811    EXPECT_EQ(11, info.selectionStart);
812    EXPECT_EQ(11, info.selectionEnd);
813    EXPECT_EQ(6, info.compositionStart);
814    EXPECT_EQ(11, info.compositionEnd);
815
816    frame->setEditableSelectionOffsets(6, 11);
817    info = webView->textInputInfo();
818    EXPECT_EQ("hello world", std::string(info.value.utf8().data()));
819    EXPECT_EQ(6, info.selectionStart);
820    EXPECT_EQ(11, info.selectionEnd);
821    EXPECT_EQ(6, info.compositionStart);
822    EXPECT_EQ(11, info.compositionEnd);
823
824    frame->setEditableSelectionOffsets(2, 2);
825    info = webView->textInputInfo();
826    EXPECT_EQ("hello world", std::string(info.value.utf8().data()));
827    EXPECT_EQ(2, info.selectionStart);
828    EXPECT_EQ(2, info.selectionEnd);
829    EXPECT_EQ(-1, info.compositionStart);
830    EXPECT_EQ(-1, info.compositionEnd);
831}
832
833TEST_F(WebViewTest, IsSelectionAnchorFirst)
834{
835    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html"));
836    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html");
837    WebFrame* frame = webView->mainFrame();
838
839    webView->setPageScaleFactorLimits(1, 1);
840    webView->setInitialFocus(false);
841    frame->setEditableSelectionOffsets(4, 10);
842    EXPECT_TRUE(webView->isSelectionAnchorFirst());
843    WebRect anchor;
844    WebRect focus;
845    webView->selectionBounds(anchor, focus);
846    frame->selectRange(WebPoint(focus.x, focus.y), WebPoint(anchor.x, anchor.y));
847    EXPECT_FALSE(webView->isSelectionAnchorFirst());
848}
849
850TEST_F(WebViewTest, HistoryResetScrollAndScaleState)
851{
852    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("hello_world.html"));
853    WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(m_baseURL + "hello_world.html");
854    webViewImpl->resize(WebSize(640, 480));
855    webViewImpl->layout();
856    EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().width);
857    EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().height);
858
859    // Make the page scale and scroll with the given paremeters.
860    webViewImpl->setPageScaleFactor(2.0f);
861    webViewImpl->setMainFrameScrollOffset(WebPoint(116, 84));
862    EXPECT_EQ(2.0f, webViewImpl->pageScaleFactor());
863    EXPECT_EQ(116, webViewImpl->mainFrame()->scrollOffset().width);
864    EXPECT_EQ(84, webViewImpl->mainFrame()->scrollOffset().height);
865    LocalFrame* mainFrameLocal = toLocalFrame(webViewImpl->page()->mainFrame());
866    mainFrameLocal->loader().saveScrollState();
867    EXPECT_EQ(2.0f, mainFrameLocal->loader().currentItem()->pageScaleFactor());
868    EXPECT_EQ(116, mainFrameLocal->loader().currentItem()->scrollPoint().x());
869    EXPECT_EQ(84, mainFrameLocal->loader().currentItem()->scrollPoint().y());
870
871    // Confirm that resetting the page state resets the saved scroll position.
872    // The HistoryController treats a page scale factor of 0.0f as special and avoids
873    // restoring it to the WebView.
874    webViewImpl->resetScrollAndScaleState();
875    EXPECT_EQ(1.0f, webViewImpl->pageScaleFactor());
876    EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().width);
877    EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().height);
878    EXPECT_EQ(0.0f, mainFrameLocal->loader().currentItem()->pageScaleFactor());
879    EXPECT_EQ(0, mainFrameLocal->loader().currentItem()->scrollPoint().x());
880    EXPECT_EQ(0, mainFrameLocal->loader().currentItem()->scrollPoint().y());
881}
882
883TEST_F(WebViewTest, BackForwardRestoreScroll)
884{
885    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("back_forward_restore_scroll.html"));
886    WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(m_baseURL + "back_forward_restore_scroll.html");
887    webViewImpl->resize(WebSize(640, 480));
888    webViewImpl->layout();
889
890    // Emulate a user scroll
891    webViewImpl->setMainFrameScrollOffset(WebPoint(0, 900));
892    LocalFrame* mainFrameLocal = toLocalFrame(webViewImpl->page()->mainFrame());
893    RefPtr<HistoryItem> item1 = mainFrameLocal->loader().currentItem();
894
895    // Click an anchor
896    mainFrameLocal->loader().load(FrameLoadRequest(mainFrameLocal->document(), ResourceRequest(mainFrameLocal->document()->completeURL("#a"))));
897    RefPtr<HistoryItem> item2 = mainFrameLocal->loader().currentItem();
898
899    // Go back, then forward, then back again.
900    mainFrameLocal->loader().loadHistoryItem(item1.get(), HistorySameDocumentLoad);
901    mainFrameLocal->loader().loadHistoryItem(item2.get(), HistorySameDocumentLoad);
902    mainFrameLocal->loader().loadHistoryItem(item1.get(), HistorySameDocumentLoad);
903
904    // Click a different anchor
905    mainFrameLocal->loader().load(FrameLoadRequest(mainFrameLocal->document(), ResourceRequest(mainFrameLocal->document()->completeURL("#b"))));
906    RefPtr<HistoryItem> item3 = mainFrameLocal->loader().currentItem();
907
908    // Go back, then forward. The scroll position should be properly set on the forward navigation.
909    mainFrameLocal->loader().loadHistoryItem(item1.get(), HistorySameDocumentLoad);
910    mainFrameLocal->loader().loadHistoryItem(item3.get(), HistorySameDocumentLoad);
911    EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().width);
912    EXPECT_GT(webViewImpl->mainFrame()->scrollOffset().height, 2000);
913}
914
915class EnterFullscreenWebViewClient : public FrameTestHelpers::TestWebViewClient {
916public:
917    // WebViewClient methods
918    virtual bool enterFullScreen() { return true; }
919    virtual void exitFullScreen() { }
920};
921
922
923TEST_F(WebViewTest, EnterFullscreenResetScrollAndScaleState)
924{
925    EnterFullscreenWebViewClient client;
926    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("hello_world.html"));
927    WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(m_baseURL + "hello_world.html", true, 0, &client);
928    webViewImpl->resize(WebSize(640, 480));
929    webViewImpl->layout();
930    EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().width);
931    EXPECT_EQ(0, webViewImpl->mainFrame()->scrollOffset().height);
932
933    // Make the page scale and scroll with the given paremeters.
934    webViewImpl->setPageScaleFactor(2.0f);
935    webViewImpl->setMainFrameScrollOffset(WebPoint(116, 84));
936    EXPECT_EQ(2.0f, webViewImpl->pageScaleFactor());
937    EXPECT_EQ(116, webViewImpl->mainFrame()->scrollOffset().width);
938    EXPECT_EQ(84, webViewImpl->mainFrame()->scrollOffset().height);
939
940    RefPtrWillBeRawPtr<Element> element = static_cast<PassRefPtrWillBeRawPtr<Element> >(webViewImpl->mainFrame()->document().body());
941    webViewImpl->enterFullScreenForElement(element.get());
942    webViewImpl->didEnterFullScreen();
943
944    // Page scale factor must be 1.0 during fullscreen for elements to be sized
945    // properly.
946    EXPECT_EQ(1.0f, webViewImpl->pageScaleFactor());
947
948    // Make sure fullscreen nesting doesn't disrupt scroll/scale saving.
949    RefPtrWillBeRawPtr<Element> otherElement = static_cast<PassRefPtrWillBeRawPtr<Element> >(webViewImpl->mainFrame()->document().head());
950    webViewImpl->enterFullScreenForElement(otherElement.get());
951
952    // Confirm that exiting fullscreen restores the parameters.
953    webViewImpl->didExitFullScreen();
954    EXPECT_EQ(2.0f, webViewImpl->pageScaleFactor());
955    EXPECT_EQ(116, webViewImpl->mainFrame()->scrollOffset().width);
956    EXPECT_EQ(84, webViewImpl->mainFrame()->scrollOffset().height);
957
958    m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client.
959}
960
961class PrintWebViewClient : public FrameTestHelpers::TestWebViewClient {
962public:
963    PrintWebViewClient()
964        : m_printCalled(false)
965    {
966    }
967
968    // WebViewClient methods
969    virtual void printPage(WebLocalFrame*) OVERRIDE
970    {
971        m_printCalled = true;
972    }
973
974    bool printCalled() const { return m_printCalled; }
975
976private:
977    bool m_printCalled;
978};
979
980
981TEST_F(WebViewTest, PrintWithXHRInFlight)
982{
983    PrintWebViewClient client;
984    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("print_with_xhr_inflight.html"));
985    WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(m_baseURL + "print_with_xhr_inflight.html", true, 0, &client);
986
987    ASSERT_EQ(FrameStateComplete, toLocalFrame(webViewImpl->page()->mainFrame())->loader().state());
988    EXPECT_TRUE(client.printCalled());
989    m_webViewHelper.reset();
990}
991
992class DropTask : public WebThread::Task {
993public:
994    explicit DropTask(WebView* webView) : m_webView(webView)
995    {
996    }
997
998    virtual void run() OVERRIDE
999    {
1000        const WebPoint clientPoint(0, 0);
1001        const WebPoint screenPoint(0, 0);
1002        m_webView->dragTargetDrop(clientPoint, screenPoint, 0);
1003    }
1004
1005private:
1006    WebView* const m_webView;
1007};
1008static void DragAndDropURL(WebViewImpl* webView, const std::string& url)
1009{
1010    WebDragData dragData;
1011    dragData.initialize();
1012
1013    WebDragData::Item item;
1014    item.storageType = WebDragData::Item::StorageTypeString;
1015    item.stringType = "text/uri-list";
1016    item.stringData = WebString::fromUTF8(url);
1017    dragData.addItem(item);
1018
1019    const WebPoint clientPoint(0, 0);
1020    const WebPoint screenPoint(0, 0);
1021    webView->dragTargetDragEnter(dragData, clientPoint, screenPoint, WebDragOperationCopy, 0);
1022    Platform::current()->currentThread()->postTask(new DropTask(webView));
1023    FrameTestHelpers::pumpPendingRequestsDoNotUse(webView->mainFrame());
1024}
1025
1026TEST_F(WebViewTest, DragDropURL)
1027{
1028    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), "foo.html");
1029    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), "bar.html");
1030
1031    const std::string fooUrl = m_baseURL + "foo.html";
1032    const std::string barUrl = m_baseURL + "bar.html";
1033
1034    WebViewImpl* webView = m_webViewHelper.initializeAndLoad(fooUrl);
1035
1036    ASSERT_TRUE(webView);
1037
1038    // Drag and drop barUrl and verify that we've navigated to it.
1039    DragAndDropURL(webView, barUrl);
1040    EXPECT_EQ(barUrl, webView->mainFrame()->document().url().string().utf8());
1041
1042    // Drag and drop fooUrl and verify that we've navigated back to it.
1043    DragAndDropURL(webView, fooUrl);
1044    EXPECT_EQ(fooUrl, webView->mainFrame()->document().url().string().utf8());
1045
1046    // Disable navigation on drag-and-drop.
1047    webView->settingsImpl()->setNavigateOnDragDrop(false);
1048
1049    // Attempt to drag and drop to barUrl and verify that no navigation has occurred.
1050    DragAndDropURL(webView, barUrl);
1051    EXPECT_EQ(fooUrl, webView->mainFrame()->document().url().string().utf8());
1052}
1053
1054class ContentDetectorClient : public FrameTestHelpers::TestWebViewClient {
1055public:
1056    ContentDetectorClient() { reset(); }
1057
1058    virtual WebContentDetectionResult detectContentAround(const WebHitTestResult& hitTest) OVERRIDE
1059    {
1060        m_contentDetectionRequested = true;
1061        return m_contentDetectionResult;
1062    }
1063
1064    virtual void scheduleContentIntent(const WebURL& url) OVERRIDE
1065    {
1066        m_scheduledIntentURL = url;
1067    }
1068
1069    virtual void cancelScheduledContentIntents() OVERRIDE
1070    {
1071        m_pendingIntentsCancelled = true;
1072    }
1073
1074    void reset()
1075    {
1076        m_contentDetectionRequested = false;
1077        m_pendingIntentsCancelled = false;
1078        m_scheduledIntentURL = WebURL();
1079        m_contentDetectionResult = WebContentDetectionResult();
1080    }
1081
1082    bool contentDetectionRequested() const { return m_contentDetectionRequested; }
1083    bool pendingIntentsCancelled() const { return m_pendingIntentsCancelled; }
1084    const WebURL& scheduledIntentURL() const { return m_scheduledIntentURL; }
1085    void setContentDetectionResult(const WebContentDetectionResult& result) { m_contentDetectionResult = result; }
1086
1087private:
1088    bool m_contentDetectionRequested;
1089    bool m_pendingIntentsCancelled;
1090    WebURL m_scheduledIntentURL;
1091    WebContentDetectionResult m_contentDetectionResult;
1092};
1093
1094static bool tapElementById(WebView* webView, WebInputEvent::Type type, const WebString& id)
1095{
1096    ASSERT(webView);
1097    RefPtrWillBeRawPtr<Element> element = static_cast<PassRefPtrWillBeRawPtr<Element> >(webView->mainFrame()->document().getElementById(id));
1098    if (!element)
1099        return false;
1100
1101    element->scrollIntoViewIfNeeded();
1102    IntPoint center = element->screenRect().center();
1103
1104    WebGestureEvent event;
1105    event.type = type;
1106    event.x = center.x();
1107    event.y = center.y();
1108
1109    webView->handleInputEvent(event);
1110    runPendingTasks();
1111    return true;
1112}
1113
1114TEST_F(WebViewTest, DetectContentAroundPosition)
1115{
1116    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("content_listeners.html"));
1117
1118    ContentDetectorClient client;
1119    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "content_listeners.html", true, 0, &client);
1120    webView->resize(WebSize(500, 300));
1121    webView->layout();
1122    runPendingTasks();
1123
1124    WebString clickListener = WebString::fromUTF8("clickListener");
1125    WebString touchstartListener = WebString::fromUTF8("touchstartListener");
1126    WebString mousedownListener = WebString::fromUTF8("mousedownListener");
1127    WebString noListener = WebString::fromUTF8("noListener");
1128    WebString link = WebString::fromUTF8("link");
1129
1130    // Ensure content detection is not requested for nodes listening to click,
1131    // mouse or touch events when we do simple taps.
1132    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, clickListener));
1133    EXPECT_FALSE(client.contentDetectionRequested());
1134    client.reset();
1135
1136    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, touchstartListener));
1137    EXPECT_FALSE(client.contentDetectionRequested());
1138    client.reset();
1139
1140    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, mousedownListener));
1141    EXPECT_FALSE(client.contentDetectionRequested());
1142    client.reset();
1143
1144    // Content detection should work normally without these event listeners.
1145    // The click listener in the body should be ignored as a special case.
1146    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, noListener));
1147    EXPECT_TRUE(client.contentDetectionRequested());
1148    EXPECT_FALSE(client.scheduledIntentURL().isValid());
1149
1150    WebURL intentURL = toKURL(m_baseURL);
1151    client.setContentDetectionResult(WebContentDetectionResult(WebRange(), WebString(), intentURL));
1152    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, noListener));
1153    EXPECT_TRUE(client.scheduledIntentURL() == intentURL);
1154
1155    // Tapping elsewhere should cancel the scheduled intent.
1156    WebGestureEvent event;
1157    event.type = WebInputEvent::GestureTap;
1158    webView->handleInputEvent(event);
1159    runPendingTasks();
1160    EXPECT_TRUE(client.pendingIntentsCancelled());
1161
1162    m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client.
1163}
1164
1165TEST_F(WebViewTest, ClientTapHandling)
1166{
1167    TapHandlingWebViewClient client;
1168    client.reset();
1169    WebView* webView = m_webViewHelper.initializeAndLoad("about:blank", true, 0, &client);
1170    WebGestureEvent event;
1171    event.type = WebInputEvent::GestureTap;
1172    event.x = 3;
1173    event.y = 8;
1174    webView->handleInputEvent(event);
1175    runPendingTasks();
1176    EXPECT_EQ(3, client.tapX());
1177    EXPECT_EQ(8, client.tapY());
1178    client.reset();
1179    event.type = WebInputEvent::GestureLongPress;
1180    event.x = 25;
1181    event.y = 7;
1182    webView->handleInputEvent(event);
1183    runPendingTasks();
1184    EXPECT_EQ(25, client.longpressX());
1185    EXPECT_EQ(7, client.longpressY());
1186
1187    m_webViewHelper.reset(); // Explicitly reset to break dependency on locally scoped client.
1188}
1189
1190#if OS(ANDROID)
1191TEST_F(WebViewTest, LongPressSelection)
1192{
1193    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("longpress_selection.html"));
1194
1195    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "longpress_selection.html", true);
1196    webView->resize(WebSize(500, 300));
1197    webView->layout();
1198    runPendingTasks();
1199
1200    WebString target = WebString::fromUTF8("target");
1201    WebString onselectstartfalse = WebString::fromUTF8("onselectstartfalse");
1202    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
1203
1204    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureLongPress, onselectstartfalse));
1205    EXPECT_EQ("", std::string(frame->selectionAsText().utf8().data()));
1206    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureLongPress, target));
1207    EXPECT_EQ("testword", std::string(frame->selectionAsText().utf8().data()));
1208}
1209
1210TEST_F(WebViewTest, BlinkCaretOnTypingAfterLongPress)
1211{
1212    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("blink_caret_on_typing_after_long_press.html"));
1213
1214    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "blink_caret_on_typing_after_long_press.html", true);
1215    webView->resize(WebSize(640, 480));
1216    webView->layout();
1217    runPendingTasks();
1218
1219    WebString target = WebString::fromUTF8("target");
1220    WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(webView->mainFrame());
1221
1222    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureLongPress, target));
1223    EXPECT_TRUE(mainFrame->frame()->selection().isCaretBlinkingSuspended());
1224
1225    WebKeyboardEvent keyEvent;
1226    keyEvent.type = WebInputEvent::RawKeyDown;
1227    webView->handleInputEvent(keyEvent);
1228    keyEvent.type = WebInputEvent::KeyUp;
1229    webView->handleInputEvent(keyEvent);
1230    EXPECT_FALSE(mainFrame->frame()->selection().isCaretBlinkingSuspended());
1231}
1232#endif
1233
1234TEST_F(WebViewTest, SelectionOnReadOnlyInput)
1235{
1236    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("selection_readonly.html"));
1237    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "selection_readonly.html", true);
1238    webView->resize(WebSize(640, 480));
1239    webView->layout();
1240    runPendingTasks();
1241
1242    std::string testWord = "This text should be selected.";
1243
1244    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
1245    EXPECT_EQ(testWord, std::string(frame->selectionAsText().utf8().data()));
1246
1247    size_t location;
1248    size_t length;
1249    EXPECT_TRUE(toWebViewImpl(webView)->caretOrSelectionRange(&location, &length));
1250    EXPECT_EQ(location, 0UL);
1251    EXPECT_EQ(length, testWord.length());
1252}
1253
1254static void configueCompositingWebView(WebSettings* settings)
1255{
1256    settings->setAcceleratedCompositingEnabled(true);
1257    settings->setPreferCompositingToLCDTextEnabled(true);
1258}
1259
1260TEST_F(WebViewTest, ShowPressOnTransformedLink)
1261{
1262    OwnPtr<FrameTestHelpers::TestWebViewClient> fakeCompositingWebViewClient = adoptPtr(new FrameTestHelpers::TestWebViewClient());
1263    FrameTestHelpers::WebViewHelper webViewHelper;
1264    WebViewImpl* webViewImpl = webViewHelper.initialize(true, 0, fakeCompositingWebViewClient.get(), &configueCompositingWebView);
1265
1266    int pageWidth = 640;
1267    int pageHeight = 480;
1268    webViewImpl->resize(WebSize(pageWidth, pageHeight));
1269
1270    WebURL baseURL = URLTestHelpers::toKURL("http://example.com/");
1271    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);
1272
1273    WebGestureEvent event;
1274    event.type = WebInputEvent::GestureShowPress;
1275    event.x = 20;
1276    event.y = 20;
1277
1278    // Just make sure we don't hit any asserts.
1279    webViewImpl->handleInputEvent(event);
1280}
1281
1282class MockAutofillClient : public WebAutofillClient {
1283public:
1284    MockAutofillClient()
1285        : m_ignoreTextChanges(false)
1286        , m_textChangesWhileIgnored(0)
1287        , m_textChangesWhileNotIgnored(0)
1288        , m_userGestureNotificationsCount(0) { }
1289
1290    virtual ~MockAutofillClient() { }
1291
1292    virtual void setIgnoreTextChanges(bool ignore) OVERRIDE { m_ignoreTextChanges = ignore; }
1293    virtual void textFieldDidChange(const WebFormControlElement&) OVERRIDE
1294    {
1295        if (m_ignoreTextChanges)
1296            ++m_textChangesWhileIgnored;
1297        else
1298            ++m_textChangesWhileNotIgnored;
1299    }
1300    virtual void firstUserGestureObserved() OVERRIDE { ++m_userGestureNotificationsCount; }
1301
1302    void clearChangeCounts()
1303    {
1304        m_textChangesWhileIgnored = 0;
1305        m_textChangesWhileNotIgnored = 0;
1306    }
1307
1308    int textChangesWhileIgnored() { return m_textChangesWhileIgnored; }
1309    int textChangesWhileNotIgnored() { return m_textChangesWhileNotIgnored; }
1310    int getUserGestureNotificationsCount() { return m_userGestureNotificationsCount; }
1311
1312private:
1313    bool m_ignoreTextChanges;
1314    int m_textChangesWhileIgnored;
1315    int m_textChangesWhileNotIgnored;
1316    int m_userGestureNotificationsCount;
1317};
1318
1319
1320TEST_F(WebViewTest, LosingFocusDoesNotTriggerAutofillTextChange)
1321{
1322    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html"));
1323    MockAutofillClient client;
1324    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html");
1325    webView->setAutofillClient(&client);
1326    webView->setInitialFocus(false);
1327
1328    // Set up a composition that needs to be committed.
1329    WebVector<WebCompositionUnderline> emptyUnderlines;
1330    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
1331    frame->setEditableSelectionOffsets(4, 10);
1332    frame->setCompositionFromExistingText(8, 12, emptyUnderlines);
1333    WebTextInputInfo info = webView->textInputInfo();
1334    EXPECT_EQ(4, info.selectionStart);
1335    EXPECT_EQ(10, info.selectionEnd);
1336    EXPECT_EQ(8, info.compositionStart);
1337    EXPECT_EQ(12, info.compositionEnd);
1338
1339    // Clear the focus and track that the subsequent composition commit does not trigger a
1340    // text changed notification for autofill.
1341    client.clearChangeCounts();
1342    webView->setFocus(false);
1343    EXPECT_EQ(1, client.textChangesWhileIgnored());
1344    EXPECT_EQ(0, client.textChangesWhileNotIgnored());
1345
1346    webView->setAutofillClient(0);
1347}
1348
1349TEST_F(WebViewTest, ConfirmCompositionTriggersAutofillTextChange)
1350{
1351    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html"));
1352    MockAutofillClient client;
1353    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html");
1354    webView->setAutofillClient(&client);
1355    webView->setInitialFocus(false);
1356
1357    // Set up a composition that needs to be committed.
1358    std::string compositionText("testingtext");
1359
1360    WebVector<WebCompositionUnderline> emptyUnderlines;
1361    webView->setComposition(WebString::fromUTF8(compositionText.c_str()), emptyUnderlines, 0, compositionText.length());
1362
1363    WebTextInputInfo info = webView->textInputInfo();
1364    EXPECT_EQ(0, info.selectionStart);
1365    EXPECT_EQ((int) compositionText.length(), info.selectionEnd);
1366    EXPECT_EQ(0, info.compositionStart);
1367    EXPECT_EQ((int) compositionText.length(), info.compositionEnd);
1368
1369    client.clearChangeCounts();
1370    webView->confirmComposition();
1371    EXPECT_EQ(0, client.textChangesWhileIgnored());
1372    EXPECT_EQ(1, client.textChangesWhileNotIgnored());
1373
1374    webView->setAutofillClient(0);
1375}
1376
1377TEST_F(WebViewTest, SetCompositionFromExistingTextTriggersAutofillTextChange)
1378{
1379    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("input_field_populated.html"));
1380    MockAutofillClient client;
1381    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "input_field_populated.html", true);
1382    webView->setAutofillClient(&client);
1383    webView->setInitialFocus(false);
1384
1385    WebVector<WebCompositionUnderline> emptyUnderlines;
1386
1387    client.clearChangeCounts();
1388    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
1389    frame->setCompositionFromExistingText(8, 12, emptyUnderlines);
1390
1391    WebTextInputInfo info = webView->textInputInfo();
1392    EXPECT_EQ("0123456789abcdefghijklmnopqrstuvwxyz", std::string(info.value.utf8().data()));
1393    EXPECT_EQ(8, info.compositionStart);
1394    EXPECT_EQ(12, info.compositionEnd);
1395
1396    EXPECT_EQ(0, client.textChangesWhileIgnored());
1397    EXPECT_EQ(0, client.textChangesWhileNotIgnored());
1398
1399    WebDocument document = webView->mainFrame()->document();
1400    EXPECT_EQ(WebString::fromUTF8("none"),  document.getElementById("inputEvent").firstChild().nodeValue());
1401
1402    webView->setAutofillClient(0);
1403}
1404
1405TEST_F(WebViewTest, ShadowRoot)
1406{
1407    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("shadow_dom_test.html"));
1408    WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(m_baseURL + "shadow_dom_test.html", true);
1409
1410    WebDocument document = webViewImpl->mainFrame()->document();
1411    {
1412        WebElement elementWithShadowRoot = document.getElementById("shadowroot");
1413        EXPECT_FALSE(elementWithShadowRoot.isNull());
1414        WebNode shadowRoot = elementWithShadowRoot.shadowRoot();
1415        EXPECT_FALSE(shadowRoot.isNull());
1416    }
1417    {
1418        WebElement elementWithoutShadowRoot = document.getElementById("noshadowroot");
1419        EXPECT_FALSE(elementWithoutShadowRoot.isNull());
1420        WebNode shadowRoot = elementWithoutShadowRoot.shadowRoot();
1421        EXPECT_TRUE(shadowRoot.isNull());
1422    }
1423}
1424
1425class ViewCreatingWebViewClient : public FrameTestHelpers::TestWebViewClient {
1426public:
1427    ViewCreatingWebViewClient()
1428        : m_didFocusCalled(false)
1429    {
1430    }
1431
1432    // WebViewClient methods
1433    virtual WebView* createView(WebLocalFrame*, const WebURLRequest&, const WebWindowFeatures&, const WebString& name, WebNavigationPolicy, bool) OVERRIDE
1434    {
1435        return m_webViewHelper.initialize(true, 0, 0);
1436    }
1437
1438    // WebWidgetClient methods
1439    virtual void didFocus() OVERRIDE
1440    {
1441        m_didFocusCalled = true;
1442    }
1443
1444    bool didFocusCalled() const { return m_didFocusCalled; }
1445    WebView* createdWebView() const { return m_webViewHelper.webView(); }
1446
1447private:
1448    FrameTestHelpers::WebViewHelper m_webViewHelper;
1449    bool m_didFocusCalled;
1450};
1451
1452TEST_F(WebViewTest, FocusExistingFrameOnNavigate)
1453{
1454    ViewCreatingWebViewClient client;
1455    FrameTestHelpers::WebViewHelper m_webViewHelper;
1456    WebViewImpl* webViewImpl = m_webViewHelper.initialize(true, 0, &client);
1457    webViewImpl->page()->settings().setJavaScriptCanOpenWindowsAutomatically(true);
1458    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewImpl->mainFrame());
1459    frame->setName("_start");
1460
1461    // Make a request that will open a new window
1462    WebURLRequest webURLRequest;
1463    webURLRequest.initialize();
1464    FrameLoadRequest request(0, webURLRequest.toResourceRequest(), "_blank");
1465    toLocalFrame(webViewImpl->page()->mainFrame())->loader().load(request);
1466    ASSERT_TRUE(client.createdWebView());
1467    EXPECT_FALSE(client.didFocusCalled());
1468
1469    // Make a request from the new window that will navigate the original window. The original window should be focused.
1470    WebURLRequest webURLRequestWithTargetStart;
1471    webURLRequestWithTargetStart.initialize();
1472    FrameLoadRequest requestWithTargetStart(0, webURLRequestWithTargetStart.toResourceRequest(), "_start");
1473    toLocalFrame(toWebViewImpl(client.createdWebView())->page()->mainFrame())->loader().load(requestWithTargetStart);
1474    EXPECT_TRUE(client.didFocusCalled());
1475
1476    m_webViewHelper.reset(); // Remove dependency on locally scoped client.
1477}
1478
1479TEST_F(WebViewTest, DispatchesFocusOutFocusInOnViewToggleFocus)
1480{
1481    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), "focusout_focusin_events.html");
1482    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "focusout_focusin_events.html", true, 0);
1483
1484    webView->setFocus(true);
1485    webView->setFocus(false);
1486    webView->setFocus(true);
1487
1488    WebElement element = webView->mainFrame()->document().getElementById("message");
1489    EXPECT_STREQ("focusoutfocusin", element.innerText().utf8().data());
1490}
1491
1492TEST_F(WebViewTest, DispatchesDomFocusOutDomFocusInOnViewToggleFocus)
1493{
1494    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), "domfocusout_domfocusin_events.html");
1495    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "domfocusout_domfocusin_events.html", true, 0);
1496
1497    webView->setFocus(true);
1498    webView->setFocus(false);
1499    webView->setFocus(true);
1500
1501    WebElement element = webView->mainFrame()->document().getElementById("message");
1502    EXPECT_STREQ("DOMFocusOutDOMFocusIn", element.innerText().utf8().data());
1503}
1504
1505#if !ENABLE(INPUT_MULTIPLE_FIELDS_UI)
1506static void openDateTimeChooser(WebView* webView, HTMLInputElement* inputElement)
1507{
1508    inputElement->focus();
1509
1510    WebKeyboardEvent keyEvent;
1511    keyEvent.windowsKeyCode = VKEY_SPACE;
1512    keyEvent.type = WebInputEvent::RawKeyDown;
1513    keyEvent.setKeyIdentifierFromWindowsKeyCode();
1514    webView->handleInputEvent(keyEvent);
1515
1516    keyEvent.type = WebInputEvent::KeyUp;
1517    webView->handleInputEvent(keyEvent);
1518}
1519
1520TEST_F(WebViewTest, ChooseValueFromDateTimeChooser)
1521{
1522    DateTimeChooserWebViewClient client;
1523    std::string url = m_baseURL + "date_time_chooser.html";
1524    URLTestHelpers::registerMockedURLLoad(toKURL(url), "date_time_chooser.html");
1525    WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(url, true, 0, &client);
1526
1527    Document* document = webViewImpl->mainFrameImpl()->frame()->document();
1528
1529    HTMLInputElement* inputElement;
1530
1531    inputElement = toHTMLInputElement(document->getElementById("date"));
1532    openDateTimeChooser(webViewImpl, inputElement);
1533    client.chooserCompletion()->didChooseValue(0);
1534    client.clearChooserCompletion();
1535    EXPECT_STREQ("1970-01-01", inputElement->value().utf8().data());
1536
1537    openDateTimeChooser(webViewImpl, inputElement);
1538    client.chooserCompletion()->didChooseValue(std::numeric_limits<double>::quiet_NaN());
1539    client.clearChooserCompletion();
1540    EXPECT_STREQ("", inputElement->value().utf8().data());
1541
1542    inputElement = toHTMLInputElement(document->getElementById("datetimelocal"));
1543    openDateTimeChooser(webViewImpl, inputElement);
1544    client.chooserCompletion()->didChooseValue(0);
1545    client.clearChooserCompletion();
1546    EXPECT_STREQ("1970-01-01T00:00", inputElement->value().utf8().data());
1547
1548    openDateTimeChooser(webViewImpl, inputElement);
1549    client.chooserCompletion()->didChooseValue(std::numeric_limits<double>::quiet_NaN());
1550    client.clearChooserCompletion();
1551    EXPECT_STREQ("", inputElement->value().utf8().data());
1552
1553    inputElement = toHTMLInputElement(document->getElementById("month"));
1554    openDateTimeChooser(webViewImpl, inputElement);
1555    client.chooserCompletion()->didChooseValue(0);
1556    client.clearChooserCompletion();
1557    EXPECT_STREQ("1970-01", inputElement->value().utf8().data());
1558
1559    openDateTimeChooser(webViewImpl, inputElement);
1560    client.chooserCompletion()->didChooseValue(std::numeric_limits<double>::quiet_NaN());
1561    client.clearChooserCompletion();
1562    EXPECT_STREQ("", inputElement->value().utf8().data());
1563
1564    inputElement = toHTMLInputElement(document->getElementById("time"));
1565    openDateTimeChooser(webViewImpl, inputElement);
1566    client.chooserCompletion()->didChooseValue(0);
1567    client.clearChooserCompletion();
1568    EXPECT_STREQ("00:00", inputElement->value().utf8().data());
1569
1570    openDateTimeChooser(webViewImpl, inputElement);
1571    client.chooserCompletion()->didChooseValue(std::numeric_limits<double>::quiet_NaN());
1572    client.clearChooserCompletion();
1573    EXPECT_STREQ("", inputElement->value().utf8().data());
1574
1575    inputElement = toHTMLInputElement(document->getElementById("week"));
1576    openDateTimeChooser(webViewImpl, inputElement);
1577    client.chooserCompletion()->didChooseValue(0);
1578    client.clearChooserCompletion();
1579    EXPECT_STREQ("1970-W01", inputElement->value().utf8().data());
1580
1581    openDateTimeChooser(webViewImpl, inputElement);
1582    client.chooserCompletion()->didChooseValue(std::numeric_limits<double>::quiet_NaN());
1583    client.clearChooserCompletion();
1584    EXPECT_STREQ("", inputElement->value().utf8().data());
1585
1586    // Clear the WebViewClient from the webViewHelper to avoid use-after-free in the
1587    // WebViewHelper destructor.
1588    m_webViewHelper.reset();
1589}
1590#endif
1591
1592TEST_F(WebViewTest, DispatchesFocusBlurOnViewToggle)
1593{
1594    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), "focus_blur_events.html");
1595    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "focus_blur_events.html", true, 0);
1596
1597    webView->setFocus(true);
1598    webView->setFocus(false);
1599    webView->setFocus(true);
1600
1601    WebElement element = webView->mainFrame()->document().getElementById("message");
1602    // Expect not to see duplication of events.
1603    EXPECT_STREQ("blurfocus", element.innerText().utf8().data());
1604}
1605
1606TEST_F(WebViewTest, SmartClipData)
1607{
1608    static const char* kExpectedClipText = "\nPrice 10,000,000won";
1609    static const char* kExpectedClipHtml =
1610        "<div id=\"div4\" style=\"padding: 10px; margin: 10px; border: 2px "
1611        "solid rgb(135, 206, 235); float: left; width: 190px; height: 30px; "
1612        "color: rgb(0, 0, 0); font-family: myahem; font-size: 8px; font-style: "
1613        "normal; font-variant: normal; font-weight: normal; letter-spacing: "
1614        "normal; line-height: normal; orphans: auto; text-align: start; "
1615        "text-indent: 0px; text-transform: none; white-space: normal; widows: "
1616        "auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;\">Air "
1617        "conditioner</div><div id=\"div5\" style=\"padding: 10px; margin: "
1618        "10px; border: 2px solid rgb(135, 206, 235); float: left; width: "
1619        "190px; height: 30px; color: rgb(0, 0, 0); font-family: myahem; "
1620        "font-size: 8px; font-style: normal; font-variant: normal; "
1621        "font-weight: normal; letter-spacing: normal; line-height: normal; "
1622        "orphans: auto; text-align: start; text-indent: 0px; text-transform: "
1623        "none; white-space: normal; widows: auto; word-spacing: 0px; "
1624        "-webkit-text-stroke-width: 0px;\">Price 10,000,000won</div>";
1625    WebString clipText;
1626    WebString clipHtml;
1627    WebRect clipRect;
1628    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("Ahem.ttf"));
1629    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("smartclip.html"));
1630    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "smartclip.html");
1631    webView->setPageScaleFactorLimits(1, 1);
1632    webView->resize(WebSize(500, 500));
1633    webView->layout();
1634    WebRect cropRect(300, 125, 152, 50);
1635    webView->extractSmartClipData(cropRect, clipText, clipHtml, clipRect);
1636    EXPECT_STREQ(kExpectedClipText, clipText.utf8().c_str());
1637    EXPECT_STREQ(kExpectedClipHtml, clipHtml.utf8().c_str());
1638}
1639
1640TEST_F(WebViewTest, SmartClipReturnsEmptyStringsWhenUserSelectIsNone)
1641{
1642    WebString clipText;
1643    WebString clipHtml;
1644    WebRect clipRect;
1645    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("Ahem.ttf"));
1646    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("smartclip_user_select_none.html"));
1647    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "smartclip_user_select_none.html");
1648    webView->setPageScaleFactorLimits(1, 1);
1649    webView->resize(WebSize(500, 500));
1650    webView->layout();
1651    WebRect cropRect(0, 0, 100, 100);
1652    webView->extractSmartClipData(cropRect, clipText, clipHtml, clipRect);
1653    EXPECT_STREQ("", clipText.utf8().c_str());
1654    EXPECT_STREQ("", clipHtml.utf8().c_str());
1655}
1656
1657class CreateChildCounterFrameClient : public FrameTestHelpers::TestWebFrameClient {
1658public:
1659    CreateChildCounterFrameClient() : m_count(0) { }
1660    virtual WebFrame* createChildFrame(WebLocalFrame* parent, const WebString& frameName) OVERRIDE;
1661
1662    int count() const { return m_count; }
1663
1664private:
1665    int m_count;
1666};
1667
1668WebFrame* CreateChildCounterFrameClient::createChildFrame(WebLocalFrame* parent, const WebString& frameName)
1669{
1670    ++m_count;
1671    return TestWebFrameClient::createChildFrame(parent, frameName);
1672}
1673
1674TEST_F(WebViewTest, AddFrameInCloseUnload)
1675{
1676    CreateChildCounterFrameClient frameClient;
1677    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("add_frame_in_unload.html"));
1678    m_webViewHelper.initializeAndLoad(m_baseURL + "add_frame_in_unload.html", true, &frameClient);
1679    m_webViewHelper.reset();
1680    EXPECT_EQ(0, frameClient.count());
1681}
1682
1683TEST_F(WebViewTest, AddFrameInCloseURLUnload)
1684{
1685    CreateChildCounterFrameClient frameClient;
1686    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("add_frame_in_unload.html"));
1687    m_webViewHelper.initializeAndLoad(m_baseURL + "add_frame_in_unload.html", true, &frameClient);
1688    m_webViewHelper.webViewImpl()->mainFrame()->dispatchUnloadEvent();
1689    EXPECT_EQ(0, frameClient.count());
1690    m_webViewHelper.reset();
1691}
1692
1693TEST_F(WebViewTest, AddFrameInNavigateUnload)
1694{
1695    CreateChildCounterFrameClient frameClient;
1696    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("add_frame_in_unload.html"));
1697    m_webViewHelper.initializeAndLoad(m_baseURL + "add_frame_in_unload.html", true, &frameClient);
1698    FrameTestHelpers::loadFrame(m_webViewHelper.webView()->mainFrame(), "about:blank");
1699    EXPECT_EQ(0, frameClient.count());
1700    m_webViewHelper.reset();
1701}
1702
1703TEST_F(WebViewTest, AddFrameInChildInNavigateUnload)
1704{
1705    CreateChildCounterFrameClient frameClient;
1706    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("add_frame_in_unload_wrapper.html"));
1707    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("add_frame_in_unload.html"));
1708    m_webViewHelper.initializeAndLoad(m_baseURL + "add_frame_in_unload_wrapper.html", true, &frameClient);
1709    FrameTestHelpers::loadFrame(m_webViewHelper.webView()->mainFrame(), "about:blank");
1710    EXPECT_EQ(1, frameClient.count());
1711    m_webViewHelper.reset();
1712}
1713
1714class TouchEventHandlerWebViewClient : public FrameTestHelpers::TestWebViewClient {
1715public:
1716    // WebWidgetClient methods
1717    virtual void hasTouchEventHandlers(bool state) OVERRIDE
1718    {
1719        m_hasTouchEventHandlerCount[state]++;
1720    }
1721
1722    // Local methods
1723    TouchEventHandlerWebViewClient() : m_hasTouchEventHandlerCount()
1724    {
1725    }
1726
1727    int getAndResetHasTouchEventHandlerCallCount(bool state)
1728    {
1729        int value = m_hasTouchEventHandlerCount[state];
1730        m_hasTouchEventHandlerCount[state] = 0;
1731        return value;
1732    }
1733
1734private:
1735    int m_hasTouchEventHandlerCount[2];
1736};
1737
1738// This test verifies that WebWidgetClient::hasTouchEventHandlers is called
1739// accordingly for various calls to EventHandlerRegistry::did{Add|Remove|
1740// RemoveAll}EventHandler(..., TouchEvent). Verifying that those calls are made
1741// correctly is the job of LayoutTests/fast/events/event-handler-count.html.
1742TEST_F(WebViewTest, HasTouchEventHandlers)
1743{
1744    TouchEventHandlerWebViewClient client;
1745    std::string url = m_baseURL + "has_touch_event_handlers.html";
1746    URLTestHelpers::registerMockedURLLoad(toKURL(url), "has_touch_event_handlers.html");
1747    WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(url, true, 0, &client);
1748    const EventHandlerRegistry::EventHandlerClass touchEvent = EventHandlerRegistry::TouchEvent;
1749
1750    // The page is initialized with at least one no-handlers call.
1751    // In practice we get two such calls because WebViewHelper::initializeAndLoad first
1752    // initializes and empty frame, and then loads a document into it, so there are two
1753    // FrameLoader::commitProvisionalLoad calls.
1754    EXPECT_GE(client.getAndResetHasTouchEventHandlerCallCount(false), 1);
1755    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
1756
1757    // Adding the first document handler results in a has-handlers call.
1758    Document* document = webViewImpl->mainFrameImpl()->frame()->document();
1759    EventHandlerRegistry* registry = &document->frameHost()->eventHandlerRegistry();
1760    registry->didAddEventHandler(*document, touchEvent);
1761    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
1762    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(true));
1763
1764    // Adding another handler has no effect.
1765    registry->didAddEventHandler(*document, touchEvent);
1766    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
1767    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
1768
1769    // Removing the duplicate handler has no effect.
1770    registry->didRemoveEventHandler(*document, touchEvent);
1771    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
1772    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
1773
1774    // Removing the final handler results in a no-handlers call.
1775    registry->didRemoveEventHandler(*document, touchEvent);
1776    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(false));
1777    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
1778
1779    // Adding a handler on a div results in a has-handlers call.
1780    Element* parentDiv = document->getElementById("parentdiv");
1781    ASSERT(parentDiv);
1782    registry->didAddEventHandler(*parentDiv, touchEvent);
1783    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
1784    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(true));
1785
1786    // Adding a duplicate handler on the div, clearing all document handlers
1787    // (of which there are none) and removing the extra handler on the div
1788    // all have no effect.
1789    registry->didAddEventHandler(*parentDiv, touchEvent);
1790    registry->didRemoveAllEventHandlers(*document);
1791    registry->didRemoveEventHandler(*parentDiv, touchEvent);
1792    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
1793    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
1794
1795    // Removing the final handler on the div results in a no-handlers call.
1796    registry->didRemoveEventHandler(*parentDiv, touchEvent);
1797    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(false));
1798    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
1799
1800    // Adding two handlers then clearing them in a single call results in a
1801    // has-handlers then no-handlers call.
1802    registry->didAddEventHandler(*parentDiv, touchEvent);
1803    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
1804    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(true));
1805    registry->didAddEventHandler(*parentDiv, touchEvent);
1806    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
1807    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
1808    registry->didRemoveAllEventHandlers(*parentDiv);
1809    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(false));
1810    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
1811
1812    // Adding a handler inside of a child iframe results in a has-handlers call.
1813    Element* childFrame = document->getElementById("childframe");
1814    ASSERT(childFrame);
1815    Document* childDocument = toHTMLIFrameElement(childFrame)->contentDocument();
1816    Element* childDiv = childDocument->getElementById("childdiv");
1817    ASSERT(childDiv);
1818    registry->didAddEventHandler(*childDiv, touchEvent);
1819    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
1820    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(true));
1821
1822    // Adding and clearing handlers in the parent doc or elsewhere in the child doc
1823    // has no impact.
1824    registry->didAddEventHandler(*document, touchEvent);
1825    registry->didAddEventHandler(*childFrame, touchEvent);
1826    registry->didAddEventHandler(*childDocument, touchEvent);
1827    registry->didRemoveAllEventHandlers(*document);
1828    registry->didRemoveAllEventHandlers(*childFrame);
1829    registry->didRemoveAllEventHandlers(*childDocument);
1830    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
1831    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
1832
1833    // Removing the final handler inside the child frame results in a no-handlers call.
1834    registry->didRemoveAllEventHandlers(*childDiv);
1835    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(false));
1836    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
1837
1838    // Adding a handler inside the child frame results in a has-handlers call.
1839    registry->didAddEventHandler(*childDocument, touchEvent);
1840    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
1841    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(true));
1842
1843    // Adding a handler in the parent document and removing the one in the frame
1844    // has no effect.
1845    registry->didAddEventHandler(*childFrame, touchEvent);
1846    registry->didRemoveEventHandler(*childDocument, touchEvent);
1847    registry->didRemoveAllEventHandlers(*childDocument);
1848    registry->didRemoveAllEventHandlers(*document);
1849    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(false));
1850    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
1851
1852    // Now removing the handler in the parent document results in a no-handlers call.
1853    registry->didRemoveEventHandler(*childFrame, touchEvent);
1854    EXPECT_EQ(1, client.getAndResetHasTouchEventHandlerCallCount(false));
1855    EXPECT_EQ(0, client.getAndResetHasTouchEventHandlerCallCount(true));
1856
1857    // Free the webView before the TouchEventHandlerWebViewClient gets freed.
1858    m_webViewHelper.reset();
1859}
1860
1861// This test checks that deleting nodes which have only non-JS-registered touch
1862// handlers also removes them from the event handler registry. Note that this
1863// is different from detaching and re-attaching the same node, which is covered
1864// by layout tests under fast/events/.
1865TEST_F(WebViewTest, DeleteElementWithRegisteredHandler)
1866{
1867    std::string url = m_baseURL + "simple_div.html";
1868    URLTestHelpers::registerMockedURLLoad(toKURL(url), "simple_div.html");
1869    WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(url, true);
1870
1871    RefPtrWillBePersistent<Document> document = webViewImpl->mainFrameImpl()->frame()->document();
1872    Element* div = document->getElementById("div");
1873    EventHandlerRegistry& registry = document->frameHost()->eventHandlerRegistry();
1874
1875    registry.didAddEventHandler(*div, EventHandlerRegistry::ScrollEvent);
1876    EXPECT_TRUE(registry.hasEventHandlers(EventHandlerRegistry::ScrollEvent));
1877
1878    TrackExceptionState exceptionState;
1879    div->remove(exceptionState);
1880#if ENABLE(OILPAN)
1881    // For oilpan we have to force a GC to ensure the event handlers have been removed when
1882    // checking below. We do a precise GC (collectAllGarbage does not scan the stack)
1883    // to ensure the div element dies. This is also why the Document is in a Persistent
1884    // since we want that to stay around.
1885    Heap::collectAllGarbage();
1886#endif
1887    EXPECT_FALSE(registry.hasEventHandlers(EventHandlerRegistry::ScrollEvent));
1888}
1889
1890static WebRect ExpectedRootBounds(Document* document, float scaleFactor)
1891{
1892    Element* element = document->getElementById("root");
1893    if (!element)
1894        element = document->getElementById("target");
1895    if (element->hasTagName(HTMLNames::iframeTag))
1896        return ExpectedRootBounds(toHTMLIFrameElement(element)->contentDocument(), scaleFactor);
1897
1898    IntRect boundingBox;
1899    if (element->hasTagName(HTMLNames::htmlTag))
1900        boundingBox = IntRect(IntPoint(0, 0), document->frame()->view()->contentsSize());
1901    else
1902        boundingBox = element->pixelSnappedBoundingBox();
1903    boundingBox = document->frame()->view()->contentsToWindow(boundingBox);
1904    boundingBox.scale(scaleFactor);
1905    return boundingBox;
1906}
1907
1908void WebViewTest::testSelectionRootBounds(const char* htmlFile, float pageScaleFactor)
1909{
1910    std::string url = m_baseURL + htmlFile;
1911
1912    WebView* webView = m_webViewHelper.initializeAndLoad(url, true);
1913    webView->resize(WebSize(640, 480));
1914    webView->setPageScaleFactor(pageScaleFactor);
1915    webView->layout();
1916    runPendingTasks();
1917
1918    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
1919    EXPECT_TRUE(frame->frame()->document()->isHTMLDocument());
1920    HTMLDocument* document = toHTMLDocument(frame->frame()->document());
1921
1922    WebRect expectedRootBounds = ExpectedRootBounds(document, webView->pageScaleFactor());
1923    WebRect actualRootBounds;
1924    webView->getSelectionRootBounds(actualRootBounds);
1925    ASSERT_EQ(expectedRootBounds, actualRootBounds);
1926
1927    WebRect anchor, focus;
1928    webView->selectionBounds(anchor, focus);
1929    IntRect expectedIntRect = expectedRootBounds;
1930    ASSERT_TRUE(expectedIntRect.contains(anchor));
1931    // The "overflow" tests have the focus boundary outside of the element box.
1932    ASSERT_EQ(url.find("overflow") == std::string::npos, expectedIntRect.contains(focus));
1933}
1934
1935TEST_F(WebViewTest, GetSelectionRootBounds)
1936{
1937    // Register all the pages we will be using.
1938    registerMockedHttpURLLoad("select_range_basic.html");
1939    registerMockedHttpURLLoad("select_range_div_editable.html");
1940    registerMockedHttpURLLoad("select_range_scroll.html");
1941    registerMockedHttpURLLoad("select_range_span_editable.html");
1942    registerMockedHttpURLLoad("select_range_input.html");
1943    registerMockedHttpURLLoad("select_range_input_overflow.html");
1944    registerMockedHttpURLLoad("select_range_textarea.html");
1945    registerMockedHttpURLLoad("select_range_textarea_overflow.html");
1946    registerMockedHttpURLLoad("select_range_iframe.html");
1947    registerMockedHttpURLLoad("select_range_iframe_div_editable.html");
1948    registerMockedHttpURLLoad("select_range_iframe_scroll.html");
1949    registerMockedHttpURLLoad("select_range_iframe_span_editable.html");
1950    registerMockedHttpURLLoad("select_range_iframe_input.html");
1951    registerMockedHttpURLLoad("select_range_iframe_input_overflow.html");
1952    registerMockedHttpURLLoad("select_range_iframe_textarea.html");
1953    registerMockedHttpURLLoad("select_range_iframe_textarea_overflow.html");
1954
1955    // Test with simple pages.
1956    testSelectionRootBounds("select_range_basic.html", 1.0f);
1957    testSelectionRootBounds("select_range_div_editable.html", 1.0f);
1958    testSelectionRootBounds("select_range_scroll.html", 1.0f);
1959    testSelectionRootBounds("select_range_span_editable.html", 1.0f);
1960    testSelectionRootBounds("select_range_input.html", 1.0f);
1961    testSelectionRootBounds("select_range_input_overflow.html", 1.0f);
1962    testSelectionRootBounds("select_range_textarea.html", 1.0f);
1963    testSelectionRootBounds("select_range_textarea_overflow.html", 1.0f);
1964
1965    // Test with the same pages as above in iframes.
1966    testSelectionRootBounds("select_range_iframe.html", 1.0f);
1967    testSelectionRootBounds("select_range_iframe_div_editable.html", 1.0f);
1968    testSelectionRootBounds("select_range_iframe_scroll.html", 1.0f);
1969    testSelectionRootBounds("select_range_iframe_span_editable.html", 1.0f);
1970    testSelectionRootBounds("select_range_iframe_input.html", 1.0f);
1971    testSelectionRootBounds("select_range_iframe_input_overflow.html", 1.0f);
1972    testSelectionRootBounds("select_range_iframe_textarea.html", 1.0f);
1973    testSelectionRootBounds("select_range_iframe_textarea_overflow.html", 1.0f);
1974
1975    // Basic page with scale factor.
1976    testSelectionRootBounds("select_range_basic.html", 0.0f);
1977    testSelectionRootBounds("select_range_basic.html", 0.1f);
1978    testSelectionRootBounds("select_range_basic.html", 1.5f);
1979    testSelectionRootBounds("select_range_basic.html", 2.0f);
1980}
1981
1982TEST_F(WebViewTest, GetSelectionRootBoundsBrokenHeight)
1983{
1984    WebSize contentSize = WebSize(640, 480);
1985
1986    registerMockedHttpURLLoad("select_range_basic_broken_height.html");
1987
1988    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "select_range_basic_broken_height.html", true);
1989    webView->resize(contentSize);
1990    webView->setPageScaleFactor(1.0f, WebPoint(0, 0));
1991    webView->layout();
1992    runPendingTasks();
1993
1994    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
1995    EXPECT_TRUE(frame->frame()->document()->isHTMLDocument());
1996
1997    WebRect expectedRootBounds = WebRect(0, 0, contentSize.width, contentSize.height);
1998    WebRect actualRootBounds;
1999    webView->getSelectionRootBounds(actualRootBounds);
2000    ASSERT_EQ(expectedRootBounds, actualRootBounds);
2001}
2002
2003class NonUserInputTextUpdateWebViewClient : public FrameTestHelpers::TestWebViewClient {
2004public:
2005    NonUserInputTextUpdateWebViewClient() : m_textIsUpdated(false) { }
2006
2007    // WebWidgetClient methods
2008    virtual void didUpdateTextOfFocusedElementByNonUserInput() OVERRIDE
2009    {
2010        m_textIsUpdated = true;
2011    }
2012
2013    void reset()
2014    {
2015        m_textIsUpdated = false;
2016    }
2017
2018    bool textIsUpdated() const
2019    {
2020        return m_textIsUpdated;
2021    }
2022
2023private:
2024    int m_textIsUpdated;
2025};
2026
2027// This test verifies that WebWidgetClient::didUpdateTextOfFocusedElementByNonUserInput is
2028// called iff value of a focused element is modified via script.
2029TEST_F(WebViewTest, NonUserInputTextUpdate)
2030{
2031    NonUserInputTextUpdateWebViewClient client;
2032    std::string url = m_baseURL + "non_user_input_text_update.html";
2033    URLTestHelpers::registerMockedURLLoad(toKURL(url), "non_user_input_text_update.html");
2034    WebViewImpl* webViewImpl = m_webViewHelper.initializeAndLoad(url, true, 0, &client);
2035    webViewImpl->setInitialFocus(false);
2036
2037    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewImpl->mainFrame());
2038    HTMLDocument* document = toHTMLDocument(frame->frame()->document());
2039
2040    // (A) <input>
2041    // (A.1) Focused and value is changed by script.
2042    client.reset();
2043    EXPECT_FALSE(client.textIsUpdated());
2044
2045    HTMLInputElement* inputElement = toHTMLInputElement(document->getElementById("input"));
2046    document->setFocusedElement(inputElement);
2047    webViewImpl->setFocus(true);
2048    EXPECT_EQ(document->focusedElement(), static_cast<Element*>(inputElement));
2049
2050    // Emulate value change from script.
2051    inputElement->setValue("testA");
2052    EXPECT_TRUE(client.textIsUpdated());
2053    WebTextInputInfo info = webViewImpl->textInputInfo();
2054    EXPECT_EQ("testA", std::string(info.value.utf8().data()));
2055
2056    // (A.2) Focused and user input modifies value.
2057    client.reset();
2058    EXPECT_FALSE(client.textIsUpdated());
2059
2060    WebVector<WebCompositionUnderline> emptyUnderlines;
2061    webViewImpl->setComposition(WebString::fromUTF8("2"), emptyUnderlines, 1, 1);
2062    webViewImpl->confirmComposition(WebWidget::KeepSelection);
2063    EXPECT_FALSE(client.textIsUpdated());
2064    info = webViewImpl->textInputInfo();
2065    EXPECT_EQ("testA2", std::string(info.value.utf8().data()));
2066
2067    // (A.3) Unfocused and value is changed by script.
2068    client.reset();
2069    EXPECT_FALSE(client.textIsUpdated());
2070    document->setFocusedElement(nullptr);
2071    webViewImpl->setFocus(false);
2072    EXPECT_NE(document->focusedElement(), static_cast<Element*>(inputElement));
2073    inputElement->setValue("testA3");
2074    EXPECT_FALSE(client.textIsUpdated());
2075
2076    // (B) <textarea>
2077    // (B.1) Focused and value is changed by script.
2078    client.reset();
2079    EXPECT_FALSE(client.textIsUpdated());
2080    HTMLTextAreaElement* textAreaElement = toHTMLTextAreaElement(document->getElementById("textarea"));
2081    document->setFocusedElement(textAreaElement);
2082    webViewImpl->setFocus(true);
2083    EXPECT_EQ(document->focusedElement(), static_cast<Element*>(textAreaElement));
2084    textAreaElement->setValue("testB");
2085    EXPECT_TRUE(client.textIsUpdated());
2086    info = webViewImpl->textInputInfo();
2087    EXPECT_EQ("testB", std::string(info.value.utf8().data()));
2088
2089    // (B.2) Focused and user input modifies value.
2090    client.reset();
2091    EXPECT_FALSE(client.textIsUpdated());
2092    webViewImpl->setComposition(WebString::fromUTF8("2"), emptyUnderlines, 1, 1);
2093    webViewImpl->confirmComposition(WebWidget::KeepSelection);
2094    info = webViewImpl->textInputInfo();
2095    EXPECT_EQ("testB2", std::string(info.value.utf8().data()));
2096
2097    // (B.3) Unfocused and value is changed by script.
2098    client.reset();
2099    EXPECT_FALSE(client.textIsUpdated());
2100    document->setFocusedElement(nullptr);
2101    webViewImpl->setFocus(false);
2102    EXPECT_NE(document->focusedElement(), static_cast<Element*>(textAreaElement));
2103    inputElement->setValue("testB3");
2104    EXPECT_FALSE(client.textIsUpdated());
2105
2106    // Free the webView before freeing the NonUserInputTextUpdateWebViewClient.
2107    m_webViewHelper.reset();
2108}
2109
2110// Check that the WebAutofillClient is correctly notified about first user
2111// gestures after load, following various input events.
2112TEST_F(WebViewTest, FirstUserGestureObservedKeyEvent)
2113{
2114    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("form.html"));
2115    MockAutofillClient client;
2116    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "form.html", true);
2117    webView->setAutofillClient(&client);
2118    webView->setInitialFocus(false);
2119
2120    EXPECT_EQ(0, client.getUserGestureNotificationsCount());
2121
2122    WebKeyboardEvent keyEvent;
2123    keyEvent.windowsKeyCode = VKEY_SPACE;
2124    keyEvent.type = WebInputEvent::RawKeyDown;
2125    keyEvent.setKeyIdentifierFromWindowsKeyCode();
2126    webView->handleInputEvent(keyEvent);
2127    keyEvent.type = WebInputEvent::KeyUp;
2128    webView->handleInputEvent(keyEvent);
2129
2130    EXPECT_EQ(1, client.getUserGestureNotificationsCount());
2131    webView->setAutofillClient(0);
2132}
2133
2134TEST_F(WebViewTest, FirstUserGestureObservedMouseEvent)
2135{
2136    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("form.html"));
2137    MockAutofillClient client;
2138    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "form.html", true);
2139    webView->setAutofillClient(&client);
2140    webView->setInitialFocus(false);
2141
2142    EXPECT_EQ(0, client.getUserGestureNotificationsCount());
2143
2144    WebMouseEvent mouseEvent;
2145    mouseEvent.button = WebMouseEvent::ButtonLeft;
2146    mouseEvent.x = 1;
2147    mouseEvent.y = 1;
2148    mouseEvent.clickCount = 1;
2149    mouseEvent.type = WebInputEvent::MouseDown;
2150    webView->handleInputEvent(mouseEvent);
2151    mouseEvent.type = WebInputEvent::MouseUp;
2152    webView->handleInputEvent(mouseEvent);
2153
2154    EXPECT_EQ(1, client.getUserGestureNotificationsCount());
2155    webView->setAutofillClient(0);
2156}
2157
2158TEST_F(WebViewTest, FirstUserGestureObservedGestureTap)
2159{
2160    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("longpress_selection.html"));
2161    MockAutofillClient client;
2162    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "longpress_selection.html", true);
2163    webView->setAutofillClient(&client);
2164    webView->setInitialFocus(false);
2165
2166    EXPECT_EQ(0, client.getUserGestureNotificationsCount());
2167
2168    EXPECT_TRUE(tapElementById(webView, WebInputEvent::GestureTap, WebString::fromUTF8("target")));
2169
2170    EXPECT_EQ(1, client.getUserGestureNotificationsCount());
2171    webView->setAutofillClient(0);
2172}
2173
2174TEST_F(WebViewTest, CompareSelectAllToContentAsText)
2175{
2176    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("longpress_selection.html"));
2177    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "longpress_selection.html", true);
2178
2179    WebLocalFrameImpl* frame = toWebLocalFrameImpl(webView->mainFrame());
2180    frame->executeScript(WebScriptSource(WebString::fromUTF8("document.execCommand('SelectAll', false, null)")));
2181    std::string actual = frame->selectionAsText().utf8();
2182
2183    const int kMaxOutputCharacters = 1024;
2184    std::string expected = frame->contentAsText(kMaxOutputCharacters).utf8();
2185    EXPECT_EQ(expected, actual);
2186}
2187
2188TEST_F(WebViewTest, AutoResizeSubtreeLayout)
2189{
2190    std::string url = m_baseURL + "subtree-layout.html";
2191    URLTestHelpers::registerMockedURLLoad(toKURL(url), "subtree-layout.html");
2192    WebView* webView = m_webViewHelper.initialize(true);
2193
2194    webView->enableAutoResizeMode(WebSize(200, 200), WebSize(200, 200));
2195    loadFrame(webView->mainFrame(), url);
2196
2197    FrameView* frameView = m_webViewHelper.webViewImpl()->mainFrameImpl()->frameView();
2198
2199    // Auto-resizing used to ASSERT(needsLayout()) in RenderBlockFlow::layout. This EXPECT is
2200    // merely a dummy. The real test is that we don't trigger asserts in debug builds.
2201    EXPECT_FALSE(frameView->needsLayout());
2202};
2203
2204} // namespace
2205