Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / web_contents / web_contents_impl_browsertest.cc
index b06a628..b143f5a 100644 (file)
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
+#include "content/browser/web_contents/web_contents_view.h"
 #include "content/public/browser/load_notification_details.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_view.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
-#include "content/test/content_browser_test.h"
-#include "content/test/content_browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
 namespace content {
@@ -30,17 +32,17 @@ void ResizeWebContentsView(Shell* shell, const gfx::Size& size,
   // works on Win and ChromeOS but not Linux - we need to resize the shell
   // window on Linux because if we don't, the next layout of the unchanged shell
   // window will resize WebContentsView back to the previous size.
-  // The cleaner and shorter SizeContents is preferred as more platforms convert
-  // to Aura.
-#if defined(TOOLKIT_GTK) || defined(OS_MACOSX)
+  // SizeContents is a hack and should not be relied on.
+#if defined(OS_MACOSX)
   shell->SizeTo(size);
   // If |set_start_page| is true, start with blank page to make sure resize
   // takes effect.
   if (set_start_page)
     NavigateToURL(shell, GURL("about://blank"));
 #else
-  shell->web_contents()->GetView()->SizeContents(size);
-#endif  // defined(TOOLKIT_GTK) || defined(OS_MACOSX)
+  static_cast<WebContentsImpl*>(shell->web_contents())->GetView()->
+      SizeContents(size);
+#endif  // defined(OS_MACOSX)
 }
 
 class WebContentsImplBrowserTest : public ContentBrowserTest {
@@ -95,6 +97,7 @@ class NavigateOnCommitObserver : public WebContentsObserver {
       const LoadCommittedDetails& load_details) OVERRIDE {
     if (!done_) {
       done_ = true;
+      shell_->Stop();
       shell_->LoadURL(url_);
     }
   }
@@ -112,8 +115,8 @@ class RenderViewSizeDelegate : public WebContentsDelegate {
 
   // WebContentsDelegate:
   virtual gfx::Size GetSizeForNewRenderView(
-      const WebContents* web_contents) const OVERRIDE {
-    gfx::Size size(web_contents->GetView()->GetContainerSize());
+      WebContents* web_contents) const OVERRIDE {
+    gfx::Size size(web_contents->GetContainerBounds().size());
     size.Enlarge(size_insets_.width(), size_insets_.height());
     return size;
   }
@@ -149,6 +152,31 @@ class RenderViewSizeObserver : public WebContentsObserver {
   gfx::Size rwhv_create_size_;
 };
 
+class LoadingStateChangedDelegate : public WebContentsDelegate {
+ public:
+  LoadingStateChangedDelegate()
+      : loadingStateChangedCount_(0)
+      , loadingStateToDifferentDocumentCount_(0) {
+  }
+
+  // WebContentsDelegate:
+  virtual void LoadingStateChanged(WebContents* contents,
+                                   bool to_different_document) OVERRIDE {
+      loadingStateChangedCount_++;
+      if (to_different_document)
+        loadingStateToDifferentDocumentCount_++;
+  }
+
+  int loadingStateChangedCount() const { return loadingStateChangedCount_; }
+  int loadingStateToDifferentDocumentCount() const {
+    return loadingStateToDifferentDocumentCount_;
+  }
+
+ private:
+  int loadingStateChangedCount_;
+  int loadingStateToDifferentDocumentCount_;
+};
+
 // See: http://crbug.com/298193
 #if defined(OS_WIN)
 #define MAYBE_DidStopLoadingDetails DISABLED_DidStopLoadingDetails
@@ -185,6 +213,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
                        MAYBE_DidStopLoadingDetailsWithPending) {
   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  GURL url("data:text/html,<div>test</div>");
 
   // Listen for the first load to stop.
   LoadStopNotificationObserver load_observer(
@@ -194,10 +223,10 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
   // is started.
   NavigateOnCommitObserver commit_observer(
       shell(), embedded_test_server()->GetURL("/title2.html"));
-  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+  NavigateToURL(shell(), url);
   load_observer.Wait();
 
-  EXPECT_EQ("/title1.html", load_observer.url_.path());
+  EXPECT_EQ(url, load_observer.url_);
   EXPECT_EQ(0, load_observer.session_index_);
   EXPECT_EQ(&shell()->web_contents()->GetController(),
             load_observer.controller_);
@@ -230,11 +259,9 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
             shell()->web_contents()->GetVisibleURL());
 }
 
-// TODO(sail): enable this for MAC when auto resizing of WebContentsViewCocoa is
-// fixed.
-// TODO(shrikant): enable this for Windows when issue with
-// force-compositing-mode is resolved (http://crbug.com/281726).
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_ANDROID)
+// Crashes under ThreadSanitizer, http://crbug.com/356758.
+#if defined(OS_WIN) || defined(OS_ANDROID) \
+    || defined(THREAD_SANITIZER)
 #define MAYBE_GetSizeForNewRenderView DISABLED_GetSizeForNewRenderView
 #else
 #define MAYBE_GetSizeForNewRenderView GetSizeForNewRenderView
@@ -256,16 +283,16 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
   ASSERT_TRUE(shell()->web_contents()->GetDelegate() == delegate.get());
 
   // When no size is set, RenderWidgetHostView adopts the size of
-  // WebContenntsView.
+  // WebContentsView.
   NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html"));
-  EXPECT_EQ(shell()->web_contents()->GetView()->GetContainerSize(),
+  EXPECT_EQ(shell()->web_contents()->GetContainerBounds().size(),
             shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds().
                 size());
 
   // When a size is set, RenderWidgetHostView and WebContentsView honor this
   // size.
   gfx::Size size(300, 300);
-  gfx::Size size_insets(-10, -15);
+  gfx::Size size_insets(10, 15);
   ResizeWebContentsView(shell(), size, true);
   delegate->set_size_insets(size_insets);
   NavigateToURL(shell(), https_server.GetURL("/"));
@@ -273,14 +300,23 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
   EXPECT_EQ(size,
             shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds().
                 size());
-  EXPECT_EQ(size, shell()->web_contents()->GetView()->GetContainerSize());
+  // The web_contents size is set by the embedder, and should not depend on the
+  // rwhv size. The behavior is correct on OSX, but incorrect on other
+  // platforms.
+  gfx::Size exp_wcv_size(300, 300);
+#if !defined(OS_MACOSX)
+  exp_wcv_size.Enlarge(size_insets.width(), size_insets.height());
+#endif
+
+  EXPECT_EQ(exp_wcv_size,
+            shell()->web_contents()->GetContainerBounds().size());
 
   // If WebContentsView is resized after RenderWidgetHostView is created but
   // before pending navigation entry is committed, both RenderWidgetHostView and
   // WebContentsView use the new size of WebContentsView.
   gfx::Size init_size(200, 200);
   gfx::Size new_size(100, 100);
-  size_insets = gfx::Size(-20, -30);
+  size_insets = gfx::Size(20, 30);
   ResizeWebContentsView(shell(), init_size, true);
   delegate->set_size_insets(size_insets);
   RenderViewSizeObserver observer(shell(), new_size);
@@ -288,21 +324,25 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
   // RenderWidgetHostView is created at specified size.
   init_size.Enlarge(size_insets.width(), size_insets.height());
   EXPECT_EQ(init_size, observer.rwhv_create_size());
-  // RenderViewSizeObserver resizes WebContentsView in
-  // DidStartNavigationToPendingEntry, so both WebContentsView and
-  // RenderWidgetHostView adopt this new size.
+
+// Once again, the behavior is correct on OSX. The embedder explicitly sets
+// the size to (100,100) during navigation. Both the wcv and the rwhv should
+// take on that size.
+#if !defined(OS_MACOSX)
   new_size.Enlarge(size_insets.width(), size_insets.height());
-  EXPECT_EQ(new_size,
-            shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds().
-                size());
-  EXPECT_EQ(new_size, shell()->web_contents()->GetView()->GetContainerSize());
+#endif
+  gfx::Size actual_size = shell()->web_contents()->GetRenderWidgetHostView()->
+      GetViewBounds().size();
+
+  EXPECT_EQ(new_size, actual_size);
+  EXPECT_EQ(new_size, shell()->web_contents()->GetContainerBounds().size());
 }
 
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, OpenURLSubframe) {
 
-  // Navigate with source_frame_id 3, FrameTreeNode ID 4.
+  // Navigate with FrameTreeNode ID 4.
   const GURL url("http://foo");
-  OpenURLParams params(url, Referrer(), 3, 4, CURRENT_TAB, PAGE_TRANSITION_LINK,
+  OpenURLParams params(url, Referrer(), 4, CURRENT_TAB, PAGE_TRANSITION_LINK,
                        true);
   shell()->web_contents()->OpenURL(params);
 
@@ -313,5 +353,208 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, OpenURLSubframe) {
                 controller->GetPendingEntry())->frame_tree_node_id());
 }
 
