15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/translate/content/renderer/translate_helper.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/metrics/histogram.h"
127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string16.h"
137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
15c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "components/translate/content/common/translate_messages.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/translate/core/common/translate_constants.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/translate/core/common/translate_metrics.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/translate/core/common/translate_util.h"
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/translate/core/language_detection/language_detection_util.h"
20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/common/content_constants.h"
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/common/url_constants.h"
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/renderer/render_thread.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/renderer/render_view.h"
24effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "ipc/ipc_platform_file.h"
257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebDocument.h"
267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebElement.h"
277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebFrame.h"
287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebNode.h"
297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebNodeList.h"
307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebScriptSource.h"
317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebView.h"
32558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "third_party/WebKit/public/web/WebWidget.h"
33558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "url/gurl.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "v8/include/v8.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::ASCIIToUTF16;
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebDocument;
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebElement;
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebFrame;
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebNode;
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebNodeList;
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebScriptSource;
43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebSecurityOrigin;
44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebString;
45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebVector;
46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebView;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The delay in milliseconds that we'll wait before checking to see if the
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// translate library injected in the page is ready.
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kTranslateInitCheckDelayMs = 150;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The maximum number of times we'll check to see if the translate library
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// injected in the page is ready.
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kMaxTranslateInitCheckAttempts = 5;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The delay we wait in milliseconds before checking whether the translation has
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// finished.
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kTranslateStatusCheckDelayMs = 400;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Language name passed to the Translate element for it to detect the language.
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kAutoDetectionLanguage[] = "auto";
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
65558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Isolated world sets following content-security-policy.
66558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochconst char kContentSecurityPolicy[] = "script-src 'self' 'unsafe-eval'";
67558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Whether or not we have set the CLD callback yet.
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool g_cld_callback_set = false;
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace translate {
74effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TranslateHelper, public:
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTranslateHelper::TranslateHelper(content::RenderView* render_view,
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 int world_id,
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 int extension_group,
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 const std::string& extension_scheme)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : content::RenderViewObserver(render_view),
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      page_seq_no_(0),
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      translation_pending_(false),
85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      cld_data_provider_(translate::CreateRendererCldDataProviderFor(this)),
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      cld_data_polling_started_(false),
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      cld_data_polling_canceled_(false),
88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      deferred_page_capture_(false),
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      deferred_page_seq_no_(-1),
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      world_id_(world_id),
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      extension_group_(extension_group),
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      extension_scheme_(extension_scheme),
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_method_factory_(this) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TranslateHelper::~TranslateHelper() {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelPendingTranslation();
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CancelCldDataPolling();
99effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
100effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
101effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid TranslateHelper::PrepareForUrl(const GURL& url) {
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ++page_seq_no_;
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  Send(new ChromeViewHostMsg_TranslateAssignedSequenceNumber(
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      routing_id(), page_seq_no_));
105effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  deferred_page_capture_ = false;
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  deferred_page_seq_no_ = -1;
107effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  deferred_contents_.clear();
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (cld_data_polling_started_)
109effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
110effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
111effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // TODO(andrewhayden): Refactor translate_manager.cc's IsTranslatableURL to
112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // components/translate/core/common/translate_util.cc, and ignore any URL
113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // that fails that check. This will require moving unit tests and rewiring
114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // other function calls as well, so for now replicate the logic here.
115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (url.is_empty())
116effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (url.SchemeIs(content::kChromeUIScheme))
118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (url.SchemeIs(content::kChromeDevToolsScheme))
120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (url.SchemeIs(url::kFtpScheme))
122effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (url.SchemeIs(extension_scheme_.c_str()))
124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
125effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
126effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Start polling for CLD data.
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  cld_data_polling_started_ = true;
128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  TranslateHelper::SendCldDataRequest(0, 1000);
129effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
131116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TranslateHelper::PageCaptured(const base::string16& contents) {
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  PageCapturedImpl(page_seq_no_, contents);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TranslateHelper::PageCapturedImpl(int page_seq_no,
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                       const base::string16& contents) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the document language as set by WebKit from the http-equiv
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // meta tag for "content-language".  This may or may not also
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // have a value derived from the actual Content-Language HTTP
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // header.  The two actually have different meanings (despite the
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // original intent of http-equiv to be an equivalent) with the former
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // being the language of the document and the latter being the
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // language of the intended audience (a distinction really only
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // relevant for things like langauge textbooks).  This distinction
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // shouldn't affect translation.
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  WebFrame* main_frame = GetMainFrame();
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!main_frame || page_seq_no_ != page_seq_no)
14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!cld_data_provider_->IsCldDataAvailable()) {
151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // We're in dynamic mode and CLD data isn't loaded. Retry when CLD data
152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // is loaded, if ever.
153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    deferred_page_capture_ = true;
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    deferred_page_seq_no_ = page_seq_no;
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    deferred_contents_ = contents;
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    RecordLanguageDetectionTiming(DEFERRED);
157effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
158effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (deferred_page_seq_no_ == -1) {
161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // CLD data was available before language detection was requested.
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    RecordLanguageDetectionTiming(ON_TIME);
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // This is a request that was triggered because CLD data is now available
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // and was previously deferred.
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    RecordLanguageDetectionTiming(RESUMED);
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  WebDocument document = main_frame->document();
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string content_language = document.contentLanguage().utf8();
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  WebElement html_element = document.documentElement();
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string html_lang;
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // |html_element| can be null element, e.g. in
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // BrowserTest.WindowOpenClose.
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!html_element.isNull())
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    html_lang = html_element.getAttribute("lang").utf8();
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string cld_language;
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool is_cld_reliable;
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string language = DeterminePageLanguage(
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      content_language, html_lang, contents, &cld_language, &is_cld_reliable);
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (language.empty())
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  language_determined_time_ = base::TimeTicks::Now();
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GURL url(document.url());
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LanguageDetectionDetails details;
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  details.time = base::Time::Now();
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  details.url = url;
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  details.content_language = content_language;
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  details.cld_language = cld_language;
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  details.is_cld_reliable = is_cld_reliable;
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  details.html_root_language = html_lang;
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  details.adopted_language = language;
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // TODO(hajimehoshi): If this affects performance, it should be set only if
198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // translate-internals tab exists.
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  details.contents = contents;
200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Send(new ChromeViewHostMsg_TranslateLanguageDetermined(
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      routing_id(),
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      details,
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      IsTranslationAllowed(&document) && !language.empty()));
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TranslateHelper::CancelPendingTranslation() {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_method_factory_.InvalidateWeakPtrs();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  translation_pending_ = false;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  source_lang_.clear();
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  target_lang_.clear();
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CancelCldDataPolling();
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TranslateHelper, protected:
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TranslateHelper::IsTranslateLibAvailable() {
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return ExecuteScriptAndGetBoolResult(
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "typeof cr != 'undefined' && typeof cr.googleTranslate != 'undefined' && "
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "typeof cr.googleTranslate.translate == 'function'", false);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TranslateHelper::IsTranslateLibReady() {
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return ExecuteScriptAndGetBoolResult("cr.googleTranslate.libReady", false);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TranslateHelper::HasTranslationFinished() {
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return ExecuteScriptAndGetBoolResult("cr.googleTranslate.finished", true);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TranslateHelper::HasTranslationFailed() {
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return ExecuteScriptAndGetBoolResult("cr.googleTranslate.error", true);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TranslateHelper::StartTranslation() {
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string script = "cr.googleTranslate.translate('" +
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       source_lang_ +
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       "','" +
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       target_lang_ +
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       "')";
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return ExecuteScriptAndGetBoolResult(script, false);
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string TranslateHelper::GetOriginalPageLanguage() {
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return ExecuteScriptAndGetStringResult("cr.googleTranslate.sourceLang");
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::TimeDelta TranslateHelper::AdjustDelay(int delayInMs) {
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Just converts |delayInMs| without any modification in practical cases.
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Tests will override this function to return modified value.
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return base::TimeDelta::FromMilliseconds(delayInMs);
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void TranslateHelper::ExecuteScript(const std::string& script) {
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebFrame* main_frame = GetMainFrame();
257558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (!main_frame)
258558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return;
259558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
260558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  WebScriptSource source = WebScriptSource(ASCIIToUTF16(script));
261558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  main_frame->executeScriptInIsolatedWorld(
2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      world_id_, &source, 1, extension_group_);
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool TranslateHelper::ExecuteScriptAndGetBoolResult(const std::string& script,
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                    bool fallback) {
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebFrame* main_frame = GetMainFrame();
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!main_frame)
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return fallback;
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
27158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
272558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  WebVector<v8::Local<v8::Value> > results;
273558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  WebScriptSource source = WebScriptSource(ASCIIToUTF16(script));
274558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  main_frame->executeScriptInIsolatedWorld(
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      world_id_, &source, 1, extension_group_, &results);
276558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (results.size() != 1 || results[0].IsEmpty() || !results[0]->IsBoolean()) {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return fallback;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
281558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return results[0]->BooleanValue();
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string TranslateHelper::ExecuteScriptAndGetStringResult(
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& script) {
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebFrame* main_frame = GetMainFrame();
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!main_frame)
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return std::string();
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
29058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
291558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  WebVector<v8::Local<v8::Value> > results;
292558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  WebScriptSource source = WebScriptSource(ASCIIToUTF16(script));
293558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  main_frame->executeScriptInIsolatedWorld(
2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      world_id_, &source, 1, extension_group_, &results);
295558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (results.size() != 1 || results[0].IsEmpty() || !results[0]->IsString()) {
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    NOTREACHED();
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return std::string();
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
300558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  v8::Local<v8::String> v8_str = results[0]->ToString();
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int length = v8_str->Utf8Length() + 1;
302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<char[]> str(new char[length]);
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  v8_str->WriteUtf8(str.get(), length);
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return std::string(str.get());
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)double TranslateHelper::ExecuteScriptAndGetDoubleResult(
308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& script) {
309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebFrame* main_frame = GetMainFrame();
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!main_frame)
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return 0.0;
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
31358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
314558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  WebVector<v8::Local<v8::Value> > results;
315558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  WebScriptSource source = WebScriptSource(ASCIIToUTF16(script));
316558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  main_frame->executeScriptInIsolatedWorld(
3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      world_id_, &source, 1, extension_group_, &results);
318558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (results.size() != 1 || results[0].IsEmpty() || !results[0]->IsNumber()) {
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    NOTREACHED();
320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return 0.0;
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
323558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return results[0]->NumberValue();
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TranslateHelper, private:
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool TranslateHelper::IsTranslationAllowed(WebDocument* document) {
33290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  WebElement head = document->head();
33390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (head.isNull() || !head.hasChildNodes())
33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return true;
33590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const WebString meta(ASCIIToUTF16("meta"));
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const WebString name(ASCIIToUTF16("name"));
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const WebString google(ASCIIToUTF16("google"));
33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const WebString value(ASCIIToUTF16("value"));
34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const WebString content(ASCIIToUTF16("content"));
34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
34290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  WebNodeList children = head.childNodes();
34390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (size_t i = 0; i < children.length(); ++i) {
34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    WebNode node = children.item(i);
34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!node.isElementNode())
34690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue;
34790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    WebElement element = node.to<WebElement>();
34890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Check if a tag is <meta>.
349116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!element.hasHTMLTagName(meta))
35090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue;
35190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Check if the tag contains name="google".
35290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    WebString attribute = element.getAttribute(name);
35390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (attribute.isNull() || attribute != google)
35490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue;
35590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Check if the tag contains value="notranslate", or content="notranslate".
35690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    attribute = element.getAttribute(value);
35790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (attribute.isNull())
35890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      attribute = element.getAttribute(content);
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (attribute.isNull())
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (LowerCaseEqualsASCII(attribute, "notranslate"))
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TranslateHelper::OnMessageReceived(const IPC::Message& message) {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool handled = true;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_BEGIN_MESSAGE_MAP(TranslateHelper, message)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(ChromeViewMsg_TranslatePage, OnTranslatePage)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_HANDLER(ChromeViewMsg_RevertTranslation, OnRevertTranslation)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC_MESSAGE_UNHANDLED(handled = false)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_END_MESSAGE_MAP()
374116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!handled) {
375116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    handled = cld_data_provider_->OnMessageReceived(message);
376116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return handled;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
380116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TranslateHelper::OnTranslatePage(int page_seq_no,
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const std::string& translate_script,
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const std::string& source_lang,
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const std::string& target_lang) {
38490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  WebFrame* main_frame = GetMainFrame();
385116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!main_frame || page_seq_no_ != page_seq_no)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // We navigated away, nothing to do.
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
388868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // A similar translation is already under way, nothing to do.
389868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (translation_pending_ && target_lang_ == target_lang)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Any pending translation is now irrelevant.
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelPendingTranslation();
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set our states.
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  translation_pending_ = true;
397868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the source language is undetermined, we'll let the translate element
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // detect it.
4001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  source_lang_ = (source_lang != kUnknownLanguageCode) ? source_lang
4011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                       : kAutoDetectionLanguage;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  target_lang_ = target_lang;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ReportUserActionDuration(language_determined_time_, base::TimeTicks::Now());
40590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
40690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GURL url(main_frame->document().url());
4071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ReportPageScheme(url.scheme());
40890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
409558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // Set up v8 isolated world with proper content-security-policy and
410558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // security-origin.
411558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  WebFrame* frame = GetMainFrame();
412558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (frame) {
413558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    frame->setIsolatedWorldContentSecurityPolicy(
4141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        world_id_, WebString::fromUTF8(kContentSecurityPolicy));
415558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
4161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    GURL security_origin = GetTranslateSecurityOrigin();
417558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    frame->setIsolatedWorldSecurityOrigin(
4181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        world_id_, WebSecurityOrigin::create(security_origin));
419558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
420558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsTranslateLibAvailable()) {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Evaluate the script to add the translation related method to the global
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // context of the page.
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExecuteScript(translate_script);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(IsTranslateLibAvailable());
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
428116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  TranslatePageImpl(page_seq_no, 0);
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
431116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TranslateHelper::OnRevertTranslation(int page_seq_no) {
432116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (page_seq_no_ != page_seq_no)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // We navigated away, nothing to do.
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsTranslateLibAvailable()) {
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelPendingTranslation();
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ExecuteScript("cr.googleTranslate.revert()");
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TranslateHelper::CheckTranslateStatus(int page_seq_no) {
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If this is not the same page, the translation has been canceled.  If the
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // view is gone, the page is closing.
448116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (page_seq_no_ != page_seq_no || !render_view()->GetWebView())
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First check if there was an error.
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HasTranslationFailed()) {
45358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // TODO(toyoshim): Check |errorCode| of translate.js and notify it here.
4541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NotifyBrowserTranslationFailed(TranslateErrors::TRANSLATION_ERROR);
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // There was an error.
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HasTranslationFinished()) {
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string actual_source_lang;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Translation was successfull, if it was auto, retrieve the source
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // language the Translate Element detected.
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (source_lang_ == kAutoDetectionLanguage) {
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      actual_source_lang = GetOriginalPageLanguage();
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (actual_source_lang.empty()) {
4651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        NotifyBrowserTranslationFailed(TranslateErrors::UNKNOWN_LANGUAGE);
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (actual_source_lang == target_lang_) {
4681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        NotifyBrowserTranslationFailed(TranslateErrors::IDENTICAL_LANGUAGES);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      actual_source_lang = source_lang_;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!translation_pending_) {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    translation_pending_ = false;
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Check JavaScript performance counters for UMA reports.
4831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ReportTimeToTranslate(
484a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        ExecuteScriptAndGetDoubleResult("cr.googleTranslate.translationTime"));
485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Notify the browser we are done.
4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    render_view()->Send(
4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        new ChromeViewHostMsg_PageTranslated(render_view()->GetRoutingID(),
4895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                             actual_source_lang,
4905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                             target_lang_,
4911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             TranslateErrors::NONE));
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The translation is still pending, check again later.
496a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&TranslateHelper::CheckTranslateStatus,
499116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 weak_method_factory_.GetWeakPtr(), page_seq_no),
500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      AdjustDelay(kTranslateStatusCheckDelayMs));
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
503116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TranslateHelper::TranslatePageImpl(int page_seq_no, int count) {
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LT(count, kMaxTranslateInitCheckAttempts);
505116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (page_seq_no_ != page_seq_no || !render_view()->GetWebView())
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsTranslateLibReady()) {
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The library is not ready, try again later, unless we have tried several
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // times unsucessfully already.
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (++count >= kMaxTranslateInitCheckAttempts) {
5121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      NotifyBrowserTranslationFailed(TranslateErrors::INITIALIZATION_ERROR);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
515a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&TranslateHelper::TranslatePageImpl,
518a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                   weak_method_factory_.GetWeakPtr(),
519116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                   page_seq_no, count),
520c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        AdjustDelay(count * kTranslateInitCheckDelayMs));
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The library is loaded, and ready for translation now.
525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Check JavaScript performance counters for UMA reports.
5261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ReportTimeToBeReady(
527a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      ExecuteScriptAndGetDoubleResult("cr.googleTranslate.readyTime"));
5281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ReportTimeToLoad(
529a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      ExecuteScriptAndGetDoubleResult("cr.googleTranslate.loadTime"));
530c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!StartTranslation()) {
5321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NotifyBrowserTranslationFailed(TranslateErrors::TRANSLATION_ERROR);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check the status of the translation.
536a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&TranslateHelper::CheckTranslateStatus,
539116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 weak_method_factory_.GetWeakPtr(), page_seq_no),
540c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      AdjustDelay(kTranslateStatusCheckDelayMs));
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TranslateHelper::NotifyBrowserTranslationFailed(
5441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    TranslateErrors::Type error) {
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  translation_pending_ = false;
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notify the browser there was an error.
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_view()->Send(new ChromeViewHostMsg_PageTranslated(
548116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      render_view()->GetRoutingID(), source_lang_, target_lang_, error));
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebFrame* TranslateHelper::GetMainFrame() {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebView* web_view = render_view()->GetWebView();
55390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
55490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // When the tab is going to be closed, the web_view can be NULL.
55590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!web_view)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
55790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return web_view->mainFrame();
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
560effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
561116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TranslateHelper::CancelCldDataPolling() {
562116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  cld_data_polling_canceled_ = true;
563effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
564effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
565116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TranslateHelper::SendCldDataRequest(const int delay_millis,
566116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                         const int next_delay_millis) {
567effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Terminate immediately if told to stop polling.
568116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (cld_data_polling_canceled_)
569effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
570effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
571effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Terminate immediately if data is already loaded.
572116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (cld_data_provider_->IsCldDataAvailable())
573effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
574effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
575116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!g_cld_callback_set) {
576116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    g_cld_callback_set = true;
577116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    cld_data_provider_->SetCldAvailableCallback(
578116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        base::Bind(&TranslateHelper::OnCldDataAvailable,
579116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                   weak_method_factory_.GetWeakPtr()));
580116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
581116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
582116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Else, make an asynchronous request to get the data we need.
583116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  cld_data_provider_->SendCldDataRequest();
584effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
585effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // ... and enqueue another delayed task to call again. This will start a
586effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // chain of polling that will last until the pointer stops being NULL,
587effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // which is the right thing to do.
588effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // NB: In the great majority of cases, the data file will be available and
589effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // the very first delayed task will be a no-op that terminates the chain.
590effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // It's only while downloading the file that this will chain for a
591effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // nontrivial amount of time.
592effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Use a weak pointer to avoid keeping this helper object around forever.
593effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  base::MessageLoop::current()->PostDelayedTask(
594effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      FROM_HERE,
595116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::Bind(&TranslateHelper::SendCldDataRequest,
596effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 weak_method_factory_.GetWeakPtr(),
597116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 next_delay_millis,
598116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 next_delay_millis),
599effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::TimeDelta::FromMilliseconds(delay_millis));
600effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
601effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
602116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TranslateHelper::OnCldDataAvailable() {
603116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (deferred_page_capture_) {
604effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    deferred_page_capture_ = false; // Don't do this a second time.
605116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    PageCapturedImpl(deferred_page_seq_no_, deferred_contents_);
606116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    deferred_page_seq_no_ = -1; // Clean up for sanity
607effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    deferred_contents_.clear(); // Clean up for sanity
608effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
609effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
610effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
611116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid TranslateHelper::RecordLanguageDetectionTiming(
612116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LanguageDetectionTiming timing) {
613116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // The following comment is copied from page_load_histograms.cc, and applies
614116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // just as equally here:
615116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  //
616116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Since there are currently no guarantees that renderer histograms will be
617116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // sent to the browser, we initiate a PostTask here to be sure that we send
618116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // the histograms we generated.  Without this call, pages that don't have an
619116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // on-close-handler might generate data that is lost when the renderer is
620116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // shutdown abruptly (perchance because the user closed the tab).
621116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DVLOG(1) << "Language detection timing: " << timing;
622116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  UMA_HISTOGRAM_ENUMERATION("Translate.LanguageDetectionTiming", timing,
623116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                            LANGUAGE_DETECTION_TIMING_MAX_VALUE);
624116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
625116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Note on performance: Under normal circumstances, this should get called
626116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // once per page load. The code will either manage to do it ON_TIME or will
627116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // be DEFERRED until CLD is ready. In the latter case, CLD is in dynamic mode
628116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // and may eventually become available, triggering the RESUMED event; after
629116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // this, everything should start being ON_TIME. This should never run more
630116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // than twice in a page load, under any conditions.
631116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Also note that language detection is triggered off of a delay AFTER the
632116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // page load completed event has fired, making this very much off the critical
633116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // path.
634116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  content::RenderThread::Get()->UpdateHistograms(
635116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      content::kHistogramSynchronizerReservedSequenceNumber);
636effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
6371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
6381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace translate
639