diff --git a/DEPS b/DEPS index 6ba7951..4dda9f72 100644 --- a/DEPS +++ b/DEPS
@@ -45,7 +45,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '9acf4ad109f6d4c642272132133addc2c7dbeb97', + 'v8_revision': '8b35cb30de6b2ed5e57ff35064870b60a18960ba', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other.
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 79f94ae8b..05b748a 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -3339,12 +3339,6 @@ FEATURE_VALUE_TYPE(features::kCaptureThumbnailOnNavigatingAway)}, #if defined(OS_CHROMEOS) - {"use-cros-midi-service", flag_descriptions::kUseCrosMidiServiceName, - flag_descriptions::kUseCrosMidiServiceNameDescription, kOsCrOS, - FEATURE_VALUE_TYPE(midi::features::kMidiManagerCros)}, -#endif // defined(OS_CHROMEOS) - -#if defined(OS_CHROMEOS) {"disable-lock-screen-apps", flag_descriptions::kDisableLockScreenAppsName, flag_descriptions::kDisableLockScreenAppsDescription, kOsCrOS, SINGLE_VALUE_TYPE(chromeos::switches::kDisableLockScreenApps)},
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 798f3df..685c912c5 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -211,6 +211,7 @@ #include "device/usb/public/interfaces/device_manager.mojom.h" #include "extensions/features/features.h" #include "google_apis/gaia/gaia_urls.h" +#include "google_apis/google_api_keys.h" #include "gpu/config/gpu_switches.h" #include "media/audio/audio_manager.h" #include "media/media_features.h" @@ -2105,6 +2106,10 @@ return NULL; } +std::string ChromeContentBrowserClient::GetGeolocationApiKey() { + return google_apis::GetAPIKey(); +} + QuotaPermissionContext* ChromeContentBrowserClient::CreateQuotaPermissionContext() { return new ChromeQuotaPermissionContext();
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index f766e0e..dce1c50 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -180,6 +180,7 @@ net::URLRequestContext* OverrideRequestContextForURL( const GURL& url, content::ResourceContext* context) override; + std::string GetGeolocationApiKey() override; content::QuotaPermissionContext* CreateQuotaPermissionContext() override; void GetQuotaSettings( content::BrowserContext* context,
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index ec9d80a3..8fcb692 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2563,11 +2563,6 @@ "Enables inspection of native UI elements. For local inspection use " "chrome://inspect#other"; -const char kUseCrosMidiServiceName[] = "Use Chrome OS MIDI Service"; -const char kUseCrosMidiServiceNameDescription[] = - "Use Chrome OS MIDI Service for Web MIDI and allow ARC to support Android " - "MIDI."; - const char kUseMusName[] = "Mus"; const char kUseMusDescription[] = "Enable the Mojo UI service."; const char kEnableMashDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 67262e3f..1732445 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1566,9 +1566,6 @@ extern const char kUiDevToolsName[]; extern const char kUiDevToolsDescription[]; -extern const char kUseCrosMidiServiceName[]; -extern const char kUseCrosMidiServiceNameDescription[]; - extern const char kUseMusName[]; extern const char kUseMusDescription[]; extern const char kEnableMashDescription[];
diff --git a/chrome/browser/geolocation/geolocation_browsertest.cc b/chrome/browser/geolocation/geolocation_browsertest.cc index c8e8f63..5e91d7f8 100644 --- a/chrome/browser/geolocation/geolocation_browsertest.cc +++ b/chrome/browser/geolocation/geolocation_browsertest.cc
@@ -35,7 +35,11 @@ #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" #include "device/geolocation/geoposition.h" +#include "device/geolocation/network_location_request.h" +#include "google_apis/google_api_keys.h" +#include "net/base/escape.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/url_request/test_url_fetcher_factory.h" namespace { @@ -165,6 +169,39 @@ DISALLOW_COPY_AND_ASSIGN(PermissionRequestObserver); }; +// Observer that waits until a TestURLFetcher with the specified fetcher_id +// starts, after which it is made available through .fetcher(). +class TestURLFetcherObserver : public net::TestURLFetcher::DelegateForTests { + public: + explicit TestURLFetcherObserver(int expected_fetcher_id) + : expected_fetcher_id_(expected_fetcher_id) { + factory_.SetDelegateForTests(this); + } + virtual ~TestURLFetcherObserver() {} + + void Wait() { loop_.Run(); } + + net::TestURLFetcher* fetcher() { return fetcher_; } + + // net::TestURLFetcher::DelegateForTests: + void OnRequestStart(int fetcher_id) override { + if (fetcher_id == expected_fetcher_id_) { + fetcher_ = factory_.GetFetcherByID(fetcher_id); + fetcher_->SetDelegateForTests(nullptr); + factory_.SetDelegateForTests(nullptr); + loop_.Quit(); + } + } + void OnChunkUpload(int fetcher_id) override {} + void OnRequestEnd(int fetcher_id) override {} + + private: + const int expected_fetcher_id_; + net::TestURLFetcher* fetcher_ = nullptr; + net::TestURLFetcherFactory factory_; + base::RunLoop loop_; +}; + } // namespace @@ -458,6 +495,36 @@ ExpectPosition(fake_latitude(), fake_longitude()); } +#if defined(OS_CHROMEOS) +// ChromeOS fails to perform network geolocation when zero wifi networks are +// detected in a scan: https://crbug.com/767300. +#define MAYBE_UrlWithApiKey DISABLED_UrlWithApiKey +#else +#define MAYBE_UrlWithApiKey UrlWithApiKey +#endif +// Tests that Chrome makes a network geolocation request to the correct URL +// including Google API key query param. +IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, MAYBE_UrlWithApiKey) { + ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT)); + + // Unique ID (derived from Gerrit CL number): + device::NetworkLocationRequest::url_fetcher_id_for_tests = 675023; + + // Intercept the URLFetcher from network geolocation request. + TestURLFetcherObserver observer( + device::NetworkLocationRequest::url_fetcher_id_for_tests); + ASSERT_TRUE(WatchPositionAndGrantPermission()); + observer.Wait(); + DCHECK(observer.fetcher()); + + // Verify full URL including Google API key. + const std::string expected_url = + "https://www.googleapis.com/geolocation/v1/geolocate?key=" + + net::EscapeQueryParamValue(google_apis::GetAPIKey(), true); + EXPECT_EQ(expected_url, + observer.fetcher()->GetOriginalURL().possibly_invalid_spec()); +} + IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, ErrorOnPermissionDenied) { ASSERT_NO_FATAL_FAILURE(Initialize(INITIALIZATION_DEFAULT)); EXPECT_TRUE(WatchPositionAndDenyPermission());
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller.cc b/chrome/browser/media/webrtc/media_stream_devices_controller.cc index cc59ecc6f..08fa971 100644 --- a/chrome/browser/media/webrtc/media_stream_devices_controller.cc +++ b/chrome/browser/media/webrtc/media_stream_devices_controller.cc
@@ -437,8 +437,10 @@ } content_settings_->OnMediaStreamPermissionSet( - request_.security_origin, microphone_camera_state, selected_audio_device, - selected_video_device, requested_audio_device, requested_video_device); + PermissionManager::Get(profile_)->GetCanonicalOrigin( + request_.security_origin), + microphone_camera_state, selected_audio_device, selected_video_device, + requested_audio_device, requested_video_device); } ContentSetting MediaStreamDevicesController::GetContentSetting(
diff --git a/chrome/browser/permissions/permission_manager.cc b/chrome/browser/permissions/permission_manager.cc index 563a03d..d2d6177 100644 --- a/chrome/browser/permissions/permission_manager.cc +++ b/chrome/browser/permissions/permission_manager.cc
@@ -24,10 +24,12 @@ #include "chrome/browser/permissions/permission_result.h" #include "chrome/browser/permissions/permission_uma_util.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/search_engines/ui_thread_search_terms_data.h" #include "chrome/browser/storage/durable_storage_permission_context.h" #include "chrome/browser/tab_contents/tab_util.h" #include "chrome/browser/vr/vr_tab_helper.h" #include "chrome/common/features.h" +#include "chrome/common/url_constants.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/permission_type.h" @@ -309,6 +311,13 @@ } } +GURL PermissionManager::GetCanonicalOrigin(const GURL& url) const { + if (url.GetOrigin() == GURL(chrome::kChromeSearchLocalNtpUrl).GetOrigin()) + return GURL(UIThreadSearchTermsData(profile_).GoogleBaseURLValue()); + + return url; +} + int PermissionManager::RequestPermission( ContentSettingsType content_settings_type, content::RenderFrameHost* render_frame_host, @@ -344,6 +353,7 @@ } GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin(); + GURL canonical_requesting_origin = GetCanonicalOrigin(requesting_origin); int request_id = pending_requests_.Add(base::MakeUnique<PendingRequest>( render_frame_host, permissions, callback)); @@ -358,7 +368,7 @@ auto callback = base::MakeUnique<PermissionResponseCallback>( weak_ptr_factory_.GetWeakPtr(), request_id, i); context->RequestPermission( - web_contents, request, requesting_origin, user_gesture, + web_contents, request, canonical_requesting_origin, user_gesture, base::Bind( &PermissionResponseCallback::OnPermissionsRequestResponseStatus, base::Passed(&callback))); @@ -479,8 +489,7 @@ GetPermissionContext(PermissionTypeToContentSetting(permission)); if (!context) return; - - context->ResetPermission(requesting_origin.GetOrigin(), + context->ResetPermission(GetCanonicalOrigin(requesting_origin).GetOrigin(), embedding_origin.GetOrigin()); } @@ -499,7 +508,7 @@ GetPermissionContext(PermissionTypeToContentSetting(permission)); if (context) { result = context->UpdatePermissionStatusWithDeviceStatus( - result, requesting_origin, embedding_origin); + result, GetCanonicalOrigin(requesting_origin), embedding_origin); } return ContentSettingToPermissionStatus(result.content_setting); @@ -517,7 +526,7 @@ ContentSettingsType content_type = PermissionTypeToContentSetting(permission); auto subscription = base::MakeUnique<Subscription>(); subscription->permission = content_type; - subscription->requesting_origin = requesting_origin; + subscription->requesting_origin = GetCanonicalOrigin(requesting_origin); subscription->embedding_origin = embedding_origin; subscription->callback = base::Bind(&SubscriptionCallbackWrapper, callback); @@ -589,9 +598,10 @@ content::RenderFrameHost* render_frame_host, const GURL& requesting_origin, const GURL& embedding_origin) { + GURL canonical_requesting_origin = GetCanonicalOrigin(requesting_origin); PermissionContextBase* context = GetPermissionContext(permission); PermissionResult result = context->GetPermissionStatus( - render_frame_host, requesting_origin.GetOrigin(), + render_frame_host, canonical_requesting_origin.GetOrigin(), embedding_origin.GetOrigin()); DCHECK(result.content_setting == CONTENT_SETTING_ALLOW || result.content_setting == CONTENT_SETTING_ASK ||
diff --git a/chrome/browser/permissions/permission_manager.h b/chrome/browser/permissions/permission_manager.h index 4b770f1..f747a35 100644 --- a/chrome/browser/permissions/permission_manager.h +++ b/chrome/browser/permissions/permission_manager.h
@@ -34,6 +34,15 @@ explicit PermissionManager(Profile* profile); ~PermissionManager() override; + // Converts from |url|'s actual origin to the "canonical origin" that should + // be used for the purpose of requesting/storing permissions. For example, the + // origin of the local NTP gets mapped to the Google base URL instead. All the + // public methods below, such as RequestPermission or GetPermissionStatus, + // take the actual origin and do the canonicalization internally. You only + // need to call this directly if you do something else with the origin, such + // as display it in the UI. + GURL GetCanonicalOrigin(const GURL& url) const; + // Callers from within chrome/ should use the methods which take the // ContentSettingsType enum. The methods which take PermissionType values // are for the content::PermissionManager overrides and shouldn't be used
diff --git a/chrome/browser/permissions/permission_manager_unittest.cc b/chrome/browser/permissions/permission_manager_unittest.cc index 06d7010..cc096534 100644 --- a/chrome/browser/permissions/permission_manager_unittest.cc +++ b/chrome/browser/permissions/permission_manager_unittest.cc
@@ -10,8 +10,10 @@ #include "chrome/browser/permissions/permission_manager_factory.h" #include "chrome/browser/permissions/permission_request_manager.h" #include "chrome/browser/permissions/permission_result.h" +#include "chrome/browser/search_engines/ui_thread_search_terms_data.h" #include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h" #include "chrome/browser/vr/vr_tab_helper.h" +#include "chrome/common/url_constants.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" #include "components/content_settings/core/browser/host_content_settings_map.h" @@ -96,6 +98,10 @@ return other_url_; } + GURL google_base_url() const { + return GURL(UIThreadSearchTermsData(profile_.get()).GoogleBaseURLValue()); + } + bool callback_called() const { return callback_called_; } @@ -494,3 +500,29 @@ EXPECT_EQ(CONTENT_SETTING_ASK, result.content_setting); EXPECT_EQ(PermissionStatusSource::UNSPECIFIED, result.source); } + +TEST_F(PermissionManagerTest, GetCanonicalOrigin) { + const GURL google_com("https://www.google.com"); + const GURL google_de("https://www.google.de"); + const GURL other_url("https://other.url"); + const GURL google_base = google_base_url().GetOrigin(); + const GURL local_ntp = GURL(chrome::kChromeSearchLocalNtpUrl).GetOrigin(); + const GURL remote_ntp = GURL(std::string("chrome-search://") + + chrome::kChromeSearchRemoteNtpHost); + const GURL other_chrome_search = GURL("chrome-search://not-local-ntp"); + + // "Normal" URLs are not affected by GetCanonicalOrigin. + EXPECT_EQ(google_com, GetPermissionManager()->GetCanonicalOrigin(google_com)); + EXPECT_EQ(google_de, GetPermissionManager()->GetCanonicalOrigin(google_de)); + EXPECT_EQ(other_url, GetPermissionManager()->GetCanonicalOrigin(other_url)); + EXPECT_EQ(google_base, + GetPermissionManager()->GetCanonicalOrigin(google_base)); + + // The local NTP URL gets mapped to the Google base URL. + EXPECT_EQ(google_base, GetPermissionManager()->GetCanonicalOrigin(local_ntp)); + // However, other chrome-search:// URLs, including the remote NTP URL, are + // not affected. + EXPECT_EQ(remote_ntp, GetPermissionManager()->GetCanonicalOrigin(remote_ntp)); + EXPECT_EQ(other_chrome_search, + GetPermissionManager()->GetCanonicalOrigin(other_chrome_search)); +}
diff --git a/chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.cc b/chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.cc index 3447053..7be876e 100644 --- a/chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.cc +++ b/chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.cc
@@ -40,8 +40,10 @@ prompts_.push_back(prompt); show_count_++; requests_count_ = delegate->Requests().size(); - for (const PermissionRequest* request : delegate->Requests()) + for (const PermissionRequest* request : delegate->Requests()) { request_types_seen_.push_back(request->GetPermissionRequestType()); + request_origins_seen_.push_back(request->GetOrigin()); + } if (!show_bubble_quit_closure_.is_null()) show_bubble_quit_closure_.Run(); @@ -60,6 +62,7 @@ show_count_ = 0; requests_count_ = 0; request_types_seen_.clear(); + request_origins_seen_.clear(); } void MockPermissionPromptFactory::DocumentOnLoadCompletedInMainFrame() { @@ -78,6 +81,10 @@ return base::ContainsValue(request_types_seen_, type); } +bool MockPermissionPromptFactory::RequestOriginSeen(const GURL& origin) { + return base::ContainsValue(request_origins_seen_, origin); +} + void MockPermissionPromptFactory::WaitForPermissionBubble() { if (is_visible()) return;
diff --git a/chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h b/chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h index 2671e919..4db9673 100644 --- a/chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h +++ b/chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h
@@ -11,6 +11,7 @@ #include "chrome/browser/permissions/permission_request.h" #include "chrome/browser/permissions/permission_request_manager.h" #include "chrome/browser/ui/permission_bubble/permission_prompt.h" +#include "url/gurl.h" class MockPermissionPrompt; @@ -57,6 +58,8 @@ int TotalRequestCount(); // Whether the specified permission was shown in a prompt. bool RequestTypeSeen(PermissionRequestType type); + // Whether a prompt with the given origin was shown. + bool RequestOriginSeen(const GURL& origin); void WaitForPermissionBubble(); @@ -75,6 +78,7 @@ int show_count_; int requests_count_; std::vector<PermissionRequestType> request_types_seen_; + std::vector<GURL> request_origins_seen_; std::vector<MockPermissionPrompt*> prompts_; PermissionRequestManager::AutoResponseType response_type_;
diff --git a/chrome/browser/ui/search/local_ntp_browsertest.cc b/chrome/browser/ui/search/local_ntp_browsertest.cc index 0ff9490..cf428cd 100644 --- a/chrome/browser/ui/search/local_ntp_browsertest.cc +++ b/chrome/browser/ui/search/local_ntp_browsertest.cc
@@ -15,6 +15,10 @@ #include "base/test/scoped_feature_list.h" #include "base/threading/thread_restrictions.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/permissions/permission_manager.h" +#include "chrome/browser/permissions/permission_manager_factory.h" +#include "chrome/browser/permissions/permission_request_manager.h" +#include "chrome/browser/permissions/permission_result.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search/one_google_bar/one_google_bar_data.h" #include "chrome/browser/search/one_google_bar/one_google_bar_fetcher.h" @@ -22,9 +26,11 @@ #include "chrome/browser/search/one_google_bar/one_google_bar_service_factory.h" #include "chrome/browser/search/search.h" #include "chrome/browser/search_engines/template_url_service_factory.h" +#include "chrome/browser/search_engines/ui_thread_search_terms_data.h" #include "chrome/browser/signin/gaia_cookie_manager_service_factory.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" +#include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h" #include "chrome/browser/ui/search/instant_test_utils.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_features.h" @@ -32,6 +38,7 @@ #include "chrome/common/url_constants.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/content_settings/core/common/content_settings.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/prefs/pref_service.h" #include "components/search_engines/template_url.h" @@ -39,8 +46,10 @@ #include "components/search_engines/template_url_service.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/web_contents.h" +#include "content/public/test/browser_test_utils.h" #include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_utils.h" +#include "media/base/media_switches.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "ui/base/resource/resource_bundle.h" @@ -591,6 +600,12 @@ InProcessBrowserTest::SetUp(); } + void SetUpCommandLine(base::CommandLine* cmdline) override { + // Requesting microphone permission doesn't work unless there's a device + // available. + cmdline->AppendSwitch(switches::kUseFakeDeviceForMediaStream); + } + base::test::ScopedFeatureList feature_list_; }; @@ -622,3 +637,61 @@ // We shouldn't have gotten any console error messages. EXPECT_TRUE(console_observer.message().empty()) << console_observer.message(); } + +IN_PROC_BROWSER_TEST_F(LocalNTPVoiceSearchSmokeTest, MicrophonePermission) { + // Open a new NTP. + content::WebContents* active_tab = + OpenNewTab(browser(), GURL(chrome::kChromeUINewTabURL)); + ASSERT_TRUE(search::IsInstantNTP(active_tab)); + ASSERT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl), + active_tab->GetController().GetVisibleEntry()->GetURL()); + + PermissionRequestManager* request_manager = + PermissionRequestManager::FromWebContents(active_tab); + MockPermissionPromptFactory prompt_factory(request_manager); + + PermissionManager* permission_manager = + PermissionManagerFactory::GetForProfile(browser()->profile()); + + // Make sure microphone permission for the NTP isn't set yet. + const PermissionResult mic_permission_before = + permission_manager->GetPermissionStatus( + CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, + GURL(chrome::kChromeSearchLocalNtpUrl).GetOrigin(), + GURL(chrome::kChromeUINewTabURL).GetOrigin()); + ASSERT_EQ(CONTENT_SETTING_ASK, mic_permission_before.content_setting); + ASSERT_EQ(PermissionStatusSource::UNSPECIFIED, mic_permission_before.source); + + ASSERT_EQ(0, prompt_factory.TotalRequestCount()); + + // Auto-approve the permissions bubble as soon as it shows up. + prompt_factory.set_response_type(PermissionRequestManager::ACCEPT_ALL); + + // Click on the microphone button, which will trigger a permission request. + ASSERT_TRUE(content::ExecuteScript( + active_tab, "document.getElementById('fakebox-microphone').click();")); + + // Make sure the request arrived. + prompt_factory.WaitForPermissionBubble(); + EXPECT_EQ(1, prompt_factory.show_count()); + EXPECT_EQ(1, prompt_factory.request_count()); + EXPECT_EQ(1, prompt_factory.TotalRequestCount()); + EXPECT_TRUE(prompt_factory.RequestTypeSeen( + PermissionRequestType::PERMISSION_MEDIASTREAM_MIC)); + // ...and that it showed the Google base URL, not the NTP URL. + const GURL google_base_url( + UIThreadSearchTermsData(browser()->profile()).GoogleBaseURLValue()); + EXPECT_TRUE(prompt_factory.RequestOriginSeen(google_base_url.GetOrigin())); + EXPECT_FALSE(prompt_factory.RequestOriginSeen( + GURL(chrome::kChromeUINewTabURL).GetOrigin())); + EXPECT_FALSE(prompt_factory.RequestOriginSeen( + GURL(chrome::kChromeSearchLocalNtpUrl).GetOrigin())); + + // Now microphone permission for the NTP should be set. + const PermissionResult mic_permission_after = + permission_manager->GetPermissionStatus( + CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, + GURL(chrome::kChromeSearchLocalNtpUrl).GetOrigin(), + GURL(chrome::kChromeUINewTabURL).GetOrigin()); + EXPECT_EQ(CONTENT_SETTING_ALLOW, mic_permission_after.content_setting); +}
diff --git a/components/search_engines/keyword_table.cc b/components/search_engines/keyword_table.cc index c384e81..bcd3fc0 100644 --- a/components/search_engines/keyword_table.cc +++ b/components/search_engines/keyword_table.cc
@@ -62,15 +62,18 @@ columns.push_back("logo_id"); } columns.push_back("created_by_policy"); - columns.push_back("instant_url"); + if (version <= 75) { + // Column removed after version 75. + columns.push_back("instant_url"); + } columns.push_back("last_modified"); columns.push_back("sync_guid"); if (version >= 47) { // Column added in version 47. columns.push_back("alternate_urls"); } - if (version >= 49) { - // Column added in version 49. + if (version >= 49 && version <= 75) { + // Column added in version 49 and removed after version 75. columns.push_back("search_terms_replacement_key"); } if (version >= 52) { @@ -78,7 +81,13 @@ columns.push_back("image_url"); columns.push_back("search_url_post_params"); columns.push_back("suggest_url_post_params"); + } + if (version >= 52 && version <= 75) { + // Column added in version 52 and removed after version 75. columns.push_back("instant_url_post_params"); + } + if (version >= 52) { + // Column added in version 52. columns.push_back("image_url_post_params"); } if (version >= 53) { @@ -130,18 +139,15 @@ s->BindString(starting_column + 9, data.suggestions_url); s->BindInt(starting_column + 10, data.prepopulate_id); s->BindBool(starting_column + 11, data.created_by_policy); - s->BindString(starting_column + 12, std::string()); - s->BindInt64(starting_column + 13, data.last_modified.ToTimeT()); - s->BindString(starting_column + 14, data.sync_guid); - s->BindString(starting_column + 15, alternate_urls); - s->BindString(starting_column + 16, std::string()); - s->BindString(starting_column + 17, data.image_url); - s->BindString(starting_column + 18, data.search_url_post_params); - s->BindString(starting_column + 19, data.suggestions_url_post_params); - s->BindString(starting_column + 20, std::string()); - s->BindString(starting_column + 21, data.image_url_post_params); - s->BindString(starting_column + 22, data.new_tab_url); - s->BindInt64(starting_column + 23, data.last_visited.ToTimeT()); + s->BindInt64(starting_column + 12, data.last_modified.ToTimeT()); + s->BindString(starting_column + 13, data.sync_guid); + s->BindString(starting_column + 14, alternate_urls); + s->BindString(starting_column + 15, data.image_url); + s->BindString(starting_column + 16, data.search_url_post_params); + s->BindString(starting_column + 17, data.suggestions_url_post_params); + s->BindString(starting_column + 18, data.image_url_post_params); + s->BindString(starting_column + 19, data.new_tab_url); + s->BindInt64(starting_column + 20, data.last_visited.ToTimeT()); } WebDatabaseTable::TypeKey GetKey() { @@ -168,32 +174,30 @@ bool KeywordTable::CreateTablesIfNecessary() { return db_->DoesTableExist("keywords") || - db_->Execute("CREATE TABLE keywords (" - "id INTEGER PRIMARY KEY," - "short_name VARCHAR NOT NULL," - "keyword VARCHAR NOT NULL," - "favicon_url VARCHAR NOT NULL," - "url VARCHAR NOT NULL," - "safe_for_autoreplace INTEGER," - "originating_url VARCHAR," - "date_created INTEGER DEFAULT 0," - "usage_count INTEGER DEFAULT 0," - "input_encodings VARCHAR," - "suggest_url VARCHAR," - "prepopulate_id INTEGER DEFAULT 0," - "created_by_policy INTEGER DEFAULT 0," - "instant_url VARCHAR," - "last_modified INTEGER DEFAULT 0," - "sync_guid VARCHAR," - "alternate_urls VARCHAR," - "search_terms_replacement_key VARCHAR," - "image_url VARCHAR," - "search_url_post_params VARCHAR," - "suggest_url_post_params VARCHAR," - "instant_url_post_params VARCHAR," - "image_url_post_params VARCHAR," - "new_tab_url VARCHAR," - " last_visited INTEGER DEFAULT 0)"); + db_->Execute( + "CREATE TABLE keywords (" + "id INTEGER PRIMARY KEY," + "short_name VARCHAR NOT NULL," + "keyword VARCHAR NOT NULL," + "favicon_url VARCHAR NOT NULL," + "url VARCHAR NOT NULL," + "safe_for_autoreplace INTEGER," + "originating_url VARCHAR," + "date_created INTEGER DEFAULT 0," + "usage_count INTEGER DEFAULT 0," + "input_encodings VARCHAR," + "suggest_url VARCHAR," + "prepopulate_id INTEGER DEFAULT 0," + "created_by_policy INTEGER DEFAULT 0," + "last_modified INTEGER DEFAULT 0," + "sync_guid VARCHAR," + "alternate_urls VARCHAR," + "image_url VARCHAR," + "search_url_post_params VARCHAR," + "suggest_url_post_params VARCHAR," + "image_url_post_params VARCHAR," + "new_tab_url VARCHAR," + "last_visited INTEGER DEFAULT 0)"); } bool KeywordTable::IsSyncable() { @@ -215,6 +219,9 @@ return MigrateToVersion68RemoveShowInDefaultListColumn(); case 69: return MigrateToVersion69AddLastVisitedColumn(); + case 76: + *update_compatible_version = true; + return MigrateToVersion76RemoveInstantColumns(); } return true; @@ -349,6 +356,46 @@ "INTEGER DEFAULT 0"); } +// SQLite does not support DROP COLUMN operation. So a new table is created +// without the removed columns. Data from all but the dropped columns of the old +// table is copied into it. After that, the old table is dropped and the new +// table is renamed to it. +bool KeywordTable::MigrateToVersion76RemoveInstantColumns() { + sql::Transaction transaction(db_); + std::string query_str = + std::string("INSERT INTO temp_keywords SELECT " + + ColumnsForVersion(76, false) + " FROM keywords"); + const char* clone_query = query_str.c_str(); + return transaction.Begin() && + db_->Execute( + "CREATE TABLE temp_keywords (" + "id INTEGER PRIMARY KEY," + "short_name VARCHAR NOT NULL," + "keyword VARCHAR NOT NULL," + "favicon_url VARCHAR NOT NULL," + "url VARCHAR NOT NULL," + "safe_for_autoreplace INTEGER," + "originating_url VARCHAR," + "date_created INTEGER DEFAULT 0," + "usage_count INTEGER DEFAULT 0," + "input_encodings VARCHAR," + "suggest_url VARCHAR," + "prepopulate_id INTEGER DEFAULT 0," + "created_by_policy INTEGER DEFAULT 0," + "last_modified INTEGER DEFAULT 0," + "sync_guid VARCHAR," + "alternate_urls VARCHAR," + "image_url VARCHAR," + "search_url_post_params VARCHAR," + "suggest_url_post_params VARCHAR," + "image_url_post_params VARCHAR," + "new_tab_url VARCHAR," + "last_visited INTEGER DEFAULT 0)") && + db_->Execute(clone_query) && db_->Execute("DROP TABLE keywords") && + db_->Execute("ALTER TABLE temp_keywords RENAME TO keywords") && + transaction.Commit(); +} + // static bool KeywordTable::GetKeywordDataFromStatement(const sql::Statement& s, TemplateURLData* data) { @@ -364,11 +411,11 @@ return false; data->SetURL(s.ColumnString(4)); data->suggestions_url = s.ColumnString(10); - data->image_url = s.ColumnString(18); - data->new_tab_url = s.ColumnString(23); - data->search_url_post_params = s.ColumnString(19); - data->suggestions_url_post_params = s.ColumnString(20); - data->image_url_post_params = s.ColumnString(22); + data->image_url = s.ColumnString(16); + data->new_tab_url = s.ColumnString(20); + data->search_url_post_params = s.ColumnString(17); + data->suggestions_url_post_params = s.ColumnString(18); + data->image_url_post_params = s.ColumnString(19); data->favicon_url = GURL(s.ColumnString(3)); data->originating_url = GURL(s.ColumnString(6)); data->safe_for_autoreplace = s.ColumnBool(5); @@ -376,16 +423,16 @@ s.ColumnString(9), ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); data->id = s.ColumnInt64(0); data->date_created = Time::FromTimeT(s.ColumnInt64(7)); - data->last_modified = Time::FromTimeT(s.ColumnInt64(14)); + data->last_modified = Time::FromTimeT(s.ColumnInt64(13)); data->created_by_policy = s.ColumnBool(12); data->usage_count = s.ColumnInt(8); data->prepopulate_id = s.ColumnInt(11); - data->sync_guid = s.ColumnString(15); + data->sync_guid = s.ColumnString(14); data->alternate_urls.clear(); base::JSONReader json_reader; std::unique_ptr<base::Value> value( - json_reader.ReadToValue(s.ColumnString(16))); + json_reader.ReadToValue(s.ColumnString(15))); base::ListValue* alternate_urls_value; if (value.get() && value->GetAsList(&alternate_urls_value)) { std::string alternate_url; @@ -395,16 +442,16 @@ } } - data->last_visited = Time::FromTimeT(s.ColumnInt64(24)); + data->last_visited = Time::FromTimeT(s.ColumnInt64(21)); return true; } bool KeywordTable::AddKeyword(const TemplateURLData& data) { DCHECK(data.id); - std::string query("INSERT INTO keywords (" + GetKeywordColumns() + ") " - "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?," - " ?,?)"); + std::string query("INSERT INTO keywords (" + GetKeywordColumns() + + ") " + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); sql::Statement s(db_->GetCachedStatement(SQL_FROM_HERE, query.c_str())); BindURLToStatement(data, &s, 0, 1); @@ -426,13 +473,11 @@ SQL_FROM_HERE, "UPDATE keywords SET short_name=?, keyword=?, favicon_url=?, url=?, " "safe_for_autoreplace=?, originating_url=?, date_created=?, " - "usage_count=?, input_encodings=?, suggest_url=?, " - "prepopulate_id=?, created_by_policy=?, instant_url=?, " - "last_modified=?, sync_guid=?, alternate_urls=?, " - "search_terms_replacement_key=?, image_url=?, search_url_post_params=?, " - "suggest_url_post_params=?, instant_url_post_params=?, " + "usage_count=?, input_encodings=?, suggest_url=?, prepopulate_id=?, " + "created_by_policy=?, last_modified=?, sync_guid=?, alternate_urls=?, " + "image_url=?, search_url_post_params=?, suggest_url_post_params=?, " "image_url_post_params=?, new_tab_url=?, last_visited=? WHERE id=?")); - BindURLToStatement(data, &s, 24, 0); // "24" binds id() as the last item. + BindURLToStatement(data, &s, 21, 0); // "21" binds id() as the last item. return s.Run(); }
diff --git a/components/search_engines/keyword_table.h b/components/search_engines/keyword_table.h index 90a4257..86059ab8 100644 --- a/components/search_engines/keyword_table.h +++ b/components/search_engines/keyword_table.h
@@ -48,25 +48,18 @@ // prepopulate_id See TemplateURLData::prepopulate_id. // created_by_policy See TemplateURLData::created_by_policy. This was // added in version 26. -// instant_url See TemplateURLData::instant_url. This was added in -// version 29. // last_modified See TemplateURLData::last_modified. This was added // in version 38. // sync_guid See TemplateURLData::sync_guid. This was added in // version 39. // alternate_urls See TemplateURLData::alternate_urls. This was added // in version 47. -// search_terms_replacement_key -// See TemplateURLData::search_terms_replacement_key. -// This was added in version 49. // image_url See TemplateURLData::image_url. This was added in // version 52. // search_url_post_params See TemplateURLData::search_url_post_params. This // was added in version 52. // suggest_url_post_params See TemplateURLData::suggestions_url_post_params. // This was added in version 52. -// instant_url_post_params See TemplateURLData::instant_url_post_params. This -// was added in version 52. // image_url_post_params See TemplateURLData::image_url_post_params. This // was added in version 52. // new_tab_url See TemplateURLData::new_tab_url. This was added in @@ -132,10 +125,10 @@ bool MigrateToVersion59RemoveExtensionKeywords(); bool MigrateToVersion68RemoveShowInDefaultListColumn(); bool MigrateToVersion69AddLastVisitedColumn(); + bool MigrateToVersion76RemoveInstantColumns(); private: friend class KeywordTableTest; - FRIEND_TEST_ALL_PREFIXES(WebDatabaseMigrationTest, MigrateVersion44ToCurrent); // NOTE: Since the table columns have changed in different versions, many // functions below take a |table_version| argument which dictates which
diff --git a/components/test/data/web_database/version_75.sql b/components/test/data/web_database/version_75.sql new file mode 100644 index 0000000..de766ceba9 --- /dev/null +++ b/components/test/data/web_database/version_75.sql
@@ -0,0 +1,26 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); +INSERT INTO "meta" VALUES('mmap_status','-1'); +INSERT INTO "meta" VALUES('version','75'); +INSERT INTO "meta" VALUES('last_compatible_version','72'); +CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); +CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,search_terms_replacement_key VARCHAR,image_url VARCHAR,search_url_post_params VARCHAR,suggest_url_post_params VARCHAR,instant_url_post_params VARCHAR,image_url_post_params VARCHAR,new_tab_url VARCHAR, last_visited INTEGER DEFAULT 0); +CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, date_created INTEGER DEFAULT 0, date_last_used INTEGER DEFAULT 0, count INTEGER DEFAULT 1, PRIMARY KEY (name, value)); +CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR); +CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0); +INSERT INTO "autofill_profiles" VALUES('00000000-0000-0000-0000-000000000001','Google Inc','340 Main St','','Los Angeles','CA','90291','','US',1395948829,'Chrome settings','en',12,12,0); +CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR); +CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); +CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); +CREATE TABLE autofill_profiles_trash ( guid VARCHAR); +CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, type INTEGER DEFAULT 0); +CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, unmask_date INTEGER NOT NULL DEFAULT 0); +CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR); +CREATE TABLE server_addresses (id VARCHAR,company_name VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code VARCHAR, recipient_name VARCHAR, phone_number VARCHAR); +CREATE TABLE server_address_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, has_converted BOOL NOT NULL DEFAULT FALSE); +CREATE TABLE autofill_sync_metadata (storage_key VARCHAR PRIMARY KEY NOT NULL,value BLOB); +CREATE TABLE autofill_model_type_state (id INTEGER PRIMARY KEY, value BLOB); +CREATE INDEX autofill_name ON autofill (name); +CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); +COMMIT;
diff --git a/components/translate/core/browser/translate_prefs.cc b/components/translate/core/browser/translate_prefs.cc index 3437031..9c96713d 100644 --- a/components/translate/core/browser/translate_prefs.cc +++ b/components/translate/core/browser/translate_prefs.cc
@@ -7,6 +7,7 @@ #include <set> #include <utility> +#include "base/feature_list.h" #include "base/memory/ptr_util.h" #include "base/strings/string_piece.h" #include "base/strings/string_split.h" @@ -104,6 +105,9 @@ const base::Feature kTranslateUI2016Q2{"TranslateUI2016Q2", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kImprovedLanguageSettings{ + "ImprovedLanguageSettings", base::FEATURE_DISABLED_BY_DEFAULT}; + DenialTimeUpdate::DenialTimeUpdate(PrefService* prefs, const std::string& language, size_t max_denial_count) @@ -469,18 +473,21 @@ void TranslatePrefs::UpdateLanguageList( const std::vector<std::string>& languages) { -#if defined(OS_CHROMEOS) std::string languages_str = base::JoinString(languages, ","); - prefs_->SetString(preferred_languages_pref_.c_str(), languages_str); + +#if defined(OS_CHROMEOS) + prefs_->SetString(preferred_languages_pref_, languages_str); #endif // Save the same language list as accept languages preference as well, but we // need to expand the language list, to make it more acceptable. For instance, // some web sites don't understand 'en-US' but 'en'. See crosbug.com/9884. - std::vector<base::StringPiece> accept_languages; - ExpandLanguageCodes(languages, &accept_languages); - std::string accept_languages_str = base::JoinString(accept_languages, ","); - prefs_->SetString(accept_languages_pref_, accept_languages_str); + if (!base::FeatureList::IsEnabled(kImprovedLanguageSettings)) { + std::vector<base::StringPiece> accept_languages; + ExpandLanguageCodes(languages, &accept_languages); + languages_str = base::JoinString(accept_languages, ","); + } + prefs_->SetString(accept_languages_pref_, languages_str); } bool TranslatePrefs::CanTranslateLanguage(
diff --git a/components/translate/core/browser/translate_prefs.h b/components/translate/core/browser/translate_prefs.h index f3ee614d..5edf073 100644 --- a/components/translate/core/browser/translate_prefs.h +++ b/components/translate/core/browser/translate_prefs.h
@@ -35,6 +35,10 @@ // Feature flag for "Translate UI 2016 Q2" project. extern const base::Feature kTranslateUI2016Q2; +// Enables or disables the new improved language settings. +// These settings support the new UI. +extern const base::Feature kImprovedLanguageSettings; + // The trial (study) name in finch study config. extern const char kTranslateUI2016Q2TrialName[];
diff --git a/components/translate/core/browser/translate_prefs_unittest.cc b/components/translate/core/browser/translate_prefs_unittest.cc index 17ee464..6bec1a7 100644 --- a/components/translate/core/browser/translate_prefs_unittest.cc +++ b/components/translate/core/browser/translate_prefs_unittest.cc
@@ -18,6 +18,8 @@ #include "components/translate/core/browser/translate_download_manager.h" #include "testing/gtest/include/gtest/gtest.h" +using base::test::ScopedFeatureList; + namespace { const char kTestLanguage[] = "en"; @@ -62,6 +64,20 @@ return update.GetOldestDenialTime(); } + void ExpectLanguagePrefs(const std::string& expected_str) { + if (expected_str.empty()) { + EXPECT_TRUE(prefs_->GetString(kAcceptLanguagesPref).empty()); +#if defined(OS_CHROMEOS) + EXPECT_TRUE(prefs_->GetString(kPreferredLanguagesPref).empty()); +#endif + } else { + EXPECT_EQ(expected_str, prefs_->GetString(kAcceptLanguagesPref)); +#if defined(OS_CHROMEOS) + EXPECT_EQ(expected_str, prefs_->GetString(kPreferredLanguagesPref)); +#endif + } + } + std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> prefs_; std::unique_ptr<translate::TranslatePrefs> translate_prefs_; @@ -220,21 +236,73 @@ now_ - base::TimeDelta::FromMinutes(2)); } +// The logic of UpdateLanguageList() changes based on the value of feature +// kImprovedLanguageSettings, which is a boolean. +// We write two separate test cases for true and false. TEST_F(TranslatePrefTest, UpdateLanguageList) { - // Test with basic set of languages (no country codes). - std::vector<std::string> languages{"en", "ja"}; - translate_prefs_->UpdateLanguageList(languages); - EXPECT_EQ("en,ja", prefs_->GetString(kAcceptLanguagesPref)); + ScopedFeatureList disable_feature; + disable_feature.InitAndDisableFeature(translate::kImprovedLanguageSettings); - // Test with languages that have country codes. Expect accepted languages both - // with and without a country code. (See documentation for - // ExpandLanguageCodes.) - languages = {"en-US", "ja", "en-CA"}; + // Empty update. + std::vector<std::string> languages; translate_prefs_->UpdateLanguageList(languages); + ExpectLanguagePrefs(""); + + // One language. + languages = {"en"}; + translate_prefs_->UpdateLanguageList(languages); + ExpectLanguagePrefs("en"); + + // More than one language. + languages = {"en", "ja", "it"}; + translate_prefs_->UpdateLanguageList(languages); + ExpectLanguagePrefs("en,ja,it"); + + // Locale-specific codes. + // The list is exanded by adding the base languagese. + languages = {"en-US", "ja", "en-CA", "fr-CA"}; + translate_prefs_->UpdateLanguageList(languages); + EXPECT_EQ("en-US,en,ja,en-CA,fr-CA,fr", + prefs_->GetString(kAcceptLanguagesPref)); #if defined(OS_CHROMEOS) - EXPECT_EQ("en-US,ja,en-CA", prefs_->GetString(kPreferredLanguagesPref)); + EXPECT_EQ("en-US,ja,en-CA,fr-CA", prefs_->GetString(kPreferredLanguagesPref)); #endif - EXPECT_EQ("en-US,en,ja,en-CA", prefs_->GetString(kAcceptLanguagesPref)); + + // List already expanded. + languages = {"en-US", "en", "fr", "fr-CA"}; + translate_prefs_->UpdateLanguageList(languages); + ExpectLanguagePrefs("en-US,en,fr,fr-CA"); +} + +TEST_F(TranslatePrefTest, UpdateLanguageListFeatureEnabled) { + ScopedFeatureList enable_feature; + enable_feature.InitAndEnableFeature(translate::kImprovedLanguageSettings); + + // Empty update. + std::vector<std::string> languages; + translate_prefs_->UpdateLanguageList(languages); + ExpectLanguagePrefs(""); + + // One language. + languages = {"en"}; + translate_prefs_->UpdateLanguageList(languages); + ExpectLanguagePrefs("en"); + + // More than one language. + languages = {"en", "ja", "it"}; + translate_prefs_->UpdateLanguageList(languages); + ExpectLanguagePrefs("en,ja,it"); + + // Locale-specific codes. + // The list is exanded by adding the base languagese. + languages = {"en-US", "ja", "en-CA", "fr-CA"}; + translate_prefs_->UpdateLanguageList(languages); + ExpectLanguagePrefs("en-US,ja,en-CA,fr-CA"); + + // List already expanded. + languages = {"en-US", "en", "fr", "fr-CA"}; + translate_prefs_->UpdateLanguageList(languages); + ExpectLanguagePrefs("en-US,en,fr,fr-CA"); } TEST_F(TranslatePrefTest, ULPPrefs) {
diff --git a/components/webdata/common/BUILD.gn b/components/webdata/common/BUILD.gn index d55783da..188da12 100644 --- a/components/webdata/common/BUILD.gn +++ b/components/webdata/common/BUILD.gn
@@ -62,6 +62,7 @@ "//components/test/data/web_database/version_73.sql", "//components/test/data/web_database/version_73_with_type_column.sql", "//components/test/data/web_database/version_74.sql", + "//components/test/data/web_database/version_75.sql", ] outputs = [ "{{bundle_resources_dir}}/" +
diff --git a/components/webdata/common/web_database.cc b/components/webdata/common/web_database.cc index e954603..2058577 100644 --- a/components/webdata/common/web_database.cc +++ b/components/webdata/common/web_database.cc
@@ -13,7 +13,7 @@ // corresponding changes must happen in the unit tests, and new migration test // added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|. // static -const int WebDatabase::kCurrentVersionNumber = 75; +const int WebDatabase::kCurrentVersionNumber = 76; const int WebDatabase::kDeprecatedVersionNumber = 51;
diff --git a/components/webdata/common/web_database_migration_unittest.cc b/components/webdata/common/web_database_migration_unittest.cc index ed46c3c..e4ba6d9 100644 --- a/components/webdata/common/web_database_migration_unittest.cc +++ b/components/webdata/common/web_database_migration_unittest.cc
@@ -130,7 +130,7 @@ DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest); }; -const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 75; +const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 76; void WebDatabaseMigrationTest::LoadDatabase( const base::FilePath::StringType& file) { @@ -225,8 +225,6 @@ ASSERT_FALSE( connection.DoesColumnExist("keywords", "suggest_url_post_params")); ASSERT_FALSE( - connection.DoesColumnExist("keywords", "instant_url_post_params")); - ASSERT_FALSE( connection.DoesColumnExist("keywords", "image_url_post_params")); } @@ -249,8 +247,6 @@ EXPECT_TRUE( connection.DoesColumnExist("keywords", "suggest_url_post_params")); EXPECT_TRUE( - connection.DoesColumnExist("keywords", "instant_url_post_params")); - EXPECT_TRUE( connection.DoesColumnExist("keywords", "image_url_post_params")); } } @@ -1470,3 +1466,42 @@ ASSERT_FALSE(s_profiles.Step()); } } + +// Tests deletion of Instant-related columns in keywords table. +TEST_F(WebDatabaseMigrationTest, MigrateVersion75ToCurrent) { + ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_75.sql"))); + + // Verify pre-conditions. + { + sql::Connection connection; + ASSERT_TRUE(connection.Open(GetDatabasePath())); + ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); + + sql::MetaTable meta_table; + ASSERT_TRUE(meta_table.Init(&connection, 75, 75)); + + EXPECT_TRUE(connection.DoesColumnExist("keywords", "instant_url")); + EXPECT_TRUE( + connection.DoesColumnExist("keywords", "instant_url_post_params")); + EXPECT_TRUE( + connection.DoesColumnExist("keywords", "search_terms_replacement_key")); + } + + DoMigration(); + + // Verify post-conditions. + { + sql::Connection connection; + ASSERT_TRUE(connection.Open(GetDatabasePath())); + ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection)); + + // Check version. + EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection)); + + EXPECT_FALSE(connection.DoesColumnExist("keywords", "instant_url")); + EXPECT_FALSE( + connection.DoesColumnExist("keywords", "instant_url_post_params")); + EXPECT_FALSE( + connection.DoesColumnExist("keywords", "search_terms_replacement_key")); + } +}
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc index 1947a15..dde1b0c7a 100644 --- a/content/browser/service_manager/service_manager_context.cc +++ b/content/browser/service_manager/service_manager_context.cc
@@ -35,6 +35,7 @@ #include "content/public/common/content_switches.h" #include "content/public/common/service_manager_connection.h" #include "content/public/common/service_names.mojom.h" +#include "device/geolocation/geolocation_provider.h" #include "media/mojo/features.h" #include "media/mojo/interfaces/constants.mojom.h" #include "mojo/edk/embedder/embedder.h" @@ -341,6 +342,13 @@ packaged_services_connection_->AddEmbeddedService(device::mojom::kServiceName, device_info); + // Pipe embedder-supplied API key through to GeolocationProvider. + // TODO(amoylan): Once GeolocationProvider hangs off DeviceService + // (https://crbug.com/709301), pass this via CreateDeviceService above + // instead. + device::GeolocationProvider::SetApiKey( + GetContentClient()->browser()->GetGeolocationApiKey()); + if (base::FeatureList::IsEnabled(features::kGlobalResourceCoordinator)) { service_manager::EmbeddedServiceInfo resource_coordinator_info; resource_coordinator_info.factory =
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc index 988fcca2..215a03c 100644 --- a/content/child/resource_dispatcher.cc +++ b/content/child/resource_dispatcher.cc
@@ -557,6 +557,7 @@ std::unique_ptr<ResourceRequest> request, int routing_id, const url::Origin& frame_origin, + const net::NetworkTrafficAnnotationTag& traffic_annotation, SyncLoadResponse* response, blink::WebURLRequest::LoadingIPCType ipc_type, mojom::URLLoaderFactory* url_loader_factory, @@ -581,8 +582,9 @@ FROM_HERE, base::BindOnce(&SyncLoadContext::StartAsyncWithWaitableEvent, std::move(request), routing_id, frame_origin, - std::move(url_loader_factory_copy), std::move(throttles), - base::Unretained(response), base::Unretained(&event))); + traffic_annotation, std::move(url_loader_factory_copy), + std::move(throttles), base::Unretained(response), + base::Unretained(&event))); event.Wait(); } else { @@ -618,6 +620,7 @@ int routing_id, scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner, const url::Origin& frame_origin, + const net::NetworkTrafficAnnotationTag& traffic_annotation, bool is_sync, std::unique_ptr<RequestPeer> peer, blink::WebURLRequest::LoadingIPCType ipc_type, @@ -652,30 +655,6 @@ return request_id; } - net::NetworkTrafficAnnotationTag traffic_annotation = - net::DefineNetworkTrafficAnnotation("blink_resource_loader", R"( - semantics { - sender: "Blink Resource Loader" - description: - "Blink initiated request, which includes all resources for " - "normal page loads, chrome URLs, resources for installed " - "extensions, as well as downloads." - trigger: - "Navigating to a URL or downloading a file. A webpage, " - "ServiceWorker, chrome:// page, or extension may also initiate " - "requests in the background." - data: "Anything the initiator wants to send." - destination: OTHER - } - policy { - cookies_allowed: YES - cookies_store: "user" - setting: "These requests cannot be disabled in settings." - policy_exception_justification: - "Not implemented. Without these requests, Chrome will be unable " - "to load any webpage." - })"); - if (ipc_type == blink::WebURLRequest::LoadingIPCType::kMojo) { scoped_refptr<base::SingleThreadTaskRunner> task_runner = loading_task_runner ? loading_task_runner : thread_task_runner_;
diff --git a/content/child/resource_dispatcher.h b/content/child/resource_dispatcher.h index aea67d9..599eeac 100644 --- a/content/child/resource_dispatcher.h +++ b/content/child/resource_dispatcher.h
@@ -29,6 +29,7 @@ #include "ipc/ipc_sender.h" #include "mojo/public/cpp/system/data_pipe.h" #include "net/base/request_priority.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" #include "url/gurl.h" #include "url/origin.h" @@ -91,6 +92,7 @@ std::unique_ptr<ResourceRequest> request, int routing_id, const url::Origin& frame_origin, + const net::NetworkTrafficAnnotationTag& traffic_annotation, SyncLoadResponse* response, blink::WebURLRequest::LoadingIPCType ipc_type, mojom::URLLoaderFactory* url_loader_factory, @@ -111,6 +113,7 @@ int routing_id, scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner, const url::Origin& frame_origin, + const net::NetworkTrafficAnnotationTag& traffic_annotation, bool is_sync, std::unique_ptr<RequestPeer> peer, blink::WebURLRequest::LoadingIPCType ipc_type,
diff --git a/content/child/resource_dispatcher_unittest.cc b/content/child/resource_dispatcher_unittest.cc index 82510673..4b16b12 100644 --- a/content/child/resource_dispatcher_unittest.cc +++ b/content/child/resource_dispatcher_unittest.cc
@@ -37,6 +37,7 @@ #include "net/base/net_errors.h" #include "net/base/request_priority.h" #include "net/http/http_response_headers.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebReferrerPolicy.h" #include "url/gurl.h" @@ -228,7 +229,8 @@ std::unique_ptr<TestRequestPeer> peer( new TestRequestPeer(dispatcher(), peer_context)); int request_id = dispatcher()->StartAsync( - std::move(request), 0, nullptr, url::Origin(), false, std::move(peer), + std::move(request), 0, nullptr, url::Origin(), + TRAFFIC_ANNOTATION_FOR_TESTS, false, std::move(peer), blink::WebURLRequest::LoadingIPCType::kChromeIPC, nullptr, std::vector<std::unique_ptr<URLLoaderThrottle>>(), mojo::ScopedDataPipeConsumerHandle());
diff --git a/content/child/sync_load_context.cc b/content/child/sync_load_context.cc index 08171352..3d0cf50 100644 --- a/content/child/sync_load_context.cc +++ b/content/child/sync_load_context.cc
@@ -21,6 +21,7 @@ std::unique_ptr<ResourceRequest> request, int routing_id, const url::Origin& frame_origin, + const net::NetworkTrafficAnnotationTag& traffic_annotation, mojom::URLLoaderFactoryPtrInfo url_loader_factory_pipe, std::vector<std::unique_ptr<URLLoaderThrottle>> throttles, SyncLoadResponse* response, @@ -29,8 +30,9 @@ request.get(), std::move(url_loader_factory_pipe), response, event); context->request_id_ = context->resource_dispatcher_->StartAsync( - std::move(request), routing_id, nullptr, frame_origin, true /* is_sync */, - base::WrapUnique(context), blink::WebURLRequest::LoadingIPCType::kMojo, + std::move(request), routing_id, nullptr, frame_origin, traffic_annotation, + true /* is_sync */, base::WrapUnique(context), + blink::WebURLRequest::LoadingIPCType::kMojo, context->url_loader_factory_.get(), std::move(throttles), mojo::ScopedDataPipeConsumerHandle()); }
diff --git a/content/child/sync_load_context.h b/content/child/sync_load_context.h index d2df986..d3d8e15 100644 --- a/content/child/sync_load_context.h +++ b/content/child/sync_load_context.h
@@ -9,6 +9,7 @@ #include "content/child/resource_dispatcher.h" #include "content/public/child/request_peer.h" #include "content/public/common/url_loader_factory.mojom.h" +#include "net/traffic_annotation/network_traffic_annotation.h" namespace base { class WaitableEvent; @@ -34,6 +35,7 @@ std::unique_ptr<ResourceRequest> request, int routing_id, const url::Origin& frame_origin, + const net::NetworkTrafficAnnotationTag& traffic_annotation, mojom::URLLoaderFactoryPtrInfo url_loader_factory_pipe, std::vector<std::unique_ptr<URLLoaderThrottle>> throttles, SyncLoadResponse* response,
diff --git a/content/child/url_loader_client_impl_unittest.cc b/content/child/url_loader_client_impl_unittest.cc index 16b229b9..63f50b57 100644 --- a/content/child/url_loader_client_impl_unittest.cc +++ b/content/child/url_loader_client_impl_unittest.cc
@@ -30,7 +30,8 @@ mojo_binding_.Bind(mojo::MakeRequest(&url_loader_factory_proxy_)); request_id_ = dispatcher_->StartAsync( - base::MakeUnique<ResourceRequest>(), 0, nullptr, url::Origin(), false, + base::MakeUnique<ResourceRequest>(), 0, nullptr, url::Origin(), + TRAFFIC_ANNOTATION_FOR_TESTS, false, base::MakeUnique<TestRequestPeer>(dispatcher_.get(), &request_peer_context_), blink::WebURLRequest::LoadingIPCType::kMojo,
diff --git a/content/child/url_response_body_consumer_unittest.cc b/content/child/url_response_body_consumer_unittest.cc index 0bfadb86..824e442f 100644 --- a/content/child/url_response_body_consumer_unittest.cc +++ b/content/child/url_response_body_consumer_unittest.cc
@@ -20,6 +20,7 @@ #include "content/public/common/resource_request_completion_status.h" #include "content/public/common/service_worker_modes.h" #include "net/base/request_priority.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" #include "url/origin.h" @@ -137,7 +138,8 @@ int SetUpRequestPeer(std::unique_ptr<ResourceRequest> request, TestRequestPeer::Context* context) { return dispatcher_->StartAsync( - std::move(request), 0, nullptr, url::Origin(), false, + std::move(request), 0, nullptr, url::Origin(), + TRAFFIC_ANNOTATION_FOR_TESTS, false, base::MakeUnique<TestRequestPeer>(context, message_loop_.task_runner()), blink::WebURLRequest::LoadingIPCType::kChromeIPC, nullptr, std::vector<std::unique_ptr<URLLoaderThrottle>>(),
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc index e1d1eae..09d8f646 100644 --- a/content/child/web_url_loader_impl.cc +++ b/content/child/web_url_loader_impl.cc
@@ -392,6 +392,9 @@ bool CanHandleDataURLRequestLocally(const WebURLRequest& request) const; void HandleDataURL(); + static net::NetworkTrafficAnnotationTag GetTrafficAnnotationTag( + const blink::WebURLRequest& request); + WebURLLoaderImpl* loader_; WebURL url_; @@ -654,8 +657,8 @@ resource_dispatcher_->StartSync( std::move(resource_request), request.RequestorID(), - extra_data->frame_origin(), sync_load_response, - request.GetLoadingIPCType(), url_loader_factory_, + extra_data->frame_origin(), GetTrafficAnnotationTag(request), + sync_load_response, request.GetLoadingIPCType(), url_loader_factory_, extra_data->TakeURLLoaderThrottles()); return; } @@ -664,7 +667,8 @@ TRACE_EVENT_FLAG_FLOW_OUT); request_id_ = resource_dispatcher_->StartAsync( std::move(resource_request), request.RequestorID(), task_runner_, - extra_data->frame_origin(), false /* is_sync */, + extra_data->frame_origin(), GetTrafficAnnotationTag(request), + false /* is_sync */, base::MakeUnique<WebURLLoaderImpl::RequestPeerImpl>(this), request.GetLoadingIPCType(), url_loader_factory_, extra_data->TakeURLLoaderThrottles(), std::move(consumer_handle)); @@ -998,6 +1002,116 @@ data.size()); } +// static +net::NetworkTrafficAnnotationTag +WebURLLoaderImpl::Context::GetTrafficAnnotationTag( + const blink::WebURLRequest& request) { + switch (request.GetRequestContext()) { + case WebURLRequest::kRequestContextUnspecified: + case WebURLRequest::kRequestContextAudio: + case WebURLRequest::kRequestContextBeacon: + case WebURLRequest::kRequestContextCSPReport: + case WebURLRequest::kRequestContextDownload: + case WebURLRequest::kRequestContextEventSource: + case WebURLRequest::kRequestContextFetch: + case WebURLRequest::kRequestContextFont: + case WebURLRequest::kRequestContextForm: + case WebURLRequest::kRequestContextFrame: + case WebURLRequest::kRequestContextHyperlink: + case WebURLRequest::kRequestContextIframe: + case WebURLRequest::kRequestContextImage: + case WebURLRequest::kRequestContextImageSet: + case WebURLRequest::kRequestContextImport: + case WebURLRequest::kRequestContextInternal: + case WebURLRequest::kRequestContextLocation: + case WebURLRequest::kRequestContextManifest: + case WebURLRequest::kRequestContextPing: + case WebURLRequest::kRequestContextPrefetch: + case WebURLRequest::kRequestContextScript: + case WebURLRequest::kRequestContextServiceWorker: + case WebURLRequest::kRequestContextSharedWorker: + case WebURLRequest::kRequestContextSubresource: + case WebURLRequest::kRequestContextStyle: + case WebURLRequest::kRequestContextTrack: + case WebURLRequest::kRequestContextVideo: + case WebURLRequest::kRequestContextWorker: + case WebURLRequest::kRequestContextXMLHttpRequest: + case WebURLRequest::kRequestContextXSLT: + return net::DefineNetworkTrafficAnnotation("blink_resource_loader", R"( + semantics { + sender: "Blink Resource Loader" + description: + "Blink-initiated request, which includes all resources for " + "normal page loads, chrome URLs, and downloads." + trigger: + "The user navigates to a URL or downloads a file. Also when a " + "webpage, ServiceWorker, or chrome:// uses any network communication." + data: "Anything the initiator wants to send." + destination: OTHER + } + policy { + cookies_allowed: YES + cookies_store: "user" + setting: "These requests cannot be disabled in settings." + policy_exception_justification: + "Not implemented. Without these requests, Chrome will be unable " + "to load any webpage." + })"); + + case WebURLRequest::kRequestContextEmbed: + case WebURLRequest::kRequestContextObject: + case WebURLRequest::kRequestContextPlugin: + return net::DefineNetworkTrafficAnnotation( + "blink_extension_resource_loader", R"( + semantics { + sender: "Blink Resource Loader" + description: + "Blink-initiated request for resources required for NaCl instances " + "tagged with <embed> or <object>, or installed extensions." + trigger: + "An extension or NaCl instance may initiate a request at any time, " + "even in the background." + data: "Anything the initiator wants to send." + destination: OTHER + } + policy { + cookies_allowed: YES + cookies_store: "user" + setting: + "These requests cannot be disabled in settings, but they are " + "sent only if user installs extensions." + chrome_policy { + ExtensionInstallBlacklist { + ExtensionInstallBlacklist: { + entries: '*' + } + } + } + })"); + + case WebURLRequest::kRequestContextFavicon: + return net::DefineNetworkTrafficAnnotation("favicon_loader", R"( + semantics { + sender: "Blink Resource Loader" + description: + "Chrome sends a request to download favicon for a URL." + trigger: + "Navigating to a URL." + data: "None." + destination: WEBSITE + } + policy { + cookies_allowed: YES + cookies_store: "user" + setting: "These requests cannot be disabled in settings." + policy_exception_justification: + "Not implemented." + })"); + } + + return net::NetworkTrafficAnnotationTag::NotReached(); +} + // WebURLLoaderImpl::RequestPeerImpl ------------------------------------------ WebURLLoaderImpl::RequestPeerImpl::RequestPeerImpl(Context* context)
diff --git a/content/child/web_url_loader_impl_unittest.cc b/content/child/web_url_loader_impl_unittest.cc index 1cabac2..ccdaa78 100644 --- a/content/child/web_url_loader_impl_unittest.cc +++ b/content/child/web_url_loader_impl_unittest.cc
@@ -30,6 +30,7 @@ #include "net/base/net_errors.h" #include "net/http/http_response_headers.h" #include "net/http/http_util.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "net/url_request/redirect_info.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebString.h" @@ -71,6 +72,7 @@ std::unique_ptr<ResourceRequest> request, int routing_id, const url::Origin& frame_origin, + const net::NetworkTrafficAnnotationTag& traffic_annotation, SyncLoadResponse* response, blink::WebURLRequest::LoadingIPCType ipc_type, mojom::URLLoaderFactory* url_loader_factory, @@ -83,6 +85,7 @@ int routing_id, scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner, const url::Origin& frame_origin, + const net::NetworkTrafficAnnotationTag& traffic_annotation, bool is_sync, std::unique_ptr<RequestPeer> peer, blink::WebURLRequest::LoadingIPCType ipc_type,
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index 3b5f1b51..a205964 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -270,6 +270,10 @@ return nullptr; } +std::string ContentBrowserClient::GetGeolocationApiKey() { + return std::string(); +} + std::string ContentBrowserClient::GetStoragePartitionIdForSite( BrowserContext* browser_context, const GURL& site) {
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 4734a72..8e25eacc 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -434,6 +434,12 @@ virtual net::URLRequestContext* OverrideRequestContextForURL( const GURL& url, ResourceContext* context); + // Allows an embedder to provide a Google API Key to use for network + // geolocation queries. + // * May be called from any thread. + // * Default implementation returns empty string, meaning send no API key. + virtual std::string GetGeolocationApiKey(); + // Allow the embedder to specify a string version of the storage partition // config with a site. virtual std::string GetStoragePartitionIdForSite(
diff --git a/dbus/end_to_end_async_unittest.cc b/dbus/end_to_end_async_unittest.cc index 2de55c3..d96ebda 100644 --- a/dbus/end_to_end_async_unittest.cc +++ b/dbus/end_to_end_async_unittest.cc
@@ -512,32 +512,13 @@ ASSERT_EQ(DBUS_ERROR_FAILED, error_names_[0]); } -TEST_F(EndToEndAsyncTest, InvalidObjectPath) { - // Trailing '/' is only allowed for the root path. - const ObjectPath invalid_object_path("/org/chromium/TestObject/"); - - // Replace object proxy with new one. - object_proxy_ = bus_->GetObjectProxy(test_service_->service_name(), - invalid_object_path); - - MethodCall method_call("org.chromium.TestInterface", "Echo"); - - const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT; - CallMethodWithErrorCallback(&method_call, timeout_ms); - WaitForErrors(1); - - // Should fail because of the invalid path. - ASSERT_TRUE(response_strings_.empty()); - ASSERT_EQ("", error_names_[0]); -} - TEST_F(EndToEndAsyncTest, InvalidServiceName) { // Bus name cannot contain '/'. const std::string invalid_service_name = ":1/2"; // Replace object proxy with new one. - object_proxy_ = bus_->GetObjectProxy( - invalid_service_name, ObjectPath("org.chromium.TestObject")); + object_proxy_ = bus_->GetObjectProxy(invalid_service_name, + ObjectPath("/org/chromium/TestObject")); MethodCall method_call("org.chromium.TestInterface", "Echo");
diff --git a/dbus/end_to_end_sync_unittest.cc b/dbus/end_to_end_sync_unittest.cc index 4eb9cd1..d0dafcc 100644 --- a/dbus/end_to_end_sync_unittest.cc +++ b/dbus/end_to_end_sync_unittest.cc
@@ -108,29 +108,13 @@ ASSERT_FALSE(response.get()); } -TEST_F(EndToEndSyncTest, InvalidObjectPath) { - // Trailing '/' is only allowed for the root path. - const ObjectPath invalid_object_path("/org/chromium/TestObject/"); - - // Replace object proxy with new one. - object_proxy_ = client_bus_->GetObjectProxy(test_service_->service_name(), - invalid_object_path); - - MethodCall method_call("org.chromium.TestInterface", "Echo"); - - const int timeout_ms = ObjectProxy::TIMEOUT_USE_DEFAULT; - std::unique_ptr<Response> response( - object_proxy_->CallMethodAndBlock(&method_call, timeout_ms)); - ASSERT_FALSE(response.get()); -} - TEST_F(EndToEndSyncTest, InvalidServiceName) { // Bus name cannot contain '/'. const std::string invalid_service_name = ":1/2"; // Replace object proxy with new one. object_proxy_ = client_bus_->GetObjectProxy( - invalid_service_name, ObjectPath("org.chromium.TestObject")); + invalid_service_name, ObjectPath("/org/chromium/TestObject")); MethodCall method_call("org.chromium.TestInterface", "Echo");
diff --git a/dbus/exported_object.cc b/dbus/exported_object.cc index 2047f3f..47d0660 100644 --- a/dbus/exported_object.cc +++ b/dbus/exported_object.cc
@@ -34,6 +34,7 @@ : bus_(bus), object_path_(object_path), object_is_registered_(false) { + LOG_IF(FATAL, !object_path_.IsValid()) << object_path_.value(); } ExportedObject::~ExportedObject() {
diff --git a/dbus/message.cc b/dbus/message.cc index 9505dbb4..ec0b2234 100644 --- a/dbus/message.cc +++ b/dbus/message.cc
@@ -459,7 +459,7 @@ // dbus_message_iter_append_basic() used in AppendBasic() expects four // bytes for DBUS_TYPE_BOOLEAN, so we must pass a dbus_bool_t, instead // of a bool, to AppendBasic(). - dbus_bool_t dbus_value = value; + dbus_bool_t dbus_value = value ? 1 : 0; AppendBasic(DBUS_TYPE_BOOLEAN, &dbus_value); }
diff --git a/dbus/object_manager.cc b/dbus/object_manager.cc index 3a39cd6..cdcd63a 100644 --- a/dbus/object_manager.cc +++ b/dbus/object_manager.cc
@@ -38,6 +38,7 @@ setup_success_(false), cleanup_called_(false), weak_ptr_factory_(this) { + LOG_IF(FATAL, !object_path_.IsValid()) << object_path_.value(); DVLOG(1) << "Creating ObjectManager for " << service_name_ << " " << object_path_.value(); DCHECK(bus_);
diff --git a/dbus/object_proxy.cc b/dbus/object_proxy.cc index 729df1f..4d4ef121 100644 --- a/dbus/object_proxy.cc +++ b/dbus/object_proxy.cc
@@ -62,6 +62,7 @@ object_path_(object_path), ignore_service_unknown_errors_( options & IGNORE_SERVICE_UNKNOWN_ERRORS) { + LOG_IF(FATAL, !object_path_.IsValid()) << object_path_.value(); } ObjectProxy::~ObjectProxy() {
diff --git a/device/geolocation/BUILD.gn b/device/geolocation/BUILD.gn index 4539c83..0d865cbc 100644 --- a/device/geolocation/BUILD.gn +++ b/device/geolocation/BUILD.gn
@@ -64,7 +64,6 @@ deps = [ "//base", - "//google_apis:google_apis", "//mojo/edk/system", "//mojo/public/cpp/bindings", "//net",
diff --git a/device/geolocation/DEPS b/device/geolocation/DEPS index 70aa741..d3e3a8c 100644 --- a/device/geolocation/DEPS +++ b/device/geolocation/DEPS
@@ -1,7 +1,6 @@ include_rules = [ "+chromeos", "+dbus", - "+google_apis", "+jni", "+net", "+third_party/cros_system_api/dbus",
diff --git a/device/geolocation/geolocation_provider.h b/device/geolocation/geolocation_provider.h index 07f58fe4..a9d95c9 100644 --- a/device/geolocation/geolocation_provider.h +++ b/device/geolocation/geolocation_provider.h
@@ -30,9 +30,15 @@ DEVICE_GEOLOCATION_EXPORT static GeolocationProvider* GetInstance(); // Optional: provide a Delegate to override typical services. + // Call before using Init() on the singleton GetInstance(), and call no more + // than once. DEVICE_GEOLOCATION_EXPORT static void SetGeolocationDelegate( GeolocationDelegate* delegate); + // Optional: Provide a Google API key for network geolocation requests. + // Call before using Init() on the singleton GetInstance(). + DEVICE_GEOLOCATION_EXPORT static void SetApiKey(const std::string& api_key); + typedef base::Callback<void(const Geoposition&)> LocationUpdateCallback; typedef base::CallbackList<void(const Geoposition&)>::Subscription Subscription;
diff --git a/device/geolocation/geolocation_provider_impl.cc b/device/geolocation/geolocation_provider_impl.cc index 3ea97c9..4f4773c 100644 --- a/device/geolocation/geolocation_provider_impl.cc +++ b/device/geolocation/geolocation_provider_impl.cc
@@ -24,7 +24,8 @@ namespace { base::LazyInstance<std::unique_ptr<GeolocationDelegate>>::Leaky g_delegate = LAZY_INSTANCE_INITIALIZER; -} // anonymous namespace +base::LazyInstance<std::string>::Leaky g_api_key = LAZY_INSTANCE_INITIALIZER; +} // namespace // static GeolocationProvider* GeolocationProvider::GetInstance() { @@ -38,6 +39,11 @@ g_delegate.Get().reset(delegate); } +// static +void GeolocationProvider::SetApiKey(const std::string& api_key) { + g_api_key.Get() = api_key; +} + std::unique_ptr<GeolocationProvider::Subscription> GeolocationProviderImpl::AddLocationUpdateCallback( const LocationUpdateCallback& callback, @@ -187,17 +193,18 @@ void GeolocationProviderImpl::Init() { DCHECK(OnGeolocationThread()); - if (!arbitrator_) { - LocationProvider::LocationProviderUpdateCallback callback = base::Bind( - &GeolocationProviderImpl::OnLocationUpdate, base::Unretained(this)); - // Use the embedder's |g_delegate| or fall back to the default one. - if (!g_delegate.Get()) - g_delegate.Get().reset(new GeolocationDelegate); + if (arbitrator_) + return; - arbitrator_ = std::make_unique<LocationArbitrator>( - base::WrapUnique(g_delegate.Get().get())); - arbitrator_->SetUpdateCallback(callback); - } + LocationProvider::LocationProviderUpdateCallback callback = base::Bind( + &GeolocationProviderImpl::OnLocationUpdate, base::Unretained(this)); + // Use the embedder's |g_delegate| or fall back to the default one. + if (!g_delegate.Get()) + g_delegate.Get().reset(new GeolocationDelegate); + + arbitrator_ = std::make_unique<LocationArbitrator>( + base::WrapUnique(g_delegate.Get().get()), g_api_key.Get()); + arbitrator_->SetUpdateCallback(callback); } void GeolocationProviderImpl::CleanUp() {
diff --git a/device/geolocation/location_arbitrator.cc b/device/geolocation/location_arbitrator.cc index ad02d19..4d221eb 100644 --- a/device/geolocation/location_arbitrator.cc +++ b/device/geolocation/location_arbitrator.cc
@@ -15,14 +15,8 @@ #include "device/geolocation/access_token_store.h" #include "device/geolocation/geolocation_delegate.h" #include "device/geolocation/network_location_provider.h" -#include "url/gurl.h" namespace device { -namespace { - -const char* kDefaultNetworkProviderUrl = - "https://www.googleapis.com/geolocation/v1/geolocate"; -} // namespace // To avoid oscillations, set this to twice the expected update interval of a // a GPS-type location provider (in case it misses a beat) plus a little. @@ -30,18 +24,16 @@ 11 * base::Time::kMillisecondsPerSecond; LocationArbitrator::LocationArbitrator( - std::unique_ptr<GeolocationDelegate> delegate) + std::unique_ptr<GeolocationDelegate> delegate, + const std::string& api_key) : delegate_(std::move(delegate)), + api_key_(api_key), position_provider_(nullptr), is_permission_granted_(false), is_running_(false) {} LocationArbitrator::~LocationArbitrator() {} -GURL LocationArbitrator::DefaultNetworkProviderURL() { - return GURL(kDefaultNetworkProviderUrl); -} - bool LocationArbitrator::HasPermissionBeenGrantedForTest() const { return is_permission_granted_; } @@ -65,7 +57,6 @@ const scoped_refptr<AccessTokenStore> access_token_store = GetAccessTokenStore(); if (access_token_store) { - DCHECK(DefaultNetworkProviderURL().is_valid()); token_store_callback_.Reset( base::Bind(&LocationArbitrator::OnAccessTokenStoresLoaded, base::Unretained(this))); @@ -106,13 +97,8 @@ void LocationArbitrator::OnAccessTokenStoresLoaded( AccessTokenStore::AccessTokenMap access_token_map, const scoped_refptr<net::URLRequestContextGetter>& context_getter) { - // If there are no access tokens, boot strap it with the default server URL. - if (access_token_map.empty()) - access_token_map[DefaultNetworkProviderURL()]; - for (const auto& entry : access_token_map) { - RegisterProvider(NewNetworkLocationProvider( - GetAccessTokenStore(), context_getter, entry.first, entry.second)); - } + // Create a NetworkLocationProvider using the provided request context. + RegisterProvider(NewNetworkLocationProvider(context_getter, api_key_)); DoStartProviders(); } @@ -169,15 +155,13 @@ std::unique_ptr<LocationProvider> LocationArbitrator::NewNetworkLocationProvider( - const scoped_refptr<AccessTokenStore>& access_token_store, const scoped_refptr<net::URLRequestContextGetter>& context, - const GURL& url, - const base::string16& access_token) { + const std::string& api_key) { #if defined(OS_ANDROID) // Android uses its own SystemLocationProvider. return nullptr; #else - return std::make_unique<NetworkLocationProvider>(context, url); + return std::make_unique<NetworkLocationProvider>(context, api_key); #endif }
diff --git a/device/geolocation/location_arbitrator.h b/device/geolocation/location_arbitrator.h index 343d366..122973e 100644 --- a/device/geolocation/location_arbitrator.h +++ b/device/geolocation/location_arbitrator.h
@@ -40,7 +40,8 @@ // (regardles of relative accuracy). Public for tests. static const int64_t kFixStaleTimeoutMilliseconds; - explicit LocationArbitrator(std::unique_ptr<GeolocationDelegate> delegate); + LocationArbitrator(std::unique_ptr<GeolocationDelegate> delegate, + const std::string& api_key); ~LocationArbitrator() override; static GURL DefaultNetworkProviderURL(); @@ -59,10 +60,8 @@ // testing classes. virtual scoped_refptr<AccessTokenStore> NewAccessTokenStore(); virtual std::unique_ptr<LocationProvider> NewNetworkLocationProvider( - const scoped_refptr<AccessTokenStore>& access_token_store, const scoped_refptr<net::URLRequestContextGetter>& context, - const GURL& url, - const base::string16& access_token); + const std::string& api_key); virtual std::unique_ptr<LocationProvider> NewSystemLocationProvider(); virtual base::Time GetTimeNow() const; @@ -92,7 +91,8 @@ const Geoposition& new_position, bool from_same_provider) const; - std::unique_ptr<GeolocationDelegate> delegate_; + const std::unique_ptr<GeolocationDelegate> delegate_; + const std::string api_key_; scoped_refptr<AccessTokenStore> access_token_store_; LocationProvider::LocationProviderUpdateCallback arbitrator_update_callback_;
diff --git a/device/geolocation/location_arbitrator_unittest.cc b/device/geolocation/location_arbitrator_unittest.cc index 4353b3cf..ea4ee5c 100644 --- a/device/geolocation/location_arbitrator_unittest.cc +++ b/device/geolocation/location_arbitrator_unittest.cc
@@ -113,17 +113,17 @@ public: TestingLocationArbitrator(const LocationProviderUpdateCallback& callback, std::unique_ptr<GeolocationDelegate> delegate) - : LocationArbitrator(std::move(delegate)), cell_(nullptr), gps_(nullptr) { + : LocationArbitrator(std::move(delegate), std::string() /* api_key */), + cell_(nullptr), + gps_(nullptr) { SetUpdateCallback(callback); } base::Time GetTimeNow() const override { return GetTimeNowForTest(); } std::unique_ptr<LocationProvider> NewNetworkLocationProvider( - const scoped_refptr<AccessTokenStore>& access_token_store, const scoped_refptr<net::URLRequestContextGetter>& context, - const GURL& url, - const base::string16& access_token) override { + const std::string& api_key) override { cell_ = new FakeLocationProvider; return base::WrapUnique(cell_); }
diff --git a/device/geolocation/network_location_provider.cc b/device/geolocation/network_location_provider.cc index d22b5767..9f7e93d 100644 --- a/device/geolocation/network_location_provider.cc +++ b/device/geolocation/network_location_provider.cc
@@ -91,17 +91,10 @@ return !key->empty(); } -// NetworkLocationProvider factory function -LocationProvider* NewNetworkLocationProvider( - const scoped_refptr<net::URLRequestContextGetter>& context, - const GURL& url) { - return new NetworkLocationProvider(context, url); -} - // NetworkLocationProvider NetworkLocationProvider::NetworkLocationProvider( const scoped_refptr<net::URLRequestContextGetter>& url_context_getter, - const GURL& url) + const std::string& api_key) : wifi_data_provider_manager_(nullptr), wifi_data_update_callback_( base::Bind(&NetworkLocationProvider::OnWifiDataUpdate, @@ -111,7 +104,7 @@ is_new_data_available_(false), request_(new NetworkLocationRequest( url_context_getter, - url, + api_key, base::Bind(&NetworkLocationProvider::OnLocationResponse, base::Unretained(this)))), position_cache_(new PositionCache),
diff --git a/device/geolocation/network_location_provider.h b/device/geolocation/network_location_provider.h index 884924a..a43b698 100644 --- a/device/geolocation/network_location_provider.h +++ b/device/geolocation/network_location_provider.h
@@ -61,9 +61,9 @@ CacheAgeList cache_age_list_; // Oldest first. }; - NetworkLocationProvider( + DEVICE_GEOLOCATION_EXPORT NetworkLocationProvider( const scoped_refptr<net::URLRequestContextGetter>& context, - const GURL& url); + const std::string& api_key); ~NetworkLocationProvider() override; // LocationProvider implementation @@ -111,7 +111,7 @@ bool is_new_data_available_; - // The network location request object, and the url it uses. + // The network location request object. const std::unique_ptr<NetworkLocationRequest> request_; // The cache of positions. @@ -124,12 +124,6 @@ DISALLOW_COPY_AND_ASSIGN(NetworkLocationProvider); }; -// Factory functions for the various types of location provider to abstract -// over the platform-dependent implementations. -DEVICE_GEOLOCATION_EXPORT LocationProvider* NewNetworkLocationProvider( - const scoped_refptr<net::URLRequestContextGetter>& context, - const GURL& url); - } // namespace device #endif // DEVICE_GEOLOCATION_NETWORK_LOCATION_PROVIDER_H_
diff --git a/device/geolocation/network_location_provider_unittest.cc b/device/geolocation/network_location_provider_unittest.cc index feb60b1..f150db0 100644 --- a/device/geolocation/network_location_provider_unittest.cc +++ b/device/geolocation/network_location_provider_unittest.cc
@@ -30,9 +30,6 @@ namespace device { -// Constants used in multiple tests. -const char kTestServerUrl[] = "https://www.geolocation.test/service"; - // Stops the specified (nested) message loop when the listener is called back. class MessageLoopQuitListener { public: @@ -116,10 +113,11 @@ WifiDataProviderManager::ResetFactoryForTesting(); } - LocationProvider* CreateProvider(bool set_permission_granted) { - LocationProvider* provider = NewNetworkLocationProvider( - nullptr, // No URLContextGetter needed, using test urlfecther factory. - test_server_url_); + LocationProvider* CreateProvider(bool set_permission_granted, + const std::string& api_key = std::string()) { + // No URLContextGetter needed: The request within the provider is tested + // directly using TestURLFetcherFactory. + LocationProvider* provider = new NetworkLocationProvider(nullptr, api_key); if (set_permission_granted) provider->OnPermissionGranted(); return provider; @@ -127,8 +125,7 @@ protected: GeolocationNetworkProviderTest() - : test_server_url_(kTestServerUrl), - wifi_data_provider_(MockWifiDataProvider::CreateInstance()) { + : wifi_data_provider_(MockWifiDataProvider::CreateInstance()) { // TODO(joth): Really these should be in SetUp, not here, but they take no // effect on Mac OS Release builds if done there. I kid not. Figure out why. WifiDataProviderManager::SetFactoryForTesting( @@ -228,20 +225,6 @@ return testing::AssertionSuccess(); } - static GURL UrlWithoutQuery(const GURL& url) { - url::Replacements<char> replacements; - replacements.ClearQuery(); - return url.ReplaceComponents(replacements); - } - - testing::AssertionResult IsTestServerUrl(const GURL& request_url) { - const GURL a(UrlWithoutQuery(test_server_url_)); - const GURL b(UrlWithoutQuery(request_url)); - if (a == b) - return testing::AssertionSuccess(); - return testing::AssertionFailure() << a << " != " << b; - } - // Checks that |request| contains valid JSON upload data. The Wifi access // points specified in the JSON are validated against the first // |expected_wifi_aps| access points, starting from position @@ -249,17 +232,6 @@ void CheckRequestIsValid(const net::TestURLFetcher& request, int expected_wifi_aps, int wifi_start_index) { - const GURL& request_url = request.GetOriginalURL(); - - EXPECT_TRUE(IsTestServerUrl(request_url)); - - // Check to see that the api key is being appended for the default - // network provider url. - bool is_default_url = - UrlWithoutQuery(request_url) == - UrlWithoutQuery(LocationArbitrator::DefaultNetworkProviderURL()); - EXPECT_EQ(is_default_url, !request_url.query().empty()); - const std::string& upload_data = request.upload_data(); ASSERT_FALSE(upload_data.empty()); std::string json_parse_error_msg; @@ -297,10 +269,8 @@ } else { ASSERT_FALSE(request_json->HasKey("wifiAccessPoints")); } - EXPECT_TRUE(request_url.is_valid()); } - GURL test_server_url_; const base::MessageLoop main_message_loop_; const net::TestURLFetcherFactory url_fetcher_factory_; const scoped_refptr<MockWifiDataProvider> wifi_data_provider_; @@ -315,20 +285,32 @@ SUCCEED(); } -// Tests that, after StartProvider(), a TestURLFetcher can be extracted, -// representing a valid request. -TEST_F(GeolocationNetworkProviderTest, StartProvider) { - std::unique_ptr<LocationProvider> provider(CreateProvider(true)); +// Tests that, with an empty api_key, no query string parameter is included in +// the request. +TEST_F(GeolocationNetworkProviderTest, EmptyApiKey) { + const std::string api_key = ""; + std::unique_ptr<LocationProvider> provider(CreateProvider(true, api_key)); EXPECT_TRUE(provider->StartProvider(false)); net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id(); ASSERT_TRUE(fetcher); - CheckRequestIsValid(*fetcher, 0, 0); + EXPECT_FALSE(fetcher->GetOriginalURL().has_query()); } -// Tests StartProvider() in the special case that the endpoint URL is the -// DefaultNetworkProviderURL. -TEST_F(GeolocationNetworkProviderTest, StartProviderDefaultUrl) { - test_server_url_ = LocationArbitrator::DefaultNetworkProviderURL(); +// Tests that, with non-empty api_key, a "key" query string parameter is +// included in the request. +TEST_F(GeolocationNetworkProviderTest, NonEmptyApiKey) { + const std::string api_key = "something"; + std::unique_ptr<LocationProvider> provider(CreateProvider(true, api_key)); + EXPECT_TRUE(provider->StartProvider(false)); + net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id(); + ASSERT_TRUE(fetcher); + EXPECT_TRUE(fetcher->GetOriginalURL().has_query()); + EXPECT_TRUE(fetcher->GetOriginalURL().query_piece().starts_with("key=")); +} + +// Tests that, after StartProvider(), a TestURLFetcher can be extracted, +// representing a valid request. +TEST_F(GeolocationNetworkProviderTest, StartProvider) { std::unique_ptr<LocationProvider> provider(CreateProvider(true)); EXPECT_TRUE(provider->StartProvider(false)); net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id(); @@ -371,14 +353,12 @@ net::TestURLFetcher* fetcher = get_url_fetcher_and_advance_id(); ASSERT_TRUE(fetcher); - EXPECT_TRUE(IsTestServerUrl(fetcher->GetOriginalURL())); // 1. Complete the network request with bad position fix. const char* kNoFixNetworkResponse = "{" " \"status\": \"ZERO_RESULTS\"" "}"; - fetcher->set_url(test_server_url_); fetcher->set_status(net::URLRequestStatus()); fetcher->set_response_code(200); // OK fetcher->SetResponseString(kNoFixNetworkResponse); @@ -405,7 +385,6 @@ " \"lng\": -0.1" " }" "}"; - fetcher->set_url(test_server_url_); fetcher->set_status(net::URLRequestStatus()); fetcher->set_response_code(200); // OK fetcher->SetResponseString(kReferenceNetworkResponse); @@ -440,7 +419,6 @@ CheckRequestIsValid(*fetcher, kThirdScanAps, 0); // 6. ...reply with a network error. - fetcher->set_url(test_server_url_); fetcher->set_status(net::URLRequestStatus::FromError(net::ERR_FAILED)); fetcher->set_response_code(200); // should be ignored fetcher->SetResponseString(std::string()); @@ -511,8 +489,6 @@ fetcher = get_url_fetcher_and_advance_id(); ASSERT_TRUE(fetcher); - - EXPECT_TRUE(IsTestServerUrl(fetcher->GetOriginalURL())); } // Tests that, even if new Wifi data arrives, the provider doesn't initiate its
diff --git a/device/geolocation/network_location_request.cc b/device/geolocation/network_location_request.cc index e3c2025..7d424fa 100644 --- a/device/geolocation/network_location_request.cc +++ b/device/geolocation/network_location_request.cc
@@ -21,7 +21,6 @@ #include "base/values.h" #include "device/geolocation/geoposition.h" #include "device/geolocation/location_arbitrator.h" -#include "google_apis/google_api_keys.h" #include "net/base/escape.h" #include "net/base/load_flags.h" #include "net/traffic_annotation/network_traffic_annotation.h" @@ -32,6 +31,9 @@ namespace device { namespace { +const char kNetworkLocationBaseUrl[] = + "https://www.googleapis.com/geolocation/v1/geolocate"; + const char kLocationString[] = "location"; const char kLatitudeString[] = "lat"; const char kLongitudeString[] = "lng"; @@ -72,8 +74,11 @@ } // Local functions -// Creates the request url to send to the server. -GURL FormRequestURL(const GURL& url); + +// Returns a URL for a request to the Google Maps geolocation API. If the +// specified |api_key| is not empty, it is escaped and included as a query +// string parameter. +GURL FormRequestURL(const std::string& api_key); void FormUploadData(const WifiData& wifi_data, const base::Time& wifi_timestamp, @@ -103,11 +108,11 @@ NetworkLocationRequest::NetworkLocationRequest( const scoped_refptr<net::URLRequestContextGetter>& context, - const GURL& url, + const std::string& api_key, LocationResponseCallback callback) - : url_context_(context), location_response_callback_(callback), url_(url) { - DCHECK(url.is_valid()); -} + : url_context_(context), + api_key_(api_key), + location_response_callback_(callback) {} NetworkLocationRequest::~NetworkLocationRequest() {} @@ -123,7 +128,6 @@ wifi_data_ = wifi_data; wifi_timestamp_ = wifi_timestamp; - GURL request_url = FormRequestURL(url_); net::NetworkTrafficAnnotationTag traffic_annotation = net::DefineNetworkTrafficAnnotation("device_geolocation_request", R"( semantics { @@ -148,6 +152,8 @@ } } })"); + const GURL request_url = FormRequestURL(api_key_); + DCHECK(request_url.is_valid()); url_fetcher_ = net::URLFetcher::Create(url_fetcher_id_for_tests, request_url, net::URLFetcher::POST, this, traffic_annotation); @@ -204,18 +210,16 @@ } }; -GURL FormRequestURL(const GURL& url) { - if (url == LocationArbitrator::DefaultNetworkProviderURL()) { - std::string api_key = google_apis::GetAPIKey(); - if (!api_key.empty()) { - std::string query(url.query()); - if (!query.empty()) - query += "&"; - query += "key=" + net::EscapeQueryParamValue(api_key, true); - GURL::Replacements replacements; - replacements.SetQueryStr(query); - return url.ReplaceComponents(replacements); - } +GURL FormRequestURL(const std::string& api_key) { + GURL url(kNetworkLocationBaseUrl); + if (!api_key.empty()) { + std::string query(url.query()); + if (!query.empty()) + query += "&"; + query += "key=" + net::EscapeQueryParamValue(api_key, true); + GURL::Replacements replacements; + replacements.SetQueryStr(query); + return url.ReplaceComponents(replacements); } return url; }
diff --git a/device/geolocation/network_location_request.h b/device/geolocation/network_location_request.h index 8215101..c58529d 100644 --- a/device/geolocation/network_location_request.h +++ b/device/geolocation/network_location_request.h
@@ -39,10 +39,9 @@ const WifiData& /* wifi_data */)> LocationResponseCallback; - // |url| is the server address to which the request wil be sent. NetworkLocationRequest( const scoped_refptr<net::URLRequestContextGetter>& context, - const GURL& url, + const std::string& api_key, LocationResponseCallback callback); ~NetworkLocationRequest() override; @@ -51,15 +50,14 @@ bool MakeRequest(const WifiData& wifi_data, const base::Time& wifi_timestamp); bool is_request_pending() const { return url_fetcher_ != NULL; } - const GURL& url() const { return url_; } private: // net::URLFetcherDelegate void OnURLFetchComplete(const net::URLFetcher* source) override; const scoped_refptr<net::URLRequestContextGetter> url_context_; + const std::string api_key_; const LocationResponseCallback location_response_callback_; - const GURL url_; std::unique_ptr<net::URLFetcher> url_fetcher_; // Keep a copy of the data sent in the request, so we can refer back to it
diff --git a/ios/tools/coverage/coverage.py b/ios/tools/coverage/coverage.py index 05436f0..c1bdb1a 100755 --- a/ios/tools/coverage/coverage.py +++ b/ios/tools/coverage/coverage.py
@@ -37,6 +37,7 @@ import json import os import subprocess +import webbrowser BUILD_DIRECTORY = 'out/Coverage-iphonesimulator' DEFAULT_GOMA_JOBS = 50 @@ -211,6 +212,30 @@ return self._coverage[path]['total'], self._coverage[path]['executed'] +def _GenerateLineByLineFileCoverageInHtml( + target, profdata_path, file_line_coverage_report, output_dir): + """Generate per file line-by-line coverage in html using 'llvm-cov show'. + + For a file with absolute path /a/b/x.cc, a html report is generated as: + output_dir/a/b/x.cc.html. An index html file is also generated as: + output_dir/index.html. + + Args: + target: A string representing the name of the target to be tested. + profdata_path: A string representing the path to the profdata file. + file_line_coverage_report: A FileLineCoverageReport object. + output_dir: output directory for generated html files. + """ + application_path = _GetApplicationBundlePath(target) + binary_path = os.path.join(application_path, target) + cmd = ['xcrun', 'llvm-cov', 'show', '-instr-profile', profdata_path, + '-arch=x86_64', binary_path, '-format=html', '-show-expansions'] + cmd.append('-output-dir=' + output_dir) + cmd.extend(file_line_coverage_report.GetListOfFiles()) + + subprocess.check_call(cmd) + + def _CreateCoverageProfileDataForTarget(target, jobs_count=None, gtest_filter=None): """Builds and runs target to generate the coverage profile data. @@ -716,6 +741,9 @@ help='Skip building test target and running tests ' 'and re-use the specified profile data file.') + arg_parser.add_argument('-o', '--output-dir', type=str, required=True, + help='Output directory for html report.') + arg_parser.add_argument('--gtest_filter', type=str, help='Only run unit tests whose full name matches ' 'the filter.') @@ -795,6 +823,13 @@ top_level_dir) _PrintLineCoverageStats(total, executed) + _GenerateLineByLineFileCoverageInHtml( + target, profdata_path, file_line_coverage_report, args.output_dir) + + html_index_file_path = 'file://' + os.path.abspath( + os.path.join(args.output_dir, 'index.html')) + webbrowser.open(html_index_file_path) + if __name__ == '__main__': sys.exit(Main())
diff --git a/media/midi/BUILD.gn b/media/midi/BUILD.gn index 22649bf..e69fe0d 100644 --- a/media/midi/BUILD.gn +++ b/media/midi/BUILD.gn
@@ -154,17 +154,6 @@ } } - if (is_chromeos) { - # CrOS version can be used with target_os="chromeos" on Linux. - # MIDI Service client library should be added here. We would have a separate - # build flag, use_midis, to use the real MIDI Service on Chrome OS device - # builds, and add a mocked service for unit tests to run on Linux. - sources += [ - "chromeos/midi_manager_cros.cc", - "chromeos/midi_manager_cros.h", - ] - } - if (use_alsa && use_udev) { deps += [ "//crypto",
diff --git a/media/midi/chromeos/midi_manager_cros.cc b/media/midi/chromeos/midi_manager_cros.cc deleted file mode 100644 index b554e0ab..0000000 --- a/media/midi/chromeos/midi_manager_cros.cc +++ /dev/null
@@ -1,24 +0,0 @@ -// 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. - -#include "media/midi/chromeos/midi_manager_cros.h" - -#include "media/midi/midi_manager_alsa.h" -#include "media/midi/midi_switches.h" - -namespace midi { - -MidiManagerCros::MidiManagerCros(MidiService* service) : MidiManager(service) {} - -MidiManagerCros::~MidiManagerCros() = default; - -MidiManager* MidiManager::Create(MidiService* service) { - // Note: Because of crbug.com/719489, chrome://flags does not affect - // base::FeatureList::IsEnabled when you build target_os="chromeos" on Linux. - if (base::FeatureList::IsEnabled(features::kMidiManagerCros)) - return new MidiManagerCros(service); - return new MidiManagerAlsa(service); -} - -} // namespace midi
diff --git a/media/midi/chromeos/midi_manager_cros.h b/media/midi/chromeos/midi_manager_cros.h deleted file mode 100644 index 4a8f94a..0000000 --- a/media/midi/chromeos/midi_manager_cros.h +++ /dev/null
@@ -1,23 +0,0 @@ -// 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. - -#ifndef MEDIA_MIDI_CHROMEOS_MIDI_MANAGER_CROS_H_ -#define MEDIA_MIDI_CHROMEOS_MIDI_MANAGER_CROS_H_ - -#include "media/midi/midi_export.h" -#include "media/midi/midi_manager.h" - -namespace midi { - -class MIDI_EXPORT MidiManagerCros final : public MidiManager { - public: - explicit MidiManagerCros(MidiService* service); - ~MidiManagerCros() override; - - DISALLOW_COPY_AND_ASSIGN(MidiManagerCros); -}; - -} // namespace midi - -#endif // MEDIA_MIDI_CHROMEOS_MIDI_MANAGER_CROS_H_
diff --git a/media/midi/midi_manager_alsa.cc b/media/midi/midi_manager_alsa.cc index 8810a14..5bd03f8a 100644 --- a/media/midi/midi_manager_alsa.cc +++ b/media/midi/midi_manager_alsa.cc
@@ -1383,10 +1383,8 @@ return ScopedSndMidiEventPtr(coder); } -#if !defined(OS_CHROMEOS) MidiManager* MidiManager::Create(MidiService* service) { return new MidiManagerAlsa(service); } -#endif } // namespace midi
diff --git a/media/midi/midi_switches.cc b/media/midi/midi_switches.cc index c64c544..96e7974b 100644 --- a/media/midi/midi_switches.cc +++ b/media/midi/midi_switches.cc
@@ -18,11 +18,6 @@ base::FEATURE_DISABLED_BY_DEFAULT}; #endif -#if defined(OS_CHROMEOS) -const base::Feature kMidiManagerCros{"MidiManagerCros", - base::FEATURE_DISABLED_BY_DEFAULT}; -#endif - const base::Feature kMidiManagerDynamicInstantiation{ "MidiManagerDynamicInstantiation", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/media/midi/midi_switches.h b/media/midi/midi_switches.h index e6b3526..b5e45b0 100644 --- a/media/midi/midi_switches.h +++ b/media/midi/midi_switches.h
@@ -22,10 +22,6 @@ MIDI_EXPORT extern const base::Feature kMidiManagerWinrt; #endif -#if defined(OS_CHROMEOS) -MIDI_EXPORT extern const base::Feature kMidiManagerCros; -#endif - MIDI_EXPORT extern const base::Feature kMidiManagerDynamicInstantiation; } // namespace features
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-star.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-star.any-expected.txt index b60014a..262978b 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-star.any-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-star.any-expected.txt
@@ -1,6 +1,6 @@ This is a testharness.js-based test. PASS CORS that succeeds with credentials: false; method: GET (allowed: get); header: X-Test,1 (allowed: x-test) -FAIL CORS that succeeds with credentials: false; method: SUPER (allowed: *); header: X-Test,1 (allowed: x-test) promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch" +PASS CORS that succeeds with credentials: false; method: SUPER (allowed: *); header: X-Test,1 (allowed: x-test) FAIL CORS that succeeds with credentials: false; method: OK (allowed: *); header: X-Test,1 (allowed: *) promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch" PASS CORS that fails with credentials: true; method: OK (allowed: *); header: X-Test,1 (allowed: *) PASS CORS that fails with credentials: true; method: PUT (allowed: *); header: (allowed: )
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-star.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-star.any.worker-expected.txt index b60014a..262978b 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-star.any.worker-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-star.any.worker-expected.txt
@@ -1,6 +1,6 @@ This is a testharness.js-based test. PASS CORS that succeeds with credentials: false; method: GET (allowed: get); header: X-Test,1 (allowed: x-test) -FAIL CORS that succeeds with credentials: false; method: SUPER (allowed: *); header: X-Test,1 (allowed: x-test) promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch" +PASS CORS that succeeds with credentials: false; method: SUPER (allowed: *); header: X-Test,1 (allowed: x-test) FAIL CORS that succeeds with credentials: false; method: OK (allowed: *); header: X-Test,1 (allowed: *) promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch" PASS CORS that fails with credentials: true; method: OK (allowed: *); header: X-Test,1 (allowed: *) PASS CORS that fails with credentials: true; method: PUT (allowed: *); header: (allowed: )
diff --git a/third_party/WebKit/Source/build/scripts/make_event_factory.py b/third_party/WebKit/Source/build/scripts/make_event_factory.py index 8cac11b0..456a86d5 100755 --- a/third_party/WebKit/Source/build/scripts/make_event_factory.py +++ b/third_party/WebKit/Source/build/scripts/make_event_factory.py
@@ -151,16 +151,8 @@ # Avoid duplicate includes. if cpp_name in includes: continue - if self.suffix == 'Modules': - subdir_name = 'modules' - else: - subdir_name = 'core' - binding_name = self.get_file_basename('V8' + name_utilities.script_name(entry)) - includes[cpp_name] = '#include "%(path)s"\n#include "bindings/%(subdir_name)s/v8/%(binding_name)s.h"' % { - 'binding_name': binding_name, - 'path': self._headers_header_include_path(entry), - 'subdir_name': subdir_name, - } + includes[cpp_name] = ('#include "%s"' % + self._headers_header_include_path(entry)) return includes.values() def generate_headers_header(self):
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp index 306932f..876cdb5 100644 --- a/third_party/WebKit/Source/core/dom/Element.cpp +++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -2417,6 +2417,7 @@ ShadowRoot* Element::attachShadow(const ScriptState* script_state, const ShadowRootInit& shadow_root_init_dict, ExceptionState& exception_state) { + DCHECK(shadow_root_init_dict.hasMode()); HostsUsingFeatures::CountMainWorldOnly( script_state, GetDocument(), HostsUsingFeatures::Feature::kElementAttachShadow); @@ -2427,31 +2428,22 @@ return nullptr; } - if (shadow_root_init_dict.hasMode() && GetShadowRoot()) { + if (GetShadowRoot()) { exception_state.ThrowDOMException(kInvalidStateError, "Shadow root cannot be created on a host " "which already hosts a shadow tree."); return nullptr; } - ShadowRootType type = ShadowRootType::V0; - if (shadow_root_init_dict.hasMode()) - type = shadow_root_init_dict.mode() == "open" ? ShadowRootType::kOpen - : ShadowRootType::kClosed; + ShadowRootType type = shadow_root_init_dict.mode() == "open" + ? ShadowRootType::kOpen + : ShadowRootType::kClosed; - if (type == ShadowRootType::kClosed) - UseCounter::Count(GetDocument(), WebFeature::kElementAttachShadowClosed); - else if (type == ShadowRootType::kOpen) + if (type == ShadowRootType::kOpen) UseCounter::Count(GetDocument(), WebFeature::kElementAttachShadowOpen); + else + UseCounter::Count(GetDocument(), WebFeature::kElementAttachShadowClosed); - if (!AreAuthorShadowsAllowed()) { - exception_state.ThrowDOMException( - kHierarchyRequestError, - "Author-created shadow roots are disabled for this element."); - return nullptr; - } - - DCHECK(!shadow_root_init_dict.hasMode() || !GetShadowRoot()); bool delegateFocus = shadow_root_init_dict.hasDelegatesFocus() && shadow_root_init_dict.delegatesFocus(); return &AttachShadowRootInternal(type, delegateFocus);
diff --git a/third_party/WebKit/Source/core/editing/LayoutSelection.cpp b/third_party/WebKit/Source/core/editing/LayoutSelection.cpp index b80f01a4..b598598 100644 --- a/third_party/WebKit/Source/core/editing/LayoutSelection.cpp +++ b/third_party/WebKit/Source/core/editing/LayoutSelection.cpp
@@ -212,62 +212,28 @@ // This class represents a selection range in layout tree for marking // SelectionState -// TODO(yoichio): Remove unused functionality comparing to SelectionPaintRange. class SelectionMarkingRange { STACK_ALLOCATED(); public: SelectionMarkingRange() = default; - SelectionMarkingRange(LayoutObject* start_layout_object, - int start_offset, - LayoutObject* end_layout_object, - int end_offset, + SelectionMarkingRange(SelectionPaintRange paint_range, PaintInvalidationSet invalidation_set) - : start_layout_object_(start_layout_object), - start_offset_(start_offset), - end_layout_object_(end_layout_object), - end_offset_(end_offset), + : paint_range_(paint_range), invalidation_set_(std::move(invalidation_set)) {} SelectionMarkingRange(SelectionMarkingRange&& other) { - start_layout_object_ = other.start_layout_object_; - start_offset_ = other.start_offset_; - end_layout_object_ = other.end_layout_object_; - end_offset_ = other.end_offset_; + paint_range_ = other.paint_range_; invalidation_set_ = std::move(other.invalidation_set_); } - SelectionPaintRange ToPaintRange() const { - return {start_layout_object_, start_offset_, end_layout_object_, - end_offset_}; - }; + SelectionPaintRange PaintRange() const { return paint_range_; }; - LayoutObject* StartLayoutObject() const { - DCHECK(!IsNull()); - return start_layout_object_; - } - int StartOffset() const { - DCHECK(!IsNull()); - return start_offset_; - } - LayoutObject* EndLayoutObject() const { - DCHECK(!IsNull()); - return end_layout_object_; - } - int EndOffset() const { - DCHECK(!IsNull()); - return end_offset_; - } const PaintInvalidationSet& InvalidationSet() const { return invalidation_set_; } - bool IsNull() const { return !start_layout_object_; } - private: - LayoutObject* start_layout_object_ = nullptr; - int start_offset_ = -1; - LayoutObject* end_layout_object_ = nullptr; - int end_offset_ = -1; + SelectionPaintRange paint_range_; PaintInvalidationSet invalidation_set_; private: @@ -416,7 +382,7 @@ } MarkSelected(&invalidation_set, layout_object, SelectionState::kStartAndEnd); - return {layout_object, start_offset, layout_object, end_offset, + return {{layout_object, start_offset, layout_object, end_offset}, std::move(invalidation_set)}; } DCHECK_LE(start_offset, end_offset); @@ -429,17 +395,17 @@ DCHECK_GT(static_cast<unsigned>(end_offset), remaining_part->Start()); MarkSelected(&invalidation_set, remaining_part, SelectionState::kStartAndEnd); - return {remaining_part, - static_cast<int>(start_offset - remaining_part->Start()), - remaining_part, - static_cast<int>(end_offset - remaining_part->Start()), + return {{remaining_part, + static_cast<int>(start_offset - remaining_part->Start()), + remaining_part, + static_cast<int>(end_offset - remaining_part->Start())}, std::move(invalidation_set)}; } if (static_cast<unsigned>(end_offset) <= remaining_part->Start()) { // Case 2: The selection starts and ends in first letter part. MarkSelected(&invalidation_set, first_letter_part, SelectionState::kStartAndEnd); - return {first_letter_part, start_offset, first_letter_part, end_offset, + return {{first_letter_part, start_offset, first_letter_part, end_offset}, std::move(invalidation_set)}; } @@ -448,8 +414,8 @@ DCHECK_GT(static_cast<unsigned>(end_offset), remaining_part->Start()); MarkSelected(&invalidation_set, first_letter_part, SelectionState::kStart); MarkSelected(&invalidation_set, remaining_part, SelectionState::kEnd); - return {first_letter_part, start_offset, remaining_part, - static_cast<int>(end_offset - remaining_part->Start()), + return {{first_letter_part, start_offset, remaining_part, + static_cast<int>(end_offset - remaining_part->Start())}, std::move(invalidation_set)}; } @@ -471,7 +437,7 @@ MarkSelected(&invalidation_set, start_layout_object, SelectionState::kStart); MarkSelected(&invalidation_set, end_layout_object, SelectionState::kEnd); - return {start_layout_object, start_offset, end_layout_object, end_offset, + return {{start_layout_object, start_offset, end_layout_object, end_offset}, std::move(invalidation_set)}; } if (!start_first_letter_part) { @@ -483,8 +449,9 @@ SelectionState::kStart); MarkSelected(&invalidation_set, end_first_letter_part, SelectionState::kEnd); - return {start_layout_object, start_offset, end_first_letter_part, - end_offset, std::move(invalidation_set)}; + return {{start_layout_object, start_offset, end_first_letter_part, + end_offset}, + std::move(invalidation_set)}; } // Case 2: The selection ends in remaining part DCHECK_GT(static_cast<unsigned>(end_offset), end_remaining_part->Start()); @@ -493,8 +460,8 @@ MarkSelected(&invalidation_set, end_first_letter_part, SelectionState::kInside); MarkSelected(&invalidation_set, end_remaining_part, SelectionState::kEnd); - return {start_layout_object, start_offset, end_remaining_part, - static_cast<int>(end_offset - end_remaining_part->Start()), + return {{start_layout_object, start_offset, end_remaining_part, + static_cast<int>(end_offset - end_remaining_part->Start())}, std::move(invalidation_set)}; } if (!end_first_letter_part) { @@ -507,16 +474,18 @@ MarkSelected(&invalidation_set, start_remaining_part, SelectionState::kInside); MarkSelected(&invalidation_set, end_layout_object, SelectionState::kEnd); - return {start_first_letter_part, start_offset, end_layout_object, - end_offset, std::move(invalidation_set)}; + return {{start_first_letter_part, start_offset, end_layout_object, + end_offset}, + std::move(invalidation_set)}; } // Case 4: The selection starts in remaining part. MarkSelected(&invalidation_set, start_remaining_part, SelectionState::kStart); MarkSelected(&invalidation_set, end_layout_object, SelectionState::kEnd); - return {start_remaining_part, - static_cast<int>(start_offset - start_remaining_part->Start()), - end_layout_object, end_offset, std::move(invalidation_set)}; + return {{start_remaining_part, + static_cast<int>(start_offset - start_remaining_part->Start()), + end_layout_object, end_offset}, + std::move(invalidation_set)}; } LayoutTextFragment* const start_remaining_part = ToLayoutTextFragment(start_layout_object); @@ -531,8 +500,9 @@ SelectionState::kInside); MarkSelected(&invalidation_set, end_first_letter_part, SelectionState::kEnd); - return {start_first_letter_part, start_offset, end_first_letter_part, - end_offset, std::move(invalidation_set)}; + return {{start_first_letter_part, start_offset, end_first_letter_part, + end_offset}, + std::move(invalidation_set)}; } if (static_cast<unsigned>(start_offset) < start_remaining_part->Start()) { // Case 6: The selection starts in first-letter part and ends in remaining @@ -545,8 +515,8 @@ MarkSelected(&invalidation_set, end_first_letter_part, SelectionState::kInside); MarkSelected(&invalidation_set, end_remaining_part, SelectionState::kEnd); - return {start_first_letter_part, start_offset, end_remaining_part, - static_cast<int>(end_offset - end_remaining_part->Start()), + return {{start_first_letter_part, start_offset, end_remaining_part, + static_cast<int>(end_offset - end_remaining_part->Start())}, std::move(invalidation_set)}; } if (static_cast<unsigned>(end_offset) <= end_remaining_part->Start()) { @@ -558,9 +528,10 @@ SelectionState::kStart); MarkSelected(&invalidation_set, end_first_letter_part, SelectionState::kEnd); - return {start_remaining_part, - static_cast<int>(start_offset - start_remaining_part->Start()), - end_first_letter_part, end_offset, std::move(invalidation_set)}; + return {{start_remaining_part, + static_cast<int>(start_offset - start_remaining_part->Start()), + end_first_letter_part, end_offset}, + std::move(invalidation_set)}; } // Case 8: The selection starts in remaining part and ends in remaining part. DCHECK_GE(static_cast<unsigned>(start_offset), start_remaining_part->Start()); @@ -569,10 +540,10 @@ MarkSelected(&invalidation_set, end_first_letter_part, SelectionState::kInside); MarkSelected(&invalidation_set, end_remaining_part, SelectionState::kEnd); - return {start_remaining_part, - static_cast<int>(start_offset - start_remaining_part->Start()), - end_remaining_part, - static_cast<int>(end_offset - end_remaining_part->Start()), + return {{start_remaining_part, + static_cast<int>(start_offset - start_remaining_part->Start()), + end_remaining_part, + static_cast<int>(end_offset - end_remaining_part->Start())}, std::move(invalidation_set)}; } @@ -652,13 +623,14 @@ frame_selection_->GetDocument().Lifecycle()); const SelectionMarkingRange& new_range = CalcSelectionRangeAndSetSelectionState(*frame_selection_); - if (new_range.IsNull()) { + const SelectionPaintRange& new_paint_range = new_range.PaintRange(); + if (new_paint_range.IsNull()) { ClearSelection(); return; } DCHECK(frame_selection_->GetDocument().GetLayoutView()->GetFrameView()); SetShouldInvalidateSelection(new_range, paint_range_); - paint_range_ = new_range.ToPaintRange(); + paint_range_ = new_paint_range; // TODO(yoichio): Remove this if state. // This SelectionState reassignment is ad-hoc patch for // prohibiting use-after-free(crbug.com/752715).
diff --git a/third_party/WebKit/Source/core/editing/LayoutSelection.h b/third_party/WebKit/Source/core/editing/LayoutSelection.h index ebedb1e..928e685 100644 --- a/third_party/WebKit/Source/core/editing/LayoutSelection.h +++ b/third_party/WebKit/Source/core/editing/LayoutSelection.h
@@ -42,8 +42,6 @@ // editing/ passes them as offsets in the DOM tree but layout uses them as // offset in the layout tree. This doesn't work in the cases of // CSS first-letter or character transform. See crbug.com/17528. -// TODO(yoichio): Remove unused functionality comparing to -// SelectionMarkingRange. class SelectionPaintRange { DISALLOW_NEW();
diff --git a/third_party/WebKit/Source/core/editing/LayoutSelectionTest.cpp b/third_party/WebKit/Source/core/editing/LayoutSelectionTest.cpp index feac94f..7cb3d6f3 100644 --- a/third_party/WebKit/Source/core/editing/LayoutSelectionTest.cpp +++ b/third_party/WebKit/Source/core/editing/LayoutSelectionTest.cpp
@@ -74,6 +74,7 @@ USING_LAYOUTOBJECT_FUNC(IsBR); USING_LAYOUTOBJECT_FUNC(IsListItem); USING_LAYOUTOBJECT_FUNC(IsListMarker); +USING_LAYOUTOBJECT_FUNC(IsLayoutImage); static IsTypeOf IsLayoutTextFragmentOf(const String& text) { return WTF::Bind( @@ -102,14 +103,18 @@ const String& text, SelectionState state, InvalidateOption invalidate) { - if (!TestLayoutObjectState(object, state, invalidate)) - return false; - - if (!object->IsText()) - return false; - if (text != ToLayoutText(object)->GetText()) - return false; - return true; + return TestLayoutObject( + object, + WTF::Bind( + [](const String& text, const LayoutObject& object) { + if (!object.IsText()) + return false; + if (text != ToLayoutText(object).GetText()) + return false; + return true; + }, + text), + state, invalidate); } #define TEST_NEXT(predicate, state, invalidate) \ @@ -394,4 +399,14 @@ .Build()); Selection().CommitAppearanceIfNeeded(); } + +TEST_F(LayoutSelectionTest, SelectImage) { + const SelectionInDOMTree& selection = + SetSelectionTextToBody("^<img style=\"width:100px; height:100px\"/>|"); + Selection().SetSelection(selection); + Selection().CommitAppearanceIfNeeded(); + TEST_NEXT(IsLayoutBlock, kStartAndEnd, ShouldInvalidate); + TEST_NEXT(IsLayoutImage, kStartAndEnd, ShouldInvalidate); + TEST_NO_NEXT_LAYOUT_OBJECT(); +} } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp index bd7892a..02e9c155 100644 --- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp +++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -347,7 +347,6 @@ SimplifiedBackwardsTextIteratorAlgorithm<Strategy> it( EphemeralRangeTemplate<Strategy>(start, end)); - int remaining_length = 0; unsigned next = 0; bool need_more_context = false; while (!it.AtEnd()) { @@ -362,10 +361,8 @@ string.Size() - suffix_length, kMayHaveMoreContext, need_more_context); } while (!next && run_offset < it.length()); - if (next) { - remaining_length = it.length() - run_offset; + if (next) break; - } } else { // Treat bullets used in the text security mode as regular // characters when looking for boundaries @@ -387,13 +384,6 @@ if (!next) return it.AtEnd() ? it.StartPosition() : pos; - Node* node = it.StartContainer(); - int boundary_offset = remaining_length + next; - if (node->IsTextNode() && boundary_offset <= node->MaxCharacterOffset()) { - // The next variable contains a usable index into a text node - return PositionTemplate<Strategy>(node, boundary_offset); - } - // Use the character iterator to translate the next value into a DOM // position. BackwardsCharacterIteratorAlgorithm<Strategy> char_it(
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnitsWordTest.cpp b/third_party/WebKit/Source/core/editing/VisibleUnitsWordTest.cpp index becbcc61..735a8f9 100644 --- a/third_party/WebKit/Source/core/editing/VisibleUnitsWordTest.cpp +++ b/third_party/WebKit/Source/core/editing/VisibleUnitsWordTest.cpp
@@ -46,20 +46,19 @@ TEST_F(VisibleUnitsWordTest, StartOfWordFirstLetter) { InsertStyleElement("p::first-letter {font-size:200%;}"); - // TODO(editing-dev): We should make expected texts as same as - // "StartOfWordBasic". + // Note: Expectations should match with |StartOfWordBasic|. EXPECT_EQ("<p> |(1) abc def</p>", DoStartOfWord("<p>| (1) abc def</p>")); EXPECT_EQ("<p> |(1) abc def</p>", DoStartOfWord("<p> |(1) abc def</p>")); EXPECT_EQ("<p> (|1) abc def</p>", DoStartOfWord("<p> (|1) abc def</p>")); EXPECT_EQ("<p> (1|) abc def</p>", DoStartOfWord("<p> (1|) abc def</p>")); EXPECT_EQ("<p> (1)| abc def</p>", DoStartOfWord("<p> (1)| abc def</p>")); - EXPECT_EQ("<p> |(1) abc def</p>", DoStartOfWord("<p> (1) |abc def</p>")); - EXPECT_EQ("<p> |(1) abc def</p>", DoStartOfWord("<p> (1) a|bc def</p>")); - EXPECT_EQ("<p> |(1) abc def</p>", DoStartOfWord("<p> (1) ab|c def</p>")); - EXPECT_EQ("<p> (1)| abc def</p>", DoStartOfWord("<p> (1) abc| def</p>")); - EXPECT_EQ("<p> (1) |abc def</p>", DoStartOfWord("<p> (1) abc |def</p>")); - EXPECT_EQ("<p> (1) |abc def</p>", DoStartOfWord("<p> (1) abc d|ef</p>")); - EXPECT_EQ("<p> (1) |abc def</p>", DoStartOfWord("<p> (1) abc de|f</p>")); + EXPECT_EQ("<p> (1) |abc def</p>", DoStartOfWord("<p> (1) |abc def</p>")); + EXPECT_EQ("<p> (1) |abc def</p>", DoStartOfWord("<p> (1) a|bc def</p>")); + EXPECT_EQ("<p> (1) |abc def</p>", DoStartOfWord("<p> (1) ab|c def</p>")); + EXPECT_EQ("<p> (1) abc| def</p>", DoStartOfWord("<p> (1) abc| def</p>")); + EXPECT_EQ("<p> (1) abc |def</p>", DoStartOfWord("<p> (1) abc |def</p>")); + EXPECT_EQ("<p> (1) abc |def</p>", DoStartOfWord("<p> (1) abc d|ef</p>")); + EXPECT_EQ("<p> (1) abc |def</p>", DoStartOfWord("<p> (1) abc de|f</p>")); EXPECT_EQ("<p> (1) abc def|</p>", DoStartOfWord("<p> (1) abc def|</p>")); EXPECT_EQ("<p> (1) abc def|</p>", DoStartOfWord("<p> (1) abc def</p>|")); }
diff --git a/third_party/WebKit/Source/core/editing/testing/SelectionSample.cpp b/third_party/WebKit/Source/core/editing/testing/SelectionSample.cpp index 5ad20afe..0a144bb 100644 --- a/third_party/WebKit/Source/core/editing/testing/SelectionSample.cpp +++ b/third_party/WebKit/Source/core/editing/testing/SelectionSample.cpp
@@ -9,16 +9,45 @@ #include "core/dom/Attribute.h" #include "core/dom/CharacterData.h" +#include "core/dom/Document.h" #include "core/dom/Element.h" #include "core/dom/ProcessingInstruction.h" +#include "core/dom/ShadowRootInit.h" #include "core/editing/EditingUtilities.h" #include "core/editing/SelectionTemplate.h" +#include "core/html/HTMLCollection.h" +#include "core/html/HTMLTemplateElement.h" #include "platform/wtf/text/StringBuilder.h" namespace blink { namespace { +void ConvertTemplatesToShadowRoots(HTMLElement& element) { + // |element| and descendant elements can have TEMPLATE element with + // |data-mode="open"|, which is required. Each elemnt can have only one + // TEMPLATE element. + HTMLCollection* const templates = element.getElementsByTagName("template"); + HeapVector<Member<Element>> template_vector; + for (Element* template_element : *templates) + template_vector.push_back(template_element); + for (Element* template_element : template_vector) { + const AtomicString& data_mode = template_element->getAttribute("data-mode"); + DCHECK_EQ(data_mode, "open"); + + Element* const parent = template_element->parentElement(); + parent->removeChild(template_element); + + Document* const document = element.ownerDocument(); + ShadowRoot& shadow_root = + parent->AttachShadowRootInternal(ShadowRootType::kOpen); + Node* const fragment = + document->importNode(toHTMLTemplateElement(template_element)->content(), + true, ASSERT_NO_EXCEPTION); + shadow_root.AppendChild(fragment); + } +} + // Parse selection text notation into Selection object. template <typename Strategy> class Parser final { @@ -309,6 +338,11 @@ } // namespace +void SelectionSample::ConvertTemplatesToShadowRootsForTesring( + HTMLElement& element) { + ConvertTemplatesToShadowRoots(element); +} + SelectionInDOMTree SelectionSample::SetSelectionText( HTMLElement* element, const std::string& selection_text) {
diff --git a/third_party/WebKit/Source/core/editing/testing/SelectionSample.h b/third_party/WebKit/Source/core/editing/testing/SelectionSample.h index 3b4111d..04fa6b67 100644 --- a/third_party/WebKit/Source/core/editing/testing/SelectionSample.h +++ b/third_party/WebKit/Source/core/editing/testing/SelectionSample.h
@@ -36,6 +36,7 @@ // Note: We don't escape "--" in comment. static std::string GetSelectionText(const ContainerNode&, const SelectionInDOMTree&); + static void ConvertTemplatesToShadowRootsForTesring(HTMLElement&); }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/testing/SelectionSampleTest.cpp b/third_party/WebKit/Source/core/editing/testing/SelectionSampleTest.cpp index fdf03e4..9935431 100644 --- a/third_party/WebKit/Source/core/editing/testing/SelectionSampleTest.cpp +++ b/third_party/WebKit/Source/core/editing/testing/SelectionSampleTest.cpp
@@ -208,4 +208,66 @@ << "When BR has child nodes, it is not void element."; } +TEST_F(SelectionSampleTest, ConvertTemplatesToShadowRoots) { + SetBodyContent( + "<div id=host>" + "<template data-mode='open'>" + "<div>shadow_first</div>" + "<div>shadow_second</div>" + "</template>" + "</div>"); + Element* body = GetDocument().body(); + Element* host = body->getElementById("host"); + SelectionSample::ConvertTemplatesToShadowRootsForTesring( + *(ToHTMLElement(host))); + ShadowRoot* shadow_root = host->ShadowRootIfV1(); + ASSERT_TRUE(shadow_root->IsShadowRoot()); + EXPECT_EQ("<div>shadow_first</div><div>shadow_second</div>", + shadow_root->InnerHTMLAsString()); +} + +TEST_F(SelectionSampleTest, ConvertTemplatesToShadowRootsNoTemplates) { + SetBodyContent( + "<div id=host>" + "<div>first</div>" + "<div>second</div>" + "</div>"); + Element* body = GetDocument().body(); + Element* host = body->getElementById("host"); + SelectionSample::ConvertTemplatesToShadowRootsForTesring( + *(ToHTMLElement(host))); + EXPECT_FALSE(host->ShadowRootIfV1()); + EXPECT_EQ("<div>first</div><div>second</div>", host->InnerHTMLAsString()); +} + +TEST_F(SelectionSampleTest, ConvertTemplatesToShadowRootsMultipleTemplates) { + SetBodyContent( + "<div id=host1>" + "<template data-mode='open'>" + "<div>shadow_first</div>" + "<div>shadow_second</div>" + "</template>" + "</div>" + "<div id=host2>" + "<template data-mode='open'>" + "<div>shadow_third</div>" + "<div>shadow_forth</div>" + "</template>" + "</div>"); + Element* body = GetDocument().body(); + Element* host1 = body->getElementById("host1"); + Element* host2 = body->getElementById("host2"); + SelectionSample::ConvertTemplatesToShadowRootsForTesring( + *(ToHTMLElement(body))); + ShadowRoot* shadow_root_1 = host1->ShadowRootIfV1(); + ShadowRoot* shadow_root_2 = host2->ShadowRootIfV1(); + + EXPECT_TRUE(shadow_root_1->IsShadowRoot()); + EXPECT_EQ("<div>shadow_first</div><div>shadow_second</div>", + shadow_root_1->InnerHTMLAsString()); + EXPECT_TRUE(shadow_root_2->IsShadowRoot()); + EXPECT_EQ("<div>shadow_third</div><div>shadow_forth</div>", + shadow_root_2->InnerHTMLAsString()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLTemplateElement.h b/third_party/WebKit/Source/core/html/HTMLTemplateElement.h index 290822c3..829a7b7 100644 --- a/third_party/WebKit/Source/core/html/HTMLTemplateElement.h +++ b/third_party/WebKit/Source/core/html/HTMLTemplateElement.h
@@ -39,7 +39,7 @@ class DocumentFragment; class TemplateContentDocumentFragment; -class HTMLTemplateElement final : public HTMLElement { +class CORE_EXPORT HTMLTemplateElement final : public HTMLElement { DEFINE_WRAPPERTYPEINFO(); public:
diff --git a/third_party/WebKit/Source/core/layout/BUILD.gn b/third_party/WebKit/Source/core/layout/BUILD.gn index bdb064f..e04fb35 100644 --- a/third_party/WebKit/Source/core/layout/BUILD.gn +++ b/third_party/WebKit/Source/core/layout/BUILD.gn
@@ -232,6 +232,10 @@ "TableLayoutAlgorithmFixed.h", "TextAutosizer.cpp", "TextAutosizer.h", + "TextDecorationOffset.cpp", + "TextDecorationOffset.h", + "TextDecorationOffsetBase", + "TextDecorationOffsetBase.cpp", "TextRunConstructor.cpp", "TextRunConstructor.h", "TracedLayoutObject.cpp", @@ -297,6 +301,7 @@ "line/LineBreaker.h", "line/LineInfo.h", "line/LineLayoutState.h", + "line/LineVerticalPositionType.h", "line/LineWidth.cpp", "line/LineWidth.h", "line/RootInlineBox.cpp",
diff --git a/third_party/WebKit/Source/core/layout/TextDecorationOffset.cpp b/third_party/WebKit/Source/core/layout/TextDecorationOffset.cpp new file mode 100644 index 0000000..75fe76dd --- /dev/null +++ b/third_party/WebKit/Source/core/layout/TextDecorationOffset.cpp
@@ -0,0 +1,35 @@ +// Copyright 2014 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 "core/layout/TextDecorationOffset.h" +#include "core/layout/line/InlineTextBox.h" +#include "core/layout/line/RootInlineBox.h" +#include "platform/fonts/FontMetrics.h" + +namespace blink { + +int TextDecorationOffset::ComputeUnderlineOffsetForUnder( + float text_decoration_thickness, + LineVerticalPositionType position_type) { + const RootInlineBox& root = inline_text_box_->Root(); + FontBaseline baseline_type = root.BaselineType(); + LayoutUnit offset = inline_text_box_->OffsetTo(position_type, baseline_type); + + // Compute offset to the farthest position of the decorating box. + LayoutUnit logical_top = inline_text_box_->LogicalTop(); + LayoutUnit position = logical_top + offset; + LayoutUnit farthest = root.FarthestPositionForUnderline( + decorating_box_, position_type, baseline_type, position); + // Round() looks more logical but Floor() produces better results in + // positive/negative offsets, in horizontal/vertical flows, on Win/Mac/Linux. + int offset_int = (farthest - logical_top).Floor(); + + // Gaps are not needed for TextTop because it generally has internal + // leadings. + if (position_type == LineVerticalPositionType::TextTop) + return offset_int; + return !IsLineOverSide(position_type) ? offset_int + 1 : offset_int - 1; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/TextDecorationOffset.h b/third_party/WebKit/Source/core/layout/TextDecorationOffset.h new file mode 100644 index 0000000..ea115c4 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/TextDecorationOffset.h
@@ -0,0 +1,39 @@ +// Copyright 2014 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 TextDecorationOffset_h +#define TextDecorationOffset_h + +#include "core/CoreExport.h" +#include "core/layout/TextDecorationOffsetBase.h" +#include "core/layout/api/LineLayoutItem.h" + +namespace blink { + +class ComputedStyle; +class InlineTextBox; + +class CORE_EXPORT TextDecorationOffset : public TextDecorationOffsetBase { + STACK_ALLOCATED(); + + public: + TextDecorationOffset(const ComputedStyle& style, + const InlineTextBox* inline_text_box, + LineLayoutItem decorating_box) + : TextDecorationOffsetBase(style), + inline_text_box_(inline_text_box), + decorating_box_(decorating_box) {} + ~TextDecorationOffset() {} + + int ComputeUnderlineOffsetForUnder(float text_decoration_thickness, + LineVerticalPositionType) override; + + private: + const InlineTextBox* inline_text_box_; + LineLayoutItem decorating_box_; +}; + +} // namespace blink + +#endif // TextDecorationOffset_h
diff --git a/third_party/WebKit/Source/core/layout/TextDecorationOffsetBase.cpp b/third_party/WebKit/Source/core/layout/TextDecorationOffsetBase.cpp new file mode 100644 index 0000000..022e11a --- /dev/null +++ b/third_party/WebKit/Source/core/layout/TextDecorationOffsetBase.cpp
@@ -0,0 +1,54 @@ +// Copyright 2014 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 "core/layout/TextDecorationOffsetBase.h" +#include "core/layout/line/LineVerticalPositionType.h" +#include "core/paint/DecorationInfo.h" +#include "platform/fonts/FontMetrics.h" + +namespace blink { + +int TextDecorationOffsetBase::ComputeUnderlineOffsetForRoman( + const FontMetrics& font_metrics, + float text_decoration_thickness) { + // Compute the gap between the font and the underline. Use at least one + // pixel gap, if underline is thick then use a bigger gap. + int gap = 0; + + // Underline position of zero means draw underline on Baseline Position, + // in Blink we need at least 1-pixel gap to adding following check. + // Positive underline Position means underline should be drawn above baseline + // and negative value means drawing below baseline, negating the value as in + // Blink downward Y-increases. + + if (font_metrics.UnderlinePosition()) + gap = -font_metrics.UnderlinePosition(); + else + gap = std::max<int>(1, ceilf(text_decoration_thickness / 2.f)); + + // Position underline near the alphabetic baseline. + return font_metrics.Ascent() + gap; +} + +int TextDecorationOffsetBase::ComputeUnderlineOffset( + ResolvedUnderlinePosition underline_position, + const FontMetrics& font_metrics, + float text_decoration_thickness) { + switch (underline_position) { + default: + NOTREACHED(); + // Fall through. + case ResolvedUnderlinePosition::kRoman: + return ComputeUnderlineOffsetForRoman(font_metrics, + text_decoration_thickness); + case ResolvedUnderlinePosition::kUnder: + // Position underline at the under edge of the lowest element's + // content box. + return ComputeUnderlineOffsetForUnder( + text_decoration_thickness, + LineVerticalPositionType::BottomOfEmHeight); + } +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/TextDecorationOffsetBase.h b/third_party/WebKit/Source/core/layout/TextDecorationOffsetBase.h new file mode 100644 index 0000000..9c046b03 --- /dev/null +++ b/third_party/WebKit/Source/core/layout/TextDecorationOffsetBase.h
@@ -0,0 +1,42 @@ +// Copyright 2014 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 TextDecorationOffsetBase_h +#define TextDecorationOffsetBase_h + +#include "core/CoreExport.h" +#include "platform/LayoutUnit.h" +#include "platform/fonts/FontBaseline.h" + +namespace blink { + +class ComputedStyle; +enum class LineVerticalPositionType; +enum class ResolvedUnderlinePosition; +class FontMetrics; + +class CORE_EXPORT TextDecorationOffsetBase { + STACK_ALLOCATED(); + + public: + TextDecorationOffsetBase(const ComputedStyle& style) : style_(style) {} + ~TextDecorationOffsetBase() {} + + virtual int ComputeUnderlineOffsetForUnder(float text_decoration_thickness, + LineVerticalPositionType) = 0; + + int ComputeUnderlineOffsetForRoman(const FontMetrics&, + float text_decoration_thickness); + + int ComputeUnderlineOffset(ResolvedUnderlinePosition, + const FontMetrics&, + float text_decoration_thickness); + + protected: + const ComputedStyle& style_; +}; + +} // namespace blink + +#endif // TextDecorationOffsetBase_h
diff --git a/third_party/WebKit/Source/core/layout/line/InlineBox.h b/third_party/WebKit/Source/core/layout/line/InlineBox.h index 25933ee..66e8e1af 100644 --- a/third_party/WebKit/Source/core/layout/line/InlineBox.h +++ b/third_party/WebKit/Source/core/layout/line/InlineBox.h
@@ -26,6 +26,7 @@ #include "core/layout/api/LineLayoutBoxModel.h" #include "core/layout/api/LineLayoutItem.h" #include "core/layout/api/SelectionState.h" +#include "core/layout/line/LineVerticalPositionType.h" #include "platform/graphics/paint/DisplayItemClient.h" #include "platform/text/TextDirection.h" @@ -39,19 +40,6 @@ enum MarkLineBoxes { kMarkLineBoxesDirty, kDontMarkLineBoxes }; -enum class LineVerticalPositionType { - // TextTop and TextBottom are the top/bottom of the content area. - // This is where 'vertical-align: text-top/text-bottom' aligns to. - // This is explicitly undefined in CSS2. - // https://drafts.csswg.org/css2/visudet.html#inline-non-replaced - TextTop, - TextBottom, - // Em height as being discussed in Font Metrics API. - // https://drafts.css-houdini.org/font-metrics-api-1/#fontmetrics - TopOfEmHeight, - BottomOfEmHeight -}; - // Returns whether the position type is CSS "line-over"; i.e., ascender side // or "top" side of a line box. // https://drafts.csswg.org/css-writing-modes-3/#line-over
diff --git a/third_party/WebKit/Source/core/layout/line/LineVerticalPositionType.h b/third_party/WebKit/Source/core/layout/line/LineVerticalPositionType.h new file mode 100644 index 0000000..c03c77b --- /dev/null +++ b/third_party/WebKit/Source/core/layout/line/LineVerticalPositionType.h
@@ -0,0 +1,25 @@ +// Copyright 2014 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 LineVerticalPositionType_h +#define LineVerticalPositionType_h + +namespace blink { + +enum class LineVerticalPositionType { + // TextTop and TextBottom are the top/bottom of the content area. + // This is where 'vertical-align: text-top/text-bottom' aligns to. + // This is explicitly undefined in CSS2. + // https://drafts.csswg.org/css2/visudet.html#inline-non-replaced + TextTop, + TextBottom, + // Em height as being discussed in Font Metrics API. + // https://drafts.css-houdini.org/font-metrics-api-1/#fontmetrics + TopOfEmHeight, + BottomOfEmHeight +}; + +} // namespace blink + +#endif // LineVerticalPositionType_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc index 7b3d02a..2abf2d8 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -308,7 +308,13 @@ HandleFloat(previous_inflow_position, ToNGBlockNode(child), ToNGBlockBreakToken(child_break_token)); } else { - if (!HandleInflow(child, child_break_token, &previous_inflow_position)) { + bool success = child.CreatesNewFormattingContext() + ? HandleNewFormattingContext(child, child_break_token, + &previous_inflow_position) + : HandleInflow(child, child_break_token, + &previous_inflow_position); + + if (!success) { // We need to abort the layout, as our BFC offset was resolved. container_builder_.SwapUnpositionedFloats(&unpositioned_floats_); return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved); @@ -475,6 +481,154 @@ } } +bool NGBlockLayoutAlgorithm::HandleNewFormattingContext( + NGLayoutInputNode child, + NGBreakToken* child_break_token, + NGPreviousInflowPosition* previous_inflow_position) { + DCHECK(child); + DCHECK(!child.IsFloating()); + DCHECK(!child.IsOutOfFlowPositioned()); + DCHECK(child.CreatesNewFormattingContext()); + + const ComputedStyle& child_style = child.Style(); + const EClear child_clear = child_style.Clear(); + const TextDirection direction = ConstraintSpace().Direction(); + + // Perform layout on the child. + NGInflowChildData child_data = + ComputeChildData(*previous_inflow_position, child, child_break_token); + RefPtr<NGConstraintSpace> child_space = + CreateConstraintSpaceForChild(child, child_data); + RefPtr<NGLayoutResult> layout_result = + child.Layout(*child_space, child_break_token); + + // We must have an actual fragment at this stage. + DCHECK(layout_result->PhysicalFragment()); + const auto& physical_fragment = *layout_result->PhysicalFragment(); + NGFragment fragment(ConstraintSpace().WritingMode(), physical_fragment); + + LayoutUnit child_bfc_offset_estimate = + child_data.bfc_offset_estimate.block_offset; + + // 1. Position all pending floats to a temporary space, which is a copy of + // the current exclusion space. + NGExclusionSpace tmp_exclusion_space(*exclusion_space_); + PositionFloats(child_bfc_offset_estimate, child_bfc_offset_estimate, + unpositioned_floats_, ConstraintSpace(), + container_builder_.Size().inline_size, &tmp_exclusion_space); + + NGBfcOffset origin_offset = { + ConstraintSpace().BfcOffset().line_offset + + border_scrollbar_padding_.LineLeft(direction) + + child_data.margins.LineLeft(direction), + child_bfc_offset_estimate}; + AdjustToClearance(tmp_exclusion_space.ClearanceOffset(child_clear), + &origin_offset); + + // 2. Find an estimated layout opportunity for our fragment. + NGLogicalSize fragment_size(fragment.InlineSize(), fragment.BlockSize()); + + // TODO(ikilpatrick): child_space.AvailableSize() is probably wrong as the + // area we need to search shrinks by the origin_offset and LineRight margin. + NGLayoutOpportunity opportunity = tmp_exclusion_space.FindLayoutOpportunity( + origin_offset, child_space->AvailableSize(), fragment_size); + + NGMarginStrut margin_strut = previous_inflow_position->margin_strut; + + // 3. If the found opportunity lies on the same line with our estimated + // child's BFC offset then merge fragment's margins with the current + // MarginStrut. + if (opportunity.offset.block_offset == child_bfc_offset_estimate) + margin_strut.Append(child_data.margins.block_start, + child_style.HasMarginBeforeQuirk()); + child_bfc_offset_estimate += margin_strut.Sum(); + + // 4. The child's BFC block offset is known here. + bool updated = MaybeUpdateFragmentBfcOffset( + ConstraintSpace(), child_bfc_offset_estimate, &container_builder_); + + if (updated && abort_when_bfc_resolved_) + return false; + + PositionPendingFloats(ConstraintSpace(), child_bfc_offset_estimate, + &container_builder_, &unpositioned_floats_, + exclusion_space_.get()); + + origin_offset = {ConstraintSpace().BfcOffset().line_offset + + border_scrollbar_padding_.LineLeft(direction) + + child_data.margins.LineLeft(direction), + child_bfc_offset_estimate}; + AdjustToClearance(exclusion_space_->ClearanceOffset(child_clear), + &origin_offset); + + // 5. Find the final layout opportunity for the fragment after all pending + // floats are positioned at the correct BFC block's offset. + // TODO(ikilpatrick): child_space.AvailableSize() is probably wrong as the + // area we need to search shrinks by the origin_offset and LineRight margin. + opportunity = exclusion_space_->FindLayoutOpportunity( + origin_offset, child_space->AvailableSize(), fragment_size); + + // Auto-margins are applied within the layout opportunity which fits. + // TODO(ikilpatrick): Some of these calculations should be pulled into + // ApplyAutoMargins. + NGBoxStrut margins(child_data.margins); + ApplyAutoMargins(child_style, opportunity.InlineSize(), fragment.InlineSize(), + &margins); + margins.inline_end = + opportunity.InlineSize() - margins.inline_start - fragment.InlineSize(); + + bool is_ltr = direction == TextDirection::kLtr; + bool is_line_left_auto_margin = + (is_ltr && child_style.MarginStart().IsAuto()) || + (!is_ltr && child_style.MarginEnd().IsAuto()); + + LayoutUnit line_left_auto_margin = + is_line_left_auto_margin ? margins.LineLeft(direction) : LayoutUnit(); + + // We try and position the child within the block formatting context. This + // may cause our BFC offset to be resolved, in which case we should abort our + // layout if needed. + NGBfcOffset child_bfc_offset( + opportunity.offset.line_offset + line_left_auto_margin, + opportunity.offset.block_offset); + + NGLogicalOffset logical_offset = + CalculateLogicalOffset(fragment, child_data.margins, child_bfc_offset); + + if (ConstraintSpace().HasBlockFragmentation() && + ShouldBreakBeforeChild(child, physical_fragment, + logical_offset.block_offset)) { + // TODO(mstensho): Make sure that we're at a valid point [1] before + // breaking. It's not allowed to break between the content edge of a + // container and its first child, if they are adjacent. If we're not allowed + // to break here, we need to attempt to propagate the break further up the + // ancestry. + // + // [1] https://drafts.csswg.org/css-break/#possible-breaks + + // The remaining part of the fragmentainer (the unusable space for child + // content, due to the break) should still be occupied by this container. + content_size_ = FragmentainerSpaceAvailable(); + // Drop the fragment on the floor and retry at the start of the next + // fragmentainer. + container_builder_.AddBreakBeforeChild(child); + container_builder_.SetDidBreak(); + return true; + } + + UpdateContentSize(child_data.margins, logical_offset, + /* is_empty_block */ false, fragment); + + container_builder_.AddChild(layout_result, logical_offset); + container_builder_.PropagateBreak(layout_result); + + *previous_inflow_position = ComputeInflowPosition( + *previous_inflow_position, child, child_data, child_bfc_offset, + logical_offset, *layout_result, fragment, + /* empty_block_affected_by_clearance */ false); + return true; +} + bool NGBlockLayoutAlgorithm::HandleInflow( NGLayoutInputNode child, NGBreakToken* child_break_token, @@ -483,14 +637,12 @@ DCHECK(!child.IsFloating()); DCHECK(!child.IsOutOfFlowPositioned()); - bool is_new_fc = child.CreatesNewFormattingContext(); - // TODO(ikilpatrick): We may only want to position pending floats if there is // something that we *might* clear in the unpositioned list. E.g. we may // clear an already placed left float, but the unpositioned list may only have // right floats. bool should_position_pending_floats = - !is_new_fc && child.IsBlock() && + child.IsBlock() && ClearanceMayAffectLayout(*exclusion_space_, unpositioned_floats_, child.Style()); @@ -540,6 +692,8 @@ RefPtr<NGLayoutResult> layout_result = child.Layout(*child_space, child_break_token); + bool is_empty_block = IsEmptyBlock(child, *layout_result); + // If we don't know our BFC offset yet, we need to copy the list of // unpositioned floats from the child's layout result. // @@ -551,7 +705,7 @@ // // TODO(ikilpatrick): a more optimal version of this is to set // abort_when_bfc_resolved_, if the child tree _added_ any floats. - if (!container_builder_.BfcOffset() && !is_new_fc) { + if (!container_builder_.BfcOffset()) { unpositioned_floats_ = layout_result->UnpositionedFloats(); abort_when_bfc_resolved_ |= !layout_result->UnpositionedFloats().IsEmpty(); if (child_space->FloatsBfcOffset()) @@ -563,8 +717,6 @@ // to our parent. if (layout_result->Status() == NGLayoutResult::kBfcOffsetResolved && !container_builder_.BfcOffset()) { - DCHECK(!is_new_fc); - MaybeUpdateFragmentBfcOffset( ConstraintSpace(), layout_result->BfcOffset().value().block_offset, &container_builder_); @@ -582,7 +734,7 @@ // // The exclusion space is then updated when the child undergoes relayout // below. - if (layout_result->Status() == NGLayoutResult::kSuccess && !is_new_fc) { + if (layout_result->Status() == NGLayoutResult::kSuccess) { DCHECK(layout_result->ExclusionSpace()); exclusion_space_ = WTF::MakeUnique<NGExclusionSpace>(*layout_result->ExclusionSpace()); @@ -596,11 +748,7 @@ // may cause our BFC offset to be resolved, in which case we should abort our // layout if needed. WTF::Optional<NGBfcOffset> child_bfc_offset; - if (is_new_fc) { - if (!PositionNewFc(child, *previous_inflow_position, *layout_result, - child_data, *child_space, &child_bfc_offset)) - return false; - } else if (layout_result->BfcOffset()) { + if (layout_result->BfcOffset()) { if (!PositionWithBfcOffset(layout_result->BfcOffset().value(), &child_bfc_offset)) return false; @@ -609,7 +757,7 @@ PositionWithParentBfc(child, *child_space, child_data, *layout_result, &empty_block_affected_by_clearance); } else - DCHECK(IsEmptyBlock(child, *layout_result)); + DCHECK(is_empty_block); // We need to re-layout a child if it was affected by clearance in order to // produce a new margin strut. For example: @@ -655,7 +803,6 @@ DCHECK_EQ(layout_result->Status(), NGLayoutResult::kSuccess); - DCHECK(!is_new_fc); DCHECK(layout_result->ExclusionSpace()); exclusion_space_ = WTF::MakeUnique<NGExclusionSpace>(*layout_result->ExclusionSpace()); @@ -690,22 +837,8 @@ return true; } - // Only modify content_size_ if the fragment is non-empty block. - // - // Empty blocks don't immediately contribute to our size, instead we wait to - // see what the final margin produced, e.g. - // <div style="display: flow-root"> - // <div style="margin-top: -8px"></div> - // <div style="margin-top: 10px"></div> - // </div> - if (!IsEmptyBlock(child, *layout_result)) { - DCHECK(container_builder_.BfcOffset()); - content_size_ = std::max( - content_size_, logical_offset.block_offset + fragment.BlockSize()); - } - max_inline_size_ = std::max( - max_inline_size_, fragment.InlineSize() + child_data.margins.InlineSum() + - border_scrollbar_padding_.InlineSum()); + UpdateContentSize(child_data.margins, logical_offset, is_empty_block, + fragment); container_builder_.AddChild(layout_result, logical_offset); container_builder_.PropagateBreak(layout_result); @@ -816,106 +949,6 @@ empty_or_sibling_empty_affected_by_clearance}; } -bool NGBlockLayoutAlgorithm::PositionNewFc( - const NGLayoutInputNode& child, - const NGPreviousInflowPosition& previous_inflow_position, - const NGLayoutResult& layout_result, - const NGInflowChildData& child_data, - const NGConstraintSpace& child_space, - WTF::Optional<NGBfcOffset>* child_bfc_offset) { - const ComputedStyle& child_style = child.Style(); - const EClear child_clear = child_style.Clear(); - const TextDirection direction = ConstraintSpace().Direction(); - - DCHECK(layout_result.PhysicalFragment()); - NGFragment fragment(ConstraintSpace().WritingMode(), - *layout_result.PhysicalFragment()); - - LayoutUnit child_bfc_offset_estimate = - child_data.bfc_offset_estimate.block_offset; - - // 1. Position all pending floats to a temporary space, which is a copy of - // the current exclusion space. - NGExclusionSpace tmp_exclusion_space(*exclusion_space_); - PositionFloats(child_bfc_offset_estimate, child_bfc_offset_estimate, - unpositioned_floats_, ConstraintSpace(), - container_builder_.Size().inline_size, &tmp_exclusion_space); - - NGBfcOffset origin_offset = { - ConstraintSpace().BfcOffset().line_offset + - border_scrollbar_padding_.LineLeft(direction) + - child_data.margins.LineLeft(direction), - child_bfc_offset_estimate}; - AdjustToClearance(tmp_exclusion_space.ClearanceOffset(child_clear), - &origin_offset); - - // 2. Find an estimated layout opportunity for our fragment. - NGLogicalSize fragment_size(fragment.InlineSize(), fragment.BlockSize()); - - // TODO(ikilpatrick): child_space.AvailableSize() is probably wrong as the - // area we need to search shrinks by the origin_offset and LineRight margin. - NGLayoutOpportunity opportunity = tmp_exclusion_space.FindLayoutOpportunity( - origin_offset, child_space.AvailableSize(), fragment_size); - - NGMarginStrut margin_strut = previous_inflow_position.margin_strut; - - // 3. If the found opportunity lies on the same line with our estimated - // child's BFC offset then merge fragment's margins with the current - // MarginStrut. - if (opportunity.offset.block_offset == child_bfc_offset_estimate) - margin_strut.Append(child_data.margins.block_start, - child_style.HasMarginBeforeQuirk()); - child_bfc_offset_estimate += margin_strut.Sum(); - - // 4. The child's BFC block offset is known here. - bool updated = MaybeUpdateFragmentBfcOffset( - ConstraintSpace(), child_bfc_offset_estimate, &container_builder_); - - if (updated && abort_when_bfc_resolved_) - return false; - - PositionPendingFloats(ConstraintSpace(), child_bfc_offset_estimate, - &container_builder_, &unpositioned_floats_, - exclusion_space_.get()); - - origin_offset = {ConstraintSpace().BfcOffset().line_offset + - border_scrollbar_padding_.LineLeft(direction) + - child_data.margins.LineLeft(direction), - child_bfc_offset_estimate}; - AdjustToClearance(exclusion_space_->ClearanceOffset(child_clear), - &origin_offset); - - // 5. Find the final layout opportunity for the fragment after all pending - // floats are positioned at the correct BFC block's offset. - // TODO(ikilpatrick): child_space.AvailableSize() is probably wrong as the - // area we need to search shrinks by the origin_offset and LineRight margin. - opportunity = exclusion_space_->FindLayoutOpportunity( - origin_offset, child_space.AvailableSize(), fragment_size); - - // Auto-margins are applied within the layout opportunity which fits. - // TODO(ikilpatrick): Some of these calculations should be pulled into - // ApplyAutoMargins. - NGBoxStrut margins(child_data.margins); - ApplyAutoMargins(child_style, opportunity.InlineSize(), fragment.InlineSize(), - &margins); - margins.inline_end = - opportunity.InlineSize() - margins.inline_start - fragment.InlineSize(); - - bool is_ltr = direction == TextDirection::kLtr; - bool is_line_left_auto_margin = - (is_ltr && child_style.MarginStart().IsAuto()) || - (!is_ltr && child_style.MarginEnd().IsAuto()); - - LayoutUnit line_left_auto_margin = - is_line_left_auto_margin ? margins.LineLeft(direction) : LayoutUnit(); - - *child_bfc_offset = - NGBfcOffset{opportunity.offset.line_offset + line_left_auto_margin, - opportunity.offset.block_offset}; - - return true; -} - bool NGBlockLayoutAlgorithm::PositionWithBfcOffset( const NGBfcOffset& bfc_offset, WTF::Optional<NGBfcOffset>* child_bfc_offset) { @@ -1194,4 +1227,29 @@ } } +// TODO(ikilpatrick): Remove/simplify this to just calculate/update +// content_size_ as max_inline_size_ is not currently used. +void NGBlockLayoutAlgorithm::UpdateContentSize( + const NGBoxStrut& margins, + const NGLogicalOffset& logical_offset, + bool is_empty_block, + const NGFragment& fragment) { + // Only modify content_size_ if the fragment is non-empty block. + // + // Empty blocks don't immediately contribute to our size, instead we wait to + // see what the final margin produced, e.g. + // <div style="display: flow-root"> + // <div style="margin-top: -8px"></div> + // <div style="margin-top: 10px"></div> + // </div> + if (!is_empty_block) { + DCHECK(container_builder_.BfcOffset()); + content_size_ = std::max( + content_size_, logical_offset.block_offset + fragment.BlockSize()); + } + max_inline_size_ = + std::max(max_inline_size_, fragment.InlineSize() + margins.InlineSum() + + border_scrollbar_padding_.InlineSum()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h index 4c58839..e9629326 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
@@ -91,31 +91,6 @@ const NGFragment& fragment, bool empty_block_affected_by_clearance); - // Positions the fragment that establishes a new formatting context. - // - // This uses Layout Opportunity iterator to position the fragment. - // That's because an element that establishes a new block formatting context - // must not overlap the margin box of any floats in the same block formatting - // context as the element itself. - // - // So if necessary, we clear the new BFC by placing it below any preceding - // floats or place it adjacent to such floats if there is sufficient space. - // - // Example: - // <div id="container"> - // <div id="float"></div> - // <div id="new-fc" style="margin-top: 20px;"></div> - // </div> - // 1) If #new-fc is small enough to fit the available space right from #float - // then it will be placed there and we collapse its margin. - // 2) If #new-fc is too big then we need to clear its position and place it - // below #float ignoring its vertical margin. - bool PositionNewFc(const NGLayoutInputNode& child, - const NGPreviousInflowPosition&, - const NGLayoutResult&, - const NGInflowChildData& child_data, - const NGConstraintSpace& child_space, - WTF::Optional<NGBfcOffset>* child_bfc_offset); // Positions the fragment that knows its BFC offset. WTF::Optional<NGBfcOffset> PositionWithBfcOffset( @@ -141,9 +116,30 @@ NGBlockNode, NGBlockBreakToken*); - // Handle an in-flow child. Returns true if everything went smoothly and we - // can continue to the next sibling. Returns false if we need to abort, - // because a previously unknown BFC offset now has been resolved. + // This uses the NGLayoutOpporunityIterator to position the fragment. + // + // An element that establishes a new formatting context must not overlap the + // margin box of any floats within the current BFC. + // + // Example: + // <div id="container"> + // <div id="float"></div> + // <div id="new-fc" style="margin-top: 20px;"></div> + // </div> + // 1) If #new-fc is small enough to fit the available space right from #float + // then it will be placed there and we collapse its margin. + // 2) If #new-fc is too big then we need to clear its position and place it + // below #float ignoring its vertical margin. + // + // Returns false if we need to abort layout, because a previously unknown BFC + // offset has now been resolved. + bool HandleNewFormattingContext(NGLayoutInputNode child, + NGBreakToken* child_break_token, + NGPreviousInflowPosition*); + + // Handle an in-flow child. + // Returns false if we need to abort layout, because a previously unknown BFC + // offset has now been resolved. (Same as HandleNewFormattingContext). bool HandleInflow(NGLayoutInputNode child, NGBreakToken* child_break_token, NGPreviousInflowPosition*); @@ -172,6 +168,11 @@ const NGPhysicalFragment*, LayoutUnit child_offset); + void UpdateContentSize(const NGBoxStrut& margins, + const NGLogicalOffset& logical_offset, + bool is_empty_block, + const NGFragment&); + // Calculates logical offset for the current fragment using either // {@code content_size_} when the fragment doesn't know it's offset // or {@code known_fragment_offset} if the fragment knows it's offset
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp index eecf24d..7b898eab 100644 --- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
@@ -12,6 +12,7 @@ #include "core/frame/LocalFrame.h" #include "core/layout/LayoutTextCombine.h" #include "core/layout/LayoutTheme.h" +#include "core/layout/TextDecorationOffset.h" #include "core/layout/api/LineLayoutAPIShim.h" #include "core/layout/api/LineLayoutBox.h" #include "core/layout/line/InlineTextBox.h" @@ -75,76 +76,6 @@ } } -static int ComputeUnderlineOffsetForUnder( - const ComputedStyle& style, - const InlineTextBox* inline_text_box, - LineLayoutItem decorating_box, - float text_decoration_thickness, - LineVerticalPositionType position_type) { - const RootInlineBox& root = inline_text_box->Root(); - FontBaseline baseline_type = root.BaselineType(); - LayoutUnit offset = inline_text_box->OffsetTo(position_type, baseline_type); - - // Compute offset to the farthest position of the decorating box. - LayoutUnit logical_top = inline_text_box->LogicalTop(); - LayoutUnit position = logical_top + offset; - LayoutUnit farthest = root.FarthestPositionForUnderline( - decorating_box, position_type, baseline_type, position); - // Round() looks more logical but Floor() produces better results in - // positive/negative offsets, in horizontal/vertical flows, on Win/Mac/Linux. - int offset_int = (farthest - logical_top).Floor(); - - // Gaps are not needed for TextTop because it generally has internal - // leadings. - if (position_type == LineVerticalPositionType::TextTop) - return offset_int; - return !IsLineOverSide(position_type) ? offset_int + 1 : offset_int - 1; -} - -static int ComputeUnderlineOffsetForRoman( - const FontMetrics& font_metrics, - const float text_decoration_thickness) { - // Compute the gap between the font and the underline. Use at least one - // pixel gap, if underline is thick then use a bigger gap. - int gap = 0; - - // Underline position of zero means draw underline on Baseline Position, - // in Blink we need at least 1-pixel gap to adding following check. - // Positive underline Position means underline should be drawn above baseline - // and negative value means drawing below baseline, negating the value as in - // Blink downward Y-increases. - - if (font_metrics.UnderlinePosition()) - gap = -font_metrics.UnderlinePosition(); - else - gap = std::max<int>(1, ceilf(text_decoration_thickness / 2.f)); - - // Position underline near the alphabetic baseline. - return font_metrics.Ascent() + gap; -} - -static int ComputeUnderlineOffset(ResolvedUnderlinePosition underline_position, - const ComputedStyle& style, - const FontMetrics& font_metrics, - const InlineTextBox* inline_text_box, - LineLayoutItem decorating_box, - const float text_decoration_thickness) { - switch (underline_position) { - default: - NOTREACHED(); - // Fall through. - case ResolvedUnderlinePosition::kRoman: - return ComputeUnderlineOffsetForRoman(font_metrics, - text_decoration_thickness); - case ResolvedUnderlinePosition::kUnder: - // Position underline at the under edge of the lowest element's - // content box. - return ComputeUnderlineOffsetForUnder( - style, inline_text_box, decorating_box, text_decoration_thickness, - LineVerticalPositionType::BottomOfEmHeight); - } -} - static const int kMisspellingLineThickness = 3; LayoutObject& InlineTextBoxPainter::InlineLayoutObject() const { @@ -222,28 +153,29 @@ underline_position = ResolvedUnderlinePosition::kUnder; } + TextDecorationOffset decoration_offset(*decoration_info.style, &box, + decorating_box); for (const AppliedTextDecoration& decoration : decorations) { TextDecoration lines = decoration.Lines(); bool has_underline = EnumHasFlags(lines, TextDecoration::kUnderline); bool has_overline = EnumHasFlags(lines, TextDecoration::kOverline); - if (flip_underline_and_overline) { + if (flip_underline_and_overline) std::swap(has_underline, has_overline); - } if (has_underline && decoration_info.font_data) { - const int underline_offset = ComputeUnderlineOffset( - underline_position, *decoration_info.style, - decoration_info.font_data->GetFontMetrics(), &box, decorating_box, + const int underline_offset = decoration_offset.ComputeUnderlineOffset( + underline_position, decoration_info.font_data->GetFontMetrics(), decoration_info.thickness); text_painter.PaintDecorationUnderOrOverLine( context, decoration_info, decoration, underline_offset, decoration_info.double_offset); } if (has_overline) { - const int overline_offset = ComputeUnderlineOffsetForUnder( - *decoration_info.style, &box, decorating_box, - decoration_info.thickness, - flip_underline_and_overline ? LineVerticalPositionType::TopOfEmHeight - : LineVerticalPositionType::TextTop); + const int overline_offset = + decoration_offset.ComputeUnderlineOffsetForUnder( + decoration_info.thickness, + flip_underline_and_overline + ? LineVerticalPositionType::TopOfEmHeight + : LineVerticalPositionType::TextTop); text_painter.PaintDecorationUnderOrOverLine( context, decoration_info, decoration, overline_offset, -decoration_info.double_offset);
diff --git a/third_party/WebKit/Source/platform/exported/WebCORSPreflightResultCache.cpp b/third_party/WebKit/Source/platform/exported/WebCORSPreflightResultCache.cpp index 515250c..43d894c 100644 --- a/third_party/WebKit/Source/platform/exported/WebCORSPreflightResultCache.cpp +++ b/third_party/WebKit/Source/platform/exported/WebCORSPreflightResultCache.cpp
@@ -167,7 +167,11 @@ const WebString& method, WebString& error_description) const { if (methods_.find(method.Ascii().data()) != methods_.end() || - FetchUtils::IsCORSSafelistedMethod(method)) + FetchUtils::IsCORSSafelistedMethod(method)) { + return true; + } + + if (!credentials_ && methods_.find("*") != methods_.end()) return true; error_description.Assign(WebString::FromASCII("Method " + method.Ascii() +
diff --git a/third_party/WebKit/Source/platform/wtf/RefPtr.h b/third_party/WebKit/Source/platform/wtf/RefPtr.h index 214619a5..b635862 100644 --- a/third_party/WebKit/Source/platform/wtf/RefPtr.h +++ b/third_party/WebKit/Source/platform/wtf/RefPtr.h
@@ -82,15 +82,6 @@ RefPtr(RefPtr<U>&& o, EnsurePtrConvertibleArgDecl(U, T)) : ptr_(o.LeakRef()) {} - // Hash table deleted values, which are only constructed and never copied or - // destroyed. - // TODO(tzik): Remove this after updating callsites of this to use - // HashTraits<RefPtr<>>::{ConstructDeletedValue,IsHashTableDeletedValue}. - RefPtr(HashTableDeletedValueType) : ptr_(HashTableDeletedValue()) {} - bool IsHashTableDeletedValue() const { - return ptr_ == HashTableDeletedValue(); - } - ALWAYS_INLINE ~RefPtr() { DerefIfNotNull(ptr_); } ALWAYS_INLINE T* Get() const { return ptr_; } @@ -118,8 +109,6 @@ void Swap(RefPtr&); - static T* HashTableDeletedValue() { return reinterpret_cast<T*>(-1); } - private: friend RefPtr AdoptRef<T>(T*);
diff --git a/third_party/WebKit/Source/platform/wtf/text/AtomicString.h b/third_party/WebKit/Source/platform/wtf/text/AtomicString.h index 7b2069b..235430e 100644 --- a/third_party/WebKit/Source/platform/wtf/text/AtomicString.h +++ b/third_party/WebKit/Source/platform/wtf/text/AtomicString.h
@@ -78,16 +78,6 @@ explicit AtomicString(StringImpl* impl) : string_(Add(impl)) {} explicit AtomicString(const String& s) : string_(Add(s.Impl())) {} - // Hash table deleted values, which are only constructed and never copied or - // destroyed. - // TODO(tzik): Remove this after updating callsites of this to use - // HashTraits<AtomicString>::{ConstructDeletedValue,IsHashTableDeletedValue}. - AtomicString(WTF::HashTableDeletedValueType) - : string_(WTF::kHashTableDeletedValue) {} - bool IsHashTableDeletedValue() const { - return string_.IsHashTableDeletedValue(); - } - explicit operator bool() const { return !IsNull(); } operator const String&() const { return string_; } const String& GetString() const { return string_; }
diff --git a/third_party/WebKit/Source/platform/wtf/text/WTFString.h b/third_party/WebKit/Source/platform/wtf/text/WTFString.h index b7918c71..949075a 100644 --- a/third_party/WebKit/Source/platform/wtf/text/WTFString.h +++ b/third_party/WebKit/Source/platform/wtf/text/WTFString.h
@@ -496,15 +496,6 @@ return impl_ ? impl_->CharactersSizeInBytes() : 0; } - // Hash table deleted values, which are only constructed and never copied or - // destroyed. - // TODO(tzik): Remove this after updating callsites of this to use - // HashTraits<String>::{ConstructDeletedValue,IsHashTableDeletedValue}. - String(WTF::HashTableDeletedValueType) : impl_(WTF::kHashTableDeletedValue) {} - bool IsHashTableDeletedValue() const { - return impl_.IsHashTableDeletedValue(); - } - #ifndef NDEBUG // For use in the debugger. void Show() const;
diff --git a/third_party/WebKit/public/platform/WebCORSPreflightResultCache.h b/third_party/WebKit/public/platform/WebCORSPreflightResultCache.h index c1b1042..06d69d5 100644 --- a/third_party/WebKit/public/platform/WebCORSPreflightResultCache.h +++ b/third_party/WebKit/public/platform/WebCORSPreflightResultCache.h
@@ -51,7 +51,7 @@ const WebHTTPHeaderMap&, WebString& error_description); - bool AllowsCrossOriginMethod(const WebString&, + bool AllowsCrossOriginMethod(const WebString& method, WebString& error_description) const; bool AllowsCrossOriginHeaders(const WebHTTPHeaderMap&, WebString& error_description) const;
diff --git a/tools/gn/format_test_data/062.gn b/tools/gn/format_test_data/062.gn index d7fbb3c..8c4cc7d 100644 --- a/tools/gn/format_test_data/062.gn +++ b/tools/gn/format_test_data/062.gn
@@ -110,3 +110,13 @@ "srtp/crypto/rng/prng.c", "srtp/crypto/rng/rand_source.c", ] + +# Try "public" too. It should be treated the same. +public = [ + # Let's sort + "this", "into", "word", "salad", + + # But leave + "these", "two" + # alone! +]
diff --git a/tools/gn/format_test_data/062.golden b/tools/gn/format_test_data/062.golden index e939e449..b5545101 100644 --- a/tools/gn/format_test_data/062.golden +++ b/tools/gn/format_test_data/062.golden
@@ -115,3 +115,18 @@ "srtp/srtp/ekt.c", "srtp/srtp/srtp.c", ] + +# Try "public" too. It should be treated the same. +public = [ + # Let's sort + "into", + "salad", + "this", + "word", + + # But leave + "these", + "two", + + # alone! +]
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 4dc6878..8641f36 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -11850,7 +11850,7 @@ </enum> <enum name="ExtensionEvents"> -<!-- Generated from extensions/browser/extension_event_histogram_value.h.--> +<!-- Generated from extensions/browser/extension_event_histogram_value.h --> <int value="0" label="UNKNOWN"/> <int value="1" label="FOR_TEST"/> @@ -12293,7 +12293,7 @@ </enum> <enum name="ExtensionFunctions"> -<!-- Generated from extensions/browser/extension_function_histogram_value.h.--> +<!-- Generated from extensions/browser/extension_function_histogram_value.h --> <int value="0" label="UNKNOWN"/> <int value="1" label="WEBNAVIGATION_GETALLFRAMES"/> @@ -12800,9 +12800,9 @@ <int value="500" label="DELETED_WEBVIEW_STOP"/> <int value="501" label="DELETED_WEBVIEW_RELOAD"/> <int value="502" label="DELETED_WEBVIEW_TERMINATE"/> - <int value="503" label="DELETED_TYPES_PRIVATE_CHROMEDIRECTSETTING_GET"/> - <int value="504" label="DELETED_TYPES_PRIVATE_CHROMEDIRECTSETTING_SET"/> - <int value="505" label="DELETED_TYPES_PRIVATE_CHROMEDIRECTSETTING_CLEAR"/> + <int value="503" label="TYPES_PRIVATE_CHROMEDIRECTSETTING_GET"/> + <int value="504" label="TYPES_PRIVATE_CHROMEDIRECTSETTING_SET"/> + <int value="505" label="TYPES_PRIVATE_CHROMEDIRECTSETTING_CLEAR"/> <int value="506" label="DELETED_EXPERIMENTAL_SYSTEMINFO_STORAGE_EJECTDEVICE"/> <int value="507" label="SYSTEM_CPU_GETINFO"/> <int value="508" label="BOOKMARKMANAGERPRIVATE_REMOVETREES"/> @@ -13520,6 +13520,7 @@ <int value="1193" label="NETWORKINGPRIVATE_SELECTCELLULARMOBILENETWORK"/> <int value="1194" label="PASSWORDSPRIVATE_IMPORTPASSWORDS"/> <int value="1195" label="PASSWORDSPRIVATE_EXPORTPASSWORDS"/> + <int value="1196" label="LANGUAGESETTINGSPRIVATE_SETTRANSLATEFORLANGUAGE"/> </enum> <enum name="ExtensionIconState"> @@ -24102,6 +24103,7 @@ <int value="862453793" label="TranslateUI2016Q2:enabled"/> <int value="867512869" label="mark-non-secure-as"/> <int value="869531646" label="enable-session-crashed-bubble"/> + <int value="871713352" label="ImprovedLanguageSettings:enabled"/> <int value="879699575" label="disable-gesture-tap-highlight"/> <int value="879992337" label="disable-pull-to-refresh-effect"/> <int value="880510010" label="enable-permissions-bubbles"/> @@ -24246,6 +24248,7 @@ <int value="1276209777" label="ntp-switch-to-existing-tab"/> <int value="1279584261" label="enable-carrier-switching"/> <int value="1280614081" label="show-overdraw-feedback"/> + <int value="1283908088" label="ImprovedLanguageSettings:disabled"/> <int value="1283956865" label="force-tablet-mode"/> <int value="1283960113" label="disable-fixed-position-compositing"/> <int value="1284910808" label="disable-checker-imaging"/> @@ -39039,6 +39042,7 @@ <int value="82462683" label="gaia_oauth_client_refresh_token"/> <int value="83476155" label="gaia_oauth_client_get_user_info"/> <int value="84045030" label="payment_manifest_downloader"/> + <int value="84165821" label="blink_extension_resource_loader"/> <int value="84212388" label="omnibox_suggest_deletion"/> <int value="84575287" label="background_performance_tracer"/> <int value="84889397" label="cryptauth_enrollment_flow_setup"/> @@ -39077,6 +39081,7 @@ <int value="111565057" label="devtools_hard_coded_data_source"/> <int value="111712433" label="cloud_print"/> <int value="111904019" label="affiliation_lookup"/> + <int value="112189210" label="favicon_loader"/> <int value="112303907" label="blob_read"/> <int value="113231892" label="url_fetcher_downloader"/> <int value="113553577" label="certificate_verifier"/>
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index 980ecf2..a1f3c58 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -18,6 +18,7 @@ <item id="autofill_upload" hash_code="104798869" content_hash_code="110634763" os_list="linux,windows"/> <item id="background_fetch_context" hash_code="16469669" content_hash_code="52235434" os_list="linux,windows"/> <item id="background_performance_tracer" hash_code="84575287" content_hash_code="120154250" os_list="linux,windows"/> + <item id="blink_extension_resource_loader" hash_code="84165821" content_hash_code="3695143" os_list="linux,windows"/> <item id="blink_resource_loader" hash_code="101845102" content_hash_code="69137084" os_list="linux,windows"/> <item id="blob_read" hash_code="112303907" content_hash_code="135449692" os_list="linux,windows"/> <item id="blob_reader" hash_code="5154306" content_hash_code="39702178" os_list="linux,windows"/> @@ -74,6 +75,7 @@ <item id="extension_manifest_fetcher" hash_code="5151071" content_hash_code="57885402" os_list="linux,windows"/> <item id="external_policy_fetcher" hash_code="9459438" content_hash_code="64260484" os_list="linux,windows"/> <item id="family_info" hash_code="30913825" content_hash_code="25369370" os_list="linux,windows"/> + <item id="favicon_loader" hash_code="112189210" content_hash_code="70773116" os_list="linux,windows"/> <item id="gaia_auth_check_connection_info" hash_code="4598626" content_hash_code="57347000" os_list="linux,windows"/> <item id="gaia_auth_exchange_cookies" hash_code="134289752" content_hash_code="66433230" os_list="linux,windows"/> <item id="gaia_auth_exchange_device_id" hash_code="39877119" content_hash_code="61857947" os_list="linux,windows"/>
diff --git a/ui/keyboard/keyboard_controller_unittest.cc b/ui/keyboard/keyboard_controller_unittest.cc index 2d5d165..b1e23d9 100644 --- a/ui/keyboard/keyboard_controller_unittest.cc +++ b/ui/keyboard/keyboard_controller_unittest.cc
@@ -690,6 +690,27 @@ EXPECT_EQ(1.0, layer->opacity()); } +TEST_P(KeyboardControllerAnimationTest, SetBoundsOnOldKeyboardUiReference) { + ScopedAccessibilityKeyboardEnabler scoped_keyboard_enabler; + + // Ensure keyboard ui is populated + ui::Layer* layer = keyboard_container()->layer(); + ShowKeyboard(); + RunAnimationForLayer(layer); + + ASSERT_TRUE(controller()->ui()); + + aura::Window* container_window = controller()->GetContainerWindow(); + + // Simulate removal of keyboard controller from root window as done by + // RootWindowController::DeactivateKeyboard() + container_window->parent()->RemoveChild(container_window); + + // lingering handle to the contents window is adjusted. + // container_window's LayoutManager should abort silently and not crash. + controller()->ui()->GetContentsWindow()->SetBounds(gfx::Rect()); +} + TEST_P(KeyboardControllerTest, DisplayChangeShouldNotifyBoundsChange) { ScopedTouchKeyboardEnabler scoped_keyboard_enabler; ui::DummyTextInputClient input_client(ui::TEXT_INPUT_TYPE_TEXT);
diff --git a/ui/keyboard/keyboard_layout_manager.cc b/ui/keyboard/keyboard_layout_manager.cc index 1f6fa8e..68d3497 100644 --- a/ui/keyboard/keyboard_layout_manager.cc +++ b/ui/keyboard/keyboard_layout_manager.cc
@@ -29,7 +29,6 @@ void KeyboardLayoutManager::SetChildBounds(aura::Window* child, const gfx::Rect& requested_bounds) { DCHECK(child == contents_window_); - TRACE_EVENT0("vk", "KeyboardLayoutSetChildBounds"); // Request to change the bounds of the contents window @@ -39,6 +38,11 @@ const aura::Window* root_window = controller_->GetContainerWindow()->GetRootWindow(); + + // If the keyboard has been deactivated, this reference will be null. + if (!root_window) + return; + gfx::Rect new_bounds = requested_bounds; // Honors only the height of the request bounds