| 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..53c96b001ebd74683e5ca049801ce75451d83ade 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;
|
| const int kTranslateStatusCheckDelayMs = 400;
|
|
|
| // Language name passed to the Translate element for it to detect the language.
|
| @@ -72,12 +78,49 @@ 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_canceled = false;
|
| + deferred_page_capture_ = false;
|
| + deferred_page_id_ = -1;
|
| + 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)
|
| + // Try to load the CLD data if we haven't already done so.
|
| + static bool startedTranslationPolling = false;
|
| + if (startedTranslationPolling) return;
|
| +
|
| + // 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;
|
| +
|
| + // If the URL isn't an extension URL, we might conceivably want translation
|
| + // capabilities. Start polling for CLD data.
|
| + startedTranslationPolling = true;
|
| + TranslateHelper::SendCLD2DataFileRequest(0, 1000);
|
| +#endif
|
| +}
|
| +
|
| +#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_.clear();
|
| + deferred_contents_.append(contents);
|
| +}
|
| +#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 +135,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.
|
| + // 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 +190,9 @@ void TranslateHelper::CancelPendingTranslation() {
|
| translation_pending_ = false;
|
| source_lang_.clear();
|
| target_lang_.clear();
|
| +#if defined(CLD2_DYNAMIC_MODE)
|
| + CancelCLD2DataFilePolling();
|
| +#endif
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| @@ -310,6 +367,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 +559,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 delayMillis,
|
| + int nextDelayMillis) {
|
| + // 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;
|
| +
|
| + // 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(),
|
| + nextDelayMillis, nextDelayMillis),
|
| + base::TimeDelta::FromMilliseconds(nextDelayMillis));
|
| +}
|
| +
|
| +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
|
|
|