summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorsadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-26 21:00:10 +0000
committersadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-26 21:00:10 +0000
commit1a3f5318d4704a0ee7db240a5191a855e671a339 (patch)
tree25cfa37e1944930ae86305458b895a584300d168 /content
parent72e457db98bc89dcacbf36b856239bb939de9b3d (diff)
downloadchromium_src-1a3f5318d4704a0ee7db240a5191a855e671a339.zip
chromium_src-1a3f5318d4704a0ee7db240a5191a855e671a339.tar.gz
chromium_src-1a3f5318d4704a0ee7db240a5191a855e671a339.tar.bz2
navigation-controller: Move all logic related to taking screenshots to ScreenshotManager.
BUG=224852 Review URL: https://codereview.chromium.org/13266003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@196828 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/browser/web_contents/navigation_controller_impl.cc181
-rw-r--r--content/browser/web_contents/navigation_controller_impl.h47
-rw-r--r--content/browser/web_contents/navigation_controller_impl_unittest.cc54
-rw-r--r--content/browser/web_contents/web_contents_screenshot_manager.cc214
-rw-r--r--content/browser/web_contents/web_contents_screenshot_manager.h79
-rw-r--r--content/browser/web_contents/web_contents_view_aura_browsertest.cc59
-rw-r--r--content/content_browser.gypi2
7 files changed, 392 insertions, 244 deletions
diff --git a/content/browser/web_contents/navigation_controller_impl.cc b/content/browser/web_contents/navigation_controller_impl.cc
index dd1d1f6..6985360 100644
--- a/content/browser/web_contents/navigation_controller_impl.cc
+++ b/content/browser/web_contents/navigation_controller_impl.cc
@@ -5,7 +5,6 @@
#include "content/browser/web_contents/navigation_controller_impl.h"
#include "base/bind.h"
-#include "base/command_line.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/string_number_conversions.h" // Temporary
@@ -22,6 +21,7 @@
#include "content/browser/web_contents/interstitial_page_impl.h"
#include "content/browser/web_contents/navigation_entry_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/browser/web_contents/web_contents_screenshot_manager.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/content_browser_client.h"
@@ -36,13 +36,11 @@
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_constants.h"
-#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "net/base/escape.h"
#include "net/base/mime_util.h"
#include "net/base/net_util.h"
#include "skia/ext/platform_canvas.h"
-#include "ui/gfx/codec/png_codec.h"
#include "webkit/glue/glue_serialize.h"
namespace content {
@@ -50,9 +48,6 @@ namespace {
const int kInvalidateAll = 0xFFFFFFFF;
-// Minimum delay between taking screenshots.
-const int kMinScreenshotIntervalMS = 1000;
-
// Invoked when entries have been pruned, or removed. For example, if the
// current entries are [google, digg, yahoo], with the current entry google,
// and the user types in cnet, then digg and yahoo are pruned.
@@ -223,8 +218,8 @@ NavigationControllerImpl::NavigationControllerImpl(
is_initial_navigation_(true),
pending_reload_(NO_RELOAD),
get_timestamp_callback_(base::Bind(&base::Time::Now)),
- ALLOW_THIS_IN_INITIALIZER_LIST(take_screenshot_factory_(this)),
- min_screenshot_interval_ms_(kMinScreenshotIntervalMS) {
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ screenshot_manager_(new WebContentsScreenshotManager(this))) {
DCHECK(browser_context_);
}
@@ -480,160 +475,13 @@ int NavigationControllerImpl::GetIndexForOffset(int offset) const {
}
void NavigationControllerImpl::TakeScreenshot() {
- static bool overscroll_enabled = CommandLine::ForCurrentProcess()->
- GetSwitchValueASCII(switches::kOverscrollHistoryNavigation) != "0";
- if (!overscroll_enabled)
- return;
-
- NavigationEntryImpl* entry =
- NavigationEntryImpl::FromNavigationEntry(GetLastCommittedEntry());
- if (!entry)
- return;
-
- RenderViewHost* render_view_host = web_contents_->GetRenderViewHost();
- if (!static_cast<RenderViewHostImpl*>
- (render_view_host)->overscroll_controller()) {
- return;
- }
- content::RenderWidgetHostView* view = render_view_host->GetView();
- if (!view)
- return;
-
- // Make sure screenshots aren't taken too frequently.
- base::Time now = base::Time::Now();
- if (now - last_screenshot_time_ <
- base::TimeDelta::FromMilliseconds(min_screenshot_interval_ms_)) {
- return;
- }
-
- last_screenshot_time_ = now;
-
- if (!take_screenshot_callback_.is_null())
- take_screenshot_callback_.Run(render_view_host);
-
- render_view_host->CopyFromBackingStore(gfx::Rect(),
- view->GetViewBounds().size(),
- base::Bind(&NavigationControllerImpl::OnScreenshotTaken,
- take_screenshot_factory_.GetWeakPtr(),
- entry->GetUniqueID()));
-}
-
-void NavigationControllerImpl::OnScreenshotTaken(
- int unique_id,
- bool success,
- const SkBitmap& bitmap) {
- NavigationEntryImpl* entry = NULL;
- for (NavigationEntries::iterator i = entries_.begin();
- i != entries_.end();
- ++i) {
- if ((*i)->GetUniqueID() == unique_id) {
- entry = (*i).get();
- break;
- }
- }
-
- if (!entry) {
- LOG(ERROR) << "Invalid entry with unique id: " << unique_id;
- return;
- }
-
- if (!success || bitmap.empty() || bitmap.isNull()) {
- ClearScreenshot(entry);
- return;
- }
-
- std::vector<unsigned char> data;
- if (gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &data)) {
- entry->SetScreenshotPNGData(data);
- PurgeScreenshotsIfNecessary();
- } else {
- ClearScreenshot(entry);
- }
-}
-
-bool NavigationControllerImpl::ClearScreenshot(NavigationEntryImpl* entry) {
- if (!entry->screenshot())
- return false;
-
- entry->SetScreenshotPNGData(std::vector<unsigned char>());
- return true;
-}
-
-void NavigationControllerImpl::PurgeScreenshotsIfNecessary() {
- // Allow only a certain number of entries to keep screenshots.
- const int kMaxScreenshots = 10;
- int screenshot_count = GetScreenshotCount();
- if (screenshot_count < kMaxScreenshots)
- return;
-
- const int current = GetCurrentEntryIndex();
- const int num_entries = GetEntryCount();
- int available_slots = kMaxScreenshots;
- if (NavigationEntryImpl::FromNavigationEntry(
- GetEntryAtIndex(current))->screenshot())
- --available_slots;
-
- // Keep screenshots closer to the current navigation entry, and purge the ones
- // that are farther away from it. So in each step, look at the entries at
- // each offset on both the back and forward history, and start counting them
- // to make sure that the correct number of screenshots are kept in memory.
- // Note that it is possible for some entries to be missing screenshots (e.g.
- // when taking the screenshot failed for some reason). So there may be a state
- // where there are a lot of entries in the back history, but none of them has
- // any screenshot. In such cases, keep the screenshots for |kMaxScreenshots|
- // entries in the forward history list.
- int back = current - 1;
- int forward = current + 1;
- while (available_slots > 0 && (back >= 0 || forward < num_entries)) {
- if (back >= 0) {
- NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
- GetEntryAtIndex(back));
- if (entry->screenshot())
- --available_slots;
- --back;
- }
-
- if (available_slots > 0 && forward < num_entries) {
- NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
- GetEntryAtIndex(forward));
- if (entry->screenshot())
- --available_slots;
- ++forward;
- }
- }
-
- // Purge any screenshot at |back| or lower indices, and |forward| or higher
- // indices.
-
- while (screenshot_count > kMaxScreenshots && back >= 0) {
- NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
- GetEntryAtIndex(back));
- if (ClearScreenshot(entry))
- --screenshot_count;
- --back;
- }
-
- while (screenshot_count > kMaxScreenshots && forward < num_entries) {
- NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
- GetEntryAtIndex(forward));
- if (ClearScreenshot(entry))
- --screenshot_count;
- ++forward;
- }
- CHECK_GE(screenshot_count, 0);
- CHECK_LE(screenshot_count, kMaxScreenshots);
+ screenshot_manager_->TakeScreenshot();
}
-int NavigationControllerImpl::GetScreenshotCount() const {
- int count = 0;
- for (NavigationEntries::const_iterator it = entries_.begin();
- it != entries_.end(); ++it) {
- NavigationEntryImpl* entry =
- NavigationEntryImpl::FromNavigationEntry(it->get());
- if (entry->screenshot())
- count++;
- }
- return count;
+void NavigationControllerImpl::SetScreenshotManager(
+ WebContentsScreenshotManager* manager) {
+ screenshot_manager_.reset(manager ? manager :
+ new WebContentsScreenshotManager(this));
}
bool NavigationControllerImpl::CanGoBack() const {
@@ -1471,14 +1319,8 @@ void NavigationControllerImpl::PruneAllButActiveInternal() {
}
}
-// Implemented here and not in NavigationEntry because this controller caches
-// the total number of screen shots across all entries.
void NavigationControllerImpl::ClearAllScreenshots() {
- for (NavigationEntries::iterator it = entries_.begin();
- it != entries_.end();
- ++it)
- ClearScreenshot(it->get());
- DCHECK_EQ(GetScreenshotCount(), 0);
+ screenshot_manager_->ClearAllScreenshots();
}
void NavigationControllerImpl::SetSessionStorageNamespace(
@@ -1825,9 +1667,4 @@ void NavigationControllerImpl::SetGetTimestampCallbackForTest(
get_timestamp_callback_ = get_timestamp_callback;
}
-void NavigationControllerImpl::SetTakeScreenshotCallbackForTest(
- const base::Callback<void(RenderViewHost*)>& take_screenshot_callback) {
- take_screenshot_callback_ = take_screenshot_callback;
-}
-
} // namespace content
diff --git a/content/browser/web_contents/navigation_controller_impl.h b/content/browser/web_contents/navigation_controller_impl.h
index 2c21330..5e50d10 100644
--- a/content/browser/web_contents/navigation_controller_impl.h
+++ b/content/browser/web_contents/navigation_controller_impl.h
@@ -15,13 +15,13 @@
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_type.h"
-class SkBitmap;
struct ViewHostMsg_FrameNavigate_Params;
namespace content {
class NavigationEntryImpl;
class RenderViewHost;
class WebContentsImpl;
+class WebContentsScreenshotManager;
class SiteInstance;
struct LoadCommittedDetails;
@@ -188,13 +188,12 @@ class CONTENT_EXPORT NavigationControllerImpl
// Takes a screenshot of the page at the current state.
void TakeScreenshot();
- void SetTakeScreenshotCallbackForTest(
- const base::Callback<void(RenderViewHost*)>& take_screenshot_callback);
-
- void set_min_screenshot_interval(int interval_ms) {
- DCHECK_GE(interval_ms, 0);
- min_screenshot_interval_ms_ = interval_ms;
- }
+ // Sets the screenshot manager for this NavigationControllerImpl. The
+ // controller takes ownership of the screenshot manager and destroys it when
+ // a new screenshot-manager is set, or when the controller is destroyed.
+ // Setting a NULL manager recreates the default screenshot manager and uses
+ // that.
+ void SetScreenshotManager(WebContentsScreenshotManager* manager);
private:
friend class RestoreHelper;
@@ -316,24 +315,6 @@ class CONTENT_EXPORT NavigationControllerImpl
// specified |offset|. The index returned is not guaranteed to be valid.
int GetIndexForOffset(int offset) const;
- // The callback invoked when taking the screenshot of the page is complete.
- // This sets the screenshot on the navigation entry.
- void OnScreenshotTaken(int unique_id,
- bool success,
- const SkBitmap& bitmap);
-
- // Removes the screenshot for the entry, returning true if the entry had a
- // screenshot.
- bool ClearScreenshot(NavigationEntryImpl* entry);
-
- // The screenshots in the NavigationEntryImpls can accumulate and consume a
- // large amount of memory. This function makes sure that the memory
- // consumption is within a certain limit.
- void PurgeScreenshotsIfNecessary();
-
- // Returns the number of entries with screenshots.
- int GetScreenshotCount() const;
-
// ---------------------------------------------------------------------------
// The user browser context associated with this controller.
@@ -404,18 +385,6 @@ class CONTENT_EXPORT NavigationControllerImpl
// Used to get timestamps for newly-created navigation entries.
base::Callback<base::Time()> get_timestamp_callback_;
- // A callback that gets called before taking the screenshot of the page. This
- // is used only for testing.
- base::Callback<void(RenderViewHost*)> take_screenshot_callback_;
-
- // Taking a screenshot can be async. So use a weakptr for the callback to make
- // sure that the screenshot completion callback does not trigger on a
- // destroyed NavigationControllerImpl.
- base::WeakPtrFactory<NavigationControllerImpl> take_screenshot_factory_;
-
- base::Time last_screenshot_time_;
- int min_screenshot_interval_ms_;
-
// Used to smooth out timestamps from |get_timestamp_callback_|.
// Without this, whenever there is a run of redirects or
// code-generated navigations, those navigations may occur within
@@ -423,6 +392,8 @@ class CONTENT_EXPORT NavigationControllerImpl
// the wrong order in the history view.
TimeSmoother time_smoother_;
+ scoped_ptr<WebContentsScreenshotManager> screenshot_manager_;
+
DISALLOW_COPY_AND_ASSIGN(NavigationControllerImpl);
};
diff --git a/content/browser/web_contents/navigation_controller_impl_unittest.cc b/content/browser/web_contents/navigation_controller_impl_unittest.cc
index 0f25e2e..320c8aa 100644
--- a/content/browser/web_contents/navigation_controller_impl_unittest.cc
+++ b/content/browser/web_contents/navigation_controller_impl_unittest.cc
@@ -24,6 +24,7 @@
#include "content/browser/web_contents/navigation_controller_impl.h"
#include "content/browser/web_contents/navigation_entry_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/browser/web_contents/web_contents_screenshot_manager.h"
#include "content/common/view_messages.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/notification_registrar.h"
@@ -69,6 +70,37 @@ bool DoImagesMatch(const gfx::Image& a, const gfx::Image& b) {
a_bitmap.getSize()) == 0;
}
+class MockScreenshotManager : public content::WebContentsScreenshotManager {
+ public:
+ explicit MockScreenshotManager(content::NavigationControllerImpl* owner)
+ : content::WebContentsScreenshotManager(owner) {
+ }
+
+ virtual ~MockScreenshotManager() {
+ }
+
+ void TakeScreenshotFor(content::NavigationEntryImpl* entry) {
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
+ bitmap.allocPixels();
+ bitmap.eraseRGB(0, 0, 0);
+ OnScreenshotTaken(entry->GetUniqueID(), true, bitmap);
+ }
+
+ int GetScreenshotCount() {
+ return content::WebContentsScreenshotManager::GetScreenshotCount();
+ }
+
+ private:
+ // Overridden from content::WebContentsScreenshotManager:
+ virtual void TakeScreenshotImpl(
+ content::RenderViewHost* host,
+ content::NavigationEntryImpl* entry) OVERRIDE {
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(MockScreenshotManager);
+};
+
} // namespace
namespace content {
@@ -3190,11 +3222,6 @@ TEST_F(NavigationControllerTest, BackNavigationDoesNotClearFavicon) {
TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
NavigationControllerImpl& controller = controller_impl();
- // Prepare some data to use as screenshot for each navigation.
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
- ASSERT_TRUE(bitmap.allocPixels());
- bitmap.eraseRGB(0, 0, 0);
NavigationEntryImpl* entry;
// Navigate enough times to make sure that some screenshots are purged.
@@ -3204,10 +3231,13 @@ TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
EXPECT_EQ(i, controller.GetCurrentEntryIndex());
}
+ MockScreenshotManager* screenshot_manager =
+ new MockScreenshotManager(&controller);
+ controller.SetScreenshotManager(screenshot_manager);
for (int i = 0; i < controller.GetEntryCount(); ++i) {
entry = NavigationEntryImpl::FromNavigationEntry(
controller.GetEntryAtIndex(i));
- controller.OnScreenshotTaken(entry->GetUniqueID(), true, bitmap);
+ screenshot_manager->TakeScreenshotFor(entry);
EXPECT_TRUE(entry->screenshot());
}
@@ -3215,7 +3245,7 @@ TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
EXPECT_EQ(13, controller.GetEntryCount());
entry = NavigationEntryImpl::FromNavigationEntry(
controller.GetEntryAtIndex(11));
- controller.OnScreenshotTaken(entry->GetUniqueID(), true, bitmap);
+ screenshot_manager->TakeScreenshotFor(entry);
for (int i = 0; i < 2; ++i) {
entry = NavigationEntryImpl::FromNavigationEntry(
@@ -3236,14 +3266,14 @@ TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
entry = NavigationEntryImpl::FromNavigationEntry(
controller.GetEntryAtIndex(i));
- controller.OnScreenshotTaken(entry->GetUniqueID(), true, bitmap);
+ screenshot_manager->TakeScreenshotFor(entry);
}
for (int i = 10; i <= 12; ++i) {
entry = NavigationEntryImpl::FromNavigationEntry(
controller.GetEntryAtIndex(i));
EXPECT_FALSE(entry->screenshot()) << "Screenshot " << i << " not purged";
- controller.OnScreenshotTaken(entry->GetUniqueID(), true, bitmap);
+ screenshot_manager->TakeScreenshotFor(entry);
}
// Navigate to index 7 and assign screenshot to all entries.
@@ -3253,7 +3283,7 @@ TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
for (int i = 0; i < controller.GetEntryCount() - 1; ++i) {
entry = NavigationEntryImpl::FromNavigationEntry(
controller.GetEntryAtIndex(i));
- controller.OnScreenshotTaken(entry->GetUniqueID(), true, bitmap);
+ screenshot_manager->TakeScreenshotFor(entry);
}
for (int i = 0; i < 2; ++i) {
@@ -3264,9 +3294,9 @@ TEST_F(NavigationControllerTest, MAYBE_PurgeScreenshot) {
// Clear all screenshots.
EXPECT_EQ(13, controller.GetEntryCount());
- EXPECT_EQ(10, controller.GetScreenshotCount());
+ EXPECT_EQ(10, screenshot_manager->GetScreenshotCount());
controller.ClearAllScreenshots();
- EXPECT_EQ(0, controller.GetScreenshotCount());
+ EXPECT_EQ(0, screenshot_manager->GetScreenshotCount());
for (int i = 0; i < controller.GetEntryCount(); ++i) {
entry = NavigationEntryImpl::FromNavigationEntry(
controller.GetEntryAtIndex(i));
diff --git a/content/browser/web_contents/web_contents_screenshot_manager.cc b/content/browser/web_contents/web_contents_screenshot_manager.cc
new file mode 100644
index 0000000..9b8750f
--- /dev/null
+++ b/content/browser/web_contents/web_contents_screenshot_manager.cc
@@ -0,0 +1,214 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/web_contents/web_contents_screenshot_manager.h"
+
+#include "base/command_line.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/web_contents/navigation_controller_impl.h"
+#include "content/browser/web_contents/navigation_entry_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/common/content_switches.h"
+#include "ui/gfx/codec/png_codec.h"
+
+namespace {
+
+// Minimum delay between taking screenshots.
+const int kMinScreenshotIntervalMS = 1000;
+
+}
+
+namespace content {
+
+WebContentsScreenshotManager::WebContentsScreenshotManager(
+ NavigationControllerImpl* owner)
+ : owner_(owner),
+ ALLOW_THIS_IN_INITIALIZER_LIST(take_screenshot_factory_(this)),
+ min_screenshot_interval_ms_(kMinScreenshotIntervalMS) {
+}
+
+WebContentsScreenshotManager::~WebContentsScreenshotManager() {
+}
+
+void WebContentsScreenshotManager::TakeScreenshot() {
+ static bool overscroll_enabled = CommandLine::ForCurrentProcess()->
+ GetSwitchValueASCII(switches::kOverscrollHistoryNavigation) != "0";
+ if (!overscroll_enabled)
+ return;
+
+ NavigationEntryImpl* entry =
+ NavigationEntryImpl::FromNavigationEntry(owner_->GetLastCommittedEntry());
+ if (!entry)
+ return;
+
+ RenderViewHost* render_view_host =
+ owner_->web_contents()->GetRenderViewHost();
+ if (!static_cast<RenderViewHostImpl*>
+ (render_view_host)->overscroll_controller()) {
+ return;
+ }
+ content::RenderWidgetHostView* view = render_view_host->GetView();
+ if (!view)
+ return;
+
+ // Make sure screenshots aren't taken too frequently.
+ base::Time now = base::Time::Now();
+ if (now - last_screenshot_time_ <
+ base::TimeDelta::FromMilliseconds(min_screenshot_interval_ms_)) {
+ return;
+ }
+
+ last_screenshot_time_ = now;
+
+ TakeScreenshotImpl(render_view_host, entry);
+}
+
+// Implemented here and not in NavigationEntry because this manager keeps track
+// of the total number of screen shots across all entries.
+void WebContentsScreenshotManager::ClearAllScreenshots() {
+ int count = owner_->GetEntryCount();
+ for (int i = 0; i < count; ++i) {
+ ClearScreenshot(NavigationEntryImpl::FromNavigationEntry(
+ owner_->GetEntryAtIndex(i)));
+ }
+ DCHECK_EQ(GetScreenshotCount(), 0);
+}
+
+void WebContentsScreenshotManager::TakeScreenshotImpl(
+ RenderViewHost* host,
+ NavigationEntryImpl* entry) {
+ DCHECK(host && host->GetView());
+ DCHECK(entry);
+ host->CopyFromBackingStore(gfx::Rect(),
+ host->GetView()->GetViewBounds().size(),
+ base::Bind(&WebContentsScreenshotManager::OnScreenshotTaken,
+ take_screenshot_factory_.GetWeakPtr(),
+ entry->GetUniqueID()));
+}
+
+void WebContentsScreenshotManager::SetMinScreenshotIntervalMS(int interval_ms) {
+ DCHECK_GE(interval_ms, 0);
+ min_screenshot_interval_ms_ = interval_ms;
+}
+
+void WebContentsScreenshotManager::OnScreenshotTaken(int unique_id,
+ bool success,
+ const SkBitmap& bitmap) {
+ NavigationEntryImpl* entry = NULL;
+ int entry_count = owner_->GetEntryCount();
+ for (int i = 0; i < entry_count; ++i) {
+ NavigationEntry* iter = owner_->GetEntryAtIndex(i);
+ if (iter->GetUniqueID() == unique_id) {
+ entry = NavigationEntryImpl::FromNavigationEntry(iter);
+ break;
+ }
+ }
+
+ if (!entry) {
+ LOG(ERROR) << "Invalid entry with unique id: " << unique_id;
+ return;
+ }
+
+ if (!success || bitmap.empty() || bitmap.isNull()) {
+ ClearScreenshot(entry);
+ return;
+ }
+
+ std::vector<unsigned char> data;
+ if (gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &data)) {
+ entry->SetScreenshotPNGData(data);
+ PurgeScreenshotsIfNecessary();
+ } else {
+ ClearScreenshot(entry);
+ }
+}
+
+int WebContentsScreenshotManager::GetScreenshotCount() const {
+ int screenshot_count = 0;
+ int entry_count = owner_->GetEntryCount();
+ for (int i = 0; i < entry_count; ++i) {
+ NavigationEntryImpl* entry =
+ NavigationEntryImpl::FromNavigationEntry(owner_->GetEntryAtIndex(i));
+ if (entry->screenshot())
+ screenshot_count++;
+ }
+ return screenshot_count;
+}
+
+bool WebContentsScreenshotManager::ClearScreenshot(NavigationEntryImpl* entry) {
+ if (!entry->screenshot())
+ return false;
+
+ entry->SetScreenshotPNGData(std::vector<unsigned char>());
+ return true;
+}
+
+void WebContentsScreenshotManager::PurgeScreenshotsIfNecessary() {
+ // Allow only a certain number of entries to keep screenshots.
+ const int kMaxScreenshots = 10;
+ int screenshot_count = GetScreenshotCount();
+ if (screenshot_count < kMaxScreenshots)
+ return;
+
+ const int current = owner_->GetCurrentEntryIndex();
+ const int num_entries = owner_->GetEntryCount();
+ int available_slots = kMaxScreenshots;
+ if (NavigationEntryImpl::FromNavigationEntry(
+ owner_->GetEntryAtIndex(current))->screenshot()) {
+ --available_slots;
+ }
+
+ // Keep screenshots closer to the current navigation entry, and purge the ones
+ // that are farther away from it. So in each step, look at the entries at
+ // each offset on both the back and forward history, and start counting them
+ // to make sure that the correct number of screenshots are kept in memory.
+ // Note that it is possible for some entries to be missing screenshots (e.g.
+ // when taking the screenshot failed for some reason). So there may be a state
+ // where there are a lot of entries in the back history, but none of them has
+ // any screenshot. In such cases, keep the screenshots for |kMaxScreenshots|
+ // entries in the forward history list.
+ int back = current - 1;
+ int forward = current + 1;
+ while (available_slots > 0 && (back >= 0 || forward < num_entries)) {
+ if (back >= 0) {
+ NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
+ owner_->GetEntryAtIndex(back));
+ if (entry->screenshot())
+ --available_slots;
+ --back;
+ }
+
+ if (available_slots > 0 && forward < num_entries) {
+ NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
+ owner_->GetEntryAtIndex(forward));
+ if (entry->screenshot())
+ --available_slots;
+ ++forward;
+ }
+ }
+
+ // Purge any screenshot at |back| or lower indices, and |forward| or higher
+ // indices.
+ while (screenshot_count > kMaxScreenshots && back >= 0) {
+ NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
+ owner_->GetEntryAtIndex(back));
+ if (ClearScreenshot(entry))
+ --screenshot_count;
+ --back;
+ }
+
+ while (screenshot_count > kMaxScreenshots && forward < num_entries) {
+ NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
+ owner_->GetEntryAtIndex(forward));
+ if (ClearScreenshot(entry))
+ --screenshot_count;
+ ++forward;
+ }
+ CHECK_GE(screenshot_count, 0);
+ CHECK_LE(screenshot_count, kMaxScreenshots);
+}
+
+} // namespace content
diff --git a/content/browser/web_contents/web_contents_screenshot_manager.h b/content/browser/web_contents/web_contents_screenshot_manager.h
new file mode 100644
index 0000000..54e58ed
--- /dev/null
+++ b/content/browser/web_contents/web_contents_screenshot_manager.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_SCREENSHOT_MANAGER_H_
+#define CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_SCREENSHOT_MANAGER_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time.h"
+#include "content/common/content_export.h"
+
+class SkBitmap;
+
+namespace content {
+
+class NavigationControllerImpl;
+class NavigationEntryImpl;
+class RenderViewHost;
+
+// WebContentsScreenshotManager takes care of taking image-captures for the
+// current navigation entry of a NavigationControllerImpl, and managing these
+// captured images. These image-captures are used for history navigation using
+// overscroll gestures.
+class CONTENT_EXPORT WebContentsScreenshotManager {
+ public:
+ explicit WebContentsScreenshotManager(NavigationControllerImpl* controller);
+ virtual ~WebContentsScreenshotManager();
+
+ // Takes a screenshot of the last-committed entry of the controller.
+ void TakeScreenshot();
+
+ // Clears screenshots of all navigation entries.
+ void ClearAllScreenshots();
+
+ protected:
+ virtual void TakeScreenshotImpl(RenderViewHost* host,
+ NavigationEntryImpl* entry);
+
+ NavigationControllerImpl* owner() { return owner_; }
+
+ void SetMinScreenshotIntervalMS(int interval_ms);
+
+ // The callback invoked when taking the screenshot of the page is complete.
+ // This sets the screenshot on the navigation entry.
+ void OnScreenshotTaken(int unique_id,
+ bool success,
+ const SkBitmap& bitmap);
+
+ // Returns the number of entries with screenshots.
+ int GetScreenshotCount() const;
+
+ private:
+ // Removes the screenshot for the entry, returning true if the entry had a
+ // screenshot.
+ bool ClearScreenshot(NavigationEntryImpl* entry);
+
+ // The screenshots in the NavigationEntryImpls can accumulate and consume a
+ // large amount of memory. This function makes sure that the memory
+ // consumption is within a certain limit.
+ void PurgeScreenshotsIfNecessary();
+
+ // The navigation controller that owns this screenshot-manager.
+ NavigationControllerImpl* owner_;
+
+ // Taking a screenshot can be async. So use a weakptr for the callback to make
+ // sure that the screenshot completion callback does not trigger on a
+ // destroyed WebContentsScreenshotManager.
+ base::WeakPtrFactory<WebContentsScreenshotManager> take_screenshot_factory_;
+
+ base::Time last_screenshot_time_;
+ int min_screenshot_interval_ms_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebContentsScreenshotManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_SCREENSHOT_MANAGER_H_
diff --git a/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
index 89cd720..a18b994 100644
--- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -13,6 +13,7 @@
#include "content/browser/web_contents/navigation_controller_impl.h"
#include "content/browser/web_contents/navigation_entry_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/browser/web_contents/web_contents_screenshot_manager.h"
#include "content/public/browser/web_contents_view.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
@@ -27,24 +28,15 @@
namespace content {
-// A dummy callback to reset the screenshot-taker callback.
-void DummyCallback(RenderViewHost* host) {
-}
-
// This class keeps track of the RenderViewHost whose screenshot was captured.
-class ScreenshotTracker {
+class ScreenshotTracker : public WebContentsScreenshotManager {
public:
explicit ScreenshotTracker(NavigationControllerImpl* controller)
- : screenshot_taken_for_(NULL),
- controller_(controller) {
- controller_->SetTakeScreenshotCallbackForTest(
- base::Bind(&ScreenshotTracker::TakeScreenshotCallback,
- base::Unretained(this)));
+ : WebContentsScreenshotManager(controller),
+ screenshot_taken_for_(NULL) {
}
virtual ~ScreenshotTracker() {
- controller_->SetTakeScreenshotCallbackForTest(
- base::Bind(&DummyCallback));
}
RenderViewHost* screenshot_taken_for() { return screenshot_taken_for_; }
@@ -53,20 +45,28 @@ class ScreenshotTracker {
screenshot_taken_for_ = NULL;
}
+ void SetScreenshotInterval(int interval_ms) {
+ SetMinScreenshotIntervalMS(interval_ms);
+ }
+
private:
- void TakeScreenshotCallback(RenderViewHost* host) {
+ // Overridden from WebContentsScreenshotManager:
+ virtual void TakeScreenshotImpl(RenderViewHost* host,
+ NavigationEntryImpl* entry) OVERRIDE {
screenshot_taken_for_ = host;
+ WebContentsScreenshotManager::TakeScreenshotImpl(host, entry);
}
RenderViewHost* screenshot_taken_for_;
- NavigationControllerImpl* controller_;
DISALLOW_COPY_AND_ASSIGN(ScreenshotTracker);
};
class WebContentsViewAuraTest : public ContentBrowserTest {
public:
- WebContentsViewAuraTest() {}
+ WebContentsViewAuraTest()
+ : screenshot_manager_(NULL) {
+ }
// Executes the javascript synchronously and makes sure the returned value is
// freed properly.
@@ -85,6 +85,13 @@ class WebContentsViewAuraTest : public ContentBrowserTest {
aura::Window* content =
shell()->web_contents()->GetView()->GetContentNativeView();
content->GetRootWindow()->SetHostSize(gfx::Size(800, 600));
+
+ WebContentsImpl* web_contents =
+ static_cast<WebContentsImpl*>(shell()->web_contents());
+ NavigationControllerImpl* controller = &web_contents->GetController();
+
+ screenshot_manager_ = new ScreenshotTracker(controller);
+ controller->SetScreenshotManager(screenshot_manager_);
}
void TestOverscrollNavigation(bool touch_handler) {
@@ -190,7 +197,15 @@ class WebContentsViewAuraTest : public ContentBrowserTest {
return index;
}
+ protected:
+ ScreenshotTracker* screenshot_manager() { return screenshot_manager_; }
+ void set_min_screenshot_interval(int interval_ms) {
+ screenshot_manager_->SetScreenshotInterval(interval_ms);
+ }
+
private:
+ ScreenshotTracker* screenshot_manager_;
+
DISALLOW_COPY_AND_ASSIGN(WebContentsViewAuraTest);
};
@@ -299,7 +314,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
RenderViewHostImpl* view_host = static_cast<RenderViewHostImpl*>(
web_contents->GetRenderViewHost());
- web_contents->GetController().set_min_screenshot_interval(0);
+ set_min_screenshot_interval(0);
// Do a few navigations initiated by the page.
ExecuteSyncJSFunction(view_host, "navigate_next()");
@@ -392,7 +407,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
- web_contents->GetController().set_min_screenshot_interval(0);
+ set_min_screenshot_interval(0);
struct {
GURL url;
@@ -407,7 +422,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
{ GURL(), 0 }
};
- ScreenshotTracker tracker(&web_contents->GetController());
+ screenshot_manager()->Reset();
for (int i = 0; !navigations[i].url.is_empty(); ++i) {
// Navigate via the user initiating a navigation from the UI.
NavigationController::LoadURLParams params(navigations[i].url);
@@ -419,8 +434,8 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
EXPECT_NE(old_host, web_contents->GetRenderViewHost())
<< navigations[i].url.spec();
- EXPECT_EQ(old_host, tracker.screenshot_taken_for());
- tracker.Reset();
+ EXPECT_EQ(old_host, screenshot_manager()->screenshot_taken_for());
+ screenshot_manager()->Reset();
NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
web_contents->GetController().GetEntryAtOffset(-1));
@@ -432,7 +447,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
}
// Increase the minimum interval between taking screenshots.
- web_contents->GetController().set_min_screenshot_interval(60000);
+ set_min_screenshot_interval(60000);
// Navigate again. This should not take any screenshot because of the
// increased screenshot interval.
@@ -441,7 +456,7 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
web_contents->GetController().LoadURLWithParams(params);
WaitForLoadStop(web_contents);
- EXPECT_EQ(NULL, tracker.screenshot_taken_for());
+ EXPECT_EQ(NULL, screenshot_manager()->screenshot_taken_for());
}
IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index b7817dd..cdd609e 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -968,6 +968,8 @@
'browser/web_contents/web_contents_drag_win.h',
'browser/web_contents/web_contents_impl.cc',
'browser/web_contents/web_contents_impl.h',
+ 'browser/web_contents/web_contents_screenshot_manager.cc',
+ 'browser/web_contents/web_contents_screenshot_manager.h',
'browser/web_contents/web_contents_view_android.cc',
'browser/web_contents/web_contents_view_android.h',
'browser/web_contents/web_contents_view_aura.cc',