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 // RenderViewObserver implementation.
178 bool OnMessageReceived(const IPC::Message
& message
) override
;
180 // Informs us that the page's text has been extracted.
181 void PageCapturedImpl(int page_seq_no
, const base::string16
& contents
);
183 // Cancels any translation that is currently being performed. This does not
184 // revert existing translations.
185 void CancelPendingTranslation();
187 // Checks if the current running page translation is finished or errored and
188 // notifies the browser accordingly. If the translation has not terminated,
189 // posts a task to check again later.
190 void CheckTranslateStatus(int page_seq_no
);
192 // Called by TranslatePage to do the actual translation. |count| is used to
193 // limit the number of retries.
194 void TranslatePageImpl(int page_seq_no
, int count
);
196 // Sends a message to the browser to notify it that the translation failed
198 void NotifyBrowserTranslationFailed(TranslateErrors::Type error
);
200 // Convenience method to access the main frame. Can return NULL, typically
201 // if the page is being closed.
202 blink::WebFrame
* GetMainFrame();
204 // Do not ask for CLD data any more.
205 void CancelCldDataPolling();
207 // Start polling for CLD data.
208 // Polling will automatically halt as soon as the renderer obtains a
209 // reference to the data file.
210 void SendCldDataRequest(const int delay_millis
, const int next_delay_millis
);
212 // Callback triggered when CLD data becomes available.
213 void OnCldDataAvailable();
215 // Record the timing of language detection, immediately sending an IPC-based
216 // histogram delta update to the browser process in case the hosting renderer
217 // process terminates before the metrics would otherwise be transferred.
218 void RecordLanguageDetectionTiming(LanguageDetectionTiming timing
);
220 // An ever-increasing sequence number of the current page, used to match up
221 // translation requests with responses.
224 // The states associated with the current translation.
225 bool translation_pending_
;
226 std::string source_lang_
;
227 std::string target_lang_
;
229 // Time when a page langauge is determined. This is used to know a duration
230 // time from showing infobar to requesting translation.
231 base::TimeTicks language_determined_time_
;
233 // Provides CLD data for this process.
234 scoped_ptr
<RendererCldDataProvider
> cld_data_provider_
;
236 // Whether or not polling for CLD2 data has started.
237 bool cld_data_polling_started_
;
239 // Whether or not CancelCldDataPolling has been called.
240 bool cld_data_polling_canceled_
;
242 // Whether or not a PageCaptured event arrived prior to CLD data becoming
243 // available. If true, deferred_contents_ contains the most recent contents.
244 bool deferred_page_capture_
;
246 // The ID of the page most recently reported to PageCaptured if
247 // deferred_page_capture_ is true.
248 int deferred_page_seq_no_
;
250 // The world ID to use for script execution.
253 // The extension group.
254 int extension_group_
;
256 // The URL scheme for translate extensions.
257 std::string extension_scheme_
;
259 // The contents of the page most recently reported to PageCaptured if
260 // deferred_page_capture_ is true.
261 base::string16 deferred_contents_
;
263 // Method factory used to make calls to TranslatePageImpl.
264 base::WeakPtrFactory
<TranslateHelper
> weak_method_factory_
;
266 DISALLOW_COPY_AND_ASSIGN(TranslateHelper
);
269 } // namespace translate
271 #endif // COMPONENTS_TRANSLATE_CONTENT_RENDERER_TRANSLATE_HELPER_H_