diff options
author | andrewhayden@chromium.org <andrewhayden@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-24 15:54:26 +0000 |
---|---|---|
committer | andrewhayden@chromium.org <andrewhayden@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-24 15:54:26 +0000 |
commit | cf78eecf38ea51a8a4c0b78974d7a5d88bbb0b54 (patch) | |
tree | 414ed885eafebf252c99cef6ccbdb72f9a3198fe | |
parent | f3918a49017af1015fe4256f80b35eb6577a67b8 (diff) | |
download | chromium_src-cf78eecf38ea51a8a4c0b78974d7a5d88bbb0b54.zip chromium_src-cf78eecf38ea51a8a4c0b78974d7a5d88bbb0b54.tar.gz chromium_src-cf78eecf38ea51a8a4c0b78974d7a5d88bbb0b54.tar.bz2 |
This patch defines three mechanisms for acquiring CLD2's data:
1. Static linking (the way it is done today)
2. Standalone dynamic data file bundled with the application
3. Dynamic data file downloaded via the Component Updater
This change does NOT switch any implementation to a different cld data source.
Android/iOS remain pinned to CLD1, and all platforms continue to statically
link the data with cld2_data_source="static".
This change has several important side effects:
1. The gyp variables "cld2_dynamic" and "cld2_is_component" have been removed.
There is now a single variable, "cld2_data_source", that defines which
implementation is to be used.
2. cld_component_installer.[h,cc] and cld_component_installer_unittest.cc are
now conditionally built if and only if cld2_data_source=="component" and
have direct dependencies upon components/translate/content/browser.
3. Almost all preprocesser checks for the CLD data source have been removed,
greatly simplifying code flow. The logic previously gated by these checks
has been split into separate implementation classes whose inclusion is
controlled by the cld2_data_source gyp variable.
For more information, refer to crbug/383769.
BUG=383769
Review URL: https://codereview.chromium.org/333603002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@279415 0039d316-1c4b-4281-b951-d872f2087c98
47 files changed, 1494 insertions, 721 deletions
diff --git a/build/common.gypi b/build/common.gypi index 4e0c35a..aca6efd 100644 --- a/build/common.gypi +++ b/build/common.gypi @@ -457,19 +457,13 @@ # 2: Large tables, high accuracy 'cld2_table_size%': 2, - # Set the way CLD is compiled. Only evaluated if cld_version == 2. - # 0: static, language scoring tables compiled into the binary - # 1: dynamic, language scoring tables live in a data file that must - # be loaded at runtime. - 'cld2_dynamic%': 0, - - # Whether CLD2 is a component. Only evaluated if cld_version == 2 and - # cld2_dynamic == 1. - # 0: Not a component. If cld2_dynamic == 1, it is up to the distribution - # to ensure that the data file is provided if desired. - # 1: Componentized. CLD data should be obtained via the Component - # Updater. - 'cld2_is_component%': 0, + # The data acquisition mode for CLD2. Possible values are: + # static: CLD2 data is statically linked to the executable. + # standalone: CLD2 data is provided in a standalone file that is + # bundled with the executable. + # component: CLD2 data is provided as a Chrome "component" and is + # downloaded via the component updater. + 'cld2_data_source': 'static', # Enable spell checker. 'enable_spellcheck%': 1, @@ -694,8 +688,6 @@ 'enable_extensions%': 0, 'enable_google_now%': 0, 'cld_version%': 1, - 'cld2_dynamic%': 0, - 'cld2_is_component%': 0, 'enable_spellcheck%': 0, 'enable_themes%': 0, 'remoting%': 0, @@ -745,7 +737,6 @@ 'enable_extensions%': 0, 'enable_google_now%': 0, 'cld_version%': 1, - 'cld2_dynamic%': 0, 'enable_printing%': 0, 'enable_session_service%': 0, 'enable_themes%': 0, @@ -1102,8 +1093,7 @@ 'enable_google_now%': '<(enable_google_now)', 'cld_version%': '<(cld_version)', 'cld2_table_size%': '<(cld2_table_size)', - 'cld2_dynamic%': '<(cld2_dynamic)', - 'cld2_is_component%': '<(cld2_is_component)', + 'cld2_data_source%': '<(cld2_data_source)', 'enable_captive_portal_detection%': '<(enable_captive_portal_detection)', 'disable_file_support%': '<(disable_file_support)', 'disable_ftp_support%': '<(disable_ftp_support)', @@ -2710,11 +2700,19 @@ ['cld_version!=0', { 'defines': ['CLD_VERSION=<(cld_version)'], }], - ['cld2_dynamic!=0', { - 'defines': ['CLD2_DYNAMIC_MODE=1'], + ['cld2_data_source=="static"', { + 'defines': ['CLD_DATA_FROM_STATIC'], + }, { + # CLD2 headers use this #define to control the visibility of dynamic + # mode functions. We use these functions, so we must define here for + # our #includes to work right. + 'defines': ['CLD2_DYNAMIC_MODE'], + }], + ['cld2_data_source=="standalone"', { + 'defines': ['CLD_DATA_FROM_STANDALONE'], }], - ['cld2_is_component!=0', { - 'defines': ['CLD2_IS_COMPONENT=1'], + ['cld2_data_source=="component"', { + 'defines': ['CLD_DATA_FROM_COMPONENT'], }], ['enable_printing==1', { 'defines': ['ENABLE_FULL_PRINTING=1', 'ENABLE_PRINTING=1'], diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index b0260a6..8bc7c2a 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc @@ -42,7 +42,6 @@ #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/browser_shutdown.h" #include "chrome/browser/chrome_browser_main_extra_parts.h" -#include "chrome/browser/component_updater/cld_component_installer.h" #include "chrome/browser/component_updater/component_updater_service.h" #include "chrome/browser/component_updater/flash_component_installer.h" #include "chrome/browser/component_updater/pnacl/pnacl_component_installer.h" @@ -184,6 +183,10 @@ #include "chrome/browser/mac/keystone_glue.h" #endif +#if defined(CLD_DATA_FROM_COMPONENT) +#include "chrome/browser/component_updater/cld_component_installer.h" +#endif + #if defined(ENABLE_FULL_PRINTING) && !defined(OFFICIAL_BUILD) #include "printing/printed_document.h" #endif @@ -404,7 +407,7 @@ void RegisterComponentsForUpdate(const CommandLine& command_line) { g_browser_process->crl_set_fetcher()->DeleteFromDisk(); #endif -#if defined(CLD2_DYNAMIC_MODE) && defined(CLD2_IS_COMPONENT) +#if defined(CLD_DATA_FROM_COMPONENT) RegisterCldComponent(cus); #endif diff --git a/chrome/browser/component_updater/cld_component_installer.cc b/chrome/browser/component_updater/cld_component_installer.cc index 5028c5b..a3e62ac 100644 --- a/chrome/browser/component_updater/cld_component_installer.cc +++ b/chrome/browser/component_updater/cld_component_installer.cc @@ -14,8 +14,8 @@ #include "base/logging.h" #include "base/path_service.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" +#include "components/translate/content/browser/data_file_browser_cld_data_provider.h" #include "content/public/browser/browser_thread.h" #include "net/ssl/ssl_config_service.h" @@ -23,15 +23,12 @@ using component_updater::ComponentUpdateService; using content::BrowserThread; namespace { - -// Once we have acquired a valid file from the component installer, we need to -// make the path available to other parts of the system such as the -// translation libraries. We create a global to hold onto the path, and a -// lock to guard it. See GetLatestCldDataFile(...) for more info. -base::LazyInstance<base::Lock> cld_file_lock = LAZY_INSTANCE_INITIALIZER; -base::LazyInstance<base::FilePath> cld_file = LAZY_INSTANCE_INITIALIZER; - -} +// TODO(andrewhayden): Make the data file path into a gyp/gn define +// If you change this, also update component_cld_data_harness.cc +// and cld_component_installer_unittest.cc accordingly! +const base::FilePath::CharType kCldDataFileName[] = + FILE_PATH_LITERAL("cld2_data.bin"); +} // namespace namespace component_updater { @@ -66,7 +63,7 @@ base::FilePath CldComponentInstallerTraits::GetInstalledPath( // NB: This may change when 64-bit is officially supported. return base.Append(FILE_PATH_LITERAL("_platform_specific")) .Append(FILE_PATH_LITERAL("all")) - .Append(chrome::kCLDDataFilename); + .Append(kCldDataFileName); } void CldComponentInstallerTraits::ComponentReady( @@ -117,14 +114,7 @@ void RegisterCldComponent(ComponentUpdateService* cus) { void CldComponentInstallerTraits::SetLatestCldDataFile( const base::FilePath& path) { VLOG(1) << "Setting CLD data file location: " << path.value(); - base::AutoLock lock(cld_file_lock.Get()); - cld_file.Get() = path; -} - -base::FilePath GetLatestCldDataFile() { - base::AutoLock lock(cld_file_lock.Get()); - // cld_file is an empty path by default, meaning "file not available yet". - return cld_file.Get(); + translate::DataFileBrowserCldDataProvider::SetCldDataFilePath(path); } } // namespace component_updater diff --git a/chrome/browser/component_updater/cld_component_installer.h b/chrome/browser/component_updater/cld_component_installer.h index 9e92c71..b226aac 100644 --- a/chrome/browser/component_updater/cld_component_installer.h +++ b/chrome/browser/component_updater/cld_component_installer.h @@ -13,7 +13,7 @@ #include "chrome/browser/component_updater/default_component_installer.h" namespace test { -class ScopedCLDDynamicDataHarness; +class ComponentCldDataHarness; } // namespace test namespace component_updater { @@ -28,7 +28,7 @@ class CldComponentInstallerTraits : public ComponentInstallerTraits { private: friend class CldComponentInstallerTest; // For access within SetUp() - friend class test::ScopedCLDDynamicDataHarness; // For browser tests only + friend class test::ComponentCldDataHarness; // For browser tests only FRIEND_TEST_ALL_PREFIXES(CldComponentInstallerTest, ComponentReady); FRIEND_TEST_ALL_PREFIXES(CldComponentInstallerTest, GetBaseDirectory); FRIEND_TEST_ALL_PREFIXES(CldComponentInstallerTest, GetHash); @@ -53,7 +53,13 @@ class CldComponentInstallerTraits : public ComponentInstallerTraits { virtual std::string GetName() const OVERRIDE; static base::FilePath GetInstalledPath(const base::FilePath& base); + + // Sets the path to the CLD data file. Called internally once a valid CLD + // data file has been observed. The implementation of this method is + // responsible for configuring the CLD data source. + // This method is threadsafe. static void SetLatestCldDataFile(const base::FilePath& path); + DISALLOW_COPY_AND_ASSIGN(CldComponentInstallerTraits); }; @@ -61,11 +67,6 @@ class CldComponentInstallerTraits : public ComponentInstallerTraits { // the CLD component. void RegisterCldComponent(ComponentUpdateService* cus); -// Returns the path to the latest CLD data file into the specified path object, -// or an empty path if the CLD data file has not been observed yet. -// This function is threadsafe. -base::FilePath GetLatestCldDataFile(); - } // namespace component_updater #endif // CHROME_BROWSER_COMPONENT_UPDATER_CLD_COMPONENT_INSTALLER_H_ diff --git a/chrome/browser/component_updater/test/cld_component_installer_unittest.cc b/chrome/browser/component_updater/test/cld_component_installer_unittest.cc index 6fc4f14..bf10a9a 100644 --- a/chrome/browser/component_updater/test/cld_component_installer_unittest.cc +++ b/chrome/browser/component_updater/test/cld_component_installer_unittest.cc @@ -7,22 +7,28 @@ #include "base/file_util.h" #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" +#include "base/macros.h" #include "base/memory/scoped_ptr.h" -#include "base/run_loop.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "base/version.h" #include "chrome/browser/component_updater/cld_component_installer.h" -#include "chrome/common/chrome_constants.h" -#include "chrome/common/chrome_paths.h" +#include "components/translate/content/browser/data_file_browser_cld_data_provider.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" +namespace { +// This has to match what's in cld_component_installer.cc. +const base::FilePath::CharType kTestCldDataFileName[] = + FILE_PATH_LITERAL("cld2_data.bin"); +} // namespace + namespace component_updater { class CldComponentInstallerTest : public PlatformTest { public: + CldComponentInstallerTest() {} virtual void SetUp() OVERRIDE { PlatformTest::SetUp(); @@ -35,77 +41,85 @@ class CldComponentInstallerTest : public PlatformTest { // The "latest CLD data file" is a static piece of information, and thus // for correctness we empty it before each test. - traits.SetLatestCldDataFile(base::FilePath()); + component_updater::CldComponentInstallerTraits::SetLatestCldDataFile( + base::FilePath()); + base::FilePath path_now = + translate::DataFileBrowserCldDataProvider::GetCldDataFilePath(); + ASSERT_TRUE(path_now.empty()); } + protected: base::ScopedTempDir temp_dir_; - component_updater::CldComponentInstallerTraits traits; + component_updater::CldComponentInstallerTraits traits_; + + private: + DISALLOW_COPY_AND_ASSIGN(CldComponentInstallerTest); }; TEST_F(CldComponentInstallerTest, SetLatestCldDataFile) { - ASSERT_TRUE(component_updater::GetLatestCldDataFile().empty()); const base::FilePath expected(FILE_PATH_LITERAL("test/foo.test")); - traits.SetLatestCldDataFile(expected); - - base::FilePath result = component_updater::GetLatestCldDataFile(); + component_updater::CldComponentInstallerTraits::SetLatestCldDataFile( + expected); + base::FilePath result = + translate::DataFileBrowserCldDataProvider::GetCldDataFilePath(); ASSERT_EQ(expected, result); } TEST_F(CldComponentInstallerTest, VerifyInstallation) { // All files are created within a ScopedTempDir, which deletes all // children when its destructor is called (at the end of each test). - ASSERT_FALSE(traits.VerifyInstallation(temp_dir_.path())); + ASSERT_FALSE(traits_.VerifyInstallation(temp_dir_.path())); const base::FilePath data_file_dir = temp_dir_.path().Append(FILE_PATH_LITERAL("_platform_specific")).Append( FILE_PATH_LITERAL("all")); ASSERT_TRUE(base::CreateDirectory(data_file_dir)); - const base::FilePath data_file = - data_file_dir.Append(chrome::kCLDDataFilename); + const base::FilePath data_file = data_file_dir.Append(kTestCldDataFileName); const std::string test_data("fake cld2 data file content here :)"); ASSERT_EQ(static_cast<int32>(test_data.length()), base::WriteFile(data_file, test_data.c_str(), test_data.length())); - ASSERT_TRUE(traits.VerifyInstallation(temp_dir_.path())); + ASSERT_TRUE(traits_.VerifyInstallation(temp_dir_.path())); } TEST_F(CldComponentInstallerTest, OnCustomInstall) { const base::DictionaryValue manifest; const base::FilePath install_dir; // Sanity: shouldn't crash. - ASSERT_TRUE(traits.OnCustomInstall(manifest, install_dir)); + ASSERT_TRUE(traits_.OnCustomInstall(manifest, install_dir)); } TEST_F(CldComponentInstallerTest, GetInstalledPath) { const base::FilePath base_dir; const base::FilePath result = CldComponentInstallerTraits::GetInstalledPath(base_dir); - ASSERT_TRUE(EndsWith(result.value(), chrome::kCLDDataFilename, true)); + ASSERT_TRUE(EndsWith(result.value(), kTestCldDataFileName, true)); } TEST_F(CldComponentInstallerTest, GetBaseDirectory) { - const base::FilePath result = traits.GetBaseDirectory(); + const base::FilePath result = traits_.GetBaseDirectory(); ASSERT_FALSE(result.empty()); } TEST_F(CldComponentInstallerTest, GetHash) { std::vector<uint8> hash; - traits.GetHash(&hash); + traits_.GetHash(&hash); ASSERT_EQ(static_cast<size_t>(32), hash.size()); } TEST_F(CldComponentInstallerTest, GetName) { - ASSERT_FALSE(traits.GetName().empty()); + ASSERT_FALSE(traits_.GetName().empty()); } TEST_F(CldComponentInstallerTest, ComponentReady) { scoped_ptr<base::DictionaryValue> manifest; const base::FilePath install_dir(FILE_PATH_LITERAL("/foo")); const base::Version version("1.2.3.4"); - traits.ComponentReady(version, install_dir, manifest.Pass()); - base::FilePath result = component_updater::GetLatestCldDataFile(); + traits_.ComponentReady(version, install_dir, manifest.Pass()); + base::FilePath result = + translate::DataFileBrowserCldDataProvider::GetCldDataFilePath(); ASSERT_TRUE(StartsWith(result.AsUTF16Unsafe(), install_dir.AsUTF16Unsafe(), true)); - ASSERT_TRUE(EndsWith(result.value(), chrome::kCLDDataFilename, true)); + ASSERT_TRUE(EndsWith(result.value(), kTestCldDataFileName, true)); } } // namespace component_updater diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc index 04be3f5..0ab8cf3 100644 --- a/chrome/browser/policy/policy_browsertest.cc +++ b/chrome/browser/policy/policy_browsertest.cc @@ -57,7 +57,7 @@ #include "chrome/browser/search_engines/template_url_service.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/translate/chrome_translate_client.h" -#include "chrome/browser/translate/translate_browser_test_utils.h" +#include "chrome/browser/translate/cld_data_harness.h" #include "chrome/browser/translate/translate_service.h" #include "chrome/browser/ui/bookmarks/bookmark_bar.h" #include "chrome/browser/ui/browser.h" @@ -1870,8 +1870,9 @@ IN_PROC_BROWSER_TEST_F(PolicyTest, DISABLED_TranslateEnabled) { if (TranslateService::IsTranslateBubbleEnabled()) return; - test::ScopedCLDDynamicDataHarness dynamic_data_scope; - ASSERT_NO_FATAL_FAILURE(dynamic_data_scope.Init()); + scoped_ptr<test::CldDataHarness> cld_data_scope = + test::CreateCldDataHarness(); + ASSERT_NO_FATAL_FAILURE(cld_data_scope->Init()); // Verifies that translate can be forced enabled or disabled by policy. diff --git a/chrome/browser/translate/chrome_translate_client.cc b/chrome/browser/translate/chrome_translate_client.cc index 6abb359..2524441 100644 --- a/chrome/browser/translate/chrome_translate_client.cc +++ b/chrome/browser/translate/chrome_translate_client.cc @@ -40,17 +40,10 @@ #include "net/http/http_status_code.h" #include "url/gurl.h" -#if defined(CLD2_DYNAMIC_MODE) -#include "base/files/file.h" +#if defined(CLD_DATA_FROM_STANDALONE) #include "base/path_service.h" -#include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_process_host.h" -#endif - -#if defined(CLD2_IS_COMPONENT) -#include "chrome/browser/component_updater/cld_component_installer.h" +#include "components/translate/content/browser/data_file_browser_cld_data_provider.h" #endif namespace { @@ -59,25 +52,46 @@ namespace { // loading before giving up the translation const int kMaxTranslateLoadCheckAttempts = 20; -} // namespace +#if defined(CLD_DATA_FROM_STANDALONE) +// This build uses a standalone CLD2 data file. +// TODO(andrewhayden): Make the data file path into a gyp/gn define +// If you change this, also update standalone_cld_data_harness.cc +// accordingly! +const base::FilePath::CharType kCldDataFileName[] = + FILE_PATH_LITERAL("cld2_data.bin"); -DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromeTranslateClient); +bool g_cld_file_path_initialized_ = false; -#if defined(CLD2_DYNAMIC_MODE) -// Statics defined in the .h file: -base::File* ChromeTranslateClient::s_cached_file_ = NULL; -uint64 ChromeTranslateClient::s_cached_data_offset_ = 0; -uint64 ChromeTranslateClient::s_cached_data_length_ = 0; -base::LazyInstance<base::Lock> ChromeTranslateClient::s_file_lock_ = - LAZY_INSTANCE_INITIALIZER; +void InitCldFilePath() { + VLOG(1) << "Initializing CLD file path for the first time."; + base::FilePath path; + if (!PathService::Get(chrome::DIR_USER_DATA, &path)) { + LOG(WARNING) << "Unable to locate user data directory"; + return; // Chrome isn't properly installed + } + g_cld_file_path_initialized_ = true; + path = path.Append(kCldDataFileName); + VLOG(1) << "Setting CLD data file path: " << path.value(); + translate::DataFileBrowserCldDataProvider::SetCldDataFilePath(path); +} #endif +} // namespace + +DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromeTranslateClient); + ChromeTranslateClient::ChromeTranslateClient(content::WebContents* web_contents) : content::WebContentsObserver(web_contents), max_reload_check_attempts_(kMaxTranslateLoadCheckAttempts), translate_driver_(&web_contents->GetController()), translate_manager_(new TranslateManager(this, prefs::kAcceptLanguages)), + cld_data_provider_(translate::CreateBrowserCldDataProviderFor( + web_contents->GetRenderViewHost())), weak_pointer_factory_(this) { +#if defined(CLD_DATA_FROM_STANDALONE) + if (!g_cld_file_path_initialized_) + InitCldFilePath(); +#endif } ChromeTranslateClient::~ChromeTranslateClient() { @@ -257,12 +271,12 @@ bool ChromeTranslateClient::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ChromeViewHostMsg_TranslateLanguageDetermined, OnLanguageDetermined) IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PageTranslated, OnPageTranslated) -#if defined(CLD2_DYNAMIC_MODE) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_NeedCLDData, OnCLDDataRequested) -#endif IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() + if (!handled) { + handled = cld_data_provider_->OnMessageReceived(message); + } return handled; } @@ -333,141 +347,6 @@ void ChromeTranslateClient::WebContentsDestroyed() { translate_manager_.reset(); } -#if defined(CLD2_DYNAMIC_MODE) -void ChromeTranslateClient::OnCLDDataRequested() { - // Quickly try to read s_cached_file_. If valid, the file handle is - // cached and can be used immediately. Else, queue the caching task to the - // blocking pool. - base::File* handle = NULL; - uint64 data_offset = 0; - uint64 data_length = 0; - { - base::AutoLock lock(s_file_lock_.Get()); - handle = s_cached_file_; - data_offset = s_cached_data_offset_; - data_length = s_cached_data_length_; - } - - if (handle && handle->IsValid()) { - // Cached data available. Respond to the request. - SendCLDDataAvailable(handle, data_offset, data_length); - return; - } - - // Else, we don't have the data file yet. Queue a caching attempt. - // The caching attempt happens in the blocking pool because it may involve - // arbitrary filesystem access. - // After the caching attempt is made, we call MaybeSendCLDDataAvailable - // to pass the file handle to the renderer. This only results in an IPC - // message if the caching attempt was successful. - content::BrowserThread::PostBlockingPoolTaskAndReply( - FROM_HERE, - base::Bind(&ChromeTranslateClient::HandleCLDDataRequest), - base::Bind(&ChromeTranslateClient::MaybeSendCLDDataAvailable, - weak_pointer_factory_.GetWeakPtr())); -} - -void ChromeTranslateClient::MaybeSendCLDDataAvailable() { - base::File* handle = NULL; - uint64 data_offset = 0; - uint64 data_length = 0; - { - base::AutoLock lock(s_file_lock_.Get()); - handle = s_cached_file_; - data_offset = s_cached_data_offset_; - data_length = s_cached_data_length_; - } - - if (handle && handle->IsValid()) - SendCLDDataAvailable(handle, data_offset, data_length); -} - -void ChromeTranslateClient::SendCLDDataAvailable(const base::File* handle, - const uint64 data_offset, - const uint64 data_length) { - // Data available, respond to the request. - IPC::PlatformFileForTransit ipc_platform_file = IPC::GetFileHandleForProcess( - handle->GetPlatformFile(), - GetWebContents()->GetRenderViewHost()->GetProcess()->GetHandle(), - false); - // In general, sending a response from within the code path that is processing - // a request is discouraged because there is potential for deadlock (if the - // methods are sent synchronously) or loops (if the response can trigger a - // new request). Neither of these concerns is relevant in this code, so - // sending the response from within the code path of the request handler is - // safe. - Send(new ChromeViewMsg_CLDDataAvailable( - GetWebContents()->GetRenderViewHost()->GetRoutingID(), - ipc_platform_file, - data_offset, - data_length)); -} - -void ChromeTranslateClient::HandleCLDDataRequest() { - // Because this function involves arbitrary file system access, it must run - // on the blocking pool. - DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - - { - base::AutoLock lock(s_file_lock_.Get()); - if (s_cached_file_) - return; // Already done, duplicate request - } - -#if defined(CLD2_IS_COMPONENT) - base::FilePath path = component_updater::GetLatestCldDataFile(); - if (path.empty()) - return; -#else // CLD2 data is at a well-known file path - base::FilePath path; - if (!PathService::Get(chrome::DIR_USER_DATA, &path)) { - LOG(WARNING) << "Unable to locate user data directory"; - return; // Chrome isn't properly installed. - } - path = path.Append(chrome::kCLDDataFilename); -#endif - - // If the file exists, we can send an IPC-safe construct back to the - // renderer process immediately; otherwise, nothing to do here. - if (!base::PathExists(path)) - return; - - // Attempt to open the file for reading. - scoped_ptr<base::File> file( - new base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ)); - if (!file->IsValid()) { - LOG(WARNING) << "CLD data file exists but cannot be opened"; - return; - } - - base::File::Info file_info; - if (!file->GetInfo(&file_info)) { - LOG(WARNING) << "CLD data file exists but cannot be inspected"; - return; - } - - // For now, our offset and length are simply 0 and the length of the file, - // respectively. If we later decide to include the CLD2 data file inside of - // a larger binary context, these params can be twiddled appropriately. - const uint64 data_offset = 0; - const uint64 data_length = file_info.size; - - { - base::AutoLock lock(s_file_lock_.Get()); - if (s_cached_file_) { - // Idempotence: Racing another request on the blocking pool, abort. - } else { - // Else, this request has taken care of it all. Cache all info. - s_cached_file_ = file.release(); - s_cached_data_offset_ = data_offset; - s_cached_data_length_ = data_length; - } - } -} - -#endif // defined(CLD2_DYNAMIC_MODE) - void ChromeTranslateClient::InitiateTranslation(const std::string& page_lang, int attempt) { if (GetLanguageState().translation_pending()) diff --git a/chrome/browser/translate/chrome_translate_client.h b/chrome/browser/translate/chrome_translate_client.h index 681f1b1..1b475cd 100644 --- a/chrome/browser/translate/chrome_translate_client.h +++ b/chrome/browser/translate/chrome_translate_client.h @@ -10,6 +10,7 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/ui/translate/translate_bubble_model.h" +#include "components/translate/content/browser/browser_cld_data_provider.h" #include "components/translate/content/browser/content_translate_driver.h" #include "components/translate/core/browser/translate_client.h" #include "components/translate/core/browser/translate_step.h" @@ -17,13 +18,6 @@ #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" -#if defined(CLD2_DYNAMIC_MODE) -#include "base/basictypes.h" -#include "base/lazy_instance.h" -#include "base/synchronization/lock.h" -#include "base/task_runner.h" -#endif - namespace base { class File; } // namespace base @@ -108,7 +102,6 @@ class ChromeTranslateClient private: explicit ChromeTranslateClient(content::WebContents* web_contents); friend class content::WebContentsUserData<ChromeTranslateClient>; - friend class test::ScopedCLDDynamicDataHarness; // For cleaning static state. // content::WebContentsObserver implementation. virtual void NavigationEntryCommitted( @@ -128,41 +121,6 @@ class ChromeTranslateClient const std::string& translated_lang, TranslateErrors::Type error_type); -#if defined(CLD2_DYNAMIC_MODE) - // Called when we receive ChromeViewHostMsg_NeedCLDData from a renderer. - // If we have already cached the data, responds immediately; else, enqueues - // a HandleCLDDataRequest on the blocking pool to cache the data. - // Acquires and releases s_file_lock_ in a non-blocking manner; queries - // handled while the file is being cached will gracefully and immediately - // fail. - // It is up to the originator of the message to poll again later if required; - // no "negative response" will be generated. - void OnCLDDataRequested(); - - // Invoked on the blocking pool in order to cache the data. When successful, - // immediately responds to the request that initiated OnCLDDataRequested. - // Holds s_file_lock_ while the file is being cached. - static void HandleCLDDataRequest(); - - // If the CLD data is ready, send it to the renderer. Briefly checks the lock. - void MaybeSendCLDDataAvailable(); - - // Sends the renderer a response containing the data file handle. No locking. - void SendCLDDataAvailable(const base::File* handle, - const uint64 data_offset, - const uint64 data_length); - - // The data file, cached as long as the process stays alive. - // We also track the offset at which the data starts, and its length. - static base::File* s_cached_file_; // guarded by file_lock_ - static uint64 s_cached_data_offset_; // guarded by file_lock_ - static uint64 s_cached_data_length_; // guarded by file_lock_ - - // Guards s_cached_file_ - static base::LazyInstance<base::Lock> s_file_lock_; - -#endif - // Shows the translate bubble. void ShowBubble(translate::TranslateStep step, TranslateErrors::Type error_type); @@ -173,9 +131,9 @@ class ChromeTranslateClient ContentTranslateDriver translate_driver_; scoped_ptr<TranslateManager> translate_manager_; - // Necessary for binding the callback to HandleCLDDataRequest on the blocking - // pool and for delaying translation initialization until the page has - // finished loading on a reload. + // Provides CLD data for this process. + scoped_ptr<translate::BrowserCldDataProvider> cld_data_provider_; + base::WeakPtrFactory<ChromeTranslateClient> weak_pointer_factory_; DISALLOW_COPY_AND_ASSIGN(ChromeTranslateClient); diff --git a/chrome/browser/translate/cld_data_harness.cc b/chrome/browser/translate/cld_data_harness.cc new file mode 100644 index 0000000..9546d6f --- /dev/null +++ b/chrome/browser/translate/cld_data_harness.cc @@ -0,0 +1,32 @@ +// 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 "chrome/browser/translate/cld_data_harness.h" + +#include "base/path_service.h" +#include "chrome/common/chrome_paths.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { +// This constant yields the version of the CRX that has been extracted into +// the test data directory, and must be kept in sync with what is there. +// A reciprocal comment has been placed in +// chrome/test/data/cld2_component/README.chromium; don't update one without +// updating the other. +const base::FilePath::CharType kCrxVersion[] = FILE_PATH_LITERAL("160"); +} // namespace + +namespace test { + +const base::FilePath::CharType* CldDataHarness::GetTestDataSourceCrxVersion() { + return kCrxVersion; +} + +void CldDataHarness::GetTestDataSourceDirectory(base::FilePath* out_path) { + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, out_path)); + *out_path = + out_path->Append(FILE_PATH_LITERAL("cld2_component")).Append(kCrxVersion); +} + +} // namespace test diff --git a/chrome/browser/translate/cld_data_harness.h b/chrome/browser/translate/cld_data_harness.h new file mode 100644 index 0000000..59f01e3 --- /dev/null +++ b/chrome/browser/translate/cld_data_harness.h @@ -0,0 +1,80 @@ +// 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 CHROME_BROWSER_TRANSLATE_CLD_DATA_HARNESS_H_ +#define CHROME_BROWSER_TRANSLATE_CLD_DATA_HARNESS_H_ + +#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" + +namespace test { + +// A utility class that sets up CLD dynamic data upon calling Init() and cleans +// it up when destroyed. +// Test data lives under: src/chrome/test/data/cld2_component +// +// This class is intended to be instantiated within IN_PROC_BROWSER_TEST_F +// test fixtures; it uses ASSERT macros for correctness, so that tests will +// fail gracefully in error conditions. Sample use: +// +// IN_PROC_BROWSER_TEST_F(BrowserTest, PageLanguageDetection) { +// scoped_ptr<test::CldDataHarness> cld_data_scope = +// test::CreateCldDataHarness(); +// ASSERT_NO_FATAL_FAILURE(cld_data_scope->Init()); +// // ... your code that depends on language detection goes here +// } +// +// If you have a lot of tests that need language translation features, you can +// add an instance of the CldDataHarness to your test class' private +// member variables and add the call to Init() into SetUpOnMainThread. +// Sample use: +// +// class MyTestClass : public InProcessBrowserTest { +// public: +// MyTestClass() : +// cld_data_scope(test::CreateCldDataHarness()) { +// } +// virtual void SetUpOnMainThread() OVERRIDE { +// cld_data_scope->Init(); +// InProcessBrowserTest::SetUpOnMainThread(); +// } +// private: +// scoped_ptr<test::CldDataHarness> cld_data_scope; +// }; +// +class CldDataHarness { + public: + // Reverses the work done by the Init() method: any files and/or directories + // that would be created by Init() (whether it was called or not) are + // immediately deleted. + // If dynamic data is not currently available for any reason, this method has + // no effect. + virtual ~CldDataHarness() {} + + // Call this method, wrapping it in ASSERT_NO_FATAL_FAILURE, to initialize + // the harness and trigger test failure if initialization fails. + virtual void Init() = 0; + + protected: + // Returns the version number of the Component Updater "extension" in the + // test directory. This generally corresponds the the revision of CLD2 that + // the data was built from. The version number is also part of the path that + // would be present at runtime if the component installer was used as the + // CLD2 data source. + const base::FilePath::CharType* GetTestDataSourceCrxVersion(); + + // Returns the path to the Component Updater "extension" files in the test + // directory. Within, there is a real copy of the CLD2 dynamic data that can + // be used in testing scenarios without accessing the network. + void GetTestDataSourceDirectory(base::FilePath* out_path); +}; + +// Static factory function that returns a data harness defined by the +// implementation, which must be a subclass of CldDataHarness. +scoped_ptr<CldDataHarness> CreateCldDataHarness(); + +} // namespace test + +#endif // CHROME_BROWSER_TRANSLATE_CLD_DATA_HARNESS_H_ diff --git a/chrome/browser/translate/component_cld_data_harness.cc b/chrome/browser/translate/component_cld_data_harness.cc new file mode 100644 index 0000000..bf8c23d --- /dev/null +++ b/chrome/browser/translate/component_cld_data_harness.cc @@ -0,0 +1,99 @@ +// 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 "component_cld_data_harness.h" + +#include "base/base_paths.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "chrome/browser/component_updater/cld_component_installer.h" +#include "chrome/common/chrome_paths.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +// This has to match what's in cld_component_installer.cc. +const base::FilePath::CharType kComponentDataFileName[] = + FILE_PATH_LITERAL("cld2_data.bin"); + +} // namespace + +namespace test { + +ComponentCldDataHarness::ComponentCldDataHarness() { + // Constructor does nothing in all cases. See Init() for initialization. +} + +ComponentCldDataHarness::~ComponentCldDataHarness() { + VLOG(1) << "Tearing down CLD data harness"; + // Dynamic data mode is enabled and we are using the component updater. + component_updater::CldComponentInstallerTraits::SetLatestCldDataFile( + base::FilePath()); + ClearComponentDataFileState(); + DeleteComponentTree(); +} + +void ComponentCldDataHarness::Init() { + VLOG(1) << "Initializing CLD data harness"; + // Dynamic data mode is enabled and we are using the component updater. + ASSERT_NO_FATAL_FAILURE(CopyComponentTree()); + base::FilePath data_file; + GetComponentDataFileDestination(&data_file); + component_updater::CldComponentInstallerTraits::SetLatestCldDataFile( + data_file); +} + +void ComponentCldDataHarness::ClearComponentDataFileState() { + VLOG(1) << "Clearing component CLD data file state"; + base::FilePath nothing; + component_updater::CldComponentInstallerTraits::SetLatestCldDataFile(nothing); +} + +// DIR_COMPONENT_CLD2 is also defined as being relative to USER_DATA_DIR, so +// like GetStandaloneDataFileDestination, this is safe to run in multiple +// parallel test processes. +void ComponentCldDataHarness::GetExtractedComponentDestination( + base::FilePath* out_path) { + ASSERT_TRUE(PathService::Get(chrome::DIR_COMPONENT_CLD2, out_path)); +} + +void ComponentCldDataHarness::GetComponentDataFileDestination( + base::FilePath* out_path) { + GetExtractedComponentDestination(out_path); + *out_path = out_path->Append(CldDataHarness::GetTestDataSourceCrxVersion()) + .Append(FILE_PATH_LITERAL("_platform_specific")) + .Append(FILE_PATH_LITERAL("all")) + .Append(kComponentDataFileName); +} + +void ComponentCldDataHarness::DeleteComponentTree() { + base::FilePath tree_path; + ASSERT_NO_FATAL_FAILURE(GetExtractedComponentDestination(&tree_path)); + VLOG(1) << "Deleting CLD component test files from " << tree_path.value(); + base::DeleteFile(tree_path, true); +} + +void ComponentCldDataHarness::CopyComponentTree() { + DeleteComponentTree(); // sanity: blow away any old copies. + base::FilePath target_dir; + GetExtractedComponentDestination(&target_dir); + base::FilePath source_dir; + CldDataHarness::GetTestDataSourceDirectory(&source_dir); + VLOG(1) << "Copying CLD component test files from " << source_dir.value() + << " to " << target_dir.value(); + ASSERT_TRUE(base::CreateDirectoryAndGetError(target_dir, NULL)); + ASSERT_TRUE(base::CopyDirectory(source_dir, target_dir, true)); + ASSERT_TRUE(base::PathExists(target_dir)); + base::FilePath check_path; + GetComponentDataFileDestination(&check_path); + ASSERT_TRUE(base::PathExists(check_path)); +} + +scoped_ptr<CldDataHarness> CreateCldDataHarness() { + scoped_ptr<CldDataHarness> result(new ComponentCldDataHarness()); + return result.Pass(); +} + +} // namespace test diff --git a/chrome/browser/translate/component_cld_data_harness.h b/chrome/browser/translate/component_cld_data_harness.h new file mode 100644 index 0000000..0d8d9ec --- /dev/null +++ b/chrome/browser/translate/component_cld_data_harness.h @@ -0,0 +1,31 @@ +// 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 CHROME_BROWSER_TRANSLATE_COMPONENT_CLD_DATA_HARNESS_H_ +#define CHROME_BROWSER_TRANSLATE_COMPONENT_CLD_DATA_HARNESS_H_ + +#include "base/macros.h" +#include "chrome/browser/translate/cld_data_harness.h" + +namespace test { + +class ComponentCldDataHarness : public CldDataHarness { + public: + ComponentCldDataHarness(); + virtual ~ComponentCldDataHarness(); + virtual void Init() OVERRIDE; + + private: + void ClearComponentDataFileState(); + void GetExtractedComponentDestination(base::FilePath*); + void GetComponentDataFileDestination(base::FilePath*); + void DeleteComponentTree(); + void CopyComponentTree(); + + DISALLOW_COPY_AND_ASSIGN(ComponentCldDataHarness); +}; + +} // namespace test + +#endif // CHROME_BROWSER_TRANSLATE_COMPONENT_CLD_DATA_HARNESS_H_ diff --git a/chrome/browser/translate/standalone_cld_data_harness.cc b/chrome/browser/translate/standalone_cld_data_harness.cc new file mode 100644 index 0000000..6b8fe42 --- /dev/null +++ b/chrome/browser/translate/standalone_cld_data_harness.cc @@ -0,0 +1,82 @@ +// 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 "standalone_cld_data_harness.h" + +#include "base/base_paths.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "chrome/common/chrome_paths.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +// This has to match what's in chrome_translate_client.cc +const base::FilePath::CharType kStandaloneDataFileName[] = + FILE_PATH_LITERAL("cld2_data.bin"); + +} // namespace + +namespace test { + +StandaloneCldDataHarness::StandaloneCldDataHarness() { + // Constructor does nothing in all cases. See Init() for initialization. +} + +StandaloneCldDataHarness::~StandaloneCldDataHarness() { + VLOG(1) << "Tearing down CLD data harness"; + DeleteStandaloneDataFile(); +} + +void StandaloneCldDataHarness::Init() { + VLOG(1) << "Initializing CLD data harness"; + // Dynamic data mode is enabled and we are using a standalone file. + ASSERT_NO_FATAL_FAILURE(CopyStandaloneDataFile()); +} + +void StandaloneCldDataHarness::GetStandaloneDataFileSource( + base::FilePath* out_path) { + CldDataHarness::GetTestDataSourceDirectory(out_path); + *out_path = out_path->Append(FILE_PATH_LITERAL("_platform_specific")) + .Append(FILE_PATH_LITERAL("all")) + .Append(kStandaloneDataFileName); +} + +// Using the USER_DATA_DIR not only mimics true functionality, but also is +// important to test isolation. Each test gets its own USER_DATA_DIR, which +// ensures proper isolation between test processes running in parallel. +void StandaloneCldDataHarness::GetStandaloneDataFileDestination( + base::FilePath* out_path) { + ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, out_path)); + *out_path = out_path->Append(kStandaloneDataFileName); +} + +void StandaloneCldDataHarness::DeleteStandaloneDataFile() { + base::FilePath path; + ASSERT_NO_FATAL_FAILURE(GetStandaloneDataFileDestination(&path)); + VLOG(1) << "Deleting CLD test data file from " << path.value(); + base::DeleteFile(path, false); +} + +void StandaloneCldDataHarness::CopyStandaloneDataFile() { + DeleteStandaloneDataFile(); // sanity: blow away any old copies. + base::FilePath target_file; + GetStandaloneDataFileDestination(&target_file); + base::FilePath target_dir = target_file.DirName(); + ASSERT_TRUE(base::CreateDirectoryAndGetError(target_dir, NULL)); + base::FilePath source_file; + GetStandaloneDataFileSource(&source_file); + VLOG(1) << "Copying CLD test data file from " << source_file.value() << " to " + << target_file.value(); + ASSERT_TRUE(base::CopyFile(source_file, target_file)); + ASSERT_TRUE(base::PathExists(target_file)); +} + +scoped_ptr<CldDataHarness> CreateCldDataHarness() { + scoped_ptr<CldDataHarness> result(new StandaloneCldDataHarness()); + return result.Pass(); +} + +} // namespace test diff --git a/chrome/browser/translate/standalone_cld_data_harness.h b/chrome/browser/translate/standalone_cld_data_harness.h new file mode 100644 index 0000000..24b2869 --- /dev/null +++ b/chrome/browser/translate/standalone_cld_data_harness.h @@ -0,0 +1,29 @@ +// 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 CHROME_BROWSER_TRANSLATE_STANDALONE_CLD_DATA_HARNESS_H_ +#define CHROME_BROWSER_TRANSLATE_STANDALONE_CLD_DATA_HARNESS_H_ + +#include "chrome/browser/translate/cld_data_harness.h" + +namespace test { + +class StandaloneCldDataHarness : public CldDataHarness { + public: + StandaloneCldDataHarness(); + virtual ~StandaloneCldDataHarness(); + virtual void Init() OVERRIDE; + + private: + void GetStandaloneDataFileSource(base::FilePath*); + void GetStandaloneDataFileDestination(base::FilePath*); + void DeleteStandaloneDataFile(); + void CopyStandaloneDataFile(); + + DISALLOW_COPY_AND_ASSIGN(StandaloneCldDataHarness); +}; + +} // namespace test + +#endif // CHROME_BROWSER_TRANSLATE_STANDALONE_CLD_DATA_HARNESS_H_ diff --git a/chrome/browser/translate/static_cld_data_harness.cc b/chrome/browser/translate/static_cld_data_harness.cc new file mode 100644 index 0000000..aed2929 --- /dev/null +++ b/chrome/browser/translate/static_cld_data_harness.cc @@ -0,0 +1,26 @@ +// 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 "static_cld_data_harness.h" + +namespace test { + +StaticCldDataHarness::StaticCldDataHarness() { + // static data requires no special work +} + +StaticCldDataHarness::~StaticCldDataHarness() { + // static data requires no special work +} + +void StaticCldDataHarness::Init() { + // static data requires no special work +} + +scoped_ptr<CldDataHarness> CreateCldDataHarness() { + scoped_ptr<CldDataHarness> result(new StaticCldDataHarness()); + return result.Pass(); +} + +} // namespace test diff --git a/chrome/browser/translate/static_cld_data_harness.h b/chrome/browser/translate/static_cld_data_harness.h new file mode 100644 index 0000000..0d5c450 --- /dev/null +++ b/chrome/browser/translate/static_cld_data_harness.h @@ -0,0 +1,24 @@ +// 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 CHROME_BROWSER_TRANSLATE_STATIC_CLD_DATA_HARNESS_H_ +#define CHROME_BROWSER_TRANSLATE_STATIC_CLD_DATA_HARNESS_H_ + +#include "chrome/browser/translate/cld_data_harness.h" + +namespace test { + +class StaticCldDataHarness : public CldDataHarness { + public: + StaticCldDataHarness(); + virtual ~StaticCldDataHarness(); + virtual void Init() OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(StaticCldDataHarness); +}; + +} // namespace test + +#endif // CHROME_BROWSER_TRANSLATE_STATIC_CLD_DATA_HARNESS_H_ diff --git a/chrome/browser/translate/translate_browser_test_utils.cc b/chrome/browser/translate/translate_browser_test_utils.cc deleted file mode 100644 index 68d611c..0000000 --- a/chrome/browser/translate/translate_browser_test_utils.cc +++ /dev/null @@ -1,167 +0,0 @@ -// 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 "chrome/browser/translate/translate_browser_test_utils.h" - -#include "base/base_paths.h" -#include "base/file_util.h" -#include "base/logging.h" -#include "base/path_service.h" -#include "base/synchronization/lock.h" -#include "chrome/browser/component_updater/cld_component_installer.h" -#include "chrome/browser/translate/chrome_translate_client.h" -#include "chrome/common/chrome_constants.h" -#include "chrome/common/chrome_paths.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -// This constant yields the version of the CRX that has been extracted into -// the test data directory, and must be kept in sync with what is there. -// A reciprocal comment has been placed in -// chrome/test/data/cld2_component/README.chromium; don't update one without -// updating the other. -#if defined(CLD2_DYNAMIC_MODE) -const base::FilePath::CharType kCrxVersion[] = FILE_PATH_LITERAL("160"); - -void GetTestDataSourceDirectory(base::FilePath* out_path) { - ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, out_path)); - *out_path = out_path->Append(FILE_PATH_LITERAL("cld2_component")) - .Append(kCrxVersion); -} -#endif // defined(CLD2_DYNAMIC_MODE) - -#if defined(CLD2_DYNAMIC_MODE) && !defined(CLD2_IS_COMPONENT) -void GetStandaloneDataFileSource(base::FilePath* out_path) { - GetTestDataSourceDirectory(out_path); - *out_path = out_path->Append(FILE_PATH_LITERAL("_platform_specific")) - .Append(FILE_PATH_LITERAL("all")) - .Append(chrome::kCLDDataFilename); -} - -// Using the USER_DATA_DIR not only mimics true functionality, but also is -// important to test isolation. Each test gets its own USER_DATA_DIR, which -// ensures proper isolation between test processes running in parallel. -void GetStandaloneDataFileDestination(base::FilePath* out_path) { - ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, out_path)); - *out_path = out_path->Append(chrome::kCLDDataFilename); -} - -void DeleteStandaloneDataFile() { - base::FilePath path; - ASSERT_NO_FATAL_FAILURE(GetStandaloneDataFileDestination(&path)); - DLOG(INFO) << "Deleting CLD test data file from " << path.value(); - base::DeleteFile(path, false); -} - -void CopyStandaloneDataFile() { - DeleteStandaloneDataFile(); // sanity: blow away any old copies. - base::FilePath target_file; - GetStandaloneDataFileDestination(&target_file); - base::FilePath target_dir = target_file.DirName(); - ASSERT_TRUE(base::CreateDirectoryAndGetError(target_dir, NULL)); - base::FilePath source_file; - GetStandaloneDataFileSource(&source_file); - DLOG(INFO) << "Copying CLD test data file from " << source_file.value() - << " to " << target_file.value(); - ASSERT_TRUE(base::CopyFile(source_file, target_file)); - ASSERT_TRUE(base::PathExists(target_file)); -} -#endif // defined(CLD2_DYNAMIC_MODE) && !defined(CLD2_IS_COMPONENT) - -#if defined(CLD2_DYNAMIC_MODE) && defined(CLD2_IS_COMPONENT) -// DIR_COMPONENT_CLD2 is also defined as being relative to USER_DATA_DIR, so -// like GetStandaloneDataFileDestination, this is safe to run in multiple -// parallel test processes. -void GetExtractedComponentDestination(base::FilePath* out_path) { - ASSERT_TRUE(PathService::Get(chrome::DIR_COMPONENT_CLD2, out_path)); -} - -void GetComponentDataFileDestination(base::FilePath* out_path) { - GetExtractedComponentDestination(out_path); - *out_path = out_path->Append(kCrxVersion) - .Append(FILE_PATH_LITERAL("_platform_specific")) - .Append(FILE_PATH_LITERAL("all")) - .Append(chrome::kCLDDataFilename); -} - -void DeleteComponentTree() { - base::FilePath tree_path; - ASSERT_NO_FATAL_FAILURE(GetExtractedComponentDestination(&tree_path)); - DLOG(INFO) << "Deleting CLD component test files from " << tree_path.value(); - base::DeleteFile(tree_path, true); -} - -void CopyComponentTree() { - DeleteComponentTree(); // sanity: blow away any old copies. - base::FilePath target_dir; - GetExtractedComponentDestination(&target_dir); - base::FilePath source_dir; - GetTestDataSourceDirectory(&source_dir); - DLOG(INFO) << "Copying CLD component test files from " << source_dir.value() - << " to " << target_dir.value(); - ASSERT_TRUE(base::CreateDirectoryAndGetError(target_dir, NULL)); - ASSERT_TRUE(base::CopyDirectory(source_dir, target_dir, true)); - ASSERT_TRUE(base::PathExists(target_dir)); - base::FilePath check_path; - GetComponentDataFileDestination(&check_path); - ASSERT_TRUE(base::PathExists(check_path)); -} -#endif // defined(CLD2_DYNAMIC_MODE) && defined(CLD2_IS_COMPONENT) - -} // namespace - -namespace test { - -ScopedCLDDynamicDataHarness::ScopedCLDDynamicDataHarness() { - // Constructor does nothing in all cases. See Init() for initialization. -} - -ScopedCLDDynamicDataHarness::~ScopedCLDDynamicDataHarness() { - DLOG(INFO) << "Tearing down CLD data harness"; -#if defined(CLD2_DYNAMIC_MODE) && defined(CLD2_IS_COMPONENT) - // Dynamic data mode is enabled and we are using the component updater. - component_updater::CldComponentInstallerTraits::SetLatestCldDataFile( - base::FilePath()); - DeleteComponentTree(); -#elif defined(CLD2_DYNAMIC_MODE) - // Dynamic data mode is enabled and we are using a standalone file. - ClearStandaloneDataFileState(); - DeleteStandaloneDataFile(); -#endif // defined(CLD2_DYNAMIC_MODE) -} - -void ScopedCLDDynamicDataHarness::Init() { - DLOG(INFO) << "Initializing CLD data harness"; -#if defined(CLD2_DYNAMIC_MODE) && defined(CLD2_IS_COMPONENT) - // Dynamic data mode is enabled and we are using the component updater. - ASSERT_NO_FATAL_FAILURE(CopyComponentTree()); - base::FilePath data_file; - GetComponentDataFileDestination(&data_file); - component_updater::CldComponentInstallerTraits::SetLatestCldDataFile( - data_file); - base::FilePath result = component_updater::GetLatestCldDataFile(); - ASSERT_EQ(data_file, result); -#elif defined(CLD2_DYNAMIC_MODE) - // Dynamic data mode is enabled and we are using a standalone file. - ASSERT_NO_FATAL_FAILURE(ClearStandaloneDataFileState()); - ASSERT_NO_FATAL_FAILURE(CopyStandaloneDataFile()); -#endif // defined(CLD2_DYNAMIC_MODE) -} - -void ScopedCLDDynamicDataHarness::ClearStandaloneDataFileState() { -#if defined(CLD2_DYNAMIC_MODE) - DLOG(INFO) << "Clearing CLD data file state"; - // This code must live within the class in order to gain "friend" access. - base::AutoLock lock(ChromeTranslateClient::s_file_lock_.Get()); - if (ChromeTranslateClient::s_cached_file_) { - // Leaks any open handle, no way to avoid safely. - ChromeTranslateClient::s_cached_file_ = NULL; - ChromeTranslateClient::s_cached_data_offset_ = 0; - ChromeTranslateClient::s_cached_data_length_ = 0; - } -#endif // defined(CLD2_DYNAMIC_MODE) -} - -} // namespace test diff --git a/chrome/browser/translate/translate_browser_test_utils.h b/chrome/browser/translate/translate_browser_test_utils.h deleted file mode 100644 index c8ad85a..0000000 --- a/chrome/browser/translate/translate_browser_test_utils.h +++ /dev/null @@ -1,66 +0,0 @@ -// 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 CHROME_BROWSER_TRANSLATE_TRANSLATE_BROWSER_TEST_UTILS_H_ -#define CHROME_BROWSER_TRANSLATE_TRANSLATE_BROWSER_TEST_UTILS_H_ - -#include "base/macros.h" - -namespace test { - -// A utility class that sets up CLD dynamic data upon calling Init() and cleans -// it up when destroyed. -// Test data lives under: src/chrome/test/data/cld2_component -// -// This class is intended to be instantiated within IN_PROC_BROWSER_TEST_F -// test fixtures; it uses ASSERT macros for correctness, so that tests will -// fail gracefully in error conditions. Sample use: -// -// IN_PROC_BROWSER_TEST_F(BrowserTest, PageLanguageDetection) { -// test::ScopedCLDDynamicDataHarness dynamic_data_scope; -// ASSERT_NO_FATAL_FAILURE(dynamic_data_scope.Init()); -// // ... your code that depends on language detection goes here -// } -// -// If you have a lot of tests that need language translation features, you can -// add an instance of the ScopedCLDDynamicDataHarness to your test class' -// private member variables and add the call to Init() into SetUpOnMainThread. -// Sample use: -// -// class MyTestClass : public InProcessBrowserTest { -// public: -// virtual void SetUpOnMainThread() OVERRIDE { -// dynamic_data_scope.Init(); -// InProcessBrowserTest::SetUpOnMainThread(); -// } -// private: -// test::ScopedCLDDynamicDataHarness dynamic_data_scope; -// }; -// -class ScopedCLDDynamicDataHarness { - public: - // Constructs the object, but does nothing. Call Init() to prepare the - // harness, and enclose that call in ASSERT_NO_FATAL_FAILURE(...). - ScopedCLDDynamicDataHarness(); - - // Reverses the work done by the constructor: any files and/or directories - // that would be created by the constructor are immediately and irrevocably - // deleted. - // If dynamic data is not currently available for any reason, this method has - // no net effect on the runtime. - ~ScopedCLDDynamicDataHarness(); - - // Call this method, wrapping it in ASSERT_NO_FATAL_FAILURE, to initialize - // the harness and trigger test failure of initialization fails. - void Init(); - - private: - void ClearStandaloneDataFileState(); - - DISALLOW_COPY_AND_ASSIGN(ScopedCLDDynamicDataHarness); -}; - -} // namespace test - -#endif // CHROME_BROWSER_TRANSLATE_TRANSLATE_BROWSER_TEST_UTILS_H_ diff --git a/chrome/browser/translate/translate_manager_browsertest.cc b/chrome/browser/translate/translate_manager_browsertest.cc index f8bda83..f48dd2a 100644 --- a/chrome/browser/translate/translate_manager_browsertest.cc +++ b/chrome/browser/translate/translate_manager_browsertest.cc @@ -4,10 +4,11 @@ #include "components/translate/core/browser/translate_manager.h" +#include "base/memory/scoped_ptr.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/translate/chrome_translate_client.h" -#include "chrome/browser/translate/translate_browser_test_utils.h" +#include "chrome/browser/translate/cld_data_harness.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/in_process_browser_test.h" @@ -27,8 +28,9 @@ class TranslateManagerBrowserTest : public InProcessBrowserTest {}; // settings. IN_PROC_BROWSER_TEST_F(TranslateManagerBrowserTest, MAYBE_PRE_TranslateSessionRestore) { - test::ScopedCLDDynamicDataHarness dynamic_data_scope; - ASSERT_NO_FATAL_FAILURE(dynamic_data_scope.Init()); + scoped_ptr<test::CldDataHarness> cld_data_harness = + test::CreateCldDataHarness(); + ASSERT_NO_FATAL_FAILURE(cld_data_harness->Init()); SessionStartupPref pref(SessionStartupPref::LAST); SessionStartupPref::SetStartupPref(browser()->profile(), pref); @@ -62,8 +64,9 @@ IN_PROC_BROWSER_TEST_F(TranslateManagerBrowserTest, #endif IN_PROC_BROWSER_TEST_F(TranslateManagerBrowserTest, MAYBE_TranslateSessionRestore) { - test::ScopedCLDDynamicDataHarness dynamic_data_scope; - ASSERT_NO_FATAL_FAILURE(dynamic_data_scope.Init()); + scoped_ptr<test::CldDataHarness> cld_data_harness = + test::CreateCldDataHarness(); + ASSERT_NO_FATAL_FAILURE(cld_data_harness->Init()); content::WebContents* current_web_contents = browser()->tab_strip_model()->GetActiveWebContents(); content::Source<content::WebContents> source(current_web_contents); diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc index f4acb79..a33a737 100644 --- a/chrome/browser/ui/browser_browsertest.cc +++ b/chrome/browser/ui/browser_browsertest.cc @@ -8,6 +8,7 @@ #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/files/file_path.h" +#include "base/memory/scoped_ptr.h" #include "base/prefs/pref_service.h" #include "base/strings/utf_string_conversions.h" #include "base/sys_info.h" @@ -30,7 +31,7 @@ #include "chrome/browser/sessions/session_backend.h" #include "chrome/browser/sessions/session_service_factory.h" #include "chrome/browser/translate/chrome_translate_client.h" -#include "chrome/browser/translate/translate_browser_test_utils.h" +#include "chrome/browser/translate/cld_data_harness.h" #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h" #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h" #include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h" @@ -1405,8 +1406,9 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, ShouldShowLocationBar) { // Tests that the CLD (Compact Language Detection) works properly. IN_PROC_BROWSER_TEST_F(BrowserTest, PageLanguageDetection) { - test::ScopedCLDDynamicDataHarness dynamic_data_scope; - ASSERT_NO_FATAL_FAILURE(dynamic_data_scope.Init()); + scoped_ptr<test::CldDataHarness> cld_data_harness = + test::CreateCldDataHarness(); + ASSERT_NO_FATAL_FAILURE(cld_data_harness->Init()); ASSERT_TRUE(test_server()->Start()); LanguageDetectionDetails details; diff --git a/chrome/browser/ui/views/translate/translate_bubble_view_browsertest.cc b/chrome/browser/ui/views/translate/translate_bubble_view_browsertest.cc index d474164..d37e163 100644 --- a/chrome/browser/ui/views/translate/translate_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/translate/translate_bubble_view_browsertest.cc @@ -5,8 +5,9 @@ #include "chrome/browser/ui/views/translate/translate_bubble_view.h" #include "base/command_line.h" +#include "base/memory/scoped_ptr.h" #include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/translate/translate_browser_test_utils.h" +#include "chrome/browser/translate/cld_data_harness.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_tabstrip.h" @@ -19,17 +20,18 @@ class TranslateBubbleViewBrowserTest : public InProcessBrowserTest { public: - TranslateBubbleViewBrowserTest() {} + TranslateBubbleViewBrowserTest() + : cld_data_harness(test::CreateCldDataHarness()) {} virtual ~TranslateBubbleViewBrowserTest() {} virtual void SetUpOnMainThread() OVERRIDE { // We can't Init() until PathService has been initialized. This happens // very late in the test fixture setup process. - dynamic_data_scope.Init(); + cld_data_harness->Init(); InProcessBrowserTest::SetUpOnMainThread(); } private: - test::ScopedCLDDynamicDataHarness dynamic_data_scope; + scoped_ptr<test::CldDataHarness> cld_data_harness; DISALLOW_COPY_AND_ASSIGN(TranslateBubbleViewBrowserTest); }; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index a8fa7d9..a2c8d1d 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -443,8 +443,6 @@ 'browser/common/cancelable_request.h', 'browser/component_updater/background_downloader_win.cc', 'browser/component_updater/background_downloader_win.h', - 'browser/component_updater/cld_component_installer.cc', - 'browser/component_updater/cld_component_installer.h', 'browser/component_updater/component_patcher.cc', 'browser/component_updater/component_patcher.h', 'browser/component_updater/component_patcher_operation.cc', @@ -2749,6 +2747,12 @@ 'browser/media_galleries/fileapi/iphoto_file_util.h', ], }], + ['cld2_data_source=="component"', { + 'sources': [ + 'browser/component_updater/cld_component_installer.cc', + 'browser/component_updater/cld_component_installer.h', + ]}, + ], ['enable_extensions==1', { 'sources': [ # Only extension API implementations should go here. diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index 5131402..86c2953 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -275,6 +275,7 @@ '../components/components.gyp:data_reduction_proxy_common', '../components/components.gyp:startup_metric_utils', '../components/components.gyp:plugins_renderer', + '../components/components.gyp:translate_content_renderer', '../components/components.gyp:translate_core_common', '../components/components.gyp:translate_core_language_detection', '../components/components.gyp:visitedlink_renderer', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index e20c037..f45e67f 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1366,8 +1366,8 @@ 'browser/task_manager/task_manager_browsertest_util.h', 'browser/themes/theme_service_browsertest.cc', 'browser/translate/translate_browsertest.cc', - 'browser/translate/translate_browser_test_utils.cc', - 'browser/translate/translate_browser_test_utils.h', + 'browser/translate/cld_data_harness.cc', + 'browser/translate/cld_data_harness.h', 'browser/translate/translate_manager_browsertest.cc', 'browser/ui/app_list/app_list_controller_browsertest.cc', 'browser/ui/app_list/app_list_service_views_browsertest.cc', @@ -1646,6 +1646,24 @@ }, }, 'conditions': [ + ['cld2_data_source=="component"', { + 'sources': [ + 'browser/translate/component_cld_data_harness.cc', + 'browser/translate/component_cld_data_harness.h', + ]}, + ], + ['cld2_data_source=="standalone"', { + 'sources': [ + 'browser/translate/standalone_cld_data_harness.cc', + 'browser/translate/standalone_cld_data_harness.h', + ]}, + ], + ['cld2_data_source=="static"', { + 'sources': [ + 'browser/translate/static_cld_data_harness.cc', + 'browser/translate/static_cld_data_harness.h', + ]}, + ], ['enable_one_click_signin==0', { 'sources!': [ 'browser/ui/sync/one_click_signin_bubble_links_delegate_browsertest.cc', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 13ad3e6..c7d0087 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -807,7 +807,6 @@ 'browser/chromeos/ui/idle_app_name_notification_view_unittest.cc', 'browser/chromeos/version_loader_unittest.cc', 'browser/command_updater_unittest.cc', - 'browser/component_updater/test/cld_component_installer_unittest.cc', 'browser/component_updater/test/component_installers_unittest.cc', 'browser/component_updater/test/component_patcher_unittest.cc', 'browser/component_updater/test/component_updater_ping_manager_unittest.cc', @@ -2071,6 +2070,11 @@ 'includes': ['chrome_ios_bundle_resources.gypi'], 'xcode_settings': {'OTHER_LDFLAGS': ['-ObjC']}, }], + ['cld2_data_source=="component"', { + 'sources': [ + 'browser/component_updater/test/cld_component_installer_unittest.cc', + ]}, + ], ['enable_background==0', { 'sources/': [ ['exclude', '^browser/background/'], diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc index 37a00f8..4f76d4f 100644 --- a/chrome/common/chrome_constants.cc +++ b/chrome/common/chrome_constants.cc @@ -155,8 +155,6 @@ const base::FilePath::CharType kCacheDirname[] = FPL("Cache"); const base::FilePath::CharType kCookieFilename[] = FPL("Cookies"); const base::FilePath::CharType kCRLSetFilename[] = FPL("Certificate Revocation Lists"); -const base::FilePath::CharType kCLDDataFilename[] = - FPL("cld2_data.bin"); const base::FilePath::CharType kCustomDictionaryFileName[] = FPL("Custom Dictionary.txt"); const base::FilePath::CharType kExtensionActivityLogFilename[] = diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h index 4a5472b..6b85b5b 100644 --- a/chrome/common/chrome_constants.h +++ b/chrome/common/chrome_constants.h @@ -59,7 +59,6 @@ extern const base::FilePath::CharType kArchivedHistoryFilename[]; extern const base::FilePath::CharType kCacheDirname[]; extern const base::FilePath::CharType kCookieFilename[]; extern const base::FilePath::CharType kCRLSetFilename[]; -extern const base::FilePath::CharType kCLDDataFilename[]; extern const base::FilePath::CharType kCustomDictionaryFileName[]; extern const base::FilePath::CharType kExtensionActivityLogFilename[]; extern const base::FilePath::CharType kExtensionsCookieFilename[]; diff --git a/chrome/renderer/DEPS b/chrome/renderer/DEPS index d806f30..0eac425 100644 --- a/chrome/renderer/DEPS +++ b/chrome/renderer/DEPS @@ -9,6 +9,7 @@ include_rules = [ "+components/plugins/renderer", "+components/signin/core/common", "+components/translate/content/common", + "+components/translate/content/renderer", "+components/translate/core/common", "+components/translate/core/language_detection", "+components/visitedlink/renderer", diff --git a/chrome/renderer/translate/translate_helper.cc b/chrome/renderer/translate/translate_helper.cc index cd710ea..bc63a57 100644 --- a/chrome/renderer/translate/translate_helper.cc +++ b/chrome/renderer/translate/translate_helper.cc @@ -4,15 +4,8 @@ #include "chrome/renderer/translate/translate_helper.h" -#if defined(CLD2_DYNAMIC_MODE) -#include <stdint.h> -#endif - #include "base/bind.h" #include "base/compiler_specific.h" -#if defined(CLD2_DYNAMIC_MODE) -#include "base/files/memory_mapped_file.h" -#endif #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/strings/string16.h" @@ -28,10 +21,7 @@ #include "extensions/common/constants.h" #include "extensions/renderer/extension_groups.h" #include "ipc/ipc_platform_file.h" -#if defined(CLD2_DYNAMIC_MODE) #include "content/public/common/url_constants.h" -#include "third_party/cld_2/src/public/compact_lang_det.h" -#endif #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebElement.h" #include "third_party/WebKit/public/web/WebFrame.h" @@ -75,14 +65,11 @@ const char kAutoDetectionLanguage[] = "auto"; // Isolated world sets following content-security-policy. const char kContentSecurityPolicy[] = "script-src 'self' 'unsafe-eval'"; +// Whether or not we have set the CLD callback yet. +bool g_cld_callback_set = false; + } // namespace -#if defined(CLD2_DYNAMIC_MODE) -// The mmap for the CLD2 data must be held forever once it is available in the -// process. This is declared static in the translate_helper.h. -base::LazyInstance<TranslateHelper::CLDMmapWrapper>::Leaky - TranslateHelper::s_cld_mmap_ = LAZY_INSTANCE_INITIALIZER; -#endif //////////////////////////////////////////////////////////////////////////////// // TranslateHelper, public: @@ -91,29 +78,24 @@ TranslateHelper::TranslateHelper(content::RenderView* render_view) : content::RenderViewObserver(render_view), page_id_(-1), translation_pending_(false), - weak_method_factory_(this) -#if defined(CLD2_DYNAMIC_MODE) - ,cld2_data_file_polling_started_(false), - cld2_data_file_polling_canceled_(false), + weak_method_factory_(this), + cld_data_provider_(translate::CreateRendererCldDataProviderFor(this)), + cld_data_polling_started_(false), + cld_data_polling_canceled_(false), deferred_page_capture_(false), deferred_page_id_(-1), - deferred_contents_(ASCIIToUTF16("")) -#endif - { + deferred_contents_(ASCIIToUTF16("")) { } TranslateHelper::~TranslateHelper() { CancelPendingTranslation(); -#if defined(CLD2_DYNAMIC_MODE) - CancelCLD2DataFilePolling(); -#endif + CancelCldDataPolling(); } void TranslateHelper::PrepareForUrl(const GURL& url) { -#if defined(CLD2_DYNAMIC_MODE) deferred_page_capture_ = false; deferred_contents_.clear(); - if (cld2_data_file_polling_started_) + if (cld_data_polling_started_) return; // TODO(andrewhayden): Refactor translate_manager.cc's IsTranslatableURL to @@ -128,26 +110,20 @@ void TranslateHelper::PrepareForUrl(const GURL& url) { return; if (url.SchemeIs(url::kFtpScheme)) return; -#if defined(OS_CHROMEOS) - if (url.SchemeIs(extensions::kExtensionScheme) && - url.DomainIs(file_manager::kFileManagerAppId)) + if (url.SchemeIs(extensions::kExtensionScheme)) return; -#endif // Start polling for CLD data. - cld2_data_file_polling_started_ = true; - TranslateHelper::SendCLD2DataFileRequest(0, 1000); -#endif + cld_data_polling_started_ = true; + TranslateHelper::SendCldDataRequest(0, 1000); } -#if defined(CLD2_DYNAMIC_MODE) void TranslateHelper::DeferPageCaptured(const int page_id, const base::string16& contents) { deferred_page_capture_ = true; deferred_page_id_ = page_id; deferred_contents_ = contents; } -#endif void TranslateHelper::PageCaptured(int page_id, const base::string16& contents) { @@ -166,14 +142,13 @@ void TranslateHelper::PageCaptured(int page_id, // TODO(andrewhayden): UMA insertion point here: Track if data is available. // TODO(andrewhayden): Retry insertion point here, retry till data available. -#if defined(CLD2_DYNAMIC_MODE) - if (!CLD2::isDataLoaded()) { + if (!cld_data_provider_->IsCldDataAvailable()) { // We're in dynamic mode and CLD data isn't loaded. Retry when CLD data // is loaded, if ever. TranslateHelper::DeferPageCaptured(page_id, contents); return; } -#endif + page_id_ = page_id; WebDocument document = main_frame->document(); std::string content_language = document.contentLanguage().utf8(); @@ -218,9 +193,7 @@ void TranslateHelper::CancelPendingTranslation() { translation_pending_ = false; source_lang_.clear(); target_lang_.clear(); -#if defined(CLD2_DYNAMIC_MODE) - CancelCLD2DataFilePolling(); -#endif + CancelCldDataPolling(); } //////////////////////////////////////////////////////////////////////////////// @@ -395,11 +368,11 @@ bool TranslateHelper::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(TranslateHelper, message) IPC_MESSAGE_HANDLER(ChromeViewMsg_TranslatePage, OnTranslatePage) IPC_MESSAGE_HANDLER(ChromeViewMsg_RevertTranslation, OnRevertTranslation) -#if defined(CLD2_DYNAMIC_MODE) - IPC_MESSAGE_HANDLER(ChromeViewMsg_CLDDataAvailable, OnCLDDataAvailable); -#endif IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() + if (!handled) { + handled = cld_data_provider_->OnMessageReceived(message); + } return handled; } @@ -588,23 +561,29 @@ WebFrame* TranslateHelper::GetMainFrame() { return web_view->mainFrame(); } -#if defined(CLD2_DYNAMIC_MODE) -void TranslateHelper::CancelCLD2DataFilePolling() { - cld2_data_file_polling_canceled_ = true; +void TranslateHelper::CancelCldDataPolling() { + cld_data_polling_canceled_ = true; } -void TranslateHelper::SendCLD2DataFileRequest(const int delay_millis, - const int next_delay_millis) { +void TranslateHelper::SendCldDataRequest(const int delay_millis, + const int next_delay_millis) { // Terminate immediately if told to stop polling. - if (cld2_data_file_polling_canceled_) + if (cld_data_polling_canceled_) return; // Terminate immediately if data is already loaded. - if (CLD2::isDataLoaded()) + if (cld_data_provider_->IsCldDataAvailable()) return; - // Else, send the IPC message to the browser process requesting the data... - Send(new ChromeViewHostMsg_NeedCLDData(routing_id())); + if (!g_cld_callback_set) { + g_cld_callback_set = true; + cld_data_provider_->SetCldAvailableCallback( + base::Bind(&TranslateHelper::OnCldDataAvailable, + weak_method_factory_.GetWeakPtr())); + } + + // Else, make an asynchronous request to get the data we need. + cld_data_provider_->SendCldDataRequest(); // ... and enqueue another delayed task to call again. This will start a // chain of polling that will last until the pointer stops being NULL, @@ -616,68 +595,18 @@ void TranslateHelper::SendCLD2DataFileRequest(const int delay_millis, // Use a weak pointer to avoid keeping this helper object around forever. base::MessageLoop::current()->PostDelayedTask( FROM_HERE, - base::Bind(&TranslateHelper::SendCLD2DataFileRequest, + base::Bind(&TranslateHelper::SendCldDataRequest, weak_method_factory_.GetWeakPtr(), - next_delay_millis, next_delay_millis), + next_delay_millis, + next_delay_millis), base::TimeDelta::FromMilliseconds(delay_millis)); } -void TranslateHelper::OnCLDDataAvailable( - const IPC::PlatformFileForTransit ipc_file_handle, - const uint64 data_offset, - const uint64 data_length) { - LoadCLDDData(IPC::PlatformFileForTransitToFile(ipc_file_handle), data_offset, - data_length); - if (deferred_page_capture_ && CLD2::isDataLoaded()) { +void TranslateHelper::OnCldDataAvailable() { + if (deferred_page_capture_) { deferred_page_capture_ = false; // Don't do this a second time. PageCaptured(deferred_page_id_, deferred_contents_); deferred_page_id_ = -1; // Clean up for sanity deferred_contents_.clear(); // Clean up for sanity } } - -void TranslateHelper::LoadCLDDData( - base::File file, - const uint64 data_offset, - const uint64 data_length) { - // Terminate immediately if told to stop polling. - if (cld2_data_file_polling_canceled_) - return; - - // Terminate immediately if data is already loaded. - if (CLD2::isDataLoaded()) - return; - - if (!file.IsValid()) { - LOG(ERROR) << "Can't find the CLD data file."; - return; - } - - // mmap the file - s_cld_mmap_.Get().value = new base::MemoryMappedFile(); - bool initialized = s_cld_mmap_.Get().value->Initialize(file.Pass()); - if (!initialized) { - LOG(ERROR) << "mmap initialization failed"; - delete s_cld_mmap_.Get().value; - s_cld_mmap_.Get().value = NULL; - return; - } - - // Sanity checks - uint64 max_int32 = std::numeric_limits<int32>::max(); - if (data_length + data_offset > s_cld_mmap_.Get().value->length() - || data_length > max_int32) { // max signed 32 bit integer - LOG(ERROR) << "Illegal mmap config: data_offset=" - << data_offset << ", data_length=" << data_length - << ", mmap->length()=" << s_cld_mmap_.Get().value->length(); - delete s_cld_mmap_.Get().value; - s_cld_mmap_.Get().value = NULL; - return; - } - - // Initialize the CLD subsystem... and it's all done! - const uint8* data_ptr = s_cld_mmap_.Get().value->data() + data_offset; - CLD2::loadDataFromRawAddress(data_ptr, data_length); - DCHECK(CLD2::isDataLoaded()) << "Failed to load CLD data from mmap"; -} -#endif diff --git a/chrome/renderer/translate/translate_helper.h b/chrome/renderer/translate/translate_helper.h index febf6af..e78ee8a 100644 --- a/chrome/renderer/translate/translate_helper.h +++ b/chrome/renderer/translate/translate_helper.h @@ -8,25 +8,24 @@ #include <string> #include "base/gtest_prod_util.h" +#include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/strings/string16.h" #include "base/time/time.h" +#include "components/translate/content/renderer/renderer_cld_data_provider.h" #include "components/translate/core/common/translate_errors.h" #include "content/public/renderer/render_view_observer.h" - -#if defined(CLD2_DYNAMIC_MODE) -#include "base/files/file.h" -#include "base/files/memory_mapped_file.h" -#include "base/lazy_instance.h" -#include "ipc/ipc_platform_file.h" #include "url/gurl.h" -#endif namespace blink { class WebDocument; class WebFrame; } +namespace content { +class RendererCldDataProvider; +} + // This class deals with page translation. // There is one TranslateHelper per RenderView. @@ -146,6 +145,25 @@ class TranslateHelper : public content::RenderViewObserver { // if the page is being closed. blink::WebFrame* GetMainFrame(); + // Do not ask for CLD data any more. + void CancelCldDataPolling(); + + // Invoked when PageCaptured is called prior to obtaining CLD data. This + // method stores the page ID into deferred_page_id_ and COPIES the contents + // of the page, then sets deferred_page_capture_ to true. When CLD data is + // eventually received (in OnCldDataAvailable), any deferred request will be + // "resurrected" and allowed to proceed automatically, assuming that the + // page ID has not changed. + void DeferPageCaptured(const int page_id, const base::string16& contents); + + // Start polling for CLD data. + // Polling will automatically halt as soon as the renderer obtains a + // reference to the data file. + void SendCldDataRequest(const int delay_millis, const int next_delay_millis); + + // Callback triggered when CLD data becomes available. + void OnCldDataAvailable(); + // ID to represent a page which TranslateHelper captured and determined a // content language. int page_id_; @@ -162,57 +180,14 @@ class TranslateHelper : public content::RenderViewObserver { // Method factory used to make calls to TranslatePageImpl. base::WeakPtrFactory<TranslateHelper> weak_method_factory_; -#if defined(CLD2_DYNAMIC_MODE) - // Do not ask for CLD data any more. - void CancelCLD2DataFilePolling(); - - // Invoked when PageCaptured is called prior to obtaining CLD data. This - // method stores the page ID into deferred_page_id_ and COPIES the contents - // of the page, then sets deferred_page_capture_ to true. When CLD data is - // eventually received (in OnCLDDataAvailable), any deferred request will be - // "resurrected" and allowed to proceed automatically, assuming that the - // page ID has not changed. - void DeferPageCaptured(const int page_id, const base::string16& contents); - - // Immediately send an IPC request to the browser process to get the CLD - // data file. In most cases, the file will already exist and we will only - // poll once; but since the file might need to be downloaded first, poll - // indefinitely until a ChromeViewMsg_CLDDataAvailable message is received - // from the browser process. - // Polling will automatically halt as soon as the renderer obtains a - // reference to the data file. - void SendCLD2DataFileRequest(const int delay_millis, - const int next_delay_millis); - - // Invoked when a ChromeViewMsg_CLDDataAvailable message is received from - // the browser process, providing a file handle for the CLD data file. If a - // PageCaptured request was previously deferred with DeferPageCaptured and - // the page ID has not yet changed, the PageCaptured is reinvoked to - // "resurrect" the language detection pathway. - void OnCLDDataAvailable(const IPC::PlatformFileForTransit ipc_file_handle, - const uint64 data_offset, - const uint64 data_length); - - // After receiving data in OnCLDDataAvailable, loads the data into CLD2. - void LoadCLDDData(base::File file, - const uint64 data_offset, - const uint64 data_length); - - // A struct that contains the pointer to the CLD mmap. Used so that we can - // leverage LazyInstance:Leaky to properly scope the lifetime of the mmap. - struct CLDMmapWrapper { - CLDMmapWrapper() { - value = NULL; - } - base::MemoryMappedFile* value; - }; - static base::LazyInstance<CLDMmapWrapper>::Leaky s_cld_mmap_; + // Provides CLD data for this process. + scoped_ptr<translate::RendererCldDataProvider> cld_data_provider_; // Whether or not polling for CLD2 data has started. - bool cld2_data_file_polling_started_; + bool cld_data_polling_started_; - // Whether or not CancelCLD2DataFilePolling has been called. - bool cld2_data_file_polling_canceled_; + // Whether or not CancelCldDataPolling has been called. + bool cld_data_polling_canceled_; // Whether or not a PageCaptured event arrived prior to CLD data becoming // available. If true, deferred_page_id_ contains the most recent page ID @@ -227,8 +202,6 @@ class TranslateHelper : public content::RenderViewObserver { // deferred_page_capture_ is true. base::string16 deferred_contents_; -#endif - DISALLOW_COPY_AND_ASSIGN(TranslateHelper); }; diff --git a/components/translate.gypi b/components/translate.gypi index 5a15611..d4bba43 100644 --- a/components/translate.gypi +++ b/components/translate.gypi @@ -130,9 +130,24 @@ '..', ], 'sources': [ + 'translate/content/browser/browser_cld_data_provider.h', 'translate/content/browser/content_translate_driver.cc', 'translate/content/browser/content_translate_driver.h', ], + 'conditions': [ + ['cld2_data_source=="standalone" or cld2_data_source=="component"', { + 'sources': [ + 'translate/content/browser/data_file_browser_cld_data_provider.cc', + 'translate/content/browser/data_file_browser_cld_data_provider.h', + ]}, + ], + ['cld2_data_source=="static"', { + 'sources': [ + 'translate/content/browser/static_browser_cld_data_provider.cc', + 'translate/content/browser/static_browser_cld_data_provider.h', + ]}, + ], + ], }, { 'target_name': 'translate_content_common', @@ -151,6 +166,43 @@ 'translate/content/common/translate_messages.cc', 'translate/content/common/translate_messages.h', ], + 'conditions': [ + ['cld2_data_source=="standalone" or cld2_data_source=="component"', { + 'sources': [ + 'translate/content/common/data_file_cld_data_provider_messages.cc', + 'translate/content/common/data_file_cld_data_provider_messages.h', + ]}, + ], + ], + }, + { + 'target_name': 'translate_content_renderer', + 'type': 'static_library', + 'dependencies': [ + '../base/base.gyp:base', + '../content/content.gyp:content_common', + '../ipc/ipc.gyp:ipc', + ], + 'include_dirs': [ + '..', + ], + 'sources': [ + 'translate/content/renderer/renderer_cld_data_provider.h', + ], + 'conditions': [ + ['cld2_data_source=="standalone" or cld2_data_source=="component"', { + 'sources': [ + 'translate/content/renderer/data_file_renderer_cld_data_provider.cc', + 'translate/content/renderer/data_file_renderer_cld_data_provider.h', + ]}, + ], + ['cld2_data_source=="static"', { + 'sources': [ + 'translate/content/renderer/static_renderer_cld_data_provider.cc', + 'translate/content/renderer/static_renderer_cld_data_provider.h', + ]}, + ], + ], }, ], }], diff --git a/components/translate/content/browser/browser_cld_data_provider.h b/components/translate/content/browser/browser_cld_data_provider.h new file mode 100644 index 0000000..9634838 --- /dev/null +++ b/components/translate/content/browser/browser_cld_data_provider.h @@ -0,0 +1,64 @@ +// 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 COMPONENTS_TRANSLATE_CONTENT_BROWSER_BROWSER_CLD_DATA_PROVIDER_H_ +#define COMPONENTS_TRANSLATE_CONTENT_BROWSER_BROWSER_CLD_DATA_PROVIDER_H_ + +#include "ipc/ipc_listener.h" + +namespace IPC { +class Message; +} + +namespace content { +class RenderViewHost; +} + +namespace translate { + +// Browser-side interface responsible for providing CLD data. +// The implementation must be paired with a renderer-side implementation of +// the RendererCldDataProvider class: +// +// components/translate/content/renderer/renderer_cld_data_provider.h +// +// ... and the glue between them is typically a pair of request/response IPC +// messages using the CldDataProviderMsgStart IPCMessageStart enumerated +// constant from ipc_message_start.h +class BrowserCldDataProvider : public IPC::Listener { + public: + virtual ~BrowserCldDataProvider() {} + + // IPC::Listener implementation: + // If the specified message is a request for CLD data, invokes + // OnCldDataRequest() and returns true. In all other cases, this method does + // nothing. This method is defined as virtual in order to force the + // implementation to define the specific IPC message(s) that it handles. + virtual bool OnMessageReceived(const IPC::Message&) = 0; + + // Called when the browser process receives an appropriate message in + // OnMessageReceived, above. The implementation should attempt to locate + // the CLD data, cache any metadata required for accessing that data, and + // ultimately trigger a response by invoking SendCldDataResponse. + // + // The renderer process may poll for data, in which case this method may be + // repeatedly invoked. The implementation must be safe to call any number + // of times. + virtual void OnCldDataRequest() = 0; + + // Invoked when OnCldDataRequest, above, results in a successful lookup or + // the data is already cached and ready to respond to. The implementation + // should take whatever action is appropriate for responding to the paired + // RendererCldDataProvider, typically by sending an IPC response. + virtual void SendCldDataResponse() = 0; +}; + +// Static factory function defined by the implementation that produces a new +// provider for the specified render view host. +BrowserCldDataProvider* CreateBrowserCldDataProviderFor( + content::RenderViewHost*); + +} // namespace translate + +#endif // COMPONENTS_TRANSLATE_CONTENT_BROWSER_BROWSER_CLD_DATAP_PROVIDER_H_ diff --git a/components/translate/content/browser/data_file_browser_cld_data_provider.cc b/components/translate/content/browser/data_file_browser_cld_data_provider.cc new file mode 100644 index 0000000..97764aa --- /dev/null +++ b/components/translate/content/browser/data_file_browser_cld_data_provider.cc @@ -0,0 +1,224 @@ +// 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 "data_file_browser_cld_data_provider.h" + +#include "base/basictypes.h" +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/memory/weak_ptr.h" +#include "base/path_service.h" +#include "base/synchronization/lock.h" +#include "base/task_runner.h" +#include "components/translate/content/common/data_file_cld_data_provider_messages.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_macros.h" +#include "ipc/ipc_platform_file.h" + +namespace { +// The data file, cached as long as the process stays alive. +// We also track the offset at which the data starts, and its length. +base::FilePath g_cached_filepath; // guarded by g_file_lock_ +base::File* g_cached_file = NULL; // guarded by g_file_lock_ +uint64 g_cached_data_offset = -1; // guarded by g_file_lock_ +uint64 g_cached_data_length = -1; // guarded by g_file_lock_ + +// Guards g_cached_filepath +base::LazyInstance<base::Lock> g_file_lock_; +} // namespace + +namespace translate { + +// Implementation of the static factory method from BrowserCldDataProvider, +// hooking up this specific implementation for all of Chromium. +BrowserCldDataProvider* CreateBrowserCldDataProviderFor( + content::RenderViewHost* render_view_host) { + return new DataFileBrowserCldDataProvider(render_view_host); +} + +void DataFileBrowserCldDataProvider::SetCldDataFilePath( + const base::FilePath& path) { + VLOG(1) << "Setting CLD data file path to: " << path.value(); + base::AutoLock lock(g_file_lock_.Get()); + if (g_cached_filepath == path) + return; // no change necessary + g_cached_filepath = path; + // For sanity, clean these other values up just in case. + g_cached_file = NULL; + g_cached_data_length = -1; + g_cached_data_offset = -1; +} + +base::FilePath DataFileBrowserCldDataProvider::GetCldDataFilePath() { + base::AutoLock lock(g_file_lock_.Get()); + return g_cached_filepath; +} + +DataFileBrowserCldDataProvider::DataFileBrowserCldDataProvider( + content::RenderViewHost* render_view_host) + : render_view_host_(render_view_host), weak_pointer_factory_() { +} + +DataFileBrowserCldDataProvider::~DataFileBrowserCldDataProvider() { +} + +bool DataFileBrowserCldDataProvider::OnMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(DataFileBrowserCldDataProvider, message) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_NeedCldDataFile, OnCldDataRequest) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void DataFileBrowserCldDataProvider::OnCldDataRequest() { + // Quickly try to read g_cached_file. If valid, the file handle is + // cached and can be used immediately. Else, queue the caching task to the + // blocking pool. + VLOG(1) << "Received request for CLD data file."; + base::File* handle = NULL; + uint64 data_offset = 0; + uint64 data_length = 0; + { + base::AutoLock lock(g_file_lock_.Get()); + handle = g_cached_file; + data_offset = g_cached_data_offset; + data_length = g_cached_data_length; + } + + if (handle && handle->IsValid()) { + // Cached data available. Respond to the request. + VLOG(1) << "CLD data file is already cached, replying immediately."; + SendCldDataResponseInternal(handle, data_offset, data_length); + return; + } + + if (weak_pointer_factory_.get() == NULL) { + weak_pointer_factory_.reset( + new base::WeakPtrFactory<DataFileBrowserCldDataProvider>(this)); + weak_pointer_factory_.get()->GetWeakPtr().get(); + } + + // Else, we don't have the data file yet. Queue a caching attempt. + // The caching attempt happens in the blocking pool because it may involve + // arbitrary filesystem access. + // After the caching attempt is made, we call MaybeSendCLDDataAvailable + // to pass the file handle to the renderer. This only results in an IPC + // message if the caching attempt was successful. + VLOG(1) << "CLD data file not yet cached, deferring lookup"; + content::BrowserThread::PostBlockingPoolTaskAndReply( + FROM_HERE, + base::Bind(&DataFileBrowserCldDataProvider::OnCldDataRequestInternal), + base::Bind(&DataFileBrowserCldDataProvider::SendCldDataResponse, + weak_pointer_factory_.get()->GetWeakPtr())); +} + +void DataFileBrowserCldDataProvider::SendCldDataResponse() { + base::File* handle = NULL; + uint64 data_offset = 0; + uint64 data_length = 0; + { + base::AutoLock lock(g_file_lock_.Get()); + handle = g_cached_file; + data_offset = g_cached_data_offset; + data_length = g_cached_data_length; + } + + if (handle && handle->IsValid()) + SendCldDataResponseInternal(handle, data_offset, data_length); +} + +void DataFileBrowserCldDataProvider::SendCldDataResponseInternal( + const base::File* handle, + const uint64 data_offset, + const uint64 data_length) { + VLOG(1) << "Sending CLD data file response."; + // Data available, respond to the request. + IPC::PlatformFileForTransit ipc_platform_file = + IPC::GetFileHandleForProcess(handle->GetPlatformFile(), + render_view_host_->GetProcess()->GetHandle(), + false); + // In general, sending a response from within the code path that is processing + // a request is discouraged because there is potential for deadlock (if the + // methods are sent synchronously) or loops (if the response can trigger a + // new request). Neither of these concerns is relevant in this code, so + // sending the response from within the code path of the request handler is + // safe. + render_view_host_->Send( + new ChromeViewMsg_CldDataFileAvailable(render_view_host_->GetRoutingID(), + ipc_platform_file, + data_offset, + data_length)); +} + +void DataFileBrowserCldDataProvider::OnCldDataRequestInternal() { + // Because this function involves arbitrary file system access, it must run + // on the blocking pool. + DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + VLOG(1) << "CLD data file caching attempt starting."; + + { + base::AutoLock lock(g_file_lock_.Get()); + if (g_cached_file) { + VLOG(1) << "CLD data file is already cached, aborting caching attempt"; + return; // Already done, duplicate request + } + } + + const base::FilePath path = GetCldDataFilePath(); + if (path.empty()) { + VLOG(1) << "CLD data file does not yet have a known location."; + return; + } + + // If the file exists, we can send an IPC-safe construct back to the + // renderer process immediately; otherwise, nothing to do here. + if (!base::PathExists(path)) { + VLOG(1) << "CLD data file does not exist."; + return; + } + + // Attempt to open the file for reading. + scoped_ptr<base::File> file( + new base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ)); + if (!file->IsValid()) { + LOG(WARNING) << "CLD data file exists but cannot be opened"; + return; + } + + base::File::Info file_info; + if (!file->GetInfo(&file_info)) { + LOG(WARNING) << "CLD data file exists but cannot be inspected"; + return; + } + + // For now, our offset and length are simply 0 and the length of the file, + // respectively. If we later decide to include the CLD2 data file inside of + // a larger binary context, these params can be twiddled appropriately. + const uint64 data_offset = 0; + const uint64 data_length = file_info.size; + + { + base::AutoLock lock(g_file_lock_.Get()); + if (g_cached_file) { + // Idempotence: Racing another request on the blocking pool, abort. + VLOG(1) << "Another thread finished caching first, aborting."; + } else { + // Else, this request has taken care of it all. Cache all info. + VLOG(1) << "Caching CLD data file information."; + g_cached_file = file.release(); + g_cached_data_offset = data_offset; + g_cached_data_length = data_length; + } + } +} + +} // namespace translate diff --git a/components/translate/content/browser/data_file_browser_cld_data_provider.h b/components/translate/content/browser/data_file_browser_cld_data_provider.h new file mode 100644 index 0000000..fdac053 --- /dev/null +++ b/components/translate/content/browser/data_file_browser_cld_data_provider.h @@ -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. + +#ifndef COMPONENTS_TRANSLATE_CONTENT_BROWSER_DATA_FILE_BROWSER_CLD_DATA_PROVIDER_H_ +#define COMPONENTS_TRANSLATE_CONTENT_BROWSER_DATA_FILE_BROWSER_CLD_DATA_PROVIDER_H_ + +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "components/translate/content/browser/browser_cld_data_provider.h" + +namespace translate { + +class DataFileBrowserCldDataProvider : public BrowserCldDataProvider { + public: + explicit DataFileBrowserCldDataProvider(content::RenderViewHost*); + virtual ~DataFileBrowserCldDataProvider(); + // BrowserCldDataProvider implementations: + virtual bool OnMessageReceived(const IPC::Message&) OVERRIDE; + virtual void OnCldDataRequest() OVERRIDE; + virtual void SendCldDataResponse() OVERRIDE; + + // Sets the data file that this data provider will use to fulfill requests. + // This method does nothing if the specified path is equal to the path that + // is already configured. Otherwise, the specified path is cached and + // subsequent requests for data will attempt to load CLD data from the file + // at the specified path. + // This method is threadsafe. + static void SetCldDataFilePath(const base::FilePath& filePath); + + // Returns the path most recently set by SetDataFilePath. The initial value + // prior to any such call is the empty path. + // This method is threadsafe. + static base::FilePath GetCldDataFilePath(); + + private: + void SendCldDataResponseInternal(const base::File*, + const uint64, + const uint64); + static void OnCldDataRequestInternal(); + + content::RenderViewHost* render_view_host_; + scoped_ptr<base::WeakPtrFactory<DataFileBrowserCldDataProvider> > + weak_pointer_factory_; + + DISALLOW_COPY_AND_ASSIGN(DataFileBrowserCldDataProvider); +}; + +} // namespace translate + +#endif // COMPONENTS_TRANSLATE_CONTENT_BROWSER_DATA_FILE_BROWSER_CLD_DATA_PROVIDER_H_ diff --git a/components/translate/content/browser/static_browser_cld_data_provider.cc b/components/translate/content/browser/static_browser_cld_data_provider.cc new file mode 100644 index 0000000..3b5fab4 --- /dev/null +++ b/components/translate/content/browser/static_browser_cld_data_provider.cc @@ -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. + +#include "static_browser_cld_data_provider.h" + +#include "content/public/browser/render_view_host.h" +#include "ipc/ipc_message.h" + +namespace translate { + +// Implementation of the static factory method from BrowserCldDataProvider, +// hooking up this specific implementation for all of Chromium. +BrowserCldDataProvider* CreateBrowserCldDataProviderFor( + content::RenderViewHost* render_view_host) { + return new StaticBrowserCldDataProvider(); +} + +StaticBrowserCldDataProvider::StaticBrowserCldDataProvider() { +} + +StaticBrowserCldDataProvider::~StaticBrowserCldDataProvider() { +} + +bool StaticBrowserCldDataProvider::OnMessageReceived( + const IPC::Message& message) { + // No-op: data is statically linked + return false; +} + +void StaticBrowserCldDataProvider::OnCldDataRequest() { + // No-op: data is statically linked +} + +void StaticBrowserCldDataProvider::SendCldDataResponse() { + // No-op: data is statically linked +} + +} // namespace translate diff --git a/components/translate/content/browser/static_browser_cld_data_provider.h b/components/translate/content/browser/static_browser_cld_data_provider.h new file mode 100644 index 0000000..fe2ab0e --- /dev/null +++ b/components/translate/content/browser/static_browser_cld_data_provider.h @@ -0,0 +1,28 @@ +// 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 COMPONENTS_TRANSLATE_CONTENT_BROWSER_STATIC_BROWSER_CLD_DATA_PROVIDER_H_ +#define COMPONENTS_TRANSLATE_CONTENT_BROWSER_STATIC_BROWSER_CLD_DATA_PROVIDER_H_ + +#include "base/macros.h" +#include "components/translate/content/browser/browser_cld_data_provider.h" + +namespace translate { + +class StaticBrowserCldDataProvider : public BrowserCldDataProvider { + public: + explicit StaticBrowserCldDataProvider(); + virtual ~StaticBrowserCldDataProvider(); + // BrowserCldDataProvider implementations: + virtual bool OnMessageReceived(const IPC::Message&) OVERRIDE; + virtual void OnCldDataRequest() OVERRIDE; + virtual void SendCldDataResponse() OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(StaticBrowserCldDataProvider); +}; + +} // namespace translate + +#endif // COMPONENTS_TRANSLATE_CONTENT_BROWSER_STATIC_BROWSER_CLD_DATA_PROVIDER_H_ diff --git a/components/translate/content/common/data_file_cld_data_provider_messages.cc b/components/translate/content/common/data_file_cld_data_provider_messages.cc new file mode 100644 index 0000000..334fe2b --- /dev/null +++ b/components/translate/content/common/data_file_cld_data_provider_messages.cc @@ -0,0 +1,33 @@ +// 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. + +// Get basic type definitions. +#define IPC_MESSAGE_IMPL +#include "components/translate/content/common/data_file_cld_data_provider_messages.h" + +// Generate constructors. +#include "ipc/struct_constructor_macros.h" +#include "components/translate/content/common/data_file_cld_data_provider_messages.h" + +// Generate destructors. +#include "ipc/struct_destructor_macros.h" +#include "components/translate/content/common/data_file_cld_data_provider_messages.h" + +// Generate param traits write methods. +#include "ipc/param_traits_write_macros.h" +namespace IPC { +#include "components/translate/content/common/data_file_cld_data_provider_messages.h" +} // namespace IPC + +// Generate param traits read methods. +#include "ipc/param_traits_read_macros.h" +namespace IPC { +#include "components/translate/content/common/data_file_cld_data_provider_messages.h" +} // namespace IPC + +// Generate param traits log methods. +#include "ipc/param_traits_log_macros.h" +namespace IPC { +#include "components/translate/content/common/data_file_cld_data_provider_messages.h" +} // namespace IPC diff --git a/components/translate/content/common/data_file_cld_data_provider_messages.h b/components/translate/content/common/data_file_cld_data_provider_messages.h new file mode 100644 index 0000000..55fcb5f --- /dev/null +++ b/components/translate/content/common/data_file_cld_data_provider_messages.h @@ -0,0 +1,32 @@ +// 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. + +// Multiply-included message file, hence no include guard. + +#include "ipc/ipc_message_macros.h" +#include "ipc/ipc_message_utils.h" +#include "ipc/ipc_platform_file.h" + +// Note, for clean abstraction there is only one "CldDataProviderMessageStart" +// that is declared in ipc_message_start.h. All implementations share it, +// which avoids the need for each implementation to make its own entry. +// This would otherwise be very messy, as there is no mechanism to customize +// or extend the IPCMessageStart enum. +#define IPC_MESSAGE_START CldDataProviderMsgStart + +// Informs the browser process that Compact Language Detector (CLD) data is +// needed in the form of a data file. +// This message is sent by a DataFileRendererCldDataProvider to a +// DataFileBrowserCldDataProvider. +IPC_MESSAGE_ROUTED0(ChromeViewHostMsg_NeedCldDataFile) + +// Informs the renderer process that Compact Language Detector (CLD) data is +// available and provides an IPC::PlatformFileForTransit obtained from +// IPC::GetFileHandleForProcess(...) +// This message is sent by a DataFileBrowserCldDataProvider to a +// DataFileRendererCldDataProvider. +IPC_MESSAGE_ROUTED3(ChromeViewMsg_CldDataFileAvailable, + IPC::PlatformFileForTransit /* ipc_file_handle */, + uint64 /* data_offset */, + uint64 /* data_length */) diff --git a/components/translate/content/common/translate_messages.h b/components/translate/content/common/translate_messages.h index 617769a..7eab8a4 100644 --- a/components/translate/content/common/translate_messages.h +++ b/components/translate/content/common/translate_messages.h @@ -10,10 +10,6 @@ #include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_utils.h" -#if defined(CLD2_DYNAMIC_MODE) -#include "ipc/ipc_platform_file.h" -#endif - #define IPC_MESSAGE_START TranslateMsgStart IPC_ENUM_TRAITS(TranslateErrors::Type) @@ -43,17 +39,6 @@ IPC_MESSAGE_ROUTED4(ChromeViewMsg_TranslatePage, std::string /* BCP 47/RFC 5646 language code to translate to */) -#if defined(CLD2_DYNAMIC_MODE) -// Informs the renderer process that Compact Language Detector (CLD) data is -// available and provides an IPC::PlatformFileForTransit obtained from -// IPC::GetFileHandleForProcess(...) -// See also: ChromeViewHostMsg_NeedCLDData -IPC_MESSAGE_ROUTED3(ChromeViewMsg_CLDDataAvailable, - IPC::PlatformFileForTransit /* ipc_file_handle */, - uint64 /* data_offset */, - uint64 /* data_length */) -#endif - //----------------------------------------------------------------------------- // Misc messages // These are messages sent from the renderer to the browser process. @@ -74,12 +59,3 @@ IPC_MESSAGE_ROUTED4(ChromeViewHostMsg_PageTranslated, // contents. IPC_MESSAGE_ROUTED1(ChromeViewMsg_RevertTranslation, int /* page id */) - -#if defined(CLD2_DYNAMIC_MODE) -// Informs the browser process that Compact Language Detector (CLD) data is -// required by the originating renderer. The browser process should respond -// with a ChromeViewMsg_CLDDataAvailable if the data is available, else it -// should go unanswered (the renderer will ask again later). -// See also: ChromeViewMsg_CLDDataAvailable -IPC_MESSAGE_ROUTED0(ChromeViewHostMsg_NeedCLDData) -#endif diff --git a/components/translate/content/renderer/DEPS b/components/translate/content/renderer/DEPS new file mode 100644 index 0000000..826b97f --- /dev/null +++ b/components/translate/content/renderer/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+content/public/renderer", + "+third_party/cld_2", +] diff --git a/components/translate/content/renderer/data_file_renderer_cld_data_provider.cc b/components/translate/content/renderer/data_file_renderer_cld_data_provider.cc new file mode 100644 index 0000000..21609fb --- /dev/null +++ b/components/translate/content/renderer/data_file_renderer_cld_data_provider.cc @@ -0,0 +1,127 @@ +// 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 "data_file_renderer_cld_data_provider.h" + +#include "base/basictypes.h" +#include "base/files/file.h" +#include "base/files/memory_mapped_file.h" +#include "base/lazy_instance.h" +#include "components/translate/content/common/data_file_cld_data_provider_messages.h" +#include "content/public/renderer/render_view_observer.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_macros.h" +#include "ipc/ipc_platform_file.h" +#include "third_party/cld_2/src/public/compact_lang_det.h" + +namespace { + +// A struct that contains the pointer to the CLD mmap. Used so that we can +// leverage LazyInstance:Leaky to properly scope the lifetime of the mmap. +struct CLDMmapWrapper { + CLDMmapWrapper() { value = NULL; } + base::MemoryMappedFile* value; +}; +base::LazyInstance<CLDMmapWrapper>::Leaky g_cld_mmap = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + +namespace translate { + +// Implementation of the static factory method from RendererCldDataProvider, +// hooking up this specific implementation for all of Chromium. +RendererCldDataProvider* CreateRendererCldDataProviderFor( + content::RenderViewObserver* render_view_observer) { + return new DataFileRendererCldDataProvider(render_view_observer); +} + +DataFileRendererCldDataProvider::DataFileRendererCldDataProvider( + content::RenderViewObserver* render_view_observer) + : render_view_observer_(render_view_observer) { +} + +DataFileRendererCldDataProvider::~DataFileRendererCldDataProvider() { +} + +bool DataFileRendererCldDataProvider::OnMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(DataFileRendererCldDataProvider, message) + IPC_MESSAGE_HANDLER(ChromeViewMsg_CldDataFileAvailable, OnCldDataAvailable) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void DataFileRendererCldDataProvider::SendCldDataRequest() { + // Else, send the IPC message to the browser process requesting the data... + render_view_observer_->Send(new ChromeViewHostMsg_NeedCldDataFile( + render_view_observer_->routing_id())); +} + +bool DataFileRendererCldDataProvider::IsCldDataAvailable() { + // This neatly removes the need for code that depends on the generalized + // RendererCldDataProvider to #ifdef on CLD2_DYNAMIC_MODE + return CLD2::isDataLoaded(); // ground truth, independent of our state. +} + +void DataFileRendererCldDataProvider::SetCldAvailableCallback( + base::Callback<void(void)> callback) { + cld_available_callback_ = callback; +} + +void DataFileRendererCldDataProvider::OnCldDataAvailable( + const IPC::PlatformFileForTransit ipc_file_handle, + const uint64 data_offset, + const uint64 data_length) { + LoadCldData(IPC::PlatformFileForTransitToFile(ipc_file_handle), + data_offset, + data_length); +} + +void DataFileRendererCldDataProvider::LoadCldData(base::File file, + const uint64 data_offset, + const uint64 data_length) { + // Terminate immediately if data is already loaded. + if (IsCldDataAvailable()) + return; + + if (!file.IsValid()) { + LOG(ERROR) << "Can't find the CLD data file."; + return; + } + + // mmap the file + g_cld_mmap.Get().value = new base::MemoryMappedFile(); + bool initialized = g_cld_mmap.Get().value->Initialize(file.Pass()); + if (!initialized) { + LOG(ERROR) << "mmap initialization failed"; + delete g_cld_mmap.Get().value; + g_cld_mmap.Get().value = NULL; + return; + } + + // Sanity checks + uint64 max_int32 = std::numeric_limits<int32>::max(); + if (data_length + data_offset > g_cld_mmap.Get().value->length() || + data_length > max_int32) { // max signed 32 bit integer + LOG(ERROR) << "Illegal mmap config: data_offset=" << data_offset + << ", data_length=" << data_length + << ", mmap->length()=" << g_cld_mmap.Get().value->length(); + delete g_cld_mmap.Get().value; + g_cld_mmap.Get().value = NULL; + return; + } + + // Initialize the CLD subsystem... and it's all done! + const uint8* data_ptr = g_cld_mmap.Get().value->data() + data_offset; + CLD2::loadDataFromRawAddress(data_ptr, data_length); + DCHECK(CLD2::isDataLoaded()) << "Failed to load CLD data from mmap"; + if (!cld_available_callback_.is_null()) { + cld_available_callback_.Run(); + } +} + +} // namespace translate diff --git a/components/translate/content/renderer/data_file_renderer_cld_data_provider.h b/components/translate/content/renderer/data_file_renderer_cld_data_provider.h new file mode 100644 index 0000000..5c470b3 --- /dev/null +++ b/components/translate/content/renderer/data_file_renderer_cld_data_provider.h @@ -0,0 +1,40 @@ +// 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 COMPONENTS_TRANSLATE_CONTENT_RENDERER_DATA_FILE_RENDERER_CLD_DATA_PROVIDER_H_ +#define COMPONENTS_TRANSLATE_CONTENT_RENDERER_DATA_FILE_RENDERER_CLD_DATA_PROVIDER_H_ + +#include "base/files/file.h" +#include "base/macros.h" +#include "components/translate/content/renderer/renderer_cld_data_provider.h" +#include "ipc/ipc_platform_file.h" + +namespace translate { + +class DataFileRendererCldDataProvider : public RendererCldDataProvider { + public: + explicit DataFileRendererCldDataProvider(content::RenderViewObserver*); + virtual ~DataFileRendererCldDataProvider(); + // RendererCldDataProvider implementations: + virtual bool OnMessageReceived(const IPC::Message&) OVERRIDE; + virtual void SendCldDataRequest() OVERRIDE; + virtual void SetCldAvailableCallback(base::Callback<void(void)>) OVERRIDE; + virtual bool IsCldDataAvailable() OVERRIDE; + + private: + void OnCldDataAvailable(const IPC::PlatformFileForTransit ipc_file_handle, + const uint64 data_offset, + const uint64 data_length); + void LoadCldData(base::File file, + const uint64 data_offset, + const uint64 data_length); + content::RenderViewObserver* render_view_observer_; + base::Callback<void(void)> cld_available_callback_; + + DISALLOW_COPY_AND_ASSIGN(DataFileRendererCldDataProvider); +}; + +} // namespace translate + +#endif // COMPONENTS_TRANSLATE_CONTENT_RENDERER_DATA_FILE_RENDERER_CLD_DATA_PROVIDER_H_ diff --git a/components/translate/content/renderer/renderer_cld_data_provider.h b/components/translate/content/renderer/renderer_cld_data_provider.h new file mode 100644 index 0000000..4da053a --- /dev/null +++ b/components/translate/content/renderer/renderer_cld_data_provider.h @@ -0,0 +1,72 @@ +// 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 COMPONENTS_TRANSLATE_CONTENT_RENDERER_RENDERER_CLD_DATA_PROVIDER_H_ +#define COMPONENTS_TRANSLATE_CONTENT_RENDERER_RENDERER_CLD_DATA_PROVIDER_H_ + +#include "base/callback.h" +#include "ipc/ipc_listener.h" + +namespace IPC { +class Message; +} + +namespace content { +class RenderViewObserver; +} + +namespace translate { + +// Renderer-side interface responsible for providing CLD data. +// The implementation must be paired with a browser-side implementation of +// the BrowserCldDataProvider class: +// +// components/translate/content/browser/browser_cld_data_provider.h +// +// ... and the glue between them is typically a pair of request/response IPC +// messages using the CldDataProviderMsgStart IPCMessageStart enumerated +// constant from ipc_message_start.h +class RendererCldDataProvider : public IPC::Listener { + public: + virtual ~RendererCldDataProvider() {} + + // (Inherited from IPC::Listener) + // If the specified message is a response for CLD data, attempts to + // initialize CLD2 and returns true in all cases. If initialization is + // successful and a callback has been configured via + // SetCldAvailableCallback(...), that callback is invoked from the message + // loop thread. + // This method is defined as virtual in order to force the implementation to + // define the specific IPC message(s) that it handles. + virtual bool OnMessageReceived(const IPC::Message&) = 0; + + // Invoked by the renderer process to request that CLD data be obtained and + // that CLD be initialized with it. The implementation is expected to + // communicate with the paired BrowserCldDataProvider implementation on the + // browser side. + // This method must be invoked on the message loop thread. + virtual void SendCldDataRequest() = 0; + + // Convenience method that tracks whether or not CLD data is available. + // This method can be used in the absence of a callback (i.e., if the caller + // wants a simple way to check the state of CLD data availability without + // keeping a separate boolean flag tripped by a callback). + virtual bool IsCldDataAvailable() = 0; + + // Sets a callback that will be invoked when CLD data is successfully + // obtained from the paired BrowserCldDataProvider implementation on the + // browser side, after CLD has been successfully initialized. + // Both the initialization of CLD2 as well as the invocation of the callback + // must happen on the message loop thread. + virtual void SetCldAvailableCallback(base::Callback<void(void)>) = 0; +}; + +// Static factory function defined by the implementation that produces a new +// provider for the specified render view host. +RendererCldDataProvider* CreateRendererCldDataProviderFor( + content::RenderViewObserver*); + +} // namespace translate + +#endif // COMPONENTS_TRANSLATE_CONTENT_RENDERER_RENDERER_CLD_DATAP_PROVIDER_H_ diff --git a/components/translate/content/renderer/static_renderer_cld_data_provider.cc b/components/translate/content/renderer/static_renderer_cld_data_provider.cc new file mode 100644 index 0000000..bb2ccf1 --- /dev/null +++ b/components/translate/content/renderer/static_renderer_cld_data_provider.cc @@ -0,0 +1,45 @@ +// 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 "static_renderer_cld_data_provider.h" + +#include "content/public/renderer/render_view_observer.h" +#include "ipc/ipc_message.h" + +namespace translate { +// Implementation of the static factory method from RendererCldDataProvider, +// hooking up this specific implementation for all of Chromium. +RendererCldDataProvider* CreateRendererCldDataProviderFor( + content::RenderViewObserver* render_view_observer) { + return new StaticRendererCldDataProvider(); +} + +StaticRendererCldDataProvider::StaticRendererCldDataProvider() { +} + +StaticRendererCldDataProvider::~StaticRendererCldDataProvider() { +} + +bool StaticRendererCldDataProvider::OnMessageReceived( + const IPC::Message& message) { + // No-op: data is statically linked + return false; +} + +void StaticRendererCldDataProvider::SendCldDataRequest() { + // No-op: data is statically linked +} + +bool StaticRendererCldDataProvider::IsCldDataAvailable() { + // No-op: data is statically linked + return true; +} + +void StaticRendererCldDataProvider::SetCldAvailableCallback( + base::Callback<void(void)> callback) { + // Data is statically linked, so just call immediately. + callback.Run(); +} + +} // namespace translate diff --git a/components/translate/content/renderer/static_renderer_cld_data_provider.h b/components/translate/content/renderer/static_renderer_cld_data_provider.h new file mode 100644 index 0000000..fcd212b --- /dev/null +++ b/components/translate/content/renderer/static_renderer_cld_data_provider.h @@ -0,0 +1,34 @@ +// 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 COMPONENTS_TRANSLATE_CONTENT_RENDERER_STATIC_RENDERER_CLD_DATA_PROVIDER_H_ +#define COMPONENTS_TRANSLATE_CONTENT_RENDERER_STATIC_RENDERER_CLD_DATA_PROVIDER_H_ + +#include "base/files/file.h" +#include "base/files/memory_mapped_file.h" +#include "base/lazy_instance.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "components/translate/content/renderer/renderer_cld_data_provider.h" +#include "ipc/ipc_platform_file.h" + +namespace translate { + +class StaticRendererCldDataProvider : public RendererCldDataProvider { + public: + explicit StaticRendererCldDataProvider(); + virtual ~StaticRendererCldDataProvider(); + // RendererCldDataProvider implementations: + virtual bool OnMessageReceived(const IPC::Message&) OVERRIDE; + virtual void SendCldDataRequest() OVERRIDE; + virtual void SetCldAvailableCallback(base::Callback<void(void)>) OVERRIDE; + virtual bool IsCldDataAvailable() OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(StaticRendererCldDataProvider); +}; + +} // namespace translate + +#endif // COMPONENTS_TRANSLATE_CONTENT_RENDERER_STATIC_RENDERER_CLD_DATA_PROVIDER_H_ diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h index 8d813a2..8a401d9 100644 --- a/ipc/ipc_message_start.h +++ b/ipc/ipc_message_start.h @@ -102,6 +102,7 @@ enum IPCMessageStart { ChromeExtensionMsgStart, MojoMsgStart, TranslateMsgStart, + CldDataProviderMsgStart, PushMessagingMsgStart, GinJavaBridgeMsgStart, BatteryStatusMsgStart, diff --git a/third_party/cld_2/cld_2.gyp b/third_party/cld_2/cld_2.gyp index 377cd96..6626a47 100644 --- a/third_party/cld_2/cld_2.gyp +++ b/third_party/cld_2/cld_2.gyp @@ -158,7 +158,7 @@ 'msvs_disabled_warnings': [4267], }], # Dynamic or vanilla mode - ['cld2_dynamic==1', + ['cld2_data_source!="static"', { # Enable dynamic mode, which allows CLD to read its data from a file # instead of requiring the data to be linked into the library. |