| 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..5bfbb4ded98e6f58bc7594dd85a9cf1fcd248267 100644
|
| --- a/chrome/browser/media/native_desktop_media_list.cc
|
| +++ b/chrome/browser/media/native_desktop_media_list.cc
|
| @@ -10,23 +10,35 @@
|
| #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.h"
|
| +#include "chrome/browser/ui/browser_iterator.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 +94,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 +105,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 +144,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 +182,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,
|
| @@ -193,11 +209,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 +240,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 +265,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 +301,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 +321,71 @@ const DesktopMediaList::Source& NativeDesktopMediaList::GetSource(
|
| }
|
|
|
| void NativeDesktopMediaList::Refresh() {
|
| + // Get tab source list.
|
| + 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;
|
| +
|
| + // Enumerate all tabs with their titles and favicons for a user profile.
|
| + Profile* profile = ProfileManager::GetLastUsedProfileAllowedByPolicy();
|
| + std::vector<Browser*> browsers;
|
| + for (chrome::BrowserIterator it; !it.done(); it.Next()) {
|
| + if (it->profile()->GetOriginalProfile() == profile->GetOriginalProfile())
|
| + browsers.push_back(*it);
|
| + }
|
| +
|
| + 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);
|
| + 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 +458,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,
|
|
|