Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(427)

Side by Side Diff: content/browser/frame_host/web_contents_screenshot_manager.cc

Issue 58343006: Rename WebContentsScreenshotManager to NavigationEntryScreenshotManager. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove TODO. Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/frame_host/web_contents_screenshot_manager.h"
6
7 #include "base/command_line.h"
8 #include "base/threading/worker_pool.h"
9 #include "content/browser/frame_host/navigation_controller_impl.h"
10 #include "content/browser/frame_host/navigation_entry_impl.h"
11 #include "content/browser/renderer_host/render_view_host_impl.h"
12 #include "content/public/browser/render_widget_host.h"
13 #include "content/public/browser/render_widget_host_view.h"
14 #include "content/public/common/content_switches.h"
15 #include "ui/gfx/codec/png_codec.h"
16
17 namespace {
18
19 // Minimum delay between taking screenshots.
20 const int kMinScreenshotIntervalMS = 1000;
21
22 }
23
24 namespace content {
25
26 // Encodes an SkBitmap to PNG data in a worker thread.
27 class ScreenshotData : public base::RefCountedThreadSafe<ScreenshotData> {
28 public:
29 ScreenshotData() {
30 }
31
32 void EncodeScreenshot(const SkBitmap& bitmap, base::Closure callback) {
33 if (!base::WorkerPool::PostTaskAndReply(FROM_HERE,
34 base::Bind(&ScreenshotData::EncodeOnWorker,
35 this,
36 bitmap),
37 callback,
38 true)) {
39 callback.Run();
40 }
41 }
42
43 scoped_refptr<base::RefCountedBytes> data() const { return data_; }
44
45 private:
46 friend class base::RefCountedThreadSafe<ScreenshotData>;
47 virtual ~ScreenshotData() {
48 }
49
50 void EncodeOnWorker(const SkBitmap& bitmap) {
51 std::vector<unsigned char> data;
52 if (gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &data))
53 data_ = new base::RefCountedBytes(data);
54 }
55
56 scoped_refptr<base::RefCountedBytes> data_;
57
58 DISALLOW_COPY_AND_ASSIGN(ScreenshotData);
59 };
60
61 WebContentsScreenshotManager::WebContentsScreenshotManager(
62 NavigationControllerImpl* owner)
63 : owner_(owner),
64 screenshot_factory_(this),
65 min_screenshot_interval_ms_(kMinScreenshotIntervalMS) {
66 }
67
68 WebContentsScreenshotManager::~WebContentsScreenshotManager() {
69 }
70
71 void WebContentsScreenshotManager::TakeScreenshot() {
72 static bool overscroll_enabled = CommandLine::ForCurrentProcess()->
73 GetSwitchValueASCII(switches::kOverscrollHistoryNavigation) != "0";
74 if (!overscroll_enabled)
75 return;
76
77 NavigationEntryImpl* entry =
78 NavigationEntryImpl::FromNavigationEntry(owner_->GetLastCommittedEntry());
79 if (!entry)
80 return;
81
82 RenderViewHost* render_view_host =
83 owner_->delegate()->GetRenderViewHost();
84 if (!static_cast<RenderViewHostImpl*>
85 (render_view_host)->overscroll_controller()) {
86 return;
87 }
88 content::RenderWidgetHostView* view = render_view_host->GetView();
89 if (!view)
90 return;
91
92 // Make sure screenshots aren't taken too frequently.
93 base::Time now = base::Time::Now();
94 if (now - last_screenshot_time_ <
95 base::TimeDelta::FromMilliseconds(min_screenshot_interval_ms_)) {
96 return;
97 }
98
99 last_screenshot_time_ = now;
100
101 TakeScreenshotImpl(render_view_host, entry);
102 }
103
104 // Implemented here and not in NavigationEntry because this manager keeps track
105 // of the total number of screen shots across all entries.
106 void WebContentsScreenshotManager::ClearAllScreenshots() {
107 int count = owner_->GetEntryCount();
108 for (int i = 0; i < count; ++i) {
109 ClearScreenshot(NavigationEntryImpl::FromNavigationEntry(
110 owner_->GetEntryAtIndex(i)));
111 }
112 DCHECK_EQ(GetScreenshotCount(), 0);
113 }
114
115 void WebContentsScreenshotManager::TakeScreenshotImpl(
116 RenderViewHost* host,
117 NavigationEntryImpl* entry) {
118 DCHECK(host && host->GetView());
119 DCHECK(entry);
120 host->CopyFromBackingStore(gfx::Rect(),
121 host->GetView()->GetViewBounds().size(),
122 base::Bind(&WebContentsScreenshotManager::OnScreenshotTaken,
123 screenshot_factory_.GetWeakPtr(),
124 entry->GetUniqueID()));
125 }
126
127 void WebContentsScreenshotManager::SetMinScreenshotIntervalMS(int interval_ms) {
128 DCHECK_GE(interval_ms, 0);
129 min_screenshot_interval_ms_ = interval_ms;
130 }
131
132 void WebContentsScreenshotManager::OnScreenshotTaken(int unique_id,
133 bool success,
134 const SkBitmap& bitmap) {
135 NavigationEntryImpl* entry = NULL;
136 int entry_count = owner_->GetEntryCount();
137 for (int i = 0; i < entry_count; ++i) {
138 NavigationEntry* iter = owner_->GetEntryAtIndex(i);
139 if (iter->GetUniqueID() == unique_id) {
140 entry = NavigationEntryImpl::FromNavigationEntry(iter);
141 break;
142 }
143 }
144
145 if (!entry) {
146 LOG(ERROR) << "Invalid entry with unique id: " << unique_id;
147 return;
148 }
149
150 if (!success || bitmap.empty() || bitmap.isNull()) {
151 if (!ClearScreenshot(entry))
152 OnScreenshotSet(entry);
153 return;
154 }
155
156 scoped_refptr<ScreenshotData> screenshot = new ScreenshotData();
157 screenshot->EncodeScreenshot(
158 bitmap,
159 base::Bind(&WebContentsScreenshotManager::OnScreenshotEncodeComplete,
160 screenshot_factory_.GetWeakPtr(),
161 unique_id,
162 screenshot));
163 }
164
165 int WebContentsScreenshotManager::GetScreenshotCount() const {
166 int screenshot_count = 0;
167 int entry_count = owner_->GetEntryCount();
168 for (int i = 0; i < entry_count; ++i) {
169 NavigationEntryImpl* entry =
170 NavigationEntryImpl::FromNavigationEntry(owner_->GetEntryAtIndex(i));
171 if (entry->screenshot().get())
172 screenshot_count++;
173 }
174 return screenshot_count;
175 }
176
177 void WebContentsScreenshotManager::OnScreenshotEncodeComplete(
178 int unique_id,
179 scoped_refptr<ScreenshotData> screenshot) {
180 NavigationEntryImpl* entry = NULL;
181 int entry_count = owner_->GetEntryCount();
182 for (int i = 0; i < entry_count; ++i) {
183 NavigationEntry* iter = owner_->GetEntryAtIndex(i);
184 if (iter->GetUniqueID() == unique_id) {
185 entry = NavigationEntryImpl::FromNavigationEntry(iter);
186 break;
187 }
188 }
189 if (!entry)
190 return;
191 entry->SetScreenshotPNGData(screenshot->data());
192 OnScreenshotSet(entry);
193 }
194
195 void WebContentsScreenshotManager::OnScreenshotSet(NavigationEntryImpl* entry) {
196 if (entry->screenshot().get())
197 PurgeScreenshotsIfNecessary();
198 }
199
200 bool WebContentsScreenshotManager::ClearScreenshot(NavigationEntryImpl* entry) {
201 if (!entry->screenshot().get())
202 return false;
203
204 entry->SetScreenshotPNGData(NULL);
205 return true;
206 }
207
208 void WebContentsScreenshotManager::PurgeScreenshotsIfNecessary() {
209 // Allow only a certain number of entries to keep screenshots.
210 const int kMaxScreenshots = 10;
211 int screenshot_count = GetScreenshotCount();
212 if (screenshot_count < kMaxScreenshots)
213 return;
214
215 const int current = owner_->GetCurrentEntryIndex();
216 const int num_entries = owner_->GetEntryCount();
217 int available_slots = kMaxScreenshots;
218 if (NavigationEntryImpl::FromNavigationEntry(owner_->GetEntryAtIndex(current))
219 ->screenshot().get()) {
220 --available_slots;
221 }
222
223 // Keep screenshots closer to the current navigation entry, and purge the ones
224 // that are farther away from it. So in each step, look at the entries at
225 // each offset on both the back and forward history, and start counting them
226 // to make sure that the correct number of screenshots are kept in memory.
227 // Note that it is possible for some entries to be missing screenshots (e.g.
228 // when taking the screenshot failed for some reason). So there may be a state
229 // where there are a lot of entries in the back history, but none of them has
230 // any screenshot. In such cases, keep the screenshots for |kMaxScreenshots|
231 // entries in the forward history list.
232 int back = current - 1;
233 int forward = current + 1;
234 while (available_slots > 0 && (back >= 0 || forward < num_entries)) {
235 if (back >= 0) {
236 NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
237 owner_->GetEntryAtIndex(back));
238 if (entry->screenshot().get())
239 --available_slots;
240 --back;
241 }
242
243 if (available_slots > 0 && forward < num_entries) {
244 NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
245 owner_->GetEntryAtIndex(forward));
246 if (entry->screenshot().get())
247 --available_slots;
248 ++forward;
249 }
250 }
251
252 // Purge any screenshot at |back| or lower indices, and |forward| or higher
253 // indices.
254 while (screenshot_count > kMaxScreenshots && back >= 0) {
255 NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
256 owner_->GetEntryAtIndex(back));
257 if (ClearScreenshot(entry))
258 --screenshot_count;
259 --back;
260 }
261
262 while (screenshot_count > kMaxScreenshots && forward < num_entries) {
263 NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
264 owner_->GetEntryAtIndex(forward));
265 if (ClearScreenshot(entry))
266 --screenshot_count;
267 ++forward;
268 }
269 CHECK_GE(screenshot_count, 0);
270 CHECK_LE(screenshot_count, kMaxScreenshots);
271 }
272
273 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698