1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef COMPONENTS_TRANSLATE_CONTENT_RENDERER_TRANSLATE_HELPER_H_
6 #define COMPONENTS_TRANSLATE_CONTENT_RENDERER_TRANSLATE_HELPER_H_
10 #include "base/gtest_prod_util.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/strings/string16.h"
14 #include "base/time/time.h"
15 #include "components/translate/content/renderer/renderer_cld_data_provider.h"
16 #include "components/translate/core/common/translate_errors.h"
17 #include "content/public/renderer/render_view_observer.h"
26 class RendererCldDataProvider
;
31 // This class deals with page translation.
32 // There is one TranslateHelper per RenderView.
34 // This class provides metrics that allow tracking the user experience impact
35 // of non-static CldDataProvider implementations. For background on the data
36 // providers, please refer to the following documentation:
37 // http://www.chromium.org/developers/how-tos/compact-language-detector-cld-data-source-configuration
39 // Available metrics (from the LanguageDetectionTiming enum):
41 // Recorded if PageCaptured(...) is invoked after CLD is available. This is
42 // the ideal case, indicating that CLD is available before it is needed.
44 // Recorded if PageCaptured(...) is invoked before CLD is available.
45 // Sub-optimal case indicating that CLD wasn't available when it was needed,
46 // so the request for detection has been deferred until CLD is available or
47 // until the user navigates to a different page.
49 // Recorded if CLD becomes available after a language detection request was
50 // deferred, but before the user navigated to a different page. Language
51 // detection is ultimately completed, it just didn't happen on time.
53 // Note that there is NOT a metric that records the number of times that
54 // language detection had to be aborted because CLD never became available in
55 // time. This is because there is no reasonable way to cover all the cases
56 // under which this could occur, particularly the destruction of the renderer
57 // for which this object was created. However, this value can be synthetically
58 // derived, using the logic below.
60 // Every page load that triggers language detection will result in the
61 // recording of exactly one of the first two events: ON_TIME or DEFERRED. If
62 // CLD is available in time to satisfy the request, the third event (RESUMED)
63 // will be recorded; thus, the number of times when language detection
64 // ultimately fails because CLD isn't ever available is implied as the number of
65 // times that detection is deferred minus the number of times that language
68 // count(FAILED) ~= count(DEFERRED) - count(RESUMED)
70 // Note that this is not 100% accurate: some renderer process are so short-lived
71 // that language detection wouldn't have been relevant anyway, and so a failure
72 // to detect the language in a timely manner might be completely innocuous. The
73 // overall problem with language detection is that it isn't possible to know
74 // whether it was required or not until after it has been performed!
76 // We use histograms for recording these metrics. On Android, the renderer can
77 // be killed without the chance to clean up or transmit these histograms,
78 // leading to dropped metrics. To work around this, this method forces an IPC
79 // message to be sent to the browser process immediately.
80 class TranslateHelper
: public content::RenderViewObserver
{
82 explicit TranslateHelper(content::RenderView
* render_view
,
85 const std::string
& extension_scheme
);
86 ~TranslateHelper() override
;
88 // Informs us that the page's text has been extracted.
89 void PageCaptured(const base::string16
& contents
);
91 // Lets the translation system know that we are preparing to navigate to
92 // the specified URL. If there is anything that can or should be done before
93 // this URL loads, this is the time to prepare for it.
94 void PrepareForUrl(const GURL
& url
);
97 // The following methods are protected so they can be overridden in
99 void OnTranslatePage(int page_seq_no
,
100 const std::string
& translate_script
,
101 const std::string
& source_lang
,
102 const std::string
& target_lang
);
103 void OnRevertTranslation(int page_seq_no
);
105 // Returns true if the translate library is available, meaning the JavaScript
106 // has already been injected in that page.
107 virtual bool IsTranslateLibAvailable();
109 // Returns true if the translate library has been initialized successfully.
110 virtual bool IsTranslateLibReady();
112 // Returns true if the translation script has finished translating the page.
113 virtual bool HasTranslationFinished();
115 // Returns true if the translation script has reported an error performing the
117 virtual bool HasTranslationFailed();
119 // Starts the translation by calling the translate library. This method
120 // should only be called when the translate script has been injected in the
121 // page. Returns false if the call failed immediately.
122 virtual bool StartTranslation();
124 // Asks the Translate element in the page what the language of the page is.
125 // Can only be called if a translation has happened and was successful.
126 // Returns the language code on success, an empty string on failure.
127 virtual std::string
GetOriginalPageLanguage();
129 // Adjusts a delay time for a posted task. This is used in tests to do tasks
130 // immediately by returning 0.
131 virtual base::TimeDelta
AdjustDelay(int delayInMs
);
133 // Executes the JavaScript code in |script| in the main frame of RenderView.
134 virtual void ExecuteScript(const std::string
& script
);
136 // Executes the JavaScript code in |script| in the main frame of RenderView,
137 // and returns the boolean returned by the script evaluation if the script was
138 // run successfully. Otherwise, returns |fallback| value.
139 virtual bool ExecuteScriptAndGetBoolResult(const std::string
& script
,
142 // Executes the JavaScript code in |script| in the main frame of RenderView,
143 // and returns the string returned by the script evaluation if the script was
144 // run successfully. Otherwise, returns empty string.
145 virtual std::string
ExecuteScriptAndGetStringResult(
146 const std::string
& script
);
148 // Executes the JavaScript code in |script| in the main frame of RenderView.
149 // and returns the number returned by the script evaluation if the script was
150 // run successfully. Otherwise, returns 0.0.
151 virtual double ExecuteScriptAndGetDoubleResult(const std::string
& script
);
154 FRIEND_TEST_ALL_PREFIXES(TranslateHelperTest
, AdoptHtmlLang
);
155 FRIEND_TEST_ALL_PREFIXES(TranslateHelperTest
,
156 CLDAgreeWithLanguageCodeHavingCountryCode
);
157 FRIEND_TEST_ALL_PREFIXES(TranslateHelperTest
,
158 CLDDisagreeWithWrongLanguageCode
);
159 FRIEND_TEST_ALL_PREFIXES(TranslateHelperTest
,
160 InvalidLanguageMetaTagProviding
);
161 FRIEND_TEST_ALL_PREFIXES(TranslateHelperTest
, LanguageCodeTypoCorrection
);
162 FRIEND_TEST_ALL_PREFIXES(TranslateHelperTest
, LanguageCodeSynonyms
);
163 FRIEND_TEST_ALL_PREFIXES(TranslateHelperTest
, ResetInvalidLanguageCode
);
164 FRIEND_TEST_ALL_PREFIXES(TranslateHelperTest
, SimilarLanguageCode
);
165 FRIEND_TEST_ALL_PREFIXES(TranslateHelperTest
, WellKnownWrongConfiguration
);
167 enum LanguageDetectionTiming
{
168 ON_TIME
, // Language detection was performed as soon as it was requested
169 DEFERRED
, // Language detection couldn't be performed when it was requested
170 RESUMED
, // A deferred language detection attempt was completed later
171 LANGUAGE_DETECTION_TIMING_MAX_VALUE
// The bounding value for this enum
174 // Converts language code to the one used in server supporting list.
175 static void ConvertLanguageCodeSynonym(std::string
* code
);
177 // Returns whether the page associated with |document| is a candidate for
178 // translation. Some pages can explictly specify (via a meta-tag) that they
179 // should not be translated.
180 static bool IsTranslationAllowed(blink::WebDocument
* document
);
182 // RenderViewObserver implementation.
183 bool OnMessageReceived(const IPC::Message
& message
) override
;
185 // Informs us that the page's text has been extracted.
186 void PageCapturedImpl(int page_seq_no
, const base::string16
& contents
);
188 // Cancels any translation that is currently being performed. This does not
189 // revert existing translations.
190 void CancelPendingTranslation();
192 // Checks if the current running page translation is finished or errored and
193 // notifies the browser accordingly. If the translation has not terminated,
194 // posts a task to check again later.
195 void CheckTranslateStatus(int page_seq_no
);
197 // Called by TranslatePage to do the actual translation. |count| is used to
198 // limit the number of retries.
199 void TranslatePageImpl(int page_seq_no
, int count
);
201 // Sends a message to the browser to notify it that the translation failed
203 void NotifyBrowserTranslationFailed(TranslateErrors::Type error
);
205 // Convenience method to access the main frame. Can return NULL, typically
206 // if the page is being closed.
207 blink::WebFrame
* GetMainFrame();
209 // Do not ask for CLD data any more.
210 void CancelCldDataPolling();
212 // Invoked when PageCaptured is called prior to obtaining CLD data. This
213 // method stores the page ID into deferred_page_id_ and COPIES the contents
214 // of the page, then sets deferred_page_capture_ to true. When CLD data is
215 // eventually received (in OnCldDataAvailable), any deferred request will be
216 // "resurrected" and allowed to proceed automatically, assuming that the
217 // page ID has not changed.
218 void DeferPageCaptured(const int page_id
, const base::string16
& contents
);
220 // Start polling for CLD data.
221 // Polling will automatically halt as soon as the renderer obtains a
222 // reference to the data file.
223 void SendCldDataRequest(const int delay_millis
, const int next_delay_millis
);
225 // Callback triggered when CLD data becomes available.
226 void OnCldDataAvailable();
228 // Record the timing of language detection, immediately sending an IPC-based
229 // histogram delta update to the browser process in case the hosting renderer
230 // process terminates before the metrics would otherwise be transferred.
231 void RecordLanguageDetectionTiming(LanguageDetectionTiming timing
);
233 // An ever-increasing sequence number of the current page, used to match up
234 // translation requests with responses.
237 // The states associated with the current translation.
238 bool translation_pending_
;
239 std::string source_lang_
;
240 std::string target_lang_
;
242 // Time when a page langauge is determined. This is used to know a duration
243 // time from showing infobar to requesting translation.
244 base::TimeTicks language_determined_time_
;
246 // Provides CLD data for this process.
247 scoped_ptr
<RendererCldDataProvider
> cld_data_provider_
;
249 // Whether or not polling for CLD2 data has started.
250 bool cld_data_polling_started_
;
252 // Whether or not CancelCldDataPolling has been called.
253 bool cld_data_polling_canceled_
;
255 // Whether or not a PageCaptured event arrived prior to CLD data becoming
256 // available. If true, deferred_contents_ contains the most recent contents.
257 bool deferred_page_capture_
;
259 // The ID of the page most recently reported to PageCaptured if
260 // deferred_page_capture_ is true.
261 int deferred_page_seq_no_
;
263 // The world ID to use for script execution.
266 // The extension group.
267 int extension_group_
;
269 // The URL scheme for translate extensions.
270 std::string extension_scheme_
;
272 // The contents of the page most recently reported to PageCaptured if
273 // deferred_page_capture_ is true.
274 base::string16 deferred_contents_
;
276 // Method factory used to make calls to TranslatePageImpl.
277 base::WeakPtrFactory
<TranslateHelper
> weak_method_factory_
;
279 DISALLOW_COPY_AND_ASSIGN(TranslateHelper
);
282 } // namespace translate
284 #endif // COMPONENTS_TRANSLATE_CONTENT_RENDERER_TRANSLATE_HELPER_H_