Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(189)

Side by Side Diff: chrome/browser/translate/chrome_translate_client.cc

Issue 333603002: Modularize Compact Language Detector 2 (CLD2) data sources (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Takashi's comments and virtual destructors Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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(CLD2_DYNAMIC_MODE) && !defined(CLD2_IS_COMPONENT)
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"
49 #include "content/public/browser/render_process_host.h"
50 #endif 46 #endif
51 47
52 #if defined(CLD2_IS_COMPONENT) 48 namespace content {
droger 2014/06/19 16:13:18 The namespace should be translate, not content.
Andrew Hayden (chromium.org) 2014/06/19 19:49:30 Whoops. Cleanup on aisle 12! <sweep> <sweep> Done
53 #include "chrome/browser/component_updater/cld_component_installer.h" 49 // From:
54 #endif 50 // /components/translate/content/browser/data_file_browser_cld_data_provider.h
51 void SetCldDataFilePath(const base::FilePath&);
52 }
55 53
56 namespace { 54 namespace {
57 55
58 // The maximum number of attempts we'll do to see if the page has finshed 56 // The maximum number of attempts we'll do to see if the page has finshed
59 // loading before giving up the translation 57 // loading before giving up the translation
60 const int kMaxTranslateLoadCheckAttempts = 20; 58 const int kMaxTranslateLoadCheckAttempts = 20;
61 59
60 #if defined(CLD2_DYNAMIC_MODE) && !defined(CLD2_IS_COMPONENT)
61 // This build uses a standalone CLD2 data file.
62 // TODO(andrewhayden): Make the data file path into a gyp/gn define
63 const base::FilePath::CharType kCLDDataFilename[] =
64 FILE_PATH_LITERAL("cld2_data.bin");
65 bool s_cld_file_path_initialized_ = false;
66 void InitCldFilePath() {
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 s_cld_file_path_initialized_ = true;
73 path = path.Append(kCLDDataFilename);
74 content::SetCldDataFilePath(path);
75 }
76 #endif
77
62 } // namespace 78 } // namespace
63 79
64 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromeTranslateClient); 80 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ChromeTranslateClient);
65 81
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) 82 ChromeTranslateClient::ChromeTranslateClient(content::WebContents* web_contents)
76 : content::WebContentsObserver(web_contents), 83 : content::WebContentsObserver(web_contents),
77 max_reload_check_attempts_(kMaxTranslateLoadCheckAttempts), 84 max_reload_check_attempts_(kMaxTranslateLoadCheckAttempts),
78 translate_driver_(&web_contents->GetController()), 85 translate_driver_(&web_contents->GetController()),
79 translate_manager_(new TranslateManager(this, prefs::kAcceptLanguages)), 86 translate_manager_(new TranslateManager(this, prefs::kAcceptLanguages)),
87 cld_data_provider_(content::CreateBrowserCldDataProviderFor(
88 web_contents->GetRenderViewHost())),
80 weak_pointer_factory_(this) { 89 weak_pointer_factory_(this) {
90 #if defined(CLD2_DYNAMIC_MODE) && !defined(CLD2_IS_COMPONENT)
91 if (!s_cld_file_path_initialized_)
92 InitCldFilePath();
93 #endif
81 } 94 }
82 95
83 ChromeTranslateClient::~ChromeTranslateClient() { 96 ChromeTranslateClient::~ChromeTranslateClient() {
84 } 97 }
85 98
86 LanguageState& ChromeTranslateClient::GetLanguageState() { 99 LanguageState& ChromeTranslateClient::GetLanguageState() {
87 return translate_manager_->GetLanguageState(); 100 return translate_manager_->GetLanguageState();
88 } 101 }
89 102
90 // static 103 // static
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 browser, report_url, content::PAGE_TRANSITION_AUTO_BOOKMARK); 263 browser, report_url, content::PAGE_TRANSITION_AUTO_BOOKMARK);
251 #endif // defined(OS_ANDROID) 264 #endif // defined(OS_ANDROID)
252 } 265 }
253 266
254 bool ChromeTranslateClient::OnMessageReceived(const IPC::Message& message) { 267 bool ChromeTranslateClient::OnMessageReceived(const IPC::Message& message) {
255 bool handled = true; 268 bool handled = true;
256 IPC_BEGIN_MESSAGE_MAP(ChromeTranslateClient, message) 269 IPC_BEGIN_MESSAGE_MAP(ChromeTranslateClient, message)
257 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_TranslateLanguageDetermined, 270 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_TranslateLanguageDetermined,
258 OnLanguageDetermined) 271 OnLanguageDetermined)
259 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PageTranslated, OnPageTranslated) 272 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) 273 IPC_MESSAGE_UNHANDLED(handled = false)
264 IPC_END_MESSAGE_MAP() 274 IPC_END_MESSAGE_MAP()
265 275
276 if (!handled) {
277 handled = cld_data_provider_->OnMessageReceived(message);
278 }
266 return handled; 279 return handled;
267 } 280 }
268 281
269 void ChromeTranslateClient::NavigationEntryCommitted( 282 void ChromeTranslateClient::NavigationEntryCommitted(
270 const content::LoadCommittedDetails& load_details) { 283 const content::LoadCommittedDetails& load_details) {
271 // Check whether this is a reload: When doing a page reload, the 284 // Check whether this is a reload: When doing a page reload, the
272 // TranslateLanguageDetermined IPC is not sent so the translation needs to be 285 // TranslateLanguageDetermined IPC is not sent so the translation needs to be
273 // explicitly initiated. 286 // explicitly initiated.
274 287
275 content::NavigationEntry* entry = 288 content::NavigationEntry* entry =
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 details.is_in_page, details.is_main_frame, reload); 339 details.is_in_page, details.is_main_frame, reload);
327 } 340 }
328 341
329 void ChromeTranslateClient::WebContentsDestroyed() { 342 void ChromeTranslateClient::WebContentsDestroyed() {
330 // Translation process can be interrupted. 343 // Translation process can be interrupted.
331 // Destroying the TranslateManager now guarantees that it never has to deal 344 // Destroying the TranslateManager now guarantees that it never has to deal
332 // with NULL WebContents. 345 // with NULL WebContents.
333 translate_manager_.reset(); 346 translate_manager_.reset();
334 } 347 }
335 348
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, 349 void ChromeTranslateClient::InitiateTranslation(const std::string& page_lang,
472 int attempt) { 350 int attempt) {
473 if (GetLanguageState().translation_pending()) 351 if (GetLanguageState().translation_pending())
474 return; 352 return;
475 353
476 // During a reload we need web content to be available before the 354 // 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 355 // 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 356 // an empty DOM which will fail. Therefore we wait a bit to see if the page
479 // has finished. 357 // has finished.
480 if (web_contents()->IsLoading() && attempt < max_reload_check_attempts_) { 358 if (web_contents()->IsLoading() && attempt < max_reload_check_attempts_) {
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 if (GetLanguageState().InTranslateNavigation()) 436 if (GetLanguageState().InTranslateNavigation())
559 return; 437 return;
560 } 438 }
561 439
562 TranslateBubbleFactory::Show( 440 TranslateBubbleFactory::Show(
563 browser->window(), web_contents(), step, error_type); 441 browser->window(), web_contents(), step, error_type);
564 #else 442 #else
565 NOTREACHED(); 443 NOTREACHED();
566 #endif 444 #endif
567 } 445 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698