OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/frame_host/navigation_entry_screenshot_manager.h" | 5 #include "content/browser/frame_host/navigation_entry_screenshot_manager.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/threading/worker_pool.h" | 8 #include "base/threading/worker_pool.h" |
9 #include "content/browser/frame_host/navigation_controller_impl.h" | 9 #include "content/browser/frame_host/navigation_controller_impl.h" |
10 #include "content/browser/frame_host/navigation_entry_impl.h" | 10 #include "content/browser/frame_host/navigation_entry_impl.h" |
| 11 #include "content/browser/frame_host/render_frame_host_manager.h" |
11 #include "content/browser/renderer_host/render_view_host_impl.h" | 12 #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.h" |
13 #include "content/public/browser/render_widget_host_view.h" | 14 #include "content/public/browser/render_widget_host_view.h" |
| 15 #include "content/public/browser/site_instance.h" |
14 #include "content/public/common/content_switches.h" | 16 #include "content/public/common/content_switches.h" |
15 #include "third_party/skia/include/core/SkCanvas.h" | 17 #include "third_party/skia/include/core/SkCanvas.h" |
16 #include "third_party/skia/include/core/SkPaint.h" | 18 #include "third_party/skia/include/core/SkPaint.h" |
17 #include "third_party/skia/include/effects/SkLumaColorFilter.h" | 19 #include "third_party/skia/include/effects/SkLumaColorFilter.h" |
18 #include "ui/gfx/codec/png_codec.h" | 20 #include "ui/gfx/codec/png_codec.h" |
19 | 21 |
20 namespace { | 22 namespace { |
21 | 23 |
22 // Minimum delay between taking screenshots. | 24 // Minimum delay between taking screenshots. |
23 const int kMinScreenshotIntervalMS = 1000; | 25 const int kMinScreenshotIntervalMS = 1000; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
68 // Encode the a8Bitmap to grayscale PNG treating alpha as color intensity | 70 // Encode the a8Bitmap to grayscale PNG treating alpha as color intensity |
69 if (gfx::PNGCodec::EncodeA8SkBitmap(a8Bitmap, &data)) | 71 if (gfx::PNGCodec::EncodeA8SkBitmap(a8Bitmap, &data)) |
70 data_ = new base::RefCountedBytes(data); | 72 data_ = new base::RefCountedBytes(data); |
71 } | 73 } |
72 | 74 |
73 scoped_refptr<base::RefCountedBytes> data_; | 75 scoped_refptr<base::RefCountedBytes> data_; |
74 | 76 |
75 DISALLOW_COPY_AND_ASSIGN(ScreenshotData); | 77 DISALLOW_COPY_AND_ASSIGN(ScreenshotData); |
76 }; | 78 }; |
77 | 79 |
| 80 // A temporary solution to keep a RenderViewHost and SiteInstanceImpl live |
| 81 // (after cross-process/cross-site navigation) for long enough to get the |
| 82 // screenshot. |
| 83 // TODO(sad): This can be removed when RenderFrameProxy replaces swappedout:// |
| 84 class SiteInstanceKeepAlive { |
| 85 public: |
| 86 explicit SiteInstanceKeepAlive(scoped_refptr<SiteInstanceImpl> site_instance) |
| 87 : site_instance_(site_instance) { |
| 88 site_instance_->increment_active_view_count(); |
| 89 site_instance_->GetProcess()->AddPendingView(); |
| 90 } |
| 91 |
| 92 ~SiteInstanceKeepAlive() { |
| 93 site_instance_->GetProcess()->RemovePendingView(); |
| 94 site_instance_->decrement_active_view_count(); |
| 95 if (!site_instance_->active_view_count()) { |
| 96 RenderFrameHostManager::ShutdownRenderFrameHostsInSiteInstance( |
| 97 site_instance_->GetId()); |
| 98 } |
| 99 } |
| 100 |
| 101 private: |
| 102 scoped_refptr<SiteInstanceImpl> site_instance_; |
| 103 |
| 104 DISALLOW_COPY_AND_ASSIGN(SiteInstanceKeepAlive); |
| 105 }; |
| 106 |
78 NavigationEntryScreenshotManager::NavigationEntryScreenshotManager( | 107 NavigationEntryScreenshotManager::NavigationEntryScreenshotManager( |
79 NavigationControllerImpl* owner) | 108 NavigationControllerImpl* owner) |
80 : owner_(owner), | 109 : owner_(owner), |
81 screenshot_factory_(this), | 110 screenshot_factory_(this), |
82 min_screenshot_interval_ms_(kMinScreenshotIntervalMS) { | 111 min_screenshot_interval_ms_(kMinScreenshotIntervalMS) { |
83 } | 112 } |
84 | 113 |
85 NavigationEntryScreenshotManager::~NavigationEntryScreenshotManager() { | 114 NavigationEntryScreenshotManager::~NavigationEntryScreenshotManager() { |
86 } | 115 } |
87 | 116 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 owner_->GetEntryAtIndex(i))); | 156 owner_->GetEntryAtIndex(i))); |
128 } | 157 } |
129 DCHECK_EQ(GetScreenshotCount(), 0); | 158 DCHECK_EQ(GetScreenshotCount(), 0); |
130 } | 159 } |
131 | 160 |
132 void NavigationEntryScreenshotManager::TakeScreenshotImpl( | 161 void NavigationEntryScreenshotManager::TakeScreenshotImpl( |
133 RenderViewHost* host, | 162 RenderViewHost* host, |
134 NavigationEntryImpl* entry) { | 163 NavigationEntryImpl* entry) { |
135 DCHECK(host && host->GetView()); | 164 DCHECK(host && host->GetView()); |
136 DCHECK(entry); | 165 DCHECK(entry); |
| 166 scoped_refptr<SiteInstanceImpl> site_instance( |
| 167 static_cast<SiteInstanceImpl*>(host->GetSiteInstance())); |
| 168 SiteInstanceKeepAlive* keep_alive = new SiteInstanceKeepAlive(site_instance); |
| 169 keep_alives_.push_back(keep_alive); |
| 170 if (!web_contents()) |
| 171 Observe(owner_->GetWebContents()); |
137 host->CopyFromBackingStore(gfx::Rect(), | 172 host->CopyFromBackingStore(gfx::Rect(), |
138 host->GetView()->GetViewBounds().size(), | 173 host->GetView()->GetViewBounds().size(), |
139 base::Bind(&NavigationEntryScreenshotManager::OnScreenshotTaken, | 174 base::Bind(&NavigationEntryScreenshotManager::OnScreenshotTaken, |
140 screenshot_factory_.GetWeakPtr(), | 175 screenshot_factory_.GetWeakPtr(), |
141 entry->GetUniqueID())); | 176 entry->GetUniqueID(), |
| 177 keep_alive)); |
142 } | 178 } |
143 | 179 |
144 void NavigationEntryScreenshotManager::SetMinScreenshotIntervalMS( | 180 void NavigationEntryScreenshotManager::SetMinScreenshotIntervalMS( |
145 int interval_ms) { | 181 int interval_ms) { |
146 DCHECK_GE(interval_ms, 0); | 182 DCHECK_GE(interval_ms, 0); |
147 min_screenshot_interval_ms_ = interval_ms; | 183 min_screenshot_interval_ms_ = interval_ms; |
148 } | 184 } |
149 | 185 |
150 void NavigationEntryScreenshotManager::OnScreenshotTaken(int unique_id, | 186 void NavigationEntryScreenshotManager::OnScreenshotTaken( |
151 bool success, | 187 int unique_id, |
152 const SkBitmap& bitmap) { | 188 SiteInstanceKeepAlive* keep_alive, |
| 189 bool success, |
| 190 const SkBitmap& bitmap) { |
| 191 if (keep_alive) { |
| 192 // |keep_alive| can be NULL in tests. |
| 193 keep_alives_.erase(std::find(keep_alives_.begin(), keep_alives_.end(), |
| 194 keep_alive)); |
| 195 keep_alive = NULL; |
| 196 if (keep_alives_.empty()) |
| 197 Observe(NULL); |
| 198 } |
| 199 |
153 NavigationEntryImpl* entry = NULL; | 200 NavigationEntryImpl* entry = NULL; |
154 int entry_count = owner_->GetEntryCount(); | 201 int entry_count = owner_->GetEntryCount(); |
155 for (int i = 0; i < entry_count; ++i) { | 202 for (int i = 0; i < entry_count; ++i) { |
156 NavigationEntry* iter = owner_->GetEntryAtIndex(i); | 203 NavigationEntry* iter = owner_->GetEntryAtIndex(i); |
157 if (iter->GetUniqueID() == unique_id) { | 204 if (iter->GetUniqueID() == unique_id) { |
158 entry = NavigationEntryImpl::FromNavigationEntry(iter); | 205 entry = NavigationEntryImpl::FromNavigationEntry(iter); |
159 break; | 206 break; |
160 } | 207 } |
161 } | 208 } |
162 | 209 |
163 if (!entry) { | 210 if (!entry) { |
164 LOG(ERROR) << "Invalid entry with unique id: " << unique_id; | 211 LOG(ERROR) << "Invalid entry with unique id: " << unique_id; |
165 return; | 212 return; |
166 } | 213 } |
167 | 214 |
168 if (!success || bitmap.empty() || bitmap.isNull()) { | 215 if (!success || bitmap.empty() || bitmap.isNull()) { |
169 if (!ClearScreenshot(entry)) | 216 ClearScreenshot(entry); |
170 OnScreenshotSet(entry); | |
171 return; | 217 return; |
172 } | 218 } |
173 | 219 |
174 scoped_refptr<ScreenshotData> screenshot = new ScreenshotData(); | 220 scoped_refptr<ScreenshotData> screenshot = new ScreenshotData(); |
175 screenshot->EncodeScreenshot( | 221 screenshot->EncodeScreenshot( |
176 bitmap, | 222 bitmap, |
177 base::Bind(&NavigationEntryScreenshotManager::OnScreenshotEncodeComplete, | 223 base::Bind(&NavigationEntryScreenshotManager::OnScreenshotEncodeComplete, |
178 screenshot_factory_.GetWeakPtr(), | 224 screenshot_factory_.GetWeakPtr(), |
179 unique_id, | 225 unique_id, |
180 screenshot)); | 226 screenshot)); |
(...skipping 24 matching lines...) Expand all Loading... |
205 } | 251 } |
206 } | 252 } |
207 if (!entry) | 253 if (!entry) |
208 return; | 254 return; |
209 entry->SetScreenshotPNGData(screenshot->data()); | 255 entry->SetScreenshotPNGData(screenshot->data()); |
210 OnScreenshotSet(entry); | 256 OnScreenshotSet(entry); |
211 } | 257 } |
212 | 258 |
213 void NavigationEntryScreenshotManager::OnScreenshotSet( | 259 void NavigationEntryScreenshotManager::OnScreenshotSet( |
214 NavigationEntryImpl* entry) { | 260 NavigationEntryImpl* entry) { |
215 if (entry->screenshot().get()) | 261 CHECK(entry->screenshot().get()); |
216 PurgeScreenshotsIfNecessary(); | 262 PurgeScreenshotsIfNecessary(); |
217 } | 263 } |
218 | 264 |
219 bool NavigationEntryScreenshotManager::ClearScreenshot( | 265 bool NavigationEntryScreenshotManager::ClearScreenshot( |
220 NavigationEntryImpl* entry) { | 266 NavigationEntryImpl* entry) { |
221 if (!entry->screenshot().get()) | 267 if (!entry->screenshot().get()) |
222 return false; | 268 return false; |
223 | 269 |
224 entry->SetScreenshotPNGData(NULL); | 270 entry->SetScreenshotPNGData(NULL); |
225 return true; | 271 return true; |
226 } | 272 } |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry( | 329 NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry( |
284 owner_->GetEntryAtIndex(forward)); | 330 owner_->GetEntryAtIndex(forward)); |
285 if (ClearScreenshot(entry)) | 331 if (ClearScreenshot(entry)) |
286 --screenshot_count; | 332 --screenshot_count; |
287 ++forward; | 333 ++forward; |
288 } | 334 } |
289 CHECK_GE(screenshot_count, 0); | 335 CHECK_GE(screenshot_count, 0); |
290 CHECK_LE(screenshot_count, kMaxScreenshots); | 336 CHECK_LE(screenshot_count, kMaxScreenshots); |
291 } | 337 } |
292 | 338 |
| 339 void NavigationEntryScreenshotManager::WebContentsDestroyed( |
| 340 WebContents* contents) { |
| 341 // The WebContents is going to be destroyed. So discard all pending screenshot |
| 342 // requests and destroy all the SiteInstanceKeepAlives. |
| 343 screenshot_factory_.InvalidateWeakPtrs(); |
| 344 keep_alives_.clear(); |
| 345 } |
| 346 |
293 } // namespace content | 347 } // namespace content |
OLD | NEW |