+// Observer class to track the creation of RenderFrameHost objects. It is used
+// in subsequent tests.
+class RenderFrameCreatedObserver : public WebContentsObserver {
+ public:
+  RenderFrameCreatedObserver(Shell* shell)
+      : WebContentsObserver(shell->web_contents()),
+        last_rfh_(NULL) {
+  }
+
+  virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) OVERRIDE {
+    last_rfh_ = render_frame_host;
+  }
+
+  RenderFrameHost* last_rfh() const { return last_rfh_; }
+
+ private:
+  RenderFrameHost* last_rfh_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderFrameCreatedObserver);
+};
+
+// Test that creation of new RenderFrameHost objects sends the correct object
+// to the WebContentObservers. See http://crbug.com/347339.
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+                       RenderFrameCreatedCorrectProcessForObservers) {
+  std::string foo_com("foo.com");
+  GURL::Replacements replace_host;
+  net::HostPortPair foo_host_port;
+  GURL cross_site_url;
+
+  // Setup the server to allow serving separate sites, so we can perform
+  // cross-process navigation.
+  host_resolver()->AddRule("*", "127.0.0.1");
+  ASSERT_TRUE(test_server()->Start());
+
+  foo_host_port = test_server()->host_port_pair();
+  foo_host_port.set_host(foo_com);
+
+  GURL initial_url(test_server()->GetURL("/title1.html"));
+
+  cross_site_url = test_server()->GetURL("/title2.html");
+  replace_host.SetHostStr(foo_com);
+  cross_site_url = cross_site_url.ReplaceComponents(replace_host);
+
+  // Navigate to the initial URL and capture the RenderFrameHost for later
+  // comparison.
+  NavigateToURL(shell(), initial_url);
+  RenderFrameHost* orig_rfh = shell()->web_contents()->GetMainFrame();
+
+  // Install the observer and navigate cross-site.
+  RenderFrameCreatedObserver observer(shell());
+  NavigateToURL(shell(), cross_site_url);
+
+  // The observer should've seen a RenderFrameCreated call for the new frame
+  // and not the old one.
+  EXPECT_NE(observer.last_rfh(), orig_rfh);
+  EXPECT_EQ(observer.last_rfh(), shell()->web_contents()->GetMainFrame());
+}
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+                       LoadingStateChangedForSameDocumentNavigation) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  scoped_ptr<LoadingStateChangedDelegate> delegate(
+      new LoadingStateChangedDelegate());
+  shell()->web_contents()->SetDelegate(delegate.get());
+
+  LoadStopNotificationObserver load_observer(
+      &shell()->web_contents()->GetController());
+  TitleWatcher title_watcher(shell()->web_contents(),
+                             base::ASCIIToUTF16("pushState"));
+  NavigateToURL(shell(), embedded_test_server()->GetURL("/push_state.html"));
+  load_observer.Wait();
+  base::string16 title = title_watcher.WaitAndGetTitle();
+  ASSERT_EQ(title, base::ASCIIToUTF16("pushState"));
+
+  // LoadingStateChanged should be called 4 times: start and stop for the
+  // initial load of push_state.html, and start and stop for the "navigation"
+  // triggered by history.pushState(). However, the start notification for the
+  // history.pushState() navigation should set to_different_document to false.
+  EXPECT_EQ("pushState", shell()->web_contents()->GetURL().ref());
+  EXPECT_EQ(4, delegate->loadingStateChangedCount());
+  EXPECT_EQ(3, delegate->loadingStateToDifferentDocumentCount());
+}
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+                       RenderViewCreatedForChildWindow) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+  NavigateToURL(shell(),
+                embedded_test_server()->GetURL("/title1.html"));
+
+  WebContentsAddedObserver new_web_contents_observer;
+  ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
+                            "var a = document.createElement('a');"
+                            "a.href='./title2.html';"
+                            "a.target = '_blank';"
+                            "document.body.appendChild(a);"
+                            "a.click();"));
+  WebContents* new_web_contents = new_web_contents_observer.GetWebContents();
+  WaitForLoadStop(new_web_contents);
+  EXPECT_TRUE(new_web_contents_observer.RenderViewCreatedCalled());
+}
+
+struct LoadProgressDelegateAndObserver : public WebContentsDelegate,
+                                         public WebContentsObserver {
+  LoadProgressDelegateAndObserver(Shell* shell)
+      : WebContentsObserver(shell->web_contents()),
+        did_start_loading(false),
+        did_stop_loading(false) {
+    web_contents()->SetDelegate(this);
+  }
+
+  // WebContentsDelegate:
+  virtual void LoadProgressChanged(WebContents* source,
+                                   double progress) OVERRIDE {
+    EXPECT_TRUE(did_start_loading);
+    EXPECT_FALSE(did_stop_loading);
+    progresses.push_back(progress);
+  }
+
+  // WebContentsObserver:
+  virtual void DidStartLoading(RenderViewHost* render_view_host) OVERRIDE {
+    EXPECT_FALSE(did_start_loading);
+    EXPECT_EQ(0U, progresses.size());
+    EXPECT_FALSE(did_stop_loading);
+    did_start_loading = true;
+  }
+
+  virtual void DidStopLoading(RenderViewHost* render_view_host) OVERRIDE {
+    EXPECT_TRUE(did_start_loading);
+    EXPECT_GE(progresses.size(), 1U);
+    EXPECT_FALSE(did_stop_loading);
+    did_stop_loading = true;
+  }
+
+  bool did_start_loading;
+  std::vector<double> progresses;
+  bool did_stop_loading;
+};
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, LoadProgress) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  scoped_ptr<LoadProgressDelegateAndObserver> delegate(
+      new LoadProgressDelegateAndObserver(shell()));
+
+  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+
+  const std::vector<double>& progresses = delegate->progresses;
+  // All updates should be in order ...
+  if (std::adjacent_find(progresses.begin(),
+                         progresses.end(),
+                         std::greater<double>()) != progresses.end()) {
+    ADD_FAILURE() << "Progress values should be in order: "
+                  << ::testing::PrintToString(progresses);
+  }
+
+  // ... and the last one should be 1.0, meaning complete.
+  ASSERT_GE(progresses.size(), 1U)
+      << "There should be at least one progress update";
+  EXPECT_EQ(1.0, *progresses.rbegin());
+}
+
+struct FirstVisuallyNonEmptyPaintObserver : public WebContentsObserver {
+  FirstVisuallyNonEmptyPaintObserver(Shell* shell)
+      : WebContentsObserver(shell->web_contents()),
+        did_fist_visually_non_empty_paint_(false) {}
+
+  virtual void DidFirstVisuallyNonEmptyPaint() OVERRIDE {
+    did_fist_visually_non_empty_paint_ = true;
+    on_did_first_visually_non_empty_paint_.Run();
+  }
+
+  void WaitForDidFirstVisuallyNonEmptyPaint() {
+    if (did_fist_visually_non_empty_paint_)
+      return;
+    base::RunLoop run_loop;
+    on_did_first_visually_non_empty_paint_ = run_loop.QuitClosure();
+    run_loop.Run();
+  }
+
+  base::Closure on_did_first_visually_non_empty_paint_;
+  bool did_fist_visually_non_empty_paint_;
+};
+
+// See: http://crbug.com/395664
+#if defined(OS_ANDROID)
+#define MAYBE_FirstVisuallyNonEmptyPaint DISABLED_FirstVisuallyNonEmptyPaint
+#else
+// http://crbug.com/398471
+#define MAYBE_FirstVisuallyNonEmptyPaint DISABLED_FirstVisuallyNonEmptyPaint
+#endif
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+                       MAYBE_FirstVisuallyNonEmptyPaint) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  scoped_ptr<FirstVisuallyNonEmptyPaintObserver> observer(
+      new FirstVisuallyNonEmptyPaintObserver(shell()));
+
+  NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
+
+  observer->WaitForDidFirstVisuallyNonEmptyPaint();
+  ASSERT_TRUE(observer->did_fist_visually_non_empty_paint_);
+}
 
 }  // namespace content
+