Bug 1197700 - Correct mistakes in InputMethod.webidl. r=kanru, r=janjongboom, sr=smaug
☠☠ backed out by 47dc98dd7dbf ☠ ☠
authorTim Chien <timdream@gmail.com>
Wed, 09 Sep 2015 19:56:00 +0200
changeset 294347 fd40cb58dca32273fb04adf1aa8483ecf2a44503
parent 294346 b046fd76907f9cb10a12b962665038d80739481a
child 294348 08d1defbf5011c13ab533b47498819bfaa50fb88
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskanru, janjongboom, smaug
bugs1197700
milestone43.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 1197700 - Correct mistakes in InputMethod.webidl. r=kanru, r=janjongboom, sr=smaug
dom/inputmethod/Keyboard.jsm
dom/inputmethod/MozKeyboard.js
dom/inputmethod/forms.js
dom/inputmethod/mochitest/test_basic.html
dom/inputmethod/mochitest/test_bug1059163.html
dom/webidl/InputMethod.webidl
--- a/dom/inputmethod/Keyboard.jsm
+++ b/dom/inputmethod/Keyboard.jsm
@@ -126,17 +126,18 @@ this.Keyboard = {
       if (!frameLoader.ownerIsBrowserOrAppFrame) {
         return;
       }
       this.initFormsFrameScript(mm);
     }
   },
 
   initFormsFrameScript: function(mm) {
-    mm.addMessageListener('Forms:Input', this);
+    mm.addMessageListener('Forms:Focus', this);
+    mm.addMessageListener('Forms:Blur', this);
     mm.addMessageListener('Forms:SelectionChange', this);
     mm.addMessageListener('Forms:GetText:Result:OK', this);
     mm.addMessageListener('Forms:GetText:Result:Error', this);
     mm.addMessageListener('Forms:SetSelectionRange:Result:OK', this);
     mm.addMessageListener('Forms:SetSelectionRange:Result:Error', this);
     mm.addMessageListener('Forms:ReplaceSurroundingText:Result:OK', this);
     mm.addMessageListener('Forms:ReplaceSurroundingText:Result:Error', this);
     mm.addMessageListener('Forms:SendKey:Result:OK', this);
@@ -187,18 +188,21 @@ this.Keyboard = {
 
     if (0 === msg.name.indexOf('Keyboard:') &&
         ('Keyboard:Register' !== msg.name && this._keyboardID !== kbID)
        ) {
       return;
     }
 
     switch (msg.name) {
-      case 'Forms:Input':
-        this.handleFocusChange(msg);
+      case 'Forms:Focus':
+        this.handleFocus(msg);
+        break;
+      case 'Forms:Blur':
+        this.handleBlur(msg);
         break;
       case 'Forms:SelectionChange':
       case 'Forms:GetText:Result:OK':
       case 'Forms:GetText:Result:Error':
       case 'Forms:SetSelectionRange:Result:OK':
       case 'Forms:ReplaceSurroundingText:Result:OK':
       case 'Forms:SendKey:Result:OK':
       case 'Forms:SendKey:Result:Error':
@@ -269,60 +273,62 @@ this.Keyboard = {
         break;
       case 'Keyboard:Unregister':
         this._keyboardMM = null;
         this._keyboardID = -1;
         break;
     }
   },
 
-  forwardEvent: function keyboardForwardEvent(newEventName, msg) {
+  handleFocus: function keyboardHandleFocus(msg) {
+    // Set the formMM to the new message manager received.
     let mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
                 .frameLoader.messageManager;
-    if (newEventName === 'Keyboard:FocusChange') {
-      if (msg.data.type !== 'blur') { // Focus on a new input field
-        // Set the formMM to the new message manager so that
-        // message gets to the right form now on.
-        this.formMM = mm;
-      } else { // input is blurred
-        // A blur message can't be sent to the keyboard if the focus has
-        // already been taken away at first place.
-        // This check is here to prevent problem caused by out-of-order
-        // ipc messages from two processes.
-        if (mm !== this.formMM) {
-          return false;
-        }
+    this.formMM = mm;
 
-        this.formMM = null;
-      }
-    }
-
-    this.sendToKeyboard(newEventName, msg.data);
-    return true;
-  },
-
-  handleFocusChange: function keyboardHandleFocusChange(msg) {
-    let isSent = this.forwardEvent('Keyboard:FocusChange', msg);
-
-    if (!isSent) {
-      return;
-    }
+    this.forwardEvent('Keyboard:Focus', msg);
 
     // Chrome event, used also to render value selectors; that's why we need
     // the info about choices / min / max here as well...
     SystemAppProxy.dispatchEvent({
       type: 'inputmethod-contextchange',
-      inputType: msg.data.type,
+      inputType: msg.data.inputType,
       value: msg.data.value,
       choices: JSON.stringify(msg.data.choices),
       min: msg.data.min,
       max: msg.data.max
     });
   },
 
+  handleBlur: function keyboardHandleBlur(msg) {
+    let mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
+                .frameLoader.messageManager;
+    // A blur message can't be sent to the keyboard if the focus has
+    // already been taken away at first place.
+    // This check is here to prevent problem caused by out-of-order
+    // ipc messages from two processes.
+    if (mm !== this.formMM) {
+      return;
+    }
+
+    // unset formMM
+    this.formMM = null;
+
+    this.forwardEvent('Keyboard:Blur', msg);
+
+    SystemAppProxy.dispatchEvent({
+      type: 'inputmethod-contextchange',
+      inputType: 'blur'
+    });
+  },
+
+  forwardEvent: function keyboardForwardEvent(newEventName, msg) {
+    this.sendToKeyboard(newEventName, msg.data);
+  },
+
   setSelectedOption: function keyboardSetSelectedOption(msg) {
     this.sendToForm('Forms:Select:Choice', msg.data);
   },
 
   setSelectedOptions: function keyboardSetSelectedOptions(msg) {
     this.sendToForm('Forms:Select:Choice', msg.data);
   },
 
--- a/dom/inputmethod/MozKeyboard.js
+++ b/dom/inputmethod/MozKeyboard.js
@@ -181,18 +181,16 @@ function MozInputMethod() { }
 
 MozInputMethod.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   _inputcontext: null,
   _wrappedInputContext: null,
   _layouts: {},
   _window: null,
-  _isSystem: false,
-  _isKeyboard: true,
 
   classID: Components.ID("{4607330d-e7d2-40a4-9eb8-43967eae0142}"),
 
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsIDOMGlobalPropertyInitializer,
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference
   ]),
@@ -201,46 +199,31 @@ MozInputMethod.prototype = {
     this._window = win;
     this._mgmt = new MozInputMethodManager(win);
     this.innerWindowID = win.QueryInterface(Ci.nsIInterfaceRequestor)
                             .getInterface(Ci.nsIDOMWindowUtils)
                             .currentInnerWindowID;
 
     Services.obs.addObserver(this, "inner-window-destroyed", false);
 
-    let principal = win.document.nodePrincipal;
-    let perm = Services.perms.testExactPermissionFromPrincipal(principal,
-                                                               "input-manage");
-    if (perm === Ci.nsIPermissionManager.ALLOW_ACTION) {
-      this._isSystem = true;
-    }
-
-    perm = Services.perms.testExactPermissionFromPrincipal(principal, "input");
-    if (perm !== Ci.nsIPermissionManager.ALLOW_ACTION) {
-      this._isKeyboard = false;
-      return;
-    }
-
-    cpmm.addWeakMessageListener('Keyboard:FocusChange', this);
+    cpmm.addWeakMessageListener('Keyboard:Focus', this);
+    cpmm.addWeakMessageListener('Keyboard:Blur', this);
     cpmm.addWeakMessageListener('Keyboard:SelectionChange', this);
     cpmm.addWeakMessageListener('Keyboard:GetContext:Result:OK', this);
     cpmm.addWeakMessageListener('Keyboard:LayoutsChange', this);
     cpmm.addWeakMessageListener('InputRegistry:Result:OK', this);
     cpmm.addWeakMessageListener('InputRegistry:Result:Error', this);
   },
 
   uninit: function mozInputMethodUninit() {
     this._window = null;
     this._mgmt = null;
-    Services.obs.removeObserver(this, "inner-window-destroyed");
-    if (!this._isKeyboard) {
-      return;
-    }
 
-    cpmm.removeWeakMessageListener('Keyboard:FocusChange', this);
+    cpmm.removeWeakMessageListener('Keyboard:Focus', this);
+    cpmm.removeWeakMessageListener('Keyboard:Blur', this);
     cpmm.removeWeakMessageListener('Keyboard:SelectionChange', this);
     cpmm.removeWeakMessageListener('Keyboard:GetContext:Result:OK', this);
     cpmm.removeWeakMessageListener('Keyboard:LayoutsChange', this);
     cpmm.removeWeakMessageListener('InputRegistry:Result:OK', this);
     cpmm.removeWeakMessageListener('InputRegistry:Result:Error', this);
     this.setActive(false);
   },
 
@@ -250,24 +233,22 @@ MozInputMethod.prototype = {
       return;
     }
 
     let data = msg.data;
     let resolver = ('requestId' in data) ?
       this.takePromiseResolver(data.requestId) : null;
 
     switch(msg.name) {
-      case 'Keyboard:FocusChange':
-        if (data.type !== 'blur') {
-          // XXX Bug 904339 could receive 'text' event twice
-          this.setInputContext(data);
-        }
-        else {
-          this.setInputContext(null);
-        }
+      case 'Keyboard:Focus':
+        // XXX Bug 904339 could receive 'text' event twice
+        this.setInputContext(data);
+        break;
+      case 'Keyboard:Blur':
+        this.setInputContext(null);
         break;
       case 'Keyboard:SelectionChange':
         if (this.inputcontext) {
           this._inputcontext.updateSelectionContext(data, false);
         }
         break;
       case 'Keyboard:GetContext:Result:OK':
         this.setInputContext(data);
@@ -317,18 +298,18 @@ MozInputMethod.prototype = {
     if (this._inputcontext) {
       this._inputcontext.destroy();
       this._inputcontext = null;
       this._wrappedInputContext = null;
       this._mgmt._supportsSwitching = false;
     }
 
     if (data) {
-      this._mgmt._supportsSwitching = this._layouts[data.type] ?
-        this._layouts[data.type] > 1 :
+      this._mgmt._supportsSwitching = this._layouts[data.inputType] ?
+        this._layouts[data.inputType] > 1 :
         false;
 
       this._inputcontext = new MozInputContext(data);
       this._inputcontext.init(this._window);
       // inputcontext will be exposed as a WebIDL object. Create its
       // content-side object explicitly to avoid Bug 1001325.
       this._wrappedInputContext =
         this._window.MozInputContext._create(this._window, this._inputcontext);
@@ -395,45 +376,35 @@ MozInputMethod.prototype = {
         requestId: resolverId,
         inputId: inputId,
         appId: appId
       });
     }.bind(this));
   },
 
   setValue: function(value) {
-    this._ensureIsSystem();
     cpmm.sendAsyncMessage('System:SetValue', {
       'value': value
     });
   },
 
   setSelectedOption: function(index) {
-    this._ensureIsSystem();
     cpmm.sendAsyncMessage('System:SetSelectedOption', {
       'index': index
     });
   },
 
   setSelectedOptions: function(indexes) {
-    this._ensureIsSystem();
     cpmm.sendAsyncMessage('System:SetSelectedOptions', {
       'indexes': indexes
     });
   },
 
   removeFocus: function() {
-    this._ensureIsSystem();
     cpmm.sendAsyncMessage('System:RemoveFocus', {});
-  },
-
-  _ensureIsSystem: function() {
-    if (!this._isSystem) {
-      throw new this._window.Error("Should have 'input-manage' permssion.");
-    }
   }
 };
 
  /**
  * ==============================================
  * InputContextDOMRequestIpcHelper
  * ==============================================
  */
