Bug 766878 - IME prototype doesn't work with <iframe mozbrowser remote>. r=cjones
authorVivien Nicolas <21@vingtetun.org>
Tue, 26 Jun 2012 16:01:53 +0200
changeset 102980 069b6fb2b5c589db304554778d009538ea0bb252
parent 102979 de70e79ced32b414eca99e219430c20d73b16500
child 102981 a22ca1e05bb8191c03967cae739c7abaeb4a9390
push id191
push userlsblakk@mozilla.com
push dateFri, 05 Oct 2012 17:12:53 +0000
treeherdermozilla-release@ddb22ac6c03b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs766878
milestone16.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 766878 - IME prototype doesn't work with <iframe mozbrowser remote>. r=cjones
b2g/chrome/content/forms.js
b2g/chrome/content/webapi.js
b2g/components/MozKeyboard.js
--- a/b2g/chrome/content/forms.js
+++ b/b2g/chrome/content/forms.js
@@ -8,120 +8,110 @@ dump("##################################
 
 "use strict";
 
 let Ci = Components.interfaces;
 let Cc = Components.classes;
 let Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 XPCOMUtils.defineLazyServiceGetter(Services, "fm",
                                    "@mozilla.org/focus-manager;1",
                                    "nsIFocusManager");
 
 let HTMLInputElement = Ci.nsIDOMHTMLInputElement;
 let HTMLTextAreaElement = Ci.nsIDOMHTMLTextAreaElement;
 let HTMLSelectElement = Ci.nsIDOMHTMLSelectElement;
 let HTMLOptGroupElement = Ci.nsIDOMHTMLOptGroupElement;
 let HTMLOptionElement = Ci.nsIDOMHTMLOptionElement;
 
 let FormAssistant = {
   init: function fa_init() {
     addEventListener("focus", this, true, false);
+    addEventListener("blur", this, true, false);
     addEventListener("keypress", this, true, false);
-    addEventListener("mousedown", this, true, false);
     addEventListener("resize", this, true, false);
-    addEventListener("click", this, true, false);
-    addEventListener("blur", this, true, false);
     addMessageListener("Forms:Select:Choice", this);
     addMessageListener("Forms:Input:Value", this);
     Services.obs.addObserver(this, "ime-enabled-state-changed", false);
     Services.obs.addObserver(this, "xpcom-shutdown", false);
   },
 
   isKeyboardOpened: false,
   previousTarget : null,
   handleEvent: function fa_handleEvent(evt) {
     let previousTarget = this.previousTarget;
     let target = evt.target;
 
     switch (evt.type) {
       case "focus":
-        this.previousTarget = Services.fm.focusedElement;
-        break;
-
-      case "blur":
-        if (!target)
-          return;
-        this.previousTarget = null;
-
-        if (target instanceof HTMLSelectElement ||
-            (target instanceof HTMLOptionElement && target.parentNode instanceof HTMLSelectElement)) {
-
-          sendAsyncMessage("Forms:Input", { "type": "blur" });
-        }
-        break;
-
-      case 'resize':
-        if (!this.isKeyboardOpened)
-          return;
-
-        Services.fm.focusedElement.scrollIntoView(false);
-        break;
-
-      case "mousedown":
-        if (evt.target != target || this.isKeyboardOpened)
+        if (this.isKeyboardOpened)
           return;
 
         let ignore = {
           button: true,
+          file: true,
           checkbox: true,
-          file: true,
           radio: true,
           reset: true,
           submit: true
         };
     
-        if ((target instanceof HTMLInputElement && ignore[target.type]) ||
-            !(target instanceof HTMLInputElement ||
-              target instanceof HTMLTextAreaElement)) {
+        if (evt.target instanceof HTMLSelectElement) { 
+          content.setTimeout(function showIMEForSelect() {
+            sendAsyncMessage("Forms:Input", getJSON(evt.target));
+          });
+        } else if (evt.target instanceof HTMLOptionElement &&
+                   evt.target.parentNode instanceof HTMLSelectElement) {
+          content.setTimeout(function showIMEForSelect() {
+            sendAsyncMessage("Forms:Input", getJSON(evt.target.parentNode));
+          });
+        } else if ((target instanceof HTMLInputElement && !ignore[target.type]) ||
+                    target instanceof HTMLTextAreaElement) {
+          this.isKeyboardOpened = this.tryShowIme(evt.target);
+          this.previousTarget = evt.target;
+        }
+        break;
+
+      case "blur":
+        if (this.previousTarget) {
+          sendAsyncMessage("Forms:Input", { "type": "blur" });
+          this.previousTarget = null;
+        }
+        break;
+
+      case "resize":
+        if (!this.isKeyboardOpened)
           return;
+
+        let focusedElement = this.previousTarget;
+        if (focusedElement) {
+          focusedElement.scrollIntoView(false);
         }
-
-        this.isKeyboardOpened = this.tryShowIme(evt.target);
         break;
 
       case "keypress":
         if (evt.keyCode != evt.DOM_VK_ESCAPE || !this.isKeyboardOpened)
           return;
 
         sendAsyncMessage("Forms:Input", { "type": "blur" });
         this.isKeyboardOpened = false;
 
         evt.preventDefault();
         evt.stopPropagation();
         break;
-
-      case "click":
-        content.setTimeout(function showIMEForSelect() {
-          if (evt.target instanceof HTMLSelectElement) { 
-            sendAsyncMessage("Forms:Input", getJSON(evt.target));
-          } else if (evt.target instanceof HTMLOptionElement &&
-                     evt.target.parentNode instanceof HTMLSelectElement) {
-            sendAsyncMessage("Forms:Input", getJSON(evt.target.parentNode));
-          }
-        });
-        break;
     }
   },
 
   receiveMessage: function fa_receiveMessage(msg) {
-    let target = Services.fm.focusedElement;
-    if (!target)
+    let target = this.previousTarget;
+    if (!target) {
       return;
+    }
 
     let json = msg.json;
     switch (msg.name) {
       case "Forms:Input:Value":
         target.value = json.value;
         break;
 
       case "Forms:Select:Choice":
@@ -164,29 +154,31 @@ let FormAssistant = {
         break;
     }
   },
 
   tryShowIme: function(element) {
     // FIXME/bug 729623: work around apparent bug in the IME manager
     // in gecko.
     let readonly = element.getAttribute("readonly");
-    if (readonly)
+    if (readonly) {
       return false;
+    }
 
     sendAsyncMessage("Forms:Input", getJSON(element));
     return true;
   }
 };
 
 FormAssistant.init();
 
 
 function getJSON(element) {
-  let type = element.type;
+  let type = element.type || "";
+
   // FIXME/bug 344616 is input type="number"
   // Until then, let's return 'number' even if the platform returns 'text'
   let attributeType = element.getAttribute("type") || "";
   if (attributeType && attributeType.toLowerCase() === "number")
     type = "number";
 
   return {
     "type": type.toLowerCase(),
--- a/b2g/chrome/content/webapi.js
+++ b/b2g/chrome/content/webapi.js
@@ -8,20 +8,16 @@
 
 dump('======================= webapi.js ======================= \n');
 
 let { classes: Cc, interfaces: Ci, utils: Cu }  = Components;
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/Geometry.jsm');
 
-XPCOMUtils.defineLazyServiceGetter(Services, 'fm',
-                                   '@mozilla.org/focus-manager;1',
-                                   'nsIFocusManager');
-
 const ContentPanning = {
   init: function cp_init() {
     ['mousedown', 'mouseup', 'mousemove'].forEach(function(type) {
       addEventListener(type, ContentPanning, true);
     });
   },
 
   handleEvent: function cp_handleEvent(evt) {
--- a/b2g/components/MozKeyboard.js
+++ b/b2g/components/MozKeyboard.js
@@ -2,16 +2,17 @@
  * 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";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
+const kFormsFrameScript = "chrome://browser/content/forms.js";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 const messageManager = Cc["@mozilla.org/globalmessagemanager;1"]
                          .getService(Ci.nsIChromeFrameMessageManager);
 
 
@@ -32,20 +33,22 @@ MozKeyboard.prototype = {
     "classID": Components.ID("{397a7fdf-2254-47be-b74e-76625a1a66d5}"),
     "contractID": "@mozilla.org/b2g-keyboard;1",
     "interfaces": [Ci.nsIB2GKeyboard],
     "flags": Ci.nsIClassInfo.DOM_OBJECT,
     "classDescription": "B2G Virtual Keyboard"
   }),
 
   init: function mozKeyboardInit(win) {
-    messageManager.loadFrameScript("chrome://browser/content/forms.js", true);
+    messageManager.loadFrameScript(kFormsFrameScript, true);
     messageManager.addMessageListener("Forms:Input", this);
 
     Services.obs.addObserver(this, "inner-window-destroyed", false);
+    Services.obs.addObserver(this, 'in-process-browser-frame-shown', false);
+    Services.obs.addObserver(this, 'remote-browser-frame-shown', false);
 
     this._window = win;
     this._utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
                      .getInterface(Ci.nsIDOMWindowUtils);
     this.innerWindowID = this._utils.currentInnerWindowID;
 
     this._focusHandler = null;
   },
@@ -100,19 +103,34 @@ MozKeyboard.prototype = {
       "detail": msg.json
     };
 
     let evt = new this._window.CustomEvent("focuschanged", detail);
     handler.handleEvent(evt);
   },
 
   observe: function mozKeyboardObserve(subject, topic, data) {
-    if (topic == "inner-window-destroyed") {
+    switch (topic) {
+    case "inner-window-destroyed": {
       let wId = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
       if (wId == this.innerWindowID) {
         this.uninit();
       }
+      break;
+    }
+    case 'remote-browser-frame-shown':
+    case 'in-process-browser-frame-shown': {
+      let frameLoader = subject.QueryInterface(Ci.nsIFrameLoader);
+      let mm = frameLoader.messageManager;
+      mm.addMessageListener("Forms:Input", this);
+      try {
+        mm.loadFrameScript(kFormsFrameScript, true);
+      } catch (e) {
+        dump('Error loading ' + kFormsFrameScript + ' as frame script: ' + e + '\n');
+      }
+      break;
+    }
     }
   }
 };
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([MozKeyboard]);