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 0c4d2108fd03945558049b451f9fa3e8c419f90f..d9781175844a7e96118041ff6715994fb42d7e14 100644 |
--- a/chrome/browser/media/native_desktop_media_list.cc |
+++ b/chrome/browser/media/native_desktop_media_list.cc |
@@ -10,23 +10,34 @@ |
#include <set> |
#include <sstream> |
#include <utility> |
+#include <vector> |
#include "base/hash.h" |
#include "base/logging.h" |
#include "base/macros.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; |
@@ -82,9 +93,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 { |
@@ -95,7 +104,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, |
+ const std::vector<SourceDescription>& tab_sources); |
private: |
typedef std::map<DesktopMediaID, uint32_t> ImageHashesMap; |
@@ -133,7 +143,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, |
+ const std::vector<SourceDescription>& tab_sources) { |
std::vector<SourceDescription> sources; |
if (screen_capturer_) { |
@@ -170,6 +181,10 @@ void NativeDesktopMediaList::Worker::Refresh( |
} |
} |
} |
+ |
+ // Add tab sources to all media sources |
Avi (use Gerrit)
2016/01/08 17:11:38
Full sentences; end with a .
GeorgeZ
2016/01/08 19:39:02
Done.
|
+ sources.insert(sources.end(), tab_sources.begin(), tab_sources.end()); |
+ |
// Update list of windows before updating thumbnails. |
BrowserThread::PostTask( |
BrowserThread::UI, FROM_HERE, |
@@ -193,11 +208,23 @@ void NativeDesktopMediaList::Worker::Refresh( |
continue; |
window_capturer_->Capture(webrtc::DesktopRegion()); |
break; |
+ case DesktopMediaID::TYPE_TAB: |
+ // Favicon has already captured for tabs. |
+ 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). |
@@ -212,8 +239,8 @@ void NativeDesktopMediaList::Worker::Refresh( |
ScaleDesktopFrame(std::move(current_frame_), thumbnail_size); |
BrowserThread::PostTask( |
BrowserThread::UI, FROM_HERE, |
- base::Bind(&NativeDesktopMediaList::OnSourceThumbnail, |
- media_list_, i, thumbnail)); |
+ base::Bind(&NativeDesktopMediaList::OnSourceThumbnail, media_list_, |
+ i, thumbnail)); |
} |
} |
} |
@@ -237,9 +264,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_(std::move(screen_capturer)), |
window_capturer_(std::move(window_capturer)), |
+ tab_capture_enabled_(tab_capture_enabled), |
update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)), |
thumbnail_size_(100, 100), |
view_dialog_id_(content::DesktopMediaID::TYPE_NONE, -1), |
@@ -271,7 +300,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; |
@@ -291,9 +320,81 @@ const DesktopMediaList::Source& NativeDesktopMediaList::GetSource( |
} |
void NativeDesktopMediaList::Refresh() { |
+ // Get tab source list |
Avi (use Gerrit)
2016/01/08 17:11:38
.
GeorgeZ
2016/01/08 19:39:02
Done.
|
+ std::vector<SourceDescription> tab_sources; |
+ if (tab_capture_enabled_) |
+ GetTabSourceDescriptions(&tab_sources); |
+ |
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)); |
+} |
+ |
+void NativeDesktopMediaList::GetTabSourceDescriptions( |
+ std::vector<SourceDescription>* tab_sources) { |
+ // 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; |
+ |
+ // Get all tabs/webcontents' ids for a user profile |
+ Profile* profile = ProfileManager::GetLastUsedProfileAllowedByPolicy(); |
+ std::vector<Browser*> browsers = FindAllTabbedBrowsersWithProfile( |
+ profile, chrome::HOST_DESKTOP_TYPE_NATIVE); |
+ |
+ std::vector<scoped_ptr<MediaListWebContentsObserver>> observers; |
+ 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++) { |
+ content::WebContents* contents = tab_strip_model->GetWebContentsAt(i); |
+ // Use observer to keep track the state of WebContents. |
+ scoped_ptr<MediaListWebContentsObserver> observer( |
+ new MediaListWebContentsObserver(contents)); |
+ observers.push_back(std::move(observer)); |
+ } |
+ } |
+ |
+ // For each tab, get its title and favicon. |
+ for (size_t i = 0; i < observers.size(); i++) { |
+ // If the WebContent has been destroyed, a nullptr will return; |
+ content::WebContents* contents = observers[i]->web_contents(); |
Avi (use Gerrit)
2016/01/08 17:11:38
Same objection here. This code is useless for the
GeorgeZ
2016/01/08 19:39:02
Done.
|
+ if (contents == nullptr) |
+ continue; |
+ |
+ content::RenderFrameHost* const main_frame = contents->GetMainFrame(); |
+ DCHECK(main_frame); |
+ DesktopMediaID media_id( |
+ DesktopMediaID::TYPE_TAB, DesktopMediaID::kNullId, |
+ content::WebContentsMediaCaptureId(main_frame->GetProcess()->GetID(), |
+ main_frame->GetRoutingID())); |
+ |
+ // Create display tab title. |
+ base::string16 title = l10n_util::GetStringFUTF16( |
+ IDS_DESKTOP_MEDIA_PICKER_CHROME_TAB_TITLE, contents->GetTitle()); |
+ |
+ // Create thumbnail based on favicon for tab. |
+ favicon::FaviconDriver* favicon_driver = |
+ favicon::ContentFaviconDriver::FromWebContents(contents); |
+ if (favicon_driver) { |
+ gfx::Image tab_icon = favicon_driver->GetFavicon(); |
+ tab_icon_map_[std::pair<int, int>(media_id.tab_id.render_process_id, |
+ media_id.tab_id.main_render_frame_id)] = |
+ CreateEnlargedFaviconImage(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); |
+ } |
} |
void NativeDesktopMediaList::OnSourcesList( |
@@ -366,6 +467,27 @@ void NativeDesktopMediaList::OnSourceThumbnail( |
observer_->OnSourceThumbnailChanged(index); |
} |
+void NativeDesktopMediaList::OnSourceTabThumbnail(SourceDescription source) { |
+ DCHECK(source.id.type == DesktopMediaID::TYPE_TAB); |
+ |
+ for (size_t i = 0; i < sources_.size(); ++i) { |
+ if (sources_[i].id == source.id) { |
+ // Use favicon as thumbnail for tab. |
+ std::pair<int, int> window_id(source.id.tab_id.render_process_id, |
+ source.id.tab_id.main_render_frame_id); |
+ 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, |