Bug 971054 - Parts 5 and 6. Move translation content handler to its own jsm and hook up it with the UI and engine. r=florian
authorFelipe Gomes <felipc@gmail.com>
Mon, 19 May 2014 17:33:41 -0300
changeset 183699 03aa0984c4371ff59e67dc3333649d5e44328571
parent 183698 92970bb568ca659b73ec387bb160d8617a14898c
child 183700 703fae2e244cab39498e99bc44481785fe6da867
push id6853
push userfelipc@gmail.com
push dateMon, 19 May 2014 20:34:43 +0000
treeherderfx-team@03aa0984c437 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersflorian
bugs971054
milestone32.0a1
Bug 971054 - Parts 5 and 6. Move translation content handler to its own jsm and hook up it with the UI and engine. r=florian
browser/base/content/content.js
browser/components/translation/Translation.jsm
browser/components/translation/TranslationContentHandler.jsm
browser/components/translation/moz.build
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -5,18 +5,16 @@
 
 let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ContentLinkHandler",
   "resource:///modules/ContentLinkHandler.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "LanguageDetector",
-  "resource:///modules/translation/LanguageDetector.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent",
   "resource://gre/modules/LoginManagerContent.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "InsecurePasswordUtils",
   "resource://gre/modules/InsecurePasswordUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "UITour",
   "resource:///modules/UITour.jsm");
@@ -437,56 +435,14 @@ let PageStyleHandler = {
                    disabled: currentStyleSheet.disabled});
     }
 
     return result;
   },
 };
 PageStyleHandler.init();
 
