fix flashing bottom gray bar when navigating away from NTP w/ unpinned bookmark bar
cause:
- when NTP has unpinned bmb, the web contents takes up the remaining height of the tab contents area.
- when navigating away from NTP, unpinned bmb disappears, so the web contents take up the entire tab contents area, i.e. taller than when on NTP.
- this resize of web contents view causes a flashing bottom gray bar after the NTP contents are cleared and before the new page contents are completely painted.
fix is to prevent any resizing, and hence re-layout, of the new page contents:
- add a method to WebContentsDelegate to allow size specification for newly-created render views.
- WebContentsImpl calls this method when creating render views and updating their sizes.
- this prevents render views from being created at a default size only to be resized immediately.
- also added browser_tests for browser and content
BUG=264207
TEST=verify per bug rpt
Review URL: https://chromiumcodereview.appspot.com/21843003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@219794 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 7d999ec..5917a447 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3552,7 +3552,7 @@
void WebContentsImpl::UpdateRenderViewSizeForRenderManager() {
// TODO(brettw) this is a hack. See WebContentsView::SizeContents.
- gfx::Size size = view_->GetContainerSize();
+ gfx::Size size = GetSizeForNewRenderView();
// 0x0 isn't a valid window size (minimal window size is 1x1) but it may be
// here during container initialization and normal window size will be set
// later. In case of tab duplication this resizing to 0x0 prevents setting
@@ -3647,7 +3647,7 @@
// Now that the RenderView has been created, we need to tell it its size.
if (rwh_view)
- rwh_view->SetSize(view_->GetContainerSize());
+ rwh_view->SetSize(GetSizeForNewRenderView());
// Make sure we use the correct starting page_id in the new RenderView.
UpdateMaxPageIDIfNecessary(render_view_host);
@@ -3751,4 +3751,13 @@
power_save_blockers_.clear();
}
+gfx::Size WebContentsImpl::GetSizeForNewRenderView() const {
+ gfx::Size size;
+ if (delegate_)
+ size = delegate_->GetSizeForNewRenderView(this);
+ if (size.IsEmpty())
+ size = view_->GetContainerSize();
+ return size;
+}
+
} // namespace content
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index bb56ddba2..55f377b 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -760,6 +760,9 @@
// Clear all PowerSaveBlockers, leave power_save_blocker_ empty.
void ClearAllPowerSaveBlockers();
+ // Helper function to invoke WebContentsDelegate::GetSizeForNewRenderView().
+ gfx::Size GetSizeForNewRenderView() const;
+
// Data for core operation ---------------------------------------------------
// Delegate for notifying our owner about stuff. Not owned by us.
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 70ab5235..05e3ebe 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -10,7 +10,9 @@
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_types.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/test_utils.h"
@@ -21,6 +23,25 @@
namespace content {
+void ResizeWebContentsView(Shell* shell, const gfx::Size& size,
+ bool set_start_page) {
+ // Shell::SizeTo is not implemented on Aura; WebContentsView::SizeContents
+ // 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)
+ shell->SizeTo(size.width(), size.height());
+ // 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)
+}
+
class WebContentsImplBrowserTest : public ContentBrowserTest {
public:
WebContentsImplBrowserTest() {}
@@ -82,6 +103,51 @@
bool done_;
};
+class RenderViewSizeDelegate : public WebContentsDelegate {
+ public:
+ void set_size_insets(const gfx::Size& size_insets) {
+ size_insets_ = size_insets;
+ }
+
+ // WebContentsDelegate:
+ virtual gfx::Size GetSizeForNewRenderView(
+ const WebContents* web_contents) const OVERRIDE {
+ gfx::Size size(web_contents->GetView()->GetContainerSize());
+ size.Enlarge(size_insets_.width(), size_insets_.height());
+ return size;
+ }
+
+ private:
+ gfx::Size size_insets_;
+};
+
+class RenderViewSizeObserver : public WebContentsObserver {
+ public:
+ RenderViewSizeObserver(Shell* shell, const gfx::Size& wcv_new_size)
+ : WebContentsObserver(shell->web_contents()),
+ shell_(shell),
+ wcv_new_size_(wcv_new_size) {
+ }
+
+ // WebContentsObserver:
+ virtual void RenderViewCreated(RenderViewHost* rvh) OVERRIDE {
+ rwhv_create_size_ = rvh->GetView()->GetViewBounds().size();
+ }
+
+ virtual void NavigateToPendingEntry(
+ const GURL& url,
+ NavigationController::ReloadType reload_type) OVERRIDE {
+ ResizeWebContentsView(shell_, wcv_new_size_, false);
+ }
+
+ gfx::Size rwhv_create_size() const { return rwhv_create_size_; }
+
+ private:
+ Shell* shell_; // Weak ptr.
+ gfx::Size wcv_new_size_;
+ gfx::Size rwhv_create_size_;
+};
+
// Test that DidStopLoading includes the correct URL in the details.
IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, DidStopLoadingDetails) {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
@@ -159,4 +225,61 @@
EXPECT_EQ(rvh->main_frame_id(), root->frame_id());
}
+// TODO(sail): enable this for MAC when auto resizing of WebContentsViewCocoa is
+// fixed.
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+#define MAYBE_GetSizeForNewRenderView DISABLED_GetSizeForNewRenderView
+#else
+#define MAYBE_GetSizeForNewRenderView GetSizeForNewRenderView
+#endif
+// Test that RenderViewHost is created and updated at the size specified by
+// WebContentsDelegate::GetSizeForNewRenderView().
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+ MAYBE_GetSizeForNewRenderView) {
+ scoped_ptr<RenderViewSizeDelegate> delegate(new RenderViewSizeDelegate());
+ shell()->web_contents()->SetDelegate(delegate.get());
+ ASSERT_TRUE(shell()->web_contents()->GetDelegate() == delegate.get());
+
+ // When no size is set, RenderWidgetHostView adopts the size of
+ // WebContenntsView.
+ NavigateToURL(shell(), GURL("http://foo0.com"));
+ EXPECT_EQ(shell()->web_contents()->GetView()->GetContainerSize(),
+ 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);
+ ResizeWebContentsView(shell(), size, true);
+ delegate->set_size_insets(size_insets);
+ NavigateToURL(shell(), GURL("http://foo1.com"));
+ size.Enlarge(size_insets.width(), size_insets.height());
+ EXPECT_EQ(size,
+ shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds().
+ size());
+ EXPECT_EQ(size, shell()->web_contents()->GetView()->GetContainerSize());
+
+ // 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);
+ ResizeWebContentsView(shell(), init_size, true);
+ delegate->set_size_insets(size_insets);
+ RenderViewSizeObserver observer(shell(), new_size);
+ NavigateToURL(shell(), GURL("http://foo2.com"));
+ // 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 NavigateToPendingEntry,
+ // so both WebContentsView and RenderWidgetHostView adopt this new size.
+ 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());
+}
+
} // namespace content
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index 47e30b2a..02ca86a4 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -172,4 +172,9 @@
attached_contents_.erase(web_contents);
}
+gfx::Size WebContentsDelegate::GetSizeForNewRenderView(
+ const WebContents* web_contents) const {
+ return gfx::Size();
+}
+
} // namespace content
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index 69ac871..0e019a9 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -94,9 +94,10 @@
// Creates a new tab with the already-created WebContents 'new_contents'.
// The window for the added contents should be reparented correctly when this
- // method returns. If |disposition| is NEW_POPUP, |pos| should hold the
- // initial position. If |was_blocked| is non-NULL, then |*was_blocked| will
- // be set to true if the popup gets blocked, and left unchanged otherwise.
+ // method returns. If |disposition| is NEW_POPUP, |initial_pos| should hold
+ // the initial position. If |was_blocked| is non-NULL, then |*was_blocked|
+ // will be set to true if the popup gets blocked, and left unchanged
+ // otherwise.
virtual void AddNewContents(WebContents* source,
WebContents* new_contents,
WindowOpenDisposition disposition,
@@ -433,6 +434,14 @@
const base::FilePath& plugin_path,
const base::Callback<void(bool)>& callback);
+ // Returns the size for the new render view created for the pending entry in
+ // |web_contents|; if there's no size, returns an empty size.
+ // This is optional for implementations of WebContentsDelegate; if the
+ // delegate doesn't provide a size, the current WebContentsView's size will be
+ // used.
+ virtual gfx::Size GetSizeForNewRenderView(
+ const WebContents* web_contents) const;
+
protected:
virtual ~WebContentsDelegate();