Chromium Code Reviews| Index: chrome/browser/media/native_desktop_media_list.cc |
| diff --git a/chrome/browser/media/native_desktop_media_list.cc b/chrome/browser/media/native_desktop_media_list.cc |
| index 32a8c0d923a27c2763ea907874af45ac7147f445..da7003c7866e0022b5367bc801871ac58f573c88 100644 |
| --- a/chrome/browser/media/native_desktop_media_list.cc |
| +++ b/chrome/browser/media/native_desktop_media_list.cc |
| @@ -12,17 +12,27 @@ |
| #include "base/logging.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/threading/sequenced_worker_pool.h" |
| +#include "chrome/browser/mac/bluetooth_utility.h" |
| #include "chrome/browser/media/desktop_media_list_observer.h" |
| +#include "chrome/browser/profiles/profile_manager.h" |
| +#include "chrome/browser/ui/browser_finder.h" |
| +#include "chrome/browser/ui/host_desktop.h" |
| +#include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/grit/generated_resources.h" |
| +#include "components/favicon/content/content_favicon_driver.h" |
| #include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/render_frame_host.h" |
| +#include "content/public/browser/render_process_host.h" |
| #include "media/base/video_util.h" |
| #include "third_party/libyuv/include/libyuv/scale_argb.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" |
| #include "third_party/webrtc/modules/desktop_capture/window_capturer.h" |
| +#include "ui/aura/window.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/gfx/skia_util.h" |
| +#include "ui/snapshot/snapshot.h" |
| using content::BrowserThread; |
| using content::DesktopMediaID; |
| @@ -78,9 +88,7 @@ gfx::ImageSkia ScaleDesktopFrame(scoped_ptr<webrtc::DesktopFrame> frame, |
| NativeDesktopMediaList::SourceDescription::SourceDescription( |
| DesktopMediaID id, |
| const base::string16& name) |
| - : id(id), |
| - name(name) { |
| -} |
| + : id(id), name(name) {} |
| class NativeDesktopMediaList::Worker |
| : public webrtc::DesktopCapturer::Callback { |
| @@ -91,7 +99,8 @@ class NativeDesktopMediaList::Worker |
| ~Worker() override; |
| void Refresh(const gfx::Size& thumbnail_size, |
| - content::DesktopMediaID::Id view_dialog_id); |
| + content::DesktopMediaID::Id view_dialog_id, |
| + std::vector<SourceDescription> tab_sources); |
| private: |
| typedef std::map<DesktopMediaID, uint32> ImageHashesMap; |
| @@ -129,7 +138,8 @@ NativeDesktopMediaList::Worker::~Worker() {} |
| void NativeDesktopMediaList::Worker::Refresh( |
| const gfx::Size& thumbnail_size, |
| - content::DesktopMediaID::Id view_dialog_id) { |
| + content::DesktopMediaID::Id view_dialog_id, |
| + std::vector<SourceDescription> tab_sources) { |
| std::vector<SourceDescription> sources; |
| if (screen_capturer_) { |
| @@ -166,6 +176,10 @@ void NativeDesktopMediaList::Worker::Refresh( |
| } |
| } |
| } |
| + |
| + // Add tab sources to all media sources |
| + sources.insert(sources.end(), tab_sources.begin(), tab_sources.end()); |
| + |
| // Update list of windows before updating thumbnails. |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| @@ -189,11 +203,23 @@ void NativeDesktopMediaList::Worker::Refresh( |
| continue; |
| window_capturer_->Capture(webrtc::DesktopRegion()); |
| break; |
| + case DesktopMediaID::TYPE_TAB: |
| + // Favicon has already captured for tabs. |
|
qiangchen
2015/12/07 22:45:56
Consider moving the Favicon "capturing" here.
miu
2015/12/08 01:54:38
IIUC, I think that has to be done on the UI thread
GeorgeZ
2015/12/09 19:36:37
This is a no UI thread. Favicon capture has to to
|
| + break; |
| default: |
| NOTREACHED(); |
| } |
| + // Use captured tab favicon as thumbnail. |
| + if (source.id.type == DesktopMediaID::TYPE_TAB) { |
| + BrowserThread::PostTask( |
| + BrowserThread::UI, FROM_HERE, |
| + base::Bind(&NativeDesktopMediaList::OnSourceTabThumbnail, media_list_, |
| + source)); |
| + continue; |
| + } |
| + |
| // Expect that DesktopCapturer to always captures frames synchronously. |
| // |current_frame_| may be NULL if capture failed (e.g. because window has |
| // been closed). |
| @@ -208,8 +234,8 @@ void NativeDesktopMediaList::Worker::Refresh( |
| ScaleDesktopFrame(current_frame_.Pass(), thumbnail_size); |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| - base::Bind(&NativeDesktopMediaList::OnSourceThumbnail, |
| - media_list_, i, thumbnail)); |
| + base::Bind(&NativeDesktopMediaList::OnSourceThumbnail, media_list_, |
| + i, thumbnail)); |
| } |
| } |
| } |
| @@ -233,9 +259,11 @@ void NativeDesktopMediaList::Worker::OnCaptureCompleted( |
| NativeDesktopMediaList::NativeDesktopMediaList( |
| scoped_ptr<webrtc::ScreenCapturer> screen_capturer, |
| - scoped_ptr<webrtc::WindowCapturer> window_capturer) |
| + scoped_ptr<webrtc::WindowCapturer> window_capturer, |
| + bool tab_capture_enabled) |
| : screen_capturer_(screen_capturer.Pass()), |
| window_capturer_(window_capturer.Pass()), |
| + tab_capture_enabled_(tab_capture_enabled), |
| update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)), |
| thumbnail_size_(100, 100), |
| view_dialog_id_(content::DesktopMediaID::TYPE_NONE, -1), |
| @@ -267,7 +295,7 @@ void NativeDesktopMediaList::SetViewDialogWindowId( |
| void NativeDesktopMediaList::StartUpdating(DesktopMediaListObserver* observer) { |
| DCHECK(!observer_); |
| - DCHECK(screen_capturer_ || window_capturer_); |
| + DCHECK(screen_capturer_ || window_capturer_ || tab_capture_enabled_); |
| observer_ = observer; |
| @@ -286,9 +314,78 @@ const DesktopMediaList::Source& NativeDesktopMediaList::GetSource( |
| } |
| void NativeDesktopMediaList::Refresh() { |
| + // Get tab source list |
|
qiangchen
2015/12/07 22:45:56
Consider moving this block to Worker::Refresh.
GeorgeZ
2015/12/09 19:36:37
Many work has to be done in UI thread here. worker
|
| + std::vector<SourceDescription> tab_sources; |
| + if (tab_capture_enabled_) { |
| + if (!GetTabSourceDescription(tab_sources)) { |
| + tab_sources.clear(); |
| + LOG(ERROR) << "Failed to get tab sources description"; |
|
miu
2015/12/08 01:54:38
Please remove this logging statement. This operat
GeorgeZ
2015/12/09 19:36:37
Done.
|
| + } |
| + } |
| + |
| capture_task_runner_->PostTask( |
| FROM_HERE, base::Bind(&Worker::Refresh, base::Unretained(worker_.get()), |
| - thumbnail_size_, view_dialog_id_.id)); |
| + thumbnail_size_, view_dialog_id_.id, tab_sources)); |
| +} |
| + |
| +bool NativeDesktopMediaList::GetTabSourceDescription( |
|
qiangchen
2015/12/07 22:45:56
GetTabSourceDescriptions is better.
miu
2015/12/08 01:54:38
This method should not return anything because it
GeorgeZ
2015/12/09 19:36:37
Done.
GeorgeZ
2015/12/09 19:36:37
Done.
|
| + std::vector<SourceDescription>& tab_sources) { |
| +// Only support mac, linux, windows and chrome OS, the last three use aura. |
| +#if !defined(OS_MACOSX) && !defined(USE_AURA) |
| + return true; |
| +#endif |
| + // Clear old favicon map. |
| + tab_icon_map_.clear(); |
| + |
| + // Use to sort tabs based on their last active time stamps. |
| + std::map<base::TimeTicks, SourceDescription> tab_map; |
| + |
| + Profile* profile = ProfileManager::GetLastUsedProfileAllowedByPolicy(); |
| + std::vector<Browser*> browsers = FindAllTabbedBrowsersWithProfile( |
| + profile, chrome::HOST_DESKTOP_TYPE_NATIVE); |
| + |
| + for (auto browser : browsers) { |
| + TabStripModel* tab_strip_model = browser->tab_strip_model(); |
| + DCHECK(tab_strip_model); |
| + |
| + for (int i = 0; i < tab_strip_model->count(); i++) { |
| + // Get DesktopMediaID. |
| + content::WebContents* contents = tab_strip_model->GetWebContentsAt(i); |
| + DesktopMediaID media_id; |
| + media_id.type = DesktopMediaID::TYPE_TAB; |
| + content::RenderFrameHost* const main_frame = contents->GetMainFrame(); |
| + DCHECK(main_frame); |
| + media_id.render_process_id = main_frame->GetProcess()->GetID(); |
| + media_id.main_render_frame_id = main_frame->GetRoutingID(); |
| + |
| + // Get tab title. |
| + base::string16 title = |
| + base::UTF8ToUTF16("Chrome tab_") + contents->GetTitle(); |
|
miu
2015/12/08 01:54:38
ditto: Make this a string resource.
GeorgeZ
2015/12/09 19:36:37
Done.
|
| + |
| + // Get tab favicon. |
| + favicon::FaviconDriver* favicon_driver = |
| + favicon::ContentFaviconDriver::FromWebContents(contents); |
| + if (favicon_driver) { |
| + gfx::Image tab_icon = favicon_driver->GetFavicon(); |
| + int window_id = |
| + (media_id.main_render_frame_id << 12) + media_id.render_process_id; |
| + tab_icon_map_[window_id] = |
| + CreateImageEncloseFavicon(thumbnail_size_, tab_icon); |
| + } |
| + |
| + // Get tab's last active time stamp. |
| + base::TimeTicks t = contents->GetLastActiveTime(); |
| + tab_map.insert(std::make_pair(t, SourceDescription(media_id, title))); |
| + } |
| + } |
| + |
| + // Add timely sorted tab sources into vector. Most recent one first. |
| + tab_sources.clear(); |
| + for (auto it = tab_map.rbegin(); it != tab_map.rend(); ++it) { |
| + tab_sources.push_back(it->second); |
| + } |
| + |
| + return true; |
| } |
| void NativeDesktopMediaList::OnSourcesList( |
| @@ -361,6 +458,27 @@ void NativeDesktopMediaList::OnSourceThumbnail( |
| observer_->OnSourceThumbnailChanged(index); |
| } |
| +void NativeDesktopMediaList::OnSourceTabThumbnail(SourceDescription source) { |
|
qiangchen
2015/12/07 22:45:56
Is it possible to remove this function, and merge
GeorgeZ
2015/12/09 19:36:37
Favicon is capture and stored in a UI thead. While
|
| + DCHECK(source.id.type == DesktopMediaID::TYPE_TAB); |
| + |
| + for (size_t i = 0; i < sources_.size(); ++i) { |
| + if (sources_[i].id == source.id) { |
| + int window_id = |
| + (source.id.main_render_frame_id << 12) + source.id.render_process_id; |
| + // Use favicon as thumbnail for tab. |
| + if (tab_icon_map_.count(window_id)) { |
| + // Only do update when there is a change to avoid flickering. |
| + if (sources_[i].thumbnail.size() != tab_icon_map_[window_id].size() || |
| + sources_[i].name != source.name) { |
| + sources_[i].thumbnail = tab_icon_map_[window_id]; |
| + observer_->OnSourceThumbnailChanged(i); |
| + } |
| + } |
| + break; |
| + } |
| + } |
| +} |
| + |
| void NativeDesktopMediaList::OnRefreshFinished() { |
| BrowserThread::PostDelayedTask( |
| BrowserThread::UI, FROM_HERE, |