@@ -489,22 +460,20 @@ InputContextDOMRequestIpcHelper.prototyp
 
  /**
  * ==============================================
  * InputContext
  * ==============================================
  */
 function MozInputContext(ctx) {
   this._context = {
-    inputtype: ctx.type,
-    inputmode: ctx.inputmode,
+    type: ctx.type,
+    inputType: ctx.inputType,
+    inputMode: ctx.inputMode,
     lang: ctx.lang,
-    type: ["textarea", "contenteditable"].indexOf(ctx.type) > -1 ?
-              ctx.type :
-              "text",
     selectionStart: ctx.selectionStart,
     selectionEnd: ctx.selectionEnd,
     textBeforeCursor: ctx.textBeforeCursor,
     textAfterCursor: ctx.textAfterCursor
   };
 
   this._contextId = ctx.contextId;
 }
@@ -643,21 +612,21 @@ MozInputContext.prototype = {
 
   // tag name of the input field
   get type() {
     return this._context.type;
   },
 
   // type of the input field
   get inputType() {
-    return this._context.inputtype;
+    return this._context.inputType;
   },
 
   get inputMode() {
-    return this._context.inputmode;
+    return this._context.inputMode;
   },
 
   get lang() {
     return this._context.lang;
   },
 
   getText: function ic_getText(offset, length) {
     let self = this;
--- a/dom/inputmethod/forms.js
+++ b/dom/inputmethod/forms.js
@@ -992,17 +992,17 @@ let FormAssistant = {
     this.setFocusedElement(target);
     this.sendInputState(target);
     this.isHandlingFocus = true;
   },
 
   unhandleFocus: function fa_unhandleFocus() {
     this.setFocusedElement(null);
     this.isHandlingFocus = false;
-    sendAsyncMessage("Forms:Input", { "type": "blur" });
+    sendAsyncMessage("Forms:Blur", {});
   },
 
   isFocusableElement: function fa_isFocusableElement(element) {
     if (element instanceof HTMLSelectElement ||
         element instanceof HTMLTextAreaElement)
       return true;
 
     if (element instanceof HTMLOptionElement &&
@@ -1021,17 +1021,17 @@ let FormAssistant = {
 
       return element;
     }
 
     return retrieveTopLevelEditable(element) || element;
   },
 
   sendInputState: function(element) {
-    sendAsyncMessage("Forms:Input", getJSON(element, this._focusCounter));
+    sendAsyncMessage("Forms:Focus", getJSON(element, this._focusCounter));
   },
 
   getSelectionInfo: function fa_getSelectionInfo() {
     let element = this.focusedElement;
     let range =  getSelectionRange(element);
 
     let text = isContentEditable(element) ? getContentEditableText(element)
                                           : element.value;
@@ -1108,65 +1108,69 @@ function isPlainTextField(element) {
 
 function getJSON(element, focusCounter) {
   // <input type=number> has a nested anonymous <input type=text> element that
   // takes focus on behalf of the number control when someone tries to focus
   // the number control. If |element| is such an anonymous text control then we
   // need it's number control here in order to get the correct 'type' etc.:
   element = element.ownerNumberControl || element;
 
-  let type = element.type || "";
+  let type = element.tagName.toLowerCase();
+  let inputType = (element.type || "").toLowerCase();
   let value = element.value || "";
   let max = element.max || "";
   let min = element.min || "";
 
-  // Treat contenteditble element as a special text area field
+  // Treat contenteditable element as a special text area field
   if (isContentEditable(element)) {
-    type = "textarea";
+    type = "contenteditable";
+    inputType = "textarea";
     value = getContentEditableText(element);
   }
 
   // Until the input type=date/datetime/range have been implemented
   // let's return their real type even if the platform returns 'text'
-  let attributeType = element.getAttribute("type") || "";
+  let attributeInputType = element.getAttribute("type") || "";
 
-  if (attributeType) {
-    var typeLowerCase = attributeType.toLowerCase();
-    switch (typeLowerCase) {
+  if (attributeInputType) {
+    let inputTypeLowerCase = attributeInputType.toLowerCase();
+    switch (inputTypeLowerCase) {
       case "datetime":
       case "datetime-local":
       case "range":
-        type = typeLowerCase;
+        inputType = inputTypeLowerCase;
         break;
     }
   }
 
   // Gecko has some support for @inputmode but behind a preference and
   // it is disabled by default.
   // Gaia is then using @x-inputmode has its proprietary way to set
   // inputmode for fields. This shouldn't be used outside of pre-installed
   // apps because the attribute is going to disappear as soon as a definitive
   // solution will be find.
-  let inputmode = element.getAttribute('x-inputmode');
-  if (inputmode) {
-    inputmode = inputmode.toLowerCase();
+  let inputMode = element.getAttribute('x-inputmode');
+  if (inputMode) {
+    inputMode = inputMode.toLowerCase();
   } else {
-    inputmode = '';
+    inputMode = '';
   }
 
   let range = getSelectionRange(element);
   let textAround = getTextAroundCursor(value, range);
 
   return {
     "contextId": focusCounter,
 
-    "type": type.toLowerCase(),
+    "type": type,
+    "inputType": inputType,
+    "inputMode": inputMode,
+
     "choices": getListForElement(element),
     "value": value,
-    "inputmode": inputmode,
     "selectionStart": range[0],
     "selectionEnd": range[1],
     "max": max,
     "min": min,
     "lang": element.lang || "",
     "textBeforeCursor": textAround.before,
     "textAfterCursor": textAround.after
   };
--- a/dom/inputmethod/mochitest/test_basic.html
+++ b/dom/inputmethod/mochitest/test_basic.html
@@ -33,19 +33,19 @@ function runTest() {
 
     gContext = im.inputcontext;
     if (!gContext) {
       ok(false, 'Should have a non-null inputcontext.');
       inputmethod_cleanup();
       return;
     }
 
-    todo_is(gContext.type, 'input', 'The input context type should match.');
+    is(gContext.type, 'input', 'The input context type should match.');
     is(gContext.inputType, 'text', 'The inputType should match.');
-    is(gContext.inputMode, 'verbatim', 'The input mode should match.');
+    is(gContext.inputMode, 'verbatim', 'The inputMode should match.');
     is(gContext.lang, 'zh', 'The language should match.');
     is(gContext.textBeforeCursor + gContext.textAfterCursor, 'Yuan',
        'Should get the text around the cursor.');
 
     test_setSelectionRange();
   };
 
   // Set current page as an input method.
--- a/dom/inputmethod/mochitest/test_bug1059163.html
+++ b/dom/inputmethod/mochitest/test_bug1059163.html
@@ -49,16 +49,19 @@ function runTest() {
   app.src = 'data:text/html,<html><body><div id="text" contenteditable>Jan Jongboom</div></html>';
   app.setAttribute('mozbrowser', true);
   document.body.appendChild(app);
   app.addEventListener('mozbrowserloadend', function() {
     let mm = SpecialPowers.getBrowserFrameMessageManager(app);
     mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
 
     im.oninputcontextchange = function() {
+      is(im.inputcontext.type, 'contenteditable', 'type');
+      is(im.inputcontext.inputType, 'textarea', 'inputType');
+
       if (im.inputcontext) {
         im.oninputcontextchange = null;
         register();
       }
     };
 
     function register() {
       im.inputcontext.onselectionchange = function() {
--- a/dom/webidl/InputMethod.webidl
+++ b/dom/webidl/InputMethod.webidl
@@ -1,375 +1,518 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/.
  */
 
+/**
+ * InputMethod API implements a bridge between the web content hosting an input
+ * element and the input content (a.k.a. input app, virtual keyboard app,
+ * or IME). This API is input content facing in order for it to interact with
+ * the remote input element.
+ * The API also contains a few Gaia System app only methods
+ * (marked with "input-manage" permission) for Gaia System app to interact with
+ * some types of inputs and to regulate the input apps.
+ */
 [JSImplementation="@mozilla.org/b2g-inputmethod;1",
  NavigatorProperty="mozInputMethod",
  Pref="dom.mozInputMethod.enabled",
  CheckAnyPermissions="input input-manage"]
 interface MozInputMethod : EventTarget {
-  // Input Method Manager contain a few global methods expose to apps
-  readonly attribute MozInputMethodManager mgmt;
-
-  // Fired when the input context changes, include changes from and to null.
-  // The new InputContext instance will be available in the event
-  // object under |inputcontext| property.  When it changes to null it
-  // means the app (the user of this API) no longer has the control of
-  // the original focused input field.
-  // Note that if the app saves the original context, it might get
-  // void; implementation decides when to void the input context.
-  attribute EventHandler oninputcontextchange;
-
-  // An "input context" is mapped to a text field that the app is
-  // allow to mutate.  this attribute should be null when there is no
-  // text field currently focused.
-  readonly attribute MozInputContext? inputcontext;
-
+  /**
+   * Activate or decactive current API instance.
+   * Gaia System app call this method via BrowserElement#setInputMethodActive.
+   */
   [ChromeOnly]
-  // Activate or decactive current input method window.
   void setActive(boolean isActive);
 
-  // Add a dynamically declared input.
-  //
-  // The id must not be the same with any statically declared input in the app
-  // manifest. If an input of the same id is already declared, the info of that
-  // input will be updated.
-  Promise<void> addInput(DOMString inputId, object inputManifest);
+  /**
+   * InputMethodManager contain a few global methods expose to input apps.
+   */
+  readonly attribute MozInputMethodManager mgmt;
+
+  /**
+   * Fired when the input context changes, include changes from and to null.
+   * The new InputContext instance will be available in the event
+   * object under |inputcontext| property.  When it changes to null it
+   * means the app (the user of this API) no longer has the control of
+   * the original focused input field.
+   * Note that if the app saves the original context, it might get
+   * void; implementation decides when to void the input context.
+   */
+  [CheckAnyPermissions="input"]
+  attribute EventHandler oninputcontextchange;
 
-  // Remove a dynamically declared input.
-  //
-  // The id must not be the same with any statically declared input in the app
-  // manifest. Silently resolves if the input is not previously declared;
-  // rejects if attempt to remove a statically declared input.
+  /**
+   * An "input context" is mapped to a text field that the app is
+   * allow to mutate. This attribute should be null when there is no
+   * text field currently focused.
+   */
+  [CheckAnyPermissions="input"]
+  readonly attribute MozInputContext? inputcontext;
+
+  /**
+   * Add a dynamically declared input.
+   *
+   * The id must not be the same with any statically declared input in the app
+   * manifest. If an input of the same id is already declared, the info of that
+   * input will be updated.
+   */
+  [CheckAnyPermissions="input"]
+  Promise<void> addInput(DOMString inputId,
+                         MozInputMethodInputManifest inputManifest);
+
+  /**
+   * Remove a dynamically declared input.
+   *
+   * The id must not be the same with any statically declared input in the app
+   * manifest. Silently resolves if the input is not previously declared;
+   * rejects if attempt to remove a statically declared input.
+   */
+  [CheckAnyPermissions="input"]
   Promise<void> removeInput(DOMString id);
 
-  // The following are internal methods for Firefox OS system app only.
+  /**
+   * Remove focus from the current input, usable by Gaia System app, globally,
+   * regardless of the current focus state.
+   */
+  [CheckAnyPermissions="input-manage"]
+  void removeFocus();
 
-  // Set the value on the currently focused element. This has to be used
-  // for special situations where the value had to be chosen amongst a
-  // list (type=month) or a widget (type=date, time, etc.).
-  // If the value passed in parameter isn't valid (in the term of HTML5
-  // Forms Validation), the value will simply be ignored by the element.
-  [Throws]
+  /**
+   * The following are internal methods for Firefox OS System app only,
+   * for handling the "option" group inputs.
+   */
+
+  /**
+   * Set the value on the currently focused element. This has to be used
+   * for special situations where the value had to be chosen amongst a
+   * list (type=month) or a widget (type=date, time, etc.).
+   * If the value passed in parameter isn't valid (in the term of HTML5
+   * Forms Validation), the value will simply be ignored by the element.
+   */
+  [CheckAnyPermissions="input-manage"]
   void setValue(DOMString value);
 
-  // Select the <select> option specified by index.
-  // If this method is called on a <select> that support multiple
-  // selection, then the option specified by index will be added to
-  // the selection.
-  // If this method is called for a select that does not support multiple
-  // selection the previous element will be unselected.
-  [Throws]
+  /**
+   * Select the <select> option specified by index.
+   * If this method is called on a <select> that support multiple
+   * selection, then the option specified by index will be added to
+   * the selection.
+   * If this method is called for a select that does not support multiple
+   * selection the previous element will be unselected.
+   */
+  [CheckAnyPermissions="input-manage"]
   void setSelectedOption(long index);
 
-  // Select the <select> options specified by indexes. All other options
-  // will be deselected.
-  // If this method is called for a <select> that does not support multiple
-  // selection, then the last index specified in indexes will be selected.
-  [Throws]
+  /**
+   * Select the <select> options specified by indexes. All other options
+   * will be deselected.
+   * If this method is called for a <select> that does not support multiple
+   * selection, then the last index specified in indexes will be selected.
+   */
+  [CheckAnyPermissions="input-manage"]
   void setSelectedOptions(sequence<long> indexes);
-
-  [Throws]
-  void removeFocus();
 };
 
-// Manages the list of IMEs, enables/disables IME and switches to an
-// IME.
+/**
+ * InputMethodManager contains a few of the global methods for the input app.
+ */
 [JSImplementation="@mozilla.org/b2g-imm;1",
- Pref="dom.mozInputMethod.enabled"]
+ Pref="dom.mozInputMethod.enabled",
+ CheckAnyPermissions="input"]
 interface MozInputMethodManager {
-  // Ask the OS to show a list of available IMEs for users to switch from.
-  // OS should ignore this request if the app is currently not the active one.
+  /**
+   * Ask the OS to show a list of available inputs for users to switch from.
+   * OS should sliently ignore this request if the app is currently not the
+   * active one.
+   */
   void showAll();
 
-  // Ask the OS to switch away from the current active Keyboard app.
-  // OS should ignore this request if the app is currently not the active one.
+  /**
+   * Ask the OS to switch away from the current active input app.
+   * OS should sliently ignore this request if the app is currently not the
+   * active one.
+   */
   void next();
 
-  // To know if the OS supports IME switching or not.
-  // Use case: let the keyboard app knows if it is necessary to show the "IME switching"
-  // (globe) button. We have a use case that when there is only one IME enabled, we
-  // should not show the globe icon.
+  /**
+   * If this method returns true, it is recommented that the input app provides
+   * a shortcut that would invoke the next() method above, for easy switching
+   * between inputs -- i.e. show a "global" button on screen if the input app
+   * implements an on-screen virtual keyboard.
+   *
+   * The returning value is depend on the inputType of the current input context.
+   */
   boolean supportsSwitching();
 
-  // Ask the OS to hide the current active Keyboard app. (was: |removeFocus()|)
-  // OS should ignore this request if the app is currently not the active one.
-  // The OS will void the current input context (if it exists).
-  // This method belong to |mgmt| because we would like to allow Keyboard to access to
-  // this method w/o a input context.
+  /**
+   * Ask the OS to remove the input focus, will cause the lost of input context.
+   * OS should sliently ignore this request if the app is currently not the
+   * active one.
+   */
   void hide();
 };
 
-// The input context, which consists of attributes and information of current input field.
-// It also hosts the methods available to the keyboard app to mutate the input field represented.
-// An "input context" gets void when the app is no longer allowed to interact with the text field,
-// e.g., the text field does no longer exist, the app is being switched to background, and etc.
+/**
+ * The input context, which consists of attributes and information of current
+ * input field. It also hosts the methods available to the keyboard app to
+ * mutate the input field represented. An "input context" gets void when the
+ * app is no longer allowed to interact with the text field,
+ * e.g., the text field does no longer exist, the app is being switched to
+ * background, and etc.
+ */
 [JSImplementation="@mozilla.org/b2g-inputcontext;1",
- Pref="dom.mozInputMethod.enabled"]
+ Pref="dom.mozInputMethod.enabled",
+ CheckAnyPermissions="input"]
 interface MozInputContext: EventTarget {
-   // The tag name of input field, which is enum of "input", "textarea", or "contenteditable"
-   readonly attribute DOMString? type;
-   // The type of the input field, which is enum of text, number, password, url, search, email, and so on.
-   // See http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#states-of-the-type-attribute
-   readonly attribute DOMString? inputType;
-   /*
-    * The inputmode string, representing the input mode.
-    * See http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#input-modalities:-the-inputmode-attribute
-    */
-   readonly attribute DOMString? inputMode;
-   /*
-    * The primary language for the input field.
-    * It is the value of HTMLElement.lang.
-    * See http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#htmlelement
-    */
-   readonly attribute DOMString? lang;
-   /*
-    * Get the whole text content of the input field.
-    * @return DOMString
-    */
-   Promise<DOMString> getText(optional long offset, optional long length);
-   // The start and stop position of the selection.
-   readonly attribute long selectionStart;
-   readonly attribute long selectionEnd;
+  /**
+   * Type of the InputContext. See MozInputMethodInputContextTypes
+   */
+  readonly attribute MozInputMethodInputContextTypes? type;
+
+  /**
+   * InputType of the InputContext. See MozInputMethodInputContextInputTypes.
+   */
+  readonly attribute MozInputMethodInputContextInputTypes? inputType;
+
+  /**
+   * The inputmode string, representing the inputmode of the input.
+   * See http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#input-modalities:-the-inputmode-attribute
+   */
+  readonly attribute DOMString? inputMode;
 
-   // The text before and after the begining of the selected text.
-   readonly attribute DOMString? textBeforeCursor;
-   readonly attribute DOMString? textAfterCursor;
+  /**
+   * The primary language for the input field.
+   * It is the value of HTMLElement.lang.
+   * See http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#htmlelement
+   */
+  readonly attribute DOMString? lang;
+
+  /**
+   * Get the whole text content of the input field.
+   * @return DOMString
+   */
+  Promise<DOMString> getText(optional long offset, optional long length);
+
+  /**
+   * The start and stop position of the current selection.
+   */
+  readonly attribute long selectionStart;
+  readonly attribute long selectionEnd;
 
-    /*
-     * Set the selection range of the the editable text.
-     * Note: This method cannot be used to move the cursor during composition. Calling this
-     * method will cancel composition.
-     * @param start The beginning of the selected text.
-     * @param length The length of the selected text.
-     *
-     * Note that the start position should be less or equal to the end position.
-     * To move the cursor, set the start and end position to the same value.
-     *
-     * @return boolean
-     */
-    Promise<boolean> setSelectionRange(long start, long length);
+  /**
+   * The text before and after the begining of the selected text.
+   */
+  readonly attribute DOMString? textBeforeCursor;
+  readonly attribute DOMString? textAfterCursor;
 
-    /* User moves the cursor, or changes the selection with other means. If the text around
-     * cursor has changed, but the cursor has not been moved, the IME won't get notification.
-     *
-     * A dict is provided in the detail property of the event containing the new values, and
-     * an "ownAction" property to denote the event is the result of our own mutation to
-     * the input field.
-     */
-    attribute EventHandler onselectionchange;
+  /**
+   * Set the selection range of the the editable text.
+   * Note: This method cannot be used to move the cursor during composition. Calling this
+   * method will cancel composition.
+   * @param start The beginning of the selected text.
+   * @param length The length of the selected text.
+   *
+   * Note that the start position should be less or equal to the end position.
+   * To move the cursor, set the start and end position to the same value.
+   *
+   * @return boolean
+   */
+  Promise<boolean> setSelectionRange(long start, long length);
 
-    /*
-     * Commit text to current input field and replace text around
-     * cursor position. It will clear the current composition.
-     *
-     * @param text The string to be replaced with.
-     * @param offset The offset from the cursor position where replacing starts. Defaults to 0.
-     * @param length The length of text to replace. Defaults to 0.
-     * @return boolean
-     */
-    Promise<boolean> replaceSurroundingText(DOMString text, optional long offset, optional long length);
+  /* User moves the cursor, or changes the selection with other means. If the text around
+   * cursor has changed, but the cursor has not been moved, the IME won't get notification.
+   *
+   * A dict is provided in the detail property of the event containing the new values, and
+   * an "ownAction" property to denote the event is the result of our own mutation to
+   * the input field.
+   */
+  attribute EventHandler onselectionchange;
 
-    /*
-     *
-     * Delete text around the cursor.
-     * @param offset The offset from the cursor position where deletion starts.
-     * @param length The length of text to delete.
-     * TODO: maybe updateSurroundingText(DOMString beforeText, DOMString afterText); ?
-     * @return boolean
-     */
-    Promise<boolean> deleteSurroundingText(long offset, long length);
+  /**
+   * Commit text to current input field and replace text around
+   * cursor position. It will clear the current composition.
+   *
+   * @param text The string to be replaced with.
+   * @param offset The offset from the cursor position where replacing starts. Defaults to 0.
+   * @param length The length of text to replace. Defaults to 0.
+   * @return boolean
+   */
+  Promise<boolean> replaceSurroundingText(DOMString text, optional long offset, optional long length);
 
-    /*
-     * Notifies when the text around the cursor is changed, due to either text
-     * editing or cursor movement. If the cursor has been moved, but the text around has not
-     * changed, the IME won't get notification.
-     *
-     * A dict is provided in the detail property of the event containing the new values, and
-     * an "ownAction" property to denote the event is the result of our own mutation to
-     * the input field.
-     */
-    attribute EventHandler onsurroundingtextchange;
+  /**
+   * Delete text around the cursor.
+   * @param offset The offset from the cursor position where deletion starts.
+   * @param length The length of text to delete.
+   * TODO: maybe updateSurroundingText(DOMString beforeText, DOMString afterText); ?
+   * @return boolean
+   */
+  Promise<boolean> deleteSurroundingText(long offset, long length);
 
-    /*
-     * Send a string/character with its key events. There are two ways of invocating 
-     * the method for backward compability purpose.
-     *
-     * (1) The recommended way, allow specifying DOM level 3 properties like |code|.
-     * @param dictOrKeyCode See MozInputMethodKeyboardEventDict.
-     * @param charCode disregarded
-     * @param modifiers disregarded
-     * @param repeat disregarded
-     *
-     * (2) Deprecated, reserved for backward compability.
-     * @param dictOrKeyCode keyCode of the key to send, should be one of the DOM_VK_ value in KeyboardEvent.
-     * @param charCode charCode of the character, should be 0 for non-printable keys.
-     * @param modifiers this paramater is no longer honored.
-     * @param repeat indicates whether a key would be sent repeatedly.
-     *
-     * @return A promise. Resolve to true if succeeds.
-     *                    Rejects to a string indicating the error.
-     *
-     * Note that, if you want to send a key n times repeatedly, make sure set
-     * parameter repeat to true and invoke sendKey n times, and invoke keyup
-     * after the end of the input.
-     */
-    Promise<boolean> sendKey((MozInputMethodRequiredKeyboardEventDict or long) dictOrKeyCode,
-                             optional long charCode, 
-                             optional long modifiers, 
-                             optional boolean repeat);
+  /**
+   * Notifies when the text around the cursor is changed, due to either text
+   * editing or cursor movement. If the cursor has been moved, but the text around has not
+   * changed, the IME won't get notification.
+   *
+   * A dict is provided in the detail property of the event containing the new values, and
+   * an "ownAction" property to denote the event is the result of our own mutation to
+   * the input field.
+   */
+  attribute EventHandler onsurroundingtextchange;
 
-    /*
-     * Send a string/character with keydown, and keypress events.
-     * keyup should be called afterwards to ensure properly sequence.
-     *
-     * @param dict See MozInputMethodKeyboardEventDict.
-     *
-     * @return A promise. Resolve to true if succeeds.
-     *                    Rejects to a string indicating the error.
-     */
-    Promise<boolean> keydown(MozInputMethodRequiredKeyboardEventDict dict);
+  /**
+   * Send a string/character with its key events. There are two ways of invocating
+   * the method for backward compability purpose.
+   *
+   * (1) The recommended way, allow specifying DOM level 3 properties like |code|.
+   * @param dictOrKeyCode See MozInputMethodKeyboardEventDict.
+   * @param charCode disregarded
+   * @param modifiers disregarded
+   * @param repeat disregarded
+   *
+   * (2) Deprecated, reserved for backward compability.
+   * @param dictOrKeyCode keyCode of the key to send, should be one of the DOM_VK_ value in KeyboardEvent.
+   * @param charCode charCode of the character, should be 0 for non-printable keys.
+   * @param modifiers this paramater is no longer honored.
+   * @param repeat indicates whether a key would be sent repeatedly.
+   *
+   * @return A promise. Resolve to true if succeeds.
+   *                    Rejects to a string indicating the error.
+   *
+   * Note that, if you want to send a key n times repeatedly, make sure set
+   * parameter repeat to true and invoke sendKey n times, and invoke keyup
+   * after the end of the input.
+   */
+  Promise<boolean> sendKey((MozInputMethodRequiredKeyboardEventDict or long) dictOrKeyCode,
+                           optional long charCode,
+                           optional long modifiers,
+                           optional boolean repeat);
 
-    /*
-     * Send a keyup event. keydown should be called first to ensure properly sequence.
-     *
-     * @param dict See MozInputMethodKeyboardEventDict.
-     *
-     * @return A promise. Resolve to true if succeeds.
-     *                    Rejects to a string indicating the error.
-     *
-     */
-    Promise<boolean> keyup(MozInputMethodRequiredKeyboardEventDict dict);
+  /**
+   * Send a string/character with keydown, and keypress events.
+   * keyup should be called afterwards to ensure properly sequence.
+   *
+   * @param dict See MozInputMethodKeyboardEventDict.
+   *
+   * @return A promise. Resolve to true if succeeds.
+   *                    Rejects to a string indicating the error.
+   */
+  Promise<boolean> keydown(MozInputMethodRequiredKeyboardEventDict dict);
 
-    /*
-     * Set current composing text. This method will start composition or update
-     * composition if it has started. The composition will be started right
-     * before the cursor position and any selected text will be replaced by the
-     * composing text. When the composition is started, calling this method can
-     * update the text and move cursor winthin the range of the composing text.
-     * @param text The new composition text to show.
-     * @param cursor The new cursor position relative to the start of the
-     * composition text. The cursor should be positioned within the composition
-     * text. This means the value should be >= 0 and <= the length of
-     * composition text. Defaults to the lenght of composition text, i.e., the
-     * cursor will be positioned after the composition text.
-     * @param clauses The array of composition clause information. If not set,
-     * only one clause is supported.
-     * @param dict The properties of the keyboard event that cause the composition
-     * to set. keydown or keyup event will be fired if it's necessary.
-     * For compatibility, we recommend that you should always set this argument 
-     * if it's caused by a key operation.
-     * 
-     * The composing text, which is shown with underlined style to distinguish
-     * from the existing text, is used to compose non-ASCII characters from
-     * keystrokes, e.g. Pinyin or Hiragana. The composing text is the
-     * intermediate text to help input complex character and is not committed to
-     * current input field. Therefore if any text operation other than
-     * composition is performed, the composition will automatically end. Same
-     * apply when the inputContext is lost during an unfinished composition
-     * session.
-     *
-     * To finish composition and commit text to current input field, an IME
-     * should call |endComposition|.
-     */
-    Promise<boolean> setComposition(DOMString text, 
-                                    optional long cursor,
-                                    optional sequence<CompositionClauseParameters> clauses,
-                                    optional MozInputMethodKeyboardEventDict dict);
+  /**
+   * Send a keyup event. keydown should be called first to ensure properly sequence.
+   *
+   * @param dict See MozInputMethodKeyboardEventDict.
+   *
+   * @return A promise. Resolve to true if succeeds.
+   *                    Rejects to a string indicating the error.
+   */
+  Promise<boolean> keyup(MozInputMethodRequiredKeyboardEventDict dict);
 
-    /*
-     * End composition, clear the composing text and commit given text to
-     * current input field. The text will be committed before the cursor
-     * position.
-     * @param text The text to commited before cursor position. If empty string
-     * is given, no text will be committed.
-     * @param dict The properties of the keyboard event that cause the composition
-     * to end. keydown or keyup event will be fired if it's necessary.
-     * For compatibility, we recommend that you should always set this argument 
-     * if it's caused by a key operation.
-     *
-     * Note that composition always ends automatically with nothing to commit if
-     * the composition does not explicitly end by calling |endComposition|, but
-     * is interrupted by |sendKey|, |setSelectionRange|,
-     * |replaceSurroundingText|, |deleteSurroundingText|, user moving the
-     * cursor, changing the focus, etc.
-     */
-    Promise<boolean> endComposition(optional DOMString text, 
-                                    optional MozInputMethodKeyboardEventDict dict);
+  /**
+   * Set current composing text. This method will start composition or update
+   * composition if it has started. The composition will be started right
+   * before the cursor position and any selected text will be replaced by the
+   * composing text. When the composition is started, calling this method can
+   * update the text and move cursor winthin the range of the composing text.
+   * @param text The new composition text to show.
+   * @param cursor The new cursor position relative to the start of the
+   * composition text. The cursor should be positioned within the composition
+   * text. This means the value should be >= 0 and <= the length of
+   * composition text. Defaults to the lenght of composition text, i.e., the
+   * cursor will be positioned after the composition text.
+   * @param clauses The array of composition clause information. If not set,
+   * only one clause is supported.
+   * @param dict The properties of the keyboard event that cause the composition
+   * to set. keydown or keyup event will be fired if it's necessary.
+   * For compatibility, we recommend that you should always set this argument
+   * if it's caused by a key operation.
+   *
+   * The composing text, which is shown with underlined style to distinguish
+   * from the existing text, is used to compose non-ASCII characters from
+   * keystrokes, e.g. Pinyin or Hiragana. The composing text is the
+   * intermediate text to help input complex character and is not committed to
+   * current input field. Therefore if any text operation other than
+   * composition is performed, the composition will automatically end. Same
+   * apply when the inputContext is lost during an unfinished composition
+   * session.
+   *
+   * To finish composition and commit text to current input field, an IME
+   * should call |endComposition|.
+   */
+  Promise<boolean> setComposition(DOMString text,
+                                  optional long cursor,
+                                  optional sequence<CompositionClauseParameters> clauses,
+                                  optional MozInputMethodKeyboardEventDict dict);
+
+  /**
+   * End composition, clear the composing text and commit given text to
+   * current input field. The text will be committed before the cursor
+   * position.
+   * @param text The text to commited before cursor position. If empty string
+   * is given, no text will be committed.
+   * @param dict The properties of the keyboard event that cause the composition
+   * to end. keydown or keyup event will be fired if it's necessary.
+   * For compatibility, we recommend that you should always set this argument
+   * if it's caused by a key operation.
+   *
+   * Note that composition always ends automatically with nothing to commit if
+   * the composition does not explicitly end by calling |endComposition|, but
+   * is interrupted by |sendKey|, |setSelectionRange|,
+   * |replaceSurroundingText|, |deleteSurroundingText|, user moving the
+   * cursor, changing the focus, etc.
+   */
+  Promise<boolean> endComposition(optional DOMString text,
+                                  optional MozInputMethodKeyboardEventDict dict);
 };
 
 enum CompositionClauseSelectionType {
   "raw-input",
   "selected-raw-text",
   "converted-text",
   "selected-converted-text"
 };
 
 dictionary CompositionClauseParameters {
-  DOMString selectionType = "raw-input";
+  CompositionClauseSelectionType selectionType = "raw-input";
   long length;
 };
 
-/*
+/**
+ * Types are HTML tag names of the inputs that is explosed with InputContext,
+ * *and* the special keyword "contenteditable" for contenteditable element.
+ */
+enum MozInputMethodInputContextTypes {
+  "input", "textarea", "contenteditable"
+  /**
+   * <select> is managed by the API but it's not exposed through InputContext
+   * yet.
+   */
+  // "select"
+};
+
+/**
+ * InputTypes of the input that InputContext is representing. The value
+ * is inferred from the type attribute of input element.
+ *
+ * See https://html.spec.whatwg.org/multipage/forms.html#states-of-the-type-attribute
+ *
+ * They are divided into groups -- an layout/input capable of handling one type
+ * in the group is considered as capable of handling all of the types in the
+ * same group.
+ * The layout/input that could handle type "text" is considered as the fallback
+ * if none of layout/input installed can handle a specific type.
+ *
+ * Groups and fallbacks is enforced in Gaia System app currently.
+ *
+ * Noted that the actual virtual keyboard to show, for example in the case of
+ * Gaia Keyboard app, will also depend on the inputMode of the input element.
+ */
+enum MozInputMethodInputContextInputTypes {
+  /**
+   * Group "text". Be reminded that contenteditable element is assigned with
+   * an input type of "textarea".
+   */
+  "text", "search", "textarea",
+  /**
+   * Group "number"
+   */
+  "number", "tel",
+  /**
+   * Group "url"
+   */
+  "url",
+  /**
+   * Group "email"
+   */
+  "email",
+  /**
+   * Group "password".
+   * An non-Latin alphabet layout/input should not be able to handle this type.
+   */
+  "password"
+  /**
+   * Group "option". These types are handled by System app itself currently, and
+   * not exposed and allowed to handled with input context.
+   */
+  //"datetime", "date", "month", "week", "time", "datetime-local", "color",
+  /**
+   * These types are ignored by the API even though they are valid
+   * HTMLInputElement#type.
+   */
+  //"checkbox", "radio", "file", "submit", "image", "range", "reset", "button"
+};
+
+/**
+ * An input app can host multiple inputs (a.k.a. layouts) and the capability of
+ * the input is described by the input manifest.
+ */
+dictionary MozInputMethodInputManifest {
+  required DOMString launch_path;
+  required DOMString name;
+  DOMString? description;
+  sequence<MozInputMethodInputContextInputTypes> types;
+};
+
+/**
  * A MozInputMethodKeyboardEventDictBase contains the following properties,
  * indicating the properties of the keyboard event caused.
  *
  * This is the base dictionary type for us to create two child types that could
  * be used as argument type in two types of methods, as WebIDL parser required.
- * 
+ *
  */
 dictionary MozInputMethodKeyboardEventDictBase {
-  /*
+  /**
    * String/character to output, or a registered name of non-printable key.
    * (To be defined in the inheriting dictionary types.)
    */
   // DOMString key;
-  /*
+  /**
    * String/char indicating the virtual hardware key pressed. Optional.
    * Must be a value defined in
    * http://www.w3.org/TR/DOM-Level-3-Events-code/#keyboard-chording-virtual
    * If your keyboard app emulates physical keyboard layout, this value should
    * not be empty string. Otherwise, it should be empty string.
    */
   DOMString code = "";
-  /*
+  /**
    * keyCode of the keyboard event. Optional.
    * To be disregarded if |key| is an alphanumeric character.
    * If the key causes inputting a character and if your keyboard app emulates
    * a physical keyboard layout, this value should be same as the value used
    * by Firefox for desktop. If the key causes inputting an ASCII character
    * but if your keyboard app doesn't emulate any physical keyboard layouts,
    * the value should be proper value for the key value.
    */
   long? keyCode;
-  /*
+  /**
    * Indicates whether a key would be sent repeatedly. Optional.
    */
   boolean repeat = false;
-  /*
+  /**
    * Optional. True if |key| property is explicitly referring to a printable key.
    * When this is set, key will be printable even if the |key| value matches any
    * of the registered name of non-printable keys.
    */
   boolean printable = false;
 };
 
-/*
+/**
  * For methods like setComposition() and endComposition(), the optional
  * dictionary type argument is really optional when all of it's property
  * are optional.
  * This dictionary type is used to denote that argument.
  */
 dictionary MozInputMethodKeyboardEventDict : MozInputMethodKeyboardEventDictBase {
   DOMString? key;
 };
 
-/*
+/**
  * For methods like keydown() and keyup(), the dictionary type argument is
  * considered required only if at least one of it's property is required.
  * This dictionary type is used to denote that argument.
  */
 dictionary MozInputMethodRequiredKeyboardEventDict : MozInputMethodKeyboardEventDictBase {
   required DOMString key;
 };