diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 52abc0a..64d3ff7a 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -490,11 +490,6 @@ <message name="IDS_EDIT" desc="Edit menu item"> &Edit </message> - <if expr="is_macosx"> - <message name="IDS_ACCNAME_TAB" desc="A generic description of a tab button's role" meaning="UI element"> - Tab - </message> - </if> <message name="IDS_SAVE" desc="Used on a button to save information you are editing."> Save </message>
diff --git a/chrome/browser/android/banners/app_banner_manager_android.cc b/chrome/browser/android/banners/app_banner_manager_android.cc index a8a21c59..8ae8d3c3 100644 --- a/chrome/browser/android/banners/app_banner_manager_android.cc +++ b/chrome/browser/android/banners/app_banner_manager_android.cc
@@ -107,6 +107,9 @@ native_app_package_ = ConvertJavaStringToUTF8(env, japp_package); icon_url_ = GURL(ConvertJavaStringToUTF8(env, jicon_url)); + if (!CheckIfShouldShowBanner()) + return false; + return ManifestIconDownloader::Download( web_contents(), icon_url_, GetIdealIconSizeInPx(), GetMinimumIconSizeInPx(),
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc index 55e03e54..908b932 100644 --- a/chrome/browser/banners/app_banner_manager.cc +++ b/chrome/browser/banners/app_banner_manager.cc
@@ -240,14 +240,7 @@ } void AppBannerManager::PerformInstallableCheck() { - if (IsWebAppInstalled(web_contents()->GetBrowserContext(), - manifest_.start_url, manifest_url_) && - !IsDebugMode()) { - ReportStatus(web_contents(), ALREADY_INSTALLED); - Stop(); - } - - if (!is_active_) + if (!CheckIfShouldShowBanner()) return; // Fetch and verify the other required information. @@ -338,13 +331,6 @@ void AppBannerManager::SendBannerPromptRequest() { RecordCouldShowBanner(); - // Given all of the other checks that have been made, the only possible reason - // for stopping now is that the app has been added to the homescreen. - if (!IsDebugMode() && !CheckIfShouldShowBanner()) { - Stop(); - return; - } - TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_CREATED); event_request_id_ = ++gCurrentRequestID; @@ -450,37 +436,43 @@ } bool AppBannerManager::CheckIfShouldShowBanner() { - content::WebContents* contents = web_contents(); - DCHECK(contents); - - InstallableStatusCode code = AppBannerSettingsHelper::ShouldShowBanner( - contents, validated_url_, GetAppIdentifier(), GetCurrentTime()); - if (code == NO_ERROR_DETECTED) + if (IsDebugMode()) return true; - switch (code) { - case ALREADY_INSTALLED: - banners::TrackDisplayEvent(banners::DISPLAY_EVENT_INSTALLED_PREVIOUSLY); - break; - case PREVIOUSLY_BLOCKED: - banners::TrackDisplayEvent(banners::DISPLAY_EVENT_BLOCKED_PREVIOUSLY); - break; - case PREVIOUSLY_IGNORED: - banners::TrackDisplayEvent(banners::DISPLAY_EVENT_IGNORED_PREVIOUSLY); - break; - case INSUFFICIENT_ENGAGEMENT: - banners::TrackDisplayEvent(banners::DISPLAY_EVENT_NOT_VISITED_ENOUGH); - break; - default: - break; + // Check whether we are permitted to show the banner. If we have already + // added this site to homescreen, or if the banner has been shown too + // recently, prevent the banner from being shown. + content::WebContents* contents = web_contents(); + InstallableStatusCode code = AppBannerSettingsHelper::ShouldShowBanner( + contents, validated_url_, GetAppIdentifier(), GetCurrentTime()); + + if (code == NO_ERROR_DETECTED && + IsWebAppInstalled(contents->GetBrowserContext(), manifest_.start_url, + manifest_url_)) { + code = ALREADY_INSTALLED; } - // If we are in debug mode, AppBannerSettingsHelper::ShouldShowBanner must - // return NO_ERROR_DETECTED (bypass flag is set) or we must not have entered - // this method. - DCHECK(!IsDebugMode()); - ReportStatus(web_contents(), code); - return false; + if (code != NO_ERROR_DETECTED) { + switch (code) { + case ALREADY_INSTALLED: + banners::TrackDisplayEvent(banners::DISPLAY_EVENT_INSTALLED_PREVIOUSLY); + break; + case PREVIOUSLY_BLOCKED: + banners::TrackDisplayEvent(banners::DISPLAY_EVENT_BLOCKED_PREVIOUSLY); + break; + case PREVIOUSLY_IGNORED: + banners::TrackDisplayEvent(banners::DISPLAY_EVENT_IGNORED_PREVIOUSLY); + break; + case PACKAGE_NAME_OR_START_URL_EMPTY: + break; + default: + NOTREACHED(); + } + ReportStatus(contents, code); + Stop(); + return false; + } + return true; } void AppBannerManager::OnBannerPromptReply(
diff --git a/chrome/browser/banners/app_banner_manager.h b/chrome/browser/banners/app_banner_manager.h index 4301ca90..be43a91 100644 --- a/chrome/browser/banners/app_banner_manager.h +++ b/chrome/browser/banners/app_banner_manager.h
@@ -104,6 +104,11 @@ explicit AppBannerManager(content::WebContents* web_contents); ~AppBannerManager() override; + // Returns true if the banner should be shown. Returns false if the banner has + // been shown too recently, or if the app has already been installed. + // GetAppIdentifier() must return a valid value for this method to work. + bool CheckIfShouldShowBanner(); + // Return a string identifying this app for metrics. virtual std::string GetAppIdentifier(); @@ -221,9 +226,6 @@ // platform-specific. virtual void ShowBanner() = 0; - // Returns true if the banner should be shown. - bool CheckIfShouldShowBanner(); - // Called after the manager sends a message to the renderer regarding its // intention to show a prompt. The renderer will send a message back with the // opportunity to cancel.
diff --git a/chrome/browser/banners/app_banner_settings_helper.cc b/chrome/browser/banners/app_banner_settings_helper.cc index f314a0c..28989395 100644 --- a/chrome/browser/banners/app_banner_settings_helper.cc +++ b/chrome/browser/banners/app_banner_settings_helper.cc
@@ -246,12 +246,6 @@ const GURL& origin_url, const std::string& package_name_or_start_url, base::Time time) { - // Ignore all checks if the flag to do so is set. - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kBypassAppBannerEngagementChecks)) { - return NO_ERROR_DETECTED; - } - // Never show a banner when the package name or URL is empty. if (package_name_or_start_url.empty()) return PACKAGE_NAME_OR_START_URL_EMPTY; @@ -277,9 +271,8 @@ base::Time shown_time = GetSingleBannerEvent(web_contents, origin_url, package_name_or_start_url, APP_BANNER_EVENT_DID_SHOW); - if (time - shown_time < base::TimeDelta::FromDays(gDaysAfterIgnoredToShow)) { + if (time - shown_time < base::TimeDelta::FromDays(gDaysAfterIgnoredToShow)) return PREVIOUSLY_IGNORED; - } return NO_ERROR_DETECTED; }
diff --git a/chrome/browser/chromeos/arc/arc_service_launcher.cc b/chrome/browser/chromeos/arc/arc_service_launcher.cc index 356664c3..06182b0 100644 --- a/chrome/browser/chromeos/arc/arc_service_launcher.cc +++ b/chrome/browser/chromeos/arc/arc_service_launcher.cc
@@ -98,20 +98,20 @@ base::MakeUnique<ArcBootPhaseMonitorBridge>(arc_bridge_service)); arc_service_manager_->AddService( base::MakeUnique<ArcClipboardBridge>(arc_bridge_service)); - arc_service_manager_->AddService( - base::MakeUnique<ArcFileSystemService>(arc_bridge_service)); arc_service_manager_->AddService(base::MakeUnique<ArcCrashCollectorBridge>( arc_bridge_service, arc_service_manager_->blocking_task_runner())); arc_service_manager_->AddService( base::MakeUnique<ArcDownloadsWatcherService>(arc_bridge_service)); arc_service_manager_->AddService( base::MakeUnique<ArcEnterpriseReportingService>(arc_bridge_service)); + arc_service_manager_->AddService( + base::MakeUnique<ArcFileSystemService>(arc_bridge_service)); + arc_service_manager_->AddService( + base::MakeUnique<ArcImeService>(arc_bridge_service)); arc_service_manager_->AddService(base::MakeUnique<ArcIntentHelperBridge>( arc_bridge_service, arc_service_manager_->icon_loader(), arc_service_manager_->activity_resolver())); arc_service_manager_->AddService( - base::MakeUnique<ArcImeService>(arc_bridge_service)); - arc_service_manager_->AddService( base::MakeUnique<ArcMetricsService>(arc_bridge_service)); arc_service_manager_->AddService( base::MakeUnique<ArcNetHostImpl>(arc_bridge_service));
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc index 2bfa997..8f9fcf3 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -160,6 +160,15 @@ IDS_FILE_BROWSER_SYNC_SERVICE_UNAVAILABLE_ERROR); } +void AddStringsForMediaView(base::DictionaryValue* dict) { + SET_STRING("MEDIA_VIEW_AUDIO_ROOT_LABEL", + IDS_FILE_BROWSER_MEDIA_VIEW_AUDIO_ROOT_LABEL); + SET_STRING("MEDIA_VIEW_IMAGES_ROOT_LABEL", + IDS_FILE_BROWSER_MEDIA_VIEW_IMAGES_ROOT_LABEL); + SET_STRING("MEDIA_VIEW_VIDEOS_ROOT_LABEL", + IDS_FILE_BROWSER_MEDIA_VIEW_VIDEOS_ROOT_LABEL); +} + void AddStringsForGallery(base::DictionaryValue* dict) { SET_STRING("GALLERY_ASPECT_RATIO_16_9", IDS_FILE_BROWSER_GALLERY_ASPECT_RATIO_16_9); @@ -357,6 +366,7 @@ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); AddStringsForDrive(dict.get()); + AddStringsForMediaView(dict.get()); AddStringsForFileTypes(dict.get()); AddStringsForGallery(dict.get()); AddStringsForMediaPlayer(dict.get());
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 7488e79..de0ea0a 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -473,6 +473,7 @@ "//chrome/browser/ui/webui/omnibox:mojo_bindings", "//chrome/browser/ui/webui/usb_internals:mojo_bindings", "//chrome/common", + "//chrome/common:instant_mojom", "//chrome/common/net", "//chrome/installer/util:with_no_strings", "//components/app_modal",
diff --git a/chrome/browser/ui/cocoa/tabs/tab_view.mm b/chrome/browser/ui/cocoa/tabs/tab_view.mm index 04f9b165..f454cfb6 100644 --- a/chrome/browser/ui/cocoa/tabs/tab_view.mm +++ b/chrome/browser/ui/cocoa/tabs/tab_view.mm
@@ -15,7 +15,6 @@ #import "chrome/browser/ui/cocoa/tabs/tab_window_controller.h" #import "chrome/browser/ui/cocoa/themed_window.h" #import "chrome/browser/ui/cocoa/view_id_util.h" -#include "chrome/grit/generated_resources.h" #include "chrome/grit/theme_resources.h" #include "skia/ext/skia_utils_mac.h" #import "third_party/google_toolbox_for_mac/src/AppKit/GTMFadeTruncatingTextFieldCell.h" @@ -26,6 +25,7 @@ #include "ui/base/material_design/material_design_controller.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" +#include "ui/strings/grit/ui_strings.h" namespace { @@ -759,7 +759,7 @@ if ([attribute isEqual:NSAccessibilityRoleAttribute]) return NSAccessibilityRadioButtonRole; if ([attribute isEqual:NSAccessibilityRoleDescriptionAttribute]) - return l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TAB); + return l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TAB_ROLE_DESCRIPTION); if ([attribute isEqual:NSAccessibilityTitleAttribute]) return [controller_ title]; if ([attribute isEqual:NSAccessibilityValueAttribute])
diff --git a/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc b/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc index 075768b..5d18b07 100644 --- a/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc +++ b/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc
@@ -28,10 +28,12 @@ #include "chrome/browser/search/search.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/ui/browser_instant_controller.h" +#include "chrome/browser/ui/search/search_ipc_router.h" #include "chrome/browser/ui/search/search_tab_helper.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/render_messages.h" #include "chrome/common/search/instant_types.h" +#include "chrome/common/search/mock_searchbox.h" #include "components/omnibox/browser/autocomplete_match.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/web_contents.h" @@ -43,9 +45,20 @@ #include "ui/gfx/geometry/size.h" using base::ASCIIToUTF16; +using testing::_; +using testing::AllOf; +using testing::Eq; +using testing::Field; +using testing::Return; namespace { +class MockSearchBoxClientFactory + : public SearchIPCRouter::SearchBoxClientFactory { + public: + MOCK_METHOD0(GetSearchBox, chrome::mojom::SearchBox*(void)); +}; + using content::Referrer; using prerender::Origin; using prerender::PrerenderContents; @@ -56,13 +69,13 @@ class DummyPrerenderContents : public PrerenderContents { public: - DummyPrerenderContents( - PrerenderManager* prerender_manager, - Profile* profile, - const GURL& url, - const Referrer& referrer, - Origin origin, - bool call_did_finish_load); + DummyPrerenderContents(PrerenderManager* prerender_manager, + Profile* profile, + const GURL& url, + const Referrer& referrer, + Origin origin, + bool call_did_finish_load, + chrome::mojom::SearchBox* search_box); void StartPrerendering( const gfx::Rect& bounds, @@ -74,15 +87,16 @@ Profile* profile_; const GURL url_; bool call_did_finish_load_; + chrome::mojom::SearchBox* search_box_; DISALLOW_COPY_AND_ASSIGN(DummyPrerenderContents); }; class DummyPrerenderContentsFactory : public PrerenderContents::Factory { public: - explicit DummyPrerenderContentsFactory(bool call_did_finish_load) - : call_did_finish_load_(call_did_finish_load) { - } + DummyPrerenderContentsFactory(bool call_did_finish_load, + chrome::mojom::SearchBox* search_box) + : call_did_finish_load_(call_did_finish_load), search_box_(search_box) {} PrerenderContents* CreatePrerenderContents( PrerenderManager* prerender_manager, @@ -93,6 +107,7 @@ private: bool call_did_finish_load_; + chrome::mojom::SearchBox* search_box_; DISALLOW_COPY_AND_ASSIGN(DummyPrerenderContentsFactory); }; @@ -103,12 +118,13 @@ const GURL& url, const Referrer& referrer, Origin origin, - bool call_did_finish_load) + bool call_did_finish_load, + chrome::mojom::SearchBox* search_box) : PrerenderContents(prerender_manager, profile, url, referrer, origin), profile_(profile), url_(url), - call_did_finish_load_(call_did_finish_load) { -} + call_did_finish_load_(call_did_finish_load), + search_box_(search_box) {} void DummyPrerenderContents::StartPrerendering( const gfx::Rect& bounds, @@ -122,6 +138,12 @@ content::NavigationController::LoadURLParams params(url_); prerender_contents_->GetController().LoadURLWithParams(params); SearchTabHelper::CreateForWebContents(prerender_contents_.get()); + auto* search_tab = + SearchTabHelper::FromWebContents(prerender_contents_.get()); + auto factory = base::MakeUnique<MockSearchBoxClientFactory>(); + ON_CALL(*factory, GetSearchBox()).WillByDefault(Return(search_box_)); + search_tab->ipc_router_for_testing() + .set_search_box_client_factory_for_testing(std::move(factory)); prerendering_has_started_ = true; DCHECK(session_storage_namespace); @@ -149,7 +171,7 @@ const Referrer& referrer, Origin origin) { return new DummyPrerenderContents(prerender_manager, profile, url, referrer, - origin, call_did_finish_load_); + origin, call_did_finish_load_, search_box_); } } // namespace @@ -170,8 +192,8 @@ AddTab(browser(), GURL(url::kAboutBlankURL)); PrerenderManagerFactory::GetForBrowserContext(browser()->profile()) - ->SetPrerenderContentsFactoryForTest( - new DummyPrerenderContentsFactory(call_did_finish_load)); + ->SetPrerenderContentsFactoryForTest(new DummyPrerenderContentsFactory( + call_did_finish_load, &mock_search_box_)); if (prerender_search_results_base_page) { content::SessionStorageNamespace* session_storage_namespace = GetActiveWebContents()->GetController(). @@ -199,13 +221,6 @@ return GetInstantSearchPrerenderer()->prerender_contents(); } - bool MessageWasSent(uint32_t id) { - content::MockRenderProcessHost* process = - static_cast<content::MockRenderProcessHost*>( - prerender_contents()->GetMainFrame()->GetProcess()); - return process->sink().GetFirstMessageMatching(id) != NULL; - } - content::WebContents* GetActiveWebContents() const { return browser()->tab_strip_model()->GetWebContentsAt(0); } @@ -222,6 +237,11 @@ EXPECT_TRUE(prerenderer->CanCommitQuery(GetActiveWebContents(), query)); EXPECT_NE(static_cast<PrerenderHandle*>(NULL), prerender_handle()); } + + MockSearchBox* mock_search_box() { return &mock_search_box_; } + + private: + MockSearchBox mock_search_box_; }; TEST_F(InstantSearchPrerendererTest, GetSearchTermsFromPrerenderedPage) { @@ -247,11 +267,10 @@ Init(true, true); EXPECT_TRUE(prerender_handle()->IsFinishedLoading()); InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer(); + EXPECT_CALL(*mock_search_box(), SetSuggestionToPrefetch(_)); prerenderer->Prerender( InstantSuggestion(ASCIIToUTF16("flowers"), std::string())); EXPECT_EQ("flowers", base::UTF16ToASCII(prerenderer->get_last_query())); - EXPECT_TRUE(MessageWasSent( - ChromeViewMsg_SearchBoxSetSuggestionToPrefetch::ID)); } TEST_F(InstantSearchPrerendererTest, DoNotPrefetchSearchResults) { @@ -259,11 +278,10 @@ // Page hasn't finished loading yet. EXPECT_FALSE(prerender_handle()->IsFinishedLoading()); InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer(); + EXPECT_CALL(*mock_search_box(), SetSuggestionToPrefetch(_)).Times(0); prerenderer->Prerender( InstantSuggestion(ASCIIToUTF16("flowers"), std::string())); EXPECT_EQ("", base::UTF16ToASCII(prerenderer->get_last_query())); - EXPECT_FALSE(MessageWasSent( - ChromeViewMsg_SearchBoxSetSuggestionToPrefetch::ID)); } TEST_F(InstantSearchPrerendererTest, CanCommitQuery) { @@ -285,8 +303,8 @@ base::string16 query = ASCIIToUTF16("flowers"); PrerenderSearchQuery(query); InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer(); + EXPECT_CALL(*mock_search_box(), Submit(_, _)); prerenderer->Commit(query, EmbeddedSearchRequestParams()); - EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxSubmit::ID)); } TEST_F(InstantSearchPrerendererTest, CancelPrerenderRequestOnTabChangeEvent) { @@ -435,7 +453,7 @@ void SetUp() override { ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("EmbeddedSearch", "Group1 strk:20")); - InstantUnitTestBase::SetUp(); + InstantSearchPrerendererTest::SetUp(); } }; @@ -504,6 +522,17 @@ TEST_F(TestUsePrerenderPage, SetEmbeddedSearchRequestParams) { PrerenderSearchQuery(ASCIIToUTF16("foo")); EXPECT_TRUE(browser()->instant_controller()); + EXPECT_CALL( + *mock_search_box(), + Submit(Eq(ASCIIToUTF16("foo")), + AllOf(Field(&EmbeddedSearchRequestParams::original_query, + Eq(base::ASCIIToUTF16("f"))), + Field(&EmbeddedSearchRequestParams::input_encoding, + Eq(base::ASCIIToUTF16("utf-8"))), + Field(&EmbeddedSearchRequestParams::rlz_parameter_value, + Eq(base::ASCIIToUTF16(""))), + Field(&EmbeddedSearchRequestParams::assisted_query_stats, + Eq(base::ASCIIToUTF16("chrome...0")))))); // Open a search results page. Query extraction flag is disabled in field // trials. Search results page URL does not contain search terms replacement @@ -511,21 +540,5 @@ GURL url("https://www.google.com/url?bar=foo&aqs=chrome...0&ie=utf-8&oq=f"); browser()->instant_controller()->OpenInstant( WindowOpenDisposition::CURRENT_TAB, url); - content::MockRenderProcessHost* process = - static_cast<content::MockRenderProcessHost*>( - prerender_contents()->GetMainFrame()->GetProcess()); - const IPC::Message* message = process->sink().GetFirstMessageMatching( - ChromeViewMsg_SearchBoxSubmit::ID); - ASSERT_TRUE(message); - - // Verify the IPC message params. - std::tuple<base::string16, EmbeddedSearchRequestParams> params; - ChromeViewMsg_SearchBoxSubmit::Read(message, ¶ms); - EXPECT_EQ("foo", base::UTF16ToASCII(std::get<0>(params))); - EXPECT_EQ("f", base::UTF16ToASCII(std::get<1>(params).original_query)); - EXPECT_EQ("utf-8", base::UTF16ToASCII(std::get<1>(params).input_encoding)); - EXPECT_EQ("", base::UTF16ToASCII(std::get<1>(params).rlz_parameter_value)); - EXPECT_EQ("chrome...0", - base::UTF16ToASCII(std::get<1>(params).assisted_query_stats)); } #endif
diff --git a/chrome/browser/ui/search/instant_tab_unittest.cc b/chrome/browser/ui/search/instant_tab_unittest.cc index b417daf..8991f26 100644 --- a/chrome/browser/ui/search/instant_tab_unittest.cc +++ b/chrome/browser/ui/search/instant_tab_unittest.cc
@@ -9,9 +9,11 @@ #include <memory> #include "base/command_line.h" +#include "chrome/browser/ui/search/search_ipc_router.h" #include "chrome/browser/ui/search/search_tab_helper.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/render_messages.h" +#include "chrome/common/search/mock_searchbox.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "content/public/browser/navigation_controller.h" @@ -23,6 +25,8 @@ #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" +using testing::Return; + class Profile; namespace { @@ -36,8 +40,13 @@ void(const content::WebContents* contents, bool supports_instant)); MOCK_METHOD2(InstantTabAboutToNavigateMainFrame, - void(const content::WebContents* contents, - const GURL& url)); + void(const content::WebContents* contents, const GURL& url)); +}; + +class MockSearchBoxClientFactory + : public SearchIPCRouter::SearchBoxClientFactory { + public: + MOCK_METHOD0(GetSearchBox, chrome::mojom::SearchBox*(void)); }; } // namespace @@ -56,11 +65,17 @@ std::unique_ptr<InstantTab> page; FakePageDelegate delegate; + MockSearchBox mock_search_box; }; void InstantTabTest::SetUp() { ChromeRenderViewHostTestHarness::SetUp(); SearchTabHelper::CreateForWebContents(web_contents()); + auto factory = base::MakeUnique<MockSearchBoxClientFactory>(); + ON_CALL(*factory, GetSearchBox()).WillByDefault(Return(&mock_search_box)); + search_tab() + ->ipc_router_for_testing() + .set_search_box_client_factory_for_testing(std::move(factory)); } TEST_F(InstantTabTest, DetermineIfPageSupportsInstant_Local) { @@ -78,13 +93,8 @@ EXPECT_FALSE(SupportsInstant()); page->Init(); NavigateAndCommit(GURL("chrome-search://foo/bar")); - process()->sink().ClearMessages(); + EXPECT_CALL(mock_search_box, DetermineIfPageSupportsInstant()); search_tab()->DetermineIfPageSupportsInstant(); - const IPC::Message* message = process()->sink().GetFirstMessageMatching( - ChromeViewMsg_DetermineIfPageSupportsInstant::ID); - ASSERT_TRUE(message != NULL); - EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(), - message->routing_id()); } TEST_F(InstantTabTest, PageURLDoesntBelongToInstantRenderer) { @@ -97,13 +107,10 @@ // SearchTabHelper::DeterminerIfPageSupportsInstant() should return // immediately without dispatching any message to the renderer. NavigateAndCommit(GURL("http://www.example.com")); - process()->sink().ClearMessages(); EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), false)); + EXPECT_CALL(mock_search_box, DetermineIfPageSupportsInstant()).Times(0); search_tab()->DetermineIfPageSupportsInstant(); - const IPC::Message* message = process()->sink().GetFirstMessageMatching( - ChromeViewMsg_DetermineIfPageSupportsInstant::ID); - ASSERT_TRUE(message == NULL); EXPECT_FALSE(SupportsInstant()); } @@ -114,13 +121,8 @@ EXPECT_FALSE(SupportsInstant()); page->Init(); NavigateAndCommit(GURL("chrome-search://foo/bar")); - process()->sink().ClearMessages(); + EXPECT_CALL(mock_search_box, DetermineIfPageSupportsInstant()); search_tab()->DetermineIfPageSupportsInstant(); - const IPC::Message* message = process()->sink().GetFirstMessageMatching( - ChromeViewMsg_DetermineIfPageSupportsInstant::ID); - ASSERT_TRUE(message != NULL); - EXPECT_EQ(web_contents()->GetRenderViewHost()->GetRoutingID(), - message->routing_id()); EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), true));
diff --git a/chrome/browser/ui/search/search_ipc_router.cc b/chrome/browser/ui/search/search_ipc_router.cc index f57f188..2dcba5b 100644 --- a/chrome/browser/ui/search/search_ipc_router.cc +++ b/chrome/browser/ui/search/search_ipc_router.cc
@@ -11,7 +11,66 @@ #include "chrome/common/render_messages.h" #include "components/search/search.h" #include "content/public/browser/navigation_details.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/associated_interface_provider.h" +#include "content/public/common/child_process_host.h" + +namespace { + +bool IsRenderedInInstantProcess(content::WebContents* web_contents) { + // TODO(tibell): Instead of rejecting messages check at connection time if we + // want to talk to the render frame or not. Later, in an out-of-process iframe + // world, the IsRenderedInInstantProcess check will have to be done, as it's + // based on the RenderView. + Profile* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + return search::IsRenderedInInstantProcess(web_contents, profile); +} + +class SearchBoxClientFactoryImpl + : public SearchIPCRouter::SearchBoxClientFactory { + public: + // The |web_contents| must outlive this object. + explicit SearchBoxClientFactoryImpl(content::WebContents* web_contents) + : web_contents_(web_contents), + last_connected_rfh_( + std::make_pair(content::ChildProcessHost::kInvalidUniqueID, + MSG_ROUTING_NONE)) {} + chrome::mojom::SearchBox* GetSearchBox() override; + + private: + content::WebContents* web_contents_; + chrome::mojom::SearchBoxAssociatedPtr search_box_; + + // The proccess ID and routing ID of the last connected main frame. May be + // (ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE) if we haven't + // connected yet. + std::pair<int, int> last_connected_rfh_; + + DISALLOW_COPY_AND_ASSIGN(SearchBoxClientFactoryImpl); +}; + +chrome::mojom::SearchBox* SearchBoxClientFactoryImpl::GetSearchBox() { + content::RenderFrameHost* frame = web_contents_->GetMainFrame(); + auto id = std::make_pair(frame->GetProcess()->GetID(), frame->GetRoutingID()); + // Avoid reconnecting repeatedly to the same RenderFrameHost for performance + // reasons. + if (id != last_connected_rfh_) { + if (IsRenderedInInstantProcess(web_contents_)) { + frame->GetRemoteAssociatedInterfaces()->GetInterface(&search_box_); + } else { + // Renderer is not an instant process. We'll create a connection that + // drops all messages. + mojo::GetIsolatedProxy(&search_box_); + } + last_connected_rfh_ = id; + } + return search_box_.get(); +} + +} // namespace SearchIPCRouter::SearchIPCRouter(content::WebContents* web_contents, Delegate* delegate, @@ -20,7 +79,9 @@ delegate_(delegate), policy_(std::move(policy)), commit_counter_(0), - is_active_tab_(false) { + is_active_tab_(false), + bindings_(web_contents, this), + search_box_client_factory_(new SearchBoxClientFactoryImpl(web_contents)) { DCHECK(web_contents); DCHECK(delegate); DCHECK(policy_.get()); @@ -30,11 +91,11 @@ void SearchIPCRouter::OnNavigationEntryCommitted() { ++commit_counter_; - Send(new ChromeViewMsg_SetPageSequenceNumber(routing_id(), commit_counter_)); + search_box()->SetPageSequenceNumber(commit_counter_); } void SearchIPCRouter::DetermineIfPageSupportsInstant() { - Send(new ChromeViewMsg_DetermineIfPageSupportsInstant(routing_id())); + search_box()->DetermineIfPageSupportsInstant(); } void SearchIPCRouter::SendChromeIdentityCheckResult( @@ -43,15 +104,14 @@ if (!policy_->ShouldProcessChromeIdentityCheck()) return; - Send(new ChromeViewMsg_ChromeIdentityCheckResult(routing_id(), identity, - identity_match)); + search_box()->ChromeIdentityCheckResult(identity, identity_match); } void SearchIPCRouter::SendHistorySyncCheckResult(bool sync_history) { if (!policy_->ShouldProcessHistorySyncCheck()) return; - Send(new ChromeViewMsg_HistorySyncCheckResult(routing_id(), sync_history)); + search_box()->HistorySyncCheckResult(sync_history); } void SearchIPCRouter::SetSuggestionToPrefetch( @@ -59,16 +119,14 @@ if (!policy_->ShouldSendSetSuggestionToPrefetch()) return; - Send(new ChromeViewMsg_SearchBoxSetSuggestionToPrefetch(routing_id(), - suggestion)); + search_box()->SetSuggestionToPrefetch(suggestion); } void SearchIPCRouter::SetInputInProgress(bool input_in_progress) { if (!policy_->ShouldSendSetInputInProgress(is_active_tab_)) return; - Send(new ChromeViewMsg_SearchBoxSetInputInProgress(routing_id(), - input_in_progress)); + search_box()->SetInputInProgress(input_in_progress); } void SearchIPCRouter::OmniboxFocusChanged(OmniboxFocusState state, @@ -76,7 +134,7 @@ if (!policy_->ShouldSendOmniboxFocusChanged()) return; - Send(new ChromeViewMsg_SearchBoxFocusChanged(routing_id(), state, reason)); + search_box()->FocusChanged(state, reason); } void SearchIPCRouter::SendMostVisitedItems( @@ -84,7 +142,7 @@ if (!policy_->ShouldSendMostVisitedItems()) return; - Send(new ChromeViewMsg_SearchBoxMostVisitedItemsChanged(routing_id(), items)); + search_box()->MostVisitedChanged(items); } void SearchIPCRouter::SendThemeBackgroundInfo( @@ -92,7 +150,7 @@ if (!policy_->ShouldSendThemeBackgroundInfo()) return; - Send(new ChromeViewMsg_SearchBoxThemeChanged(routing_id(), theme_info)); + search_box()->ThemeChanged(theme_info); } void SearchIPCRouter::Submit(const base::string16& text, @@ -100,7 +158,7 @@ if (!policy_->ShouldSubmitQuery()) return; - Send(new ChromeViewMsg_SearchBoxSubmit(routing_id(), text, params)); + search_box()->Submit(text, params); } void SearchIPCRouter::OnTabActivated() { @@ -111,52 +169,19 @@ is_active_tab_ = false; } -bool SearchIPCRouter::OnMessageReceived(const IPC::Message& message) { - if (IPC_MESSAGE_CLASS(message) != ChromeMsgStart) - return false; - - Profile* profile = - Profile::FromBrowserContext(web_contents()->GetBrowserContext()); - if (!search::IsRenderedInInstantProcess(web_contents(), profile)) - return false; - - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(SearchIPCRouter, message) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_InstantSupportDetermined, - OnInstantSupportDetermined) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FocusOmnibox, OnFocusOmnibox); - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem, - OnDeleteMostVisitedItem); - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion, - OnUndoMostVisitedDeletion); - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions, - OnUndoAllMostVisitedDeletions); - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_LogEvent, OnLogEvent); - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_LogMostVisitedImpression, - OnLogMostVisitedImpression); - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_LogMostVisitedNavigation, - OnLogMostVisitedNavigation); - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PasteAndOpenDropdown, - OnPasteAndOpenDropDown); - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_HistorySyncCheck, - OnHistorySyncCheck); - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ChromeIdentityCheck, - OnChromeIdentityCheck); - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void SearchIPCRouter::OnInstantSupportDetermined(int page_seq_no, - bool instant_support) const { +void SearchIPCRouter::InstantSupportDetermined(int page_seq_no, + bool instant_support) { + if (!IsRenderedInInstantProcess(web_contents())) + return; if (page_seq_no != commit_counter_) return; delegate_->OnInstantSupportDetermined(instant_support); } -void SearchIPCRouter::OnFocusOmnibox(int page_seq_no, - OmniboxFocusState state) const { +void SearchIPCRouter::FocusOmnibox(int page_seq_no, OmniboxFocusState state) { + if (!IsRenderedInInstantProcess(web_contents())) + return; if (page_seq_no != commit_counter_) return; @@ -167,8 +192,10 @@ delegate_->FocusOmnibox(state); } -void SearchIPCRouter::OnDeleteMostVisitedItem(int page_seq_no, - const GURL& url) const { +void SearchIPCRouter::SearchBoxDeleteMostVisitedItem(int page_seq_no, + const GURL& url) { + if (!IsRenderedInInstantProcess(web_contents())) + return; if (page_seq_no != commit_counter_) return; @@ -179,8 +206,10 @@ delegate_->OnDeleteMostVisitedItem(url); } -void SearchIPCRouter::OnUndoMostVisitedDeletion(int page_seq_no, - const GURL& url) const { +void SearchIPCRouter::SearchBoxUndoMostVisitedDeletion(int page_seq_no, + const GURL& url) { + if (!IsRenderedInInstantProcess(web_contents())) + return; if (page_seq_no != commit_counter_) return; @@ -191,7 +220,9 @@ delegate_->OnUndoMostVisitedDeletion(url); } -void SearchIPCRouter::OnUndoAllMostVisitedDeletions(int page_seq_no) const { +void SearchIPCRouter::SearchBoxUndoAllMostVisitedDeletions(int page_seq_no) { + if (!IsRenderedInInstantProcess(web_contents())) + return; if (page_seq_no != commit_counter_) return; @@ -202,9 +233,11 @@ delegate_->OnUndoAllMostVisitedDeletions(); } -void SearchIPCRouter::OnLogEvent(int page_seq_no, - NTPLoggingEventType event, - base::TimeDelta time) const { +void SearchIPCRouter::LogEvent(int page_seq_no, + NTPLoggingEventType event, + base::TimeDelta time) { + if (!IsRenderedInInstantProcess(web_contents())) + return; if (page_seq_no != commit_counter_) return; @@ -215,10 +248,12 @@ delegate_->OnLogEvent(event, time); } -void SearchIPCRouter::OnLogMostVisitedImpression( +void SearchIPCRouter::LogMostVisitedImpression( int page_seq_no, int position, - ntp_tiles::NTPTileSource tile_source) const { + ntp_tiles::NTPTileSource tile_source) { + if (!IsRenderedInInstantProcess(web_contents())) + return; if (page_seq_no != commit_counter_) return; @@ -230,10 +265,12 @@ delegate_->OnLogMostVisitedImpression(position, tile_source); } -void SearchIPCRouter::OnLogMostVisitedNavigation( +void SearchIPCRouter::LogMostVisitedNavigation( int page_seq_no, int position, - ntp_tiles::NTPTileSource tile_source) const { + ntp_tiles::NTPTileSource tile_source) { + if (!IsRenderedInInstantProcess(web_contents())) + return; if (page_seq_no != commit_counter_) return; @@ -245,8 +282,10 @@ delegate_->OnLogMostVisitedNavigation(position, tile_source); } -void SearchIPCRouter::OnPasteAndOpenDropDown(int page_seq_no, - const base::string16& text) const { +void SearchIPCRouter::PasteAndOpenDropdown(int page_seq_no, + const base::string16& text) { + if (!IsRenderedInInstantProcess(web_contents())) + return; if (page_seq_no != commit_counter_) return; @@ -257,9 +296,10 @@ delegate_->PasteIntoOmnibox(text); } -void SearchIPCRouter::OnChromeIdentityCheck( - int page_seq_no, - const base::string16& identity) const { +void SearchIPCRouter::ChromeIdentityCheck(int page_seq_no, + const base::string16& identity) { + if (!IsRenderedInInstantProcess(web_contents())) + return; if (page_seq_no != commit_counter_) return; @@ -270,7 +310,9 @@ delegate_->OnChromeIdentityCheck(identity); } -void SearchIPCRouter::OnHistorySyncCheck(int page_seq_no) const { +void SearchIPCRouter::HistorySyncCheck(int page_seq_no) { + if (!IsRenderedInInstantProcess(web_contents())) + return; if (page_seq_no != commit_counter_) return;
diff --git a/chrome/browser/ui/search/search_ipc_router.h b/chrome/browser/ui/search/search_ipc_router.h index b878018..43398249 100644 --- a/chrome/browser/ui/search/search_ipc_router.h +++ b/chrome/browser/ui/search/search_ipc_router.h
@@ -11,10 +11,12 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/time/time.h" +#include "chrome/common/instant.mojom.h" #include "chrome/common/search/instant_types.h" #include "chrome/common/search/ntp_logging_events.h" #include "components/ntp_tiles/ntp_tile_source.h" #include "components/omnibox/common/omnibox_focus_state.h" +#include "content/public/browser/web_contents_binding_set.h" #include "content/public/browser/web_contents_observer.h" #include "ui/base/window_open_disposition.h" @@ -28,7 +30,8 @@ // SearchIPCRouter is responsible for receiving and sending IPC messages between // the browser and the Instant page. -class SearchIPCRouter : public content::WebContentsObserver { +class SearchIPCRouter : public content::WebContentsObserver, + public chrome::mojom::Instant { public: // SearchIPCRouter calls its delegate in response to messages received from // the page. @@ -109,6 +112,19 @@ virtual bool ShouldSubmitQuery() = 0; }; + // Creates chrome::mojom::SearchBox connections on request. + class SearchBoxClientFactory { + public: + SearchBoxClientFactory() = default; + virtual ~SearchBoxClientFactory() = default; + + // The returned pointer is owned by the factory. + virtual chrome::mojom::SearchBox* GetSearchBox() = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(SearchBoxClientFactory); + }; + SearchIPCRouter(content::WebContents* web_contents, Delegate* delegate, std::unique_ptr<Policy> policy); @@ -155,6 +171,35 @@ // Called when the tab corresponding to |this| instance is deactivated. void OnTabDeactivated(); + // chrome::mojom::Instant: + void InstantSupportDetermined(int page_seq_no, + bool supports_instant) override; + void FocusOmnibox(int page_id, OmniboxFocusState state) override; + void SearchBoxDeleteMostVisitedItem(int page_seq_no, + const GURL& url) override; + void SearchBoxUndoMostVisitedDeletion(int page_seq_no, + const GURL& url) override; + void SearchBoxUndoAllMostVisitedDeletions(int page_seq_no) override; + void LogEvent(int page_seq_no, + NTPLoggingEventType event, + base::TimeDelta time) override; + void LogMostVisitedImpression(int page_seq_no, + int position, + ntp_tiles::NTPTileSource tile_source) override; + void LogMostVisitedNavigation(int page_seq_no, + int position, + ntp_tiles::NTPTileSource tile_source) override; + void PasteAndOpenDropdown(int page_seq_no, + const base::string16& text) override; + void ChromeIdentityCheck(int page_seq_no, + const base::string16& identity) override; + void HistorySyncCheck(int page_seq_no) override; + + void set_search_box_client_factory_for_testing( + std::unique_ptr<SearchBoxClientFactory> factory) { + search_box_client_factory_ = std::move(factory); + } + private: friend class SearchIPCRouterPolicyTest; friend class SearchIPCRouterTest; @@ -168,29 +213,6 @@ IgnoreMessageIfThePageIsNotActive); FRIEND_TEST_ALL_PREFIXES(SearchIPCRouterTest, HandleTabChangedEvents); - // Overridden from contents::WebContentsObserver: - bool OnMessageReceived(const IPC::Message& message) override; - - void OnInstantSupportDetermined(int page_seq_no, bool supports_instant) const; - void OnFocusOmnibox(int page_id, OmniboxFocusState state) const; - void OnDeleteMostVisitedItem(int page_seq_no, const GURL& url) const; - void OnUndoMostVisitedDeletion(int page_seq_no, const GURL& url) const; - void OnUndoAllMostVisitedDeletions(int page_seq_no) const; - void OnLogEvent(int page_seq_no, - NTPLoggingEventType event, - base::TimeDelta time) const; - void OnLogMostVisitedImpression(int page_seq_no, - int position, - ntp_tiles::NTPTileSource tile_source) const; - void OnLogMostVisitedNavigation(int page_seq_no, - int position, - ntp_tiles::NTPTileSource tile_source) const; - void OnPasteAndOpenDropDown(int page_seq_no, - const base::string16& text) const; - void OnChromeIdentityCheck(int page_seq_no, - const base::string16& identity) const; - void OnHistorySyncCheck(int page_seq_no) const; - // Used by unit tests to set a fake delegate. void set_delegate_for_testing(Delegate* delegate); @@ -203,6 +225,10 @@ // Used by unit tests. int page_seq_no_for_testing() const { return commit_counter_; } + chrome::mojom::SearchBox* search_box() { + return search_box_client_factory_->GetSearchBox(); + } + Delegate* delegate_; std::unique_ptr<Policy> policy_; @@ -213,6 +239,10 @@ // Set to true, when the tab corresponding to |this| instance is active. bool is_active_tab_; + content::WebContentsFrameBindingSet<chrome::mojom::Instant> bindings_; + + std::unique_ptr<SearchBoxClientFactory> search_box_client_factory_; + DISALLOW_COPY_AND_ASSIGN(SearchIPCRouter); };
diff --git a/chrome/browser/ui/search/search_ipc_router_policy_unittest.cc b/chrome/browser/ui/search/search_ipc_router_policy_unittest.cc index 8d52521a..ba6b7ef 100644 --- a/chrome/browser/ui/search/search_ipc_router_policy_unittest.cc +++ b/chrome/browser/ui/search/search_ipc_router_policy_unittest.cc
@@ -31,7 +31,7 @@ SearchTabHelper* search_tab_helper = SearchTabHelper::FromWebContents(web_contents()); EXPECT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper); - return search_tab_helper->ipc_router().policy_for_testing(); + return search_tab_helper->ipc_router_for_testing().policy_for_testing(); } void SetIncognitoProfile() {
diff --git a/chrome/browser/ui/search/search_ipc_router_unittest.cc b/chrome/browser/ui/search/search_ipc_router_unittest.cc index 6b183c0d..bb7db73 100644 --- a/chrome/browser/ui/search/search_ipc_router_unittest.cc +++ b/chrome/browser/ui/search/search_ipc_router_unittest.cc
@@ -24,6 +24,7 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/render_messages.h" #include "chrome/common/search/instant_types.h" +#include "chrome/common/search/mock_searchbox.h" #include "chrome/common/search/ntp_logging_events.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/browser_with_test_window_test.h" @@ -42,6 +43,9 @@ #include "ui/base/window_open_disposition.h" #include "url/gurl.h" +using testing::_; +using testing::Return; + namespace { class MockSearchIPCRouterDelegate : public SearchIPCRouter::Delegate { @@ -84,6 +88,12 @@ MOCK_METHOD0(ShouldSubmitQuery, bool()); }; +class MockSearchBoxClientFactory + : public SearchIPCRouter::SearchBoxClientFactory { + public: + MOCK_METHOD0(GetSearchBox, chrome::mojom::SearchBox*(void)); +}; + } // namespace class SearchIPCRouterTest : public BrowserWithTestWindowTest { @@ -113,18 +123,12 @@ TemplateURL* template_url = template_url_service->Add(base::MakeUnique<TemplateURL>(data)); template_url_service->SetUserSelectedDefaultSearchProvider(template_url); - process()->sink().ClearMessages(); } content::WebContents* web_contents() { return browser()->tab_strip_model()->GetActiveWebContents(); } - content::MockRenderProcessHost* process() { - return static_cast<content::MockRenderProcessHost*>( - web_contents()->GetMainFrame()->GetProcess()); - } - SearchTabHelper* GetSearchTabHelper( content::WebContents* web_contents) { EXPECT_NE(static_cast<content::WebContents*>(NULL), web_contents); @@ -136,13 +140,14 @@ ASSERT_NE(static_cast<content::WebContents*>(NULL), contents); SearchTabHelper* search_tab_helper = GetSearchTabHelper(contents); ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper); - search_tab_helper->ipc_router().set_delegate_for_testing(mock_delegate()); - search_tab_helper->ipc_router().set_policy_for_testing( + search_tab_helper->ipc_router_for_testing().set_delegate_for_testing( + mock_delegate()); + search_tab_helper->ipc_router_for_testing().set_policy_for_testing( base::WrapUnique(new MockSearchIPCRouterPolicy)); - } - - bool MessageWasSent(uint32_t id) { - return process()->sink().GetFirstMessageMatching(id) != NULL; + auto factory = base::MakeUnique<MockSearchBoxClientFactory>(); + ON_CALL(*factory, GetSearchBox()).WillByDefault(Return(&mock_search_box_)); + GetSearchIPCRouter().set_search_box_client_factory_for_testing( + std::move(factory)); } MockSearchIPCRouterDelegate* mock_delegate() { return &delegate_; } @@ -153,35 +158,29 @@ SearchTabHelper* search_tab_helper = GetSearchTabHelper(contents); EXPECT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper); return static_cast<MockSearchIPCRouterPolicy*>( - search_tab_helper->ipc_router().policy_for_testing()); + search_tab_helper->ipc_router_for_testing().policy_for_testing()); } SearchIPCRouter& GetSearchIPCRouter() { - return GetSearchTabHelper(web_contents())->ipc_router(); + return GetSearchTabHelper(web_contents())->ipc_router_for_testing(); } int GetSearchIPCRouterSeqNo() { return GetSearchIPCRouter().page_seq_no_for_testing(); } - void OnMessageReceived(const IPC::Message& message) { - bool should_handle_message = - search::IsRenderedInInstantProcess(web_contents(), profile()); - bool handled = GetSearchIPCRouter().OnMessageReceived(message); - ASSERT_EQ(should_handle_message, handled); - } - - bool OnSpuriousMessageReceived(const IPC::Message& message) { - return GetSearchIPCRouter().OnMessageReceived(message); - } - bool IsActiveTab(content::WebContents* contents) { - return GetSearchTabHelper(contents)->ipc_router().is_active_tab_; + return GetSearchTabHelper(contents) + ->ipc_router_for_testing() + .is_active_tab_; } + MockSearchBox* mock_search_box() { return &mock_search_box_; } + private: MockSearchIPCRouterDelegate delegate_; base::FieldTrialList field_trial_list_; + MockSearchBox mock_search_box_; }; TEST_F(SearchIPCRouterTest, IgnoreMessagesFromNonInstantRenderers) { @@ -195,9 +194,8 @@ MockSearchIPCRouterPolicy* policy = GetSearchIPCRouterPolicy(); EXPECT_CALL(*policy, ShouldProcessFocusOmnibox(is_active_tab)).Times(0); - OnMessageReceived(ChromeViewHostMsg_FocusOmnibox( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - OMNIBOX_FOCUS_VISIBLE)); + GetSearchIPCRouter().FocusOmnibox(GetSearchIPCRouterSeqNo(), + OMNIBOX_FOCUS_VISIBLE); } TEST_F(SearchIPCRouterTest, ProcessFocusOmniboxMsg) { @@ -212,9 +210,8 @@ EXPECT_CALL(*policy, ShouldProcessFocusOmnibox(is_active_tab)).Times(1) .WillOnce(testing::Return(true)); - OnMessageReceived(ChromeViewHostMsg_FocusOmnibox( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - OMNIBOX_FOCUS_VISIBLE)); + GetSearchIPCRouter().FocusOmnibox(GetSearchIPCRouterSeqNo(), + OMNIBOX_FOCUS_VISIBLE); } TEST_F(SearchIPCRouterTest, IgnoreFocusOmniboxMsg) { @@ -229,9 +226,8 @@ EXPECT_CALL(*policy, ShouldProcessFocusOmnibox(is_active_tab)).Times(1) .WillOnce(testing::Return(false)); - OnMessageReceived(ChromeViewHostMsg_FocusOmnibox( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - OMNIBOX_FOCUS_VISIBLE)); + GetSearchIPCRouter().FocusOmnibox(GetSearchIPCRouterSeqNo(), + OMNIBOX_FOCUS_VISIBLE); } TEST_F(SearchIPCRouterTest, HandleTabChangedEvents) { @@ -264,10 +260,8 @@ EXPECT_CALL(*policy, ShouldProcessLogEvent()).Times(1) .WillOnce(testing::Return(true)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_LogEvent( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - NTP_ALL_TILES_LOADED, delta)); + GetSearchIPCRouter().LogEvent(GetSearchIPCRouterSeqNo(), NTP_ALL_TILES_LOADED, + delta); } TEST_F(SearchIPCRouterTest, IgnoreLogEventMsg) { @@ -280,10 +274,8 @@ EXPECT_CALL(*policy, ShouldProcessLogEvent()).Times(1) .WillOnce(testing::Return(false)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_LogEvent( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - NTP_ALL_TILES_LOADED, delta)); + GetSearchIPCRouter().LogEvent(GetSearchIPCRouterSeqNo(), NTP_ALL_TILES_LOADED, + delta); } TEST_F(SearchIPCRouterTest, ProcessLogMostVisitedImpressionMsg) { @@ -297,10 +289,9 @@ EXPECT_CALL(*policy, ShouldProcessLogEvent()).Times(1) .WillOnce(testing::Return(true)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_LogMostVisitedImpression( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - 3, ntp_tiles::NTPTileSource::SUGGESTIONS_SERVICE)); + GetSearchIPCRouter().LogMostVisitedImpression( + GetSearchIPCRouterSeqNo(), 3, + ntp_tiles::NTPTileSource::SUGGESTIONS_SERVICE); } TEST_F(SearchIPCRouterTest, ProcessLogMostVisitedNavigationMsg) { @@ -314,10 +305,9 @@ EXPECT_CALL(*policy, ShouldProcessLogEvent()).Times(1) .WillOnce(testing::Return(true)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_LogMostVisitedNavigation( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - 3, ntp_tiles::NTPTileSource::SUGGESTIONS_SERVICE)); + GetSearchIPCRouter().LogMostVisitedNavigation( + GetSearchIPCRouterSeqNo(), 3, + ntp_tiles::NTPTileSource::SUGGESTIONS_SERVICE); } TEST_F(SearchIPCRouterTest, ProcessChromeIdentityCheckMsg) { @@ -329,10 +319,8 @@ EXPECT_CALL(*policy, ShouldProcessChromeIdentityCheck()).Times(1) .WillOnce(testing::Return(true)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_ChromeIdentityCheck( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - test_identity)); + GetSearchIPCRouter().ChromeIdentityCheck(GetSearchIPCRouterSeqNo(), + test_identity); } TEST_F(SearchIPCRouterTest, IgnoreChromeIdentityCheckMsg) { @@ -345,10 +333,8 @@ EXPECT_CALL(*policy, ShouldProcessChromeIdentityCheck()).Times(1) .WillOnce(testing::Return(false)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_ChromeIdentityCheck( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - test_identity)); + GetSearchIPCRouter().ChromeIdentityCheck(GetSearchIPCRouterSeqNo(), + test_identity); } TEST_F(SearchIPCRouterTest, ProcessHistorySyncCheckMsg) { @@ -359,10 +345,7 @@ EXPECT_CALL(*policy, ShouldProcessHistorySyncCheck()).Times(1) .WillOnce(testing::Return(true)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_HistorySyncCheck( - contents->GetRenderViewHost()->GetRoutingID(), - GetSearchIPCRouterSeqNo())); + GetSearchIPCRouter().HistorySyncCheck(GetSearchIPCRouterSeqNo()); } TEST_F(SearchIPCRouterTest, IgnoreHistorySyncCheckMsg) { @@ -374,10 +357,7 @@ EXPECT_CALL(*policy, ShouldProcessHistorySyncCheck()).Times(1) .WillOnce(testing::Return(false)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_HistorySyncCheck( - contents->GetRenderViewHost()->GetRoutingID(), - GetSearchIPCRouterSeqNo())); + GetSearchIPCRouter().HistorySyncCheck(GetSearchIPCRouterSeqNo()); } TEST_F(SearchIPCRouterTest, ProcessDeleteMostVisitedItemMsg) { @@ -389,10 +369,8 @@ EXPECT_CALL(*policy, ShouldProcessDeleteMostVisitedItem()).Times(1) .WillOnce(testing::Return(true)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - item_url)); + GetSearchIPCRouter().SearchBoxDeleteMostVisitedItem(GetSearchIPCRouterSeqNo(), + item_url); } TEST_F(SearchIPCRouterTest, IgnoreDeleteMostVisitedItemMsg) { @@ -404,10 +382,8 @@ EXPECT_CALL(*policy, ShouldProcessDeleteMostVisitedItem()).Times(1) .WillOnce(testing::Return(false)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - item_url)); + GetSearchIPCRouter().SearchBoxDeleteMostVisitedItem(GetSearchIPCRouterSeqNo(), + item_url); } TEST_F(SearchIPCRouterTest, ProcessUndoMostVisitedDeletionMsg) { @@ -419,10 +395,8 @@ EXPECT_CALL(*policy, ShouldProcessUndoMostVisitedDeletion()).Times(1) .WillOnce(testing::Return(true)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - item_url)); + GetSearchIPCRouter().SearchBoxUndoMostVisitedDeletion( + GetSearchIPCRouterSeqNo(), item_url); } TEST_F(SearchIPCRouterTest, IgnoreUndoMostVisitedDeletionMsg) { @@ -434,10 +408,8 @@ EXPECT_CALL(*policy, ShouldProcessUndoMostVisitedDeletion()).Times(1) .WillOnce(testing::Return(false)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - item_url)); + GetSearchIPCRouter().SearchBoxUndoMostVisitedDeletion( + GetSearchIPCRouterSeqNo(), item_url); } TEST_F(SearchIPCRouterTest, ProcessUndoAllMostVisitedDeletionsMsg) { @@ -448,10 +420,8 @@ EXPECT_CALL(*policy, ShouldProcessUndoAllMostVisitedDeletions()).Times(1) .WillOnce(testing::Return(true)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions( - contents->GetRenderViewHost()->GetRoutingID(), - GetSearchIPCRouterSeqNo())); + GetSearchIPCRouter().SearchBoxUndoAllMostVisitedDeletions( + GetSearchIPCRouterSeqNo()); } TEST_F(SearchIPCRouterTest, IgnoreUndoAllMostVisitedDeletionsMsg) { @@ -462,10 +432,8 @@ EXPECT_CALL(*policy, ShouldProcessUndoAllMostVisitedDeletions()).Times(1) .WillOnce(testing::Return(false)); - content::WebContents* contents = web_contents(); - OnMessageReceived(ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions( - contents->GetRenderViewHost()->GetRoutingID(), - GetSearchIPCRouterSeqNo())); + GetSearchIPCRouter().SearchBoxUndoAllMostVisitedDeletions( + GetSearchIPCRouterSeqNo()); } TEST_F(SearchIPCRouterTest, IgnoreMessageIfThePageIsNotActive) { @@ -483,38 +451,30 @@ EXPECT_CALL(*mock_delegate(), OnDeleteMostVisitedItem(item_url)).Times(0); EXPECT_CALL(*policy, ShouldProcessDeleteMostVisitedItem()).Times(0); - OnMessageReceived(ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem( - contents->GetRenderViewHost()->GetRoutingID(), page_seq_no, item_url)); + GetSearchIPCRouter().SearchBoxDeleteMostVisitedItem(page_seq_no, item_url); EXPECT_CALL(*mock_delegate(), OnUndoMostVisitedDeletion(item_url)).Times(0); EXPECT_CALL(*policy, ShouldProcessUndoMostVisitedDeletion()).Times(0); - OnMessageReceived(ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion( - contents->GetRenderViewHost()->GetRoutingID(), page_seq_no, item_url)); + GetSearchIPCRouter().SearchBoxUndoMostVisitedDeletion(page_seq_no, item_url); EXPECT_CALL(*mock_delegate(), OnUndoAllMostVisitedDeletions()).Times(0); EXPECT_CALL(*policy, ShouldProcessUndoAllMostVisitedDeletions()).Times(0); - OnMessageReceived(ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions( - contents->GetRenderViewHost()->GetRoutingID(), page_seq_no)); + GetSearchIPCRouter().SearchBoxUndoAllMostVisitedDeletions(page_seq_no); EXPECT_CALL(*mock_delegate(), FocusOmnibox(OMNIBOX_FOCUS_VISIBLE)).Times(0); EXPECT_CALL(*policy, ShouldProcessFocusOmnibox(is_active_tab)).Times(0); - OnMessageReceived(ChromeViewHostMsg_FocusOmnibox( - contents->GetRenderViewHost()->GetRoutingID(), page_seq_no, - OMNIBOX_FOCUS_VISIBLE)); + GetSearchIPCRouter().FocusOmnibox(page_seq_no, OMNIBOX_FOCUS_VISIBLE); base::TimeDelta delta = base::TimeDelta::FromMilliseconds(123); EXPECT_CALL(*mock_delegate(), OnLogEvent(NTP_ALL_TILES_LOADED, delta)) .Times(0); EXPECT_CALL(*policy, ShouldProcessLogEvent()).Times(0); - OnMessageReceived( - ChromeViewHostMsg_LogEvent(contents->GetRenderViewHost()->GetRoutingID(), - page_seq_no, NTP_ALL_TILES_LOADED, delta)); + GetSearchIPCRouter().LogEvent(page_seq_no, NTP_ALL_TILES_LOADED, delta); base::string16 text; EXPECT_CALL(*mock_delegate(), PasteIntoOmnibox(text)).Times(0); EXPECT_CALL(*policy, ShouldProcessPasteIntoOmnibox(is_active_tab)).Times(0); - OnMessageReceived(ChromeViewHostMsg_PasteAndOpenDropdown( - contents->GetRenderViewHost()->GetRoutingID(), page_seq_no, text)); + GetSearchIPCRouter().PasteAndOpenDropdown(page_seq_no, text); } TEST_F(SearchIPCRouterTest, ProcessPasteAndOpenDropdownMsg) { @@ -530,9 +490,7 @@ EXPECT_CALL(*mock_delegate(), PasteIntoOmnibox(text)).Times(1); EXPECT_CALL(*policy, ShouldProcessPasteIntoOmnibox(is_active_tab)).Times(1) .WillOnce(testing::Return(true)); - OnMessageReceived(ChromeViewHostMsg_PasteAndOpenDropdown( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - text)); + GetSearchIPCRouter().PasteAndOpenDropdown(GetSearchIPCRouterSeqNo(), text); } TEST_F(SearchIPCRouterTest, IgnorePasteAndOpenDropdownMsg) { @@ -549,9 +507,7 @@ EXPECT_CALL(*policy, ShouldProcessPasteIntoOmnibox(is_active_tab)).Times(1) .WillOnce(testing::Return(false)); - OnMessageReceived(ChromeViewHostMsg_PasteAndOpenDropdown( - contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - text)); + GetSearchIPCRouter().PasteAndOpenDropdown(GetSearchIPCRouterSeqNo(), text); } TEST_F(SearchIPCRouterTest, SendSetSuggestionToPrefetch) { @@ -561,11 +517,9 @@ EXPECT_CALL(*policy, ShouldSendSetSuggestionToPrefetch()).Times(1) .WillOnce(testing::Return(true)); - process()->sink().ClearMessages(); content::WebContents* contents = web_contents(); + EXPECT_CALL(*mock_search_box(), SetSuggestionToPrefetch(_)); GetSearchTabHelper(contents)->SetSuggestionToPrefetch(InstantSuggestion()); - EXPECT_TRUE(MessageWasSent( - ChromeViewMsg_SearchBoxSetSuggestionToPrefetch::ID)); } TEST_F(SearchIPCRouterTest, DoNotSendSetSuggestionToPrefetch) { @@ -575,11 +529,9 @@ EXPECT_CALL(*policy, ShouldSendSetSuggestionToPrefetch()).Times(1) .WillOnce(testing::Return(false)); - process()->sink().ClearMessages(); content::WebContents* contents = web_contents(); + EXPECT_CALL(*mock_search_box(), SetSuggestionToPrefetch(_)).Times(0); GetSearchTabHelper(contents)->SetSuggestionToPrefetch(InstantSuggestion()); - EXPECT_FALSE(MessageWasSent( - ChromeViewMsg_SearchBoxSetSuggestionToPrefetch::ID)); } TEST_F(SearchIPCRouterTest, SendOmniboxFocusChange) { @@ -589,10 +541,9 @@ EXPECT_CALL(*policy, ShouldSendOmniboxFocusChanged()).Times(1) .WillOnce(testing::Return(true)); - process()->sink().ClearMessages(); + EXPECT_CALL(*mock_search_box(), FocusChanged(_, _)); GetSearchIPCRouter().OmniboxFocusChanged(OMNIBOX_FOCUS_NONE, OMNIBOX_FOCUS_CHANGE_EXPLICIT); - EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxFocusChanged::ID)); } TEST_F(SearchIPCRouterTest, DoNotSendOmniboxFocusChange) { @@ -602,10 +553,9 @@ EXPECT_CALL(*policy, ShouldSendOmniboxFocusChanged()).Times(1) .WillOnce(testing::Return(false)); - process()->sink().ClearMessages(); + EXPECT_CALL(*mock_search_box(), FocusChanged(_, _)).Times(0); GetSearchIPCRouter().OmniboxFocusChanged(OMNIBOX_FOCUS_NONE, OMNIBOX_FOCUS_CHANGE_EXPLICIT); - EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxFocusChanged::ID)); } TEST_F(SearchIPCRouterTest, SendSetInputInProgress) { @@ -615,9 +565,8 @@ EXPECT_CALL(*policy, ShouldSendSetInputInProgress(true)).Times(1) .WillOnce(testing::Return(true)); - process()->sink().ClearMessages(); + EXPECT_CALL(*mock_search_box(), SetInputInProgress(_)); GetSearchIPCRouter().SetInputInProgress(true); - EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxSetInputInProgress::ID)); } TEST_F(SearchIPCRouterTest, DoNotSendSetInputInProgress) { @@ -627,9 +576,8 @@ EXPECT_CALL(*policy, ShouldSendSetInputInProgress(true)).Times(1) .WillOnce(testing::Return(false)); - process()->sink().ClearMessages(); + EXPECT_CALL(*mock_search_box(), SetInputInProgress(_)).Times(0); GetSearchIPCRouter().SetInputInProgress(true); - EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxSetInputInProgress::ID)); } TEST_F(SearchIPCRouterTest, SendMostVisitedItemsMsg) { @@ -639,11 +587,9 @@ EXPECT_CALL(*policy, ShouldSendMostVisitedItems()).Times(1) .WillOnce(testing::Return(true)); - process()->sink().ClearMessages(); + EXPECT_CALL(*mock_search_box(), MostVisitedChanged(_)); GetSearchIPCRouter().SendMostVisitedItems( std::vector<InstantMostVisitedItem>()); - EXPECT_TRUE(MessageWasSent( - ChromeViewMsg_SearchBoxMostVisitedItemsChanged::ID)); } TEST_F(SearchIPCRouterTest, DoNotSendMostVisitedItemsMsg) { @@ -653,11 +599,9 @@ EXPECT_CALL(*policy, ShouldSendMostVisitedItems()).Times(1) .WillOnce(testing::Return(false)); - process()->sink().ClearMessages(); + EXPECT_CALL(*mock_search_box(), MostVisitedChanged(_)).Times(0); GetSearchIPCRouter().SendMostVisitedItems( std::vector<InstantMostVisitedItem>()); - EXPECT_FALSE(MessageWasSent( - ChromeViewMsg_SearchBoxMostVisitedItemsChanged::ID)); } TEST_F(SearchIPCRouterTest, SendThemeBackgroundInfoMsg) { @@ -667,9 +611,8 @@ EXPECT_CALL(*policy, ShouldSendThemeBackgroundInfo()).Times(1) .WillOnce(testing::Return(true)); - process()->sink().ClearMessages(); + EXPECT_CALL(*mock_search_box(), ThemeChanged(_)); GetSearchIPCRouter().SendThemeBackgroundInfo(ThemeBackgroundInfo()); - EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxThemeChanged::ID)); } TEST_F(SearchIPCRouterTest, DoNotSendThemeBackgroundInfoMsg) { @@ -679,9 +622,8 @@ EXPECT_CALL(*policy, ShouldSendThemeBackgroundInfo()).Times(1) .WillOnce(testing::Return(false)); - process()->sink().ClearMessages(); + EXPECT_CALL(*mock_search_box(), ThemeChanged(_)).Times(0); GetSearchIPCRouter().SendThemeBackgroundInfo(ThemeBackgroundInfo()); - EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxThemeChanged::ID)); } TEST_F(SearchIPCRouterTest, SendSubmitMsg) { @@ -691,9 +633,8 @@ EXPECT_CALL(*policy, ShouldSubmitQuery()).Times(1) .WillOnce(testing::Return(true)); - process()->sink().ClearMessages(); + EXPECT_CALL(*mock_search_box(), Submit(_, _)); GetSearchIPCRouter().Submit(base::string16(), EmbeddedSearchRequestParams()); - EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxSubmit::ID)); } TEST_F(SearchIPCRouterTest, DoNotSendSubmitMsg) { @@ -703,22 +644,6 @@ EXPECT_CALL(*policy, ShouldSubmitQuery()).Times(1) .WillOnce(testing::Return(false)); - process()->sink().ClearMessages(); + EXPECT_CALL(*mock_search_box(), Submit(_, _)).Times(0); GetSearchIPCRouter().Submit(base::string16(), EmbeddedSearchRequestParams()); - EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxSubmit::ID)); -} - -TEST_F(SearchIPCRouterTest, SpuriousMessageTypesIgnored) { - NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar")); - SetupMockDelegateAndPolicy(); - const int routing_id = web_contents()->GetRenderViewHost()->GetRoutingID(); - - // Construct a series of synthetic messages for each valid IPC message type, - // ensuring the router ignores them all. - for (int i = 0; i < LastIPCMsgStart; ++i) { - const int message_id = i << 16; - ASSERT_EQ(IPC_MESSAGE_ID_CLASS(message_id), i); - IPC::Message msg(routing_id, message_id, IPC::Message::PRIORITY_LOW); - EXPECT_FALSE(OnSpuriousMessageReceived(msg)) << i; - } }
diff --git a/chrome/browser/ui/search/search_tab_helper.h b/chrome/browser/ui/search/search_tab_helper.h index 35c9ee7..96c5add 100644 --- a/chrome/browser/ui/search/search_tab_helper.h +++ b/chrome/browser/ui/search/search_tab_helper.h
@@ -83,6 +83,8 @@ void set_delegate(SearchTabHelperDelegate* delegate) { delegate_ = delegate; } + SearchIPCRouter& ipc_router_for_testing() { return ipc_router_; } + private: friend class content::WebContentsUserData<SearchTabHelper>; friend class SearchIPCRouterPolicyTest; @@ -167,9 +169,6 @@ // received. void DetermineIfPageSupportsInstant(); - // Used by unit tests. - SearchIPCRouter& ipc_router() { return ipc_router_; } - Profile* profile() const; // Returns whether input is in progress, i.e. if the omnibox has focus and the
diff --git a/chrome/browser/ui/search/search_tab_helper_unittest.cc b/chrome/browser/ui/search/search_tab_helper_unittest.cc index 231f650..6c6cd0d 100644 --- a/chrome/browser/ui/search/search_tab_helper_unittest.cc +++ b/chrome/browser/ui/search/search_tab_helper_unittest.cc
@@ -19,6 +19,7 @@ #include "chrome/browser/ui/search/search_ipc_router.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/render_messages.h" +#include "chrome/common/search/mock_searchbox.h" #include "chrome/common/url_constants.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/browser_with_test_window_test.h" @@ -41,7 +42,9 @@ class OmniboxView; +using testing::Eq; using testing::Return; +using testing::_; namespace { @@ -66,13 +69,26 @@ MOCK_METHOD0(OnHistorySyncCheck, void()); }; +class MockSearchBoxClientFactory + : public SearchIPCRouter::SearchBoxClientFactory { + public: + MOCK_METHOD0(GetSearchBox, chrome::mojom::SearchBox*(void)); +}; + } // namespace class SearchTabHelperTest : public ChromeRenderViewHostTestHarness { public: + SearchTabHelperTest() {} + void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); SearchTabHelper::CreateForWebContents(web_contents()); + auto search_tab = SearchTabHelper::FromWebContents(web_contents()); + auto factory = base::MakeUnique<MockSearchBoxClientFactory>(); + ON_CALL(*factory, GetSearchBox()).WillByDefault(Return(&mock_search_box_)); + search_tab->ipc_router_for_testing() + .set_search_box_client_factory_for_testing(std::move(factory)); } content::BrowserContext* CreateBrowserContext() override { @@ -110,14 +126,13 @@ .WillRepeatedly(Return(result)); } - bool MessageWasSent(uint32_t id) { - return process()->sink().GetFirstMessageMatching(id) != NULL; - } - MockSearchIPCRouterDelegate* mock_delegate() { return &delegate_; } + MockSearchBox* mock_search_box() { return &mock_search_box_; } + private: MockSearchIPCRouterDelegate delegate_; + MockSearchBox mock_search_box_; }; TEST_F(SearchTabHelperTest, DetermineIfPageSupportsInstant_Local) { @@ -127,27 +142,26 @@ SearchTabHelper* search_tab_helper = SearchTabHelper::FromWebContents(web_contents()); ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper); - search_tab_helper->ipc_router().set_delegate_for_testing(mock_delegate()); + search_tab_helper->ipc_router_for_testing().set_delegate_for_testing( + mock_delegate()); search_tab_helper->DetermineIfPageSupportsInstant(); } TEST_F(SearchTabHelperTest, DetermineIfPageSupportsInstant_NonLocal) { NavigateAndCommit(GURL("chrome-search://foo/bar")); - process()->sink().ClearMessages(); EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(true)).Times(1); SearchTabHelper* search_tab_helper = SearchTabHelper::FromWebContents(web_contents()); ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper); - search_tab_helper->ipc_router().set_delegate_for_testing(mock_delegate()); + search_tab_helper->ipc_router_for_testing().set_delegate_for_testing( + mock_delegate()); + EXPECT_CALL(*mock_search_box(), DetermineIfPageSupportsInstant()); search_tab_helper->DetermineIfPageSupportsInstant(); - ASSERT_TRUE(MessageWasSent(ChromeViewMsg_DetermineIfPageSupportsInstant::ID)); - std::unique_ptr<IPC::Message> response( - new ChromeViewHostMsg_InstantSupportDetermined( - web_contents()->GetRenderViewHost()->GetRoutingID(), - search_tab_helper->ipc_router().page_seq_no_for_testing(), true)); - search_tab_helper->ipc_router().OnMessageReceived(*response); + search_tab_helper->ipc_router_for_testing().InstantSupportDetermined( + search_tab_helper->ipc_router_for_testing().page_seq_no_for_testing(), + true); } TEST_F(SearchTabHelperTest, PageURLDoesntBelongToInstantRenderer) { @@ -155,16 +169,15 @@ // SearchTabHelper::DeterminerIfPageSupportsInstant() should return // immediately without dispatching any message to the renderer. NavigateAndCommit(GURL("http://www.example.com")); - process()->sink().ClearMessages(); EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(false)).Times(0); SearchTabHelper* search_tab_helper = SearchTabHelper::FromWebContents(web_contents()); ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper); - search_tab_helper->ipc_router().set_delegate_for_testing(mock_delegate()); + search_tab_helper->ipc_router_for_testing().set_delegate_for_testing( + mock_delegate()); + EXPECT_CALL(*mock_search_box(), DetermineIfPageSupportsInstant()).Times(0); search_tab_helper->DetermineIfPageSupportsInstant(); - ASSERT_FALSE(MessageWasSent( - ChromeViewMsg_DetermineIfPageSupportsInstant::ID)); } TEST_F(SearchTabHelperTest, OnChromeIdentityCheckMatch) { @@ -175,16 +188,9 @@ ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper); const base::string16 test_identity = base::ASCIIToUTF16("foo@bar.com"); + EXPECT_CALL(*mock_search_box(), + ChromeIdentityCheckResult(Eq(test_identity), true)); search_tab_helper->OnChromeIdentityCheck(test_identity); - - const IPC::Message* message = process()->sink().GetUniqueMessageMatching( - ChromeViewMsg_ChromeIdentityCheckResult::ID); - ASSERT_TRUE(message != NULL); - - ChromeViewMsg_ChromeIdentityCheckResult::Param params; - ChromeViewMsg_ChromeIdentityCheckResult::Read(message, ¶ms); - EXPECT_EQ(test_identity, std::get<0>(params)); - ASSERT_TRUE(std::get<1>(params)); } TEST_F(SearchTabHelperTest, OnChromeIdentityCheckMatchSlightlyDifferentGmail) { @@ -198,16 +204,9 @@ // standard form. const base::string16 test_identity = base::ASCIIToUTF16("Foo.Bar.123@gmail.com"); + EXPECT_CALL(*mock_search_box(), + ChromeIdentityCheckResult(Eq(test_identity), true)); search_tab_helper->OnChromeIdentityCheck(test_identity); - - const IPC::Message* message = process()->sink().GetUniqueMessageMatching( - ChromeViewMsg_ChromeIdentityCheckResult::ID); - ASSERT_TRUE(message != NULL); - - ChromeViewMsg_ChromeIdentityCheckResult::Param params; - ChromeViewMsg_ChromeIdentityCheckResult::Read(message, ¶ms); - EXPECT_EQ(test_identity, std::get<0>(params)); - ASSERT_TRUE(std::get<1>(params)); } TEST_F(SearchTabHelperTest, OnChromeIdentityCheckMatchSlightlyDifferentGmail2) { @@ -222,16 +221,9 @@ // a standard form. const base::string16 test_identity = base::ASCIIToUTF16("chromeuser7forever@googlemail.com"); + EXPECT_CALL(*mock_search_box(), + ChromeIdentityCheckResult(Eq(test_identity), true)); search_tab_helper->OnChromeIdentityCheck(test_identity); - - const IPC::Message* message = process()->sink().GetUniqueMessageMatching( - ChromeViewMsg_ChromeIdentityCheckResult::ID); - ASSERT_TRUE(message != NULL); - - ChromeViewMsg_ChromeIdentityCheckResult::Param params; - ChromeViewMsg_ChromeIdentityCheckResult::Read(message, ¶ms); - EXPECT_EQ(test_identity, std::get<0>(params)); - ASSERT_TRUE(std::get<1>(params)); } TEST_F(SearchTabHelperTest, OnChromeIdentityCheckMismatch) { @@ -242,16 +234,9 @@ ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper); const base::string16 test_identity = base::ASCIIToUTF16("bar@foo.com"); + EXPECT_CALL(*mock_search_box(), + ChromeIdentityCheckResult(Eq(test_identity), false)); search_tab_helper->OnChromeIdentityCheck(test_identity); - - const IPC::Message* message = process()->sink().GetUniqueMessageMatching( - ChromeViewMsg_ChromeIdentityCheckResult::ID); - ASSERT_TRUE(message != NULL); - - ChromeViewMsg_ChromeIdentityCheckResult::Param params; - ChromeViewMsg_ChromeIdentityCheckResult::Read(message, ¶ms); - EXPECT_EQ(test_identity, std::get<0>(params)); - ASSERT_FALSE(std::get<1>(params)); } TEST_F(SearchTabHelperTest, OnChromeIdentityCheckSignedOutMismatch) { @@ -262,16 +247,9 @@ ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper); const base::string16 test_identity = base::ASCIIToUTF16("bar@foo.com"); + EXPECT_CALL(*mock_search_box(), + ChromeIdentityCheckResult(Eq(test_identity), false)); search_tab_helper->OnChromeIdentityCheck(test_identity); - - const IPC::Message* message = process()->sink().GetUniqueMessageMatching( - ChromeViewMsg_ChromeIdentityCheckResult::ID); - ASSERT_TRUE(message != NULL); - - ChromeViewMsg_ChromeIdentityCheckResult::Param params; - ChromeViewMsg_ChromeIdentityCheckResult::Read(message, ¶ms); - EXPECT_EQ(test_identity, std::get<0>(params)); - ASSERT_FALSE(std::get<1>(params)); } TEST_F(SearchTabHelperTest, OnHistorySyncCheckSyncing) { @@ -281,15 +259,8 @@ SearchTabHelper::FromWebContents(web_contents()); ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper); + EXPECT_CALL(*mock_search_box(), HistorySyncCheckResult(true)); search_tab_helper->OnHistorySyncCheck(); - - const IPC::Message* message = process()->sink().GetUniqueMessageMatching( - ChromeViewMsg_HistorySyncCheckResult::ID); - ASSERT_TRUE(message != NULL); - - ChromeViewMsg_HistorySyncCheckResult::Param params; - ChromeViewMsg_HistorySyncCheckResult::Read(message, ¶ms); - ASSERT_TRUE(std::get<0>(params)); } TEST_F(SearchTabHelperTest, OnHistorySyncCheckNotSyncing) { @@ -299,15 +270,8 @@ SearchTabHelper::FromWebContents(web_contents()); ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper); + EXPECT_CALL(*mock_search_box(), HistorySyncCheckResult(false)); search_tab_helper->OnHistorySyncCheck(); - - const IPC::Message* message = process()->sink().GetUniqueMessageMatching( - ChromeViewMsg_HistorySyncCheckResult::ID); - ASSERT_TRUE(message != NULL); - - ChromeViewMsg_HistorySyncCheckResult::Param params; - ChromeViewMsg_HistorySyncCheckResult::Read(message, ¶ms); - ASSERT_FALSE(std::get<0>(params)); } class TabTitleObserver : public content::WebContentsObserver {
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index 2c5b6d8..e34b618 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -92,6 +92,7 @@ "descriptors_android.h", "ini_parser.cc", "ini_parser.h", + "instant_type_traits.h", "logging_chrome.cc", "logging_chrome.h", "mac/app_shim_launch.h", @@ -623,13 +624,18 @@ # require many files from it. This makes linking more efficient. static_library("test_support") { testonly = true - visibility = [ "//chrome/test:test_support" ] + visibility = [ "//chrome/test:*" ] - sources = [] + sources = [ + "search/mock_searchbox.cc", + "search/mock_searchbox.h", + ] deps = [ ":common", + ":instant_mojom", "//base", + "//testing/gmock", "//testing/gtest", ] @@ -685,3 +691,14 @@ "//url/mojo:url_mojom_gurl", ] } + +mojom("instant_mojom") { + sources = [ + "instant.mojom", + ] + + public_deps = [ + "//mojo/common:common_custom_types", + "//url/mojo:url_mojom_gurl", + ] +}
diff --git a/chrome/common/instant.mojom b/chrome/common/instant.mojom new file mode 100644 index 0000000..3935339e --- /dev/null +++ b/chrome/common/instant.mojom
@@ -0,0 +1,104 @@ +// Copyright 2016 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. + +module chrome.mojom; + +import "mojo/common/string16.mojom"; +import "mojo/common/time.mojom"; +import "url/mojo/url.mojom"; + +[Native] +enum NTPLoggingEventType; + +[Native] +enum OmniboxFocusState; + +[Native] +enum NTPTileSource; + +interface Instant { + // Tells InstantExtended whether the embedded search API is supported. + // See http://dev.chromium.org/embeddedsearch + InstantSupportDetermined(int32 page_seq_no, bool result); + + // Tells InstantExtended to set the omnibox focus state. + FocusOmnibox(int32 page_seq_no, OmniboxFocusState state); + + // TODO(treib): Remove the SearchBox prefix from these three methods. + // Tells InstantExtended to delete a most visited item. + SearchBoxDeleteMostVisitedItem(int32 page_seq_no, url.mojom.Url url); + + // Tells InstantExtended to undo all most visited item deletions. + SearchBoxUndoAllMostVisitedDeletions(int32 page_seq_no); + + // Tells InstantExtended to undo one most visited item deletion. + SearchBoxUndoMostVisitedDeletion(int32 page_seq_no, url.mojom.Url url); + + // Logs events from InstantExtended New Tab Pages. + LogEvent(int32 page_seq_no, + NTPLoggingEventType event, + mojo.common.mojom.TimeDelta time); + + // Logs an impression on one of the Most Visited tile on the InstantExtended + // New Tab Page. + LogMostVisitedImpression(int32 page_seq_no, int32 position, + NTPTileSource tile_source); + + // Logs a navigation on one of the Most Visited tile on the InstantExtended + // New Tab Page. + LogMostVisitedNavigation(int32 page_seq_no, int32 position, + NTPTileSource tile_source); + + // Tells InstantExtended to paste text into the omnibox. If text is empty, + // the clipboard contents will be pasted. This causes the omnibox dropdown to + // open. + PasteAndOpenDropdown(int32 page_seq_no, + mojo.common.mojom.String16 text_to_be_pasted); + + // The Instant page asks whether the user syncs its history. + HistorySyncCheck(int32 page_seq_no); + + // The Instant page asks for Chrome identity check against |identity|. + ChromeIdentityCheck(int32 page_seq_no, mojo.common.mojom.String16 identity); +}; + +[Native] +enum OmniboxFocusChangeReason; + +[Native] +struct InstantMostVisitedItem; + +[Native] +struct InstantSuggestion; + +[Native] +struct EmbeddedSearchRequestParams; + +[Native] +struct ThemeBackgroundInfo; + +interface SearchBox { + SetPageSequenceNumber(int32 page_seq_no); + + DetermineIfPageSupportsInstant(); + + FocusChanged(OmniboxFocusState new_focus_state, + OmniboxFocusChangeReason reason); + + MostVisitedChanged(array<InstantMostVisitedItem> items); + + SetInputInProgress(bool input_in_progress); + + SetSuggestionToPrefetch(InstantSuggestion suggestion); + + Submit(mojo.common.mojom.String16 value, + EmbeddedSearchRequestParams params); + + ThemeChanged(ThemeBackgroundInfo value); + + HistorySyncCheckResult(bool sync_history); + + ChromeIdentityCheckResult(mojo.common.mojom.String16 identity, + bool identity_match); +};
diff --git a/chrome/common/instant.typemap b/chrome/common/instant.typemap new file mode 100644 index 0000000..04878d87 --- /dev/null +++ b/chrome/common/instant.typemap
@@ -0,0 +1,26 @@ +# Copyright 2016 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. + +mojom = "//chrome/common/instant.mojom" +public_headers = [ + "//chrome/common/search/instant_types.h", + "//chrome/common/search/ntp_logging_events.h", + "//components/ntp_tiles/ntp_tile_source.h", + "//components/omnibox/common/omnibox_focus_state.h", +] +traits_headers = [ "//chrome/common/instant_type_traits.h" ] +deps = [ + "//chrome/common", + "//ipc", +] +type_mappings = [ + "chrome.mojom.NTPLoggingEventType=::NTPLoggingEventType", + "chrome.mojom.NTPTileSource=::ntp_tiles::NTPTileSource", + "chrome.mojom.OmniboxFocusState=::OmniboxFocusState", + "chrome.mojom.OmniboxFocusChangeReason=::OmniboxFocusChangeReason", + "chrome.mojom.InstantMostVisitedItem=::InstantMostVisitedItem", + "chrome.mojom.InstantSuggestion=::InstantSuggestion", + "chrome.mojom.EmbeddedSearchRequestParams=::EmbeddedSearchRequestParams", + "chrome.mojom.ThemeBackgroundInfo=::ThemeBackgroundInfo", +]
diff --git a/chrome/common/instant_type_traits.h b/chrome/common/instant_type_traits.h new file mode 100644 index 0000000..4b97866 --- /dev/null +++ b/chrome/common/instant_type_traits.h
@@ -0,0 +1,57 @@ +// Copyright (c) 2016 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. + +// Multiply-included file, no traditional include guard. +#include "chrome/common/search/instant_types.h" +#include "chrome/common/search/ntp_logging_events.h" +#include "components/omnibox/common/omnibox_focus_state.h" +#include "ipc/ipc_message_macros.h" + +IPC_ENUM_TRAITS_MAX_VALUE(OmniboxFocusState, OMNIBOX_FOCUS_STATE_LAST) + +IPC_ENUM_TRAITS_MAX_VALUE(OmniboxFocusChangeReason, + OMNIBOX_FOCUS_CHANGE_REASON_LAST) + +IPC_ENUM_TRAITS_MAX_VALUE(NTPLoggingEventType, NTP_EVENT_TYPE_LAST) + +IPC_ENUM_TRAITS_MAX_VALUE(ntp_tiles::NTPTileSource, + ntp_tiles::NTPTileSource::LAST) + +IPC_STRUCT_TRAITS_BEGIN(InstantMostVisitedItem) + IPC_STRUCT_TRAITS_MEMBER(url) + IPC_STRUCT_TRAITS_MEMBER(title) + IPC_STRUCT_TRAITS_MEMBER(thumbnail) + IPC_STRUCT_TRAITS_MEMBER(favicon) + IPC_STRUCT_TRAITS_MEMBER(source) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(InstantSuggestion) + IPC_STRUCT_TRAITS_MEMBER(text) + IPC_STRUCT_TRAITS_MEMBER(metadata) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(EmbeddedSearchRequestParams) + IPC_STRUCT_TRAITS_MEMBER(search_query) + IPC_STRUCT_TRAITS_MEMBER(original_query) + IPC_STRUCT_TRAITS_MEMBER(rlz_parameter_value) + IPC_STRUCT_TRAITS_MEMBER(input_encoding) + IPC_STRUCT_TRAITS_MEMBER(assisted_query_stats) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(ThemeBackgroundInfo) + IPC_STRUCT_TRAITS_MEMBER(using_default_theme) + IPC_STRUCT_TRAITS_MEMBER(background_color) + IPC_STRUCT_TRAITS_MEMBER(text_color) + IPC_STRUCT_TRAITS_MEMBER(link_color) + IPC_STRUCT_TRAITS_MEMBER(text_color_light) + IPC_STRUCT_TRAITS_MEMBER(header_color) + IPC_STRUCT_TRAITS_MEMBER(section_border_color) + IPC_STRUCT_TRAITS_MEMBER(theme_id) + IPC_STRUCT_TRAITS_MEMBER(image_horizontal_alignment) + IPC_STRUCT_TRAITS_MEMBER(image_vertical_alignment) + IPC_STRUCT_TRAITS_MEMBER(image_tiling) + IPC_STRUCT_TRAITS_MEMBER(image_height) + IPC_STRUCT_TRAITS_MEMBER(has_attribution) + IPC_STRUCT_TRAITS_MEMBER(logo_alternate) +IPC_STRUCT_TRAITS_END()
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index b8242b3..4ebddb8 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h
@@ -12,6 +12,7 @@ #include "base/time/time.h" #include "build/build_config.h" #include "chrome/common/features.h" +#include "chrome/common/instant_type_traits.h" #include "chrome/common/search/instant_types.h" #include "chrome/common/search/ntp_logging_events.h" #include "chrome/common/web_application_info.h" @@ -80,9 +81,6 @@ IPC_ENUM_TRAITS_MAX_VALUE(ChromeViewHostMsg_GetPluginInfo_Status, ChromeViewHostMsg_GetPluginInfo_Status::kUnauthorized) -IPC_ENUM_TRAITS_MAX_VALUE(OmniboxFocusChangeReason, - OMNIBOX_FOCUS_CHANGE_REASON_LAST) -IPC_ENUM_TRAITS_MAX_VALUE(OmniboxFocusState, OMNIBOX_FOCUS_STATE_LAST) IPC_ENUM_TRAITS_MAX_VALUE(ThemeBackgroundImageAlignment, THEME_BKGRND_IMAGE_ALIGN_LAST) IPC_ENUM_TRAITS_MAX_VALUE(ThemeBackgroundImageTiling, THEME_BKGRND_IMAGE_LAST) @@ -119,27 +117,6 @@ IPC_STRUCT_TRAITS_MEMBER(incognito) IPC_STRUCT_TRAITS_END() -IPC_STRUCT_TRAITS_BEGIN(EmbeddedSearchRequestParams) - IPC_STRUCT_TRAITS_MEMBER(search_query) - IPC_STRUCT_TRAITS_MEMBER(original_query) - IPC_STRUCT_TRAITS_MEMBER(rlz_parameter_value) - IPC_STRUCT_TRAITS_MEMBER(input_encoding) - IPC_STRUCT_TRAITS_MEMBER(assisted_query_stats) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(InstantSuggestion) - IPC_STRUCT_TRAITS_MEMBER(text) - IPC_STRUCT_TRAITS_MEMBER(metadata) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(InstantMostVisitedItem) - IPC_STRUCT_TRAITS_MEMBER(url) - IPC_STRUCT_TRAITS_MEMBER(title) - IPC_STRUCT_TRAITS_MEMBER(thumbnail) - IPC_STRUCT_TRAITS_MEMBER(favicon) - IPC_STRUCT_TRAITS_MEMBER(source) -IPC_STRUCT_TRAITS_END() - IPC_STRUCT_TRAITS_BEGIN(RendererContentSettingRules) IPC_STRUCT_TRAITS_MEMBER(image_rules) IPC_STRUCT_TRAITS_MEMBER(script_rules) @@ -153,29 +130,6 @@ IPC_STRUCT_TRAITS_MEMBER(a) IPC_STRUCT_TRAITS_END() -IPC_STRUCT_TRAITS_BEGIN(ThemeBackgroundInfo) - IPC_STRUCT_TRAITS_MEMBER(using_default_theme) - IPC_STRUCT_TRAITS_MEMBER(background_color) - IPC_STRUCT_TRAITS_MEMBER(text_color) - IPC_STRUCT_TRAITS_MEMBER(link_color) - IPC_STRUCT_TRAITS_MEMBER(text_color_light) - IPC_STRUCT_TRAITS_MEMBER(header_color) - IPC_STRUCT_TRAITS_MEMBER(section_border_color) - IPC_STRUCT_TRAITS_MEMBER(theme_id) - IPC_STRUCT_TRAITS_MEMBER(image_horizontal_alignment) - IPC_STRUCT_TRAITS_MEMBER(image_vertical_alignment) - IPC_STRUCT_TRAITS_MEMBER(image_tiling) - IPC_STRUCT_TRAITS_MEMBER(image_height) - IPC_STRUCT_TRAITS_MEMBER(has_attribution) - IPC_STRUCT_TRAITS_MEMBER(logo_alternate) -IPC_STRUCT_TRAITS_END() - -IPC_ENUM_TRAITS_MAX_VALUE(NTPLoggingEventType, - NTP_EVENT_TYPE_LAST) - -IPC_ENUM_TRAITS_MAX_VALUE(ntp_tiles::NTPTileSource, - ntp_tiles::NTPTileSource::LAST) - IPC_ENUM_TRAITS_MAX_VALUE(WebApplicationInfo::MobileCapable, WebApplicationInfo::MOBILE_CAPABLE_APPLE) @@ -220,38 +174,6 @@ std::string /* field trial name */, std::string /* group name that was assigned. */) -IPC_MESSAGE_ROUTED1(ChromeViewMsg_SetPageSequenceNumber, - int /* page_seq_no */) - -IPC_MESSAGE_ROUTED0(ChromeViewMsg_DetermineIfPageSupportsInstant) - -IPC_MESSAGE_ROUTED2(ChromeViewMsg_SearchBoxFocusChanged, - OmniboxFocusState /* new_focus_state */, - OmniboxFocusChangeReason /* reason */) - -IPC_MESSAGE_ROUTED1(ChromeViewMsg_SearchBoxMostVisitedItemsChanged, - std::vector<InstantMostVisitedItem> /* items */) - -IPC_MESSAGE_ROUTED1(ChromeViewMsg_SearchBoxSetInputInProgress, - bool /* input_in_progress */) - -IPC_MESSAGE_ROUTED1(ChromeViewMsg_SearchBoxSetSuggestionToPrefetch, - InstantSuggestion /* suggestion */) - -IPC_MESSAGE_ROUTED2(ChromeViewMsg_SearchBoxSubmit, - base::string16 /* value */, - EmbeddedSearchRequestParams /* params */) - -IPC_MESSAGE_ROUTED1(ChromeViewMsg_SearchBoxThemeChanged, - ThemeBackgroundInfo /* value */) - -IPC_MESSAGE_ROUTED1(ChromeViewMsg_HistorySyncCheckResult, - bool /* sync_history */) - -IPC_MESSAGE_ROUTED2(ChromeViewMsg_ChromeIdentityCheckResult, - base::string16 /* identity */, - bool /* identity_match */) - // Sent to allow or forbid the running of insecure mixed-content. IPC_MESSAGE_ROUTED1(ChromeViewMsg_SetAllowRunningInsecureContent, bool /* allowed */) @@ -518,67 +440,6 @@ IPC_MESSAGE_ROUTED1(ChromeViewHostMsg_DidGetWebApplicationInfo, WebApplicationInfo) -// Logs events from InstantExtended New Tab Pages. -IPC_MESSAGE_ROUTED3(ChromeViewHostMsg_LogEvent, - int /* page_seq_no */, - NTPLoggingEventType /* event */, - base::TimeDelta /* time */) - -// Logs an impression on one of the Most Visited tile on the InstantExtended -// New Tab Page. -IPC_MESSAGE_ROUTED3(ChromeViewHostMsg_LogMostVisitedImpression, - int /* page_seq_no */, - int /* position */, - ntp_tiles::NTPTileSource /* tile_source */) - -// Logs a navigation on one of the Most Visited tile on the InstantExtended -// New Tab Page. -IPC_MESSAGE_ROUTED3(ChromeViewHostMsg_LogMostVisitedNavigation, - int /* page_seq_no */, - int /* position */, - ntp_tiles::NTPTileSource /* tile_source */) - -// The Instant page asks whether the user syncs its history. -IPC_MESSAGE_ROUTED1(ChromeViewHostMsg_HistorySyncCheck, - int /* page_seq_no */) - -// The Instant page asks for Chrome identity check against |identity|. -IPC_MESSAGE_ROUTED2(ChromeViewHostMsg_ChromeIdentityCheck, - int /* page_seq_no */, - base::string16 /* identity */) - -// Tells InstantExtended to set the omnibox focus state. -IPC_MESSAGE_ROUTED2(ChromeViewHostMsg_FocusOmnibox, - int /* page_seq_no */, - OmniboxFocusState /* state */) - -// Tells InstantExtended to paste text into the omnibox. If text is empty, -// the clipboard contents will be pasted. This causes the omnibox dropdown to -// open. -IPC_MESSAGE_ROUTED2(ChromeViewHostMsg_PasteAndOpenDropdown, - int /* page_seq_no */, - base::string16 /* text to be pasted */) - -// Tells InstantExtended whether the embedded search API is supported. -// See http://dev.chromium.org/embeddedsearch -IPC_MESSAGE_ROUTED2(ChromeViewHostMsg_InstantSupportDetermined, - int /* page_seq_no */, - bool /* result */) - -// Tells InstantExtended to delete a most visited item. -IPC_MESSAGE_ROUTED2(ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem, - int /* page_seq_no */, - GURL /* url */) - -// Tells InstantExtended to undo all most visited item deletions. -IPC_MESSAGE_ROUTED1(ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions, - int /* page_seq_no */) - -// Tells InstantExtended to undo one most visited item deletion. -IPC_MESSAGE_ROUTED2(ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion, - int /* page_seq_no */, - GURL /* url */) - // Tells the renderer a list of URLs which should be bounced back to the browser // process so that they can be assigned to an Instant renderer. IPC_MESSAGE_CONTROL2(ChromeViewMsg_SetSearchURLs,
diff --git a/chrome/common/search/mock_searchbox.cc b/chrome/common/search/mock_searchbox.cc new file mode 100644 index 0000000..a6412a3 --- /dev/null +++ b/chrome/common/search/mock_searchbox.cc
@@ -0,0 +1,8 @@ +// Copyright 2016 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/common/search/mock_searchbox.h" + +MockSearchBox::MockSearchBox() = default; +MockSearchBox::~MockSearchBox() = default;
diff --git a/chrome/common/search/mock_searchbox.h b/chrome/common/search/mock_searchbox.h new file mode 100644 index 0000000..baaf455 --- /dev/null +++ b/chrome/common/search/mock_searchbox.h
@@ -0,0 +1,31 @@ +// Copyright 2016 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_COMMON_SEARCH_MOCK_SEARCHBOX_H_ +#define CHROME_COMMON_SEARCH_MOCK_SEARCHBOX_H_ + +#include "chrome/common/instant.mojom.h" +#include "testing/gmock/include/gmock/gmock.h" + +class MockSearchBox : public chrome::mojom::SearchBox { + public: + MockSearchBox(); + ~MockSearchBox(); + + MOCK_METHOD1(SetPageSequenceNumber, void(int)); + MOCK_METHOD2(ChromeIdentityCheckResult, void(const base::string16&, bool)); + MOCK_METHOD0(DetermineIfPageSupportsInstant, void()); + MOCK_METHOD2(FocusChanged, void(OmniboxFocusState, OmniboxFocusChangeReason)); + MOCK_METHOD1(HistorySyncCheckResult, void(bool)); + MOCK_METHOD1(MostVisitedChanged, + void(const std::vector<InstantMostVisitedItem>&)); + MOCK_METHOD1(SetInputInProgress, void(bool)); + MOCK_METHOD1(SetSuggestionToPrefetch, void(const InstantSuggestion&)); + MOCK_METHOD2(Submit, + void(const base::string16&, const EmbeddedSearchRequestParams&)); + MOCK_METHOD1(ThemeChanged, void(const ThemeBackgroundInfo&)); +}; + + +#endif // CHROME_COMMON_SEARCH_MOCK_SEARCHBOX_H_
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn index fe84d48f..e3783b3a 100644 --- a/chrome/renderer/BUILD.gn +++ b/chrome/renderer/BUILD.gn
@@ -92,6 +92,7 @@ "//chrome:resources", "//chrome:strings", "//chrome/common", + "//chrome/common:instant_mojom", "//chrome/common:mojo_bindings", "//chrome/common/net", "//components/autofill/content/renderer", @@ -127,6 +128,7 @@ "//net", "//ppapi/features", "//printing/features", + "//services/service_manager/public/cpp", "//skia", "//storage/common", "//third_party/WebKit/public:blink", @@ -377,6 +379,7 @@ deps = [ ":renderer", + "//chrome/common:instant_mojom", "//content/test:test_support", "//extensions/features", "//testing/gmock",
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 25add39..6728fc9 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -520,6 +520,11 @@ new subresource_filter::SubresourceFilterAgent( render_frame, subresource_filter_ruleset_dealer_.get()); } + + if (command_line->HasSwitch(switches::kInstantProcess) && + render_frame->IsMainFrame()) { + new SearchBox(render_frame); + } } void ChromeContentRendererClient::RenderViewCreated( @@ -532,10 +537,6 @@ #endif new prerender::PrerendererClient(render_view); - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kInstantProcess)) - new SearchBox(render_view); - new ChromeRenderViewObserver(render_view, web_cache_impl_.get()); new password_manager::CredentialManagerClient(render_view); @@ -1118,9 +1119,8 @@ if (!url.protocolIs(chrome::kChromeSearchScheme)) return false; - const content::RenderView* render_view = - content::RenderView::FromWebView(frame->view()); - SearchBox* search_box = SearchBox::Get(render_view); + SearchBox* search_box = + SearchBox::Get(content::RenderFrame::FromWebFrame(frame)); if (search_box) { // Note: this GURL copy could be avoided if host() were added to WebURL. GURL gurl(url);
diff --git a/chrome/renderer/searchbox/searchbox.cc b/chrome/renderer/searchbox/searchbox.cc index 6262ed56..41a44b6 100644 --- a/chrome/renderer/searchbox/searchbox.cc +++ b/chrome/renderer/searchbox/searchbox.cc
@@ -16,6 +16,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/instant.mojom.h" #include "chrome/common/render_messages.h" #include "chrome/common/url_constants.h" #include "chrome/renderer/searchbox/searchbox_extension.h" @@ -24,6 +25,8 @@ #include "components/favicon_base/favicon_url_parser.h" #include "components/favicon_base/large_icon_url_parser.h" #include "components/omnibox/common/omnibox_focus_state.h" +#include "content/public/common/associated_interface_provider.h" +#include "content/public/common/associated_interface_registry.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_view.h" #include "net/base/escape.h" @@ -123,7 +126,7 @@ } int SearchBoxIconURLHelper::GetViewID() const { - return search_box_->render_view()->GetRoutingID(); + return search_box_->render_frame()->GetRenderView()->GetRoutingID(); } std::string SearchBoxIconURLHelper::GetURLStringFromRestrictedID( @@ -231,69 +234,60 @@ SearchBox::IconURLHelper::~IconURLHelper() { } -SearchBox::SearchBox(content::RenderView* render_view) - : content::RenderViewObserver(render_view), - content::RenderViewObserverTracker<SearchBox>(render_view), - page_seq_no_(0), - is_focused_(false), - is_input_in_progress_(false), - is_key_capture_enabled_(false), - most_visited_items_cache_(kMaxInstantMostVisitedItemCacheSize), - query_() { +SearchBox::SearchBox(content::RenderFrame* render_frame) + : content::RenderFrameObserver(render_frame), + content::RenderFrameObserverTracker<SearchBox>(render_frame), + page_seq_no_(0), + is_focused_(false), + is_input_in_progress_(false), + is_key_capture_enabled_(false), + most_visited_items_cache_(kMaxInstantMostVisitedItemCacheSize), + query_(), + binding_(this) { + render_frame->GetRemoteAssociatedInterfaces()->GetInterface( + &instant_service_); + render_frame->GetAssociatedInterfaceRegistry()->AddInterface( + base::Bind(&SearchBox::Bind, base::Unretained(this))); } SearchBox::~SearchBox() { } void SearchBox::LogEvent(NTPLoggingEventType event) { - // The main frame for the current RenderView may be out-of-process, in which - // case it won't have performance(). Use the default delta of 0 in this - // case. - base::TimeDelta delta; - if (render_view()->GetWebView()->mainFrame()->isWebLocalFrame()) { - // navigation_start in ms. - uint64_t start = 1000 * (render_view() - ->GetMainRenderFrame() - ->GetWebFrame() - ->performance() - .navigationStart()); - uint64_t now = (base::TimeTicks::Now() - base::TimeTicks::UnixEpoch()) - .InMilliseconds(); - DCHECK(now >= start); - delta = base::TimeDelta::FromMilliseconds(now - start); - } - render_view()->Send(new ChromeViewHostMsg_LogEvent( - render_view()->GetRoutingID(), page_seq_no_, event, delta)); + // navigation_start in ms. + uint64_t start = + 1000 * (render_frame()->GetWebFrame()->performance().navigationStart()); + uint64_t now = + (base::TimeTicks::Now() - base::TimeTicks::UnixEpoch()).InMilliseconds(); + DCHECK(now >= start); + base::TimeDelta delta = base::TimeDelta::FromMilliseconds(now - start); + instant_service_->LogEvent(page_seq_no_, event, delta); } void SearchBox::LogMostVisitedImpression(int position, ntp_tiles::NTPTileSource tile_source) { - render_view()->Send(new ChromeViewHostMsg_LogMostVisitedImpression( - render_view()->GetRoutingID(), page_seq_no_, position, tile_source)); + instant_service_->LogMostVisitedImpression(page_seq_no_, position, + tile_source); } void SearchBox::LogMostVisitedNavigation(int position, ntp_tiles::NTPTileSource tile_source) { - render_view()->Send(new ChromeViewHostMsg_LogMostVisitedNavigation( - render_view()->GetRoutingID(), page_seq_no_, position, tile_source)); + instant_service_->LogMostVisitedNavigation(page_seq_no_, position, + tile_source); } void SearchBox::CheckIsUserSignedInToChromeAs(const base::string16& identity) { - render_view()->Send(new ChromeViewHostMsg_ChromeIdentityCheck( - render_view()->GetRoutingID(), page_seq_no_, identity)); + instant_service_->ChromeIdentityCheck(page_seq_no_, identity); } void SearchBox::CheckIsUserSyncingHistory() { - render_view()->Send(new ChromeViewHostMsg_HistorySyncCheck( - render_view()->GetRoutingID(), page_seq_no_)); + instant_service_->HistorySyncCheck(page_seq_no_); } void SearchBox::DeleteMostVisitedItem( InstantRestrictedID most_visited_item_id) { - render_view()->Send(new ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem( - render_view()->GetRoutingID(), - page_seq_no_, - GetURLForMostVisitedItem(most_visited_item_id))); + instant_service_->SearchBoxDeleteMostVisitedItem( + page_seq_no_, GetURLForMostVisitedItem(most_visited_item_id)); } bool SearchBox::GenerateImageURLFromTransientURL(const GURL& transient_url, @@ -324,83 +318,46 @@ } void SearchBox::Paste(const base::string16& text) { - render_view()->Send(new ChromeViewHostMsg_PasteAndOpenDropdown( - render_view()->GetRoutingID(), page_seq_no_, text)); + instant_service_->PasteAndOpenDropdown(page_seq_no_, text); } void SearchBox::StartCapturingKeyStrokes() { - render_view()->Send(new ChromeViewHostMsg_FocusOmnibox( - render_view()->GetRoutingID(), page_seq_no_, OMNIBOX_FOCUS_INVISIBLE)); + instant_service_->FocusOmnibox(page_seq_no_, OMNIBOX_FOCUS_INVISIBLE); } void SearchBox::StopCapturingKeyStrokes() { - render_view()->Send(new ChromeViewHostMsg_FocusOmnibox( - render_view()->GetRoutingID(), page_seq_no_, OMNIBOX_FOCUS_NONE)); + instant_service_->FocusOmnibox(page_seq_no_, OMNIBOX_FOCUS_NONE); } void SearchBox::UndoAllMostVisitedDeletions() { - render_view()->Send( - new ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions( - render_view()->GetRoutingID(), page_seq_no_)); + instant_service_->SearchBoxUndoAllMostVisitedDeletions(page_seq_no_); } void SearchBox::UndoMostVisitedDeletion( InstantRestrictedID most_visited_item_id) { - render_view()->Send(new ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion( - render_view()->GetRoutingID(), page_seq_no_, - GetURLForMostVisitedItem(most_visited_item_id))); + instant_service_->SearchBoxUndoMostVisitedDeletion( + page_seq_no_, GetURLForMostVisitedItem(most_visited_item_id)); } -bool SearchBox::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(SearchBox, message) - IPC_MESSAGE_HANDLER(ChromeViewMsg_SetPageSequenceNumber, - OnSetPageSequenceNumber) - IPC_MESSAGE_HANDLER(ChromeViewMsg_ChromeIdentityCheckResult, - OnChromeIdentityCheckResult) - IPC_MESSAGE_HANDLER(ChromeViewMsg_DetermineIfPageSupportsInstant, - OnDetermineIfPageSupportsInstant) - IPC_MESSAGE_HANDLER(ChromeViewMsg_HistorySyncCheckResult, - OnHistorySyncCheckResult) - IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxFocusChanged, OnFocusChanged) - IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxMostVisitedItemsChanged, - OnMostVisitedChanged) - IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxSetInputInProgress, - OnSetInputInProgress) - IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxSetSuggestionToPrefetch, - OnSetSuggestionToPrefetch) - IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxSubmit, OnSubmit) - IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxThemeChanged, - OnThemeChanged) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void SearchBox::OnSetPageSequenceNumber(int page_seq_no) { +void SearchBox::SetPageSequenceNumber(int page_seq_no) { page_seq_no_ = page_seq_no; } -void SearchBox::OnChromeIdentityCheckResult(const base::string16& identity, - bool identity_match) { - if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { - extensions_v8::SearchBoxExtension::DispatchChromeIdentityCheckResult( - render_view()->GetWebView()->mainFrame(), identity, identity_match); - } +void SearchBox::ChromeIdentityCheckResult(const base::string16& identity, + bool identity_match) { + extensions_v8::SearchBoxExtension::DispatchChromeIdentityCheckResult( + render_frame()->GetWebFrame(), identity, identity_match); } -void SearchBox::OnDetermineIfPageSupportsInstant() { - if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { - bool result = extensions_v8::SearchBoxExtension::PageSupportsInstant( - render_view()->GetWebView()->mainFrame()); - DVLOG(1) << render_view() << " PageSupportsInstant: " << result; - render_view()->Send(new ChromeViewHostMsg_InstantSupportDetermined( - render_view()->GetRoutingID(), page_seq_no_, result)); - } +void SearchBox::DetermineIfPageSupportsInstant() { + bool result = extensions_v8::SearchBoxExtension::PageSupportsInstant( + render_frame()->GetWebFrame()); + DVLOG(1) << render_frame() << " PageSupportsInstant: " << result; + instant_service_->InstantSupportDetermined(page_seq_no_, result); } -void SearchBox::OnFocusChanged(OmniboxFocusState new_focus_state, - OmniboxFocusChangeReason reason) { +void SearchBox::FocusChanged(OmniboxFocusState new_focus_state, + OmniboxFocusChangeReason reason) { bool key_capture_enabled = new_focus_state == OMNIBOX_FOCUS_INVISIBLE; if (key_capture_enabled != is_key_capture_enabled_) { // Tell the page if the key capture mode changed unless the focus state @@ -411,98 +368,81 @@ // onkeycapturechange before the corresponding onchange, and the page would // have no way of telling whether the keycapturechange happened because of // some actual user action or just because they started typing.) - if (reason != OMNIBOX_FOCUS_CHANGE_TYPING && - render_view()->GetWebView() && - render_view()->GetWebView()->mainFrame()) { + if (reason != OMNIBOX_FOCUS_CHANGE_TYPING) { is_key_capture_enabled_ = key_capture_enabled; - DVLOG(1) << render_view() << " OnKeyCaptureChange"; + DVLOG(1) << render_frame() << " KeyCaptureChange"; extensions_v8::SearchBoxExtension::DispatchKeyCaptureChange( - render_view()->GetWebView()->mainFrame()); + render_frame()->GetWebFrame()); } } bool is_focused = new_focus_state == OMNIBOX_FOCUS_VISIBLE; if (is_focused != is_focused_) { is_focused_ = is_focused; - DVLOG(1) << render_view() << " OnFocusChange"; - if (render_view()->GetWebView() && - render_view()->GetWebView()->mainFrame()) { - extensions_v8::SearchBoxExtension::DispatchFocusChange( - render_view()->GetWebView()->mainFrame()); - } + DVLOG(1) << render_frame() << " FocusChange"; + extensions_v8::SearchBoxExtension::DispatchFocusChange( + render_frame()->GetWebFrame()); } } -void SearchBox::OnHistorySyncCheckResult(bool sync_history) { - if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { - extensions_v8::SearchBoxExtension::DispatchHistorySyncCheckResult( - render_view()->GetWebView()->mainFrame(), sync_history); - } +void SearchBox::HistorySyncCheckResult(bool sync_history) { + extensions_v8::SearchBoxExtension::DispatchHistorySyncCheckResult( + render_frame()->GetWebFrame(), sync_history); } -void SearchBox::OnMostVisitedChanged( +void SearchBox::MostVisitedChanged( const std::vector<InstantMostVisitedItem>& items) { std::vector<InstantMostVisitedItemIDPair> last_known_items; GetMostVisitedItems(&last_known_items); - if (AreMostVisitedItemsEqual(last_known_items, items)) + if (AreMostVisitedItemsEqual(last_known_items, items)) { return; // Do not send duplicate onmostvisitedchange events. + } most_visited_items_cache_.AddItems(items); - if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { - extensions_v8::SearchBoxExtension::DispatchMostVisitedChanged( - render_view()->GetWebView()->mainFrame()); - } + extensions_v8::SearchBoxExtension::DispatchMostVisitedChanged( + render_frame()->GetWebFrame()); } -void SearchBox::OnSetInputInProgress(bool is_input_in_progress) { +void SearchBox::SetInputInProgress(bool is_input_in_progress) { if (is_input_in_progress_ != is_input_in_progress) { is_input_in_progress_ = is_input_in_progress; - DVLOG(1) << render_view() << " OnSetInputInProgress"; - if (render_view()->GetWebView() && - render_view()->GetWebView()->mainFrame()) { - if (is_input_in_progress_) { - extensions_v8::SearchBoxExtension::DispatchInputStart( - render_view()->GetWebView()->mainFrame()); - } else { - extensions_v8::SearchBoxExtension::DispatchInputCancel( - render_view()->GetWebView()->mainFrame()); - } + DVLOG(1) << render_frame() << " SetInputInProgress"; + if (is_input_in_progress_) { + extensions_v8::SearchBoxExtension::DispatchInputStart( + render_frame()->GetWebFrame()); + } else { + extensions_v8::SearchBoxExtension::DispatchInputCancel( + render_frame()->GetWebFrame()); } } } -void SearchBox::OnSetSuggestionToPrefetch(const InstantSuggestion& suggestion) { +void SearchBox::SetSuggestionToPrefetch(const InstantSuggestion& suggestion) { suggestion_ = suggestion; - if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { - DVLOG(1) << render_view() << " OnSetSuggestionToPrefetch"; - extensions_v8::SearchBoxExtension::DispatchSuggestionChange( - render_view()->GetWebView()->mainFrame()); - } + DVLOG(1) << render_frame() << " SetSuggestionToPrefetch"; + extensions_v8::SearchBoxExtension::DispatchSuggestionChange( + render_frame()->GetWebFrame()); } -void SearchBox::OnSubmit(const base::string16& query, - const EmbeddedSearchRequestParams& params) { +void SearchBox::Submit(const base::string16& query, + const EmbeddedSearchRequestParams& params) { query_ = query; embedded_search_request_params_ = params; - if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { - DVLOG(1) << render_view() << " OnSubmit"; - extensions_v8::SearchBoxExtension::DispatchSubmit( - render_view()->GetWebView()->mainFrame()); - } + DVLOG(1) << render_frame() << " Submit"; + extensions_v8::SearchBoxExtension::DispatchSubmit( + render_frame()->GetWebFrame()); if (!query.empty()) Reset(); } -void SearchBox::OnThemeChanged(const ThemeBackgroundInfo& theme_info) { +void SearchBox::ThemeChanged(const ThemeBackgroundInfo& theme_info) { // Do not send duplicate notifications. if (theme_info_ == theme_info) return; theme_info_ = theme_info; - if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { - extensions_v8::SearchBoxExtension::DispatchThemeChange( - render_view()->GetWebView()->mainFrame()); - } + extensions_v8::SearchBoxExtension::DispatchThemeChange( + render_frame()->GetWebFrame()); } GURL SearchBox::GetURLForMostVisitedItem(InstantRestrictedID item_id) const { @@ -510,6 +450,10 @@ return GetMostVisitedItemWithID(item_id, &item) ? item.url : GURL(); } +void SearchBox::Bind(chrome::mojom::SearchBoxAssociatedRequest request) { + binding_.Bind(std::move(request)); +} + void SearchBox::Reset() { query_.clear(); embedded_search_request_params_ = EmbeddedSearchRequestParams();
diff --git a/chrome/renderer/searchbox/searchbox.h b/chrome/renderer/searchbox/searchbox.h index 50e89ec..5781157 100644 --- a/chrome/renderer/searchbox/searchbox.h +++ b/chrome/renderer/searchbox/searchbox.h
@@ -10,22 +10,21 @@ #include "base/macros.h" #include "base/strings/string16.h" +#include "chrome/common/instant.mojom.h" #include "chrome/common/search/instant_types.h" #include "chrome/common/search/ntp_logging_events.h" #include "chrome/renderer/instant_restricted_id_cache.h" #include "components/ntp_tiles/ntp_tile_source.h" #include "components/omnibox/common/omnibox_focus_state.h" -#include "content/public/renderer/render_view_observer.h" -#include "content/public/renderer/render_view_observer_tracker.h" +#include "content/public/renderer/render_frame_observer.h" +#include "content/public/renderer/render_frame_observer_tracker.h" +#include "mojo/public/cpp/bindings/associated_binding.h" #include "ui/base/window_open_disposition.h" #include "url/gurl.h" -namespace content { -class RenderView; -} - -class SearchBox : public content::RenderViewObserver, - public content::RenderViewObserverTracker<SearchBox> { +class SearchBox : public content::RenderFrameObserver, + public content::RenderFrameObserverTracker<SearchBox>, + public chrome::mojom::SearchBox { public: enum ImageSourceType { NONE = -1, @@ -48,27 +47,27 @@ const = 0; }; - explicit SearchBox(content::RenderView* render_view); + explicit SearchBox(content::RenderFrame* render_frame); ~SearchBox() override; - // Sends ChromeViewHostMsg_LogEvent to the browser. + // Sends LogEvent to the browser. void LogEvent(NTPLoggingEventType event); - // Sends ChromeViewHostMsg_LogMostVisitedImpression to the browser. + // Sends LogMostVisitedImpression to the browser. void LogMostVisitedImpression(int position, ntp_tiles::NTPTileSource tile_source); - // Sends ChromeViewHostMsg_LogMostVisitedNavigation to the browser. + // Sends LogMostVisitedNavigation to the browser. void LogMostVisitedNavigation(int position, ntp_tiles::NTPTileSource tile_source); - // Sends ChromeViewHostMsg_ChromeIdentityCheck to the browser. + // Sends ChromeIdentityCheck to the browser. void CheckIsUserSignedInToChromeAs(const base::string16& identity); - // Sends ChromeViewHostMsg_HistorySyncCheck to the browser. + // Sends HistorySyncCheck to the browser. void CheckIsUserSyncingHistory(); - // Sends ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem to the browser. + // Sends SearchBoxDeleteMostVisitedItem to the browser. void DeleteMostVisitedItem(InstantRestrictedID most_visited_item_id); // Generates the image URL of |type| for the most visited item specified in @@ -110,7 +109,7 @@ bool GetMostVisitedItemWithID(InstantRestrictedID most_visited_item_id, InstantMostVisitedItem* item) const; - // Sends ChromeViewHostMsg_SearchBoxPaste to the browser. + // Sends SearchBoxPaste to the browser. void Paste(const base::string16& text); const ThemeBackgroundInfo& GetThemeBackgroundInfo(); @@ -122,11 +121,10 @@ // Sends ChromeViewHostMsg_StopCapturingKeyStrokes to the browser. void StopCapturingKeyStrokes(); - // Sends ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions to the - // browser. + // Sends SearchBoxUndoAllMostVisitedDeletions to the browser. void UndoAllMostVisitedDeletions(); - // Sends ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion to the browser. + // Sends SearchBoxUndoMostVisitedDeletion to the browser. void UndoMostVisitedDeletion(InstantRestrictedID most_visited_item_id); bool is_focused() const { return is_focused_; } @@ -136,24 +134,24 @@ const InstantSuggestion& suggestion() const { return suggestion_; } private: - // Overridden from content::RenderViewObserver: - bool OnMessageReceived(const IPC::Message& message) override; + // Overridden from content::RenderFrameObserver: void OnDestruct() override; - void OnSetPageSequenceNumber(int page_seq_no); - void OnChromeIdentityCheckResult(const base::string16& identity, - bool identity_match); - void OnDetermineIfPageSupportsInstant(); - void OnFocusChanged(OmniboxFocusState new_focus_state, - OmniboxFocusChangeReason reason); - void OnHistorySyncCheckResult(bool sync_history); - void OnMostVisitedChanged( - const std::vector<InstantMostVisitedItem>& items); - void OnSetInputInProgress(bool input_in_progress); - void OnSetSuggestionToPrefetch(const InstantSuggestion& suggestion); - void OnSubmit(const base::string16& query, - const EmbeddedSearchRequestParams& params); - void OnThemeChanged(const ThemeBackgroundInfo& theme_info); + // Overridden from chrome::mojom::SearchBox: + void SetPageSequenceNumber(int page_seq_no) override; + void ChromeIdentityCheckResult(const base::string16& identity, + bool identity_match) override; + void DetermineIfPageSupportsInstant() override; + void FocusChanged(OmniboxFocusState new_focus_state, + OmniboxFocusChangeReason reason) override; + void HistorySyncCheckResult(bool sync_history) override; + void MostVisitedChanged( + const std::vector<InstantMostVisitedItem>& items) override; + void SetInputInProgress(bool input_in_progress) override; + void SetSuggestionToPrefetch(const InstantSuggestion& suggestion) override; + void Submit(const base::string16& query, + const EmbeddedSearchRequestParams& params) override; + void ThemeChanged(const ThemeBackgroundInfo& theme_info) override; // Returns the current zoom factor of the render view or 1 on failure. double GetZoom() const; @@ -164,6 +162,8 @@ // Returns the URL of the Most Visited item specified by the |item_id|. GURL GetURLForMostVisitedItem(InstantRestrictedID item_id) const; + void Bind(chrome::mojom::SearchBoxAssociatedRequest request); + int page_seq_no_; bool is_focused_; bool is_input_in_progress_; @@ -173,6 +173,8 @@ base::string16 query_; EmbeddedSearchRequestParams embedded_search_request_params_; InstantSuggestion suggestion_; + chrome::mojom::InstantAssociatedPtr instant_service_; + mojo::AssociatedBinding<chrome::mojom::SearchBox> binding_; DISALLOW_COPY_AND_ASSIGN(SearchBox); };
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc index d86f66e..dd6221e4 100644 --- a/chrome/renderer/searchbox/searchbox_extension.cc +++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -23,6 +23,7 @@ #include "chrome/renderer/searchbox/searchbox.h" #include "components/crx_file/id_util.h" #include "components/ntp_tiles/ntp_tile_source.h" +#include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_view.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" #include "third_party/WebKit/public/web/WebDocument.h" @@ -211,27 +212,24 @@ return obj; } -// Returns the render view for the current JS context if it matches |origin|, -// otherwise returns NULL. Used to restrict methods that access suggestions and -// most visited data to pages with origin chrome-search://most-visited and -// chrome-search://suggestions. -content::RenderView* GetRenderViewWithCheckedOrigin(const GURL& origin) { +// Returns the main frame of the render frame for the current JS context if it +// matches |origin|, otherwise returns NULL. Used to restrict methods that +// access suggestions and most visited data to pages with origin +// chrome-search://most-visited and chrome-search://suggestions. +content::RenderFrame* GetRenderFrameWithCheckedOrigin(const GURL& origin) { blink::WebLocalFrame* webframe = blink::WebLocalFrame::frameForCurrentContext(); if (!webframe) return NULL; - blink::WebView* webview = webframe->view(); - if (!webview) - return NULL; // Can happen during closing. - content::RenderView* render_view = content::RenderView::FromWebView(webview); - if (!render_view) + auto* main_frame = content::RenderFrame::FromWebFrame(webframe->localRoot()); + if (!main_frame || !main_frame->IsMainFrame()) return NULL; GURL url(webframe->document().url()); if (url.GetOrigin() != origin.GetOrigin()) return NULL; - return render_view; + return main_frame; } } // namespace @@ -398,8 +396,8 @@ v8::Isolate*, v8::Local<v8::String> name) override; - // Helper function to find the RenderView. May return NULL. - static content::RenderView* GetRenderView(); + // Helper function to find the main RenderFrame. May return NULL. + static content::RenderFrame* GetRenderFrame(); // Sends a Chrome identity check to the browser. static void CheckIsUserSignedInToChromeAs( @@ -418,7 +416,7 @@ const v8::FunctionCallbackInfo<v8::Value>& args); // Gets the raw data for a most visited item including its raw URL. - // GetRenderViewWithCheckedOrigin() enforces that only code in the origin + // GetRenderFrameWithCheckedOrigin() enforces that only code in the origin // chrome-search://most-visited can call this function. static void GetMostVisitedItemData( const v8::FunctionCallbackInfo<v8::Value>& args); @@ -629,70 +627,74 @@ } // static -content::RenderView* SearchBoxExtensionWrapper::GetRenderView() { +content::RenderFrame* SearchBoxExtensionWrapper::GetRenderFrame() { blink::WebLocalFrame* webframe = blink::WebLocalFrame::frameForCurrentContext(); if (!webframe) return NULL; - blink::WebView* webview = webframe->view(); - if (!webview) return NULL; // can happen during closing + auto* main_frame = content::RenderFrame::FromWebFrame(webframe->localRoot()); + if (!main_frame || !main_frame->IsMainFrame()) + return NULL; - return content::RenderView::FromWebView(webview); + return main_frame; } // static void SearchBoxExtensionWrapper::CheckIsUserSignedInToChromeAs( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; if (!args.Length() || args[0]->IsUndefined()) { ThrowInvalidParameters(args); return; } - DVLOG(1) << render_view << " CheckIsUserSignedInToChromeAs"; + DVLOG(1) << render_frame << " CheckIsUserSignedInToChromeAs"; - SearchBox::Get(render_view)->CheckIsUserSignedInToChromeAs( - V8ValueToUTF16(args[0])); + SearchBox::Get(render_frame) + ->CheckIsUserSignedInToChromeAs(V8ValueToUTF16(args[0])); } // static void SearchBoxExtensionWrapper::CheckIsUserSyncingHistory( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; - DVLOG(1) << render_view << " CheckIsUserSyncingHistory"; - SearchBox::Get(render_view)->CheckIsUserSyncingHistory(); + DVLOG(1) << render_frame << " CheckIsUserSyncingHistory"; + SearchBox::Get(render_frame)->CheckIsUserSyncingHistory(); } // static void SearchBoxExtensionWrapper::DeleteMostVisitedItem( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; if (!args.Length()) { ThrowInvalidParameters(args); return; } - DVLOG(1) << render_view + DVLOG(1) << render_frame << " DeleteMostVisitedItem: " << args[0]->ToInteger()->Value(); - SearchBox::Get(render_view)-> - DeleteMostVisitedItem(args[0]->ToInteger()->Value()); + SearchBox::Get(render_frame) + ->DeleteMostVisitedItem(args[0]->ToInteger()->Value()); } // static void SearchBoxExtensionWrapper::GetMostVisitedItems( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) return; - DVLOG(1) << render_view << " GetMostVisitedItems"; + DVLOG(1) << render_frame << " GetMostVisitedItems"; - const SearchBox* search_box = SearchBox::Get(render_view); + const SearchBox* search_box = SearchBox::Get(render_frame); std::vector<InstantMostVisitedItemIDPair> instant_mv_items; search_box->GetMostVisitedItems(&instant_mv_items); @@ -700,11 +702,10 @@ v8::Local<v8::Array> v8_mv_items = v8::Array::New(isolate, instant_mv_items.size()); for (size_t i = 0; i < instant_mv_items.size(); ++i) { - v8_mv_items->Set(i, - GenerateMostVisitedItem(isolate, - render_view->GetRoutingID(), - instant_mv_items[i].first, - instant_mv_items[i].second)); + v8_mv_items->Set( + i, GenerateMostVisitedItem( + isolate, render_frame->GetRenderView()->GetRoutingID(), + instant_mv_items[i].first, instant_mv_items[i].second)); } args.GetReturnValue().Set(v8_mv_items); } @@ -712,9 +713,10 @@ // static void SearchBoxExtensionWrapper::GetMostVisitedItemData( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderViewWithCheckedOrigin( + content::RenderFrame* render_frame = GetRenderFrameWithCheckedOrigin( GURL(chrome::kChromeSearchMostVisitedUrl)); - if (!render_view) return; + if (!render_frame) + return; // Need an rid argument. if (!args.Length() || !args[0]->IsNumber()) { @@ -722,25 +724,27 @@ return; } - DVLOG(1) << render_view << " GetMostVisitedItem"; + DVLOG(1) << render_frame << " GetMostVisitedItem"; InstantRestrictedID restricted_id = args[0]->IntegerValue(); InstantMostVisitedItem mv_item; - if (!SearchBox::Get(render_view)->GetMostVisitedItemWithID( - restricted_id, &mv_item)) { + if (!SearchBox::Get(render_frame) + ->GetMostVisitedItemWithID(restricted_id, &mv_item)) { return; } v8::Isolate* isolate = args.GetIsolate(); args.GetReturnValue().Set(GenerateMostVisitedItem( - isolate, render_view->GetRoutingID(), restricted_id, mv_item)); + isolate, render_frame->GetRenderView()->GetRoutingID(), restricted_id, + mv_item)); } // static void SearchBoxExtensionWrapper::GetQuery( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; - const base::string16& query = SearchBox::Get(render_view)->query(); - DVLOG(1) << render_view << " GetQuery: '" << query << "'"; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; + const base::string16& query = SearchBox::Get(render_frame)->query(); + DVLOG(1) << render_frame << " GetQuery: '" << query << "'"; v8::Isolate* isolate = args.GetIsolate(); args.GetReturnValue().Set(UTF16ToV8String(isolate, query)); } @@ -754,11 +758,12 @@ // static void SearchBoxExtensionWrapper::GetSearchRequestParams( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; const EmbeddedSearchRequestParams& params = - SearchBox::Get(render_view)->GetEmbeddedSearchRequestParams(); + SearchBox::Get(render_frame)->GetEmbeddedSearchRequestParams(); v8::Isolate* isolate = args.GetIsolate(); v8::Local<v8::Object> data = v8::Object::New(isolate); if (!params.search_query.empty()) { @@ -787,11 +792,12 @@ // static void SearchBoxExtensionWrapper::GetSuggestionToPrefetch( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; const InstantSuggestion& suggestion = - SearchBox::Get(render_view)->suggestion(); + SearchBox::Get(render_frame)->suggestion(); v8::Isolate* isolate = args.GetIsolate(); v8::Local<v8::Object> data = v8::Object::New(isolate); data->Set(v8::String::NewFromUtf8(isolate, "text"), @@ -804,12 +810,13 @@ // static void SearchBoxExtensionWrapper::GetThemeBackgroundInfo( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; - DVLOG(1) << render_view << " GetThemeBackgroundInfo"; + DVLOG(1) << render_frame << " GetThemeBackgroundInfo"; const ThemeBackgroundInfo& theme_info = - SearchBox::Get(render_view)->GetThemeBackgroundInfo(); + SearchBox::Get(render_frame)->GetThemeBackgroundInfo(); v8::Isolate* isolate = args.GetIsolate(); v8::Local<v8::Object> info = v8::Object::New(isolate); @@ -959,152 +966,162 @@ // static void SearchBoxExtensionWrapper::IsFocused( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; - bool is_focused = SearchBox::Get(render_view)->is_focused(); - DVLOG(1) << render_view << " IsFocused: " << is_focused; + bool is_focused = SearchBox::Get(render_frame)->is_focused(); + DVLOG(1) << render_frame << " IsFocused: " << is_focused; args.GetReturnValue().Set(is_focused); } // static void SearchBoxExtensionWrapper::IsInputInProgress( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; bool is_input_in_progress = - SearchBox::Get(render_view)->is_input_in_progress(); - DVLOG(1) << render_view << " IsInputInProgress: " << is_input_in_progress; + SearchBox::Get(render_frame)->is_input_in_progress(); + DVLOG(1) << render_frame << " IsInputInProgress: " << is_input_in_progress; args.GetReturnValue().Set(is_input_in_progress); } // static void SearchBoxExtensionWrapper::IsKeyCaptureEnabled( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; - args.GetReturnValue().Set(SearchBox::Get(render_view)-> - is_key_capture_enabled()); + args.GetReturnValue().Set( + SearchBox::Get(render_frame)->is_key_capture_enabled()); } // static void SearchBoxExtensionWrapper::LogEvent( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderViewWithCheckedOrigin( + content::RenderFrame* render_frame = GetRenderFrameWithCheckedOrigin( GURL(chrome::kChromeSearchMostVisitedUrl)); - if (!render_view) return; + if (!render_frame) + return; if (!args.Length() || !args[0]->IsNumber()) { ThrowInvalidParameters(args); return; } - DVLOG(1) << render_view << " LogEvent"; + DVLOG(1) << render_frame << " LogEvent"; if (args[0]->Uint32Value() <= NTP_EVENT_TYPE_LAST) { NTPLoggingEventType event = static_cast<NTPLoggingEventType>(args[0]->Uint32Value()); - SearchBox::Get(render_view)->LogEvent(event); + SearchBox::Get(render_frame)->LogEvent(event); } } // static void SearchBoxExtensionWrapper::LogMostVisitedImpression( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderViewWithCheckedOrigin( + content::RenderFrame* render_frame = GetRenderFrameWithCheckedOrigin( GURL(chrome::kChromeSearchMostVisitedUrl)); - if (!render_view) return; + if (!render_frame) + return; if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsNumber()) { ThrowInvalidParameters(args); return; } - DVLOG(1) << render_view << " LogMostVisitedImpression"; + DVLOG(1) << render_frame << " LogMostVisitedImpression"; if (args[1]->Uint32Value() <= static_cast<int>(ntp_tiles::NTPTileSource::LAST)) { ntp_tiles::NTPTileSource tile_source = static_cast<ntp_tiles::NTPTileSource>(args[1]->Uint32Value()); - SearchBox::Get(render_view)->LogMostVisitedImpression( - args[0]->IntegerValue(), tile_source); + SearchBox::Get(render_frame) + ->LogMostVisitedImpression(args[0]->IntegerValue(), tile_source); } } // static void SearchBoxExtensionWrapper::LogMostVisitedNavigation( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderViewWithCheckedOrigin( + content::RenderFrame* render_frame = GetRenderFrameWithCheckedOrigin( GURL(chrome::kChromeSearchMostVisitedUrl)); - if (!render_view) return; + if (!render_frame) + return; if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsNumber()) { ThrowInvalidParameters(args); return; } - DVLOG(1) << render_view << " LogMostVisitedNavigation"; + DVLOG(1) << render_frame << " LogMostVisitedNavigation"; if (args[1]->Uint32Value() <= static_cast<int>(ntp_tiles::NTPTileSource::LAST)) { ntp_tiles::NTPTileSource tile_source = static_cast<ntp_tiles::NTPTileSource>(args[1]->Uint32Value()); - SearchBox::Get(render_view)->LogMostVisitedNavigation( - args[0]->IntegerValue(), tile_source); + SearchBox::Get(render_frame) + ->LogMostVisitedNavigation(args[0]->IntegerValue(), tile_source); } } // static void SearchBoxExtensionWrapper::Paste( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; base::string16 text; if (!args[0]->IsUndefined()) text = V8ValueToUTF16(args[0]); - DVLOG(1) << render_view << " Paste: " << text; - SearchBox::Get(render_view)->Paste(text); + DVLOG(1) << render_frame << " Paste: " << text; + SearchBox::Get(render_frame)->Paste(text); } // static void SearchBoxExtensionWrapper::StartCapturingKeyStrokes( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; - DVLOG(1) << render_view << " StartCapturingKeyStrokes"; - SearchBox::Get(render_view)->StartCapturingKeyStrokes(); + DVLOG(1) << render_frame << " StartCapturingKeyStrokes"; + SearchBox::Get(render_frame)->StartCapturingKeyStrokes(); } // static void SearchBoxExtensionWrapper::StopCapturingKeyStrokes( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; - DVLOG(1) << render_view << " StopCapturingKeyStrokes"; - SearchBox::Get(render_view)->StopCapturingKeyStrokes(); + DVLOG(1) << render_frame << " StopCapturingKeyStrokes"; + SearchBox::Get(render_frame)->StopCapturingKeyStrokes(); } // static void SearchBoxExtensionWrapper::UndoAllMostVisitedDeletions( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) + return; - DVLOG(1) << render_view << " UndoAllMostVisitedDeletions"; - SearchBox::Get(render_view)->UndoAllMostVisitedDeletions(); + DVLOG(1) << render_frame << " UndoAllMostVisitedDeletions"; + SearchBox::Get(render_frame)->UndoAllMostVisitedDeletions(); } // static void SearchBoxExtensionWrapper::UndoMostVisitedDeletion( const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) { + content::RenderFrame* render_frame = GetRenderFrame(); + if (!render_frame) { return; } if (!args.Length()) { @@ -1112,8 +1129,8 @@ return; } - DVLOG(1) << render_view << " UndoMostVisitedDeletion"; - SearchBox::Get(render_view) + DVLOG(1) << render_frame << " UndoMostVisitedDeletion"; + SearchBox::Get(render_frame) ->UndoMostVisitedDeletion(args[0]->ToInteger()->Value()); }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index f7c7431c..d5d16ed 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3440,6 +3440,7 @@ ":test_support", ":test_support_unit", "//base/test:test_support", + "//chrome/common:test_support", "//components/browser_sync:test_support", "//components/content_settings/core/test:test_support", "//components/resources",
diff --git a/chrome/typemaps.gni b/chrome/typemaps.gni new file mode 100644 index 0000000..9a20fe5 --- /dev/null +++ b/chrome/typemaps.gni
@@ -0,0 +1,5 @@ +# Copyright 2016 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. + +typemaps = [ "//chrome/common/instant.typemap" ]
diff --git a/components/arc/ime/arc_ime_service.cc b/components/arc/ime/arc_ime_service.cc index 7d49a17..e2ffb34 100644 --- a/components/arc/ime/arc_ime_service.cc +++ b/components/arc/ime/arc_ime_service.cc
@@ -21,17 +21,36 @@ namespace arc { -ArcImeService::ArcWindowDetector::~ArcWindowDetector() = default; +namespace { -bool ArcImeService::ArcWindowDetector::IsArcWindow( - const aura::Window* window) const { - return exo::Surface::AsSurface(window); -} +class ArcWindowDelegateImpl : public ArcImeService::ArcWindowDelegate { + public: + explicit ArcWindowDelegateImpl(ArcImeService* ime_service) + : ime_service_(ime_service) {} -bool ArcImeService::ArcWindowDetector::IsArcTopLevelWindow( - const aura::Window* window) const { - return exo::ShellSurface::GetMainSurface(window); -} + ~ArcWindowDelegateImpl() override = default; + + bool IsArcWindow( + const aura::Window* window) const override { + return exo::Surface::AsSurface(window) || + exo::ShellSurface::GetMainSurface(window); + } + + void RegisterFocusObserver() override { + exo::WMHelper::GetInstance()->AddFocusObserver(ime_service_); + } + + void UnregisterFocusObserver() override { + exo::WMHelper::GetInstance()->RemoveFocusObserver(ime_service_); + } + + private: + ArcImeService* const ime_service_; + + DISALLOW_COPY_AND_ASSIGN(ArcWindowDelegateImpl); +}; + +} // anonymous namespace //////////////////////////////////////////////////////////////////////////////// // ArcImeService main implementation: @@ -39,7 +58,7 @@ ArcImeService::ArcImeService(ArcBridgeService* bridge_service) : ArcService(bridge_service), ime_bridge_(new ArcImeBridgeImpl(this, bridge_service)), - arc_window_detector_(new ArcWindowDetector()), + arc_window_delegate_(new ArcWindowDelegateImpl(this)), ime_type_(ui::TEXT_INPUT_TYPE_NONE), has_composition_text_(false), keyboard_controller_(nullptr), @@ -55,8 +74,8 @@ if (input_method) input_method->DetachTextInputClient(this); - if (is_focus_observer_installed_ && exo::WMHelper::GetInstance()) - exo::WMHelper::GetInstance()->RemoveFocusObserver(this); + if (is_focus_observer_installed_) + arc_window_delegate_->UnregisterFocusObserver(); aura::Env* env = aura::Env::GetInstanceDontCreate(); if (env) env->RemoveObserver(this); @@ -78,9 +97,9 @@ test_input_method_ = test_input_method; } -void ArcImeService::SetArcWindowDetectorForTesting( - std::unique_ptr<ArcWindowDetector> detector) { - arc_window_detector_ = std::move(detector); +void ArcImeService::SetArcWindowDelegateForTesting( + std::unique_ptr<ArcWindowDelegate> delegate) { + arc_window_delegate_= std::move(delegate); } ui::InputMethod* ArcImeService::GetInputMethod() { @@ -96,9 +115,9 @@ // Overridden from aura::EnvObserver: void ArcImeService::OnWindowInitialized(aura::Window* new_window) { - if (arc_window_detector_->IsArcWindow(new_window)) { + if (arc_window_delegate_->IsArcWindow(new_window)) { if (!is_focus_observer_installed_) { - exo::WMHelper::GetInstance()->AddFocusObserver(this); + arc_window_delegate_->RegisterFocusObserver(); is_focus_observer_installed_ = true; } } @@ -116,16 +135,12 @@ void ArcImeService::OnWindowFocused(aura::Window* gained_focus, aura::Window* lost_focus) { - // The Aura focus may or may not be on sub-window of the toplevel ARC++ frame. - // To handle all cases, judge the state by always climbing up to the toplevel. - gained_focus = gained_focus ? gained_focus->GetToplevelWindow() : nullptr; - lost_focus = lost_focus ? lost_focus->GetToplevelWindow() : nullptr; if (lost_focus == gained_focus) return; const bool detach = (lost_focus && focused_arc_window_.Contains(lost_focus)); const bool attach = - (gained_focus && arc_window_detector_->IsArcTopLevelWindow(gained_focus)); + (gained_focus && arc_window_delegate_->IsArcWindow(gained_focus)); // TODO(kinaba): Implicit dependency in GetInputMethod as described below is // confusing. Consider getting InputMethod directly from lost_ or gained_focus @@ -288,7 +303,11 @@ cursor_rect_, 1 / window->layer()->device_scale_factor()); // Add the offset of the window showing the ARC app. - converted.Offset(window->GetBoundsInScreen().OffsetFromOrigin()); + // TODO(yoshiki): Support for non-arc toplevel window. The following code do + // not work correctly with arc windows inside non-arc toplevel window (eg. + // notification). + converted.Offset( + window->GetToplevelWindow()->GetBoundsInScreen().OffsetFromOrigin()); return converted; }
diff --git a/components/arc/ime/arc_ime_service.h b/components/arc/ime/arc_ime_service.h index 12610a8b..86784b7 100644 --- a/components/arc/ime/arc_ime_service.h +++ b/components/arc/ime/arc_ime_service.h
@@ -45,11 +45,12 @@ explicit ArcImeService(ArcBridgeService* bridge_service); ~ArcImeService() override; - class ArcWindowDetector { + class ArcWindowDelegate { public: - virtual ~ArcWindowDetector(); - virtual bool IsArcTopLevelWindow(const aura::Window* window) const; - virtual bool IsArcWindow(const aura::Window* window) const; + virtual ~ArcWindowDelegate() {} + virtual bool IsArcWindow(const aura::Window* window) const = 0; + virtual void RegisterFocusObserver() = 0; + virtual void UnregisterFocusObserver() = 0; }; // Injects the custom IPC bridge object for testing purpose only. @@ -58,9 +59,9 @@ // Injects the custom IME for testing purpose only. void SetInputMethodForTesting(ui::InputMethod* test_input_method); - // Injects the custom detector for ARC windows, for testing purpose only. - void SetArcWindowDetectorForTesting( - std::unique_ptr<ArcWindowDetector> detector); + // Injects the custom delegate for ARC windows, for testing purpose only. + void SetArcWindowDelegateForTesting( + std::unique_ptr<ArcWindowDelegate> delegate); // Overridden from aura::EnvObserver: void OnWindowInitialized(aura::Window* new_window) override; @@ -118,7 +119,7 @@ ui::InputMethod* GetInputMethod(); std::unique_ptr<ArcImeBridge> ime_bridge_; - std::unique_ptr<ArcWindowDetector> arc_window_detector_; + std::unique_ptr<ArcWindowDelegate> arc_window_delegate_; ui::TextInputType ime_type_; gfx::Rect cursor_rect_; bool has_composition_text_;
diff --git a/components/arc/ime/arc_ime_service_unittest.cc b/components/arc/ime/arc_ime_service_unittest.cc index 086bea93..1b2ea0e3 100644 --- a/components/arc/ime/arc_ime_service_unittest.cc +++ b/components/arc/ime/arc_ime_service_unittest.cc
@@ -98,23 +98,25 @@ // Helper class for testing the window focus tracking feature of ArcImeService, // not depending on the full setup of Exo and Ash. -class FakeArcWindowDetector : public ArcImeService::ArcWindowDetector { +class FakeArcWindowDelegate : public ArcImeService::ArcWindowDelegate { public: - FakeArcWindowDetector() : next_id_(0) {} + FakeArcWindowDelegate() : next_id_(0) {} - bool IsArcWindow(const aura::Window* window) const override { return false; } - bool IsArcTopLevelWindow(const aura::Window* window) const override { - return arc_toplevel_window_id_.count(window->id()); + bool IsArcWindow(const aura::Window* window) const override { + return arc_window_id_.count(window->id()); } - std::unique_ptr<aura::Window> CreateFakeArcTopLevelWindow() { + void RegisterFocusObserver() override {} + void UnregisterFocusObserver() override {} + + std::unique_ptr<aura::Window> CreateFakeArcWindow() { const int id = next_id_++; - arc_toplevel_window_id_.insert(id); + arc_window_id_.insert(id); return base::WrapUnique(aura::test::CreateTestWindowWithDelegate( &dummy_delegate_, id, gfx::Rect(), nullptr)); } - std::unique_ptr<aura::Window> CreateFakeNonArcTopLevelWindow() { + std::unique_ptr<aura::Window> CreateFakeNonArcWindow() { const int id = next_id_++; return base::WrapUnique(aura::test::CreateTestWindowWithDelegate( &dummy_delegate_, id, gfx::Rect(), nullptr)); @@ -123,14 +125,14 @@ private: aura::test::TestWindowDelegate dummy_delegate_; int next_id_; - std::set<int> arc_toplevel_window_id_; + std::set<int> arc_window_id_; }; } // namespace class ArcImeServiceTest : public testing::Test { public: - ArcImeServiceTest() {} + ArcImeServiceTest() = default; protected: std::unique_ptr<ArcBridgeService> arc_bridge_service_; @@ -138,7 +140,7 @@ std::unique_ptr<ArcImeService> instance_; FakeArcImeBridge* fake_arc_ime_bridge_; // Owned by |instance_| - FakeArcWindowDetector* fake_window_detector_; // Owned by |instance_| + FakeArcWindowDelegate* fake_window_delegate_; // Owned by |instance_| std::unique_ptr<aura::Window> arc_win_; private: @@ -151,15 +153,15 @@ fake_input_method_ = base::MakeUnique<FakeInputMethod>(); instance_->SetInputMethodForTesting(fake_input_method_.get()); - fake_window_detector_ = new FakeArcWindowDetector(); - instance_->SetArcWindowDetectorForTesting( - base::WrapUnique(fake_window_detector_)); - arc_win_ = fake_window_detector_->CreateFakeArcTopLevelWindow(); + fake_window_delegate_ = new FakeArcWindowDelegate(); + instance_->SetArcWindowDelegateForTesting( + base::WrapUnique(fake_window_delegate_)); + arc_win_ = fake_window_delegate_->CreateFakeArcWindow(); } void TearDown() override { arc_win_.reset(); - fake_window_detector_ = nullptr; + fake_window_delegate_ = nullptr; fake_arc_ime_bridge_ = nullptr; instance_.reset(); arc_bridge_service_.reset(); @@ -233,9 +235,9 @@ TEST_F(ArcImeServiceTest, WindowFocusTracking) { std::unique_ptr<aura::Window> arc_win2 = - fake_window_detector_->CreateFakeArcTopLevelWindow(); + fake_window_delegate_->CreateFakeArcWindow(); std::unique_ptr<aura::Window> nonarc_win = - fake_window_detector_->CreateFakeNonArcTopLevelWindow(); + fake_window_delegate_->CreateFakeNonArcWindow(); // ARC window is focused. ArcImeService is set as the text input client. instance_->OnWindowFocused(arc_win_.get(), nullptr);
diff --git a/components/arc/metrics/arc_metrics_service.h b/components/arc/metrics/arc_metrics_service.h index 7ad1a0be3..df59122 100644 --- a/components/arc/metrics/arc_metrics_service.h +++ b/components/arc/metrics/arc_metrics_service.h
@@ -64,6 +64,8 @@ void OnInstanceClosed() override; ArcMetricsService* arc_metrics_service_; + + DISALLOW_COPY_AND_ASSIGN(ProcessObserver); }; mojo::Binding<mojom::MetricsHost> binding_;
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc index 6dc7a550..9537ec6 100644 --- a/content/browser/android/content_view_core_impl.cc +++ b/content/browser/android/content_view_core_impl.cc
@@ -1300,7 +1300,7 @@ int composition_start, int composition_end, bool show_ime_if_needed, - bool is_non_ime_change) { + bool reply_to_request) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); if (obj.is_null()) @@ -1310,8 +1310,7 @@ Java_ContentViewCore_updateImeAdapter( env, obj, native_ime_adapter, text_input_type, text_input_flags, text_input_mode, jstring_text, selection_start, selection_end, - composition_start, composition_end, show_ime_if_needed, - is_non_ime_change); + composition_start, composition_end, show_ime_if_needed, reply_to_request); } void ContentViewCoreImpl::SetAccessibilityEnabled(
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h index f76b041..18d55d4 100644 --- a/content/browser/android/content_view_core_impl.h +++ b/content/browser/android/content_view_core_impl.h
@@ -334,7 +334,7 @@ int composition_start, int composition_end, bool show_ime_if_needed, - bool is_non_ime_change); + bool reply_to_request); void OnBackgroundColorChanged(SkColor color); bool HasFocus();
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index b1dbc1a4..fc8f8812 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -601,7 +601,7 @@ } else { // The channel may not be initialized in some tests environments. In this // case we set up a dummy interface provider. - mojo::GetDummyProxyForTesting(&remote_interfaces); + mojo::GetIsolatedProxy(&remote_interfaces); } remote_associated_interfaces_.reset(new AssociatedInterfaceProviderImpl( std::move(remote_interfaces)));
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 6d4b39c..a016d8f 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -783,7 +783,7 @@ GetNativeImeAdapter(), static_cast<int>(state.type), state.flags, state.mode, state.value, state.selection_start, state.selection_end, state.composition_start, state.composition_end, state.show_ime_if_needed, - state.is_non_ime_change); + state.reply_to_request); } void RenderWidgetHostViewAndroid::OnImeCompositionRangeChanged(
diff --git a/content/common/text_input_state.cc b/content/common/text_input_state.cc index ec5fbfe9..f6044bf 100644 --- a/content/common/text_input_state.cc +++ b/content/common/text_input_state.cc
@@ -16,7 +16,7 @@ composition_end(-1), can_compose_inline(true), show_ime_if_needed(false), - is_non_ime_change(true) {} + reply_to_request(false) {} TextInputState::TextInputState(const TextInputState& other) = default;
diff --git a/content/common/text_input_state.h b/content/common/text_input_state.h index 0fdc32b..16b4994 100644 --- a/content/common/text_input_state.h +++ b/content/common/text_input_state.h
@@ -54,9 +54,8 @@ // TEXT_INPUT_TYPE_NONE). bool show_ime_if_needed; - // Whether this change is originated from non-IME (e.g., Javascript, - // Autofill). - bool is_non_ime_change; + // Whether or not this is a reply to a request from IME. + bool reply_to_request; }; } // namespace content
diff --git a/content/common/view_messages.h b/content/common/view_messages.h index 7bf0b14b..60e2313f 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h
@@ -286,7 +286,7 @@ IPC_STRUCT_TRAITS_MEMBER(composition_end) IPC_STRUCT_TRAITS_MEMBER(can_compose_inline) IPC_STRUCT_TRAITS_MEMBER(show_ime_if_needed) - IPC_STRUCT_TRAITS_MEMBER(is_non_ime_change) + IPC_STRUCT_TRAITS_MEMBER(reply_to_request) IPC_STRUCT_TRAITS_END() IPC_STRUCT_BEGIN(ViewHostMsg_CreateWorker_Params)
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java index af892bf..9f97f23 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -1914,7 +1914,7 @@ private void updateImeAdapter(long nativeImeAdapterAndroid, int textInputType, int textInputFlags, int textInputMode, String text, int selectionStart, int selectionEnd, int compositionStart, int compositionEnd, boolean showImeIfNeeded, - boolean isNonImeChange) { + boolean replyToRequest) { try { TraceEvent.begin("ContentViewCore.updateImeAdapter"); boolean focusedNodeEditable = (textInputType != TextInputType.NONE); @@ -1924,7 +1924,7 @@ mImeAdapter.updateKeyboardVisibility( textInputType, textInputFlags, textInputMode, showImeIfNeeded); mImeAdapter.updateState(text, selectionStart, selectionEnd, compositionStart, - compositionEnd, isNonImeChange); + compositionEnd, replyToRequest); boolean editableToggled = (focusedNodeEditable != isFocusedNodeEditable()); mSelectionPopupController.updateSelectionState(focusedNodeEditable,
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ChromiumBaseInputConnection.java b/content/public/android/java/src/org/chromium/content/browser/input/ChromiumBaseInputConnection.java index eaedcac..4e10479 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/ChromiumBaseInputConnection.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/ChromiumBaseInputConnection.java
@@ -46,10 +46,10 @@ * composition. * @param compositionEnd The character offset of the composition end, or -1 if there is no * selection. - * @param isNonImeChange True when the update was caused by non-IME (e.g. Javascript). + * @param replyToRequest True when the update was made in a reply to IME's request. */ void updateStateOnUiThread(String text, int selectionStart, int selectionEnd, - int compositionStart, int compositionEnd, boolean singleLine, boolean isNonImeChange); + int compositionStart, int compositionEnd, boolean singleLine, boolean replyToRequest); /** * Send key event on UI thread.
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java index fd5833f..df58b85a1 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
@@ -304,10 +304,10 @@ * composition. * @param compositionEnd The character offset of the composition end, or -1 if there is no * selection. - * @param isNonImeChange True when the update was caused by non-IME (e.g. Javascript). + * @param replyToRequest True when the update was requested by IME. */ public void updateState(String text, int selectionStart, int selectionEnd, int compositionStart, - int compositionEnd, boolean isNonImeChange) { + int compositionEnd, boolean replyToRequest) { if (mCursorAnchorInfoController != null && (!TextUtils.equals(mLastText, text) || mLastSelectionStart != selectionStart || mLastSelectionEnd != selectionEnd || mLastCompositionStart != compositionStart @@ -324,7 +324,7 @@ boolean singleLine = mTextInputType != TextInputType.TEXT_AREA && mTextInputType != TextInputType.CONTENT_EDITABLE; mInputConnection.updateStateOnUiThread(text, selectionStart, selectionEnd, compositionStart, - compositionEnd, singleLine, isNonImeChange); + compositionEnd, singleLine, replyToRequest); } /**
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/TextInputState.java b/content/public/android/java/src/org/chromium/content/browser/input/TextInputState.java index 38684df..d205485 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/TextInputState.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/TextInputState.java
@@ -17,10 +17,10 @@ private final Range mSelection; private final Range mComposition; private final boolean mSingleLine; - private final boolean mFromIme; + private final boolean mReplyToRequest; public TextInputState(CharSequence text, Range selection, Range composition, boolean singleLine, - boolean fromIme) { + boolean replyToRequest) { selection.clamp(0, text.length()); if (composition.start() != -1 || composition.end() != -1) { composition.clamp(0, text.length()); @@ -29,7 +29,7 @@ mSelection = selection; mComposition = composition; mSingleLine = singleLine; - mFromIme = fromIme; + mReplyToRequest = replyToRequest; } public CharSequence text() { @@ -48,8 +48,8 @@ return mSingleLine; } - public boolean fromIme() { - return mFromIme; + public boolean replyToRequest() { + return mReplyToRequest; } public CharSequence getSelectedText() { @@ -74,13 +74,13 @@ if (t == this) return true; return TextUtils.equals(mText, t.mText) && mSelection.equals(t.mSelection) && mComposition.equals(t.mComposition) && mSingleLine == t.mSingleLine - && mFromIme == t.mFromIme; + && mReplyToRequest == t.mReplyToRequest; } @Override public int hashCode() { return mText.hashCode() * 7 + mSelection.hashCode() * 11 + mComposition.hashCode() * 13 - + (mSingleLine ? 19 : 0) + (mFromIme ? 23 : 0); + + (mSingleLine ? 19 : 0) + (mReplyToRequest ? 23 : 0); } @SuppressWarnings("unused") @@ -90,8 +90,8 @@ @Override public String toString() { - return String.format(Locale.US, "TextInputState {[%s] SEL%s COM%s %s %s}", mText, - mSelection, mComposition, mSingleLine ? "SIN" : "MUL", - mFromIme ? "fromIME" : "NOTfromIME"); + return String.format(Locale.US, "TextInputState {[%s] SEL%s COM%s %s%s}", mText, mSelection, + mComposition, mSingleLine ? "SIN" : "MUL", + mReplyToRequest ? " ReplyToRequest" : ""); } } \ No newline at end of file
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java b/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java index 92c24c983..330863f770 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnection.java
@@ -114,22 +114,21 @@ } @Override - public void updateStateOnUiThread(String text, final int selectionStart, - final int selectionEnd, final int compositionStart, final int compositionEnd, - boolean singleLine, final boolean isNonImeChange) { + public void updateStateOnUiThread(String text, final int selectionStart, final int selectionEnd, + final int compositionStart, final int compositionEnd, boolean singleLine, + final boolean replyToRequest) { ImeUtils.checkOnUiThread(); // crbug.com/663880: Non-breaking spaces can cause the IME to get confused. Replace with // normal spaces. text = text.replace('\u00A0', ' '); - mCachedTextInputState = - new TextInputState(text, new Range(selectionStart, selectionEnd), - new Range(compositionStart, compositionEnd), singleLine, !isNonImeChange); + mCachedTextInputState = new TextInputState(text, new Range(selectionStart, selectionEnd), + new Range(compositionStart, compositionEnd), singleLine, replyToRequest); if (DEBUG_LOGS) Log.w(TAG, "updateState: %s", mCachedTextInputState); addToQueueOnUiThread(mCachedTextInputState); - if (isNonImeChange) { + if (!replyToRequest) { mHandler.post(mProcessPendingInputStatesRunnable); } } @@ -270,7 +269,7 @@ if (state.shouldUnblock()) { if (DEBUG_LOGS) Log.w(TAG, "blockAndGetStateUpdate: unblocked"); return null; - } else if (state.fromIme()) { + } else if (state.replyToRequest()) { if (shouldUpdateSelection) updateSelection(state); if (DEBUG_LOGS) Log.w(TAG, "blockAndGetStateUpdate done: %d", mQueue.size()); return state;
diff --git a/content/public/android/junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java b/content/public/android/junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java index b452b80..a6c32806 100644 --- a/content/public/android/junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java +++ b/content/public/android/junit/src/org/chromium/content/browser/input/ThreadedInputConnectionTest.java
@@ -80,12 +80,12 @@ mInOrder.verify(mImeAdapter).sendCompositionToNative("hello", 1, false, 0); // Renderer updates states asynchronously. - mConnection.updateStateOnUiThread("hello", 5, 5, 0, 5, true, true); + mConnection.updateStateOnUiThread("hello", 5, 5, 0, 5, true, false); mInOrder.verify(mImeAdapter).updateSelection(5, 5, 0, 5); assertEquals(0, mConnection.getQueueForTest().size()); // Prepare to call requestTextInputStateUpdate. - mConnection.updateStateOnUiThread("hello", 5, 5, 0, 5, true, false); + mConnection.updateStateOnUiThread("hello", 5, 5, 0, 5, true, true); assertEquals(1, mConnection.getQueueForTest().size()); when(mImeAdapter.requestTextInputStateUpdate()).thenReturn(true); @@ -95,11 +95,11 @@ // IME app calls finishComposingText(). mConnection.finishComposingText(); mInOrder.verify(mImeAdapter).finishComposingText(); - mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, true); + mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, false); mInOrder.verify(mImeAdapter).updateSelection(5, 5, -1, -1); // Prepare to call requestTextInputStateUpdate. - mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, false); + mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, true); assertEquals(1, mConnection.getQueueForTest().size()); when(mImeAdapter.requestTextInputStateUpdate()).thenReturn(true); @@ -124,7 +124,7 @@ @Feature({"TextInput"}) public void testRenderChangeUpdatesSelection() { // User moves the cursor. - mConnection.updateStateOnUiThread("hello", 4, 4, -1, -1, true, true); + mConnection.updateStateOnUiThread("hello", 4, 4, -1, -1, true, false); mInOrder.verify(mImeAdapter).updateSelection(4, 4, -1, -1); assertEquals(0, mConnection.getQueueForTest().size()); } @@ -139,7 +139,7 @@ mInOrder.verify(mImeAdapter).sendCompositionToNative("hello", 1, true, 0); // Renderer updates states asynchronously. - mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, true); + mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, false); mInOrder.verify(mImeAdapter, never()).updateSelection(5, 5, -1, -1); assertEquals(0, mConnection.getQueueForTest().size()); @@ -154,7 +154,7 @@ mInOrder.verify(mImeAdapter, never()).updateSelection(4, 4, -1, -1); // Prepare to call requestTextInputStateUpdate. - mConnection.updateStateOnUiThread("hello", 4, 4, -1, -1, true, false); + mConnection.updateStateOnUiThread("hello", 4, 4, -1, -1, true, true); assertEquals(1, mConnection.getQueueForTest().size()); when(mImeAdapter.requestTextInputStateUpdate()).thenReturn(true); @@ -212,7 +212,7 @@ } })); // Or it could be. - mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, true); + mConnection.updateStateOnUiThread("hello", 5, 5, -1, -1, true, false); assertEquals("hello", ThreadUtils.runOnUiThreadBlockingNoException(new Callable<CharSequence>() { @Override
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc index c7ba2ec..d0af148f 100644 --- a/content/public/test/mock_render_process_host.cc +++ b/content/public/test/mock_render_process_host.cc
@@ -310,7 +310,7 @@ mojom::Renderer* MockRenderProcessHost::GetRendererInterface() { if (!renderer_interface_) { renderer_interface_.reset(new mojom::RendererAssociatedPtr); - mojo::GetDummyProxyForTesting(renderer_interface_.get()); + mojo::GetIsolatedProxy(renderer_interface_.get()); } return renderer_interface_->get(); }
diff --git a/content/public/test/text_input_test_utils.cc b/content/public/test/text_input_test_utils.cc index 6e734b9..e37b5dc 100644 --- a/content/public/test/text_input_test_utils.cc +++ b/content/public/test/text_input_test_utils.cc
@@ -396,10 +396,6 @@ text_input_state_->show_ime_if_needed = show_ime_if_needed; } -void TextInputStateSender::SetIsNonImeChange(bool is_non_ime_change) { - text_input_state_->is_non_ime_change = is_non_ime_change; -} - TestInputMethodObserver::TestInputMethodObserver() {} TestInputMethodObserver::~TestInputMethodObserver() {}
diff --git a/content/public/test/text_input_test_utils.h b/content/public/test/text_input_test_utils.h index a552dd4..6c0c2bc 100644 --- a/content/public/test/text_input_test_utils.h +++ b/content/public/test/text_input_test_utils.h
@@ -160,7 +160,6 @@ void SetFlags(int flags); void SetCanComposeInline(bool can_compose_inline); void SetShowImeIfNeeded(bool show_ime_if_needed); - void SetIsNonImeChange(bool is_non_ime_change); private: std::unique_ptr<TextInputState> text_input_state_;
diff --git a/content/renderer/ime_event_guard.cc b/content/renderer/ime_event_guard.cc index b33183f..b2d78c6b 100644 --- a/content/renderer/ime_event_guard.cc +++ b/content/renderer/ime_event_guard.cc
@@ -13,7 +13,7 @@ // it from other updates so that we can wait for it safely. So it is false by // default. ImeEventGuard::ImeEventGuard(RenderWidget* widget) - : widget_(widget), show_ime_(false), from_ime_(false) { + : widget_(widget), show_virtual_keyboard_(false), reply_to_request_(false) { widget_->OnImeEventGuardStart(this); }
diff --git a/content/renderer/ime_event_guard.h b/content/renderer/ime_event_guard.h index 6d69912..1df77f34 100644 --- a/content/renderer/ime_event_guard.h +++ b/content/renderer/ime_event_guard.h
@@ -15,15 +15,14 @@ explicit ImeEventGuard(RenderWidget* widget); ~ImeEventGuard(); - bool show_ime() const { return show_ime_; } - bool from_ime() const { return from_ime_; } - void set_show_ime(bool show_ime) { show_ime_ = show_ime; } - void set_from_ime(bool from_ime) { from_ime_ = from_ime; } + bool show_virtual_keyboard() const { return show_virtual_keyboard_; } + bool reply_to_request() const { return reply_to_request_; } + void set_show_virtual_keyboard(bool show) { show_virtual_keyboard_ = show; } private: RenderWidget* widget_; - bool show_ime_; - bool from_ime_; + bool show_virtual_keyboard_; + bool reply_to_request_; }; }
diff --git a/content/renderer/input/render_widget_input_handler.cc b/content/renderer/input/render_widget_input_handler.cc index 6e1ad1e0..63e11df6 100644 --- a/content/renderer/input/render_widget_input_handler.cc +++ b/content/renderer/input/render_widget_input_handler.cc
@@ -279,7 +279,7 @@ static_cast<const WebKeyboardEvent&>(input_event); if (key_event.nativeKeyCode == AKEYCODE_DPAD_CENTER && widget_->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE) { - widget_->showImeIfNeeded(); + widget_->showVirtualKeyboard(); prevent_default = true; } #endif @@ -415,8 +415,7 @@ // of a processed touch end event. if (input_event.type() == WebInputEvent::TouchEnd && processed != WebInputEventResult::NotHandled) { - delegate_->UpdateTextInputState(ShowIme::IF_NEEDED, - ChangeSource::FROM_NON_IME); + delegate_->ShowVirtualKeyboard(); } #elif defined(USE_AURA) // Show the virtual keyboard if enabled and a user gesture triggers a focus @@ -424,7 +423,7 @@ if (processed != WebInputEventResult::NotHandled && (input_event.type() == WebInputEvent::TouchEnd || input_event.type() == WebInputEvent::MouseUp)) { - delegate_->UpdateTextInputState(ShowIme::IF_NEEDED, ChangeSource::FROM_IME); + delegate_->ShowVirtualKeyboard(); } #endif
diff --git a/content/renderer/input/render_widget_input_handler_delegate.h b/content/renderer/input/render_widget_input_handler_delegate.h index 4c245f2..d1fd030 100644 --- a/content/renderer/input/render_widget_input_handler_delegate.h +++ b/content/renderer/input/render_widget_input_handler_delegate.h
@@ -24,13 +24,6 @@ class RenderWidgetInputHandler; -enum class ShowIme { IF_NEEDED, HIDE_IME }; - -enum class ChangeSource { - FROM_NON_IME, - FROM_IME, -}; - // Consumers of RenderWidgetInputHandler implement this delegate in order to // transport input handling information across processes. class CONTENT_EXPORT RenderWidgetInputHandlerDelegate { @@ -68,15 +61,14 @@ // Notifies the delegate of the |input_handler| managing it. virtual void SetInputHandler(RenderWidgetInputHandler* input_handler) = 0; - // |show_ime| should be ShowIme::IF_NEEDED iff the update may cause the ime to - // be displayed, e.g. after a tap on an input field on mobile. - // |change_source| should be ChangeSource::FROM_NON_IME when the renderer has - // to wait for the browser to acknowledge the change before the renderer - // handles any more IME events. This is when the text change did not originate - // from the IME in the browser side, such as changes by JavaScript or - // autofill. - virtual void UpdateTextInputState(ShowIme show_ime, - ChangeSource change_source) = 0; + // Call this if virtual keyboard should be displayed, e.g. after a tap on an + // input field on mobile. Note that we do this just by setting a bit in + // text input state and update it to the browser such that browser process can + // be up to date when showing virtual keyboard. + virtual void ShowVirtualKeyboard() = 0; + + // Send an update of text input state to the browser process. + virtual void UpdateTextInputState() = 0; // Notifies that a gesture event is about to be handled. // Returns true if no further handling is needed. In that case, the event
diff --git a/content/renderer/mus/render_widget_mus_connection.cc b/content/renderer/mus/render_widget_mus_connection.cc index b416e755..24594cb 100644 --- a/content/renderer/mus/render_widget_mus_connection.cc +++ b/content/renderer/mus/render_widget_mus_connection.cc
@@ -129,9 +129,11 @@ input_handler_ = input_handler; } -void RenderWidgetMusConnection::UpdateTextInputState( - ShowIme show_ime, - ChangeSource change_source) { +void RenderWidgetMusConnection::ShowVirtualKeyboard() { + NOTIMPLEMENTED(); +} + +void RenderWidgetMusConnection::UpdateTextInputState() { NOTIMPLEMENTED(); }
diff --git a/content/renderer/mus/render_widget_mus_connection.h b/content/renderer/mus/render_widget_mus_connection.h index bcf2d1c..7cf7bc9 100644 --- a/content/renderer/mus/render_widget_mus_connection.h +++ b/content/renderer/mus/render_widget_mus_connection.h
@@ -57,8 +57,8 @@ void NotifyInputEventHandled(blink::WebInputEvent::Type handled_type, InputEventAckState ack_result) override; void SetInputHandler(RenderWidgetInputHandler* input_handler) override; - void UpdateTextInputState(ShowIme show_ime, - ChangeSource change_source) override; + void ShowVirtualKeyboard() override; + void UpdateTextInputState() override; bool WillHandleGestureEvent(const blink::WebGestureEvent& event) override; bool WillHandleMouseEvent(const blink::WebMouseEvent& event) override;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index c0adcb2..ce8f2725 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -1305,8 +1305,7 @@ if (instance != focused_pepper_plugin_) return; - GetRenderWidget()->UpdateTextInputState(ShowIme::HIDE_IME, - ChangeSource::FROM_NON_IME); + GetRenderWidget()->UpdateTextInputState(); FocusedNodeChangedForAccessibility(WebNode()); } @@ -4043,8 +4042,7 @@ // was changed, and SyncSelectionIfRequired may send SelectionChanged // to notify the selection was changed. Focus change should be notified // before selection change. - GetRenderWidget()->UpdateTextInputState(ShowIme::HIDE_IME, - ChangeSource::FROM_NON_IME); + GetRenderWidget()->UpdateTextInputState(); SyncSelectionIfRequired(); } @@ -6811,8 +6809,7 @@ GetRenderWidget()->set_focused_pepper_plugin(focused_pepper_plugin_); - GetRenderWidget()->UpdateTextInputState(ShowIme::HIDE_IME, - ChangeSource::FROM_NON_IME); + GetRenderWidget()->UpdateTextInputState(); GetRenderWidget()->UpdateSelectionBounds(); }
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc index af65af0..3970bb9e 100644 --- a/content/renderer/render_view_browsertest.cc +++ b/content/renderer/render_view_browsertest.cc
@@ -1092,7 +1092,7 @@ // Update the IME status and verify if our IME backend sends an IPC message // to activate IMEs. - view()->UpdateTextInputState(ShowIme::HIDE_IME, ChangeSource::FROM_NON_IME); + view()->UpdateTextInputState(); const IPC::Message* msg = render_thread_->sink().GetMessageAt(0); EXPECT_TRUE(msg != NULL); EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type()); @@ -1113,7 +1113,7 @@ // Update the IME status and verify if our IME backend sends an IPC message // to de-activate IMEs. - view()->UpdateTextInputState(ShowIme::HIDE_IME, ChangeSource::FROM_NON_IME); + view()->UpdateTextInputState(); msg = render_thread_->sink().GetMessageAt(0); EXPECT_TRUE(msg != NULL); EXPECT_EQ(ViewHostMsg_TextInputStateChanged::ID, msg->type()); @@ -1136,8 +1136,7 @@ // Update the IME status and verify if our IME backend sends an IPC // message to activate IMEs. - view()->UpdateTextInputState(ShowIme::HIDE_IME, - ChangeSource::FROM_NON_IME); + view()->UpdateTextInputState(); ProcessPendingMessages(); const IPC::Message* msg = render_thread_->sink().GetMessageAt(0); EXPECT_TRUE(msg != NULL); @@ -1277,7 +1276,7 @@ // Update the status of our IME back-end. // TODO(hbono): we should verify messages to be sent from the back-end. - view()->UpdateTextInputState(ShowIme::HIDE_IME, ChangeSource::FROM_NON_IME); + view()->UpdateTextInputState(); ProcessPendingMessages(); render_thread_->sink().ClearMessages();
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 42a0bb7..7083f7d 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -1904,8 +1904,8 @@ RenderWidget::setTouchAction(touchAction); } -void RenderViewImpl::showImeIfNeeded() { - RenderWidget::showImeIfNeeded(); +void RenderViewImpl::showVirtualKeyboard() { + RenderWidget::showVirtualKeyboard(); } void RenderViewImpl::showUnhandledTapUIIfNeeded(
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 7cdb321..3e062e1 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h
@@ -283,7 +283,7 @@ void setToolTipText(const blink::WebString&, blink::WebTextDirection hint) override; void setTouchAction(blink::WebTouchAction touchAction) override; - void showImeIfNeeded() override; + void showVirtualKeyboard() override; void showUnhandledTapUIIfNeeded(const blink::WebPoint& tappedPosition, const blink::WebNode& tappedNode, bool pageChanged) override;
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index fd245a41..7bd31d9 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc
@@ -932,7 +932,7 @@ // The UpdateTextInputState can result in further layout and possibly // enable GPU acceleration so they need to be called before any painting // is done. - UpdateTextInputState(ShowIme::HIDE_IME, ChangeSource::FROM_NON_IME); + UpdateTextInputState(); UpdateSelectionBounds(); for (auto& observer : render_frame_proxies_) @@ -1024,15 +1024,25 @@ DCHECK(!input_handler_); } -void RenderWidget::UpdateTextInputState(ShowIme show_ime, - ChangeSource change_source) { +void RenderWidget::ShowVirtualKeyboard() { + UpdateTextInputStateInternal(true, false); +} + +void RenderWidget::UpdateTextInputState() { + UpdateTextInputStateInternal(false, false); +} + +void RenderWidget::UpdateTextInputStateInternal(bool show_virtual_keyboard, + bool reply_to_request) { TRACE_EVENT0("renderer", "RenderWidget::UpdateTextInputState"); + if (ime_event_guard_) { - // show_ime should still be effective even if it was set inside the IME + DCHECK(!reply_to_request); + // show_virtual_keyboard should still be effective even if it was set inside + // the IME // event guard. - if (show_ime == ShowIme::IF_NEEDED) { - ime_event_guard_->set_show_ime(true); - } + if (show_virtual_keyboard) + ime_event_guard_->set_show_virtual_keyboard(true); return; } @@ -1050,8 +1060,7 @@ // Only sends text input params if they are changed or if the ime should be // shown. - if (show_ime == ShowIme::IF_NEEDED || - change_source == ChangeSource::FROM_IME || + if (show_virtual_keyboard || reply_to_request || text_input_type_ != new_type || text_input_mode_ != new_mode || text_input_info_ != new_info || can_compose_inline_ != new_can_compose_inline) { @@ -1065,10 +1074,10 @@ params.composition_start = new_info.compositionStart; params.composition_end = new_info.compositionEnd; params.can_compose_inline = new_can_compose_inline; - params.show_ime_if_needed = (show_ime == ShowIme::IF_NEEDED); -#if defined(OS_ANDROID) || defined(USE_AURA) - params.is_non_ime_change = (change_source == ChangeSource::FROM_NON_IME); -#endif + // TODO(changwan): change instances of show_ime_if_needed to + // show_virtual_keyboard. + params.show_ime_if_needed = show_virtual_keyboard; + params.reply_to_request = reply_to_request; Send(new ViewHostMsg_TextInputStateChanged(routing_id(), params)); text_input_info_ = new_info; @@ -1739,10 +1748,8 @@ static_cast<WebFrameWidget*>(GetWebWidget())->dragSourceSystemDragEnded(); } -void RenderWidget::showImeIfNeeded() { -#if defined(OS_ANDROID) || defined(USE_AURA) - UpdateTextInputState(ShowIme::IF_NEEDED, ChangeSource::FROM_NON_IME); -#endif +void RenderWidget::showVirtualKeyboard() { + ShowVirtualKeyboard(); // TODO(rouslan): Fix ChromeOS and Windows 8 behavior of autofill popup with // virtual keyboard. @@ -1814,7 +1821,7 @@ void RenderWidget::OnRequestTextInputStateUpdate() { DCHECK(!ime_event_guard_); UpdateSelectionBounds(); - UpdateTextInputState(ShowIme::HIDE_IME, ChangeSource::FROM_IME); + UpdateTextInputStateInternal(false, true /* reply_to_request */); } #endif @@ -1888,15 +1895,7 @@ void RenderWidget::OnImeEventGuardFinish(ImeEventGuard* guard) { if (ime_event_guard_ != guard) { -#if defined(OS_ANDROID) - // In case a from-IME event (e.g. touch) ends up in not-from-IME event - // (e.g. long press gesture), we want to treat it as not-from-IME event - // so that ReplicaInputConnection can make changes to its Editable model. - // Therefore, we want to mark this text state update as 'from IME' only - // when all the nested events are all originating from IME. - ime_event_guard_->set_from_ime( - ime_event_guard_->from_ime() && guard->from_ime()); -#endif + DCHECK(!ime_event_guard_->reply_to_request()); return; } ime_event_guard_ = nullptr; @@ -1906,9 +1905,10 @@ // ime event. UpdateSelectionBounds(); #if defined(OS_ANDROID) - UpdateTextInputState( - guard->show_ime() ? ShowIme::IF_NEEDED : ShowIme::HIDE_IME, - guard->from_ime() ? ChangeSource::FROM_IME : ChangeSource::FROM_NON_IME); + if (guard->show_virtual_keyboard()) + ShowVirtualKeyboard(); + else + UpdateTextInputState(); #endif } @@ -2123,14 +2123,14 @@ if (event_cancelled) return; if (event.type() == WebInputEvent::GestureTap) { - UpdateTextInputState(ShowIme::IF_NEEDED, ChangeSource::FROM_NON_IME); + ShowVirtualKeyboard(); } else if (event.type() == WebInputEvent::GestureLongPress) { DCHECK(GetWebWidget()); blink::WebInputMethodController* controller = GetInputMethodController(); if (!controller || controller->textInputInfo().value.isEmpty()) - UpdateTextInputState(ShowIme::HIDE_IME, ChangeSource::FROM_NON_IME); + UpdateTextInputState(); else - UpdateTextInputState(ShowIme::IF_NEEDED, ChangeSource::FROM_NON_IME); + ShowVirtualKeyboard(); } // TODO(ananta): Piggyback off existing IPCs to communicate this information, // crbug/420130.
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index 7c71a0e..c446998 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h
@@ -264,8 +264,8 @@ void NotifyInputEventHandled(blink::WebInputEvent::Type handled_type, InputEventAckState ack_result) override; void SetInputHandler(RenderWidgetInputHandler* input_handler) override; - void UpdateTextInputState(ShowIme show_ime, - ChangeSource change_source) override; + void ShowVirtualKeyboard() override; + void UpdateTextInputState() override; bool WillHandleGestureEvent(const blink::WebGestureEvent& event) override; bool WillHandleMouseEvent(const blink::WebMouseEvent& event) override; @@ -297,7 +297,7 @@ const blink::WebFloatSize& accumulatedOverscroll, const blink::WebFloatPoint& position, const blink::WebFloatSize& velocity) override; - void showImeIfNeeded() override; + void showVirtualKeyboard() override; void convertViewportToWindow(blink::WebRect* rect) override; void convertWindowToViewport(blink::WebFloatRect* rect) override; bool requestPointerLock() override; @@ -809,6 +809,9 @@ // handle the event, or there is no page focus. bool ShouldHandleImeEvents() const; + void UpdateTextInputStateInternal(bool show_virtual_keyboard, + bool reply_to_request); + // Indicates whether this widget has focus. bool has_focus_;
diff --git a/content/renderer/screen_orientation/screen_orientation_dispatcher_browsertest.cc b/content/renderer/screen_orientation/screen_orientation_dispatcher_browsertest.cc index 102006b1..973c8e1f 100644 --- a/content/renderer/screen_orientation/screen_orientation_dispatcher_browsertest.cc +++ b/content/renderer/screen_orientation/screen_orientation_dispatcher_browsertest.cc
@@ -59,7 +59,7 @@ RenderViewTest::SetUp(); dispatcher_.reset(new ScreenOrientationDispatcher(nullptr)); ScreenOrientationAssociatedPtr screen_orientation; - mojo::GetDummyProxyForTesting(&screen_orientation); + mojo::GetIsolatedProxy(&screen_orientation); dispatcher_->SetScreenOrientationForTests(screen_orientation); }
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc index 764125ce..0107ded 100644 --- a/content/test/layouttest_support.cc +++ b/content/test/layouttest_support.cc
@@ -604,8 +604,7 @@ void ForceTextInputStateUpdateForRenderFrame(RenderFrame* frame) { if (auto* render_widget = static_cast<RenderFrameImpl*>(frame)->GetRenderWidget()) { - render_widget->UpdateTextInputState(ShowIme::IF_NEEDED, - ChangeSource::FROM_NON_IME); + render_widget->ShowVirtualKeyboard(); } }
diff --git a/google_apis/drive/drive_api_requests.cc b/google_apis/drive/drive_api_requests.cc index 607c657..f534efa0 100644 --- a/google_apis/drive/drive_api_requests.cc +++ b/google_apis/drive/drive_api_requests.cc
@@ -10,6 +10,7 @@ #include "base/callback.h" #include "base/json/json_writer.h" #include "base/location.h" +#include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/sparse_histogram.h" #include "base/sequenced_task_runner.h" @@ -1226,7 +1227,7 @@ DCHECK(request); DCHECK(GetChildEntry(request) == child_requests_.end()); DCHECK(!committed_); - child_requests_.push_back(new BatchUploadChildEntry(request)); + child_requests_.push_back(base::MakeUnique<BatchUploadChildEntry>(request)); request->Prepare(base::Bind(&BatchUploadRequest::OnChildRequestPrepared, weak_ptr_factory_.GetWeakPtr(), request)); } @@ -1270,8 +1271,8 @@ // Obtains corresponding child entry of |request_id|. Returns NULL if the // entry is not found. -ScopedVector<BatchUploadChildEntry>::iterator BatchUploadRequest::GetChildEntry( - RequestID request_id) { +std::vector<std::unique_ptr<BatchUploadChildEntry>>::iterator +BatchUploadRequest::GetChildEntry(RequestID request_id) { for (auto it = child_requests_.begin(); it != child_requests_.end(); ++it) { if ((*it)->request.get() == request_id) return it; @@ -1282,7 +1283,7 @@ void BatchUploadRequest::MayCompletePrepare() { if (!committed_ || prepare_callback_.is_null()) return; - for (auto* child : child_requests_) { + for (const auto& child : child_requests_) { if (!child->prepared) return; } @@ -1290,7 +1291,7 @@ // Build multipart body here. int64_t total_size = 0; std::vector<ContentTypeAndData> parts; - for (auto* child : child_requests_) { + for (const auto& child : child_requests_) { std::string type; std::string data; const bool result = child->request->GetContentData(&type, &data); @@ -1409,7 +1410,7 @@ } void BatchUploadRequest::RunCallbackOnPrematureFailure(DriveApiErrorCode code) { - for (auto* child : child_requests_) + for (const auto& child : child_requests_) child->request->NotifyError(code); child_requests_.clear(); } @@ -1417,7 +1418,7 @@ void BatchUploadRequest::OnURLFetchUploadProgress(const net::URLFetcher* source, int64_t current, int64_t total) { - for (auto* child : child_requests_) { + for (const auto& child : child_requests_) { if (child->data_offset <= current && current <= child->data_offset + child->data_size) { child->request->NotifyUploadProgress(source, current - child->data_offset,
diff --git a/google_apis/drive/drive_api_requests.h b/google_apis/drive/drive_api_requests.h index 9ccd9fa7..f880fcf9 100644 --- a/google_apis/drive/drive_api_requests.h +++ b/google_apis/drive/drive_api_requests.h
@@ -15,7 +15,6 @@ #include "base/callback_forward.h" #include "base/location.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/sequenced_task_runner.h" #include "base/task_runner_util.h" #include "base/time/time.h" @@ -1227,7 +1226,7 @@ typedef void* RequestID; // Obtains corresponding child entry of |request_id|. Returns NULL if the // entry is not found. - ScopedVector<BatchUploadChildEntry>::iterator GetChildEntry( + std::vector<std::unique_ptr<BatchUploadChildEntry>>::iterator GetChildEntry( RequestID request_id); // Called after child requests' |Prepare| method. @@ -1241,7 +1240,7 @@ RequestSender* const sender_; const DriveApiUrlGenerator url_generator_; - ScopedVector<BatchUploadChildEntry> child_requests_; + std::vector<std::unique_ptr<BatchUploadChildEntry>> child_requests_; PrepareCallback prepare_callback_; bool committed_;
diff --git a/google_apis/drive/test_util.cc b/google_apis/drive/test_util.cc index a6497ca..6c0202fc 100644 --- a/google_apis/drive/test_util.cc +++ b/google_apis/drive/test_util.cc
@@ -174,7 +174,7 @@ void TestGetContentCallback::OnGetContent(google_apis::DriveApiErrorCode error, std::unique_ptr<std::string> data) { - data_.push_back(data.release()); + data_.push_back(std::move(data)); } } // namespace test_util
diff --git a/google_apis/drive/test_util.h b/google_apis/drive/test_util.h index 79e07c4..8b17f4b 100644 --- a/google_apis/drive/test_util.h +++ b/google_apis/drive/test_util.h
@@ -16,7 +16,6 @@ #include "base/bind.h" #include "base/callback.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "google_apis/drive/base_requests.h" #include "google_apis/drive/drive_api_error_codes.h" #include "google_apis/drive/task_util.h" @@ -282,8 +281,10 @@ ~TestGetContentCallback(); const GetContentCallback& callback() const { return callback_; } - const ScopedVector<std::string>& data() const { return data_; } - ScopedVector<std::string>* mutable_data() { return &data_; } + const std::vector<std::unique_ptr<std::string>>& data() const { + return data_; + } + std::vector<std::unique_ptr<std::string>>* mutable_data() { return &data_; } std::string GetConcatenatedData() const; private: @@ -291,7 +292,7 @@ std::unique_ptr<std::string> data); const GetContentCallback callback_; - ScopedVector<std::string> data_; + std::vector<std::unique_ptr<std::string>> data_; DISALLOW_COPY_AND_ASSIGN(TestGetContentCallback); };
diff --git a/mojo/public/cpp/bindings/associated_interface_ptr.h b/mojo/public/cpp/bindings/associated_interface_ptr.h index e760c7d..5d83e48 100644 --- a/mojo/public/cpp/bindings/associated_interface_ptr.h +++ b/mojo/public/cpp/bindings/associated_interface_ptr.h
@@ -204,7 +204,7 @@ // Creates an associated interface. The output |ptr| should be used locally // while the returned request should be passed through the message pipe endpoint -// referred to by |associated_group| to setup the corresponding asssociated +// referred to by |associated_group| to setup the corresponding associated // interface implementation at the remote side. // // NOTE: |ptr| should NOT be used to make calls before the request is sent. @@ -255,16 +255,41 @@ return request; } -// Creates an associated interface proxy which casts its messages into the void. +// Like |GetProxy|, but the interface is never associated with any other +// interface. The returned request can be bound directly to the corresponding +// associated interface implementation, without first passing it through a +// message pipe endpoint. +// +// This function has two main uses: +// +// * In testing, where the returned request is bound to e.g. a mock and there +// are no other interfaces involved. +// +// * When discarding messages sent on an interface, which can be done by +// discarding the returned request. template <typename Interface> -void GetDummyProxyForTesting(AssociatedInterfacePtr<Interface>* proxy) { +AssociatedInterfaceRequest<Interface> GetIsolatedProxy( + AssociatedInterfacePtr<Interface>* ptr) { MessagePipe pipe; - scoped_refptr<internal::MultiplexRouter> router = + scoped_refptr<internal::MultiplexRouter> router0 = new internal::MultiplexRouter(std::move(pipe.handle0), internal::MultiplexRouter::MULTI_INTERFACE, false, base::ThreadTaskRunnerHandle::Get()); - std::unique_ptr<AssociatedGroup> group = router->CreateAssociatedGroup(); - MakeRequest(proxy, group.get()); + scoped_refptr<internal::MultiplexRouter> router1 = + new internal::MultiplexRouter(std::move(pipe.handle1), + internal::MultiplexRouter::MULTI_INTERFACE, + true, base::ThreadTaskRunnerHandle::Get()); + + ScopedInterfaceEndpointHandle endpoint0, endpoint1; + router0->CreateEndpointHandlePair(&endpoint0, &endpoint1); + endpoint1 = router1->CreateLocalEndpointHandle(endpoint1.release()); + + ptr->Bind(AssociatedInterfacePtrInfo<Interface>(std::move(endpoint0), + Interface::Version_)); + + AssociatedInterfaceRequest<Interface> request; + request.Bind(std::move(endpoint1)); + return request; } } // namespace mojo
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni index 791bfa1d..f35a119 100644 --- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni +++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -8,6 +8,7 @@ "//chrome/browser/media/router/mojo/typemaps.gni", "//chrome/common/extensions/typemaps.gni", "//chrome/common/importer/typemaps.gni", + "//chrome/typemaps.gni", "//components/arc/common/typemaps.gni", "//components/metrics/public/cpp/typemaps.gni", "//components/typemaps.gni",
diff --git a/remoting/protocol/ice_transport_channel.h b/remoting/protocol/ice_transport_channel.h index f28ff82..2fbb33c 100644 --- a/remoting/protocol/ice_transport_channel.h +++ b/remoting/protocol/ice_transport_channel.h
@@ -99,7 +99,7 @@ void NotifyConnected(); // Signal handlers for cricket::IceTransportInternal. - void OnCandidateGathered(cricket::IceTransportInternal2* ice_transport, + void OnCandidateGathered(cricket::IceTransportInternal* ice_transport, const cricket::Candidate& candidate); void OnRouteChange(cricket::IceTransportInternal* ice_transport, const cricket::Candidate& candidate);
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests index 9ff65fe..fe3ec0e9 100644 --- a/third_party/WebKit/LayoutTests/NeverFixTests +++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -208,6 +208,16 @@ webaudio/codec-tests/mp3 [ WontFix ] webaudio/codec-tests/aac [ WontFix ] +# WPT subdirectories without owners. +imported/wpt/accelerometer [ WontFix ] +imported/wpt/auxclick [ WontFix ] +imported/wpt/clear-site-data [ WontFix ] +imported/wpt/css-values [ WontFix ] +imported/wpt/gyroscope [ WontFix ] +imported/wpt/magnetometer [ WontFix ] +imported/wpt/preload [ WontFix ] +imported/wpt/upgrade-insecure-requests [ WontFix ] + # These tests require a DRM system that is not available with content_shell. imported/wpt/encrypted-media/drm-check-initdata-type.html [ WontFix ] imported/wpt/encrypted-media/drm-events.html [ WontFix ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 01f68414..6b1c23e 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1716,14 +1716,7 @@ crbug.com/626703 imported/wpt/html/semantics/interfaces.html [ Failure ] crbug.com/626703 imported/wpt/pointerevents/pointerevent_sequence_at_implicit_release_on_drag-manual.html [ Timeout ] crbug.com/626703 imported/wpt/pointerevents/pointerevent_sequence_at_implicit_release_on_click-manual.html [ Timeout ] -crbug.com/626703 imported/wpt/clear-site-data/navigation.html [ Timeout ] -crbug.com/626703 imported/wpt/auxclick/auxclick_event-manual.html [ Timeout ] crbug.com/626703 imported/wpt/pointerevents/pointerevent_boundary_events_in_capturing-manual.html [ Timeout ] -crbug.com/626703 imported/wpt/upgrade-insecure-requests/image-redirect-upgrade.https.html [ Timeout ] -crbug.com/626703 imported/wpt/upgrade-insecure-requests/websocket-upgrade.https.html [ Timeout ] -crbug.com/626703 imported/wpt/upgrade-insecure-requests/image-upgrade.https.html [ Timeout ] -crbug.com/626703 imported/wpt/upgrade-insecure-requests/iframe-upgrade.https.html [ Timeout ] -crbug.com/626703 imported/wpt/upgrade-insecure-requests/iframe-redirect-upgrade.https.html [ Timeout ] crbug.com/626703 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-baseline-horiz-001a.xhtml [ Failure ] crbug.com/626703 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-baseline-horiz-001b.xhtml [ Failure ] crbug.com/626703 imported/csswg-test/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-baseline-horiz-006.xhtml [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/WPTServeExpectations b/third_party/WebKit/LayoutTests/WPTServeExpectations index af4f3396..e09a1b0e 100644 --- a/third_party/WebKit/LayoutTests/WPTServeExpectations +++ b/third_party/WebKit/LayoutTests/WPTServeExpectations
@@ -1,3 +1,18 @@ # Overriden expectations for imported tests when run with --enable-wptserve # This file is now obsolete and will be removed. See https://crbug.com/666111 + +# Needs rebaseline after enabling WPTServe. +imported/wpt/domparsing/DOMParser-parseFromString-html.html [ Failure ] +imported/wpt/domparsing/DOMParser-parseFromString-xml.html [ Failure ] +imported/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/dynamic-append.html [ Failure ] +imported/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/not-in-shadow-tree.html [ Failure ] +imported/wpt/html/webappapis/scripting/processing-model-2/compile-error-same-origin-with-hash.html [ Failure ] +imported/wpt/html/webappapis/scripting/processing-model-2/runtime-error-same-origin-with-hash.html [ Failure ] + +# Update expectation after enabling WPTServe +imported/wpt/domparsing/innerhtml-05.xhtml [ Crash Failure ] +imported/wpt/workers/opaque-origin.html [ Crash Failure ] +imported/wpt/workers/Worker_cross_origin_security_err.htm [ Timeout ] +imported/wpt/service-workers/service-worker/fetch-frame-resource.https.html [ Timeout ] +imported/wpt/service-workers/service-worker/update-after-oneday.https.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/fast/input/placeholder-wrongly-placed-if-too-tall-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/text/placeholder-wrongly-placed-if-too-tall-expected.txt similarity index 100% rename from third_party/WebKit/LayoutTests/fast/input/placeholder-wrongly-placed-if-too-tall-expected.txt rename to third_party/WebKit/LayoutTests/fast/forms/text/placeholder-wrongly-placed-if-too-tall-expected.txt
diff --git a/third_party/WebKit/LayoutTests/fast/input/placeholder-wrongly-placed-if-too-tall.html b/third_party/WebKit/LayoutTests/fast/forms/text/placeholder-wrongly-placed-if-too-tall.html similarity index 93% rename from third_party/WebKit/LayoutTests/fast/input/placeholder-wrongly-placed-if-too-tall.html rename to third_party/WebKit/LayoutTests/fast/forms/text/placeholder-wrongly-placed-if-too-tall.html index d71cc1e..b3d2ca5 100644 --- a/third_party/WebKit/LayoutTests/fast/input/placeholder-wrongly-placed-if-too-tall.html +++ b/third_party/WebKit/LayoutTests/fast/forms/text/placeholder-wrongly-placed-if-too-tall.html
@@ -1,5 +1,5 @@ <!DOCTYPE html> -<script src="../../resources/js-test.js"></script> +<script src="../../../resources/js-test.js"></script> <style> input { height: 26px;
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp index 1c0ff85..7a2f548 100644 --- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp +++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -1948,26 +1948,17 @@ const PropertyRegistry::Registration* registration = registry->registration(customPropertyName); if (registration) { - const CSSValue* result = nullptr; - if (registration->inherits()) { - if (StyleInheritedVariables* variables = style.inheritedVariables()) - result = variables->registeredVariable(customPropertyName); - } else { - if (StyleNonInheritedVariables* variables = - style.nonInheritedVariables()) - result = variables->registeredVariable(customPropertyName); - } + const CSSValue* result = style.getRegisteredVariable( + customPropertyName, registration->inherits()); if (result) return result; return registration->initial(); } } - StyleInheritedVariables* variables = style.inheritedVariables(); - if (!variables) - return nullptr; - - CSSVariableData* data = variables->getVariable(customPropertyName); + bool isInheritedProperty = true; + CSSVariableData* data = + style.getVariable(customPropertyName, isInheritedProperty); if (!data) return nullptr;
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp index fede332..d5ea539 100644 --- a/third_party/WebKit/Source/core/dom/Element.cpp +++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -2666,7 +2666,7 @@ // gesture. Since tracking that across arbitrary boundaries (eg. // animations) is difficult, for now we match IE's heuristic and bring // up the keyboard if there's been any gesture since load. - document().page()->chromeClient().showImeIfNeeded(); + document().page()->chromeClient().showVirtualKeyboard(); } }
diff --git a/third_party/WebKit/Source/core/frame/BUILD.gn b/third_party/WebKit/Source/core/frame/BUILD.gn index d75dc18..cc8f8861 100644 --- a/third_party/WebKit/Source/core/frame/BUILD.gn +++ b/third_party/WebKit/Source/core/frame/BUILD.gn
@@ -21,8 +21,6 @@ "DOMWindowBase64.cpp", "DOMWindowBase64.h", "DOMWindowEventHandlers.h", - "DOMWindowProperty.cpp", - "DOMWindowProperty.h", "DOMWindowTimers.cpp", "DOMWindowTimers.h", "DeprecatedScheduleStyleRecalcDuringLayout.cpp",
diff --git a/third_party/WebKit/Source/core/frame/DOMWindow.cpp b/third_party/WebKit/Source/core/frame/DOMWindow.cpp index c5f9123..2e3704b 100644 --- a/third_party/WebKit/Source/core/frame/DOMWindow.cpp +++ b/third_party/WebKit/Source/core/frame/DOMWindow.cpp
@@ -155,9 +155,8 @@ } void DOMWindow::resetLocation() { - // Location needs to be reset manually because it doesn't inherit from - // DOMWindowProperty. DOMWindowProperty is local-only, and Location needs to - // support remote windows, too. + // Location needs to be reset manually so that it doesn't retain a stale + // Frame pointer. if (m_location) { m_location->reset(); m_location = nullptr;
diff --git a/third_party/WebKit/Source/core/frame/DOMWindowProperty.cpp b/third_party/WebKit/Source/core/frame/DOMWindowProperty.cpp deleted file mode 100644 index fef480ff..0000000 --- a/third_party/WebKit/Source/core/frame/DOMWindowProperty.cpp +++ /dev/null
@@ -1,56 +0,0 @@ -/* - * Copyright (C) 2011 Google, Inc. All Rights Reserved. - * Copyright (C) 2012 Apple Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "core/frame/DOMWindowProperty.h" - -#include "core/frame/LocalDOMWindow.h" -#include "core/frame/LocalFrame.h" - -namespace blink { - -DOMWindowProperty::DOMWindowProperty(LocalFrame* frame) : m_frame(frame) { - // FIXME: For now it *is* acceptable for a DOMWindowProperty to be created - // with a null frame. See fast/dom/navigator-detached-no-crash.html for the - // recipe. We should fix that. <rdar://problem/11567132> - if (m_frame) { - // FIXME: Need to figure out what to do with DOMWindowProperties on - // remote DOM windows. - m_frame->domWindow()->registerProperty(this); - } -} - -void DOMWindowProperty::frameDestroyed() { - // If the property is getting this callback it must have been - // created with a LocalFrame and it should still have it. - ASSERT(m_frame); - m_frame = nullptr; -} - -DEFINE_TRACE(DOMWindowProperty) { - visitor->trace(m_frame); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/DOMWindowProperty.h b/third_party/WebKit/Source/core/frame/DOMWindowProperty.h deleted file mode 100644 index 283f23b..0000000 --- a/third_party/WebKit/Source/core/frame/DOMWindowProperty.h +++ /dev/null
@@ -1,52 +0,0 @@ -/* - * Copyright (C) 2011 Google, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef DOMWindowProperty_h -#define DOMWindowProperty_h - -#include "core/CoreExport.h" -#include "platform/heap/Handle.h" - -namespace blink { - -class LocalFrame; - -class CORE_EXPORT DOMWindowProperty : public GarbageCollectedMixin { - public: - explicit DOMWindowProperty(LocalFrame*); - - void frameDestroyed(); - - LocalFrame* frame() const { return m_frame; } - - DECLARE_VIRTUAL_TRACE(); - - private: - Member<LocalFrame> m_frame; -}; - -} // namespace blink - -#endif // DOMWindowProperty_h
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp index 9a9bab1..62548b8 100644 --- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp +++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -53,7 +53,6 @@ #include "core/fetch/ResourceFetcher.h" #include "core/frame/BarProp.h" #include "core/frame/DOMVisualViewport.h" -#include "core/frame/DOMWindowProperty.h" #include "core/frame/EventHandlerRegistry.h" #include "core/frame/FrameConsole.h" #include "core/frame/FrameView.h" @@ -479,23 +478,11 @@ } void LocalDOMWindow::frameDestroyed() { - for (const auto& domWindowProperty : m_properties) - domWindowProperty->frameDestroyed(); - resetLocation(); - m_properties.clear(); removeAllEventListeners(); disconnectFromFrame(); } -void LocalDOMWindow::registerProperty(DOMWindowProperty* property) { - m_properties.add(property); -} - -void LocalDOMWindow::unregisterProperty(DOMWindowProperty* property) { - m_properties.remove(property); -} - void LocalDOMWindow::registerEventListenerObserver( EventListenerObserver* eventListenerObserver) { m_eventListenerObservers.add(eventListenerObserver); @@ -1609,7 +1596,6 @@ DEFINE_TRACE(LocalDOMWindow) { visitor->trace(m_document); - visitor->trace(m_properties); visitor->trace(m_screen); visitor->trace(m_history); visitor->trace(m_locationbar);
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.h b/third_party/WebKit/Source/core/frame/LocalDOMWindow.h index ad9a4cb..2a12b79 100644 --- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.h +++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.h
@@ -42,7 +42,6 @@ class CustomElementRegistry; class DOMWindowEventQueue; -class DOMWindowProperty; class DocumentInit; class EventQueue; class FrameConsole; @@ -172,9 +171,6 @@ CustomElementRegistry* customElements() const; CustomElementRegistry* maybeCustomElements() const; - void registerProperty(DOMWindowProperty*); - void unregisterProperty(DOMWindowProperty*); - void registerEventListenerObserver(EventListenerObserver*); void frameDestroyed(); @@ -267,8 +263,6 @@ bool m_shouldPrintWhenFinishedLoading; - HeapHashSet<WeakMember<DOMWindowProperty>> m_properties; - mutable Member<Screen> m_screen; mutable Member<History> m_history; mutable Member<BarProp> m_locationbar;
diff --git a/third_party/WebKit/Source/core/frame/Location.h b/third_party/WebKit/Source/core/frame/Location.h index bcf777c..2618f79 100644 --- a/third_party/WebKit/Source/core/frame/Location.h +++ b/third_party/WebKit/Source/core/frame/Location.h
@@ -33,7 +33,6 @@ #include "bindings/core/v8/ScriptWrappable.h" #include "core/CoreExport.h" #include "core/dom/DOMStringList.h" -#include "core/frame/DOMWindowProperty.h" #include "wtf/text/WTFString.h" namespace blink { @@ -44,11 +43,9 @@ class KURL; // This class corresponds to the JS Location API, which is the only DOM API -// besides Window that is operable in a RemoteFrame. Rather than making -// DOMWindowProperty support RemoteFrames and generating a lot code churn, -// Location is implemented as a one-off with some custom lifetime management -// code. Namely, it needs a manual call to reset() from DOMWindow::reset() to -// ensure it doesn't retain a stale Frame pointer. +// besides Window that is operable in a RemoteFrame. Location needs to be +// manually updated in DOMWindow::reset() to ensure it doesn't retain a stale +// Frame pointer. class CORE_EXPORT Location final : public GarbageCollected<Location>, public ScriptWrappable { DEFINE_WRAPPERTYPEINFO();
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.h b/third_party/WebKit/Source/core/page/ChromeClient.h index 4788dfc..e1785e59 100644 --- a/third_party/WebKit/Source/core/page/ChromeClient.h +++ b/third_party/WebKit/Source/core/page/ChromeClient.h
@@ -311,7 +311,7 @@ virtual void didCancelCompositionOnSelectionChange() {} virtual void resetInputMethod() {} virtual void didUpdateTextOfFocusedElementByNonUserInput(LocalFrame&) {} - virtual void showImeIfNeeded() {} + virtual void showVirtualKeyboard() {} virtual void registerViewportLayers() const {}
diff --git a/third_party/WebKit/Source/modules/quota/WorkerNavigatorStorageQuota.h b/third_party/WebKit/Source/modules/quota/WorkerNavigatorStorageQuota.h index 2a7279b..581bfc3c 100644 --- a/third_party/WebKit/Source/modules/quota/WorkerNavigatorStorageQuota.h +++ b/third_party/WebKit/Source/modules/quota/WorkerNavigatorStorageQuota.h
@@ -31,7 +31,6 @@ #ifndef WorkerNavigatorStorageQuota_h #define WorkerNavigatorStorageQuota_h -#include "core/frame/DOMWindowProperty.h" #include "core/workers/WorkerNavigator.h" #include "modules/quota/DeprecatedStorageQuota.h" #include "platform/Supplementable.h"
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp index 3fa95b1..11d980e8 100644 --- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp +++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -1023,9 +1023,9 @@ m_webView->client()->resetInputMethod(); } -void ChromeClientImpl::showImeIfNeeded() { +void ChromeClientImpl::showVirtualKeyboard() { if (m_webView->client()) - m_webView->client()->showImeIfNeeded(); + m_webView->client()->showVirtualKeyboard(); } void ChromeClientImpl::showUnhandledTapUIIfNeeded(
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.h b/third_party/WebKit/Source/web/ChromeClientImpl.h index 33b1194..4cf59e7 100644 --- a/third_party/WebKit/Source/web/ChromeClientImpl.h +++ b/third_party/WebKit/Source/web/ChromeClientImpl.h
@@ -199,7 +199,7 @@ void didCancelCompositionOnSelectionChange() override; void resetInputMethod() override; - void showImeIfNeeded() override; + void showVirtualKeyboard() override; void registerViewportLayers() const override;
diff --git a/third_party/WebKit/Source/web/tests/ImeOnFocusTest.cpp b/third_party/WebKit/Source/web/tests/ImeOnFocusTest.cpp index 2d7d552..50f42c5 100644 --- a/third_party/WebKit/Source/web/tests/ImeOnFocusTest.cpp +++ b/third_party/WebKit/Source/web/tests/ImeOnFocusTest.cpp
@@ -25,18 +25,18 @@ class ImeRequestTrackingWebViewClient : public FrameTestHelpers::TestWebViewClient { public: - ImeRequestTrackingWebViewClient() : m_imeRequestCount(0) {} + ImeRequestTrackingWebViewClient() : m_virtualKeyboardRequestCount(0) {} // WebWidgetClient methods - void showImeIfNeeded() override { ++m_imeRequestCount; } + void showVirtualKeyboard() override { ++m_virtualKeyboardRequestCount; } // Local methds - void reset() { m_imeRequestCount = 0; } + void reset() { m_virtualKeyboardRequestCount = 0; } - int imeRequestCount() { return m_imeRequestCount; } + int virtualKeyboardRequestCount() { return m_virtualKeyboardRequestCount; } private: - int m_imeRequestCount; + int m_virtualKeyboardRequestCount; }; class ImeOnFocusTest : public ::testing::Test { @@ -85,7 +85,7 @@ } void ImeOnFocusTest::runImeOnFocusTest(std::string fileName, - int expectedImeRequestCount, + int expectedVirtualKeyboardRequestCount, IntPoint tapPoint, const AtomicString& focusElement, std::string frame) { @@ -100,7 +100,7 @@ if (!focusElement.isNull()) focus(focusElement); - EXPECT_EQ(0, client.imeRequestCount()); + EXPECT_EQ(0, client.virtualKeyboardRequestCount()); if (tapPoint.x() >= 0 && tapPoint.y() >= 0) sendGestureTap(webView, tapPoint); @@ -114,7 +114,8 @@ if (!focusElement.isNull()) focus(focusElement); - EXPECT_EQ(expectedImeRequestCount, client.imeRequestCount()); + EXPECT_EQ(expectedVirtualKeyboardRequestCount, + client.virtualKeyboardRequestCount()); m_webViewHelper.reset(); }
diff --git a/third_party/WebKit/public/web/WebViewClient.h b/third_party/WebKit/public/web/WebViewClient.h index 3f77867..0cafd7d 100644 --- a/third_party/WebKit/public/web/WebViewClient.h +++ b/third_party/WebKit/public/web/WebViewClient.h
@@ -276,7 +276,7 @@ void resetInputMethod() override {} WebScreenInfo screenInfo() override { return WebScreenInfo(); } void setTouchAction(WebTouchAction touchAction) override {} - void showImeIfNeeded() override {} + void showVirtualKeyboard() override {} void showUnhandledTapUIIfNeeded(const WebPoint& tappedPosition, const WebNode& tappedNode, bool pageChanged) override {}
diff --git a/third_party/WebKit/public/web/WebWidgetClient.h b/third_party/WebKit/public/web/WebWidgetClient.h index bd80104e..c4e2b44b 100644 --- a/third_party/WebKit/public/web/WebWidgetClient.h +++ b/third_party/WebKit/public/web/WebWidgetClient.h
@@ -143,8 +143,8 @@ // the embedder of the touch actions that are permitted for this touch. virtual void setTouchAction(WebTouchAction touchAction) {} - // Request the browser to show the IME for current input type. - virtual void showImeIfNeeded() {} + // Request the browser to show virtual keyboard for current input type. + virtual void showVirtualKeyboard() {} // Request that the browser show a UI for an unhandled tap, if needed. // Invoked during the handling of a GestureTap input event whenever the
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 82b7e74c3..5ff826f91 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -19098,6 +19098,12 @@ <summary>The volume type where quick view is opened.</summary> </histogram> +<histogram name="FileBrowser.QuickView.WayToOpen" + enum="FileManagerQuickViewWayToOpen"> + <owner>oka@google.com</owner> + <summary>How quick view was opened.</summary> +</histogram> + <histogram name="FileBrowser.SuggestApps.Close" enum="SuggestAppsDialogCloseReason"> <owner>joshwoodward@google.com</owner> @@ -89859,6 +89865,11 @@ <int value="6" label="Error"/> </enum> +<enum name="FileManagerQuickViewWayToOpen" type="int"> + <int value="0" label="Context menu"/> + <int value="1" label="Space key"/> +</enum> + <enum name="FileManagerVolumeType" type="int"> <int value="0" label="Google Drive"/> <int value="1" label="Download Folder"/> @@ -89866,6 +89877,7 @@ <int value="3" label="Archive File"/> <int value="4" label="FileSystemProvider API"/> <int value="5" label="MTP (Media Transfer Protocol) Device"/> + <int value="6" label="Media View"/> </enum> <enum name="FileMetricsProviderAccessResult" type="int">
diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm index 0cabd69..5bfa69c 100644 --- a/ui/accessibility/platform/ax_platform_node_mac.mm +++ b/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -12,7 +12,9 @@ #include "ui/accessibility/ax_action_data.h" #include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/platform/ax_platform_node_delegate.h" +#include "ui/base/l10n/l10n_util.h" #import "ui/gfx/mac/coordinate_conversion.h" +#include "ui/strings/grit/ui_strings.h" namespace { @@ -371,8 +373,7 @@ // Allow certain attributes to be written via an accessibility client. A // writable attribute will only appear as such if the accessibility element // has a value set for that attribute. - if ([attributeName isEqualToString:NSAccessibilitySelectedAttribute] || - [attributeName + if ([attributeName isEqualToString:NSAccessibilitySelectedChildrenAttribute] || [attributeName isEqualToString:NSAccessibilitySelectedTextRangeAttribute] || @@ -381,10 +382,18 @@ return NO; } + // Since tabs use the Radio Button role on Mac, the standard way to set them + // is via the value attribute rather than the selected attribute. + if ([attributeName isEqualToString:NSAccessibilityValueAttribute] && + node_->GetData().role == ui::AX_ROLE_TAB) { + return !node_->GetData().HasStateFlag(ui::AX_STATE_SELECTED); + } + if ([attributeName isEqualToString:NSAccessibilityValueAttribute] || - [attributeName isEqualToString:NSAccessibilitySelectedTextAttribute]) + [attributeName isEqualToString:NSAccessibilitySelectedTextAttribute]) { return !ui::AXNodeData::IsFlagSet(node_->GetData().state, ui::AX_STATE_READ_ONLY); + } if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute]) { return ui::AXNodeData::IsFlagSet(node_->GetData().state, @@ -398,21 +407,26 @@ - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute { ui::AXActionData data; - if ([value isKindOfClass:[NSString class]]) { - data.value = base::SysNSStringToUTF16(value); - if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { - data.action = ui::AX_ACTION_SET_VALUE; - } else if ([attribute - isEqualToString:NSAccessibilitySelectedTextAttribute]) { - data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT; - } - } else if ([value isKindOfClass:[NSNumber class]]) { - if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { + + // Check for attributes first. Only the |data.action| should be set here - any + // type-specific information, if needed, should be set below. + if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { + data.action = node_->GetData().role == ui::AX_ROLE_TAB + ? ui::AX_ACTION_SET_SELECTION + : ui::AX_ACTION_SET_VALUE; + } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) { + data.action = ui::AX_ACTION_REPLACE_SELECTED_TEXT; + } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { + if ([value isKindOfClass:[NSNumber class]]) { data.action = [value boolValue] ? ui::AX_ACTION_FOCUS : ui::AX_ACTION_BLUR; } } + // Set type-specific information as necessary for actions set above. + if ([value isKindOfClass:[NSString class]]) + data.value = base::SysNSStringToUTF16(value); + if (data.action != ui::AX_ACTION_NONE) node_->GetDelegate()->AccessibilityPerformAction(data); @@ -437,6 +451,15 @@ } - (NSString*)AXRoleDescription { + switch (node_->GetData().role) { + case ui::AX_ROLE_TAB: + // There is no NSAccessibilityTabRole or similar (AXRadioButton is used + // instead). Do the same as NSTabView and put "tab" in the description. + return [l10n_util::GetNSStringWithFixup(IDS_ACCNAME_TAB_ROLE_DESCRIPTION) + lowercaseString]; + default: + break; + } return NSAccessibilityRoleDescription([self AXRole], [self AXSubrole]); } @@ -458,7 +481,9 @@ return [self getStringAttribute:ui::AX_ATTR_DESCRIPTION]; } -- (NSString*)AXValue { +- (id)AXValue { + if (node_->GetData().role == ui::AX_ROLE_TAB) + return [self AXSelected]; return [self getStringAttribute:ui::AX_ATTR_VALUE]; } @@ -514,6 +539,11 @@ // Misc attributes. +- (NSNumber*)AXSelected { + return [NSNumber + numberWithBool:node_->GetData().HasStateFlag(ui::AX_STATE_SELECTED)]; +} + - (NSString*)AXPlaceholderValue { return [self getStringAttribute:ui::AX_ATTR_PLACEHOLDER]; }
diff --git a/ui/file_manager/file_manager/background/js/volume_info_list_impl.js b/ui/file_manager/file_manager/background/js/volume_info_list_impl.js index 08b4f5ea..b3981cc 100644 --- a/ui/file_manager/file_manager/background/js/volume_info_list_impl.js +++ b/ui/file_manager/file_manager/background/js/volume_info_list_impl.js
@@ -37,13 +37,27 @@ VolumeManagerCommon.VolumeType.REMOVABLE, VolumeManagerCommon.VolumeType.MTP, VolumeManagerCommon.VolumeType.PROVIDED, + VolumeManagerCommon.VolumeType.MEDIA_VIEW, +]; + +/** + * The order of the media view roots. + * @type {Array<VolumeManagerCommon.MediaViewRootType>} + * @const + * @private + */ +VolumeInfoListImpl.MEDIA_VIEW_ROOT_ORDER_ = [ + VolumeManagerCommon.MediaViewRootType.IMAGES, + VolumeManagerCommon.MediaViewRootType.VIDEOS, + VolumeManagerCommon.MediaViewRootType.AUDIO, ]; /** * Orders two volumes by volumeType and volumeId. * * The volumes at first are compared by volume type in the order of - * volumeListOrder_. Then they are compared by volume ID. + * volumeListOrder_. Then they are compared by volume ID, except for media + * views which are sorted in a fixed order. * * @param {!VolumeInfo} volumeInfo1 Volume info to be compared. * @param {!VolumeInfo} volumeInfo2 Volume info to be compared. @@ -58,6 +72,17 @@ VolumeInfoListImpl.VOLUME_LIST_ORDER_.indexOf(volumeInfo2.volumeType); if (typeIndex1 !== typeIndex2) return typeIndex1 < typeIndex2 ? -1 : 1; + if (volumeInfo1.volumeType === VolumeManagerCommon.VolumeType.MEDIA_VIEW) { + var mediaTypeIndex1 = VolumeInfoListImpl.MEDIA_VIEW_ROOT_ORDER_.indexOf( + VolumeManagerCommon.getMediaViewRootTypeFromVolumeId( + volumeInfo1.volumeId)); + var mediaTypeIndex2 = VolumeInfoListImpl.MEDIA_VIEW_ROOT_ORDER_.indexOf( + VolumeManagerCommon.getMediaViewRootTypeFromVolumeId( + volumeInfo2.volumeId)); + if (mediaTypeIndex1 !== mediaTypeIndex2) + return mediaTypeIndex1 < mediaTypeIndex2 ? -1 : 1; + return 0; + } if (volumeInfo1.volumeId !== volumeInfo2.volumeId) return volumeInfo1.volumeId < volumeInfo2.volumeId ? -1 : 1; return 0;
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_impl.js b/ui/file_manager/file_manager/background/js/volume_manager_impl.js index e6463bec..7288036 100644 --- a/ui/file_manager/file_manager/background/js/volume_manager_impl.js +++ b/ui/file_manager/file_manager/background/js/volume_manager_impl.js
@@ -331,6 +331,9 @@ case VolumeManagerCommon.VolumeType.PROVIDED: rootType = VolumeManagerCommon.RootType.PROVIDED; break; + case VolumeManagerCommon.VolumeType.MEDIA_VIEW: + rootType = VolumeManagerCommon.RootType.MEDIA_VIEW; + break; default: // Programming error, throw an exception. throw new Error('Invalid volume type: ' + volumeInfo.volumeType);
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_util.js b/ui/file_manager/file_manager/background/js/volume_manager_util.js index ec6abc2..a02ce6a9 100644 --- a/ui/file_manager/file_manager/background/js/volume_manager_util.js +++ b/ui/file_manager/file_manager/background/js/volume_manager_util.js
@@ -63,6 +63,20 @@ case VolumeManagerCommon.VolumeType.DRIVE: localizedLabel = str('DRIVE_DIRECTORY_LABEL'); break; + case VolumeManagerCommon.VolumeType.MEDIA_VIEW: + switch (VolumeManagerCommon.getMediaViewRootTypeFromVolumeId( + volumeMetadata.volumeId)) { + case VolumeManagerCommon.MediaViewRootType.IMAGES: + localizedLabel = str('MEDIA_VIEW_IMAGES_ROOT_LABEL'); + break; + case VolumeManagerCommon.MediaViewRootType.VIDEOS: + localizedLabel = str('MEDIA_VIEW_VIDEOS_ROOT_LABEL'); + break; + case VolumeManagerCommon.MediaViewRootType.AUDIO: + localizedLabel = str('MEDIA_VIEW_AUDIO_ROOT_LABEL'); + break; + } + break; default: // TODO(mtomasz): Calculate volumeLabel for all types of volumes in the // C++ layer.
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js index f5a0455..d7b0b83 100644 --- a/ui/file_manager/file_manager/common/js/util.js +++ b/ui/file_manager/file_manager/common/js/util.js
@@ -940,6 +940,20 @@ return str('DRIVE_SHARED_WITH_ME_COLLECTION_LABEL'); case VolumeManagerCommon.RootType.DRIVE_RECENT: return str('DRIVE_RECENT_COLLECTION_LABEL'); + case VolumeManagerCommon.RootType.MEDIA_VIEW: + var mediaViewRootType = + VolumeManagerCommon.getMediaViewRootTypeFromVolumeId( + locationInfo.volumeInfo.volumeId); + switch (mediaViewRootType) { + case VolumeManagerCommon.MediaViewRootType.IMAGES: + return str('MEDIA_VIEW_IMAGES_ROOT_LABEL'); + case VolumeManagerCommon.MediaViewRootType.VIDEOS: + return str('MEDIA_VIEW_VIDEOS_ROOT_LABEL'); + case VolumeManagerCommon.MediaViewRootType.AUDIO: + return str('MEDIA_VIEW_AUDIO_ROOT_LABEL'); + } + console.error('Unsupported media view root type: ' + mediaViewRootType); + return locationInfo.volumeInfo.label; case VolumeManagerCommon.RootType.DRIVE_OTHER: case VolumeManagerCommon.RootType.ARCHIVE: case VolumeManagerCommon.RootType.REMOVABLE:
diff --git a/ui/file_manager/file_manager/common/js/volume_manager_common.js b/ui/file_manager/file_manager/common/js/volume_manager_common.js index 03b72e4..2085eac 100644 --- a/ui/file_manager/file_manager/common/js/volume_manager_common.js +++ b/ui/file_manager/file_manager/common/js/volume_manager_common.js
@@ -54,7 +54,10 @@ DRIVE_SHARED_WITH_ME: 'drive_shared_with_me', // Fake root for recent files on the drive. - DRIVE_RECENT: 'drive_recent' + DRIVE_RECENT: 'drive_recent', + + // Root for media views. + MEDIA_VIEW: 'media_view', }; Object.freeze(VolumeManagerCommon.RootType); @@ -132,7 +135,8 @@ REMOVABLE: 'removable', ARCHIVE: 'archive', MTP: 'mtp', - PROVIDED: 'provided' + PROVIDED: 'provided', + MEDIA_VIEW: 'media_view', }; /** @@ -184,6 +188,8 @@ return VolumeManagerCommon.VolumeType.MTP; case VolumeManagerCommon.RootType.PROVIDED: return VolumeManagerCommon.VolumeType.PROVIDED; + case VolumeManagerCommon.RootType.MEDIA_VIEW: + return VolumeManagerCommon.VolumeType.MEDIA_VIEW; } assertNotReached('Unknown root type: ' + rootType); }; @@ -212,6 +218,31 @@ VolumeManagerCommon.VolumeInfoProvider.prototype.getVolumeInfo; /** + * List of media view root types. + * + * Keep this in sync with constants in arc_media_view_util.cc. + * + * @enum {string} + * @const + */ +VolumeManagerCommon.MediaViewRootType = { + IMAGES: 'images_root', + VIDEOS: 'videos_root', + AUDIO: 'audio_root', +}; +Object.freeze(VolumeManagerCommon.MediaViewRootType); + +/** + * Obtains volume type from root type. + * @param {string} volumeId Volume ID. + * @return {VolumeManagerCommon.MediaViewRootType} + */ +VolumeManagerCommon.getMediaViewRootTypeFromVolumeId = function(volumeId) { + return /** @type {VolumeManagerCommon.MediaViewRootType} */ ( + volumeId.split(':', 2)[1]); +}; + +/** * Fake entries for Google Drive's virtual folders. * (OFFLINE, RECENT, and SHARED_WITH_ME) * @typedef {{
diff --git a/ui/file_manager/file_manager/foreground/css/file_types.css b/ui/file_manager/file_manager/foreground/css/file_types.css index 66ec654..151de60 100644 --- a/ui/file_manager/file_manager/foreground/css/file_types.css +++ b/ui/file_manager/file_manager/foreground/css/file_types.css
@@ -306,6 +306,45 @@ url(../images/volumes/2x/cd_active.png) 2x); } +[volume-type-icon='media_view'][volume-subtype='images_root'] { + background-image: -webkit-image-set( + url(../images/volumes/images.png) 1x, + url(../images/volumes/2x/images.png) 2x); +} + +.tree-row[selected] + [volume-type-icon='media_view'][volume-subtype='images_root'] { + background-image: -webkit-image-set( + url(../images/volumes/images_active.png) 1x, + url(../images/volumes/2x/images_active.png) 2x); +} + +[volume-type-icon='media_view'][volume-subtype='videos_root'] { + background-image: -webkit-image-set( + url(../images/volumes/videos.png) 1x, + url(../images/volumes/2x/videos.png) 2x); +} + +.tree-row[selected] + [volume-type-icon='media_view'][volume-subtype='videos_root'] { + background-image: -webkit-image-set( + url(../images/volumes/videos_active.png) 1x, + url(../images/volumes/2x/videos_active.png) 2x); +} + +[volume-type-icon='media_view'][volume-subtype='audio_root'] { + background-image: -webkit-image-set( + url(../images/volumes/audio.png) 1x, + url(../images/volumes/2x/audio.png) 2x); +} + +.tree-row[selected] + [volume-type-icon='media_view'][volume-subtype='audio_root'] { + background-image: -webkit-image-set( + url(../images/volumes/audio_active.png) 1x, + url(../images/volumes/2x/audio_active.png) 2x); +} + [volume-type-icon='mtp'] { background-image: -webkit-image-set( url(../images/volumes/phone.png) 1x,
diff --git a/ui/file_manager/file_manager/foreground/images/volumes/2x/audio.png b/ui/file_manager/file_manager/foreground/images/volumes/2x/audio.png new file mode 100644 index 0000000..94f018f --- /dev/null +++ b/ui/file_manager/file_manager/foreground/images/volumes/2x/audio.png Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/volumes/2x/audio_active.png b/ui/file_manager/file_manager/foreground/images/volumes/2x/audio_active.png new file mode 100644 index 0000000..e4f9d4d --- /dev/null +++ b/ui/file_manager/file_manager/foreground/images/volumes/2x/audio_active.png Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/volumes/2x/images.png b/ui/file_manager/file_manager/foreground/images/volumes/2x/images.png new file mode 100644 index 0000000..685ed43 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/images/volumes/2x/images.png Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/volumes/2x/images_active.png b/ui/file_manager/file_manager/foreground/images/volumes/2x/images_active.png new file mode 100644 index 0000000..f0a9a84 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/images/volumes/2x/images_active.png Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/volumes/2x/videos.png b/ui/file_manager/file_manager/foreground/images/volumes/2x/videos.png new file mode 100644 index 0000000..3c23e32f --- /dev/null +++ b/ui/file_manager/file_manager/foreground/images/volumes/2x/videos.png Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/volumes/2x/videos_active.png b/ui/file_manager/file_manager/foreground/images/volumes/2x/videos_active.png new file mode 100644 index 0000000..e774fc15 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/images/volumes/2x/videos_active.png Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/volumes/audio.png b/ui/file_manager/file_manager/foreground/images/volumes/audio.png new file mode 100644 index 0000000..7ad30ec --- /dev/null +++ b/ui/file_manager/file_manager/foreground/images/volumes/audio.png Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/volumes/audio_active.png b/ui/file_manager/file_manager/foreground/images/volumes/audio_active.png new file mode 100644 index 0000000..1e4ea54 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/images/volumes/audio_active.png Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/volumes/images.png b/ui/file_manager/file_manager/foreground/images/volumes/images.png new file mode 100644 index 0000000..7bb644f5 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/images/volumes/images.png Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/volumes/images_active.png b/ui/file_manager/file_manager/foreground/images/volumes/images_active.png new file mode 100644 index 0000000..92a67cf --- /dev/null +++ b/ui/file_manager/file_manager/foreground/images/volumes/images_active.png Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/volumes/videos.png b/ui/file_manager/file_manager/foreground/images/volumes/videos.png new file mode 100644 index 0000000..bef8132 --- /dev/null +++ b/ui/file_manager/file_manager/foreground/images/volumes/videos.png Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/volumes/videos_active.png b/ui/file_manager/file_manager/foreground/images/volumes/videos_active.png new file mode 100644 index 0000000..3bc025d --- /dev/null +++ b/ui/file_manager/file_manager/foreground/images/volumes/videos_active.png Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js index 25667c7..7435dc6 100644 --- a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js +++ b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
@@ -90,7 +90,7 @@ 'keydown', this.onKeyDownToOpen_.bind(this)); this.listContainer_.element.addEventListener('command', function(event) { if(event.command.id === 'get-info') - this.display_(); + this.display_(QuickViewUma.WayToOpen.CONTEXT_MENU); }.bind(this)); } @@ -151,7 +151,7 @@ return; if (event.key === ' ') { event.preventDefault(); - this.display_(); + this.display_(QuickViewUma.WayToOpen.SPACE_KEY); } }; @@ -188,13 +188,15 @@ /** * Display quick view. * + * @param {QuickViewUma.WayToOpen=} opt_wayToOpen in which way opening of + * quick view was triggered. Can be omitted if quick view is already open. * @private */ -QuickViewController.prototype.display_ = function() { +QuickViewController.prototype.display_ = function(opt_wayToOpen) { this.updateQuickView_().then(function() { if (!this.quickView_.isOpened()) { this.quickView_.open(); - this.quickViewUma_.onOpened(this.entries_[0]); + this.quickViewUma_.onOpened(this.entries_[0], assert(opt_wayToOpen)); } }.bind(this)); };
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_uma.js b/ui/file_manager/file_manager/foreground/js/quick_view_uma.js index 66d7df66..1391070 100644 --- a/ui/file_manager/file_manager/foreground/js/quick_view_uma.js +++ b/ui/file_manager/file_manager/foreground/js/quick_view_uma.js
@@ -25,6 +25,27 @@ } /** + * In which way quick view was opened. + * @enum {string} + * @const + */ +QuickViewUma.WayToOpen = { + CONTEXT_MENU: 'contextMenu', + SPACE_KEY: 'spaceKey', +}; + +/** + * The order should be consistnet with the definition in histograms.xml. + * + * @const {!Array<QuickViewUma.WayToOpen>} + * @private + */ +QuickViewUma.WayToOpenValues_ = [ + QuickViewUma.WayToOpen.CONTEXT_MENU, + QuickViewUma.WayToOpen.SPACE_KEY, +]; + +/** * Keep the order of this in sync with FileManagerVolumeType in * tools/metrics/histograms/histograms.xml. * @@ -38,6 +59,7 @@ VolumeManagerCommon.VolumeType.ARCHIVE, VolumeManagerCommon.VolumeType.PROVIDED, VolumeManagerCommon.VolumeType.MTP, + VolumeManagerCommon.VolumeType.MEDIA_VIEW, ]; /** @@ -69,9 +91,13 @@ * Exports UMA based on the entry selected when Quick View is opened. * * @param {!FileEntry} entry + * @param {QuickViewUma.WayToOpen} wayToOpen */ -QuickViewUma.prototype.onOpened = function(entry) { +QuickViewUma.prototype.onOpened = function(entry, wayToOpen) { this.exportFileType_(entry, 'QuickView.FileTypeOnLaunch'); + metrics.recordEnum( + 'QuickView.WayToOpen', wayToOpen, QuickViewUma.WayToOpenValues_); + var volumeType = this.volumeManager_.getVolumeInfo(entry).volumeType; if (QuickViewUma.VolumeType.includes(volumeType)) { metrics.recordEnum(
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js index e51bae72..489ee96 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js +++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -641,7 +641,14 @@ 'style', 'background-image: ' + backgroundImage); } icon.setAttribute('volume-type-icon', volumeInfo.volumeType); - icon.setAttribute('volume-subtype', volumeInfo.deviceType || ''); + if (volumeInfo.volumeType === VolumeManagerCommon.VolumeType.MEDIA_VIEW) { + icon.setAttribute( + 'volume-subtype', + VolumeManagerCommon.getMediaViewRootTypeFromVolumeId( + volumeInfo.volumeId)); + } else { + icon.setAttribute('volume-subtype', volumeInfo.deviceType || ''); + } }; /**
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd index 3160c1c..da3b2787 100644 --- a/ui/strings/ui_strings.grd +++ b/ui/strings/ui_strings.grd
@@ -344,6 +344,11 @@ </message> <!--Accessible name strings--> + <if expr="is_macosx"> + <message name="IDS_ACCNAME_TAB_ROLE_DESCRIPTION" desc="A generic description of a tab button's role." meaning="UI element"> + Tab + </message> + </if> <message name="IDS_APP_ACCNAME_CLOSE" desc="The accessible name for the Close button."> Close </message>
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index 0c762ff..4b4ec7f 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn
@@ -845,6 +845,7 @@ "controls/scrollbar/scrollbar_unittest.cc", "controls/slider_unittest.cc", "controls/styled_label_unittest.cc", + "controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm", "controls/tabbed_pane/tabbed_pane_unittest.cc", "controls/table/table_utils_unittest.cc", "controls/table/table_view_unittest.cc",
diff --git a/ui/views/cocoa/bridged_content_view.h b/ui/views/cocoa/bridged_content_view.h index f6952a2..c04515dd 100644 --- a/ui/views/cocoa/bridged_content_view.h +++ b/ui/views/cocoa/bridged_content_view.h
@@ -39,6 +39,9 @@ // The keyDown event currently being handled, nil otherwise. NSEvent* keyDownEvent_; + // Whether there's an active key down event which is not handled yet. + BOOL hasUnhandledKeyDownEvent_; + // The last tooltip text, used to limit updates. base::string16 lastTooltipText_;
diff --git a/ui/views/cocoa/bridged_content_view.mm b/ui/views/cocoa/bridged_content_view.mm index 15ac350..3afe6232 100644 --- a/ui/views/cocoa/bridged_content_view.mm +++ b/ui/views/cocoa/bridged_content_view.mm
@@ -200,19 +200,6 @@ return substring; } -// Returns a character event corresponding to |event|. |event| must be a -// character event itself. -ui::KeyEvent GetCharacterEventFromNSEvent(NSEvent* event) { - DCHECK([event type] == NSKeyDown || [event type] == NSKeyUp); - DCHECK_EQ(1u, [[event characters] length]); - - // [NSEvent characters] already considers the pressed key modifiers. Hence - // send ui::EF_NONE as the key modifier to the KeyEvent constructor. - // E.g. For Alt+S, [NSEvent characters] is 'ß' and not 'S'. - return ui::KeyEvent([[event characters] characterAtIndex:0], - ui::KeyboardCodeFromNSEvent(event), ui::EF_NONE); -} - NSAttributedString* GetAttributedString( const gfx::DecoratedText& decorated_text) { base::scoped_nsobject<NSMutableAttributedString> str( @@ -462,12 +449,12 @@ } - (BOOL)handleUnhandledKeyDownAsKeyEvent { - if (!keyDownEvent_) + if (!hasUnhandledKeyDownEvent_) return NO; ui::KeyEvent event(keyDownEvent_); [self handleKeyEvent:&event]; - keyDownEvent_ = nil; + hasUnhandledKeyDownEvent_ = NO; return event.handled(); } @@ -506,6 +493,42 @@ text = [text string]; bool isCharacterEvent = keyDownEvent_ && [text length] == 1; + // Pass the character event to the View hierarchy. Cases this handles (non- + // exhaustive)- + // - Space key press on controls. Unlike Tab and newline which have + // corresponding action messages, an insertText: message is generated for + // the Space key (insertText:replacementRange: when there's an active + // input context). + // - Menu mnemonic selection. + // Note we create a custom character ui::KeyEvent (and not use the + // ui::KeyEvent(NSEvent*) constructor) since we can't just rely on the event + // key code to get the actual characters from the ui::KeyEvent. This for + // example is necessary for menu mnemonic selection of non-latin text. + + // Don't generate a key event when there is active composition text. These key + // down events should be consumed by the IME and not reach the Views layer. + // For example, on pressing Return to commit composition text, if we passed a + // synthetic key event to the View hierarchy, it will have the effect of + // performing the default action on the current dialog. We do not want this. + + // Also note that a single key down event can cause multiple + // insertText:replacementRange: action messages. Example, on pressing Alt+e, + // the accent (´) character is composed via setMarkedText:. Now on pressing + // the character 'r', two insertText:replacementRange: action messages are + // generated with the text value of accent (´) and 'r' respectively. The key + // down event will have characters field of length 2. The first of these + // insertText messages won't generate a KeyEvent since there'll be active + // marked text. However, a KeyEvent will be generated corresponding to 'r'. + + // Currently there seems to be no use case to pass non-character events routed + // from insertText: handlers to the View hierarchy. + if (isCharacterEvent && ![self hasMarkedText]) { + ui::KeyEvent charEvent([text characterAtIndex:0], + ui::KeyboardCodeFromNSEvent(keyDownEvent_), + ui::EF_NONE); + [self handleKeyEvent:&charEvent]; + hasUnhandledKeyDownEvent_ = NO; + } // Forward the |text| to |textInputClient_| if no menu is active. if (textInputClient_ && ![self activeMenuController]) { @@ -518,34 +541,17 @@ // modifiers. // Also, note we don't use |keyDownEvent_| to generate the synthetic - // ui::KeyEvent since for text inserted using an IME, [keyDownEvent_ - // characters] might not be the same as |text|. This is because - // |keyDownEvent_| will correspond to the event that caused the composition - // text to be confirmed, say, Return key press. + // ui::KeyEvent since for composed text, [keyDownEvent_ characters] might + // not be the same as |text|. This is because |keyDownEvent_| will + // correspond to the event that caused the composition text to be confirmed, + // say, Return key press. if (isCharacterEvent) { textInputClient_->InsertChar(ui::KeyEvent([text characterAtIndex:0], ui::VKEY_UNKNOWN, ui::EF_NONE)); } else { textInputClient_->InsertText(base::SysNSStringToUTF16(text)); } - - keyDownEvent_ = nil; // Handled. - return; - } - - // Only handle the case where no. of characters is 1. Cases not handled (not - // an exhaustive list): - // - |text| contains a unicode surrogate pair, i.e. a single grapheme which - // requires two 16 bit characters. Currently Views menu only supports - // mnemonics using a single 16 bit character, so it is ok to ignore this - // case. - // - Programmatically created events. - // - Input from IME. But this case should not occur since inputContext is - // nil. - if (isCharacterEvent) { - ui::KeyEvent charEvent = GetCharacterEventFromNSEvent(keyDownEvent_); - [self handleKeyEvent:&charEvent]; - keyDownEvent_ = nil; // Handled. + hasUnhandledKeyDownEvent_ = NO; } } @@ -804,12 +810,14 @@ - (void)keyDown:(NSEvent*)theEvent { // Convert the event into an action message, according to OSX key mappings. keyDownEvent_ = theEvent; + hasUnhandledKeyDownEvent_ = YES; [self interpretKeyEvents:@[ theEvent ]]; // If |keyDownEvent_| wasn't cleared during -interpretKeyEvents:, it wasn't // handled. Give Widget accelerators a chance to handle it. [self handleUnhandledKeyDownAsKeyEvent]; - DCHECK(!keyDownEvent_); + DCHECK(!hasUnhandledKeyDownEvent_); + keyDownEvent_ = nil; } - (void)keyUp:(NSEvent*)theEvent { @@ -1333,7 +1341,7 @@ if ([self respondsToSelector:selector]) { [self performSelector:selector withObject:nil]; - keyDownEvent_ = nil; + hasUnhandledKeyDownEvent_ = NO; return; } @@ -1412,7 +1420,7 @@ composition.underlines.push_back(ui::CompositionUnderline( 0, [text length], SK_ColorBLACK, false, SK_ColorTRANSPARENT)); textInputClient_->SetCompositionText(composition); - keyDownEvent_ = nil; // Handled. + hasUnhandledKeyDownEvent_ = NO; } - (void)unmarkText { @@ -1420,7 +1428,7 @@ return; textInputClient_->ConfirmCompositionText(); - keyDownEvent_ = nil; // Handled. + hasUnhandledKeyDownEvent_ = NO; } - (NSArray*)validAttributesForMarkedText {
diff --git a/ui/views/controls/combobox/combobox_unittest.cc b/ui/views/controls/combobox/combobox_unittest.cc index 927a76f7..1863286 100644 --- a/ui/views/controls/combobox/combobox_unittest.cc +++ b/ui/views/controls/combobox/combobox_unittest.cc
@@ -18,6 +18,7 @@ #include "ui/events/event_utils.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/keyboard_codes.h" +#include "ui/events/test/event_generator.h" #include "ui/views/controls/combobox/combobox_listener.h" #include "ui/views/test/combobox_test_api.h" #include "ui/views/test/views_test_base.h" @@ -206,7 +207,8 @@ combobox_->set_id(1); widget_ = new Widget; - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); + Widget::InitParams params = + CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); params.bounds = gfx::Rect(200, 200, 200, 200); widget_->Init(params); View* container = new View(); @@ -216,19 +218,19 @@ combobox_->RequestFocus(); combobox_->SizeToPreferredSize(); + + event_generator_ = + base::MakeUnique<ui::test::EventGenerator>(widget_->GetNativeWindow()); + event_generator_->set_target(ui::test::EventGenerator::Target::WINDOW); } protected: - void SendKeyEvent(ui::KeyboardCode key_code) { - SendKeyEventWithType(key_code, ui::ET_KEY_PRESSED); + void PressKey(ui::KeyboardCode key_code) { + event_generator_->PressKey(key_code, ui::EF_NONE); } - void SendKeyEventWithType(ui::KeyboardCode key_code, ui::EventType type) { - ui::KeyEvent event(type, key_code, ui::EF_NONE); - FocusManager* focus_manager = widget_->GetFocusManager(); - widget_->OnKeyEvent(&event); - if (!event.handled() && focus_manager) - focus_manager->OnKeyEvent(event); + void ReleaseKey(ui::KeyboardCode key_code) { + event_generator_->ReleaseKey(key_code, ui::EF_NONE); } View* GetFocusedView() { @@ -267,28 +269,30 @@ // The current menu show count. int menu_show_count_ = 0; + std::unique_ptr<ui::test::EventGenerator> event_generator_; + private: DISALLOW_COPY_AND_ASSIGN(ComboboxTest); }; TEST_F(ComboboxTest, KeyTest) { InitCombobox(nullptr, Combobox::STYLE_NORMAL); - SendKeyEvent(ui::VKEY_END); + PressKey(ui::VKEY_END); EXPECT_EQ(combobox_->selected_index() + 1, model_->GetItemCount()); - SendKeyEvent(ui::VKEY_HOME); + PressKey(ui::VKEY_HOME); EXPECT_EQ(combobox_->selected_index(), 0); - SendKeyEvent(ui::VKEY_DOWN); - SendKeyEvent(ui::VKEY_DOWN); + PressKey(ui::VKEY_DOWN); + PressKey(ui::VKEY_DOWN); EXPECT_EQ(combobox_->selected_index(), 2); - SendKeyEvent(ui::VKEY_RIGHT); + PressKey(ui::VKEY_RIGHT); EXPECT_EQ(combobox_->selected_index(), 2); - SendKeyEvent(ui::VKEY_LEFT); + PressKey(ui::VKEY_LEFT); EXPECT_EQ(combobox_->selected_index(), 2); - SendKeyEvent(ui::VKEY_UP); + PressKey(ui::VKEY_UP); EXPECT_EQ(combobox_->selected_index(), 1); - SendKeyEvent(ui::VKEY_PRIOR); + PressKey(ui::VKEY_PRIOR); EXPECT_EQ(combobox_->selected_index(), 0); - SendKeyEvent(ui::VKEY_NEXT); + PressKey(ui::VKEY_NEXT); EXPECT_EQ(combobox_->selected_index(), model_->GetItemCount() - 1); } @@ -302,7 +306,8 @@ combobox_->SetEnabled(false); widget_ = new Widget; - Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); + Widget::InitParams params = + CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); params.bounds = gfx::Rect(100, 100, 100, 100); widget_->Init(params); View* container = new View(); @@ -318,17 +323,17 @@ separators.insert(2); InitCombobox(&separators, Combobox::STYLE_NORMAL); EXPECT_EQ(0, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_DOWN); + PressKey(ui::VKEY_DOWN); EXPECT_EQ(1, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_DOWN); + PressKey(ui::VKEY_DOWN); EXPECT_EQ(3, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_UP); + PressKey(ui::VKEY_UP); EXPECT_EQ(1, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_HOME); + PressKey(ui::VKEY_HOME); EXPECT_EQ(0, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_PRIOR); + PressKey(ui::VKEY_PRIOR); EXPECT_EQ(0, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_END); + PressKey(ui::VKEY_END); EXPECT_EQ(9, combobox_->selected_index()); } @@ -339,17 +344,17 @@ separators.insert(0); InitCombobox(&separators, Combobox::STYLE_NORMAL); EXPECT_EQ(1, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_DOWN); + PressKey(ui::VKEY_DOWN); EXPECT_EQ(2, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_DOWN); + PressKey(ui::VKEY_DOWN); EXPECT_EQ(3, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_UP); + PressKey(ui::VKEY_UP); EXPECT_EQ(2, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_HOME); + PressKey(ui::VKEY_HOME); EXPECT_EQ(1, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_PRIOR); + PressKey(ui::VKEY_PRIOR); EXPECT_EQ(1, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_END); + PressKey(ui::VKEY_END); EXPECT_EQ(9, combobox_->selected_index()); } @@ -360,11 +365,11 @@ separators.insert(TestComboboxModel::kItemCount - 1); InitCombobox(&separators, Combobox::STYLE_NORMAL); combobox_->SetSelectedIndex(8); - SendKeyEvent(ui::VKEY_DOWN); + PressKey(ui::VKEY_DOWN); EXPECT_EQ(8, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_UP); + PressKey(ui::VKEY_UP); EXPECT_EQ(7, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_END); + PressKey(ui::VKEY_END); EXPECT_EQ(8, combobox_->selected_index()); } @@ -378,17 +383,17 @@ separators.insert(2); InitCombobox(&separators, Combobox::STYLE_NORMAL); EXPECT_EQ(3, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_DOWN); + PressKey(ui::VKEY_DOWN); EXPECT_EQ(4, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_UP); + PressKey(ui::VKEY_UP); EXPECT_EQ(3, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_NEXT); + PressKey(ui::VKEY_NEXT); EXPECT_EQ(9, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_HOME); + PressKey(ui::VKEY_HOME); EXPECT_EQ(3, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_END); + PressKey(ui::VKEY_END); EXPECT_EQ(9, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_PRIOR); + PressKey(ui::VKEY_PRIOR); EXPECT_EQ(3, combobox_->selected_index()); } @@ -402,9 +407,9 @@ separators.insert(6); InitCombobox(&separators, Combobox::STYLE_NORMAL); combobox_->SetSelectedIndex(3); - SendKeyEvent(ui::VKEY_DOWN); + PressKey(ui::VKEY_DOWN); EXPECT_EQ(7, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_UP); + PressKey(ui::VKEY_UP); EXPECT_EQ(3, combobox_->selected_index()); } @@ -418,17 +423,17 @@ separators.insert(9); InitCombobox(&separators, Combobox::STYLE_NORMAL); combobox_->SetSelectedIndex(6); - SendKeyEvent(ui::VKEY_DOWN); + PressKey(ui::VKEY_DOWN); EXPECT_EQ(6, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_UP); + PressKey(ui::VKEY_UP); EXPECT_EQ(5, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_HOME); + PressKey(ui::VKEY_HOME); EXPECT_EQ(0, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_NEXT); + PressKey(ui::VKEY_NEXT); EXPECT_EQ(6, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_PRIOR); + PressKey(ui::VKEY_PRIOR); EXPECT_EQ(0, combobox_->selected_index()); - SendKeyEvent(ui::VKEY_END); + PressKey(ui::VKEY_END); EXPECT_EQ(6, combobox_->selected_index()); } @@ -540,7 +545,7 @@ combobox_->set_listener(&listener); // With STYLE_NORMAL, the click event is ignored. Instead the menu is shown. - SendKeyEvent(ui::VKEY_RETURN); + PressKey(ui::VKEY_RETURN); EXPECT_EQ(1, menu_show_count_); EXPECT_FALSE(listener.on_perform_action_called()); } @@ -552,7 +557,7 @@ combobox_->set_listener(&listener); // With STYLE_ACTION, the click event is notified and the menu is not shown. - SendKeyEvent(ui::VKEY_RETURN); + PressKey(ui::VKEY_RETURN); EXPECT_EQ(0, menu_show_count_); EXPECT_TRUE(listener.on_perform_action_called()); EXPECT_EQ(0, listener.perform_action_index()); @@ -565,11 +570,11 @@ combobox_->set_listener(&listener); // With STYLE_NORMAL, the click event is ignored. Instead the menu is shwon. - SendKeyEvent(ui::VKEY_SPACE); + PressKey(ui::VKEY_SPACE); EXPECT_EQ(1, menu_show_count_); EXPECT_FALSE(listener.on_perform_action_called()); - SendKeyEventWithType(ui::VKEY_SPACE, ui::ET_KEY_RELEASED); + ReleaseKey(ui::VKEY_SPACE); EXPECT_EQ(1, menu_show_count_); EXPECT_FALSE(listener.on_perform_action_called()); } @@ -582,11 +587,11 @@ // With STYLE_ACTION, the click event is notified after releasing and the menu // is not shown. - SendKeyEvent(ui::VKEY_SPACE); + PressKey(ui::VKEY_SPACE); EXPECT_EQ(0, menu_show_count_); EXPECT_FALSE(listener.on_perform_action_called()); - SendKeyEventWithType(ui::VKEY_SPACE, ui::ET_KEY_RELEASED); + ReleaseKey(ui::VKEY_SPACE); EXPECT_EQ(0, menu_show_count_); EXPECT_TRUE(listener.on_perform_action_called()); EXPECT_EQ(0, listener.perform_action_index());
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane.cc b/ui/views/controls/tabbed_pane/tabbed_pane.cc index f36f68083..552c6ee 100644 --- a/ui/views/controls/tabbed_pane/tabbed_pane.cc +++ b/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPath.h" +#include "ui/accessibility/ax_action_data.h" #include "ui/accessibility/ax_node_data.h" #include "ui/base/default_style.h" #include "ui/base/material_design/material_design_controller.h" @@ -27,6 +28,8 @@ #include "ui/views/layout/layout_manager.h" #include "ui/views/widget/widget.h" +namespace views { + namespace { // TODO(markusheintz|msw): Use NativeTheme colors. @@ -42,9 +45,29 @@ const int kHarmonyTabStripTabHeight = 40; -} // namespace +// The View containing the text for each tab in the tab strip. +class TabLabel : public Label { + public: + explicit TabLabel(const base::string16& tab_title) + : Label(tab_title, + ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta( + ui::kLabelFontSizeDelta, + gfx::Font::NORMAL, + kActiveWeight)) {} -namespace views { + // Label: + void GetAccessibleNodeData(ui::AXNodeData* data) override { + // views::Tab shouldn't expose any of its children in the a11y tree. + // Instead, it should provide the a11y information itself. Normally, + // non-keyboard-focusable children of keyboard-focusable parents are + // ignored, but Tabs only mark the currently selected tab as + // keyboard-focusable. This means all unselected Tabs expose their children + // to the a11y tree. To fix, manually ignore the children. + data->role = ui::AX_ROLE_IGNORED; + } +}; + +} // namespace // static const char TabbedPane::kViewClassName[] = "TabbedPane"; @@ -67,33 +90,6 @@ DISALLOW_COPY_AND_ASSIGN(MdTab); }; -// The tab strip shown above the tab contents. -class TabStrip : public View { - public: - // Internal class name. - static const char kViewClassName[]; - - TabStrip(); - ~TabStrip() override; - - // Called by TabStrip when the selected tab changes. This function is only - // called if |from_tab| is not null, i.e., there was a previously selected - // tab. - virtual void OnSelectedTabChanged(Tab* from_tab, Tab* to_tab); - - // Overridden from View: - const char* GetClassName() const override; - void OnPaintBorder(gfx::Canvas* canvas) override; - - Tab* GetSelectedTab() const; - Tab* GetTabAtDeltaFromSelected(int delta) const; - Tab* GetTabAtIndex(int index) const; - int GetSelectedTabIndex() const; - - private: - DISALLOW_COPY_AND_ASSIGN(TabStrip); -}; - // A subclass of TabStrip that implements the Harmony visual styling. This // class uses a BoxLayout to position tabs. class MdTabStrip : public TabStrip, public gfx::AnimationDelegate { @@ -132,12 +128,7 @@ Tab::Tab(TabbedPane* tabbed_pane, const base::string16& title, View* contents) : tabbed_pane_(tabbed_pane), - title_(new Label( - title, - ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta( - ui::kLabelFontSizeDelta, - gfx::Font::NORMAL, - kActiveWeight))), + title_(new TabLabel(title)), tab_state_(TAB_ACTIVE), contents_(contents) { // Calculate this now while the font list is guaranteed to be bold. @@ -238,6 +229,24 @@ SchedulePaint(); } +void Tab::GetAccessibleNodeData(ui::AXNodeData* data) { + data->role = ui::AX_ROLE_TAB; + data->SetName(title()->text()); + data->AddStateFlag(ui::AX_STATE_SELECTABLE); + if (selected()) + data->AddStateFlag(ui::AX_STATE_SELECTED); +} + +bool Tab::HandleAccessibleAction(const ui::AXActionData& action_data) { + if (action_data.action != ui::AX_ACTION_SET_SELECTION || !enabled()) + return false; + + // It's not clear what should happen if a tab is 'deselected', so the + // AX_ACTION_SET_SELECTION action will always select the tab. + tabbed_pane_->SelectTab(this); + return true; +} + void Tab::OnFocus() { OnStateChanged(); // When the tab gains focus, send an accessibility event indicating that the
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane.h b/ui/views/controls/tabbed_pane/tabbed_pane.h index 4ff3c692..aca7f69 100644 --- a/ui/views/controls/tabbed_pane/tabbed_pane.h +++ b/ui/views/controls/tabbed_pane/tabbed_pane.h
@@ -17,6 +17,11 @@ class TabbedPaneListener; class TabStrip; +namespace test { +class TabbedPaneAccessibilityMacTest; +class TabbedPaneTest; +} + // TabbedPane is a view that shows tabs. When the user clicks on a tab, the // associated view is displayed. class VIEWS_EXPORT TabbedPane : public View { @@ -61,11 +66,8 @@ friend class FocusTraversalTest; friend class Tab; friend class TabStrip; - FRIEND_TEST_ALL_PREFIXES(TabbedPaneTest, AddAndSelect); - FRIEND_TEST_ALL_PREFIXES(TabbedPaneTest, ArrowKeyBindings); - - // Get the Tab (the tabstrip view, not its content) at the valid |index|. - Tab* GetTabAt(int index); + friend class test::TabbedPaneTest; + friend class test::TabbedPaneAccessibilityMacTest; // Get the Tab (the tabstrip view, not its content) at the selected index. Tab* GetSelectedTab(); @@ -121,6 +123,8 @@ void OnGestureEvent(ui::GestureEvent* event) override; gfx::Size GetPreferredSize() const override; const char* GetClassName() const override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + bool HandleAccessibleAction(const ui::AXActionData& action_data) override; void OnFocus() override; void OnBlur() override; bool OnKeyPressed(const ui::KeyEvent& event) override; @@ -150,6 +154,33 @@ DISALLOW_COPY_AND_ASSIGN(Tab); }; +// The tab strip shown above the tab contents. +class TabStrip : public View { + public: + // Internal class name. + static const char kViewClassName[]; + + TabStrip(); + ~TabStrip() override; + + // Called by TabStrip when the selected tab changes. This function is only + // called if |from_tab| is not null, i.e., there was a previously selected + // tab. + virtual void OnSelectedTabChanged(Tab* from_tab, Tab* to_tab); + + // Overridden from View: + const char* GetClassName() const override; + void OnPaintBorder(gfx::Canvas* canvas) override; + + Tab* GetSelectedTab() const; + Tab* GetTabAtDeltaFromSelected(int delta) const; + Tab* GetTabAtIndex(int index) const; + int GetSelectedTabIndex() const; + + private: + DISALLOW_COPY_AND_ASSIGN(TabStrip); +}; + } // namespace views #endif // UI_VIEWS_CONTROLS_TABBED_PANE_TABBED_PANE_H_
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm b/ui/views/controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm new file mode 100644 index 0000000..d0ae166c --- /dev/null +++ b/ui/views/controls/tabbed_pane/tabbed_pane_accessibility_mac_unittest.mm
@@ -0,0 +1,164 @@ +// Copyright 2017 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. + +#import <Cocoa/Cocoa.h> + +#import "base/mac/scoped_nsobject.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/gfx/geometry/point.h" +#import "ui/gfx/mac/coordinate_conversion.h" +#include "ui/views/controls/tabbed_pane/tabbed_pane.h" +#include "ui/views/test/widget_test.h" +#include "ui/views/widget/widget.h" +#import "testing/gtest_mac.h" + +namespace views { +namespace test { + +class TabbedPaneAccessibilityMacTest : public WidgetTest { + public: + TabbedPaneAccessibilityMacTest() {} + + // WidgetTest: + void SetUp() override { + WidgetTest::SetUp(); + widget_ = CreateTopLevelPlatformWidget(); + widget_->SetBounds(gfx::Rect(50, 50, 100, 100)); + tabbed_pane_ = new TabbedPane(); + tabbed_pane_->SetSize(gfx::Size(100, 100)); + + // Create two tabs and position/size them. + tabbed_pane_->AddTab(base::ASCIIToUTF16("Tab 1"), new View()); + tabbed_pane_->AddTab(base::ASCIIToUTF16("Tab 2"), new View()); + tabbed_pane_->Layout(); + + widget_->GetContentsView()->AddChildView(tabbed_pane_); + widget_->Show(); + } + + void TearDown() override { + widget_->CloseNow(); + WidgetTest::TearDown(); + } + + Tab* GetTabAt(int index) { + return static_cast<Tab*>(tabbed_pane_->tab_strip_->child_at(index)); + } + + id AttributeValueAtPoint(NSString* attribute, const gfx::Point& point) { + id value = + [A11yElementAtPoint(point) accessibilityAttributeValue:attribute]; + EXPECT_NE(nil, value); + return value; + } + + id A11yElementAtPoint(const gfx::Point& point) { + // Accessibility hit tests come in Cocoa screen coordinates. + NSPoint ns_point = gfx::ScreenPointToNSPoint(point); + return [widget_->GetNativeWindow() accessibilityHitTest:ns_point]; + } + + gfx::Point TabCenterPoint(int index) { + return GetTabAt(index)->GetBoundsInScreen().CenterPoint(); + } + + protected: + Widget* widget_ = nullptr; + TabbedPane* tabbed_pane_ = nullptr; + + private: + DISALLOW_COPY_AND_ASSIGN(TabbedPaneAccessibilityMacTest); +}; + +// Test the Tab's a11y information compared to a Cocoa NSTabViewItem. +TEST_F(TabbedPaneAccessibilityMacTest, AttributesMatchAppKit) { + // Create a Cocoa NSTabView to test against and select the first tab. + base::scoped_nsobject<NSTabView> cocoa_tab_group( + [[NSTabView alloc] initWithFrame:NSMakeRect(50, 50, 100, 100)]); + NSArray* cocoa_tabs = @[ + [[[NSTabViewItem alloc] init] autorelease], + [[[NSTabViewItem alloc] init] autorelease], + ]; + for (size_t i = 0; i < [cocoa_tabs count]; ++i) { + [cocoa_tabs[i] setLabel:[NSString stringWithFormat:@"Tab %zu", i + 1]]; + [cocoa_tab_group addTabViewItem:cocoa_tabs[i]]; + } + + // General a11y information. + EXPECT_NSEQ( + [cocoa_tabs[0] accessibilityAttributeValue:NSAccessibilityRoleAttribute], + AttributeValueAtPoint(NSAccessibilityRoleAttribute, TabCenterPoint(0))); + EXPECT_NSEQ( + [cocoa_tabs[0] + accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute], + AttributeValueAtPoint(NSAccessibilityRoleDescriptionAttribute, + TabCenterPoint(0))); + EXPECT_NSEQ( + [cocoa_tabs[0] accessibilityAttributeValue:NSAccessibilityTitleAttribute], + AttributeValueAtPoint(NSAccessibilityTitleAttribute, TabCenterPoint(0))); + + // Compare the value attribute against native Cocoa and check it matches up + // with whether tabs are actually selected. + for (int i : {0, 1}) { + NSNumber* cocoa_value = [cocoa_tabs[i] + accessibilityAttributeValue:NSAccessibilityValueAttribute]; + // Verify that only the second tab is selected. + EXPECT_EQ(i ? 0 : 1, [cocoa_value intValue]); + EXPECT_NSEQ(cocoa_value, + AttributeValueAtPoint(NSAccessibilityValueAttribute, + TabCenterPoint(i))); + } + + // NSTabViewItem doesn't support NSAccessibilitySelectedAttribute, so don't + // compare against Cocoa here. + EXPECT_TRUE([AttributeValueAtPoint(NSAccessibilitySelectedAttribute, + TabCenterPoint(0)) boolValue]); + EXPECT_FALSE([AttributeValueAtPoint(NSAccessibilitySelectedAttribute, + TabCenterPoint(1)) boolValue]); +} + +// Make sure tabs can be selected by writing the value attribute. +TEST_F(TabbedPaneAccessibilityMacTest, WritableValue) { + id tab1_a11y = A11yElementAtPoint(TabCenterPoint(0)); + id tab2_a11y = A11yElementAtPoint(TabCenterPoint(1)); + + // Only unselected tabs should be writable. + EXPECT_FALSE([tab1_a11y + accessibilityIsAttributeSettable:NSAccessibilityValueAttribute]); + EXPECT_TRUE([tab2_a11y + accessibilityIsAttributeSettable:NSAccessibilityValueAttribute]); + + // Select the second tab. AXValue actually accepts any type, but for tabs, + // Cocoa uses an integer. Despite this, the Accessibility Inspector provides a + // textfield to set the value for a control, so test this with an NSString. + [tab2_a11y accessibilitySetValue:@"string" + forAttribute:NSAccessibilityValueAttribute]; + EXPECT_EQ(0, [AttributeValueAtPoint(NSAccessibilityValueAttribute, + TabCenterPoint(0)) intValue]); + EXPECT_EQ(1, [AttributeValueAtPoint(NSAccessibilityValueAttribute, + TabCenterPoint(1)) intValue]); + EXPECT_FALSE([AttributeValueAtPoint(NSAccessibilitySelectedAttribute, + TabCenterPoint(0)) boolValue]); + EXPECT_TRUE([AttributeValueAtPoint(NSAccessibilitySelectedAttribute, + TabCenterPoint(1)) boolValue]); + EXPECT_TRUE(GetTabAt(1)->selected()); + + // It doesn't make sense to 'deselect' a tab (i.e., without specifying another + // to select). So any value passed to -accessibilitySetValue: should select + // that tab. Try an empty string. + [tab1_a11y accessibilitySetValue:@"" + forAttribute:NSAccessibilityValueAttribute]; + EXPECT_EQ(1, [AttributeValueAtPoint(NSAccessibilityValueAttribute, + TabCenterPoint(0)) intValue]); + EXPECT_EQ(0, [AttributeValueAtPoint(NSAccessibilityValueAttribute, + TabCenterPoint(1)) intValue]); + EXPECT_TRUE([AttributeValueAtPoint(NSAccessibilitySelectedAttribute, + TabCenterPoint(0)) boolValue]); + EXPECT_FALSE([AttributeValueAtPoint(NSAccessibilitySelectedAttribute, + TabCenterPoint(1)) boolValue]); + EXPECT_TRUE(GetTabAt(0)->selected()); +} + +} // namespace test +} // namespace views
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc b/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc index e02a252..8761683 100644 --- a/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc +++ b/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
@@ -10,121 +10,183 @@ #include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/accessibility/ax_action_data.h" +#include "ui/accessibility/ax_enums.h" #include "ui/events/keycodes/keyboard_code_conversion.h" +#include "ui/views/accessibility/native_view_accessibility.h" +#include "ui/views/test/test_views.h" #include "ui/views/test/views_test_base.h" +#include "ui/views/widget/widget.h" using base::ASCIIToUTF16; namespace views { +namespace test { +namespace { -// A view for testing that takes a fixed preferred size upon construction. -class FixedSizeView : public View { +base::string16 DefaultTabTitle() { + return ASCIIToUTF16("tab"); +} + +} // namespace + +class TabbedPaneTest : public ViewsTestBase { public: - explicit FixedSizeView(const gfx::Size& size) - : size_(size) {} + TabbedPaneTest() { + tabbed_pane_ = base::MakeUnique<TabbedPane>(); + tabbed_pane_->set_owned_by_client(); + } - // Overridden from View: - gfx::Size GetPreferredSize() const override { return size_; } + protected: + Tab* GetTabAt(int index) { + return static_cast<Tab*>(tabbed_pane_->tab_strip_->child_at(index)); + } + + View* GetSelectedTabContentView() { + return tabbed_pane_->GetSelectedTabContentView(); + } + + void SendKeyPressToSelectedTab(ui::KeyboardCode keyboard_code) { + tabbed_pane_->GetSelectedTab()->OnKeyPressed( + ui::KeyEvent(ui::ET_KEY_PRESSED, keyboard_code, + ui::UsLayoutKeyboardCodeToDomCode(keyboard_code), 0)); + } + + std::unique_ptr<TabbedPane> tabbed_pane_; private: - const gfx::Size size_; - - DISALLOW_COPY_AND_ASSIGN(FixedSizeView); + DISALLOW_COPY_AND_ASSIGN(TabbedPaneTest); }; -typedef ViewsTestBase TabbedPaneTest; - // Tests TabbedPane::GetPreferredSize() and TabbedPane::Layout(). TEST_F(TabbedPaneTest, SizeAndLayout) { - std::unique_ptr<TabbedPane> tabbed_pane(new TabbedPane()); - View* child1 = new FixedSizeView(gfx::Size(20, 10)); - tabbed_pane->AddTab(ASCIIToUTF16("tab1"), child1); - View* child2 = new FixedSizeView(gfx::Size(5, 5)); - tabbed_pane->AddTab(ASCIIToUTF16("tab2"), child2); - tabbed_pane->SelectTabAt(0); + View* child1 = new StaticSizedView(gfx::Size(20, 10)); + tabbed_pane_->AddTab(ASCIIToUTF16("tab1"), child1); + View* child2 = new StaticSizedView(gfx::Size(5, 5)); + tabbed_pane_->AddTab(ASCIIToUTF16("tab2"), child2); + tabbed_pane_->SelectTabAt(0); - // The |tabbed_pane| implementation of Views has no border by default. + // The |tabbed_pane_| implementation of Views has no border by default. // Therefore it should be as wide as the widest tab. The native Windows // tabbed pane has a border that used up extra space. Therefore the preferred // width is larger than the largest child. - gfx::Size pref(tabbed_pane->GetPreferredSize()); + gfx::Size pref(tabbed_pane_->GetPreferredSize()); EXPECT_GE(pref.width(), 20); EXPECT_GT(pref.height(), 10); // The bounds of our children should be smaller than the tabbed pane's bounds. - tabbed_pane->SetBounds(0, 0, 100, 200); + tabbed_pane_->SetBounds(0, 0, 100, 200); RunPendingMessages(); gfx::Rect bounds(child1->bounds()); EXPECT_GT(bounds.width(), 0); - // The |tabbed_pane| has no border. Therefore the children should be as wide - // as the |tabbed_pane|. + // The |tabbed_pane_| has no border. Therefore the children should be as wide + // as the |tabbed_pane_|. EXPECT_LE(bounds.width(), 100); EXPECT_GT(bounds.height(), 0); EXPECT_LT(bounds.height(), 200); // If we switch to the other tab, it should get assigned the same bounds. - tabbed_pane->SelectTabAt(1); + tabbed_pane_->SelectTabAt(1); EXPECT_EQ(bounds, child2->bounds()); } TEST_F(TabbedPaneTest, AddAndSelect) { - std::unique_ptr<TabbedPane> tabbed_pane(new TabbedPane()); - // Add several tabs; only the first should be a selected automatically. + // Add several tabs; only the first should be selected automatically. for (int i = 0; i < 3; ++i) { View* tab = new View(); - tabbed_pane->AddTab(ASCIIToUTF16("tab"), tab); - EXPECT_EQ(i + 1, tabbed_pane->GetTabCount()); - EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex()); + tabbed_pane_->AddTab(DefaultTabTitle(), tab); + EXPECT_EQ(i + 1, tabbed_pane_->GetTabCount()); + EXPECT_EQ(0, tabbed_pane_->GetSelectedTabIndex()); } // Select each tab. - for (int i = 0; i < tabbed_pane->GetTabCount(); ++i) { - tabbed_pane->SelectTabAt(i); - EXPECT_EQ(i, tabbed_pane->GetSelectedTabIndex()); + for (int i = 0; i < tabbed_pane_->GetTabCount(); ++i) { + tabbed_pane_->SelectTabAt(i); + EXPECT_EQ(i, tabbed_pane_->GetSelectedTabIndex()); } // Add a tab at index 0, it should not be selected automatically. View* tab0 = new View(); - tabbed_pane->AddTabAtIndex(0, ASCIIToUTF16("tab0"), tab0); - EXPECT_NE(tab0, tabbed_pane->GetSelectedTabContentView()); - EXPECT_NE(0, tabbed_pane->GetSelectedTabIndex()); -} - -ui::KeyEvent MakeKeyPressedEvent(ui::KeyboardCode keyboard_code, int flags) { - return ui::KeyEvent(ui::ET_KEY_PRESSED, keyboard_code, - ui::UsLayoutKeyboardCodeToDomCode(keyboard_code), flags); + tabbed_pane_->AddTabAtIndex(0, ASCIIToUTF16("tab0"), tab0); + EXPECT_NE(tab0, GetSelectedTabContentView()); + EXPECT_NE(0, tabbed_pane_->GetSelectedTabIndex()); } TEST_F(TabbedPaneTest, ArrowKeyBindings) { - std::unique_ptr<TabbedPane> tabbed_pane(new TabbedPane()); - // Add several tabs; only the first should be a selected automatically. + // Add several tabs; only the first should be selected automatically. for (int i = 0; i < 3; ++i) { View* tab = new View(); - tabbed_pane->AddTab(ASCIIToUTF16("tab"), tab); - EXPECT_EQ(i + 1, tabbed_pane->GetTabCount()); + tabbed_pane_->AddTab(DefaultTabTitle(), tab); + EXPECT_EQ(i + 1, tabbed_pane_->GetTabCount()); } - EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex()); + EXPECT_EQ(0, tabbed_pane_->GetSelectedTabIndex()); // Right arrow should select tab 1: - tabbed_pane->GetSelectedTab()->OnKeyPressed( - MakeKeyPressedEvent(ui::VKEY_RIGHT, 0)); - EXPECT_EQ(1, tabbed_pane->GetSelectedTabIndex()); + SendKeyPressToSelectedTab(ui::VKEY_RIGHT); + EXPECT_EQ(1, tabbed_pane_->GetSelectedTabIndex()); // Left arrow should select tab 0: - tabbed_pane->GetSelectedTab()->OnKeyPressed( - MakeKeyPressedEvent(ui::VKEY_LEFT, 0)); - EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex()); + SendKeyPressToSelectedTab(ui::VKEY_LEFT); + EXPECT_EQ(0, tabbed_pane_->GetSelectedTabIndex()); // Left arrow again should wrap to tab 2: - tabbed_pane->GetSelectedTab()->OnKeyPressed( - MakeKeyPressedEvent(ui::VKEY_LEFT, 0)); - EXPECT_EQ(2, tabbed_pane->GetSelectedTabIndex()); + SendKeyPressToSelectedTab(ui::VKEY_LEFT); + EXPECT_EQ(2, tabbed_pane_->GetSelectedTabIndex()); // Right arrow again should wrap to tab 0: - tabbed_pane->GetSelectedTab()->OnKeyPressed( - MakeKeyPressedEvent(ui::VKEY_RIGHT, 0)); - EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex()); + SendKeyPressToSelectedTab(ui::VKEY_RIGHT); + EXPECT_EQ(0, tabbed_pane_->GetSelectedTabIndex()); } +// Use TabbedPane::HandleAccessibleAction() to select tabs and make sure their +// a11y information is correct. +TEST_F(TabbedPaneTest, SelectTabWithAccessibleAction) { + // Testing accessibility information requires the View to have a Widget. + Widget* widget = new Widget; + Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); + widget->Init(params); + widget->GetContentsView()->AddChildView(tabbed_pane_.get()); + widget->Show(); + + constexpr int kNumTabs = 3; + for (int i = 0; i < kNumTabs; ++i) { + tabbed_pane_->AddTab(DefaultTabTitle(), new View()); + } + // Check the first tab is selected. + EXPECT_EQ(0, tabbed_pane_->GetSelectedTabIndex()); + + // Check the a11y information for each tab. + for (int i = 0; i < kNumTabs; ++i) { + NativeViewAccessibility* nva = NativeViewAccessibility::Create(GetTabAt(i)); + ui::AXNodeData data = nva->GetData(); + SCOPED_TRACE(testing::Message() << "Tab at index: " << i); + EXPECT_EQ(ui::AX_ROLE_TAB, data.role); + EXPECT_EQ(DefaultTabTitle(), data.GetString16Attribute(ui::AX_ATTR_NAME)); + EXPECT_TRUE(data.HasStateFlag(ui::AX_STATE_SELECTABLE)); + EXPECT_EQ(i == 0, data.HasStateFlag(ui::AX_STATE_SELECTED)); + nva->Destroy(); + } + + ui::AXActionData action; + action.action = ui::AX_ACTION_SET_SELECTION; + // Select the first tab. + NativeViewAccessibility* nva = NativeViewAccessibility::Create(GetTabAt(0)); + nva->AccessibilityPerformAction(action); + EXPECT_EQ(0, tabbed_pane_->GetSelectedTabIndex()); + nva->Destroy(); + + // Select the second tab. + nva = NativeViewAccessibility::Create(GetTabAt(1)); + nva->AccessibilityPerformAction(action); + EXPECT_EQ(1, tabbed_pane_->GetSelectedTabIndex()); + // Select the second tab again. + nva->AccessibilityPerformAction(action); + EXPECT_EQ(1, tabbed_pane_->GetSelectedTabIndex()); + nva->Destroy(); + + widget->CloseNow(); +} + +} // namespace test } // namespace views
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index 08578add..8b062753 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc
@@ -1303,18 +1303,24 @@ } bool Widget::SetInitialFocus(ui::WindowShowState show_state) { + FocusManager* focus_manager = GetFocusManager(); View* v = widget_delegate_->GetInitiallyFocusedView(); if (!focus_on_creation_ || show_state == ui::SHOW_STATE_INACTIVE || show_state == ui::SHOW_STATE_MINIMIZED) { // If not focusing the window now, tell the focus manager which view to // focus when the window is restored. - if (v && focus_manager_.get()) - focus_manager_->SetStoredFocusView(v); + if (v && focus_manager) + focus_manager->SetStoredFocusView(v); return true; } - if (v) + if (v) { v->RequestFocus(); - return !!v; + // If the request for focus was unsuccessful, fall back to using the first + // focusable View instead. + if (focus_manager && focus_manager->GetFocusedView() == nullptr) + focus_manager->AdvanceFocus(false); + } + return !!focus_manager->GetFocusedView(); } ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/window/dialog_delegate_unittest.cc b/ui/views/window/dialog_delegate_unittest.cc index 10e45c0..bf2a32e 100644 --- a/ui/views/window/dialog_delegate_unittest.cc +++ b/ui/views/window/dialog_delegate_unittest.cc
@@ -18,6 +18,10 @@ #include "ui/views/window/dialog_client_view.h" #include "ui/views/window/dialog_delegate.h" +#if defined(OS_MACOSX) +#include "ui/base/test/scoped_fake_full_keyboard_access.h" +#endif + namespace views { namespace { @@ -273,4 +277,38 @@ EXPECT_EQ(dialog()->input(), dialog()->GetFocusManager()->GetFocusedView()); } +// If the initially focused View provided is unfocusable, check the next +// available focusable View is focused. +TEST_F(DialogTest, UnfocusableInitialFocus) { +#if defined(OS_MACOSX) + // On Mac, make all buttons unfocusable by turning off full keyboard access. + // This is the more common configuration, and if a dialog has a focusable + // textfield, tree or table, that should obtain focus instead. + ui::test::ScopedFakeFullKeyboardAccess::GetInstance() + ->set_full_keyboard_access_state(false); +#endif + + DialogDelegateView* dialog = new DialogDelegateView(); + Textfield* textfield = new Textfield(); + dialog->AddChildView(textfield); + Widget* dialog_widget = + DialogDelegate::CreateDialogWidget(dialog, GetContext(), nullptr); + +#if !defined(OS_MACOSX) + // For non-Mac, turn off focusability on all the dialog's buttons manually. + // This achieves the same effect as disabling full keyboard access. + DialogClientView* dcv = dialog->GetDialogClientView(); + dcv->ok_button()->SetFocusBehavior(View::FocusBehavior::NEVER); + dcv->cancel_button()->SetFocusBehavior(View::FocusBehavior::NEVER); +#endif + + // On showing the dialog, the initially focused View will be the OK button. + // Since it is no longer focusable, focus should advance to the next focusable + // View, which is |textfield|. + dialog_widget->Show(); + EXPECT_TRUE(textfield->HasFocus()); + EXPECT_EQ(textfield, dialog->GetFocusManager()->GetFocusedView()); + dialog_widget->Close(); +} + } // namespace views