| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/translate/chrome_translate_client.h" | 5 #include "chrome/browser/translate/chrome_translate_client.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/prefs/pref_service.h" | 10 #include "base/prefs/pref_service.h" |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 #include "components/translate/core/common/language_detection_details.h" | 33 #include "components/translate/core/common/language_detection_details.h" |
| 34 #include "content/public/browser/navigation_details.h" | 34 #include "content/public/browser/navigation_details.h" |
| 35 #include "content/public/browser/navigation_entry.h" | 35 #include "content/public/browser/navigation_entry.h" |
| 36 #include "content/public/browser/notification_service.h" | 36 #include "content/public/browser/notification_service.h" |
| 37 #include "content/public/browser/render_view_host.h" | 37 #include "content/public/browser/render_view_host.h" |
| 38 #include "content/public/browser/web_contents.h" | 38 #include "content/public/browser/web_contents.h" |
| 39 #include "grit/theme_resources.h" | 39 #include "grit/theme_resources.h" |
| 40 #include "net/http/http_status_code.h" | 40 #include "net/http/http_status_code.h" |
| 41 #include "url/gurl.h" | 41 #include "url/gurl.h" |
| 42 | 42 |
| 43 #if defined(CLD2_DYNAMIC_MODE) | 43 #if defined(CLD_DATA_FROM_STANDALONE) |
| 44 #include "base/files/file.h" | |
| 45 #include "base/path_service.h" | 44 #include "base/path_service.h" |
| 46 #include "chrome/common/chrome_constants.h" | |
| 47 #include "chrome/common/chrome_paths.h" | 45 #include "chrome/common/chrome_paths.h" |
| 48 #include "content/public/browser/browser_thread.h" | 46 #include "components/translate/content/browser/data_file_browser_cld_data_provid
er.h" |
| 49 #include "content/public/browser/render_process_host.h" | |
| 50 #endif | |
| 51 | |
| 52 #if defined(CLD2_IS_COMPONENT) | |
| 53 #include "chrome/browser/component_updater/cld_component_installer.h" | |
| 54 #endif | 47 #endif |
| 55 | 48 |
| 56 namespace { | 49 namespace { |
| 57 | 50 |
| 58 // The maximum number of attempts we'll do to see if the page has finshed | 51 // The maximum number of attempts we'll do to see if the page has finshed |
| 59 // loading before giving up the translation | 52 // loading before giving up the translation |
| 60 const int kMaxTranslateLoadCheckAttempts = 20; | 53 const int kMaxTranslateLoadCheckAttempts = 20; |
| 61 | 54 |
| 55 #if defined(CLD_DATA_FROM_STANDALONE) |
| 56 // This build uses a standalone CLD2 data file. |
| 57 // TODO(andrewhayden): Make the data file path into a gyp/gn define |
| 58 // If you change this, also update standalone_cld_data_harness.cc |
| 59 // accordingly! |
| 60 const base::FilePath::CharType kCldDataFileName[] = |
| 61 FILE_PATH_LITERAL("cld2_data.bin"); |
| 62 |
| 63 bool g_cld_file_path_initialized_ = false; |
| 64 |
| 65 void InitCldFilePath() { |
| 66 VLOG(1) << "Initializing CLD file path for the first time."; |
| 67 base::FilePath path; |
| 68 if (!PathService::Get(chrome::DIR_USER_DATA, &path)) { |
| 69 LOG(WARNING) << "Unable to locate user data directory"; |
| 70 return; // Chrome isn't properly installed |
| 71 } |
| 72 g_cld_file_path_initialized_ = true; |
| 73 path = path.Append(kCldDataFileName); |
| 74 VLOG(1) << "Setting CLD data file path: " << path.value(); |
| 75 translate::DataFileBrowserCldDataProvider::SetCldDataFilePath(path); |
| 76 } |
| 77 #endif |
| 78 |
| 62 } // namespace | 79 } // namespace |
| 63 | 80 |
| 64 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromeTranslateClient); | 81 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromeTranslateClient); |
| 65 | 82 |
| 66 #if defined(CLD2_DYNAMIC_MODE) | |
| 67 // Statics defined in the .h file: | |
| 68 base::File* ChromeTranslateClient::s_cached_file_ = NULL; | |
| 69 uint64 ChromeTranslateClient::s_cached_data_offset_ = 0; | |
| 70 uint64 ChromeTranslateClient::s_cached_data_length_ = 0; | |
| 71 base::LazyInstance<base::Lock> ChromeTranslateClient::s_file_lock_ = | |
| 72 LAZY_INSTANCE_INITIALIZER; | |
| 73 #endif | |
| 74 | |
| 75 ChromeTranslateClient::ChromeTranslateClient(content::WebContents* web_contents) | 83 ChromeTranslateClient::ChromeTranslateClient(content::WebContents* web_contents) |
| 76 : content::WebContentsObserver(web_contents), | 84 : content::WebContentsObserver(web_contents), |
| 77 max_reload_check_attempts_(kMaxTranslateLoadCheckAttempts), | 85 max_reload_check_attempts_(kMaxTranslateLoadCheckAttempts), |
| 78 translate_driver_(&web_contents->GetController()), | 86 translate_driver_(&web_contents->GetController()), |
| 79 translate_manager_(new TranslateManager(this, prefs::kAcceptLanguages)), | 87 translate_manager_(new TranslateManager(this, prefs::kAcceptLanguages)), |
| 88 cld_data_provider_(translate::CreateBrowserCldDataProviderFor( |
| 89 web_contents->GetRenderViewHost())), |
| 80 weak_pointer_factory_(this) { | 90 weak_pointer_factory_(this) { |
| 91 #if defined(CLD_DATA_FROM_STANDALONE) |
| 92 if (!g_cld_file_path_initialized_) |
| 93 InitCldFilePath(); |
| 94 #endif |
| 81 } | 95 } |
| 82 | 96 |
| 83 ChromeTranslateClient::~ChromeTranslateClient() { | 97 ChromeTranslateClient::~ChromeTranslateClient() { |
| 84 } | 98 } |
| 85 | 99 |
| 86 LanguageState& ChromeTranslateClient::GetLanguageState() { | 100 LanguageState& ChromeTranslateClient::GetLanguageState() { |
| 87 return translate_manager_->GetLanguageState(); | 101 return translate_manager_->GetLanguageState(); |
| 88 } | 102 } |
| 89 | 103 |
| 90 // static | 104 // static |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 250 browser, report_url, content::PAGE_TRANSITION_AUTO_BOOKMARK); | 264 browser, report_url, content::PAGE_TRANSITION_AUTO_BOOKMARK); |
| 251 #endif // defined(OS_ANDROID) | 265 #endif // defined(OS_ANDROID) |
| 252 } | 266 } |
| 253 | 267 |
| 254 bool ChromeTranslateClient::OnMessageReceived(const IPC::Message& message) { | 268 bool ChromeTranslateClient::OnMessageReceived(const IPC::Message& message) { |
| 255 bool handled = true; | 269 bool handled = true; |
| 256 IPC_BEGIN_MESSAGE_MAP(ChromeTranslateClient, message) | 270 IPC_BEGIN_MESSAGE_MAP(ChromeTranslateClient, message) |
| 257 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_TranslateLanguageDetermined, | 271 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_TranslateLanguageDetermined, |
| 258 OnLanguageDetermined) | 272 OnLanguageDetermined) |
| 259 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PageTranslated, OnPageTranslated) | 273 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PageTranslated, OnPageTranslated) |
| 260 #if defined(CLD2_DYNAMIC_MODE) | |
| 261 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_NeedCLDData, OnCLDDataRequested) | |
| 262 #endif | |
| 263 IPC_MESSAGE_UNHANDLED(handled = false) | 274 IPC_MESSAGE_UNHANDLED(handled = false) |
| 264 IPC_END_MESSAGE_MAP() | 275 IPC_END_MESSAGE_MAP() |
| 265 | 276 |
| 277 if (!handled) { |
| 278 handled = cld_data_provider_->OnMessageReceived(message); |
| 279 } |
| 266 return handled; | 280 return handled; |
| 267 } | 281 } |
| 268 | 282 |
| 269 void ChromeTranslateClient::NavigationEntryCommitted( | 283 void ChromeTranslateClient::NavigationEntryCommitted( |
| 270 const content::LoadCommittedDetails& load_details) { | 284 const content::LoadCommittedDetails& load_details) { |
| 271 // Check whether this is a reload: When doing a page reload, the | 285 // Check whether this is a reload: When doing a page reload, the |
| 272 // TranslateLanguageDetermined IPC is not sent so the translation needs to be | 286 // TranslateLanguageDetermined IPC is not sent so the translation needs to be |
| 273 // explicitly initiated. | 287 // explicitly initiated. |
| 274 | 288 |
| 275 content::NavigationEntry* entry = | 289 content::NavigationEntry* entry = |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 details.is_in_page, details.is_main_frame, reload); | 340 details.is_in_page, details.is_main_frame, reload); |
| 327 } | 341 } |
| 328 | 342 |
| 329 void ChromeTranslateClient::WebContentsDestroyed() { | 343 void ChromeTranslateClient::WebContentsDestroyed() { |
| 330 // Translation process can be interrupted. | 344 // Translation process can be interrupted. |
| 331 // Destroying the TranslateManager now guarantees that it never has to deal | 345 // Destroying the TranslateManager now guarantees that it never has to deal |
| 332 // with NULL WebContents. | 346 // with NULL WebContents. |
| 333 translate_manager_.reset(); | 347 translate_manager_.reset(); |
| 334 } | 348 } |
| 335 | 349 |
| 336 #if defined(CLD2_DYNAMIC_MODE) | |
| 337 void ChromeTranslateClient::OnCLDDataRequested() { | |
| 338 // Quickly try to read s_cached_file_. If valid, the file handle is | |
| 339 // cached and can be used immediately. Else, queue the caching task to the | |
| 340 // blocking pool. | |
| 341 base::File* handle = NULL; | |
| 342 uint64 data_offset = 0; | |
| 343 uint64 data_length = 0; | |
| 344 { | |
| 345 base::AutoLock lock(s_file_lock_.Get()); | |
| 346 handle = s_cached_file_; | |
| 347 data_offset = s_cached_data_offset_; | |
| 348 data_length = s_cached_data_length_; | |
| 349 } | |
| 350 | |
| 351 if (handle && handle->IsValid()) { | |
| 352 // Cached data available. Respond to the request. | |
| 353 SendCLDDataAvailable(handle, data_offset, data_length); | |
| 354 return; | |
| 355 } | |
| 356 | |
| 357 // Else, we don't have the data file yet. Queue a caching attempt. | |
| 358 // The caching attempt happens in the blocking pool because it may involve | |
| 359 // arbitrary filesystem access. | |
| 360 // After the caching attempt is made, we call MaybeSendCLDDataAvailable | |
| 361 // to pass the file handle to the renderer. This only results in an IPC | |
| 362 // message if the caching attempt was successful. | |
| 363 content::BrowserThread::PostBlockingPoolTaskAndReply( | |
| 364 FROM_HERE, | |
| 365 base::Bind(&ChromeTranslateClient::HandleCLDDataRequest), | |
| 366 base::Bind(&ChromeTranslateClient::MaybeSendCLDDataAvailable, | |
| 367 weak_pointer_factory_.GetWeakPtr())); | |
| 368 } | |
| 369 | |
| 370 void ChromeTranslateClient::MaybeSendCLDDataAvailable() { | |
| 371 base::File* handle = NULL; | |
| 372 uint64 data_offset = 0; | |
| 373 uint64 data_length = 0; | |
| 374 { | |
| 375 base::AutoLock lock(s_file_lock_.Get()); | |
| 376 handle = s_cached_file_; | |
| 377 data_offset = s_cached_data_offset_; | |
| 378 data_length = s_cached_data_length_; | |
| 379 } | |
| 380 | |
| 381 if (handle && handle->IsValid()) | |
| 382 SendCLDDataAvailable(handle, data_offset, data_length); | |
| 383 } | |
| 384 | |
| 385 void ChromeTranslateClient::SendCLDDataAvailable(const base::File* handle, | |
| 386 const uint64 data_offset, | |
| 387 const uint64 data_length) { | |
| 388 // Data available, respond to the request. | |
| 389 IPC::PlatformFileForTransit ipc_platform_file = IPC::GetFileHandleForProcess( | |
| 390 handle->GetPlatformFile(), | |
| 391 GetWebContents()->GetRenderViewHost()->GetProcess()->GetHandle(), | |
| 392 false); | |
| 393 // In general, sending a response from within the code path that is processing | |
| 394 // a request is discouraged because there is potential for deadlock (if the | |
| 395 // methods are sent synchronously) or loops (if the response can trigger a | |
| 396 // new request). Neither of these concerns is relevant in this code, so | |
| 397 // sending the response from within the code path of the request handler is | |
| 398 // safe. | |
| 399 Send(new ChromeViewMsg_CLDDataAvailable( | |
| 400 GetWebContents()->GetRenderViewHost()->GetRoutingID(), | |
| 401 ipc_platform_file, | |
| 402 data_offset, | |
| 403 data_length)); | |
| 404 } | |
| 405 | |
| 406 void ChromeTranslateClient::HandleCLDDataRequest() { | |
| 407 // Because this function involves arbitrary file system access, it must run | |
| 408 // on the blocking pool. | |
| 409 DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
| 410 DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 411 | |
| 412 { | |
| 413 base::AutoLock lock(s_file_lock_.Get()); | |
| 414 if (s_cached_file_) | |
| 415 return; // Already done, duplicate request | |
| 416 } | |
| 417 | |
| 418 #if defined(CLD2_IS_COMPONENT) | |
| 419 base::FilePath path = component_updater::GetLatestCldDataFile(); | |
| 420 if (path.empty()) | |
| 421 return; | |
| 422 #else // CLD2 data is at a well-known file path | |
| 423 base::FilePath path; | |
| 424 if (!PathService::Get(chrome::DIR_USER_DATA, &path)) { | |
| 425 LOG(WARNING) << "Unable to locate user data directory"; | |
| 426 return; // Chrome isn't properly installed. | |
| 427 } | |
| 428 path = path.Append(chrome::kCLDDataFilename); | |
| 429 #endif | |
| 430 | |
| 431 // If the file exists, we can send an IPC-safe construct back to the | |
| 432 // renderer process immediately; otherwise, nothing to do here. | |
| 433 if (!base::PathExists(path)) | |
| 434 return; | |
| 435 | |
| 436 // Attempt to open the file for reading. | |
| 437 scoped_ptr<base::File> file( | |
| 438 new base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ)); | |
| 439 if (!file->IsValid()) { | |
| 440 LOG(WARNING) << "CLD data file exists but cannot be opened"; | |
| 441 return; | |
| 442 } | |
| 443 | |
| 444 base::File::Info file_info; | |
| 445 if (!file->GetInfo(&file_info)) { | |
| 446 LOG(WARNING) << "CLD data file exists but cannot be inspected"; | |
| 447 return; | |
| 448 } | |
| 449 | |
| 450 // For now, our offset and length are simply 0 and the length of the file, | |
| 451 // respectively. If we later decide to include the CLD2 data file inside of | |
| 452 // a larger binary context, these params can be twiddled appropriately. | |
| 453 const uint64 data_offset = 0; | |
| 454 const uint64 data_length = file_info.size; | |
| 455 | |
| 456 { | |
| 457 base::AutoLock lock(s_file_lock_.Get()); | |
| 458 if (s_cached_file_) { | |
| 459 // Idempotence: Racing another request on the blocking pool, abort. | |
| 460 } else { | |
| 461 // Else, this request has taken care of it all. Cache all info. | |
| 462 s_cached_file_ = file.release(); | |
| 463 s_cached_data_offset_ = data_offset; | |
| 464 s_cached_data_length_ = data_length; | |
| 465 } | |
| 466 } | |
| 467 } | |
| 468 | |
| 469 #endif // defined(CLD2_DYNAMIC_MODE) | |
| 470 | |
| 471 void ChromeTranslateClient::InitiateTranslation(const std::string& page_lang, | 350 void ChromeTranslateClient::InitiateTranslation(const std::string& page_lang, |
| 472 int attempt) { | 351 int attempt) { |
| 473 if (GetLanguageState().translation_pending()) | 352 if (GetLanguageState().translation_pending()) |
| 474 return; | 353 return; |
| 475 | 354 |
| 476 // During a reload we need web content to be available before the | 355 // During a reload we need web content to be available before the |
| 477 // translate script is executed. Otherwise we will run the translate script on | 356 // translate script is executed. Otherwise we will run the translate script on |
| 478 // an empty DOM which will fail. Therefore we wait a bit to see if the page | 357 // an empty DOM which will fail. Therefore we wait a bit to see if the page |
| 479 // has finished. | 358 // has finished. |
| 480 if (web_contents()->IsLoading() && attempt < max_reload_check_attempts_) { | 359 if (web_contents()->IsLoading() && attempt < max_reload_check_attempts_) { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 558 if (GetLanguageState().InTranslateNavigation()) | 437 if (GetLanguageState().InTranslateNavigation()) |
| 559 return; | 438 return; |
| 560 } | 439 } |
| 561 | 440 |
| 562 TranslateBubbleFactory::Show( | 441 TranslateBubbleFactory::Show( |
| 563 browser->window(), web_contents(), step, error_type); | 442 browser->window(), web_contents(), step, error_type); |
| 564 #else | 443 #else |
| 565 NOTREACHED(); | 444 NOTREACHED(); |
| 566 #endif | 445 #endif |
| 567 } | 446 } |
| OLD | NEW |