[Chromium] Let the embedder override the max page scale factor set by the page
[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 "Frame.h"
36 #include "FrameTestHelpers.h"
37 #include "FrameView.h"
38 #include "ResourceError.h"
39 #include "WebDataSource.h"
40 #include "WebDocument.h"
41 #include "WebFindOptions.h"
42 #include "WebFormElement.h"
43 #include "WebFrameClient.h"
44 #include "WebFrameImpl.h"
45 #include "WebRange.h"
46 #include "WebScriptSource.h"
47 #include "WebSearchableFormData.h"
48 #include "WebSecurityOrigin.h"
49 #include "WebSecurityPolicy.h"
50 #include "WebSettings.h"
51 #include "WebViewClient.h"
52 #include "WebViewImpl.h"
53 #include "v8.h"
54 #include <gtest/gtest.h>
55 #include <webkit/support/webkit_support.h>
56
57 using namespace WebKit;
58
59 namespace {
60
61 class WebFrameTest : public testing::Test {
62 public:
63     WebFrameTest()
64         : m_baseURL("http://www.test.com/"),
65           m_chromeURL("chrome://")
66     {
67     }
68
69     virtual void TearDown()
70     {
71         webkit_support::UnregisterAllMockedURLs();
72     }
73
74     void registerMockedHttpURLLoad(const std::string& fileName)
75     {
76         FrameTestHelpers::registerMockedURLLoadAsHTML(m_baseURL, fileName);
77     }
78
79     void registerMockedChromeURLLoad(const std::string& fileName)
80     {
81         FrameTestHelpers::registerMockedURLLoadAsHTML(m_chromeURL, fileName);
82     }
83
84 protected:
85     std::string m_baseURL;
86     std::string m_chromeURL;
87 };
88
89 TEST_F(WebFrameTest, ContentText)
90 {
91     registerMockedHttpURLLoad("iframes_test.html");
92     registerMockedHttpURLLoad("visible_iframe.html");
93     registerMockedHttpURLLoad("invisible_iframe.html");
94     registerMockedHttpURLLoad("zero_sized_iframe.html");
95
96     WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "iframes_test.html");
97
98     // Now retrieve the frames text and test it only includes visible elements.
99     std::string content = webView->mainFrame()->contentAsText(1024).utf8();
100     EXPECT_NE(std::string::npos, content.find(" visible paragraph"));
101     EXPECT_NE(std::string::npos, content.find(" visible iframe"));
102     EXPECT_EQ(std::string::npos, content.find(" invisible pararaph"));
103     EXPECT_EQ(std::string::npos, content.find(" invisible iframe"));
104     EXPECT_EQ(std::string::npos, content.find("iframe with zero size"));
105
106     webView->close();
107 }
108
109 TEST_F(WebFrameTest, FrameForEnteredContext)
110 {
111     registerMockedHttpURLLoad("iframes_test.html");
112     registerMockedHttpURLLoad("visible_iframe.html");
113     registerMockedHttpURLLoad("invisible_iframe.html");
114     registerMockedHttpURLLoad("zero_sized_iframe.html");
115
116     WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "iframes_test.html", true);
117
118     v8::HandleScope scope;
119     EXPECT_EQ(webView->mainFrame(),
120               WebFrame::frameForContext(
121                   webView->mainFrame()->mainWorldScriptContext()));
122     EXPECT_EQ(webView->mainFrame()->firstChild(),
123               WebFrame::frameForContext(
124                   webView->mainFrame()->firstChild()->mainWorldScriptContext()));
125
126     webView->close();
127 }
128
129 TEST_F(WebFrameTest, FormWithNullFrame)
130 {
131     registerMockedHttpURLLoad("form.html");
132
133     WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "form.html");
134
135     WebVector<WebFormElement> forms;
136     webView->mainFrame()->document().forms(forms);
137     webView->close();
138
139     EXPECT_EQ(forms.size(), 1U);
140
141     // This test passes if this doesn't crash.
142     WebSearchableFormData searchableDataForm(forms[0]);
143 }
144
145 TEST_F(WebFrameTest, ChromePageJavascript)
146 {
147     registerMockedChromeURLLoad("history.html");
148  
149     // Pass true to enable JavaScript.
150     WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_chromeURL + "history.html", true);
151
152     // Try to run JS against the chrome-style URL.
153     FrameTestHelpers::loadFrame(webView->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Clobbered'))");
154
155     // Required to see any updates in contentAsText.
156     webView->layout();
157
158     // Now retrieve the frame's text and ensure it was modified by running javascript.
159     std::string content = webView->mainFrame()->contentAsText(1024).utf8();
160     EXPECT_NE(std::string::npos, content.find("Clobbered"));
161 }
162
163 TEST_F(WebFrameTest, ChromePageNoJavascript)
164 {
165     registerMockedChromeURLLoad("history.html");
166
167     /// Pass true to enable JavaScript.
168     WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_chromeURL + "history.html", true);
169
170     // Try to run JS against the chrome-style URL after prohibiting it.
171     WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs("chrome");
172     FrameTestHelpers::loadFrame(webView->mainFrame(), "javascript:document.body.appendChild(document.createTextNode('Clobbered'))");
173
174     // Required to see any updates in contentAsText.
175     webView->layout();
176
177     // Now retrieve the frame's text and ensure it wasn't modified by running javascript.
178     std::string content = webView->mainFrame()->contentAsText(1024).utf8();
179     EXPECT_EQ(std::string::npos, content.find("Clobbered"));
180 }
181
182 TEST_F(WebFrameTest, DispatchMessageEventWithOriginCheck)
183 {
184     registerMockedHttpURLLoad("postmessage_test.html");
185
186     // Pass true to enable JavaScript.
187     WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "postmessage_test.html", true);
188     
189     // Send a message with the correct origin.
190     WebSecurityOrigin correctOrigin(WebSecurityOrigin::create(GURL(m_baseURL)));
191     WebDOMEvent event = webView->mainFrame()->document().createEvent("MessageEvent");
192     WebDOMMessageEvent message = event.to<WebDOMMessageEvent>();
193     WebSerializedScriptValue data(WebSerializedScriptValue::fromString("foo"));
194     message.initMessageEvent("message", false, false, data, "http://origin.com", 0, "");
195     webView->mainFrame()->dispatchMessageEventWithOriginCheck(correctOrigin, message);
196
197     // Send another message with incorrect origin.
198     WebSecurityOrigin incorrectOrigin(WebSecurityOrigin::create(GURL(m_chromeURL)));
199     webView->mainFrame()->dispatchMessageEventWithOriginCheck(incorrectOrigin, message);
200
201     // Required to see any updates in contentAsText.
202     webView->layout();
203
204     // Verify that only the first addition is in the body of the page.
205     std::string content = webView->mainFrame()->contentAsText(1024).utf8();
206     EXPECT_NE(std::string::npos, content.find("Message 1."));
207     EXPECT_EQ(std::string::npos, content.find("Message 2."));
208 }
209
210 #if ENABLE(VIEWPORT)
211
212 class FixedLayoutTestWebViewClient : public WebViewClient {
213  public:
214     virtual WebRect windowRect() OVERRIDE { return m_windowRect; }
215     virtual WebScreenInfo screenInfo() OVERRIDE { return m_screenInfo; }
216
217     WebRect m_windowRect;
218     WebScreenInfo m_screenInfo;
219 };
220
221 TEST_F(WebFrameTest, DeviceScaleFactorUsesDefaultWithoutViewportTag)
222 {
223     registerMockedHttpURLLoad("no_viewport_tag.html");
224
225     int viewportWidth = 640;
226     int viewportHeight = 480;
227
228     FixedLayoutTestWebViewClient client;
229     client.m_screenInfo.horizontalDPI = 320;
230     client.m_windowRect = WebRect(0, 0, viewportWidth, viewportHeight);
231
232     WebView* webView = static_cast<WebView*>(FrameTestHelpers::createWebViewAndLoad(m_baseURL + "no_viewport_tag.html", true, 0, &client));
233
234     webView->settings()->setViewportEnabled(true);
235     webView->enableFixedLayoutMode(true);
236     webView->resize(WebSize(viewportWidth, viewportHeight));
237     webView->layout();
238
239     EXPECT_EQ(2, webView->deviceScaleFactor());
240
241     // Device scale factor should be a component of page scale factor in fixed-layout, so a scale of 1 becomes 2.
242     webView->setPageScaleFactorLimits(1, 2);
243     EXPECT_EQ(2, webView->pageScaleFactor());
244
245     // Force the layout to happen before leaving the test.
246     webView->mainFrame()->contentAsText(1024).utf8();
247 }
248
249 TEST_F(WebFrameTest, FixedLayoutInitializeAtMinimumPageScale)
250 {
251     registerMockedHttpURLLoad("fixed_layout.html");
252
253     FixedLayoutTestWebViewClient client;
254     client.m_screenInfo.horizontalDPI = 160;
255     int viewportWidth = 640;
256     int viewportHeight = 480;
257     client.m_windowRect = WebRect(0, 0, viewportWidth, viewportHeight);
258
259     // Make sure we initialize to minimum scale, even if the window size
260     // only becomes available after the load begins.
261     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(FrameTestHelpers::createWebViewAndLoad(m_baseURL + "fixed_layout.html", true, 0, &client));
262     webViewImpl->enableFixedLayoutMode(true);
263     webViewImpl->settings()->setViewportEnabled(true);
264     webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
265
266     int defaultFixedLayoutWidth = 980;
267     float minimumPageScaleFactor = viewportWidth / (float) defaultFixedLayoutWidth;
268     EXPECT_EQ(minimumPageScaleFactor, webViewImpl->pageScaleFactor());
269
270     // Assume the user has pinch zoomed to page scale factor 2.
271     float userPinchPageScaleFactor = 2;
272     webViewImpl->setPageScaleFactorPreservingScrollOffset(userPinchPageScaleFactor);
273     webViewImpl->mainFrameImpl()->frameView()->layout();
274
275     // Make sure we don't reset to initial scale if the page continues to load.
276     bool isNewNavigation;
277     webViewImpl->didCommitLoad(&isNewNavigation, false);
278     webViewImpl->didChangeContentsSize();
279     EXPECT_EQ(userPinchPageScaleFactor, webViewImpl->pageScaleFactor());
280
281     // Make sure we don't reset to initial scale if the viewport size changes.
282     webViewImpl->resize(WebSize(viewportWidth, viewportHeight + 100));
283     EXPECT_EQ(userPinchPageScaleFactor, webViewImpl->pageScaleFactor());
284 }
285 #endif
286
287 TEST_F(WebFrameTest, CanOverrideMaximumScaleFactor)
288 {
289     registerMockedHttpURLLoad("no_scale_for_you.html");
290
291     FixedLayoutTestWebViewClient client;
292     client.m_screenInfo.horizontalDPI = 160;
293     int viewportWidth = 640;
294     int viewportHeight = 480;
295     client.m_windowRect = WebRect(0, 0, viewportWidth, viewportHeight);
296
297     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(FrameTestHelpers::createWebViewAndLoad(m_baseURL + "no_scale_for_you.html", true, 0, &client));
298     webViewImpl->enableFixedLayoutMode(true);
299     webViewImpl->settings()->setViewportEnabled(true);
300     webViewImpl->resize(WebSize(viewportWidth, viewportHeight));
301
302     EXPECT_EQ(1.0f, webViewImpl->maximumPageScaleFactor());
303
304     webViewImpl->setIgnoreViewportTagMaximumScale(true);
305
306     EXPECT_EQ(4.0f, webViewImpl->maximumPageScaleFactor());
307 }
308
309 #if ENABLE(GESTURE_EVENTS)
310 TEST_F(WebFrameTest, DivAutoZoomParamsTest)
311 {
312     registerMockedHttpURLLoad("get_scale_for_auto_zoom_into_div_test.html");
313
314     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(FrameTestHelpers::createWebViewAndLoad(m_baseURL + "get_scale_for_auto_zoom_into_div_test.html", true));
315     int pageWidth = 640;
316     int pageHeight = 480;
317     int divPosX = 200;
318     int divPosY = 200;
319     int divWidth = 200;
320     int divHeight = 150;
321     WebRect doubleTapPoint(250, 250, 0, 0);
322     webViewImpl->resize(WebSize(pageWidth, pageHeight));
323     float scale;
324     WebPoint scroll;
325
326     // Test for Doubletap scaling
327
328     // Tests for zooming in and out without clamping.
329     // Set device scale and scale limits so we dont get clamped.
330     webViewImpl->setDeviceScaleFactor(4);
331     webViewImpl->setPageScaleFactorLimits(0, 4 / webViewImpl->deviceScaleFactor());
332
333     // Test zooming into div.
334     webViewImpl->computeScaleAndScrollForHitRect(doubleTapPoint, WebViewImpl::DoubleTap, scale, scroll);
335     float scaledDivWidth = divWidth * scale;
336     float scaledDivHeight = divHeight * scale;
337     int hScroll = ((divPosX * scale) - ((pageWidth - scaledDivWidth) / 2)) / scale;
338     int vScroll = ((divPosY * scale) - ((pageHeight - scaledDivHeight) / 2)) / scale;
339     EXPECT_NEAR(pageWidth / divWidth, scale, 0.1);
340     EXPECT_EQ(hScroll, scroll.x);
341     EXPECT_EQ(vScroll, scroll.y);
342
343     // Test zoom out to overview scale.
344     webViewImpl->applyScrollAndScale(WebSize(scroll.x, scroll.y), scale / webViewImpl->pageScaleFactor());
345     webViewImpl->computeScaleAndScrollForHitRect(doubleTapPoint, WebViewImpl::DoubleTap, scale, scroll);
346     EXPECT_FLOAT_EQ(1, scale);
347     EXPECT_EQ(WebPoint(0, 0), scroll);
348
349     // Tests for clamped scaling.
350     // Test clamp to device scale:
351     webViewImpl->applyScrollAndScale(WebSize(scroll.x, scroll.y), scale / webViewImpl->pageScaleFactor());
352     webViewImpl->setDeviceScaleFactor(2.5);
353     webViewImpl->computeScaleAndScrollForHitRect(doubleTapPoint, WebViewImpl::DoubleTap, scale, scroll);
354     EXPECT_FLOAT_EQ(2.5, scale);
355
356     // Test clamp to minimum scale:
357     webViewImpl->applyScrollAndScale(WebSize(scroll.x, scroll.y), scale / webViewImpl->pageScaleFactor());
358     webViewImpl->setPageScaleFactorLimits(1.5 / webViewImpl->deviceScaleFactor(), 4 / webViewImpl->deviceScaleFactor());
359     webViewImpl->computeScaleAndScrollForHitRect(doubleTapPoint, WebViewImpl::DoubleTap, scale, scroll);
360     EXPECT_FLOAT_EQ(1.5, scale);
361     EXPECT_EQ(WebPoint(0, 0), scroll);
362
363     // Test clamp to maximum scale:
364     webViewImpl->applyScrollAndScale(WebSize(scroll.x, scroll.y), scale / webViewImpl->pageScaleFactor());
365     webViewImpl->setDeviceScaleFactor(4);
366     webViewImpl->setPageScaleFactorLimits(0, 3 / webViewImpl->deviceScaleFactor());
367     webViewImpl->computeScaleAndScrollForHitRect(doubleTapPoint, WebViewImpl::DoubleTap, scale, scroll);
368     EXPECT_FLOAT_EQ(3, scale);
369
370     // Test for Non-doubletap scaling
371     webViewImpl->setPageScaleFactor(1, WebPoint(0, 0));
372     webViewImpl->setDeviceScaleFactor(4);
373     webViewImpl->setPageScaleFactorLimits(0, 4 / webViewImpl->deviceScaleFactor());
374     // Test zooming into div.
375     webViewImpl->computeScaleAndScrollForHitRect(WebRect(250, 250, 10, 10), WebViewImpl::FindInPage, scale, scroll);
376     EXPECT_NEAR(pageWidth / divWidth, scale, 0.1);
377
378     // Drop any pending fake mouse events from zooming before leaving the test.
379     webViewImpl->page()->mainFrame()->eventHandler()->clear();
380 }
381 #endif
382
383 class TestReloadDoesntRedirectWebFrameClient : public WebFrameClient {
384 public:
385     virtual WebNavigationPolicy decidePolicyForNavigation(
386         WebFrame*, const WebURLRequest&, WebNavigationType,
387         const WebNode& originatingNode,
388         WebNavigationPolicy defaultPolicy, bool isRedirect)
389     {
390         EXPECT_FALSE(isRedirect);
391         return WebNavigationPolicyCurrentTab;
392     }
393
394     virtual WebURLError cancelledError(WebFrame*, const WebURLRequest& request)
395     {
396         // Return a dummy error so the DocumentLoader doesn't assert when
397         // the reload cancels it.
398         WebURLError webURLError;
399         webURLError.domain = "";
400         webURLError.reason = 1;
401         webURLError.isCancellation = true;
402         webURLError.unreachableURL = WebURL();
403         return webURLError;
404     }
405 };
406
407 TEST_F(WebFrameTest, ReloadDoesntSetRedirect)
408 {
409     // Test for case in http://crbug.com/73104. Reloading a frame very quickly
410     // would sometimes call decidePolicyForNavigation with isRedirect=true
411     registerMockedHttpURLLoad("form.html");
412
413     TestReloadDoesntRedirectWebFrameClient webFrameClient;
414     WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "form.html", false, &webFrameClient);
415
416     webView->mainFrame()->reload(true);
417     // start reload before request is delivered.
418     webView->mainFrame()->reload(true);
419     webkit_support::ServeAsynchronousMockedRequests();
420 }
421
422 TEST_F(WebFrameTest, IframeRedirect)
423 {
424     registerMockedHttpURLLoad("iframe_redirect.html");
425     registerMockedHttpURLLoad("visible_iframe.html");
426
427     WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "iframe_redirect.html", true);
428     webkit_support::RunAllPendingMessages(); // Queue the iframe.
429     webkit_support::ServeAsynchronousMockedRequests(); // Load the iframe.
430
431     WebFrame* iframe = webView->findFrameByName(WebString::fromUTF8("ifr"));
432     ASSERT_TRUE(iframe);
433     WebDataSource* iframeDataSource = iframe->dataSource();
434     ASSERT_TRUE(iframeDataSource);
435     WebVector<WebURL> redirects;
436     iframeDataSource->redirectChain(redirects);
437     ASSERT_EQ(2U, redirects.size());
438     EXPECT_EQ(GURL("about:blank"), GURL(redirects[0]));
439     EXPECT_EQ(GURL("http://www.test.com/visible_iframe.html"), GURL(redirects[1]));
440
441     webView->close();
442 }
443
444 TEST_F(WebFrameTest, ClearFocusedNodeTest)
445 {
446     registerMockedHttpURLLoad("iframe_clear_focused_node_test.html");
447     registerMockedHttpURLLoad("autofocus_input_field_iframe.html");
448
449     WebViewImpl* webViewImpl = static_cast<WebViewImpl*>(FrameTestHelpers::createWebViewAndLoad(m_baseURL + "iframe_clear_focused_node_test.html", true));
450
451     // Clear the focused node.
452     webViewImpl->clearFocusedNode();
453
454     // Now retrieve the FocusedNode and test it should be null.
455     EXPECT_EQ(0, webViewImpl->focusedWebCoreNode());
456
457     webViewImpl->close();
458 }
459
460 // Implementation of WebFrameClient that tracks the v8 contexts that are created
461 // and destroyed for verification.
462 class ContextLifetimeTestWebFrameClient : public WebFrameClient {
463 public:
464     struct Notification {
465     public:
466         Notification(WebFrame* frame, v8::Handle<v8::Context> context, int worldId)
467             : frame(frame) ,
468               context(v8::Persistent<v8::Context>::New(context)),
469               worldId(worldId)
470         {
471         }
472
473         ~Notification()
474         {
475             context.Dispose();
476         }
477
478         bool Equals(Notification* other)
479         {
480             return other && frame == other->frame && context == other->context && worldId == other->worldId;
481         }
482
483         WebFrame* frame;
484         v8::Persistent<v8::Context> context;
485         int worldId;
486     };
487
488     ~ContextLifetimeTestWebFrameClient()
489     {
490         reset();
491     }
492
493     void reset()
494     {
495         for (size_t i = 0; i < createNotifications.size(); ++i)
496             delete createNotifications[i];
497
498         for (size_t i = 0; i < releaseNotifications.size(); ++i)
499             delete releaseNotifications[i];
500
501         createNotifications.clear();
502         releaseNotifications.clear();
503     }
504
505     std::vector<Notification*> createNotifications;
506     std::vector<Notification*> releaseNotifications;
507
508  private:
509     virtual void didCreateScriptContext(WebFrame* frame, v8::Handle<v8::Context> context, int extensionGroup, int worldId) OVERRIDE
510     {
511         createNotifications.push_back(new Notification(frame, context, worldId));
512     }
513
514     virtual void willReleaseScriptContext(WebFrame* frame, v8::Handle<v8::Context> context, int worldId) OVERRIDE
515     {
516         releaseNotifications.push_back(new Notification(frame, context, worldId));
517     }
518 };
519
520 TEST_F(WebFrameTest, ContextNotificationsLoadUnload)
521 {
522     v8::HandleScope handleScope;
523
524     registerMockedHttpURLLoad("context_notifications_test.html");
525     registerMockedHttpURLLoad("context_notifications_test_frame.html");
526
527     // Load a frame with an iframe, make sure we get the right create notifications.
528     ContextLifetimeTestWebFrameClient webFrameClient;
529     WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
530
531     WebFrame* mainFrame = webView->mainFrame();
532     WebFrame* childFrame = mainFrame->firstChild();
533
534     ASSERT_EQ(2u, webFrameClient.createNotifications.size());
535     EXPECT_EQ(0u, webFrameClient.releaseNotifications.size());
536
537     ContextLifetimeTestWebFrameClient::Notification* firstCreateNotification = webFrameClient.createNotifications[0];
538     ContextLifetimeTestWebFrameClient::Notification* secondCreateNotification = webFrameClient.createNotifications[1];
539
540     EXPECT_EQ(mainFrame, firstCreateNotification->frame);
541     EXPECT_EQ(mainFrame->mainWorldScriptContext(), firstCreateNotification->context);
542     EXPECT_EQ(0, firstCreateNotification->worldId);
543
544     EXPECT_EQ(childFrame, secondCreateNotification->frame);
545     EXPECT_EQ(childFrame->mainWorldScriptContext(), secondCreateNotification->context);
546     EXPECT_EQ(0, secondCreateNotification->worldId);
547
548     // Close the view. We should get two release notifications that are exactly the same as the create ones, in reverse order.
549     webView->close();
550
551     ASSERT_EQ(2u, webFrameClient.releaseNotifications.size());
552     ContextLifetimeTestWebFrameClient::Notification* firstReleaseNotification = webFrameClient.releaseNotifications[0];
553     ContextLifetimeTestWebFrameClient::Notification* secondReleaseNotification = webFrameClient.releaseNotifications[1];
554
555     ASSERT_TRUE(firstCreateNotification->Equals(secondReleaseNotification));
556     ASSERT_TRUE(secondCreateNotification->Equals(firstReleaseNotification));
557 }
558
559 TEST_F(WebFrameTest, ContextNotificationsReload)
560 {
561     v8::HandleScope handleScope;
562
563     registerMockedHttpURLLoad("context_notifications_test.html");
564     registerMockedHttpURLLoad("context_notifications_test_frame.html");
565
566     ContextLifetimeTestWebFrameClient webFrameClient;
567     WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
568
569     // Refresh, we should get two release notifications and two more create notifications.
570     webView->mainFrame()->reload(false);
571     webkit_support::ServeAsynchronousMockedRequests();
572     ASSERT_EQ(4u, webFrameClient.createNotifications.size());
573     ASSERT_EQ(2u, webFrameClient.releaseNotifications.size());
574
575     // The two release notifications we got should be exactly the same as the first two create notifications.
576     for (size_t i = 0; i < webFrameClient.releaseNotifications.size(); ++i) {
577       EXPECT_TRUE(webFrameClient.releaseNotifications[i]->Equals(
578           webFrameClient.createNotifications[webFrameClient.createNotifications.size() - 3 - i]));
579     }
580
581     // The last two create notifications should be for the current frames and context.
582     WebFrame* mainFrame = webView->mainFrame();
583     WebFrame* childFrame = mainFrame->firstChild();
584     ContextLifetimeTestWebFrameClient::Notification* firstRefreshNotification = webFrameClient.createNotifications[2];
585     ContextLifetimeTestWebFrameClient::Notification* secondRefreshNotification = webFrameClient.createNotifications[3];
586
587     EXPECT_EQ(mainFrame, firstRefreshNotification->frame);
588     EXPECT_EQ(mainFrame->mainWorldScriptContext(), firstRefreshNotification->context);
589     EXPECT_EQ(0, firstRefreshNotification->worldId);
590
591     EXPECT_EQ(childFrame, secondRefreshNotification->frame);
592     EXPECT_EQ(childFrame->mainWorldScriptContext(), secondRefreshNotification->context);
593     EXPECT_EQ(0, secondRefreshNotification->worldId);
594
595     webView->close();
596 }
597
598 TEST_F(WebFrameTest, ContextNotificationsIsolatedWorlds)
599 {
600     v8::HandleScope handleScope;
601
602     registerMockedHttpURLLoad("context_notifications_test.html");
603     registerMockedHttpURLLoad("context_notifications_test_frame.html");
604
605     ContextLifetimeTestWebFrameClient webFrameClient;
606     WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "context_notifications_test.html", true, &webFrameClient);
607
608     // Add an isolated world.
609     webFrameClient.reset();
610
611     int isolatedWorldId = 42;
612     WebScriptSource scriptSource("hi!");
613     int numSources = 1;
614     int extensionGroup = 0;
615     webView->mainFrame()->executeScriptInIsolatedWorld(isolatedWorldId, &scriptSource, numSources, extensionGroup);
616
617     // We should now have a new create notification.
618     ASSERT_EQ(1u, webFrameClient.createNotifications.size());
619     ContextLifetimeTestWebFrameClient::Notification* notification = webFrameClient.createNotifications[0];
620     ASSERT_EQ(isolatedWorldId, notification->worldId);
621     ASSERT_EQ(webView->mainFrame(), notification->frame);
622
623     // 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.
624     ASSERT_NE(webView->mainFrame()->mainWorldScriptContext(), notification->context);
625
626     webView->close();
627
628     // We should have gotten three release notifications (one for each of the frames, plus one for the isolated context).
629     ASSERT_EQ(3u, webFrameClient.releaseNotifications.size());
630
631     // And one of them should be exactly the same as the create notification for the isolated context.
632     int matchCount = 0;
633     for (size_t i = 0; i < webFrameClient.releaseNotifications.size(); ++i) {
634       if (webFrameClient.releaseNotifications[i]->Equals(webFrameClient.createNotifications[0]))
635         ++matchCount;
636     }
637     EXPECT_EQ(1, matchCount);
638 }
639
640 TEST_F(WebFrameTest, FindInPage)
641 {
642     registerMockedHttpURLLoad("find.html");
643     WebView* webView = FrameTestHelpers::createWebViewAndLoad(m_baseURL + "find.html");
644     WebFrame* frame = webView->mainFrame();
645     const int findIdentifier = 12345;
646     WebFindOptions options;
647
648     // Find in a <div> element.
649     EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar1"), options, false, 0));
650     frame->stopFinding(false);
651     WebRange range = frame->selectionRange();
652     EXPECT_EQ(5, range.startOffset());
653     EXPECT_EQ(9, range.endOffset());
654     EXPECT_TRUE(frame->document().focusedNode().isNull());
655
656     // Find in an <input> value.
657     EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar2"), options, false, 0));
658     // Confirm stopFinding(false) sets the selection on the found text.
659     frame->stopFinding(false);
660     range = frame->selectionRange();
661     ASSERT_FALSE(range.isNull());
662     EXPECT_EQ(5, range.startOffset());
663     EXPECT_EQ(9, range.endOffset());
664     EXPECT_EQ(WebString::fromUTF8("INPUT"), frame->document().focusedNode().nodeName());
665
666     // Find in a <textarea> content.
667     EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar3"), options, false, 0));
668     // Confirm stopFinding(false) sets the selection on the found text.
669     frame->stopFinding(false);
670     range = frame->selectionRange();
671     ASSERT_FALSE(range.isNull());
672     EXPECT_EQ(5, range.startOffset());
673     EXPECT_EQ(9, range.endOffset());
674     EXPECT_EQ(WebString::fromUTF8("TEXTAREA"), frame->document().focusedNode().nodeName());
675
676     // Find in a contentEditable element.
677     EXPECT_TRUE(frame->find(findIdentifier, WebString::fromUTF8("bar4"), options, false, 0));
678     // Confirm stopFinding(false) sets the selection on the found text.
679     frame->stopFinding(false);
680     range = frame->selectionRange();
681     ASSERT_FALSE(range.isNull());
682     EXPECT_EQ(0, range.startOffset());
683     EXPECT_EQ(4, range.endOffset());
684     // "bar4" is surrounded by <span>, but the focusable node should be the parent <div>.
685     EXPECT_EQ(WebString::fromUTF8("DIV"), frame->document().focusedNode().nodeName());
686
687     webView->close();
688 }
689
690 TEST_F(WebFrameTest, GetContentAsPlainText)
691 {
692     WebView* webView = FrameTestHelpers::createWebViewAndLoad("about:blank", true);
693     // We set the size because it impacts line wrapping, which changes the
694     // resulting text value.
695     webView->resize(WebSize(640, 480));
696     WebFrame* frame = webView->mainFrame();
697
698     // Generate a simple test case.
699     const char simpleSource[] = "<div>Foo bar</div><div></div>baz";
700     GURL testURL("about:blank");
701     frame->loadHTMLString(simpleSource, testURL);
702     webkit_support::RunAllPendingMessages();
703
704     // Make sure it comes out OK.
705     const std::string expected("Foo bar\nbaz");
706     WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
707     EXPECT_EQ(expected, std::string(text.utf8()));
708
709     // Try reading the same one with clipping of the text.
710     const int length = 5;
711     text = frame->contentAsText(length);
712     EXPECT_EQ(expected.substr(0, length), std::string(text.utf8()));
713
714     // Now do a new test with a subframe.
715     const char outerFrameSource[] = "Hello<iframe></iframe> world";
716     frame->loadHTMLString(outerFrameSource, testURL);
717     webkit_support::RunAllPendingMessages();
718
719     // Load something into the subframe.
720     WebFrame* subframe = frame->findChildByExpression(WebString::fromUTF8("/html/body/iframe"));
721     ASSERT_TRUE(subframe);
722     subframe->loadHTMLString("sub<p>text", testURL);
723     webkit_support::RunAllPendingMessages();
724
725     text = frame->contentAsText(std::numeric_limits<size_t>::max());
726     EXPECT_EQ("Hello world\n\nsub\ntext", std::string(text.utf8()));
727
728     // Get the frame text where the subframe separator falls on the boundary of
729     // what we'll take. There used to be a crash in this case.
730     text = frame->contentAsText(12);
731     EXPECT_EQ("Hello world", std::string(text.utf8()));
732
733     webView->close();
734 }
735
736 TEST_F(WebFrameTest, GetFullHtmlOfPage)
737 {
738     WebView* webView = FrameTestHelpers::createWebViewAndLoad("about:blank", true);
739     WebFrame* frame = webView->mainFrame();
740
741     // Generate a simple test case.
742     const char simpleSource[] = "<p>Hello</p><p>World</p>";
743     GURL testURL("about:blank");
744     frame->loadHTMLString(simpleSource, testURL);
745     webkit_support::RunAllPendingMessages();
746
747     WebString text = frame->contentAsText(std::numeric_limits<size_t>::max());
748     EXPECT_EQ("Hello\n\nWorld", std::string(text.utf8()));
749
750     const std::string html = frame->contentAsMarkup().utf8();
751
752     // Load again with the output html.
753     frame->loadHTMLString(html, testURL);
754     webkit_support::RunAllPendingMessages();
755
756     EXPECT_EQ(html, std::string(frame->contentAsMarkup().utf8()));
757
758     text = frame->contentAsText(std::numeric_limits<size_t>::max());
759     EXPECT_EQ("Hello\n\nWorld", std::string(text.utf8()));
760
761     // Test selection check
762     EXPECT_FALSE(frame->hasSelection());
763     frame->executeCommand(WebString::fromUTF8("SelectAll"));
764     EXPECT_TRUE(frame->hasSelection());
765     frame->executeCommand(WebString::fromUTF8("Unselect"));
766     EXPECT_FALSE(frame->hasSelection());
767     WebString selectionHtml = frame->selectionAsMarkup();
768     EXPECT_TRUE(selectionHtml.isEmpty());
769 }
770
771 } // namespace