-let TranslationHandler = {
-  init: function() {
-    let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
-                              .getInterface(Ci.nsIWebProgress);
-    webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
-  },
-
-  /* nsIWebProgressListener implementation */
-  onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
-    // Don't bother if we're not a toplevel document, if this isn't the 'stop'
-    // notification, or if the content document has gone away
-    if (!aWebProgress.isTopLevel ||
-        !(aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) ||
-        !content)
-      return;
-
-    let url = aRequest.name;
-    if (!url.startsWith("http://") && !url.startsWith("https://"))
-      return;
-
-    // Grab a 60k sample of text from the page.
-    let encoder = Cc["@mozilla.org/layout/documentEncoder;1?type=text/plain"]
-                    .createInstance(Ci.nsIDocumentEncoder);
-    encoder.init(content.document, "text/plain", encoder.SkipInvisibleContent);
-    let string = encoder.encodeToStringWithMaxLength(60 * 1024);
-
-    // Language detection isn't reliable on very short strings.
-    if (string.length < 100)
-      return;
-
-    LanguageDetector.detectLanguage(string).then(result => {
-      if (result.confident)
-        sendAsyncMessage("LanguageDetection:Result", result.language);
-    });
-  },
-
-  // Unused methods.
-  onProgressChange: function() {},
-  onLocationChange: function() {},
-  onStatusChange:   function() {},
-  onSecurityChange: function() {},
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                         Ci.nsISupportsWeakReference])
-};
-
-if (Services.prefs.getBoolPref("browser.translation.detectLanguage"))
-  TranslationHandler.init();
+// Keep a reference to the translation content handler to avoid it it being GC'ed.
+let trHandler = null;
+if (Services.prefs.getBoolPref("browser.translation.detectLanguage")) {
+  Cu.import("resource:///modules/translation/TranslationContentHandler.jsm");
+  trHandler = new TranslationContentHandler(global, docShell);
+}
--- a/browser/components/translation/Translation.jsm
+++ b/browser/components/translation/Translation.jsm
@@ -51,28 +51,34 @@ this.Translation = {
  * - showOriginalContent, method showing the original page content.
  * - showTranslatedContent, method showing the translation for an
  *   already translated page whose original content is shown.
  * - originalShown, boolean indicating if the original or translated
  *   version of the page is shown.
  */
 function TranslationUI(aBrowser) {
   this.browser = aBrowser;
+  aBrowser.messageManager.addMessageListener("Translation:Finished", this);
 }
 
 TranslationUI.prototype = {
   STATE_OFFER: 0,
   STATE_TRANSLATING: 1,
   STATE_TRANSLATED: 2,
   STATE_ERROR: 3,
 
   translate: function(aFrom, aTo) {
     this.state = this.STATE_TRANSLATING;
     this.translatedFrom = aFrom;
     this.translatedTo = aTo;
+
+    this.browser.messageManager.sendAsyncMessage(
+      "Translation:TranslateDocument",
+      { from: aFrom, to: aTo }
+    );
   },
 
   showURLBarIcon: function(aTranslated) {
     let chromeWin = this.browser.ownerGlobal;
     let PopupNotifications = chromeWin.PopupNotifications;
     let removeId = aTranslated ? "translate" : "translated";
     let notification =
       PopupNotifications.getNotification(removeId, this.browser);
@@ -104,21 +110,23 @@ TranslationUI.prototype = {
       notif.state = val;
     this._state = val;
   },
 
   originalShown: true,
   showOriginalContent: function() {
     this.showURLBarIcon();
     this.originalShown = true;
+    this.browser.messageManager.sendAsyncMessage("Translation:ShowOriginal");
   },
 
   showTranslatedContent: function() {
     this.showURLBarIcon(true);
     this.originalShown = false;
+    this.browser.messageManager.sendAsyncMessage("Translation:ShowTranslation");
   },
 
   get notificationBox() this.browser.ownerGlobal.gBrowser.getNotificationBox(),
 
   showTranslationInfoBar: function() {
     let notificationBox = this.notificationBox;
     let notif = notificationBox.appendNotification("", "translation", null,
                                                    notificationBox.PRIORITY_INFO_HIGH);
@@ -148,10 +156,24 @@ TranslationUI.prototype = {
     this.originalShown = true;
 
     this.showURLBarIcon();
 
     if (!this.shouldShowInfoBar(this.browser.currentURI, aDetectedLanguage))
       return null;
 
     return this.showTranslationInfoBar();
+  },
+
+  receiveMessage: function(msg) {
+    switch (msg.name) {
+      case "Translation:Finished":
+        if (msg.data.success) {
+          this.state = this.STATE_TRANSLATED;
+          this.showURLBarIcon(true);
+          this.originalShown = false;
+        } else {
+          this.state = this.STATE_ERROR;
+        }
+        break;
+    }
   }
 };
new file mode 100644
--- /dev/null
+++ b/browser/components/translation/TranslationContentHandler.jsm
@@ -0,0 +1,97 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "TranslationContentHandler" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "LanguageDetector",
+  "resource:///modules/translation/LanguageDetector.jsm");
+
+this.TranslationContentHandler = function(global, docShell) {
+  let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+                            .getInterface(Ci.nsIWebProgress);
+  webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
+
+  global.addMessageListener("Translation:TranslateDocument", this);
+  global.addMessageListener("Translation:ShowTranslation", this);
+  global.addMessageListener("Translation:ShowOriginal", this);
+  this.global = global;
+}
+
+TranslationContentHandler.prototype = {
+  /* nsIWebProgressListener implementation */
+  onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
+    if (!aWebProgress.isTopLevel ||
+        !(aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) ||
+        !this.global.content)
+      return;
+
+    let url = aRequest.name;
+    if (!url.startsWith("http://") && !url.startsWith("https://"))
+      return;
+
+    // Grab a 60k sample of text from the page.
+    let encoder = Cc["@mozilla.org/layout/documentEncoder;1?type=text/plain"]
+                    .createInstance(Ci.nsIDocumentEncoder);
+    encoder.init(this.global.content.document, "text/plain", encoder.SkipInvisibleContent);
+    let string = encoder.encodeToStringWithMaxLength(60 * 1024);
+
+    // Language detection isn't reliable on very short strings.
+    if (string.length < 100)
+      return;
+
+    LanguageDetector.detectLanguage(string).then(result => {
+      if (result.confident)
+        this.global.sendAsyncMessage("LanguageDetection:Result", result.language);
+    });
+  },
+
+  // Unused methods.
+  onProgressChange: function() {},
+  onLocationChange: function() {},
+  onStatusChange:   function() {},
+  onSecurityChange: function() {},
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+                                         Ci.nsISupportsWeakReference]),
+
+  receiveMessage: function(msg) {
+    switch (msg.name) {
+      case "Translation:TranslateDocument":
+      {
+        Cu.import("resource:///modules/translation/TranslationDocument.jsm");
+        Cu.import("resource:///modules/translation/BingTranslator.jsm");
+
+        let translationDocument = new TranslationDocument(this.global.content.document);
+        let bingTranslation = new BingTranslation(translationDocument,
+                                                  msg.data.from,
+                                                  msg.data.to);
+
+        this.global.content.translationDocument = translationDocument;
+        bingTranslation.translate().then(
+          success => {
+            this.global.sendAsyncMessage("Translation:Finished", {success: true});
+            translationDocument.showTranslation();
+          },
+          error => {
+            this.global.sendAsyncMessage("Translation:Finished", {success: false});
+          }
+        );
+        break;
+      }
+
+      case "Translation:ShowOriginal":
+        this.global.content.translationDocument.showOriginal();
+        break;
+
+      case "Translation:ShowTranslation":
+        this.global.content.translationDocument.showTranslation();
+        break;
+    }
+  }
+};
--- a/browser/components/translation/moz.build
+++ b/browser/components/translation/moz.build
@@ -5,16 +5,17 @@
 JS_MODULES_PATH = 'modules/translation'
 
 EXTRA_JS_MODULES = [
     'BingTranslator.jsm',
     'cld2/cld-worker.js',
     'cld2/cld-worker.js.mem',
     'LanguageDetector.jsm',
     'Translation.jsm',
+    'TranslationContentHandler.jsm',
     'TranslationDocument.jsm'
 ]
 
 JAR_MANIFESTS += ['jar.mn']
 
 BROWSER_CHROME_MANIFESTS += [
     'test/browser.ini'
 ]