Home | History | Annotate | Download | only in renderer
      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.
      4 
      5 #ifndef COMPONENTS_TRANSLATE_CONTENT_RENDERER_TRANSLATE_HELPER_H_
      6 #define COMPONENTS_TRANSLATE_CONTENT_RENDERER_TRANSLATE_HELPER_H_
      7 
      8 #include <string>
      9 
     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"
     18 #include "url/gurl.h"
     19 
     20 namespace blink {
     21 class WebDocument;
     22 class WebFrame;
     23 }
     24 
     25 namespace content {
     26 class RendererCldDataProvider;
     27 }
     28 
     29 namespace translate {
     30 
     31 // This class deals with page translation.
     32 // There is one TranslateHelper per RenderView.
     33 //
     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
     38 //
     39 // Available metrics (from the LanguageDetectionTiming enum):
     40 // 1. ON_TIME
     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.
     43 // 2. DEFERRED
     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.
     48 // 3. RESUMED
     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.
     52 //
     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.
     59 //
     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
     66 // detection is late:
     67 //
     68 //   count(FAILED) ~= count(DEFERRED) - count(RESUMED)
     69 //
     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!
     75 //
     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 {
     81  public:
     82   explicit TranslateHelper(content::RenderView* render_view,
     83                            int world_id,
     84                            int extension_group,
     85                            const std::string& extension_scheme);
     86   virtual ~TranslateHelper();
     87 
     88   // Informs us that the page's text has been extracted.
     89   void PageCaptured(const base::string16& contents);
     90 
     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);
     95 
     96  protected:
     97   // The following methods are protected so they can be overridden in
     98   // unit-tests.
     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);
    104 
    105   // Returns true if the translate library is available, meaning the JavaScript
    106   // has already been injected in that page.
    107   virtual bool IsTranslateLibAvailable();
    108 
    109   // Returns true if the translate library has been initialized successfully.
    110   virtual bool IsTranslateLibReady();
    111 
    112   // Returns true if the translation script has finished translating the page.
    113   virtual bool HasTranslationFinished();
    114 
    115   // Returns true if the translation script has reported an error performing the
    116   // translation.
    117   virtual bool HasTranslationFailed();
    118 
    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();
    123 
    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();
    128 
    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);
    132 
    133   // Executes the JavaScript code in |script| in the main frame of RenderView.
    134   virtual void ExecuteScript(const std::string& script);
    135 
    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,
    140                                              bool fallback);
    141 
    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);
    147 
    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);
    152 
    153  private:
    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);
    166 
    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
    172   };
    173 
    174   // Converts language code to the one used in server supporting list.
    175   static void ConvertLanguageCodeSynonym(std::string* code);
    176 
    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);
    181 
    182   // RenderViewObserver implementation.
    183   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
    184 
    185   // Informs us that the page's text has been extracted.
    186   void PageCapturedImpl(int page_seq_no, const base::string16& contents);
    187 
    188   // Cancels any translation that is currently being performed.  This does not
    189   // revert existing translations.
    190   void CancelPendingTranslation();
    191 
    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);
    196 
    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);
    200 
    201   // Sends a message to the browser to notify it that the translation failed
    202   // with |error|.
    203   void NotifyBrowserTranslationFailed(TranslateErrors::Type error);
    204 
    205   // Convenience method to access the main frame.  Can return NULL, typically
    206   // if the page is being closed.
    207   blink::WebFrame* GetMainFrame();
    208 
    209   // Do not ask for CLD data any more.
    210   void CancelCldDataPolling();
    211 
    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);
    219 
    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);
    224 
    225   // Callback triggered when CLD data becomes available.
    226   void OnCldDataAvailable();
    227 
    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);
    232 
    233   // An ever-increasing sequence number of the current page, used to match up
    234   // translation requests with responses.
    235   int page_seq_no_;
    236 
    237   // The states associated with the current translation.
    238   bool translation_pending_;
    239   std::string source_lang_;
    240   std::string target_lang_;
    241 
    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_;
    245 
    246   // Provides CLD data for this process.
    247   scoped_ptr<RendererCldDataProvider> cld_data_provider_;
    248 
    249   // Whether or not polling for CLD2 data has started.
    250   bool cld_data_polling_started_;
    251 
    252   // Whether or not CancelCldDataPolling has been called.
    253   bool cld_data_polling_canceled_;
    254 
    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_;
    258 
    259   // The ID of the page most recently reported to PageCaptured if
    260   // deferred_page_capture_ is true.
    261   int deferred_page_seq_no_;
    262 
    263   // The world ID to use for script execution.
    264   int world_id_;
    265 
    266   // The extension group.
    267   int extension_group_;
    268 
    269   // The URL scheme for translate extensions.
    270   std::string extension_scheme_;
    271 
    272   // The contents of the page most recently reported to PageCaptured if
    273   // deferred_page_capture_ is true.
    274   base::string16 deferred_contents_;
    275 
    276   // Method factory used to make calls to TranslatePageImpl.
    277   base::WeakPtrFactory<TranslateHelper> weak_method_factory_;
    278 
    279   DISALLOW_COPY_AND_ASSIGN(TranslateHelper);
    280 };
    281 
    282 }  // namespace translate
    283 
    284 #endif  // COMPONENTS_TRANSLATE_CONTENT_RENDERER_TRANSLATE_HELPER_H_
    285