diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-01-31 16:33:43 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-02-06 16:33:22 +0000 |
commit | da51f56cc21233c2d30f0fe0d171727c3102b2e0 (patch) | |
tree | 4e579ab70ce4b19bee7984237f3ce05a96d59d83 /chromium/components/language | |
parent | c8c2d1901aec01e934adf561a9fdf0cc776cdef8 (diff) | |
download | qtwebengine-chromium-da51f56cc21233c2d30f0fe0d171727c3102b2e0.tar.gz |
BASELINE: Update Chromium to 65.0.3525.40
Also imports missing submodules
Change-Id: I36901b7c6a325cda3d2c10cedb2186c25af3b79b
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/components/language')
16 files changed, 707 insertions, 156 deletions
diff --git a/chromium/components/language/README b/chromium/components/language/README index 15ce9d425c3..e4c4821cc4c 100644 --- a/chromium/components/language/README +++ b/chromium/components/language/README @@ -13,7 +13,3 @@ content/: Driver for the shared code based on the content layer. renderer/: Renderer process code. common/: Code shared by the browser and the renderer. ios/: Driver for the shared code based on src/ios. - -Note: -The language code locator is built on all platforms but iOS since iOS currently -does not support //device/geolocation. See http://crbug.com/774879 for details. diff --git a/chromium/components/language/BUILD.gn b/chromium/components/language/content/browser/BUILD.gn index b77574817d2..06b29c29d6f 100644 --- a/chromium/components/language/BUILD.gn +++ b/chromium/components/language/content/browser/BUILD.gn @@ -10,10 +10,10 @@ action("make_s2_language_locator") { "adminregionsdata.csv", ] inputs = [ - "template/language_code_locator_helper.cc.tmpl", + "template/language_code_locator_helper.h.tmpl", ] outputs = [ - "$target_gen_dir/language_code_locator_helper.cc", + "$target_gen_dir/language_code_locator_helper.h", ] args = [ @@ -35,14 +35,34 @@ source_set("language_code_locator") { ] } +static_library("browser") { + sources = [ + "geo_language_provider.cc", + "geo_language_provider.h", + ] + + deps = [ + ":language_code_locator", + "//base", + "//net", + "//services/device/public/interfaces:interfaces", + "//services/service_manager/public/cpp", + ] +} + source_set("unit_tests") { testonly = true sources = [ + "geo_language_provider_unittest.cc", "language_code_locator_unittest.cc", ] deps = [ + ":browser", ":language_code_locator", "//base", + "//base/test:test_support", + "//services/device/public/interfaces:interfaces", + "//services/service_manager/public/cpp", "//testing/gmock", "//testing/gtest", ] diff --git a/chromium/components/language/content/browser/DEPS b/chromium/components/language/content/browser/DEPS index 1c35d9ca694..9d2ba3a3188 100644 --- a/chromium/components/language/content/browser/DEPS +++ b/chromium/components/language/content/browser/DEPS @@ -1,3 +1,6 @@ include_rules = [ - "+content/public/browser", + "+device/geolocation/public/interfaces", + "+net", + "+services/device/public/interfaces", + "+services/service_manager/public", ] diff --git a/chromium/components/language/content/browser/README b/chromium/components/language/content/browser/README new file mode 100644 index 00000000000..3ce50f2b614 --- /dev/null +++ b/chromium/components/language/content/browser/README @@ -0,0 +1,3 @@ +Note: +The language code locator is built on all platforms but iOS since iOS currently +does not support //device/geolocation. See http://crbug.com/774879 for details. diff --git a/chromium/components/language/adminregionsdata.csv b/chromium/components/language/content/browser/adminregionsdata.csv index bbc58dcc2b4..bbc58dcc2b4 100644 --- a/chromium/components/language/adminregionsdata.csv +++ b/chromium/components/language/content/browser/adminregionsdata.csv diff --git a/chromium/components/language/content/browser/convert_s2_cell.py b/chromium/components/language/content/browser/convert_s2_cell.py new file mode 100644 index 00000000000..1c6be45ff16 --- /dev/null +++ b/chromium/components/language/content/browser/convert_s2_cell.py @@ -0,0 +1,132 @@ +# 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. + +"""Generate c++ structure mapping position to language code from .csv input.""" + +import argparse +import csv +import os.path +import string +import sys + +sys.path.insert(1, + os.path.join(os.path.dirname(__file__), + os.path.pardir, + os.path.pardir, + os.path.pardir, + os.path.pardir, + "third_party")) +import jinja2 # pylint: disable=F0401 + + +CELL_ID_FIELD = "cell_ids" +LANGUAGE_FIELD = "languages" + + +def ParseInputCsv(input_path): + """Derive cell_id : language_code pairs.""" + district_with_languages = [] + with open(input_path, "r") as f: + reader = csv.DictReader(f, delimiter=",") + for row in reader: + district_with_languages.append((row[LANGUAGE_FIELD], + row[CELL_ID_FIELD])) + return district_with_languages + + +def ExtractCellIds(language_districts): + """Convert <language code>: [<cell_ids>...] into + a list of cell_id : language_code pairs.""" + cell_language_code_pairs = [] + language_code_enum = {} + for language_code, cell_ids in language_districts: + cell_ids = cell_ids.split(";") + for cell_id in cell_ids: + # We only store a coarser cell_ids (represent using uint32_t) + # to reduce binary size. + coarse_cell_id = cell_id[:-8] + # Change language code to language_enum to save some space. + if not language_code_enum.has_key(language_code): + language_code_enum[language_code] = len(language_code_enum) + language_enum = language_code_enum[language_code] + cell_language_code_pairs.append((coarse_cell_id, language_enum)) + return cell_language_code_pairs, language_code_enum + + +def ExtractLanguageCodeCounts(cell_language_code_pairs): + """Convert a list of cell_id : language_code pairs to cell_ids and counts""" + language_code_cell_id = {} + for cell_lang in cell_language_code_pairs: + if not language_code_cell_id.has_key(cell_lang[1]): + language_code_cell_id[cell_lang[1]] = [] + language_code_cell_id[cell_lang[1]].append(cell_lang[0]) + language_counts = [] + cell_ids = [] + for i in range(len(language_code_cell_id)): + language_counts.append(len(language_code_cell_id[i])) + cell_ids.extend(language_code_cell_id[i]) + return cell_ids, language_counts + + +def ExtractLanguageCodeEnum(language_code_enum): + """Convert language code enum dictionary to array.""" + language_codes = [] + inverted_lanugage_code_enum = dict( + [[v, k] for k, v in language_code_enum.items()]) + for i in range(len(inverted_lanugage_code_enum)): + language_codes.append(inverted_lanugage_code_enum[i]) + return language_codes + + +def GenerateCpp(output_path, + template_path, + cell_ids, + language_counts, + language_codes): + """Render the template to generate cpp code for LanguageCodeLocator.""" + with open(template_path, "r") as f: + template = jinja2.Template(f.read()) + context = { + "cell_ids" : cell_ids, + "language_counts" : language_counts, + "language_codes" : language_codes + } + generated_code = template.render(context) + + # Write the generated code. + with open(output_path, "w") as f: + f.write(generated_code) + + +def Main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--outputs", "-o", required=True, + help="path to the generate c++ file") + parser.add_argument( + "--template", "-t", required=True, + help="path to the template used to generate c++ file") + parser.add_argument( + "--inputs", "-i", required=True, + help="path to the input .csv file") + args = parser.parse_args() + + output_path = args.outputs + template_file_path = args.template + data_file_path = args.inputs + + cell_language_code_pairs, language_code_enum = ExtractCellIds( + ParseInputCsv(data_file_path)) + + cell_ids, language_counts = ExtractLanguageCodeCounts( + cell_language_code_pairs) + language_codes = ExtractLanguageCodeEnum(language_code_enum) + GenerateCpp(output_path, + template_file_path, + cell_ids, + language_counts, + language_codes) + +if __name__ == "__main__": + Main() diff --git a/chromium/components/language/content/browser/geo_language_provider.cc b/chromium/components/language/content/browser/geo_language_provider.cc new file mode 100644 index 00000000000..b06bb4743c9 --- /dev/null +++ b/chromium/components/language/content/browser/geo_language_provider.cc @@ -0,0 +1,153 @@ +// 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 "components/language/content/browser/geo_language_provider.h" + +#include "base/memory/singleton.h" +#include "base/task_scheduler/post_task.h" +#include "base/time/time.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/device/public/interfaces/constants.mojom.h" +#include "services/device/public/interfaces/public_ip_address_geolocation_provider.mojom.h" +#include "services/service_manager/public/cpp/connector.h" + +namespace language { +namespace { + +// Don't start requesting updates to IP-based approximation geolocation until +// this long after receiving the last one. +constexpr base::TimeDelta kMinUpdatePeriod = base::TimeDelta::FromDays(1); + +} // namespace + +GeoLanguageProvider::GeoLanguageProvider() + : languages_(), + creation_task_runner_(base::SequencedTaskRunnerHandle::Get()), + background_task_runner_(base::CreateSequencedTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BACKGROUND, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) { + // Constructor is not required to run on |background_task_runner_|: + DETACH_FROM_SEQUENCE(background_sequence_checker_); +} + +GeoLanguageProvider::GeoLanguageProvider( + scoped_refptr<base::SequencedTaskRunner> background_task_runner) + : languages_(), + creation_task_runner_(base::SequencedTaskRunnerHandle::Get()), + background_task_runner_(background_task_runner) { + // Constructor is not required to run on |background_task_runner_|: + DETACH_FROM_SEQUENCE(background_sequence_checker_); +} + +GeoLanguageProvider::~GeoLanguageProvider() = default; + +/* static */ +GeoLanguageProvider* GeoLanguageProvider::GetInstance() { + return base::Singleton<GeoLanguageProvider, base::LeakySingletonTraits< + GeoLanguageProvider>>::get(); +} + +void GeoLanguageProvider::StartUp( + std::unique_ptr<service_manager::Connector> service_manager_connector) { + DCHECK_CALLED_ON_VALID_SEQUENCE(creation_sequence_checker_); + + service_manager_connector_ = std::move(service_manager_connector); + // Continue startup in the background. + background_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&GeoLanguageProvider::BackgroundStartUp, + base::Unretained(this))); +} + +std::vector<std::string> GeoLanguageProvider::CurrentGeoLanguages() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(creation_sequence_checker_); + return languages_; +} + +void GeoLanguageProvider::BackgroundStartUp() { + // This binds background_sequence_checker_. + DCHECK_CALLED_ON_VALID_SEQUENCE(background_sequence_checker_); + + // Initialize location->language lookup library. + language_code_locator_ = std::make_unique<language::LanguageCodeLocator>(); + + // Make initial query. + QueryNextPosition(); +} + +void GeoLanguageProvider::BindIpGeolocationService() { + DCHECK_CALLED_ON_VALID_SEQUENCE(background_sequence_checker_); + DCHECK(!geolocation_provider_.is_bound()); + + // Bind a PublicIpAddressGeolocationProvider. + device::mojom::PublicIpAddressGeolocationProviderPtr ip_geolocation_provider; + service_manager_connector_->BindInterface( + device::mojom::kServiceName, mojo::MakeRequest(&ip_geolocation_provider)); + + net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation = + net::DefinePartialNetworkTrafficAnnotation("geo_language_provider", + "network_location_request", + R"( + semantics { + sender: "GeoLanguage Provider" + } + policy { + setting: + "Users can control this feature via the translation settings " + "'Languages', 'Language', 'Offer to translate'." + chrome_policy { + DefaultGeolocationSetting { + DefaultGeolocationSetting: 2 + } + } + })"); + + // Use the PublicIpAddressGeolocationProvider to bind ip_geolocation_service_. + ip_geolocation_provider->CreateGeolocation( + static_cast<net::MutablePartialNetworkTrafficAnnotationTag>( + partial_traffic_annotation), + mojo::MakeRequest(&geolocation_provider_)); + // No error handler required: If the connection is broken, QueryNextPosition + // will bind it again. +} + +void GeoLanguageProvider::QueryNextPosition() { + DCHECK_CALLED_ON_VALID_SEQUENCE(background_sequence_checker_); + + if (geolocation_provider_.encountered_error()) + geolocation_provider_.reset(); + if (!geolocation_provider_.is_bound()) + BindIpGeolocationService(); + + geolocation_provider_->QueryNextPosition(base::BindOnce( + &GeoLanguageProvider::OnIpGeolocationResponse, base::Unretained(this))); +} + +void GeoLanguageProvider::OnIpGeolocationResponse( + device::mojom::GeopositionPtr geoposition) { + DCHECK_CALLED_ON_VALID_SEQUENCE(background_sequence_checker_); + + const std::vector<std::string> languages = + language_code_locator_->GetLanguageCode(geoposition->latitude, + geoposition->longitude); + + // Update current languages on UI thread. + creation_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&GeoLanguageProvider::SetGeoLanguages, + base::Unretained(this), languages)); + + // Post a task to request a fresh lookup after |kMinUpdatePeriod|. + background_task_runner_->PostDelayedTask( + FROM_HERE, + base::BindOnce(&GeoLanguageProvider::QueryNextPosition, + base::Unretained(this)), + kMinUpdatePeriod); +} + +void GeoLanguageProvider::SetGeoLanguages( + const std::vector<std::string>& languages) { + DCHECK_CALLED_ON_VALID_SEQUENCE(creation_sequence_checker_); + languages_ = languages; +} + +} // namespace language diff --git a/chromium/components/language/content/browser/geo_language_provider.h b/chromium/components/language/content/browser/geo_language_provider.h new file mode 100644 index 00000000000..b361a639926 --- /dev/null +++ b/chromium/components/language/content/browser/geo_language_provider.h @@ -0,0 +1,114 @@ +// 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 COMPONENTS_LANGUAGE_CONTENT_BROWSER_GEO_LANGUAGE_PROVIDER_H_ +#define COMPONENTS_LANGUAGE_CONTENT_BROWSER_GEO_LANGUAGE_PROVIDER_H_ + +#include <string> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/sequence_checker.h" +#include "base/sequenced_task_runner.h" +#include "components/language/content/browser/language_code_locator.h" +#include "device/geolocation/public/interfaces/geolocation.mojom.h" + +namespace base { +template <typename T> +struct DefaultSingletonTraits; +} + +namespace service_manager { +class Connector; +} + +namespace language { +// GeoLanguageProvider is responsible for providing a "local" language derived +// from the approximate geolocation of the device based only on its public IP +// address. +// * Singleton class. Access through GetInstance(). +// * Sequencing: Must be created and used on the same sequence. +class GeoLanguageProvider { + public: + static GeoLanguageProvider* GetInstance(); + + // Call this once near browser startup. Begins ongoing geo-language updates. + // * Initializes location->language mapping in a low-priority background task. + // * Until the first IP geolocation completes, CurrentGeoLanguages() will + // return an empty list. + // |service_manager_connector| should not yet be bound to a sequence, e.g., it + // should be the result of invoking ServiceManagerConnect::Clone() on another + // connector. + void StartUp( + std::unique_ptr<service_manager::Connector> service_manager_connector); + + // Returns the inferred ranked list of local languages based on the most + // recently obtained approximate public-IP geolocation of the device. + // * Returns a list of BCP-47 language codes. + // * Returns an empty list in these cases: + // - StartUp() not yet called + // - Geolocation failed + // - Geolocation pending + // - Geolocation succeeded but no local language is mapped to that location + std::vector<std::string> CurrentGeoLanguages() const; + + private: + friend class GeoLanguageProviderTest; + + GeoLanguageProvider(); + explicit GeoLanguageProvider( + scoped_refptr<base::SequencedTaskRunner> background_task_runner); + ~GeoLanguageProvider(); + friend struct base::DefaultSingletonTraits<GeoLanguageProvider>; + + // Performs actual work described in StartUp() above. + void BackgroundStartUp(); + + // Binds |ip_geolocation_service_| using a service_manager::Connector. + void BindIpGeolocationService(); + + // Requests the next available IP-based approximate geolocation from + // |ip_geolocation_service_|, binding |ip_geolocation_service_| first if + // necessary. + void QueryNextPosition(); + + // Updates the list of BCP-47 language codes that will be returned by calls to + // CurrentGeoLanguages(). + // Must be called on the UI thread. + void SetGeoLanguages(const std::vector<std::string>& languages); + + // Callback for updates from |ip_geolocation_service_|. + void OnIpGeolocationResponse(device::mojom::GeopositionPtr geoposition); + + // List of BCP-47 language code inferred from public-IP geolocation. + // May be empty. See comment on CurrentGeoLanguages() above. + std::vector<std::string> languages_; + + // Service manager connector for use on background_task_runner_. + std::unique_ptr<service_manager::Connector> service_manager_connector_; + + // Connection to the IP geolocation service. + device::mojom::GeolocationPtr geolocation_provider_; + + // Location -> Language lookup library. + std::unique_ptr<language::LanguageCodeLocator> language_code_locator_; + + // Runner for tasks that should run on the creation sequence. + scoped_refptr<base::SequencedTaskRunner> creation_task_runner_; + + // Runner for low priority background tasks. + scoped_refptr<base::SequencedTaskRunner> background_task_runner_; + + // Sequence checker for methods that must run on the creation sequence. + SEQUENCE_CHECKER(creation_sequence_checker_); + + // Sequence checker for background_task_runner_. + SEQUENCE_CHECKER(background_sequence_checker_); + + DISALLOW_COPY_AND_ASSIGN(GeoLanguageProvider); +}; + +} // namespace language + +#endif // COMPONENTS_LANGUAGE_CONTENT_BROWSER_GEO_LANGUAGE_PROVIDER_H_ diff --git a/chromium/components/language/content/browser/geo_language_provider_unittest.cc b/chromium/components/language/content/browser/geo_language_provider_unittest.cc new file mode 100644 index 00000000000..bb73e412492 --- /dev/null +++ b/chromium/components/language/content/browser/geo_language_provider_unittest.cc @@ -0,0 +1,183 @@ +// 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 "components/language/content/browser/geo_language_provider.h" + +#include <memory> +#include <string> +#include <vector> + +#include "base/macros.h" +#include "base/test/test_mock_time_task_runner.h" +#include "base/timer/timer.h" +#include "device/geolocation/public/interfaces/geolocation.mojom.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "services/device/public/interfaces/constants.mojom.h" +#include "services/device/public/interfaces/public_ip_address_geolocation_provider.mojom.h" +#include "services/service_manager/public/cpp/connector.h" +#include "services/service_manager/public/interfaces/connector.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +// Mock impl of mojom::Geolocation that allows tests to control the returned +// location. +class MockGeoLocation : public device::mojom::Geolocation { + public: + MockGeoLocation() : binding_(this) {} + // device::mojom::Geolocation implementation: + void SetHighAccuracy(bool high_accuracy) override {} + void QueryNextPosition(QueryNextPositionCallback callback) override { + ++query_next_position_called_times_; + std::move(callback).Run(position_.Clone()); + } + + void BindGeoLocation(device::mojom::GeolocationRequest request) { + binding_.Bind(std::move(request)); + } + + void MoveToLocation(float latitude, float longitude) { + position_.latitude = latitude; + position_.longitude = longitude; + } + + int query_next_position_called_times() const { + return query_next_position_called_times_; + } + + private: + int query_next_position_called_times_ = 0; + device::mojom::Geoposition position_; + mojo::Binding<device::mojom::Geolocation> binding_; +}; + +// Mock impl of mojom::PublicIpAddressGeolocationProvider that binds Geolocation +// to testing impl. +class MockIpGeoLocationProvider + : public device::mojom::PublicIpAddressGeolocationProvider { + public: + explicit MockIpGeoLocationProvider(MockGeoLocation* mock_geo_location) + : mock_geo_location_(mock_geo_location), binding_(this) {} + + void Bind(mojo::ScopedMessagePipeHandle handle) { + binding_.Bind(device::mojom::PublicIpAddressGeolocationProviderRequest( + std::move(handle))); + } + + void CreateGeolocation( + const net::MutablePartialNetworkTrafficAnnotationTag& /* unused */, + device::mojom::GeolocationRequest request) override { + mock_geo_location_->BindGeoLocation(std::move(request)); + } + + private: + MockGeoLocation* mock_geo_location_; + + mojo::Binding<device::mojom::PublicIpAddressGeolocationProvider> binding_; +}; + +} // namespace + +namespace language { + +class GeoLanguageProviderTest : public testing::Test { + public: + GeoLanguageProviderTest() + : task_runner_(base::MakeRefCounted<base::TestMockTimeTaskRunner>( + base::TestMockTimeTaskRunner::Type::kBoundToThread)), + scoped_context_(task_runner_.get()), + geo_language_provider_(task_runner_), + mock_ip_geo_location_provider_(&mock_geo_location_) { + service_manager::mojom::ConnectorRequest request; + connector_ = service_manager::Connector::Create(&request); + service_manager::Connector::TestApi test_api(connector_.get()); + test_api.OverrideBinderForTesting( + device::mojom::kServiceName, + device::mojom::PublicIpAddressGeolocationProvider::Name_, + base::BindRepeating(&MockIpGeoLocationProvider::Bind, + base::Unretained(&mock_ip_geo_location_provider_))); + } + + protected: + std::vector<std::string> GetCurrentGeoLanguages() { + return geo_language_provider_.CurrentGeoLanguages(); + } + + void StartGeoLanguageProvider() { + geo_language_provider_.StartUp(std::move(connector_)); + } + + void MoveToLocation(float latitude, float longitude) { + mock_geo_location_.MoveToLocation(latitude, longitude); + } + + const scoped_refptr<base::TestMockTimeTaskRunner>& GetTaskRunner() { + return task_runner_; + } + + int GetQueryNextPositionCalledTimes() { + return mock_geo_location_.query_next_position_called_times(); + } + + private: + scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; + const base::TestMockTimeTaskRunner::ScopedContext scoped_context_; + + // Object under test. + GeoLanguageProvider geo_language_provider_; + MockGeoLocation mock_geo_location_; + MockIpGeoLocationProvider mock_ip_geo_location_provider_; + std::unique_ptr<service_manager::Connector> connector_; +}; + +TEST_F(GeoLanguageProviderTest, GetCurrentGeoLanguages) { + // Setup a random place in Madhya Pradesh, India. + MoveToLocation(23.0, 80.0); + StartGeoLanguageProvider(); + const auto task_runner = GetTaskRunner(); + task_runner->RunUntilIdle(); + + const std::vector<std::string>& result = GetCurrentGeoLanguages(); + std::vector<std::string> expected_langs = {"hi", "mr", "ur"}; + EXPECT_EQ(expected_langs, result); + EXPECT_EQ(1, GetQueryNextPositionCalledTimes()); +} + +TEST_F(GeoLanguageProviderTest, NoFrequentCalls) { + // Setup a random place in Madhya Pradesh, India. + MoveToLocation(23.0, 80.0); + StartGeoLanguageProvider(); + const auto task_runner = GetTaskRunner(); + task_runner->RunUntilIdle(); + + const std::vector<std::string>& result = GetCurrentGeoLanguages(); + std::vector<std::string> expected_langs = {"hi", "mr", "ur"}; + EXPECT_EQ(expected_langs, result); + + task_runner->FastForwardBy(base::TimeDelta::FromHours(12)); + EXPECT_EQ(1, GetQueryNextPositionCalledTimes()); +} + +TEST_F(GeoLanguageProviderTest, ButDoCallInTheNextDay) { + // Setup a random place in Madhya Pradesh, India. + MoveToLocation(23.0, 80.0); + StartGeoLanguageProvider(); + const auto task_runner = GetTaskRunner(); + task_runner->RunUntilIdle(); + + std::vector<std::string> result = GetCurrentGeoLanguages(); + std::vector<std::string> expected_langs = {"hi", "mr", "ur"}; + EXPECT_EQ(expected_langs, result); + + // Move to another random place in Karnataka, India. + MoveToLocation(15.0, 75.0); + task_runner->FastForwardBy(base::TimeDelta::FromHours(25)); + EXPECT_EQ(2, GetQueryNextPositionCalledTimes()); + + result = GetCurrentGeoLanguages(); + std::vector<std::string> expected_langs_2 = {"kn", "ur", "te", "mr", "ta"}; + EXPECT_EQ(expected_langs_2, result); +} + +} // namespace language diff --git a/chromium/components/language/content/browser/language_code_locator.cc b/chromium/components/language/content/browser/language_code_locator.cc new file mode 100644 index 00000000000..0530d7264c3 --- /dev/null +++ b/chromium/components/language/content/browser/language_code_locator.cc @@ -0,0 +1,48 @@ +// 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 "components/language/content/browser/language_code_locator.h" + +#include "base/strings/string_split.h" +#include "third_party/s2cellid/src/s2/s2cellid.h" +#include "third_party/s2cellid/src/s2/s2latlng.h" + +namespace language { +namespace { +#include "components/language/content/browser/language_code_locator_helper.h" +} // namespace + +LanguageCodeLocator::LanguageCodeLocator() { + int pos = 0; + int index = 0; + std::vector<std::pair<uint32_t, char>> items(arraysize(kDistrictPositions)); + for (const uint16_t language_count : kLanguageCodeCounts) { + for (int i = 0; i < language_count; ++i) { + items[pos] = std::make_pair(kDistrictPositions[pos], index); + ++pos; + } + ++index; + } + district_languages_ = base::flat_map<uint32_t, char>(items); +} + +LanguageCodeLocator::~LanguageCodeLocator() {} + +std::vector<std::string> LanguageCodeLocator::GetLanguageCode( + double latitude, + double longitude) const { + S2CellId current_cell(S2LatLng::FromDegrees(latitude, longitude)); + while (current_cell.level() > 0) { + auto search = district_languages_.find(current_cell.id() >> 32); + if (search != district_languages_.end()) { + return base::SplitString( + kLanguageEnumCodeMapping[static_cast<uint8_t>(search->second)], ";", + base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + } + current_cell = current_cell.parent(); + } + return {}; +} + +} // namespace language diff --git a/chromium/components/language/language_code_locator.h b/chromium/components/language/content/browser/language_code_locator.h index 3cc9ac66867..ef07e739a09 100644 --- a/chromium/components/language/language_code_locator.h +++ b/chromium/components/language/content/browser/language_code_locator.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_LANGUAGE_LANGUAGE_CODE_LOCATOR_H_ -#define COMPONENTS_LANGUAGE_LANGUAGE_CODE_LOCATOR_H_ +#ifndef COMPONENTS_LANGUAGE_CONTENT_BROWSER_LANGUAGE_CODE_LOCATOR_H_ +#define COMPONENTS_LANGUAGE_CONTENT_BROWSER_LANGUAGE_CODE_LOCATOR_H_ #include <string> #include <vector> @@ -24,12 +24,12 @@ class LanguageCodeLocator { double longitude) const; private: - // Map from s2 cellid to ';' delimited list of language codes. - const base::flat_map<uint64_t, std::string> district_languages_; + // Map from s2 cellid to ';' delimited list of language codes enum. + base::flat_map<uint32_t, char> district_languages_; DISALLOW_COPY_AND_ASSIGN(LanguageCodeLocator); }; } // namespace language -#endif // COMPONENTS_LANGUAGE_LANGUAGE_CODE_LOCATOR_H_ +#endif // COMPONENTS_LANGUAGE_CONTENT_BROWSER_LANGUAGE_CODE_LOCATOR_H_ diff --git a/chromium/components/language/language_code_locator_unittest.cc b/chromium/components/language/content/browser/language_code_locator_unittest.cc index 2553353c5ec..62d5c979014 100644 --- a/chromium/components/language/language_code_locator_unittest.cc +++ b/chromium/components/language/content/browser/language_code_locator_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/language/language_code_locator.h" +#include "components/language/content/browser/language_code_locator.h" #include <string> #include <vector> @@ -12,7 +12,7 @@ namespace language { -TEST(LanguageCodeLocatorTest, LocatedLanguage) { +TEST(LanguageCodeLocatorTest, LocatedLanguageOne) { LanguageCodeLocator locator; std::vector<std::string> expected_langs = {"hi", "mr", "ur"}; // Random place in Madhya Pradesh, expected langs should be hi;mr;ur. @@ -20,6 +20,14 @@ TEST(LanguageCodeLocatorTest, LocatedLanguage) { EXPECT_EQ(expected_langs, result); } +TEST(LanguageCodeLocatorTest, LocatedLanguageTwo) { + LanguageCodeLocator locator; + std::vector<std::string> expected_langs = {"bn"}; + // Random place in Tripura, expected langs should be bn. + const auto& result = locator.GetLanguageCode(23.7f, 91.7f); + EXPECT_EQ(expected_langs, result); +} + TEST(LanguageCodeLocatorTest, NotFoundLanguage) { LanguageCodeLocator locator; std::vector<std::string> expected_langs = {}; diff --git a/chromium/components/language/content/browser/template/language_code_locator_helper.h.tmpl b/chromium/components/language/content/browser/template/language_code_locator_helper.h.tmpl new file mode 100644 index 00000000000..bcf5ee3a47a --- /dev/null +++ b/chromium/components/language/content/browser/template/language_code_locator_helper.h.tmpl @@ -0,0 +1,33 @@ +// 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 <string> +#include <vector> + +namespace { +const uint32_t kDistrictPositions[] = { + {% set c = 1 %} + {% for cell_id in cell_ids -%} + {{cell_id}}u{% if c < cell_ids|length%},{% endif %} + {% set c = c + 1%} + {%- endfor %} +}; + +const uint16_t kLanguageCodeCounts[] = { + {% set c = 1 %} + {% for language_count in language_counts -%} + {{language_count}}u{% if c < language_counts|length%},{% endif %} + {% set c = c + 1%} + {%- endfor %} +}; + +const char* const kLanguageEnumCodeMapping[] = { + {% set c = 1 %} + {% for language_code in language_codes -%} + "{{language_code}}"{% if c < language_codes|length%},{% endif %} + {% set c = c + 1%} + {%- endfor %} +}; + +} // namespace diff --git a/chromium/components/language/convert_s2_cell.py b/chromium/components/language/convert_s2_cell.py deleted file mode 100644 index b9646677260..00000000000 --- a/chromium/components/language/convert_s2_cell.py +++ /dev/null @@ -1,83 +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. - -"""Generate c++ structure mapping position to language code from .csv input.""" - -import argparse -import csv -import os.path -import string -import sys - -sys.path.insert(1, - os.path.join(os.path.dirname(__file__), - os.path.pardir, - os.path.pardir, - "third_party")) -import jinja2 # pylint: disable=F0401 - - -CELL_ID_FIELD = "cell_ids" -LANGUAGE_FIELD = "languages" - - -def ParseInputCsv(input_path): - """Derive cell_id : language_code pairs.""" - district_with_languages = [] - with open(input_path, "r") as f: - reader = csv.DictReader(f, delimiter=",") - for row in reader: - district_with_languages.append((row[LANGUAGE_FIELD], - row[CELL_ID_FIELD])) - return district_with_languages - - -def ExtractCellIds(language_districts): - """Convert <language code>: [<cell_ids>...] into - a list of cell_id : language_code pairs.""" - cell_language_code_pairs = [] - for language_code, cell_ids in language_districts: - cell_ids = cell_ids.split(";") - for cell_id in cell_ids: - cell_language_code_pairs.append((cell_id, language_code)) - return cell_language_code_pairs - - -def GenerateCpp(output_path, template_path, cell_language_code_pairs): - """Render the template to generate cpp code for LanguageCodeLocator.""" - with open(template_path, "r") as f: - template = jinja2.Template(f.read()) - context = { - "cell_lang_pairs" : cell_language_code_pairs - } - generated_code = template.render(context) - - # Write the generated code. - with open(output_path, "w") as f: - f.write(generated_code) - - -def Main(): - parser = argparse.ArgumentParser() - parser.add_argument( - "--outputs", "-o", required=True, - help="path to the generate c++ file") - parser.add_argument( - "--template", "-t", required=True, - help="path to the template used to generate c++ file") - parser.add_argument( - "--inputs", "-i", required=True, - help="path to the input .csv file") - args = parser.parse_args() - - output_path = args.outputs - template_file_path = args.template - data_file_path = args.inputs - - cell_language_code_pairs = ExtractCellIds(ParseInputCsv(data_file_path)) - - GenerateCpp(output_path, template_file_path, cell_language_code_pairs) - -if __name__ == "__main__": - Main() diff --git a/chromium/components/language/language_code_locator.cc b/chromium/components/language/language_code_locator.cc deleted file mode 100644 index bb06734cc18..00000000000 --- a/chromium/components/language/language_code_locator.cc +++ /dev/null @@ -1,37 +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 "components/language/language_code_locator.h" - -#include "base/strings/string_split.h" -#include "third_party/s2cellid/src/s2/s2cellid.h" -#include "third_party/s2cellid/src/s2/s2latlng.h" - -namespace language { -namespace internal { -extern std::vector<std::pair<uint64_t, std::string>> -GenerateDistrictLanguageMapping(); -} // namespace internal - -LanguageCodeLocator::LanguageCodeLocator() - : district_languages_(internal::GenerateDistrictLanguageMapping()) {} - -LanguageCodeLocator::~LanguageCodeLocator() {} - -std::vector<std::string> LanguageCodeLocator::GetLanguageCode( - double latitude, - double longitude) const { - S2CellId current_cell(S2LatLng::FromDegrees(latitude, longitude)); - while (current_cell.level() > 0) { - auto search = district_languages_.find(current_cell.id()); - if (search != district_languages_.end()) { - return base::SplitString(search->second, ";", base::KEEP_WHITESPACE, - base::SPLIT_WANT_ALL); - } - current_cell = current_cell.parent(); - } - return {}; -} - -} // namespace language diff --git a/chromium/components/language/template/language_code_locator_helper.cc.tmpl b/chromium/components/language/template/language_code_locator_helper.cc.tmpl deleted file mode 100644 index 9c36aa89ee6..00000000000 --- a/chromium/components/language/template/language_code_locator_helper.cc.tmpl +++ /dev/null @@ -1,22 +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 <string> -#include <vector> - -namespace language { -namespace internal { -std::vector<std::pair<uint64_t, std::string>> -GenerateDistrictLanguageMapping() { - return { - {% set c = 1 %} - {% for cell_lang_pair in cell_lang_pairs -%} - { {{cell_lang_pair[0]}}ull, "{{cell_lang_pair[1]}}"}{% if c < cell_lang_pairs|length%},{% endif %} - {% set c = c + 1%} - {%- endfor %} - }; -} - -} // namespace internal -} // namespace language |