Commit 4a8125c3 authored by Yuheng Huang's avatar Yuheng Huang Committed by Commit Bot

Tab Search: Implement TabSearchUI and TabSearchPageHandler

TabSearchUI is used for serving webui resources for tab search feature,
which will be checked in later. TabSearchPageHandler implements the
tab_search.mojom interface. The logic of this CL is mostly mimicking
TabStripUIHandler. Some code is moved from TabStripUIHandler to
chrome/browser/ui/webui/util/image_util.h to be able to used in
TabSearchPageHandler as well.

Bug: 1096120
Change-Id: I4668ad18ebb84282dc44d2dfb78916f54cd55abc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2242215
Commit-Queue: Yuheng Huang <yuhengh@chromium.org>
Reviewed-by: default avatardpapad <dpapad@chromium.org>
Reviewed-by: default avatarRobert Liao <robliao@chromium.org>
Reviewed-by: default avatarMatthew Denton <mpdenton@chromium.org>
Reviewed-by: default avatarJohn Lee <johntlee@chromium.org>
Reviewed-by: default avatarThomas Lukaszewicz <tluk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#781521}
parent 09a0b9ec
......@@ -110,6 +110,8 @@
#include "chrome/browser/ui/webui/media/media_feeds_ui.h"
#include "chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom.h"
#include "chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.h"
#include "chrome/browser/ui/webui/tab_search/tab_search.mojom.h"
#include "chrome/browser/ui/webui/tab_search/tab_search_ui.h"
#include "chrome/common/caption.mojom.h"
#include "media/mojo/mojom/speech_recognition_service.mojom.h"
#endif
......@@ -497,6 +499,9 @@ void PopulateChromeWebUIFrameBinders(
RegisterWebUIControllerInterfaceBinder<media_feeds::mojom::MediaFeedsStore,
MediaFeedsUI>(map);
RegisterWebUIControllerInterfaceBinder<tab_search::mojom::PageHandlerFactory,
TabSearchUI>(map);
#endif
#if defined(OS_CHROMEOS)
......
......@@ -387,6 +387,7 @@ static_library("ui") {
"//chrome/browser/ui/webui/interventions_internals:mojo_bindings",
"//chrome/browser/ui/webui/new_tab_page:mojo_bindings",
"//chrome/browser/ui/webui/omnibox:mojo_bindings",
"//chrome/browser/ui/webui/tab_search:mojo_bindings",
"//chrome/browser/ui/webui/usb_internals:mojo_bindings",
"//chrome/common",
"//chrome/common/net",
......@@ -1428,10 +1429,16 @@ static_library("ui") {
"webui/sync_file_system_internals/sync_file_system_internals_ui.h",
"webui/system_info_ui.cc",
"webui/system_info_ui.h",
"webui/tab_search/tab_search_page_handler.cc",
"webui/tab_search/tab_search_page_handler.h",
"webui/tab_search/tab_search_ui.cc",
"webui/tab_search/tab_search_ui.h",
"webui/theme_handler.cc",
"webui/theme_handler.h",
"webui/theme_source.cc",
"webui/theme_source.h",
"webui/util/image_util.cc",
"webui/util/image_util.h",
"webui/web_footer_experiment_ui.cc",
"webui/web_footer_experiment_ui.h",
"window_sizer/window_sizer.cc",
......
......@@ -87,6 +87,9 @@ const base::Feature kTabHoverCardImages{"TabHoverCardImages",
const base::Feature kTabOutlinesInLowContrastThemes{
"TabOutlinesInLowContrastThemes", base::FEATURE_DISABLED_BY_DEFAULT};
// Enables searching tabs across multiple windows.
const base::Feature kTabSearch{"TabSearch", base::FEATURE_DISABLED_BY_DEFAULT};
// Enables showing text next to the 3-dot menu when an update is available.
// See https://crbug.com/1001731
const base::Feature kUseTextForUpdateButton{"UseTextForUpdateButton",
......
......@@ -51,6 +51,8 @@ extern const base::Feature kTabHoverCardImages;
extern const base::Feature kTabOutlinesInLowContrastThemes;
extern const base::Feature kTabSearch;
extern const base::Feature kUseTextForUpdateButton;
extern const base::Feature kWebFooterExperiment;
......
......@@ -5,6 +5,10 @@
#include "chrome/browser/ui/views/tab_search/tab_search_bubble_view.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
#include "chrome/browser/ui/webui/tab_search/tab_search_ui.h"
#include "chrome/common/webui_url_constants.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/layout/fill_layout.h"
......@@ -37,10 +41,11 @@ class TabSearchWebView : public views::WebView {
} // namespace
void TabSearchBubbleView::CreateTabSearchBubble(Profile* profile,
views::View* anchor_view) {
auto delegate =
base::WrapUnique(new TabSearchBubbleView(profile, anchor_view));
void TabSearchBubbleView::CreateTabSearchBubble(Browser* browser) {
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
DCHECK(browser_view);
auto delegate = base::WrapUnique(
new TabSearchBubbleView(browser, browser_view->toolbar()));
BubbleDialogDelegateView::CreateBubble(delegate.release())->Show();
}
......@@ -56,17 +61,17 @@ void TabSearchBubbleView::OnWebViewSizeChanged() {
SizeToContents();
}
TabSearchBubbleView::TabSearchBubbleView(Profile* profile,
TabSearchBubbleView::TabSearchBubbleView(Browser* browser,
views::View* anchor_view)
: BubbleDialogDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),
web_view_(
AddChildView(std::make_unique<TabSearchWebView>(profile, this))) {
web_view_(AddChildView(
std::make_unique<TabSearchWebView>(browser->profile(), this))) {
SetButtons(ui::DIALOG_BUTTON_NONE);
set_margins(gfx::Insets());
SetLayoutManager(std::make_unique<views::FillLayout>());
web_view_->EnableSizingFromWebContents(kMinSize, kMaxSize);
web_view_->LoadInitialURL(GURL("chrome://about"));
web_view_->LoadInitialURL(GURL(chrome::kChromeUITabSearchURL));
// TODO(crbug.com/1010589) WebContents are initially assumed to be visible by
// default unless explicitly hidden. The WebContents need to be set to hidden
......
......@@ -9,13 +9,13 @@
#include "ui/views/controls/webview/webview.h"
#include "ui/web_dialogs/web_dialog_delegate.h"
class Profile;
class Browser;
// TODO(tluk): Only show the bubble once web contents are available to prevent
// akward resizing when web content finally loads in.
class TabSearchBubbleView : public views::BubbleDialogDelegateView {
public:
static void CreateTabSearchBubble(Profile* profile, views::View* anchor_view);
static void CreateTabSearchBubble(Browser* browser);
~TabSearchBubbleView() override = default;
......@@ -25,7 +25,7 @@ class TabSearchBubbleView : public views::BubbleDialogDelegateView {
void OnWebViewSizeChanged();
private:
TabSearchBubbleView(Profile* profile, views::View* anchor_view);
TabSearchBubbleView(Browser* browser, views::View* anchor_view);
views::WebView* web_view_;
......
......@@ -6,24 +6,34 @@
#include <string>
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/test/test_browser_dialog.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/common/webui_url_constants.h"
#include "content/public/test/browser_test.h"
class TabSearchBubbleBrowserTest : public DialogBrowserTest {
public:
TabSearchBubbleBrowserTest() = default;
TabSearchBubbleBrowserTest() {
feature_list_.InitAndEnableFeature(features::kTabSearch);
}
// DialogBrowserTest:
void ShowUi(const std::string& name) override {
BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
TabSearchBubbleView::CreateTabSearchBubble(browser()->profile(),
browser_view->toolbar());
AppendTab(chrome::kChromeUISettingsURL);
AppendTab(chrome::kChromeUIHistoryURL);
AppendTab(chrome::kChromeUIBookmarksURL);
TabSearchBubbleView::CreateTabSearchBubble(browser());
}
void AppendTab(std::string url) {
chrome::AddTabAt(browser(), GURL(url), -1, true);
}
private:
base::test::ScopedFeatureList feature_list_;
DISALLOW_COPY_AND_ASSIGN(TabSearchBubbleBrowserTest);
};
......
......@@ -134,6 +134,7 @@
#else // defined(OS_ANDROID)
#include "chrome/browser/media/feeds/media_feeds_service.h"
#include "chrome/browser/media/router/media_router_feature.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/webui/bookmarks/bookmarks_ui.h"
#include "chrome/browser/ui/webui/devtools_ui.h"
#include "chrome/browser/ui/webui/downloads/downloads_ui.h"
......@@ -148,6 +149,7 @@
#include "chrome/browser/ui/webui/signin/sync_confirmation_ui.h"
#include "chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_ui.h"
#include "chrome/browser/ui/webui/system_info_ui.h"
#include "chrome/browser/ui/webui/tab_search/tab_search_ui.h"
#include "chrome/browser/ui/webui/web_footer_experiment_ui.h"
#endif // defined(OS_ANDROID)
......@@ -218,7 +220,6 @@
#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
#include "chrome/browser/ui/sync/sync_promo_ui.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/webui/browser_switch/browser_switch_ui.h"
#include "chrome/browser/ui/webui/signin/profile_picker_ui.h"
#include "chrome/browser/ui/webui/signin/signin_email_confirmation_ui.h"
......@@ -527,6 +528,10 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
// Settings are implemented with native UI elements on Android.
if (url.host_piece() == chrome::kChromeUISettingsHost)
return &NewWebUI<settings::SettingsUI>;
if (url.host_piece() == chrome::kChromeUITabSearchHost &&
base::FeatureList::IsEnabled(features::kTabSearch)) {
return &NewWebUI<TabSearchUI>;
}
if (url.host_piece() == chrome::kChromeUIExtensionsHost)
return &NewWebUI<extensions::ExtensionsUI>;
if (url.host_piece() == chrome::kChromeUIHistoryHost)
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/tab_search/tab_search_page_handler.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/base64.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/favicon/favicon_utils.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_renderer_data.h"
#include "chrome/browser/ui/webui/util/image_util.h"
TabSearchPageHandler::TabSearchPageHandler(
mojo::PendingReceiver<tab_search::mojom::PageHandler> receiver,
mojo::PendingRemote<tab_search::mojom::Page> page,
content::WebUI* web_ui)
: receiver_(this, std::move(receiver)),
page_(std::move(page)),
browser_(chrome::FindLastActive()),
web_ui_(web_ui) {
DCHECK(browser_);
}
TabSearchPageHandler::~TabSearchPageHandler() = default;
void TabSearchPageHandler::GetProfileTabs(GetProfileTabsCallback callback) {
auto profile_tabs = tab_search::mojom::ProfileTabs::New();
Profile* profile = browser_->profile();
for (auto* browser : *BrowserList::GetInstance()) {
if (browser->profile() != profile) {
continue;
}
TabStripModel* tab_strip_model = browser->tab_strip_model();
auto window_tabs = tab_search::mojom::WindowTabs::New();
window_tabs->active = (browser == browser_);
for (int i = 0; i < tab_strip_model->count(); ++i) {
window_tabs->tabs.push_back(
GetTabData(browser, tab_strip_model->GetWebContentsAt(i), i));
}
profile_tabs->windows.push_back(std::move(window_tabs));
}
std::move(callback).Run(std::move(profile_tabs));
}
void TabSearchPageHandler::GetTabGroups(GetTabGroupsCallback callback) {
// TODO(crbug.com/1096120): Implement this when we can get theme color from
// browser
NOTIMPLEMENTED();
}
void TabSearchPageHandler::SwitchToTab(
tab_search::mojom::SwitchToTabInfoPtr switch_to_tab_info) {
Profile* profile = browser_->profile();
for (auto* browser : *BrowserList::GetInstance()) {
if (browser->profile() != profile) {
continue;
}
TabStripModel* tab_strip_model = browser->tab_strip_model();
for (int index = 0; index < tab_strip_model->count(); ++index) {
content::WebContents* contents = tab_strip_model->GetWebContentsAt(index);
if (extensions::ExtensionTabUtil::GetTabId(contents) ==
switch_to_tab_info->tab_id) {
tab_strip_model->ActivateTabAt(index);
browser->window()->Activate();
return;
}
}
}
}
tab_search::mojom::TabPtr TabSearchPageHandler::GetTabData(
Browser* browser,
content::WebContents* contents,
int index) {
auto tab_data = tab_search::mojom::Tab::New();
tab_data->active = browser->tab_strip_model()->active_index() == index;
tab_data->tab_id = extensions::ExtensionTabUtil::GetTabId(contents);
tab_data->index = index;
const base::Optional<tab_groups::TabGroupId> group_id =
browser->tab_strip_model()->GetTabGroupForTab(index);
if (group_id.has_value()) {
tab_data->group_id = group_id.value().ToString();
}
TabRendererData tab_renderer_data =
TabRendererData::FromTabInModel(browser->tab_strip_model(), index);
tab_data->pinned = tab_renderer_data.pinned;
tab_data->title = base::UTF16ToUTF8(tab_renderer_data.title);
tab_data->url = tab_renderer_data.visible_url.GetContent();
if (tab_renderer_data.favicon.isNull()) {
tab_data->is_default_favicon = true;
} else {
tab_data->fav_icon_url = webui::EncodePNGAndMakeDataURI(
tab_renderer_data.favicon, web_ui_->GetDeviceScaleFactor());
tab_data->is_default_favicon =
tab_renderer_data.favicon.BackedBySameObjectAs(
favicon::GetDefaultFavicon().AsImageSkia());
}
tab_data->show_icon = tab_renderer_data.show_icon;
return tab_data;
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_TAB_SEARCH_TAB_SEARCH_PAGE_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_TAB_SEARCH_TAB_SEARCH_PAGE_HANDLER_H_
#include "chrome/browser/ui/tabs/tab_group.h"
#include "chrome/browser/ui/tabs/tab_group_model.h"
#include "chrome/browser/ui/tabs/tab_group_theme.h"
#include "chrome/browser/ui/webui/tab_search/tab_search.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "ui/webui/mojo_web_ui_controller.h"
class Browser;
class TabSearchPageHandler : public tab_search::mojom::PageHandler {
public:
TabSearchPageHandler(
mojo::PendingReceiver<tab_search::mojom::PageHandler> receiver,
mojo::PendingRemote<tab_search::mojom::Page> page,
content::WebUI* web_ui);
TabSearchPageHandler(const TabSearchPageHandler&) = delete;
TabSearchPageHandler& operator=(const TabSearchPageHandler&) = delete;
~TabSearchPageHandler() override;
// tab_search::mojom::PageHandler:
void GetProfileTabs(GetProfileTabsCallback callback) override;
void GetTabGroups(GetTabGroupsCallback callback) override;
void SwitchToTab(
tab_search::mojom::SwitchToTabInfoPtr switch_to_tab_info) override;
private:
tab_search::mojom::TabPtr GetTabData(Browser* browser,
content::WebContents* contents,
int index);
mojo::Receiver<tab_search::mojom::PageHandler> receiver_;
mojo::Remote<tab_search::mojom::Page> page_;
Browser* const browser_;
content::WebUI* const web_ui_;
};
#endif // CHROME_BROWSER_UI_WEBUI_TAB_SEARCH_TAB_SEARCH_PAGE_HANDLER_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/tab_search/tab_search_page_handler.h"
#include "base/test/bind_test_util.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/test_browser_window.h"
#include "content/public/test/test_web_ui.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/gfx/color_utils.h"
namespace {
constexpr char kTabUrl1[] = "http://foo/1";
constexpr char kTabUrl2[] = "http://foo/2";
constexpr char kTabUrl3[] = "http://foo/3";
constexpr char kTabUrl4[] = "http://foo/4";
constexpr char kTabUrlName1[] = "foo/1";
constexpr char kTabUrlName2[] = "foo/2";
constexpr char kTabUrlName3[] = "foo/3";
constexpr char kTabName1[] = "Tab 1";
constexpr char kTabName2[] = "Tab 2";
constexpr char kTabName3[] = "Tab 3";
constexpr char kTabName4[] = "Tab 4";
class MockPage : public tab_search::mojom::Page {
public:
MockPage() = default;
~MockPage() override = default;
mojo::PendingRemote<tab_search::mojom::Page> BindAndGetRemote() {
DCHECK(!receiver_.is_bound());
return receiver_.BindNewPipeAndPassRemote();
}
mojo::Receiver<tab_search::mojom::Page> receiver_{this};
};
void ExpectNewTab(const tab_search::mojom::Tab* tab,
const std::string url,
const std::string title,
int index) {
EXPECT_EQ(index, tab->index);
EXPECT_LT(0, tab->tab_id);
EXPECT_FALSE(tab->group_id.has_value());
EXPECT_FALSE(tab->pinned);
EXPECT_EQ(title, tab->title);
EXPECT_EQ(url, tab->url);
EXPECT_TRUE(tab->fav_icon_url.has_value());
EXPECT_TRUE(tab->is_default_favicon);
EXPECT_TRUE(tab->show_icon);
}
void ExpectProfileTabs(tab_search::mojom::ProfileTabs* profile_tabs) {
ASSERT_EQ(2u, profile_tabs->windows.size());
auto* window1 = profile_tabs->windows[0].get();
ASSERT_EQ(2u, window1->tabs.size());
ASSERT_FALSE(window1->tabs[0]->active);
ASSERT_TRUE(window1->tabs[1]->active);
auto* window2 = profile_tabs->windows[1].get();
ASSERT_EQ(1u, window2->tabs.size());
ASSERT_TRUE(window2->tabs[0]->active);
}
class TestTabSearchPageHandler : public TabSearchPageHandler {
public:
TestTabSearchPageHandler(mojo::PendingRemote<tab_search::mojom::Page> page,
content::WebUI* web_ui)
: TabSearchPageHandler(
mojo::PendingReceiver<tab_search::mojom::PageHandler>(),
std::move(page),
web_ui) {}
};
class TabSearchPageHandlerTest : public BrowserWithTestWindowTest {
public:
void SetUp() override {
BrowserWithTestWindowTest::SetUp();
browser2_ = CreateTestBrowser(false, false);
browser3_ = CreateTestBrowser(true, false);
BrowserList::SetLastActive(browser1());
handler_ = std::make_unique<TestTabSearchPageHandler>(
page_.BindAndGetRemote(), web_ui());
}
void TearDown() override {
browser1()->tab_strip_model()->CloseAllTabs();
browser2()->tab_strip_model()->CloseAllTabs();
browser3()->tab_strip_model()->CloseAllTabs();
browser2_.reset();
browser3_.reset();
BrowserWithTestWindowTest::TearDown();
}
content::TestWebUI* web_ui() { return &web_ui_; }
Browser* browser1() { return browser(); }
Browser* browser2() { return browser2_.get(); }
Browser* browser3() { return browser3_.get(); }
TestTabSearchPageHandler* handler() { return handler_.get(); }
protected:
void AddTabWithTitle(Browser* browser,
const GURL url,
const std::string title) {
AddTab(browser, url);
NavigateAndCommitActiveTabWithTitle(browser, url,
base::ASCIIToUTF16(title));
}
private:
std::unique_ptr<Browser> CreateTestBrowser(bool incognito, bool popup) {
auto window = std::make_unique<TestBrowserWindow>();
Profile* profile = incognito ? browser()->profile()->GetPrimaryOTRProfile()
: browser()->profile();
Browser::Type type = popup ? Browser::TYPE_POPUP : Browser::TYPE_NORMAL;
std::unique_ptr<Browser> browser =
CreateBrowser(profile, type, false, window.get());
BrowserList::SetLastActive(browser.get());
new TestBrowserWindowOwner(window.release());
return browser;
}
testing::StrictMock<MockPage> page_;
content::TestWebUI web_ui_;
std::unique_ptr<Browser> browser2_;
std::unique_ptr<Browser> browser3_;
std::unique_ptr<TestTabSearchPageHandler> handler_;
};
TEST_F(TabSearchPageHandlerTest, GetTabs) {
// Browser3 is in incognito mode, thus its tab should not be accessible.
AddTabWithTitle(browser3(), GURL(kTabUrl4), kTabName4);
AddTabWithTitle(browser2(), GURL(kTabUrl3), kTabName3);
AddTabWithTitle(browser1(), GURL(kTabUrl2), kTabName2);
AddTabWithTitle(browser1(), GURL(kTabUrl1), kTabName1);
int32_t tab_id2 = 0;
int32_t tab_id3 = 0;
// Get Tabs.
tab_search::mojom::PageHandler::GetProfileTabsCallback callback1 =
base::BindLambdaForTesting(
[&](tab_search::mojom::ProfileTabsPtr profile_tabs) {
ASSERT_EQ(2u, profile_tabs->windows.size());
auto* window1 = profile_tabs->windows[0].get();
ASSERT_TRUE(window1->active);
ASSERT_EQ(2u, window1->tabs.size());
auto* tab1 = window1->tabs[0].get();
ExpectNewTab(tab1, kTabUrlName1, kTabName1, 0);
ASSERT_TRUE(tab1->active);
auto* tab2 = window1->tabs[1].get();
ExpectNewTab(tab2, kTabUrlName2, kTabName2, 1);
ASSERT_FALSE(tab2->active);
auto* window2 = profile_tabs->windows[1].get();
ASSERT_FALSE(window2->active);
ASSERT_EQ(1u, window2->tabs.size());
auto* tab3 = window2->tabs[0].get();
ExpectNewTab(tab3, kTabUrlName3, kTabName3, 0);
ASSERT_TRUE(tab3->active);
tab_id2 = tab2->tab_id;
tab_id3 = tab3->tab_id;
});
handler()->GetProfileTabs(std::move(callback1));
// Switch to 2nd tab.
auto switch_to_tab_info = tab_search::mojom::SwitchToTabInfo::New();
switch_to_tab_info->tab_id = tab_id2;
handler()->SwitchToTab(std::move(switch_to_tab_info));
// Get Tabs again to verify tab switch.
tab_search::mojom::PageHandler::GetProfileTabsCallback callback2 =
base::BindLambdaForTesting(
[&](tab_search::mojom::ProfileTabsPtr profile_tabs) {
ExpectProfileTabs(profile_tabs.get());
});
handler()->GetProfileTabs(std::move(callback2));
// Switch to 3rd tab.
switch_to_tab_info = tab_search::mojom::SwitchToTabInfo::New();
switch_to_tab_info->tab_id = tab_id3;
handler()->SwitchToTab(std::move(switch_to_tab_info));
// Get Tabs again to verify tab switch.
tab_search::mojom::PageHandler::GetProfileTabsCallback callback3 =
base::BindLambdaForTesting(
[&](tab_search::mojom::ProfileTabsPtr profile_tabs) {
ExpectProfileTabs(profile_tabs.get());
});
handler()->GetProfileTabs(std::move(callback3));
}
} // namespace
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/tab_search/tab_search_ui.h"
#include "chrome/browser/ui/webui/tab_search/tab_search_page_handler.h"
#include "chrome/browser/ui/webui/webui_util.h"
#include "chrome/common/webui_url_constants.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
TabSearchUI::TabSearchUI(content::WebUI* web_ui)
: ui::MojoWebUIController(web_ui) {
content::WebUIDataSource* source =
content::WebUIDataSource::Create(chrome::kChromeUITabSearchHost);
content::WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(),
source);
}
TabSearchUI::~TabSearchUI() = default;
WEB_UI_CONTROLLER_TYPE_IMPL(TabSearchUI)
void TabSearchUI::BindInterface(
mojo::PendingReceiver<tab_search::mojom::PageHandlerFactory> receiver) {
page_factory_receiver_.reset();
page_factory_receiver_.Bind(std::move(receiver));
}
void TabSearchUI::CreatePageHandler(
mojo::PendingRemote<tab_search::mojom::Page> page,
mojo::PendingReceiver<tab_search::mojom::PageHandler> receiver) {
DCHECK(page);
page_handler_ = std::make_unique<TabSearchPageHandler>(
std::move(receiver), std::move(page), web_ui());
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_TAB_SEARCH_TAB_SEARCH_UI_H_
#define CHROME_BROWSER_UI_WEBUI_TAB_SEARCH_TAB_SEARCH_UI_H_
#include <memory>
#include "base/macros.h"
#include "chrome/browser/ui/webui/tab_search/tab_search.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "ui/webui/mojo_web_ui_controller.h"
class Browser;
class TabSearchUIEmbedder;
class TabSearchPageHandler;
class TabSearchUI : public ui::MojoWebUIController,
public tab_search::mojom::PageHandlerFactory {
public:
explicit TabSearchUI(content::WebUI* web_ui);
TabSearchUI(const TabSearchUI&) = delete;
TabSearchUI& operator=(const TabSearchUI&) = delete;
~TabSearchUI() override;
// Initialize TabSearchUI by passing in the current browser and the
// current embedder, the WebUI won't work until this is called.
void Initialize(Browser* browser, TabSearchUIEmbedder* embedder);
// Instantiates the implementor of the mojom::PageHandlerFactory mojo
// interface passing the pending receiver that will be internally bound.
void BindInterface(
mojo::PendingReceiver<tab_search::mojom::PageHandlerFactory> receiver);
private:
// tab_search::mojom::PageHandlerFactory
void CreatePageHandler(
mojo::PendingRemote<tab_search::mojom::Page> page,
mojo::PendingReceiver<tab_search::mojom::PageHandler> receiver) override;
std::unique_ptr<TabSearchPageHandler> page_handler_;
mojo::Receiver<tab_search::mojom::PageHandlerFactory> page_factory_receiver_{
this};
WEB_UI_CONTROLLER_TYPE_DECL();
};
#endif // CHROME_BROWSER_UI_WEBUI_TAB_SEARCH_TAB_SEARCH_UI_H_
......@@ -5,7 +5,6 @@
#include "chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler.h"
#include <memory>
#include "base/base64.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/optional.h"
......@@ -28,11 +27,11 @@
#include "chrome/browser/ui/webui/tab_strip/tab_strip_ui_embedder.h"
#include "chrome/browser/ui/webui/tab_strip/tab_strip_ui_metrics.h"
#include "chrome/browser/ui/webui/tab_strip/tab_strip_ui_util.h"
#include "chrome/browser/ui/webui/util/image_util.h"
#include "chrome/grit/generated_resources.h"
#include "components/tab_groups/tab_group_color.h"
#include "components/tab_groups/tab_group_id.h"
#include "components/tab_groups/tab_group_visual_data.h"
#include "third_party/skia/include/core/SkStream.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/list_selection_model.h"
#include "ui/base/models/simple_menu_model.h"
......@@ -72,48 +71,6 @@ std::string ConvertAlertStateToString(TabAlertState alert_state) {
}
}
// Writes bytes to a std::vector that can be fetched. This is used to record the
// output of skia image encoding.
class BufferWStream : public SkWStream {
public:
BufferWStream() = default;
~BufferWStream() override = default;
// Returns the output buffer by moving.
std::vector<unsigned char> GetBuffer() { return std::move(result_); }
// SkWStream:
bool write(const void* buffer, size_t size) override {
const unsigned char* bytes = reinterpret_cast<const unsigned char*>(buffer);
result_.insert(result_.end(), bytes, bytes + size);
return true;
}
size_t bytesWritten() const override { return result_.size(); }
private:
std::vector<unsigned char> result_;
};
std::string MakeDataURIForImage(base::span<const uint8_t> image_data,
base::StringPiece mime_subtype) {
std::string result = "data:image/";
result.append(mime_subtype.begin(), mime_subtype.end());
result += ";base64,";
result += base::Base64Encode(image_data);
return result;
}
std::string EncodePNGAndMakeDataURI(gfx::ImageSkia image, float scale_factor) {
const SkBitmap& bitmap = image.GetRepresentation(scale_factor).GetBitmap();
BufferWStream stream;
const bool encoding_succeeded =
SkEncodeImage(&stream, bitmap, SkEncodedImageFormat::kPNG, 100);
DCHECK(encoding_succeeded);
return MakeDataURIForImage(
base::as_bytes(base::make_span(stream.GetBuffer())), "png");
}
class WebUIBackgroundMenuModel : public ui::SimpleMenuModel {
public:
explicit WebUIBackgroundMenuModel(ui::SimpleMenuModel::Delegate* delegate)
......@@ -459,7 +416,7 @@ base::DictionaryValue TabStripUIHandler::GetTabData(
tab_data.SetString("url", tab_renderer_data.visible_url.GetContent());
if (!tab_renderer_data.favicon.isNull()) {
tab_data.SetString("favIconUrl", EncodePNGAndMakeDataURI(
tab_data.SetString("favIconUrl", webui::EncodePNGAndMakeDataURI(
tab_renderer_data.favicon,
web_ui()->GetDeviceScaleFactor()));
tab_data.SetBoolean("isDefaultFavicon",
......@@ -876,7 +833,7 @@ void TabStripUIHandler::HandleThumbnailUpdate(
ThumbnailTracker::CompressedThumbnailData image) {
// Send base-64 encoded image to JS side.
std::string data_uri =
MakeDataURIForImage(base::make_span(image->data), "jpeg");
webui::MakeDataURIForImage(base::make_span(image->data), "jpeg");
const int tab_id = extensions::ExtensionTabUtil::GetTabId(tab);
FireWebUIListener("tab-thumbnail-updated", base::Value(tab_id),
......
dpapad@chromium.org
johntlee@chromium.org
robliao@chromium.org
tluk@chromium.org
# COMPONENT: UI>Browser>WebUI
\ No newline at end of file
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/util/image_util.h"
#include "base/base64.h"
#include "third_party/skia/include/core/SkStream.h"
#include "ui/gfx/image/image_skia.h"
namespace {
// Writes bytes to a std::vector that can be fetched. This is used to record the
// output of skia image encoding.
class BufferWStream : public SkWStream {
public:
BufferWStream() = default;
~BufferWStream() override = default;
// Returns the output buffer by moving.
std::vector<unsigned char> GetBuffer() { return std::move(result_); }
// SkWStream:
bool write(const void* buffer, size_t size) override {
const unsigned char* bytes = reinterpret_cast<const unsigned char*>(buffer);
result_.insert(result_.end(), bytes, bytes + size);
return true;
}
size_t bytesWritten() const override { return result_.size(); }
private:
std::vector<unsigned char> result_;
};
} // namespace
namespace webui {
std::string MakeDataURIForImage(base::span<const uint8_t> image_data,
base::StringPiece mime_subtype) {
std::string result = "data:image/";
result.append(mime_subtype.begin(), mime_subtype.end());
result += ";base64,";
result += base::Base64Encode(image_data);
return result;
}
std::string EncodePNGAndMakeDataURI(gfx::ImageSkia image, float scale_factor) {
const SkBitmap& bitmap = image.GetRepresentation(scale_factor).GetBitmap();
BufferWStream stream;
const bool encoding_succeeded =
SkEncodeImage(&stream, bitmap, SkEncodedImageFormat::kPNG, 100);
DCHECK(encoding_succeeded);
return MakeDataURIForImage(
base::as_bytes(base::make_span(stream.GetBuffer())), "png");
}
} // namespace webui
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_UTIL_IMAGE_UTIL_H_
#define CHROME_BROWSER_UI_WEBUI_UTIL_IMAGE_UTIL_H_
#include "base/containers/span.h"
#include "base/strings/string_piece_forward.h"
namespace gfx {
class ImageSkia;
} // namespace gfx
namespace webui {
std::string MakeDataURIForImage(base::span<const uint8_t> image_data,
base::StringPiece mime_subtype);
std::string EncodePNGAndMakeDataURI(gfx::ImageSkia image, float scale_factor);
} // namespace webui
#endif // CHROME_BROWSER_UI_WEBUI_UTIL_IMAGE_UTIL_H_
......@@ -350,6 +350,11 @@ const char kChromeUITabStripHost[] = "tab-strip";
const char kChromeUITabStripURL[] = "chrome://tab-strip";
#endif
#if !defined(OS_ANDROID)
const char kChromeUITabSearchHost[] = "tab-search";
const char kChromeUITabSearchURL[] = "chrome://tab-search/";
#endif
const char kChromeUIWebRtcLogsHost[] = "webrtc-logs";
// Settings sub pages.
......
......@@ -310,6 +310,11 @@ extern const char kChromeUITabStripHost[];
extern const char kChromeUITabStripURL[];
#endif
#if !defined(OS_ANDROID)
extern const char kChromeUITabSearchHost[];
extern const char kChromeUITabSearchURL[];
#endif
extern const char kChromeUIWebRtcLogsHost[];
// Settings sub-pages.
......
......@@ -4270,6 +4270,7 @@ test("unit_tests") {
"../browser/ui/webui/settings_utils_unittest.cc",
"../browser/ui/webui/signin/login_ui_service_unittest.cc",
"../browser/ui/webui/sync_internals_message_handler_unittest.cc",
"../browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc",
"../browser/ui/webui/theme_source_unittest.cc",
"../browser/ui/webui/web_dialog_web_contents_delegate_unittest.cc",
"../browser/ui/webui/webui_allowlist_provider_unittest.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment