Index: chrome/renderer/translate/translate_helper.cc |
diff --git a/chrome/renderer/translate/translate_helper.cc b/chrome/renderer/translate/translate_helper.cc |
index ccd2279a294de5603fb918002707f27b268f5817..488a38e9e38cb0fc4cbf28ec5dc492877c071416 100644 |
--- a/chrome/renderer/translate/translate_helper.cc |
+++ b/chrome/renderer/translate/translate_helper.cc |
@@ -6,6 +6,7 @@ |
#include "base/bind.h" |
#include "base/compiler_specific.h" |
+#include "base/files/memory_mapped_file.h" |
#include "base/logging.h" |
#include "base/message_loop/message_loop.h" |
#include "base/strings/string16.h" |
@@ -19,6 +20,11 @@ |
#include "components/translate/core/common/translate_util.h" |
#include "components/translate/language_detection/language_detection_util.h" |
#include "content/public/renderer/render_view.h" |
+#include "extensions/common/constants.h" |
+#include "ipc/ipc_platform_file.h" |
+#if defined(CLD2_DYNAMIC_MODE) |
+#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" |
@@ -53,7 +59,7 @@ const int kTranslateInitCheckDelayMs = 150; |
const int kMaxTranslateInitCheckAttempts = 5; |
// The delay we wait in milliseconds before checking whether the translation has |
-// finished. |
+// finished.cld2_data_file = NULL; |
Takashi Toyoshima
2014/03/13 18:37:37
paste it mistakenly?
Andrew Hayden (chromium.org)
2014/03/14 10:10:52
Done.
|
const int kTranslateStatusCheckDelayMs = 400; |
// Language name passed to the Translate element for it to detect the language. |
@@ -72,12 +78,48 @@ TranslateHelper::TranslateHelper(content::RenderView* 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; |
+ deferred_page_capture_ = false; |
+ deferred_page_id_ = -1; |
palmer
2014/03/13 17:59:50
Put these up above in the : initialization list.
Andrew Hayden (chromium.org)
2014/03/13 23:20:21
Done.
|
+ deferred_contents_ = ASCIIToUTF16(""); |
+#endif |
} |
TranslateHelper::~TranslateHelper() { |
CancelPendingTranslation(); |
+#if defined(CLD2_DYNAMIC_MODE) |
+ CancelCLD2DataFilePolling(); |
+#endif |
} |
+void TranslateHelper::PrepareForUrl(const GURL& url) { |
+#if defined(CLD2_DYNAMIC_MODE) |
Takashi Toyoshima
2014/03/13 18:37:37
you may want to reset deferred_* here?
Andrew Hayden (chromium.org)
2014/03/14 10:10:52
Hmm, good thought. It's SAFE to leave it alone, be
|
+ if (cld2_data_file_polling_started) return; |
palmer
2014/03/13 17:59:50
Style nit.
Andrew Hayden (chromium.org)
2014/03/13 23:20:21
Done.
|
+ |
+ // There is no reason to ever bother loading CLD data for an extension URL. |
+ // There's also no render_view_host_observer to answer us, so don't ask for |
+ // CLD data! |
+ if (url.SchemeIs(extensions::kExtensionScheme)) return; |
Takashi Toyoshima
2014/03/13 18:37:37
TranslateManager::IsTranslatableURL() is the funct
Andrew Hayden (chromium.org)
2014/03/14 10:10:52
For clarity I'll submit a separate patchset in thi
|
+ |
+ // If the URL isn't an extension URL, we might conceivably want translation |
+ // capabilities. Start polling for CLD data. |
+ cld2_data_file_polling_started = true; |
+ TranslateHelper::SendCLD2DataFileRequest(0, 1000); |
+#endif |
+} |
+ |
+#if defined(CLD2_DYNAMIC_MODE) |
+void TranslateHelper::DeferPageCaptured(const int page_id, |
+ const base::string16& contents) { |
palmer
2014/03/13 17:59:50
Nit: indentation.
Takashi Toyoshima
2014/03/13 18:37:37
wrong indent
Andrew Hayden (chromium.org)
2014/03/13 23:20:21
Done.
|
+ deferred_page_capture_ = true; |
+ deferred_page_id_ = page_id; |
+ deferred_contents_.clear(); |
+ deferred_contents_.append(contents); |
Takashi Toyoshima
2014/03/13 18:37:37
Just a question.
Why don't you simply assign it, b
Andrew Hayden (chromium.org)
2014/03/14 10:10:52
I'll assign it instead. I was concerned about the
|
+} |
+#endif |
+ |
void TranslateHelper::PageCaptured(int page_id, |
const base::string16& contents) { |
// Get the document language as set by WebKit from the http-equiv |
@@ -92,6 +134,17 @@ void TranslateHelper::PageCaptured(int page_id, |
WebFrame* main_frame = GetMainFrame(); |
if (!main_frame || render_view()->GetPageId() != page_id) |
return; |
+ |
+ // TODO(andrewhayden): UMA insertion point here: Track if data is available. |
Takashi Toyoshima
2014/03/13 18:37:37
Just a question:
How long time does it take from c
Andrew Hayden (chromium.org)
2014/03/14 10:10:52
I don't have data but I'd be happy to measure it :
|
+ // TODO(andrewhayden): Retry insertion point here, retry till data available. |
+#if defined(CLD2_DYNAMIC_MODE) |
+ if (!CLD2::isDataLoaded()) { |
+ // 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(); |
@@ -136,6 +189,9 @@ void TranslateHelper::CancelPendingTranslation() { |
translation_pending_ = false; |
source_lang_.clear(); |
target_lang_.clear(); |
+#if defined(CLD2_DYNAMIC_MODE) |
+ CancelCLD2DataFilePolling(); |
+#endif |
} |
//////////////////////////////////////////////////////////////////////////////// |
@@ -310,6 +366,9 @@ 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() |
return handled; |
@@ -499,3 +558,92 @@ WebFrame* TranslateHelper::GetMainFrame() { |
return web_view->mainFrame(); |
} |
+ |
+#if defined(CLD2_DYNAMIC_MODE) |
+void TranslateHelper::CancelCLD2DataFilePolling() { |
+ cld2_data_file_polling_canceled = true; |
+} |
+ |
+void TranslateHelper::SendCLD2DataFileRequest(int delay_millis, |
+ int next_delay_millis) { |
+ // We terminate immediately if we've been told to stop polling |
+ if (cld2_data_file_polling_canceled) return; |
palmer
2014/03/13 17:59:50
Style (everywhere this occurs).
Andrew Hayden (chromium.org)
2014/03/13 23:20:21
Done.
|
+ |
+ // We terminate immediately if we've already loaded the data. |
+ if (CLD2::isDataLoaded()) return; |
+ |
+ // Else, send the IPC message to the browser process requesting the data... |
+ Send(new ChromeViewHostMsg_NeedCLDData(routing_id())); |
+ |
+ // ... and enqueue another delayed task to call again. This will start a |
+ // chain of polling that will last until the pointer stops being null, |
+ // which is the right thing to do. |
+ // NB: In the great majority of cases, the data file will be available and |
+ // the very first delayed task will be a no-op that terminates the chain. |
+ // It's only while downloading the file that we expect this to chain for a |
+ // nontrivial amount of time. |
+ // Use a weak pointer so that we don't keep this helper object around forever. |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&TranslateHelper::SendCLD2DataFileRequest, |
+ weak_method_factory_.GetWeakPtr(), |
+ next_delay_millis, next_delay_millis), |
+ base::TimeDelta::FromMilliseconds(delay_millis)); |
+} |
+ |
+void TranslateHelper::OnCLDDataAvailable( |
+ IPC::PlatformFileForTransit ipc_file_handle) { |
+ LoadCLDDData(ipc_file_handle); |
+ if (deferred_page_capture_) { |
+ if (CLD2::isDataLoaded()) { |
+ // We have data available now, and we previously deferred a request to |
+ // start translation. Finish that request up and clear our state. |
+ // The real situation this translates to is as follows: |
+ // The user loaded a page before the CLD data was available - either |
+ // because the browser process took too long to respond to our CLD data |
+ // request, or because the data truly hasn't been available; |
+ // The data is now available, so we should get that language check |
+ // done and post the message back to the browser ASAP. |
+ 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( |
+ IPC::PlatformFileForTransit ipc_file_handle) { |
+ // We terminate immediately if we've been told to stop polling |
+ if (cld2_data_file_polling_canceled) return; |
+ |
+ // We terminate immediately if we've already loaded the data. |
+ if (CLD2::isDataLoaded()) return; |
+ |
+ // The mmap must outlive this function and must not be destroyed because |
+ // the destructor for mmap will unmap the memory segment and close the file |
+ // handle. Thus, declare it static. |
+ static base::MemoryMappedFile* mmap = NULL; |
+ DCHECK(mmap != NULL) << "Lost CLD mmap!"; // Should be impossible! |
+ |
+ // Grab the file handle |
+ base::PlatformFile platformFile = |
+ IPC::PlatformFileForTransitToPlatformFile(ipc_file_handle); |
+ DCHECK(platformFile > 0) << "Can't find the CLD data file!"; |
+ base::File basicFile(platformFile); |
+ |
+ // mmap the file |
+ mmap = new base::MemoryMappedFile(); |
+ bool loadedOk = mmap->Initialize(basicFile.Pass()); |
+ DCHECK(loadedOk) << "Failed to initialize CLD data mmap"; |
+ if (!loadedOk) { |
+ delete mmap; |
+ mmap = NULL; |
+ return; |
+ } |
+ |
+ // Initialize the CLD subsystem... we're done! |
+ CLD2::loadDataFromRawAddress(mmap->data(), mmap->length()); |
+ DCHECK(CLD2::isDataLoaded()) << "Failed to load CLD data from mmap"; |
+} |
+#endif |