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