d519703830f1903e2185e63e1fa7cb90ab0c14ae
[WebKit-https.git] / Source / WebKit / chromium / tests / WebFrameTest.cpp
1 /*
2  * Copyright (C) 2010 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
33 #include "WebFrame.h"
34
35 #include "FloatRect.h"
36 #include "Frame.h"
37 #include "FrameTestHelpers.h"
38 #include "FrameView.h"
39 #include "PlatformContextSkia.h"
40 #include "Range.h"
41 #include "RenderView.h"
42 #include "ResourceError.h"
43 #include "Settings.h"
44 #include "SkBitmap.h"
45 #include "SkCanvas.h"
46 #include "URLTestHelpers.h"
47 #include "WebDataSource.h"
48 #include "WebDocument.h"
49 #include "WebFindOptions.h"
50 #include "WebFormElement.h"
51 #include "WebFrameClient.h"
52 #include "WebFrameImpl.h"
53 #include "WebHistoryItem.h"
54 #include "WebRange.h"
55 #include "WebScriptSource.h"
56 #include "WebSearchableFormData.h"
57 #include "WebSecurityOrigin.h"
58 #include "WebSecurityPolicy.h"
59 #include "WebSettings.h"
60 #include "WebViewClient.h"
61 #include "WebViewImpl.h"
62 #include "v8.h"
63 #include <gtest/gtest.h>
64 #include <public/Platform.h>
65 #include <public/WebFloatRect.h>
66 #include <public/WebThread.h>
67 #include <public/WebURLResponse.h>
68 #include <public/WebUnitTestSupport.h>
69 #include <wtf/Forward.h>
70
71 using namespace WebKit;
72 using WebCore::FloatRect;
73 using WebCore::Range;
74 using WebKit::URLTestHelpers::toKURL;
75 using WebKit::FrameTestHelpers::runPendingTasks;
76
77 namespace {
78
79 #define EXPECT_EQ_RECT(a, b) \
80     EXPECT_EQ(a.x(), b.x()); \
81     EXPECT_EQ(a.y(), b.y()); \
82     EXPECT_EQ(a.width(), b.width()); \
83     EXPECT_EQ(a.height(), b.height());
84
85 class WebFrameTest : public testing::Test {
86 public:
87     WebFrameTest()
88         : m_baseURL("http://www.test.com/")
89         , m_chromeURL("chrome://")
90         , m_webView(0)
91     {
92     }
93
94     virtual ~WebFrameTest()
95     {
96         if (m_webView)
97             m_webView->close();
98     }
99
100     virtual void TearDown()
101     {
102         Platform::current()->unitTestSupport()->unregisterAllMockedURLs();
103     }
104
105     void registerMockedHttpURLLoad(const std::string& fileName)
106     {
107         URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8(fileName.c_str()));
108     }
109
110     void registerMockedChromeURLLoad(const std::string& fileName)
111     {
112         URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_chromeURL.c_str()), WebString::fromUTF8(fileName.c_str()));
113     }
114
115 protected:
116     std::string m_baseURL;
117     std::string m_chromeURL;
118
119     WebView* m_webView;
120 };
121
122 TEST_F(WebFrameTest, ContentText)
123 {
124     registerMockedHttpURLLoad("iframes_test.html");
125     registerMockedHttpURLLoad("visible_iframe.html");
126     registerMockedHttpURLLoad("invisible_iframe.html");
127     registerMockedHttpURLLoad("zero_sized_iframe.html");
128
129     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "iframes_test.html");
130
131     // Now retrieve the frames text and test it only includes visible elements.
132     std::string content = std::string(m_webView->mainFrame()->contentAsText(1024).utf8().data());
133     EXPECT_NE(std::string::npos, content.find(" visible paragraph"));
134     EXPECT_NE(std::string::npos, content.find(" visible iframe"));
135     EXPECT_EQ(std::string::npos, content.find(" invisible pararaph"));
136     EXPECT_EQ(std::string::npos, content.find(" invisible iframe"));
137     EXPECT_EQ(std::string::npos, content.find("iframe with zero size"));
138 }
139
140 TEST_F(WebFrameTest, FrameForEnteredContext)
141 {
142     registerMockedHttpURLLoad("iframes_test.html");
143     registerMockedHttpURLLoad("visible_iframe.html");
144     registerMockedHttpURLLoad("invisible_iframe.html");
145     registerMockedHttpURLLoad("zero_sized_iframe.html");
146
147     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "iframes_test.html", true);
148
149     v8::HandleScope scope;
150     EXPECT_EQ(m_webView->mainFrame(),
151               WebFrame::frameForContext(
152                   m_webView->mainFrame()->mainWorldScriptContext()));
153     EXPECT_EQ(m_webView->mainFrame()->firstChild(),
154               WebFrame::frameForContext(
155                   m_webView->mainFrame()->firstChild()->mainWorldScriptContext()));
156 }
157
158 TEST_F(WebFrameTest, FormWithNullFrame)
159 {
160     registerMockedHttpURLLoad("form.html");
161
162     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "form.html");
163
164     WebVector<WebFormElement> forms;
165     m_webView->mainFrame()->document().forms(forms);
166     m_webView->close();
167     m_webView = 0;
168
169     EXPECT_EQ(forms.size(), 1U);
170
171     // This test passes if this doesn't crash.
172     WebSearchableFormData searchableDataForm(forms[0]);
173 }
174
175 TEST_F(WebFrameTest, ChromePageJavascript)
176 {
177     registerMockedChromeURLLoad("history.html");
178  
179     // Pass true to enable JavaScript.
180     m_webView = FrameTestHelpers::createWebViewAndLoad(m_chromeURL + "history.html", true);
181
182     // Try to run JS against the chrome-style URL.
183     FrameTestHelpers::loadFrame(m_webView->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Clobbered'))");
184
185     // Required to see any updates in contentAsText.
186     m_webView->layout();
187
188     // Now retrieve the frame's text and ensure it was modified by running javascript.
189     std::string content = std::string(m_webView->mainFrame()->contentAsText(1024).utf8().data());
190     EXPECT_NE(std::string::npos, content.find("Clobbered"));
191 }
192
193 TEST_F(WebFrameTest, ChromePageNoJavascript)
194 {
195     registerMockedChromeURLLoad("history.html");
196
197     /// Pass true to enable JavaScript.
198     m_webView = FrameTestHelpers::createWebViewAndLoad(m_chromeURL + "history.html", true);
199
200     // Try to run JS against the chrome-style URL after prohibiting it.
201     WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs("chrome");
202     FrameTestHelpers::loadFrame(m_webView->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Clobbered'))");
203
204     // Required to see any updates in contentAsText.
205     m_webView->layout();
206
207     // Now retrieve the frame's text and ensure it wasn't modified by running javascript.
208     std::string content = std::string(m_webView->mainFrame()->contentAsText(1024).utf8().data());
209     EXPECT_EQ(std::string::npos, content.find("Clobbered"));
210 }
211
212 TEST_F(WebFrameTest, DispatchMessageEventWithOriginCheck)
213 {
214     registerMockedHttpURLLoad("postmessage_test.html");
215
216     // Pass true to enable JavaScript.
217     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "postmessage_test.html", true);
218     
219     // Send a message with the correct origin.
220     WebSecurityOrigin correctOrigin(WebSecurityOrigin::create(toKURL(m_baseURL)));
221     WebDOMEvent event = m_webView->mainFrame()->document().createEvent("MessageEvent");
222     WebDOMMessageEvent message = event.to<WebDOMMessageEvent>();
223     WebSerializedScriptValue data(WebSerializedScriptValue::fromString("foo"));
224     message.initMessageEvent("message", false, false, data, "http://origin.com", 0, "");
225     m_webView->mainFrame()->dispatchMessageEventWithOriginCheck(correctOrigin, message);
226
227     // Send another message with incorrect origin.
228     WebSecurityOrigin incorrectOrigin(WebSecurityOrigin::create(toKURL(m_chromeURL)));
229     m_webView->mainFrame()->dispatchMessageEventWithOriginCheck(incorrectOrigin, message);
230
231     // Required to see any updates in contentAsText.
232     m_webView->layout();
233
234     // Verify that only the first addition is in the body of the page.
235     std::string content = std::string(m_webView->mainFrame()->contentAsText(1024).utf8().data());
236     EXPECT_NE(std::string::npos, content.find("Message 1."));
237     EXPECT_EQ(std::string::npos, content.find("Message 2."));
238 }
239
240 #if ENABLE(VIEWPORT)
241
242 class FixedLayoutTestWebViewClient : public WebViewClient {
243  public:
244     virtual WebScreenInfo screenInfo() OVERRIDE { return m_screenInfo; }
245
246     WebScreenInfo m_screenInfo;
247 };
248
249 TEST_F(WebFrameTest, FrameViewNeedsLayoutOnFixedLayoutResize)
250 {
251     registerMockedHttpURLLoad("fixed_layout.html");
252
253     FixedLayoutTestWebViewClient client;
254     int viewportWidth = 640;
255     int viewportHeight = 480;
256
257     // Make sure we initialize to minimum scale, even if the window size
258     // only becomes available after the load begins.
259     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client);
260     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
261     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
262     m_webView->enableFixedLayoutMode(true);
263     m_webView->settings()->setViewportEnabled(true);
264     m_webView->resize(WebSize(viewportWidth, viewportHeight));
265     m_webView->layout();
266
267     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(m_webView);
268     webViewImpl->mainFrameImpl()->frameView()->setFixedLayoutSize(WebCore::IntSize(100, 100));
269     EXPECT_TRUE(webViewImpl->mainFrameImpl()->frameView()->needsLayout());
270
271     int prevLayoutCount = webViewImpl->mainFrameImpl()->frameView()->layoutCount();
272     webViewImpl->mainFrameImpl()->frameView()->setFrameRect(WebCore::IntRect(0, 0, 641, 481));
273     EXPECT_EQ(prevLayoutCount, webViewImpl->mainFrameImpl()->frameView()->layoutCount());
274
275     webViewImpl->layout();
276 }
277
278 TEST_F(WebFrameTest, DeviceScaleFactorUsesDefaultWithoutViewportTag)
279 {
280     registerMockedHttpURLLoad("no_viewport_tag.html");
281
282     int viewportWidth = 640;
283     int viewportHeight = 480;
284
285     FixedLayoutTestWebViewClient client;
286     client.m_screenInfo.deviceScaleFactor = 2;
287
288     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "no_viewport_tag.html", true, 0, &client);
289
290     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
291     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
292     m_webView->settings()->setViewportEnabled(true);
293     m_webView->enableFixedLayoutMode(true);
294     m_webView->resize(WebSize(viewportWidth, viewportHeight));
295     m_webView->layout();
296
297     EXPECT_EQ(2, m_webView->deviceScaleFactor());
298
299     // Device scale factor should be independent of page scale.
300     m_webView->setPageScaleFactorLimits(1, 2);
301     m_webView->setPageScaleFactorPreservingScrollOffset(0.5);
302     m_webView->layout();
303     EXPECT_EQ(1, m_webView->pageScaleFactor());
304
305     // Force the layout to happen before leaving the test.
306     m_webView->mainFrame()->contentAsText(1024).utf8();
307 }
308
309 TEST_F(WebFrameTest, FixedLayoutInitializeAtMinimumPageScale)
310 {
311     registerMockedHttpURLLoad("fixed_layout.html");
312
313     FixedLayoutTestWebViewClient client;
314     client.m_screenInfo.deviceScaleFactor = 1;
315     int viewportWidth = 640;
316     int viewportHeight = 480;
317
318     // Make sure we initialize to minimum scale, even if the window size
319     // only becomes available after the load begins.
320     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client);
321     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
322     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
323     m_webView->enableFixedLayoutMode(true);
324     m_webView->settings()->setViewportEnabled(true);
325     m_webView->resize(WebSize(viewportWidth, viewportHeight));
326
327     int defaultFixedLayoutWidth = 980;
328     float minimumPageScaleFactor = viewportWidth / (float) defaultFixedLayoutWidth;
329     EXPECT_EQ(minimumPageScaleFactor, m_webView->pageScaleFactor());
330
331     // Assume the user has pinch zoomed to page scale factor 2.
332     float userPinchPageScaleFactor = 2;
333     m_webView->setPageScaleFactorPreservingScrollOffset(userPinchPageScaleFactor);
334     m_webView->layout();
335
336     // Make sure we don't reset to initial scale if the page continues to load.
337     bool isNewNavigation;
338     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(m_webView);
339     webViewImpl ->didCommitLoad(&isNewNavigation, false);
340     webViewImpl ->didChangeContentsSize();
341     EXPECT_EQ(userPinchPageScaleFactor, m_webView->pageScaleFactor());
342
343     // Make sure we don't reset to initial scale if the viewport size changes.
344     m_webView->resize(WebSize(viewportWidth, viewportHeight + 100));
345     EXPECT_EQ(userPinchPageScaleFactor, m_webView->pageScaleFactor());
346 }
347
348 TEST_F(WebFrameTest, ScaleFactorShouldNotOscillate)
349 {
350     registerMockedHttpURLLoad("scale_oscillate.html");
351
352     FixedLayoutTestWebViewClient client;
353     client.m_screenInfo.deviceScaleFactor = static_cast<float>(1.325);
354     int viewportWidth = 800;
355     int viewportHeight = 1057;
356
357     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "scale_oscillate.html", true, 0, &client);
358     m_webView->enableFixedLayoutMode(true);
359     m_webView->settings()->setViewportEnabled(true);
360     m_webView->resize(WebSize(viewportWidth, viewportHeight));
361     m_webView->layout();
362 }
363
364 TEST_F(WebFrameTest, setPageScaleFactorDoesNotLayout)
365 {
366     registerMockedHttpURLLoad("fixed_layout.html");
367
368     FixedLayoutTestWebViewClient client;
369     client.m_screenInfo.deviceScaleFactor = 1;
370     int viewportWidth = 640;
371     int viewportHeight = 480;
372
373     m_webView = static_cast<WebViewImpl*>(FrameTestHelpers::createWebViewAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client));
374     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
375     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
376     m_webView->enableFixedLayoutMode(true);
377     m_webView->settings()->setViewportEnabled(true);
378     m_webView->resize(WebSize(viewportWidth, viewportHeight));
379     m_webView->layout();
380
381     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(m_webView);
382     int prevLayoutCount = webViewImpl->mainFrameImpl()->frameView()->layoutCount();
383     webViewImpl->setPageScaleFactor(3, WebPoint());
384     EXPECT_FALSE(webViewImpl->mainFrameImpl()->frameView()->needsLayout());
385     EXPECT_EQ(prevLayoutCount, webViewImpl->mainFrameImpl()->frameView()->layoutCount());
386 }
387
388 TEST_F(WebFrameTest, pageScaleFactorWrittenToHistoryItem)
389 {
390     registerMockedHttpURLLoad("fixed_layout.html");
391
392     FixedLayoutTestWebViewClient client;
393     client.m_screenInfo.deviceScaleFactor = 1;
394     int viewportWidth = 640;
395     int viewportHeight = 480;
396
397     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client);
398     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
399     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
400     m_webView->enableFixedLayoutMode(true);
401     m_webView->settings()->setViewportEnabled(true);
402     m_webView->resize(WebSize(viewportWidth, viewportHeight));
403     m_webView->layout();
404
405     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(m_webView);
406     m_webView->setPageScaleFactor(3, WebPoint());
407     webViewImpl->page()->mainFrame()->loader()->history()->saveDocumentAndScrollState();
408     m_webView->setPageScaleFactor(1, WebPoint());
409     webViewImpl->page()->mainFrame()->loader()->history()->restoreScrollPositionAndViewState();
410     EXPECT_EQ(3, m_webView->pageScaleFactor());
411 }
412
413 TEST_F(WebFrameTest, pageScaleFactorShrinksViewport)
414 {
415     registerMockedHttpURLLoad("fixed_layout.html");
416
417     FixedLayoutTestWebViewClient client;
418     client.m_screenInfo.deviceScaleFactor = 1;
419     int viewportWidth = 640;
420     int viewportHeight = 480;
421
422     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client);
423     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
424     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
425     m_webView->enableFixedLayoutMode(true);
426     m_webView->settings()->setViewportEnabled(true);
427     m_webView->resize(WebSize(viewportWidth, viewportHeight));
428     m_webView->layout();
429
430     WebCore::FrameView* view = static_cast<WebViewImpl*>(m_webView)->mainFrameImpl()->frameView();
431     int viewportWidthMinusScrollbar = 640 - (view->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
432     int viewportHeightMinusScrollbar = 480 - (view->horizontalScrollbar()->isOverlayScrollbar() ? 0 : 15);
433
434     m_webView->setPageScaleFactor(2, WebPoint());
435
436     WebCore::IntSize unscaledSize = view->unscaledVisibleContentSize(true);
437     EXPECT_EQ(viewportWidth, unscaledSize.width());
438     EXPECT_EQ(viewportHeight, unscaledSize.height());
439
440     WebCore::IntSize unscaledSizeMinusScrollbar = view->unscaledVisibleContentSize(false);
441     EXPECT_EQ(viewportWidthMinusScrollbar, unscaledSizeMinusScrollbar.width());
442     EXPECT_EQ(viewportHeightMinusScrollbar, unscaledSizeMinusScrollbar.height());
443
444     WebCore::IntSize scaledSize = view->visibleContentRect().size();
445     EXPECT_EQ(ceil(viewportWidthMinusScrollbar / 2.0), scaledSize.width());
446     EXPECT_EQ(ceil(viewportHeightMinusScrollbar / 2.0), scaledSize.height());
447 }
448
449 TEST_F(WebFrameTest, pageScaleFactorDoesNotApplyCssTransform)
450 {
451     registerMockedHttpURLLoad("fixed_layout.html");
452
453     FixedLayoutTestWebViewClient client;
454     client.m_screenInfo.deviceScaleFactor = 1;
455     int viewportWidth = 640;
456     int viewportHeight = 480;
457
458     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client);
459     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
460     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
461     m_webView->enableFixedLayoutMode(true);
462     m_webView->settings()->setViewportEnabled(true);
463     m_webView->resize(WebSize(viewportWidth, viewportHeight));
464     m_webView->layout();
465
466     m_webView->setPageScaleFactor(2, WebPoint());
467
468     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(m_webView);
469     EXPECT_EQ(1, webViewImpl->page()->mainFrame()->frameScaleFactor());
470     EXPECT_EQ(980, webViewImpl->page()->mainFrame()->contentRenderer()->unscaledDocumentRect().width());
471     EXPECT_EQ(980, webViewImpl->mainFrameImpl()->frameView()->contentsSize().width());
472 }
473 #endif
474
475 TEST_F(WebFrameTest, pageScaleFactorScalesPaintClip)
476 {
477     registerMockedHttpURLLoad("fixed_layout.html");
478
479     FixedLayoutTestWebViewClient client;
480     client.m_screenInfo.deviceScaleFactor = 1;
481     int viewportWidth = 50;
482     int viewportHeight = 50;
483
484     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client);
485     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
486     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
487     m_webView->enableFixedLayoutMode(true);
488     m_webView->settings()->setViewportEnabled(true);
489     m_webView->resize(WebSize(viewportWidth, viewportHeight));
490     m_webView->layout();
491
492     // Set <1 page scale so that the clip rect should be larger than
493     // the viewport size as passed into resize().
494     m_webView->setPageScaleFactor(0.5, WebPoint());
495
496     SkBitmap bitmap;
497     bitmap.setConfig(SkBitmap::kARGB_8888_Config, 200, 200);
498     bitmap.allocPixels();
499     bitmap.eraseColor(0);
500     SkCanvas canvas(bitmap);
501
502     WebCore::PlatformContextSkia platformContext(&canvas);
503     platformContext.setTrackOpaqueRegion(true);
504     WebCore::GraphicsContext context(&platformContext);
505
506     EXPECT_EQ_RECT(WebCore::IntRect(0, 0, 0, 0), platformContext.opaqueRegion().asRect());
507
508     WebCore::FrameView* view = static_cast<WebViewImpl*>(m_webView)->mainFrameImpl()->frameView();
509     WebCore::IntRect paintRect(0, 0, 200, 200);
510     view->paint(&context, paintRect);
511
512     int viewportWidthMinusScrollbar = 50 - (view->verticalScrollbar()->isOverlayScrollbar() ? 0 : 15);
513     int viewportHeightMinusScrollbar = 50 - (view->horizontalScrollbar()->isOverlayScrollbar() ? 0 : 15);
514     WebCore::IntRect clippedRect(0, 0, viewportWidthMinusScrollbar * 2, viewportHeightMinusScrollbar * 2);
515     EXPECT_EQ_RECT(clippedRect, platformContext.opaqueRegion().asRect());
516 }
517
518 TEST_F(WebFrameTest, CanOverrideMaximumScaleFactor)
519 {
520     registerMockedHttpURLLoad("no_scale_for_you.html");
521
522     FixedLayoutTestWebViewClient client;
523     client.m_screenInfo.deviceScaleFactor = 1;
524     int viewportWidth = 640;
525     int viewportHeight = 480;
526
527     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "no_scale_for_you.html", true, 0, &client);
528     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
529     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
530     m_webView->enableFixedLayoutMode(true);
531     m_webView->settings()->setViewportEnabled(true);
532     m_webView->resize(WebSize(viewportWidth, viewportHeight));
533
534     EXPECT_EQ(1.0f, m_webView->maximumPageScaleFactor());
535
536     m_webView->setIgnoreViewportTagMaximumScale(true);
537     m_webView->layout();
538
539     EXPECT_EQ(4.0f, m_webView->maximumPageScaleFactor());
540 }
541
542 #if ENABLE(GESTURE_EVENTS)
543 void setScaleAndScrollAndLayout(WebKit::WebView* webView, WebPoint scroll, float scale)
544 {
545     webView->setPageScaleFactor(scale, WebPoint(scroll.x, scroll.y));
546     webView->layout();
547 }
548
549 TEST_F(WebFrameTest, DivAutoZoomParamsTestCompositorScaling)
550 {
551     registerMockedHttpURLLoad("get_scale_for_auto_zoom_into_div_test.html");
552
553     const float deviceScaleFactor = 2.0f;
554     int viewportWidth = 640 / deviceScaleFactor;
555     int viewportHeight = 1280 / deviceScaleFactor;
556     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "get_scale_for_auto_zoom_into_div_test.html"); //
557     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
558     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
559     m_webView->setDeviceScaleFactor(deviceScaleFactor);
560     m_webView->setPageScaleFactorLimits(0.01f, 4);
561     m_webView->setPageScaleFactor(0.5f, WebPoint(0, 0));
562     m_webView->resize(WebSize(viewportWidth, viewportHeight));
563     m_webView->enableFixedLayoutMode(true);
564     m_webView->layout();
565
566     WebRect wideDiv(200, 100, 400, 150);
567     WebRect tallDiv(200, 300, 400, 800);
568     WebRect doubleTapPointWide(wideDiv.x + 50, wideDiv.y + 50, 0, 0);
569     WebRect doubleTapPointTall(tallDiv.x + 50, tallDiv.y + 50, 0, 0);
570     float scale;
571     WebPoint scroll;
572     bool isAnchor;
573
574     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(m_webView);
575     // Test double-tap zooming into wide div.
576     webViewImpl->computeScaleAndScrollForHitRect(doubleTapPointWide, WebViewImpl::DoubleTap, scale, scroll, isAnchor);
577     // The div should horizontally fill the screen (modulo margins), and
578     // vertically centered (modulo integer rounding).
579     EXPECT_NEAR(viewportWidth / (float) wideDiv.width, scale, 0.1);
580     EXPECT_NEAR(wideDiv.x, scroll.x, 20);
581     EXPECT_EQ(0, scroll.y);
582     EXPECT_FALSE(isAnchor);
583
584     setScaleAndScrollAndLayout(webViewImpl, scroll, scale);
585
586     // Test zoom out back to minimum scale.
587     webViewImpl->computeScaleAndScrollForHitRect(doubleTapPointWide, WebViewImpl::DoubleTap, scale, scroll, isAnchor);
588     EXPECT_FLOAT_EQ(webViewImpl->minimumPageScaleFactor(), scale);
589     EXPECT_TRUE(isAnchor);
590
591     setScaleAndScrollAndLayout(webViewImpl, WebPoint(0, 0), scale);
592
593     // Test double-tap zooming into tall div.
594     webViewImpl->computeScaleAndScrollForHitRect(doubleTapPointTall, WebViewImpl::DoubleTap, scale, scroll, isAnchor);
595     // The div should start at the top left of the viewport.
596     EXPECT_NEAR(viewportWidth / (float) tallDiv.width, scale, 0.1);
597     EXPECT_NEAR(tallDiv.x, scroll.x, 20);
598     EXPECT_NEAR(tallDiv.y, scroll.y, 20);
599     EXPECT_FALSE(isAnchor);
600
601     // Test for Non-doubletap scaling
602     // Test zooming into div.
603     webViewImpl->computeScaleAndScrollForHitRect(WebRect(250, 250, 10, 10), WebViewImpl::FindInPage, scale, scroll, isAnchor);
604     EXPECT_NEAR(viewportWidth / (float) wideDiv.width, scale, 0.1);
605 }
606
607 void simulateDoubleTap(WebViewImpl* webViewImpl, WebPoint& point, float& scale)
608 {
609     webViewImpl->animateZoomAroundPoint(point, WebViewImpl::DoubleTap);
610     webViewImpl->mainFrameImpl()->frameView()->layout();
611     scale = webViewImpl->pageScaleFactor();
612 }
613
614 TEST_F(WebFrameTest, DivAutoZoomMultipleDivsTestCompositorScaling)
615 {
616     registerMockedHttpURLLoad("get_multiple_divs_for_auto_zoom_test.html");
617
618     const float deviceScaleFactor = 2.0f;
619     int viewportWidth = 640 / deviceScaleFactor;
620     int viewportHeight = 1280 / deviceScaleFactor;
621     float doubleTapZoomAlreadyLegibleRatio = 1.2f;
622     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "get_multiple_divs_for_auto_zoom_test.html");
623     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
624     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
625     m_webView->enableFixedLayoutMode(true);
626     m_webView->resize(WebSize(viewportWidth, viewportHeight));
627     m_webView->setPageScaleFactorLimits(0.5f, 4);
628     m_webView->setDeviceScaleFactor(deviceScaleFactor);
629     m_webView->setPageScaleFactor(0.5f, WebPoint(0, 0));
630     m_webView->layout();
631
632     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(m_webView);
633     webViewImpl->shouldUseAnimateDoubleTapTimeZeroForTesting(true);
634
635     WebRect topDiv(200, 100, 200, 150);
636     WebRect bottomDiv(200, 300, 200, 150);
637     WebPoint topPoint(topDiv.x + 50, topDiv.y + 50);
638     WebPoint bottomPoint(bottomDiv.x + 50, bottomDiv.y + 50);
639     float scale;
640     setScaleAndScrollAndLayout(webViewImpl, WebPoint(0, 0), (webViewImpl->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
641
642     // Test double tap on two different divs
643     // After first zoom, we should go back to minimum page scale with a second double tap.
644     simulateDoubleTap(webViewImpl, topPoint, scale);
645     EXPECT_FLOAT_EQ(1, scale);
646     simulateDoubleTap(webViewImpl, bottomPoint, scale);
647     EXPECT_FLOAT_EQ(webViewImpl->minimumPageScaleFactor(), scale);
648
649     // If the user pinch zooms after double tap, a second double tap should zoom back to the div.
650     simulateDoubleTap(webViewImpl, topPoint, scale);
651     EXPECT_FLOAT_EQ(1, scale);
652     webViewImpl->applyScrollAndScale(WebSize(), 0.6f);
653     simulateDoubleTap(webViewImpl, bottomPoint, scale);
654     EXPECT_FLOAT_EQ(1, scale);
655 }
656
657 TEST_F(WebFrameTest, DivAutoZoomScaleBoundsTestCompositorScaling)
658 {
659     registerMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html");
660
661     int viewportWidth = 320;
662     int viewportHeight = 480;
663     float doubleTapZoomAlreadyLegibleRatio = 1.2f;
664     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "get_scale_bounds_check_for_auto_zoom_test.html");
665     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
666     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
667     m_webView->enableFixedLayoutMode(true);
668     m_webView->resize(WebSize(viewportWidth, viewportHeight));
669     m_webView->setDeviceScaleFactor(1.5f);
670     m_webView->layout();
671
672     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(m_webView);
673     webViewImpl->shouldUseAnimateDoubleTapTimeZeroForTesting(true);
674
675     WebRect div(200, 100, 200, 150);
676     WebPoint doubleTapPoint(div.x + 50, div.y + 50);
677     float scale;
678
679     // Test double tap scale bounds.
680     // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1
681     m_webView->setPageScaleFactorLimits(0.5f, 4);
682     m_webView->layout();
683     float doubleTapZoomAlreadyLegibleScale = webViewImpl->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
684     setScaleAndScrollAndLayout(webViewImpl, WebPoint(0, 0), (webViewImpl->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
685     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
686     EXPECT_FLOAT_EQ(1, scale);
687     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
688     EXPECT_FLOAT_EQ(webViewImpl->minimumPageScaleFactor(), scale);
689     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
690     EXPECT_FLOAT_EQ(1, scale);
691
692     // Zoom in to reset double_tap_zoom_in_effect flag.
693     webViewImpl->applyScrollAndScale(WebSize(), 1.1f);
694     // 1 < minimumPageScale < doubleTapZoomAlreadyLegibleScale
695     m_webView->setPageScaleFactorLimits(1.1f, 4);
696     m_webView->layout();
697     doubleTapZoomAlreadyLegibleScale = webViewImpl->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
698     setScaleAndScrollAndLayout(webViewImpl, WebPoint(0, 0), (webViewImpl->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
699     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
700     EXPECT_FLOAT_EQ(webViewImpl->minimumPageScaleFactor(), scale);
701     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
702     EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
703     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
704     EXPECT_FLOAT_EQ(webViewImpl->minimumPageScaleFactor(), scale);
705
706     // Zoom in to reset double_tap_zoom_in_effect flag.
707     webViewImpl->applyScrollAndScale(WebSize(), 1.1f);
708     // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale
709     m_webView->setPageScaleFactorLimits(0.95f, 4);
710     m_webView->layout();
711     doubleTapZoomAlreadyLegibleScale = webViewImpl->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
712     setScaleAndScrollAndLayout(webViewImpl, WebPoint(0, 0), (webViewImpl->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
713     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
714     EXPECT_FLOAT_EQ(webViewImpl->minimumPageScaleFactor(), scale);
715     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
716     EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
717     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
718     EXPECT_FLOAT_EQ(webViewImpl->minimumPageScaleFactor(), scale);
719 }
720
721 #if ENABLE(TEXT_AUTOSIZING)
722 TEST_F(WebFrameTest, DivAutoZoomScaleFontScaleFactorTestCompositorScaling)
723 {
724     registerMockedHttpURLLoad("get_scale_bounds_check_for_auto_zoom_test.html");
725
726     int viewportWidth = 320;
727     int viewportHeight = 480;
728     float doubleTapZoomAlreadyLegibleRatio = 1.2f;
729     float textAutosizingFontScaleFactor = 1.13f;
730     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "get_scale_bounds_check_for_auto_zoom_test.html");
731     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
732     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
733     m_webView->enableFixedLayoutMode(true);
734     m_webView->resize(WebSize(viewportWidth, viewportHeight));
735     m_webView->layout();
736
737     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(m_webView);
738     webViewImpl->shouldUseAnimateDoubleTapTimeZeroForTesting(true);
739     webViewImpl->page()->settings()->setTextAutosizingFontScaleFactor(textAutosizingFontScaleFactor);
740
741     WebRect div(200, 100, 200, 150);
742     WebPoint doubleTapPoint(div.x + 50, div.y + 50);
743     float scale;
744
745     // Test double tap scale bounds.
746     // minimumPageScale < doubleTapZoomAlreadyLegibleScale < 1 < textAutosizingFontScaleFactor
747     float legibleScale = textAutosizingFontScaleFactor;
748     setScaleAndScrollAndLayout(webViewImpl, WebPoint(0, 0), (webViewImpl->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
749     float doubleTapZoomAlreadyLegibleScale = webViewImpl->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
750     m_webView->setPageScaleFactorLimits(0.5f, 4);
751     m_webView->layout();
752     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
753     EXPECT_FLOAT_EQ(legibleScale, scale);
754     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
755     EXPECT_FLOAT_EQ(webViewImpl->minimumPageScaleFactor(), scale);
756     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
757     EXPECT_FLOAT_EQ(legibleScale, scale);
758
759     // Zoom in to reset double_tap_zoom_in_effect flag.
760     webViewImpl->applyScrollAndScale(WebSize(), 1.1f);
761     // 1 < textAutosizingFontScaleFactor < minimumPageScale < doubleTapZoomAlreadyLegibleScale
762     m_webView->setPageScaleFactorLimits(1.0f, 4);
763     m_webView->layout();
764     doubleTapZoomAlreadyLegibleScale = webViewImpl->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
765     setScaleAndScrollAndLayout(webViewImpl, WebPoint(0, 0), (webViewImpl->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
766     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
767     EXPECT_FLOAT_EQ(webViewImpl->minimumPageScaleFactor(), scale);
768     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
769     EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
770     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
771     EXPECT_FLOAT_EQ(webViewImpl->minimumPageScaleFactor(), scale);
772
773     // Zoom in to reset double_tap_zoom_in_effect flag.
774     webViewImpl->applyScrollAndScale(WebSize(), 1.1f);
775     // minimumPageScale < 1 < textAutosizingFontScaleFactor < doubleTapZoomAlreadyLegibleScale
776     m_webView->setPageScaleFactorLimits(0.95f, 4);
777     m_webView->layout();
778     doubleTapZoomAlreadyLegibleScale = webViewImpl->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
779     setScaleAndScrollAndLayout(webViewImpl, WebPoint(0, 0), (webViewImpl->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
780     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
781     EXPECT_FLOAT_EQ(webViewImpl->minimumPageScaleFactor(), scale);
782     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
783     EXPECT_FLOAT_EQ(doubleTapZoomAlreadyLegibleScale, scale);
784     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
785     EXPECT_FLOAT_EQ(webViewImpl->minimumPageScaleFactor(), scale);
786
787     // Zoom in to reset double_tap_zoom_in_effect flag.
788     webViewImpl->applyScrollAndScale(WebSize(), 1.1f);
789     // minimumPageScale < 1 < doubleTapZoomAlreadyLegibleScale < textAutosizingFontScaleFactor
790     m_webView->setPageScaleFactorLimits(0.9f, 4);
791     m_webView->layout();
792     doubleTapZoomAlreadyLegibleScale = webViewImpl->minimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio;
793     setScaleAndScrollAndLayout(webViewImpl, WebPoint(0, 0), (webViewImpl->minimumPageScaleFactor()) * (1 + doubleTapZoomAlreadyLegibleRatio) / 2);
794     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
795     EXPECT_FLOAT_EQ(legibleScale, scale);
796     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
797     EXPECT_FLOAT_EQ(webViewImpl->minimumPageScaleFactor(), scale);
798     simulateDoubleTap(webViewImpl, doubleTapPoint, scale);
799     EXPECT_FLOAT_EQ(legibleScale, scale);
800 }
801 #endif
802
803 TEST_F(WebFrameTest, DivScrollIntoEditableTest)
804 {
805     registerMockedHttpURLLoad("get_scale_for_zoom_into_editable_test.html");
806
807     int viewportWidth = 450;
808     int viewportHeight = 300;
809     float leftBoxRatio = 0.3f;
810     int caretPadding = 10;
811     float minReadableCaretHeight = 18.0f;
812     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "get_scale_for_zoom_into_editable_test.html");
813     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
814     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
815     m_webView->enableFixedLayoutMode(true);
816     m_webView->resize(WebSize(viewportWidth, viewportHeight));
817     m_webView->setPageScaleFactorLimits(1, 4);
818     m_webView->layout();
819     m_webView->setDeviceScaleFactor(1.5f);
820     m_webView->settings()->setAutoZoomFocusedNodeToLegibleScale(true);
821
822     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(m_webView);
823     webViewImpl->shouldUseAnimateDoubleTapTimeZeroForTesting(true);
824
825     WebRect editBoxWithText(200, 200, 250, 20);
826     WebRect editBoxWithNoText(200, 250, 250, 20);
827
828     // Test scrolling the focused node
829     // The edit box is shorter and narrower than the viewport when legible.
830     m_webView->advanceFocus(false);
831     // Set the caret to the end of the input box.
832     m_webView->mainFrame()->document().getElementById("EditBoxWithText").to<WebInputElement>().setSelectionRange(1000, 1000);
833     setScaleAndScrollAndLayout(m_webView, WebPoint(0, 0), 1);
834     WebRect rect, caret;
835     webViewImpl->selectionBounds(caret, rect);
836
837     float scale;
838     WebCore::IntPoint scroll;
839     bool needAnimation;
840     webViewImpl->computeScaleAndScrollForFocusedNode(webViewImpl->focusedWebCoreNode(), scale, scroll, needAnimation);
841     EXPECT_TRUE(needAnimation);
842     // The edit box should be left aligned with a margin for possible label.
843     int hScroll = editBoxWithText.x - leftBoxRatio * viewportWidth / scale;
844     EXPECT_NEAR(hScroll, scroll.x(), 1);
845     int vScroll = editBoxWithText.y - (viewportHeight / scale - editBoxWithText.height) / 2;
846     EXPECT_NEAR(vScroll, scroll.y(), 1);
847     EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1);
848
849     // The edit box is wider than the viewport when legible.
850     viewportWidth = 200;
851     viewportHeight = 150;
852     m_webView->resize(WebSize(viewportWidth, viewportHeight));
853     setScaleAndScrollAndLayout(m_webView, WebPoint(0, 0), 1);
854     webViewImpl->selectionBounds(caret, rect);
855     webViewImpl->computeScaleAndScrollForFocusedNode(webViewImpl->focusedWebCoreNode(), scale, scroll, needAnimation);
856     EXPECT_TRUE(needAnimation);
857     // The caret should be right aligned since the caret would be offscreen when the edit box is left aligned.
858     hScroll = caret.x + caret.width + caretPadding - viewportWidth / scale;
859     EXPECT_NEAR(hScroll, scroll.x(), 1);
860     EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1);
861
862     setScaleAndScrollAndLayout(m_webView, WebPoint(0, 0), 1);
863     // Move focus to edit box with text.
864     m_webView->advanceFocus(false);
865     webViewImpl->selectionBounds(caret, rect);
866     webViewImpl->computeScaleAndScrollForFocusedNode(webViewImpl->focusedWebCoreNode(), scale, scroll, needAnimation);
867     EXPECT_TRUE(needAnimation);
868     // The edit box should be left aligned.
869     hScroll = editBoxWithNoText.x;
870     EXPECT_NEAR(hScroll, scroll.x(), 1);
871     vScroll = editBoxWithNoText.y - (viewportHeight / scale - editBoxWithNoText.height) / 2;
872     EXPECT_NEAR(vScroll, scroll.y(), 1);
873     EXPECT_NEAR(minReadableCaretHeight / caret.height, scale, 0.1);
874
875     setScaleAndScrollAndLayout(webViewImpl, scroll, scale);
876
877     // Move focus back to the first edit box.
878     m_webView->advanceFocus(true);
879     webViewImpl->computeScaleAndScrollForFocusedNode(webViewImpl->focusedWebCoreNode(), scale, scroll, needAnimation);
880     // The position should have stayed the same since this box was already on screen with the right scale.
881     EXPECT_FALSE(needAnimation);
882 }
883
884 #endif
885
886 class TestReloadDoesntRedirectWebFrameClient : public WebFrameClient {
887 public:
888     virtual WebNavigationPolicy decidePolicyForNavigation(
889         WebFrame*, const WebURLRequest&, WebNavigationType,
890         const WebNode& originatingNode,
891         WebNavigationPolicy defaultPolicy, bool isRedirect)
892     {
893         EXPECT_FALSE(isRedirect);
894         return WebNavigationPolicyCurrentTab;
895     }
896
897     virtual WebURLError cancelledError(WebFrame*, const WebURLRequest& request)
898     {
899         // Return a dummy error so the DocumentLoader doesn't assert when
900         // the reload cancels it.
901         WebURLError webURLError;
902         webURLError.domain = "";
903         webURLError.reason = 1;
904         webURLError.isCancellation = true;
905         webURLError.unreachableURL = WebURL();
906         return webURLError;
907     }
908 };
909
910 TEST_F(WebFrameTest, ReloadDoesntSetRedirect)
911 {
912     // Test for case in http://crbug.com/73104. Reloading a frame very quickly
913     // would sometimes call decidePolicyForNavigation with isRedirect=true
914     registerMockedHttpURLLoad("form.html");
915
916     TestReloadDoesntRedirectWebFrameClient webFrameClient;
917     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "form.html", false, &webFrameClient);
918
919     m_webView->mainFrame()->reload(true);
920     // start reload before request is delivered.
921     m_webView->mainFrame()->reload(true);
922     Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
923
924     m_webView->close();
925     m_webView = 0;
926 }
927
928 TEST_F(WebFrameTest, ReloadWithOverrideURLPreservesState)
929 {
930     const std::string firstURL = "find.html";
931     const std::string secondURL = "form.html";
932     const std::string thirdURL = "history.html";
933     const float pageScaleFactor = 1.1684f;
934     const int pageWidth = 640;
935     const int pageHeight = 480;
936
937     registerMockedHttpURLLoad(firstURL);
938     registerMockedHttpURLLoad(secondURL);
939     registerMockedHttpURLLoad(thirdURL);
940
941     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + firstURL, true);
942     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(m_webView);
943     webViewImpl->resize(WebSize(pageWidth, pageHeight));
944     webViewImpl->mainFrame()->setScrollOffset(WebSize(pageWidth / 4, pageHeight / 4));
945     webViewImpl->setPageScaleFactorPreservingScrollOffset(pageScaleFactor);
946
947     WebSize previousOffset = webViewImpl->mainFrame()->scrollOffset();
948     float previousScale = webViewImpl->pageScaleFactor();
949
950     // Reload the page using the cache.
951     webViewImpl->mainFrame()->reloadWithOverrideURL(toKURL(m_baseURL + secondURL), false);
952     Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
953     ASSERT_EQ(previousOffset, webViewImpl->mainFrame()->scrollOffset());
954     ASSERT_EQ(previousScale, webViewImpl->pageScaleFactor());
955
956     // Reload the page while ignoring the cache.
957     webViewImpl->mainFrame()->reloadWithOverrideURL(toKURL(m_baseURL + thirdURL), true);
958     Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
959     ASSERT_EQ(previousOffset, webViewImpl->mainFrame()->scrollOffset());
960     ASSERT_EQ(previousScale, webViewImpl->pageScaleFactor());
961 }
962
963 TEST_F(WebFrameTest, IframeRedirect)
964 {
965     registerMockedHttpURLLoad("iframe_redirect.html");
966     registerMockedHttpURLLoad("visible_iframe.html");
967
968     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "iframe_redirect.html", true);
969     Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests(); // Load the iframe.
970
971     WebFrame* iframe = m_webView->findFrameByName(WebString::fromUTF8("ifr"));
972     ASSERT_TRUE(iframe);
973     WebDataSource* iframeDataSource = iframe->dataSource();
974     ASSERT_TRUE(iframeDataSource);
975     WebVector<WebURL> redirects;
976     iframeDataSource->redirectChain(redirects);
977     ASSERT_EQ(2U, redirects.size());
978     EXPECT_EQ(toKURL("about:blank"), toKURL(redirects[0].spec().data()));
979     EXPECT_EQ(toKURL("http://www.test.com/visible_iframe.html"), toKURL(redirects[1].spec().data()));
980 }
981
982 TEST_F(WebFrameTest, ClearFocusedNodeTest)
983 {
984     registerMockedHttpURLLoad("iframe_clear_focused_node_test.html");
985     registerMockedHttpURLLoad("autofocus_input_field_iframe.html");
986
987     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "iframe_clear_focused_node_test.html", true);
988
989     // Clear the focused node.
990     m_webView->clearFocusedNode();
991
992     // Now retrieve the FocusedNode and test it should be null.
993     EXPECT_EQ(0, static_cast<WebViewImpl*>(m_webView)->focusedWebCoreNode());
994 }
995
996 // Implementation of WebFrameClient that tracks the v8 contexts that are created
997 // and destroyed for verification.
998 class ContextLifetimeTestWebFrameClient : public WebFrameClient {
999 public:
1000     struct Notification {
1001     public:
1002         Notification(WebFrame* frame, v8::Handle<v8::Context> context, int worldId)
1003             : frame(frame)
1004             , context(v8::Persistent<v8::Context>::New(context->GetIsolate(), context))
1005             , worldId(worldId)
1006         {
1007         }
1008
1009         ~Notification()
1010         {
1011             context.Dispose(context->GetIsolate());
1012         }
1013
1014         bool Equals(Notification* other)
1015         {
1016             return other && frame == other->frame && context == other->context && worldId == other->worldId;
1017         }
1018
1019         WebFrame* frame;
1020         v8::Persistent<v8::Context> context;
1021         int worldId;
1022     };
1023
1024     virtual ~ContextLifetimeTestWebFrameClient()
1025     {
1026         reset();
1027     }
1028
1029     void reset()
1030     {
1031         for (size_t i = 0; i < createNotifications.size(); ++i)
1032             delete createNotifications[i];
1033
1034         for (size_t i = 0; i < releaseNotifications.size(); ++i)
1035             delete releaseNotifications[i];
1036
1037         createNotifications.clear();
1038         releaseNotifications.clear();
1039     }
1040
1041     std::vector<Notification*> createNotifications;
1042     std::vector<Notification*> releaseNotifications;
1043
1044  private:
1045     virtual void didCreateScriptContext(WebFrame* frame, v8::Handle<v8::Context> context, int extensionGroup, int worldId) OVERRIDE
1046     {
1047         createNotifications.push_back(new Notification(frame, context, worldId));
1048     }
1049
1050     virtual void willReleaseScriptContext(WebFrame* frame, v8::Handle<v8::Context> context, int worldId) OVERRIDE
1051     {
1052         releaseNotifications.push_back(new Notification(frame, context, worldId));
1053     }
1054 };
1055
1056 TEST_F(WebFrameTest, ContextNotificationsLoadUnload)
1057 {
1058     v8::HandleScope handleScope;
1059
1060     registerMockedHttpURLLoad("context_notifications_test.html");
1061     registerMockedHttpURLLoad("context_notifications_test_frame.html");
1062
1063     // Load a frame with an iframe, make sure we get the right create notifications.
1064     ContextLifetimeTestWebFrameClient webFrameClient;
1065     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
1066
1067     WebFrame* mainFrame = m_webView->mainFrame();
1068     WebFrame* childFrame = mainFrame->firstChild();
1069
1070     ASSERT_EQ(2u, webFrameClient.createNotifications.size());
1071     EXPECT_EQ(0u, webFrameClient.releaseNotifications.size());
1072
1073     ContextLifetimeTestWebFrameClient::Notification* firstCreateNotification = webFrameClient.createNotifications[0];
1074     ContextLifetimeTestWebFrameClient::Notification* secondCreateNotification = webFrameClient.createNotifications[1];
1075
1076     EXPECT_EQ(mainFrame, firstCreateNotification->frame);
1077     EXPECT_EQ(mainFrame->mainWorldScriptContext(), firstCreateNotification->context);
1078     EXPECT_EQ(0, firstCreateNotification->worldId);
1079
1080     EXPECT_EQ(childFrame, secondCreateNotification->frame);
1081     EXPECT_EQ(childFrame->mainWorldScriptContext(), secondCreateNotification->context);
1082     EXPECT_EQ(0, secondCreateNotification->worldId);
1083
1084     // Close the view. We should get two release notifications that are exactly the same as the create ones, in reverse order.
1085     m_webView->close();
1086     m_webView = 0;
1087
1088     ASSERT_EQ(2u, webFrameClient.releaseNotifications.size());
1089     ContextLifetimeTestWebFrameClient::Notification* firstReleaseNotification = webFrameClient.releaseNotifications[0];
1090     ContextLifetimeTestWebFrameClient::Notification* secondReleaseNotification = webFrameClient.releaseNotifications[1];
1091
1092     ASSERT_TRUE(firstCreateNotification->Equals(secondReleaseNotification));
1093     ASSERT_TRUE(secondCreateNotification->Equals(firstReleaseNotification));
1094 }
1095
1096 TEST_F(WebFrameTest, ContextNotificationsReload)
1097 {
1098     v8::HandleScope handleScope;
1099
1100     registerMockedHttpURLLoad("context_notifications_test.html");
1101     registerMockedHttpURLLoad("context_notifications_test_frame.html");
1102
1103     ContextLifetimeTestWebFrameClient webFrameClient;
1104     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
1105
1106     // Refresh, we should get two release notifications and two more create notifications.
1107     m_webView->mainFrame()->reload(false);
1108     Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
1109     ASSERT_EQ(4u, webFrameClient.createNotifications.size());
1110     ASSERT_EQ(2u, webFrameClient.releaseNotifications.size());
1111
1112     // The two release notifications we got should be exactly the same as the first two create notifications.
1113     for (size_t i = 0; i < webFrameClient.releaseNotifications.size(); ++i) {
1114       EXPECT_TRUE(webFrameClient.releaseNotifications[i]->Equals(
1115           webFrameClient.createNotifications[webFrameClient.createNotifications.size() - 3 - i]));
1116     }
1117
1118     // The last two create notifications should be for the current frames and context.
1119     WebFrame* mainFrame = m_webView->mainFrame();
1120     WebFrame* childFrame = mainFrame->firstChild();
1121     ContextLifetimeTestWebFrameClient::Notification* firstRefreshNotification = webFrameClient.createNotifications[2];
1122     ContextLifetimeTestWebFrameClient::Notification* secondRefreshNotification = webFrameClient.createNotifications[3];
1123
1124     EXPECT_EQ(mainFrame, firstRefreshNotification->frame);
1125     EXPECT_EQ(mainFrame->mainWorldScriptContext(), firstRefreshNotification->context);
1126     EXPECT_EQ(0, firstRefreshNotification->worldId);
1127
1128     EXPECT_EQ(childFrame, secondRefreshNotification->frame);
1129     EXPECT_EQ(childFrame->mainWorldScriptContext(), secondRefreshNotification->context);
1130     EXPECT_EQ(0, secondRefreshNotification->worldId);
1131
1132     m_webView->close();
1133     m_webView = 0;
1134 }
1135
1136 TEST_F(WebFrameTest, ContextNotificationsIsolatedWorlds)
1137 {
1138     v8::HandleScope handleScope;
1139
1140     registerMockedHttpURLLoad("context_notifications_test.html");
1141     registerMockedHttpURLLoad("context_notifications_test_frame.html");
1142
1143     ContextLifetimeTestWebFrameClient webFrameClient;
1144     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
1145
1146     // Add an isolated world.
1147     webFrameClient.reset();
1148
1149     int isolatedWorldId = 42;
1150     WebScriptSource scriptSource("hi!");
1151     int numSources = 1;
1152     int extensionGroup = 0;
1153     m_webView->mainFrame()->executeScriptInIsolatedWorld(isolatedWorldId, &scriptSource, numSources, extensionGroup);
1154
1155     // We should now have a new create notification.
1156     ASSERT_EQ(1u, webFrameClient.createNotifications.size());
1157     ContextLifetimeTestWebFrameClient::Notification* notification = webFrameClient.createNotifications[0];
1158     ASSERT_EQ(isolatedWorldId, notification->worldId);
1159     ASSERT_EQ(m_webView->mainFrame(), notification->frame);
1160
1161     // We don't have an API to enumarate isolated worlds for a frame, but we can at least assert that the context we got is *not* the main world's context.
1162     ASSERT_NE(m_webView->mainFrame()->mainWorldScriptContext(), notification->context);
1163
1164     m_webView->close();
1165     m_webView = 0;
1166
1167     // We should have gotten three release notifications (one for each of the frames, plus one for the isolated context).
1168     ASSERT_EQ(3u, webFrameClient.releaseNotifications.size());
1169
1170     // And one of them should be exactly the same as the create notification for the isolated context.
1171     int matchCount = 0;
1172     for (size_t i = 0; i < webFrameClient.releaseNotifications.size(); ++i) {
1173       if (webFrameClient.releaseNotifications[i]->Equals(webFrameClient.createNotifications[0]))
1174         ++matchCount;
1175     }
1176     EXPECT_EQ(1, matchCount);
1177 }
1178
1179 TEST_F(WebFrameTest, FindInPage)
1180 {
1181     registerMockedHttpURLLoad("find.html");
1182     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "find.html");
1183     WebFrame* frame = m_webView->mainFrame();
1184     const int findIdentifier = 12345;
1185     WebFindOptions options;
1186
1187     // Find in a <div> element.
1188     EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar1"), options, false, 0));
1189     frame->stopFinding(false);
1190     WebRange range = frame->selectionRange();
1191     EXPECT_EQ(5, range.startOffset());
1192     EXPECT_EQ(9, range.endOffset());
1193     EXPECT_TRUE(frame->document().focusedNode().isNull());
1194
1195     // Find in an <input> value.
1196     EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar2"), options, false, 0));
1197     // Confirm stopFinding(false) sets the selection on the found text.
1198     frame->stopFinding(false);
1199     range = frame->selectionRange();
1200     ASSERT_FALSE(range.isNull());
1201     EXPECT_EQ(5, range.startOffset());
1202     EXPECT_EQ(9, range.endOffset());
1203     EXPECT_EQ(WebString::fromUTF8("INPUT"), frame->document().focusedNode().nodeName());
1204
1205     // Find in a <textarea> content.
1206     EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar3"), options, false, 0));
1207     // Confirm stopFinding(false) sets the selection on the found text.
1208     frame->stopFinding(false);
1209     range = frame->selectionRange();
1210     ASSERT_FALSE(range.isNull());
1211     EXPECT_EQ(5, range.startOffset());
1212     EXPECT_EQ(9, range.endOffset());
1213     EXPECT_EQ(WebString::fromUTF8("TEXTAREA"), frame->document().focusedNode().nodeName());
1214
1215     // Find in a contentEditable element.
1216     EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar4"), options, false, 0));
1217     // Confirm stopFinding(false) sets the selection on the found text.
1218     frame->stopFinding(false);
1219     range = frame->selectionRange();
1220     ASSERT_FALSE(range.isNull());
1221     EXPECT_EQ(0, range.startOffset());
1222     EXPECT_EQ(4, range.endOffset());
1223     // "bar4" is surrounded by <span>, but the focusable node should be the parent <div>.
1224     EXPECT_EQ(WebString::fromUTF8("DIV"), frame->document().focusedNode().nodeName());
1225
1226     // Find in <select> content.
1227     EXPECT_FALSE(frame->find(findIdentifier, WebString::fromUTF8("bar5"), options, false, 0));
1228     // If there are any matches, stopFinding will set the selection on the found text.
1229     // However, we do not expect any matches, so check that the selection is null.
1230     frame->stopFinding(false);
1231     range = frame->selectionRange();
1232     ASSERT_TRUE(range.isNull());
1233 }
1234
1235 TEST_F(WebFrameTest, GetContentAsPlainText)
1236 {
1237     m_webView = FrameTestHelpers::createWebViewAndLoad("about:blank", true);
1238     // We set the size because it impacts line wrapping, which changes the
1239     // resulting text value.
1240     m_webView->resize(WebSize(640, 480));
1241     WebFrame* frame = m_webView->mainFrame();
1242
1243     // Generate a simple test case.
1244     const char simpleSource[] = "<div>Foo bar</div><div></div>baz";
1245     WebCore::KURL testURL = toKURL("about:blank");
1246     frame->loadHTMLString(simpleSource, testURL);
1247     runPendingTasks();
1248
1249     // Make sure it comes out OK.
1250     const std::string expected("Foo bar\nbaz");
1251     WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
1252     EXPECT_EQ(expected, std::string(text.utf8().data()));
1253
1254     // Try reading the same one with clipping of the text.
1255     const int length = 5;
1256     text = frame->contentAsText(length);
1257     EXPECT_EQ(expected.substr(0, length), std::string(text.utf8().data()));
1258
1259     // Now do a new test with a subframe.
1260     const char outerFrameSource[] = "Hello<iframe></iframe> world";
1261     frame->loadHTMLString(outerFrameSource, testURL);
1262     runPendingTasks();
1263
1264     // Load something into the subframe.
1265     WebFrame* subframe = frame->findChildByExpression(WebString::fromUTF8("/html/body/iframe"));
1266     ASSERT_TRUE(subframe);
1267     subframe->loadHTMLString("sub<p>text", testURL);
1268     runPendingTasks();
1269
1270     text = frame->contentAsText(std::numeric_limits<size_t>::max());
1271     EXPECT_EQ("Hello world\n\nsub\ntext", std::string(text.utf8().data()));
1272
1273     // Get the frame text where the subframe separator falls on the boundary of
1274     // what we'll take. There used to be a crash in this case.
1275     text = frame->contentAsText(12);
1276     EXPECT_EQ("Hello world", std::string(text.utf8().data()));
1277 }
1278
1279 TEST_F(WebFrameTest, GetFullHtmlOfPage)
1280 {
1281     m_webView = FrameTestHelpers::createWebViewAndLoad("about:blank", true);
1282     WebFrame* frame = m_webView->mainFrame();
1283
1284     // Generate a simple test case.
1285     const char simpleSource[] = "<p>Hello</p><p>World</p>";
1286     WebCore::KURL testURL = toKURL("about:blank");
1287     frame->loadHTMLString(simpleSource, testURL);
1288     runPendingTasks();
1289
1290     WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
1291     EXPECT_EQ("Hello\n\nWorld", std::string(text.utf8().data()));
1292
1293     const std::string html = std::string(frame->contentAsMarkup().utf8().data());
1294
1295     // Load again with the output html.
1296     frame->loadHTMLString(WebData(html.c_str(), html.length()), testURL);
1297     runPendingTasks();
1298
1299     EXPECT_EQ(html, std::string(frame->contentAsMarkup().utf8().data()));
1300
1301     text = frame->contentAsText(std::numeric_limits<size_t>::max());
1302     EXPECT_EQ("Hello\n\nWorld", std::string(text.utf8().data()));
1303
1304     // Test selection check
1305     EXPECT_FALSE(frame->hasSelection());
1306     frame->executeCommand(WebString::fromUTF8("SelectAll"));
1307     EXPECT_TRUE(frame->hasSelection());
1308     frame->executeCommand(WebString::fromUTF8("Unselect"));
1309     EXPECT_FALSE(frame->hasSelection());
1310     WebString selectionHtml = frame->selectionAsMarkup();
1311     EXPECT_TRUE(selectionHtml.isEmpty());
1312 }
1313
1314 class TestExecuteScriptDuringDidCreateScriptContext : public WebFrameClient {
1315 public:
1316     virtual void didCreateScriptContext(WebFrame* frame, v8::Handle<v8::Context> context, int extensionGroup, int worldId) OVERRIDE
1317     {
1318         frame->executeScript(WebScriptSource("window.history = 'replaced';"));
1319     }
1320 };
1321
1322 TEST_F(WebFrameTest, ExecuteScriptDuringDidCreateScriptContext)
1323 {
1324     registerMockedHttpURLLoad("hello_world.html");
1325
1326     TestExecuteScriptDuringDidCreateScriptContext webFrameClient;
1327     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "hello_world.html", true, &webFrameClient);
1328
1329     m_webView->mainFrame()->reload();
1330     Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
1331
1332     m_webView->close();
1333     m_webView = 0;
1334 }
1335
1336 class TestDidCreateFrameWebFrameClient : public WebFrameClient {
1337 public:
1338     TestDidCreateFrameWebFrameClient() : m_frameCount(0), m_parent(0)
1339     {
1340     }
1341
1342     virtual void didCreateFrame(WebFrame* parent, WebFrame* child) 
1343     {
1344         m_frameCount++;
1345         if (!m_parent)
1346             m_parent = parent;
1347     }
1348     
1349     int m_frameCount;
1350     WebFrame* m_parent;
1351 };
1352
1353 TEST_F(WebFrameTest, DidCreateFrame)
1354 {
1355     registerMockedHttpURLLoad("iframes_test.html");
1356     registerMockedHttpURLLoad("visible_iframe.html");
1357     registerMockedHttpURLLoad("invisible_iframe.html");
1358     registerMockedHttpURLLoad("zero_sized_iframe.html");
1359
1360     TestDidCreateFrameWebFrameClient webFrameClient;
1361     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "iframes_test.html", false, &webFrameClient);
1362
1363     EXPECT_EQ(webFrameClient.m_frameCount, 3); 
1364     EXPECT_EQ(webFrameClient.m_parent, m_webView->mainFrame());
1365
1366     m_webView->close();
1367     m_webView = 0;
1368 }
1369
1370 class FindUpdateWebFrameClient : public WebFrameClient {
1371 public:
1372     FindUpdateWebFrameClient()
1373         : m_findResultsAreReady(false)
1374         , m_count(-1)
1375     {
1376     }
1377
1378     virtual void reportFindInPageMatchCount(int, int count, bool finalUpdate) OVERRIDE
1379     {
1380         m_count = count;
1381         if (finalUpdate)
1382             m_findResultsAreReady = true;
1383     }
1384
1385     bool findResultsAreReady() const { return m_findResultsAreReady; }
1386     int count() const { return m_count; }
1387
1388 private:
1389     bool m_findResultsAreReady;
1390     int m_count;
1391 };
1392
1393 // This fails on Mac https://bugs.webkit.org/show_bug.cgi?id=108574
1394 #if OS(DARWIN)
1395 TEST_F(WebFrameTest, DISABLED_FindInPageMatchRects)
1396 #else
1397 TEST_F(WebFrameTest, FindInPageMatchRects)
1398 #endif
1399 {
1400     registerMockedHttpURLLoad("find_in_page.html");
1401     registerMockedHttpURLLoad("find_in_page_frame.html");
1402
1403     FindUpdateWebFrameClient client;
1404     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "find_in_page.html", true, &client);
1405     m_webView->resize(WebSize(640, 480));
1406     m_webView->layout();
1407     runPendingTasks();
1408
1409     // Note that the 'result 19' in the <select> element is not expected to produce a match.
1410     static const char* kFindString = "result";
1411     static const int kFindIdentifier = 12345;
1412     static const int kNumResults = 19;
1413
1414     WebFindOptions options;
1415     WebString searchText = WebString::fromUTF8(kFindString);
1416     WebFrameImpl* mainFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame());
1417     EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
1418
1419     mainFrame->resetMatchCount();
1420
1421     for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
1422         frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
1423
1424     runPendingTasks();
1425     EXPECT_TRUE(client.findResultsAreReady());
1426
1427     WebVector<WebFloatRect> webMatchRects;
1428     mainFrame->findMatchRects(webMatchRects);
1429     ASSERT_EQ(webMatchRects.size(), static_cast<size_t>(kNumResults));
1430     int rectsVersion = mainFrame->findMatchMarkersVersion();
1431
1432     for (int resultIndex = 0; resultIndex < kNumResults; ++resultIndex) {
1433         FloatRect resultRect = static_cast<FloatRect>(webMatchRects[resultIndex]);
1434
1435         // Select the match by the center of its rect.
1436         EXPECT_EQ(mainFrame->selectNearestFindMatch(resultRect.center(), 0), resultIndex + 1);
1437
1438         // Check that the find result ordering matches with our expectations.
1439         Range* result = mainFrame->activeMatchFrame()->activeMatch();
1440         ASSERT_TRUE(result);
1441         result->setEnd(result->endContainer(), result->endOffset() + 3);
1442         EXPECT_EQ(result->text(), String::format("%s %02d", kFindString, resultIndex));
1443
1444         // Verify that the expected match rect also matches the currently active match.
1445         // Compare the enclosing rects to prevent precision issues caused by CSS transforms.
1446         FloatRect activeMatch = mainFrame->activeFindMatchRect();
1447         EXPECT_EQ(enclosingIntRect(activeMatch), enclosingIntRect(resultRect));
1448
1449         // The rects version should not have changed.
1450         EXPECT_EQ(mainFrame->findMatchMarkersVersion(), rectsVersion);
1451     }
1452
1453     // All results after the first two ones should be below between them in find-in-page coordinates.
1454     // This is because results 2 to 9 are inside an iframe located between results 0 and 1. This applies to the fixed div too.
1455     EXPECT_TRUE(webMatchRects[0].y < webMatchRects[1].y);
1456     for (int resultIndex = 2; resultIndex < kNumResults; ++resultIndex) {
1457         EXPECT_TRUE(webMatchRects[0].y < webMatchRects[resultIndex].y);
1458         EXPECT_TRUE(webMatchRects[1].y > webMatchRects[resultIndex].y);
1459     }
1460
1461     // Result 3 should be below both 2 and 4. This is caused by the CSS transform in the containing div.
1462     // If the transform doesn't work then 3 will be between 2 and 4.
1463     EXPECT_TRUE(webMatchRects[3].y > webMatchRects[2].y);
1464     EXPECT_TRUE(webMatchRects[3].y > webMatchRects[4].y);
1465
1466     // Results 6, 7, 8 and 9 should be one below the other in that same order.
1467     // If overflow:scroll is not properly handled then result 8 would be below result 9 or
1468     // result 7 above result 6 depending on the scroll.
1469     EXPECT_TRUE(webMatchRects[6].y < webMatchRects[7].y);
1470     EXPECT_TRUE(webMatchRects[7].y < webMatchRects[8].y);
1471     EXPECT_TRUE(webMatchRects[8].y < webMatchRects[9].y);
1472
1473     // Results 11, 12, 13 and 14 should be between results 10 and 15, as they are inside the table.
1474     EXPECT_TRUE(webMatchRects[11].y > webMatchRects[10].y);
1475     EXPECT_TRUE(webMatchRects[12].y > webMatchRects[10].y);
1476     EXPECT_TRUE(webMatchRects[13].y > webMatchRects[10].y);
1477     EXPECT_TRUE(webMatchRects[14].y > webMatchRects[10].y);
1478     EXPECT_TRUE(webMatchRects[11].y < webMatchRects[15].y);
1479     EXPECT_TRUE(webMatchRects[12].y < webMatchRects[15].y);
1480     EXPECT_TRUE(webMatchRects[13].y < webMatchRects[15].y);
1481     EXPECT_TRUE(webMatchRects[14].y < webMatchRects[15].y);
1482
1483     // Result 11 should be above 12, 13 and 14 as it's in the table header.
1484     EXPECT_TRUE(webMatchRects[11].y < webMatchRects[12].y);
1485     EXPECT_TRUE(webMatchRects[11].y < webMatchRects[13].y);
1486     EXPECT_TRUE(webMatchRects[11].y < webMatchRects[14].y);
1487
1488     // Result 11 should also be right to 12, 13 and 14 because of the colspan.
1489     EXPECT_TRUE(webMatchRects[11].x > webMatchRects[12].x);
1490     EXPECT_TRUE(webMatchRects[11].x > webMatchRects[13].x);
1491     EXPECT_TRUE(webMatchRects[11].x > webMatchRects[14].x);
1492
1493     // Result 12 should be left to results 11, 13 and 14 in the table layout.
1494     EXPECT_TRUE(webMatchRects[12].x < webMatchRects[11].x);
1495     EXPECT_TRUE(webMatchRects[12].x < webMatchRects[13].x);
1496     EXPECT_TRUE(webMatchRects[12].x < webMatchRects[14].x);
1497
1498     // Results 13, 12 and 14 should be one above the other in that order because of the rowspan
1499     // and vertical-align: middle by default.
1500     EXPECT_TRUE(webMatchRects[13].y < webMatchRects[12].y);
1501     EXPECT_TRUE(webMatchRects[12].y < webMatchRects[14].y);
1502
1503     // Result 16 should be below result 15.
1504     EXPECT_TRUE(webMatchRects[15].y > webMatchRects[14].y);
1505
1506     // Result 18 should be normalized with respect to the position:relative div, and not it's
1507     // immediate containing div. Consequently, result 18 should be above result 17.
1508     EXPECT_TRUE(webMatchRects[17].y > webMatchRects[18].y);
1509
1510     // Resizing should update the rects version.
1511     m_webView->resize(WebSize(800, 600));
1512     runPendingTasks();
1513     EXPECT_TRUE(mainFrame->findMatchMarkersVersion() != rectsVersion);
1514
1515     m_webView->close();
1516     m_webView = 0;
1517 }
1518
1519 TEST_F(WebFrameTest, FindInPageSkipsHiddenFrames)
1520 {
1521     registerMockedHttpURLLoad("find_in_hidden_frame.html");
1522
1523     FindUpdateWebFrameClient client;
1524     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "find_in_hidden_frame.html", true, &client);
1525     m_webView->resize(WebSize(640, 480));
1526     m_webView->layout();
1527     runPendingTasks();
1528
1529     static const char* kFindString = "hello";
1530     static const int kFindIdentifier = 12345;
1531     static const int kNumResults = 1;
1532
1533     WebFindOptions options;
1534     WebString searchText = WebString::fromUTF8(kFindString);
1535     WebFrameImpl* mainFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame());
1536     EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
1537
1538     mainFrame->resetMatchCount();
1539
1540     for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
1541         frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
1542
1543     runPendingTasks();
1544     EXPECT_TRUE(client.findResultsAreReady());
1545     EXPECT_EQ(kNumResults, client.count());
1546
1547     m_webView->close();
1548     m_webView = 0;
1549 }
1550
1551 TEST_F(WebFrameTest, FindOnDetachedFrame)
1552 {
1553     registerMockedHttpURLLoad("find_in_page.html");
1554     registerMockedHttpURLLoad("find_in_page_frame.html");
1555
1556     FindUpdateWebFrameClient client;
1557     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "find_in_page.html", true, &client);
1558     m_webView->resize(WebSize(640, 480));
1559     m_webView->layout();
1560     runPendingTasks();
1561
1562     static const char* kFindString = "result";
1563     static const int kFindIdentifier = 12345;
1564
1565     WebFindOptions options;
1566     WebString searchText = WebString::fromUTF8(kFindString);
1567     WebFrameImpl* mainFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame());
1568     WebFrameImpl* secondFrame = static_cast<WebFrameImpl*>(mainFrame->traverseNext(false));
1569     RefPtr<WebCore::Frame> holdSecondFrame = secondFrame->frame();
1570
1571     // Detach the frame before finding.
1572     EXPECT_TRUE(mainFrame->document().getElementById("frame").remove());
1573
1574     EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false, 0));
1575     EXPECT_FALSE(secondFrame->find(kFindIdentifier, searchText, options, false, 0));
1576
1577     runPendingTasks();
1578     EXPECT_FALSE(client.findResultsAreReady());
1579
1580     mainFrame->resetMatchCount();
1581
1582     for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
1583         frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
1584
1585     runPendingTasks();
1586     EXPECT_TRUE(client.findResultsAreReady());
1587
1588     holdSecondFrame.release();
1589
1590     m_webView->close();
1591     m_webView = 0;
1592 }
1593
1594 TEST_F(WebFrameTest, FindDetachFrameBeforeScopeStrings)
1595 {
1596     registerMockedHttpURLLoad("find_in_page.html");
1597     registerMockedHttpURLLoad("find_in_page_frame.html");
1598
1599     FindUpdateWebFrameClient client;
1600     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "find_in_page.html", true, &client);
1601     m_webView->resize(WebSize(640, 480));
1602     m_webView->layout();
1603     runPendingTasks();
1604
1605     static const char* kFindString = "result";
1606     static const int kFindIdentifier = 12345;
1607
1608     WebFindOptions options;
1609     WebString searchText = WebString::fromUTF8(kFindString);
1610     WebFrameImpl* mainFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame());
1611     WebFrameImpl* secondFrame = static_cast<WebFrameImpl*>(mainFrame->traverseNext(false));
1612     RefPtr<WebCore::Frame> holdSecondFrame = secondFrame->frame();
1613
1614     for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
1615         EXPECT_TRUE(frame->find(kFindIdentifier, searchText, options, false, 0));
1616
1617     runPendingTasks();
1618     EXPECT_FALSE(client.findResultsAreReady());
1619
1620     // Detach the frame between finding and scoping.
1621     EXPECT_TRUE(mainFrame->document().getElementById("frame").remove());
1622
1623     mainFrame->resetMatchCount();
1624
1625     for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
1626         frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
1627
1628     runPendingTasks();
1629     EXPECT_TRUE(client.findResultsAreReady());
1630
1631     holdSecondFrame.release();
1632
1633     m_webView->close();
1634     m_webView = 0;
1635 }
1636
1637 TEST_F(WebFrameTest, FindDetachFrameWhileScopingStrings)
1638 {
1639     registerMockedHttpURLLoad("find_in_page.html");
1640     registerMockedHttpURLLoad("find_in_page_frame.html");
1641
1642     FindUpdateWebFrameClient client;
1643     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "find_in_page.html", true, &client);
1644     m_webView->resize(WebSize(640, 480));
1645     m_webView->layout();
1646     runPendingTasks();
1647
1648     static const char* kFindString = "result";
1649     static const int kFindIdentifier = 12345;
1650
1651     WebFindOptions options;
1652     WebString searchText = WebString::fromUTF8(kFindString);
1653     WebFrameImpl* mainFrame = static_cast<WebFrameImpl*>(m_webView->mainFrame());
1654     WebFrameImpl* secondFrame = static_cast<WebFrameImpl*>(mainFrame->traverseNext(false));
1655     RefPtr<WebCore::Frame> holdSecondFrame = secondFrame->frame();
1656
1657     for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
1658         EXPECT_TRUE(frame->find(kFindIdentifier, searchText, options, false, 0));
1659
1660     runPendingTasks();
1661     EXPECT_FALSE(client.findResultsAreReady());
1662
1663     mainFrame->resetMatchCount();
1664
1665     for (WebFrame* frame = mainFrame; frame; frame = frame->traverseNext(false))
1666         frame->scopeStringMatches(kFindIdentifier, searchText, options, true);
1667
1668     // The first scopeStringMatches will have reset the state. Detach before it actually scopes.
1669     EXPECT_TRUE(mainFrame->document().getElementById("frame").remove());
1670
1671     runPendingTasks();
1672     EXPECT_TRUE(client.findResultsAreReady());
1673
1674     holdSecondFrame.release();
1675
1676     m_webView->close();
1677     m_webView = 0;
1678 }
1679
1680 static WebView* createWebViewForTextSelection(const std::string& url)
1681 {
1682     WebView* webView = FrameTestHelpers::createWebViewAndLoad(url, true);
1683     webView->settings()->setDefaultFontSize(12);
1684     webView->enableFixedLayoutMode(false);
1685     webView->resize(WebSize(640, 480));
1686     return webView;
1687 }
1688
1689 static WebPoint topLeft(const WebRect& rect)
1690 {
1691     return WebPoint(rect.x, rect.y);
1692 }
1693
1694 static WebPoint bottomRightMinusOne(const WebRect& rect)
1695 {
1696     // FIXME: If we don't subtract 1 from the x- and y-coordinates of the
1697     // selection bounds, selectRange() will select the *next* element. That's
1698     // strictly correct, as hit-testing checks the pixel to the lower-right of
1699     // the input coordinate, but it's a wart on the API.
1700     return WebPoint(rect.x + rect.width - 1, rect.y + rect.height - 1);
1701 }
1702
1703 static WebRect elementBounds(WebFrame* frame, const WebString& id)
1704 {
1705     return frame->document().getElementById(id).boundsInViewportSpace();
1706 }
1707
1708 static std::string selectionAsString(WebFrame* frame)
1709 {
1710     return std::string(frame->selectionAsText().utf8().data());
1711 }
1712
1713 TEST_F(WebFrameTest, SelectRange)
1714 {
1715     WebFrame* frame;
1716     WebRect startWebRect;
1717     WebRect endWebRect;
1718
1719     registerMockedHttpURLLoad("select_range_basic.html");
1720     registerMockedHttpURLLoad("select_range_scroll.html");
1721     registerMockedHttpURLLoad("select_range_iframe.html");
1722     registerMockedHttpURLLoad("select_range_editable.html");
1723
1724     m_webView = createWebViewForTextSelection(m_baseURL + "select_range_basic.html");
1725     frame = m_webView->mainFrame();
1726     EXPECT_EQ("Some test text for testing.", selectionAsString(frame));
1727     m_webView->selectionBounds(startWebRect, endWebRect);
1728     frame->executeCommand(WebString::fromUTF8("Unselect"));
1729     EXPECT_EQ("", selectionAsString(frame));
1730     frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
1731     EXPECT_EQ("Some test text for testing.", selectionAsString(frame));
1732     m_webView->close();
1733     m_webView = 0;
1734
1735     m_webView = createWebViewForTextSelection(m_baseURL + "select_range_scroll.html");
1736     frame = m_webView->mainFrame();
1737     EXPECT_EQ("Some offscreen test text for testing.", selectionAsString(frame));
1738     m_webView->selectionBounds(startWebRect, endWebRect);
1739     frame->executeCommand(WebString::fromUTF8("Unselect"));
1740     EXPECT_EQ("", selectionAsString(frame));
1741     frame->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
1742     EXPECT_EQ("Some offscreen test text for testing.", selectionAsString(frame));
1743     m_webView->close();
1744     m_webView = 0;
1745
1746     m_webView = createWebViewForTextSelection(m_baseURL + "select_range_iframe.html");
1747     frame = m_webView->mainFrame();
1748     WebFrame* subframe = frame->findChildByExpression(WebString::fromUTF8("/html/body/iframe"));
1749     EXPECT_EQ("Some test text for testing.", selectionAsString(subframe));
1750     m_webView->selectionBounds(startWebRect, endWebRect);
1751     subframe->executeCommand(WebString::fromUTF8("Unselect"));
1752     EXPECT_EQ("", selectionAsString(subframe));
1753     subframe->selectRange(topLeft(startWebRect), bottomRightMinusOne(endWebRect));
1754     EXPECT_EQ("Some test text for testing.", selectionAsString(subframe));
1755     m_webView->close();
1756     m_webView = 0;
1757
1758     // Select the middle of an editable element, then try to extend the selection to the top of the document.
1759     // The selection range should be clipped to the bounds of the editable element.
1760     m_webView = createWebViewForTextSelection(m_baseURL + "select_range_editable.html");
1761     frame = m_webView->mainFrame();
1762     EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
1763     m_webView->selectionBounds(startWebRect, endWebRect);
1764     frame->selectRange(bottomRightMinusOne(endWebRect), WebPoint(0, 0));
1765     EXPECT_EQ("16-char header. This text is initially selected.", selectionAsString(frame));
1766     m_webView->close();
1767     m_webView = 0;
1768
1769     // As above, but extending the selection to the bottom of the document.
1770     m_webView = createWebViewForTextSelection(m_baseURL + "select_range_editable.html");
1771     frame = m_webView->mainFrame();
1772     EXPECT_EQ("This text is initially selected.", selectionAsString(frame));
1773     m_webView->selectionBounds(startWebRect, endWebRect);
1774     frame->selectRange(topLeft(startWebRect), WebPoint(640, 480));
1775     EXPECT_EQ("This text is initially selected. 16-char footer.", selectionAsString(frame));
1776     m_webView->close();
1777     m_webView = 0;
1778 }
1779
1780 TEST_F(WebFrameTest, SelectRangeCanMoveSelectionStart)
1781 {
1782     registerMockedHttpURLLoad("text_selection.html");
1783     m_webView = createWebViewForTextSelection(m_baseURL + "text_selection.html");
1784     WebFrame* frame = m_webView->mainFrame();
1785
1786     // Select second span. We can move the start to include the first span.
1787     frame->executeScript(WebScriptSource("selectElement('header_2');"));
1788     EXPECT_EQ("Header 2.", selectionAsString(frame));
1789     frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_1")));
1790     EXPECT_EQ("Header 1. Header 2.", selectionAsString(frame));
1791
1792     // We can move the start and end together.
1793     frame->executeScript(WebScriptSource("selectElement('header_1');"));
1794     EXPECT_EQ("Header 1.", selectionAsString(frame));
1795     frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_1")));
1796     EXPECT_EQ("", selectionAsString(frame));
1797     // Selection is a caret, not empty.
1798     EXPECT_FALSE(frame->selectionRange().isNull());
1799
1800     // We can move the start across the end.
1801     frame->executeScript(WebScriptSource("selectElement('header_1');"));
1802     EXPECT_EQ("Header 1.", selectionAsString(frame));
1803     frame->selectRange(bottomRightMinusOne(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_2")));
1804     EXPECT_EQ(" Header 2.", selectionAsString(frame));
1805
1806     // Can't extend the selection part-way into an editable element.
1807     frame->executeScript(WebScriptSource("selectElement('footer_2');"));
1808     EXPECT_EQ("Footer 2.", selectionAsString(frame));
1809     frame->selectRange(bottomRightMinusOne(elementBounds(frame, "footer_2")), topLeft(elementBounds(frame, "editable_2")));
1810     EXPECT_EQ(" [ Footer 1. Footer 2.", selectionAsString(frame));
1811
1812     // Can extend the selection completely across editable elements.
1813     frame->executeScript(WebScriptSource("selectElement('footer_2');"));
1814     EXPECT_EQ("Footer 2.", selectionAsString(frame));
1815     frame->selectRange(bottomRightMinusOne(elementBounds(frame, "footer_2")), topLeft(elementBounds(frame, "header_2")));
1816     EXPECT_EQ("Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1. Footer 2.", selectionAsString(frame));
1817
1818     // If the selection is editable text, we can't extend it into non-editable text.
1819     frame->executeScript(WebScriptSource("selectElement('editable_2');"));
1820     EXPECT_EQ("Editable 2.", selectionAsString(frame));
1821     frame->selectRange(bottomRightMinusOne(elementBounds(frame, "editable_2")), topLeft(elementBounds(frame, "header_2")));
1822     EXPECT_EQ("[ Editable 1. Editable 2.", selectionAsString(frame));
1823 }
1824
1825 TEST_F(WebFrameTest, SelectRangeCanMoveSelectionEnd)
1826 {
1827     registerMockedHttpURLLoad("text_selection.html");
1828     m_webView = createWebViewForTextSelection(m_baseURL + "text_selection.html");
1829     WebFrame* frame = m_webView->mainFrame();
1830
1831     // Select first span. We can move the end to include the second span.
1832     frame->executeScript(WebScriptSource("selectElement('header_1');"));
1833     EXPECT_EQ("Header 1.", selectionAsString(frame));
1834     frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "header_2")));
1835     EXPECT_EQ("Header 1. Header 2.", selectionAsString(frame));
1836
1837     // We can move the start and end together.
1838     frame->executeScript(WebScriptSource("selectElement('header_2');"));
1839     EXPECT_EQ("Header 2.", selectionAsString(frame));
1840     frame->selectRange(topLeft(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_2")));
1841     EXPECT_EQ("", selectionAsString(frame));
1842     // Selection is a caret, not empty.
1843     EXPECT_FALSE(frame->selectionRange().isNull());
1844
1845     // We can move the end across the start.
1846     frame->executeScript(WebScriptSource("selectElement('header_2');"));
1847     EXPECT_EQ("Header 2.", selectionAsString(frame));
1848     frame->selectRange(topLeft(elementBounds(frame, "header_2")), topLeft(elementBounds(frame, "header_1")));
1849     EXPECT_EQ("Header 1. ", selectionAsString(frame));
1850
1851     // Can't extend the selection part-way into an editable element.
1852     frame->executeScript(WebScriptSource("selectElement('header_1');"));
1853     EXPECT_EQ("Header 1.", selectionAsString(frame));
1854     frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "editable_1")));
1855     EXPECT_EQ("Header 1. Header 2. ] ", selectionAsString(frame));
1856
1857     // Can extend the selection completely across editable elements.
1858     frame->executeScript(WebScriptSource("selectElement('header_1');"));
1859     EXPECT_EQ("Header 1.", selectionAsString(frame));
1860     frame->selectRange(topLeft(elementBounds(frame, "header_1")), bottomRightMinusOne(elementBounds(frame, "footer_1")));
1861     EXPECT_EQ("Header 1. Header 2. ] [ Editable 1. Editable 2. ] [ Footer 1.", selectionAsString(frame));
1862
1863     // If the selection is editable text, we can't extend it into non-editable text.
1864     frame->executeScript(WebScriptSource("selectElement('editable_1');"));
1865     EXPECT_EQ("Editable 1.", selectionAsString(frame));
1866     frame->selectRange(topLeft(elementBounds(frame, "editable_1")), bottomRightMinusOne(elementBounds(frame, "footer_1")));
1867     EXPECT_EQ("Editable 1. Editable 2. ]", selectionAsString(frame));
1868 }
1869
1870 #if OS(ANDROID)
1871 TEST_F(WebFrameTest, MoveCaretStaysHorizontallyAlignedWhenMoved)
1872 {
1873     WebFrameImpl* frame;
1874     registerMockedHttpURLLoad("move_caret.html");
1875
1876     m_webView = createWebViewForTextSelection(m_baseURL + "move_caret.html");
1877     frame = (WebFrameImpl*)m_webView->mainFrame();
1878
1879     WebRect initialStartRect;
1880     WebRect initialEndRect;
1881     WebRect startRect;
1882     WebRect endRect;
1883
1884     frame->executeScript(WebScriptSource("select();"));
1885     m_webView->selectionBounds(initialStartRect, initialEndRect);
1886     WebPoint moveTo(topLeft(initialStartRect));
1887
1888     moveTo.y += 40;
1889     frame->moveCaretSelectionTowardsWindowPoint(moveTo);
1890     m_webView->selectionBounds(startRect, endRect);
1891     EXPECT_EQ(startRect, initialStartRect);
1892     EXPECT_EQ(endRect, initialEndRect);
1893
1894     moveTo.y -= 80;
1895     frame->moveCaretSelectionTowardsWindowPoint(moveTo);
1896     m_webView->selectionBounds(startRect, endRect);
1897     EXPECT_EQ(startRect, initialStartRect);
1898     EXPECT_EQ(endRect, initialEndRect);
1899 }
1900 #endif
1901
1902 class DisambiguationPopupTestWebViewClient : public WebViewClient {
1903 public:
1904     virtual bool didTapMultipleTargets(const WebGestureEvent&, const WebVector<WebRect>& targetRects) OVERRIDE
1905     {
1906         EXPECT_GE(targetRects.size(), 2u);
1907         m_triggered = true;
1908         return true;
1909     }
1910
1911     bool triggered() const { return m_triggered; }
1912     void resetTriggered() { m_triggered = false; }
1913     bool m_triggered;
1914 };
1915
1916 static WebGestureEvent fatTap(int x, int y)
1917 {
1918     WebGestureEvent event;
1919     event.type = WebInputEvent::GestureTap;
1920     event.x = x;
1921     event.y = y;
1922     event.data.tap.width = 50;
1923     event.data.tap.height = 50;
1924     return event;
1925 }
1926
1927 TEST_F(WebFrameTest, DisambiguationPopup)
1928 {
1929     const std::string htmlFile = "disambiguation_popup.html";
1930     registerMockedHttpURLLoad(htmlFile);
1931
1932     DisambiguationPopupTestWebViewClient client;
1933
1934     // Make sure we initialize to minimum scale, even if the window size
1935     // only becomes available after the load begins.
1936     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + htmlFile, true, 0, &client);
1937     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
1938     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
1939     m_webView->resize(WebSize(1000, 1000));
1940     m_webView->layout();
1941
1942     client.resetTriggered();
1943     m_webView->handleInputEvent(fatTap(0, 0));
1944     EXPECT_FALSE(client.triggered());
1945
1946     client.resetTriggered();
1947     m_webView->handleInputEvent(fatTap(200, 115));
1948     EXPECT_FALSE(client.triggered());
1949
1950     for (int i = 0; i <= 46; i++) {
1951         client.resetTriggered();
1952         m_webView->handleInputEvent(fatTap(120, 230 + i * 5));
1953
1954         int j = i % 10;
1955         if (j >= 7 && j <= 9)
1956             EXPECT_TRUE(client.triggered());
1957         else
1958             EXPECT_FALSE(client.triggered());
1959     }
1960
1961     for (int i = 0; i <= 46; i++) {
1962         client.resetTriggered();
1963         m_webView->handleInputEvent(fatTap(10 + i * 5, 590));
1964
1965         int j = i % 10;
1966         if (j >= 7 && j <= 9)
1967             EXPECT_TRUE(client.triggered());
1968         else
1969             EXPECT_FALSE(client.triggered());
1970     }
1971
1972     m_webView->close();
1973     m_webView = 0;
1974
1975 }
1976
1977 TEST_F(WebFrameTest, DisambiguationPopupNoContainer)
1978 {
1979     registerMockedHttpURLLoad("disambiguation_popup_no_container.html");
1980
1981     DisambiguationPopupTestWebViewClient client;
1982
1983     // Make sure we initialize to minimum scale, even if the window size
1984     // only becomes available after the load begins.
1985     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "disambiguation_popup_no_container.html", true, 0, &client);
1986     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
1987     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
1988     m_webView->resize(WebSize(1000, 1000));
1989     m_webView->layout();
1990
1991     client.resetTriggered();
1992     m_webView->handleInputEvent(fatTap(50, 50));
1993     EXPECT_FALSE(client.triggered());
1994
1995     m_webView->close();
1996     m_webView = 0;
1997 }
1998
1999 TEST_F(WebFrameTest, DisambiguationPopupMobileSite)
2000 {
2001     const std::string htmlFile = "disambiguation_popup_mobile_site.html";
2002     registerMockedHttpURLLoad(htmlFile);
2003
2004     DisambiguationPopupTestWebViewClient client;
2005
2006     // Make sure we initialize to minimum scale, even if the window size
2007     // only becomes available after the load begins.
2008     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + htmlFile, true, 0, &client);
2009     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
2010     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
2011     m_webView->resize(WebSize(1000, 1000));
2012     m_webView->layout();
2013
2014     client.resetTriggered();
2015     m_webView->handleInputEvent(fatTap(0, 0));
2016     EXPECT_FALSE(client.triggered());
2017
2018     client.resetTriggered();
2019     m_webView->handleInputEvent(fatTap(200, 115));
2020     EXPECT_FALSE(client.triggered());
2021
2022     for (int i = 0; i <= 46; i++) {
2023         client.resetTriggered();
2024         m_webView->handleInputEvent(fatTap(120, 230 + i * 5));
2025         EXPECT_FALSE(client.triggered());
2026     }
2027
2028     for (int i = 0; i <= 46; i++) {
2029         client.resetTriggered();
2030         m_webView->handleInputEvent(fatTap(10 + i * 5, 590));
2031         EXPECT_FALSE(client.triggered());
2032     }
2033
2034     m_webView->close();
2035     m_webView = 0;
2036 }
2037
2038 TEST_F(WebFrameTest, DisambiguationPopupBlacklist)
2039 {
2040     const unsigned viewportWidth = 500;
2041     const unsigned viewportHeight = 1000;
2042     const unsigned divHeight = 100;
2043     const std::string htmlFile = "disambiguation_popup_blacklist.html";
2044     registerMockedHttpURLLoad(htmlFile);
2045
2046     DisambiguationPopupTestWebViewClient client;
2047
2048     // Make sure we initialize to minimum scale, even if the window size
2049     // only becomes available after the load begins.
2050     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + htmlFile, true, 0, &client);
2051     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
2052     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
2053     m_webView->resize(WebSize(viewportWidth, viewportHeight));
2054     m_webView->layout();
2055
2056     // Click somewhere where the popup shouldn't appear.
2057     client.resetTriggered();
2058     m_webView->handleInputEvent(fatTap(viewportWidth / 2, 0));
2059     EXPECT_FALSE(client.triggered());
2060
2061     // Click directly in between two container divs with click handlers, with children that don't handle clicks.
2062     client.resetTriggered();
2063     m_webView->handleInputEvent(fatTap(viewportWidth / 2, divHeight));
2064     EXPECT_TRUE(client.triggered());
2065
2066     // The third div container should be blacklisted if you click on the link it contains.
2067     client.resetTriggered();
2068     m_webView->handleInputEvent(fatTap(viewportWidth / 2, divHeight * 3.25));
2069     EXPECT_FALSE(client.triggered());
2070
2071     m_webView->close();
2072     m_webView = 0;
2073 }
2074
2075 TEST_F(WebFrameTest, DisambiguationPopupPageScale)
2076 {
2077     registerMockedHttpURLLoad("disambiguation_popup_page_scale.html");
2078
2079     DisambiguationPopupTestWebViewClient client;
2080
2081     // Make sure we initialize to minimum scale, even if the window size
2082     // only becomes available after the load begins.
2083     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "disambiguation_popup_page_scale.html", true, 0, &client);
2084     m_webView->settings()->setApplyDeviceScaleFactorInCompositor(true);
2085     m_webView->settings()->setApplyPageScaleFactorInCompositor(true);
2086     m_webView->resize(WebSize(1000, 1000));
2087     m_webView->layout();
2088
2089     client.resetTriggered();
2090     m_webView->handleInputEvent(fatTap(80, 80));
2091     EXPECT_TRUE(client.triggered());
2092
2093     client.resetTriggered();
2094     m_webView->handleInputEvent(fatTap(230, 190));
2095     EXPECT_TRUE(client.triggered());
2096
2097     m_webView->setPageScaleFactor(3.0f, WebPoint(0, 0));
2098     m_webView->layout();
2099
2100     client.resetTriggered();
2101     m_webView->handleInputEvent(fatTap(240, 240));
2102     EXPECT_TRUE(client.triggered());
2103
2104     client.resetTriggered();
2105     m_webView->handleInputEvent(fatTap(690, 570));
2106     EXPECT_FALSE(client.triggered());
2107
2108     m_webView->close();
2109     m_webView = 0;
2110 }
2111
2112 class TestSubstituteDataWebFrameClient : public WebFrameClient {
2113 public:
2114     TestSubstituteDataWebFrameClient()
2115         : m_commitCalled(false)
2116     {
2117     }
2118
2119     virtual void didFailProvisionalLoad(WebFrame* frame, const WebURLError& error)
2120     {
2121         frame->loadHTMLString("This should appear", toKURL("data:text/html,chromewebdata"), error.unreachableURL, true);
2122         runPendingTasks();
2123     }
2124
2125     virtual void didCommitProvisionalLoad(WebFrame* frame, bool)
2126     {
2127         if (frame->dataSource()->response().url() != WebURL(URLTestHelpers::toKURL("about:blank")))
2128             m_commitCalled = true;
2129     }
2130
2131     bool commitCalled() const { return m_commitCalled; }
2132
2133 private:
2134     bool m_commitCalled;
2135 };
2136
2137 TEST_F(WebFrameTest, ReplaceNavigationAfterHistoryNavigation)
2138 {
2139     TestSubstituteDataWebFrameClient webFrameClient;
2140
2141     m_webView = FrameTestHelpers::createWebViewAndLoad("about:blank", true, &webFrameClient);
2142     runPendingTasks();
2143     WebFrame* frame = m_webView->mainFrame();
2144
2145     // Load a url as a history navigation that will return an error. TestSubstituteDataWebFrameClient
2146     // will start a SubstituteData load in response to the load failure, which should get fully committed.
2147     // Due to https://bugs.webkit.org/show_bug.cgi?id=91685, FrameLoader::didReceiveData() wasn't getting
2148     // called in this case, which resulted in the SubstituteData document not getting displayed.
2149     WebURLError error;
2150     error.reason = 1337;
2151     error.domain = "WebFrameTest";
2152     std::string errorURL = "http://0.0.0.0";
2153     WebURLResponse response;
2154     response.initialize();
2155     response.setURL(URLTestHelpers::toKURL(errorURL));
2156     response.setMIMEType("text/html");
2157     response.setHTTPStatusCode(500);
2158     WebHistoryItem errorHistoryItem;
2159     errorHistoryItem.initialize();
2160     errorHistoryItem.setURLString(WebString::fromUTF8(errorURL.c_str(), errorURL.length()));
2161     errorHistoryItem.setOriginalURLString(WebString::fromUTF8(errorURL.c_str(), errorURL.length()));
2162     Platform::current()->unitTestSupport()->registerMockedErrorURL(URLTestHelpers::toKURL(errorURL), response, error);
2163     frame->loadHistoryItem(errorHistoryItem);
2164     Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests();
2165
2166     WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
2167     EXPECT_EQ("This should appear", std::string(text.utf8().data()));
2168     EXPECT_TRUE(webFrameClient.commitCalled());
2169
2170     m_webView->close();
2171     m_webView = 0;
2172 }
2173
2174 class TestWillInsertBodyWebFrameClient : public WebFrameClient {
2175 public:
2176     TestWillInsertBodyWebFrameClient() : m_numBodies(0), m_didLoad(false)
2177     {
2178     }
2179
2180     virtual void didCommitProvisionalLoad(WebFrame*, bool) OVERRIDE
2181     {
2182         m_numBodies = 0;
2183         m_didLoad = true;
2184     }
2185
2186     virtual void didCreateDocumentElement(WebFrame*) OVERRIDE
2187     {
2188         EXPECT_EQ(0, m_numBodies);
2189     }
2190
2191     virtual void willInsertBody(WebFrame*) OVERRIDE
2192     {
2193         m_numBodies++;
2194     }
2195
2196     int m_numBodies;
2197     bool m_didLoad;
2198 };
2199
2200 TEST_F(WebFrameTest, HTMLDocument)
2201 {
2202     registerMockedHttpURLLoad("clipped-body.html");
2203
2204     TestWillInsertBodyWebFrameClient webFrameClient;
2205     m_webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "clipped-body.html", false, &webFrameClient);
2206
2207     EXPECT_TRUE(webFrameClient.m_didLoad);
2208     EXPECT_EQ(1, webFrameClient.m_numBodies);
2209
2210     m_webView->close();
2211     m_webView = 0;
2212 }
2213
2214 TEST_F(WebFrameTest, EmptyDocument)
2215 {
2216     registerMockedHttpURLLoad("pageserializer/green_rectangle.svg");
2217
2218     TestWillInsertBodyWebFrameClient webFrameClient;
2219     m_webView = FrameTestHelpers::createWebView(false, &webFrameClient);
2220
2221     EXPECT_FALSE(webFrameClient.m_didLoad);
2222     EXPECT_EQ(1, webFrameClient.m_numBodies); // The empty document that a new frame starts with triggers this.
2223     m_webView->close();
2224     m_webView = 0;
2225 }
2226
2227 TEST_F(WebFrameTest, MoveCaretSelectionTowardsWindowPointWithNoSelection)
2228 {
2229     m_webView = FrameTestHelpers::createWebViewAndLoad("about:blank", true);
2230     WebFrame* frame = m_webView->mainFrame();
2231
2232     // This test passes if this doesn't crash.
2233     frame->moveCaretSelectionTowardsWindowPoint(WebPoint(0, 0));
2234 }
2235
2236 } // namespace