Bug 1525035 - Handle IME composition in Quantum Bar. r=adw
authorMarco Bonardo <mbonardo@mozilla.com>
Fri, 22 Feb 2019 20:02:35 +0000
changeset 460661 62bec7b76cab37d9678759b7b2d5be5eb1e86e69
parent 460660 ca2b32dbbae0129a998e50f9199fc822376163d1
child 460662 218e965ee9b363861ff07772f24c23aed3ac3d37
push id78797
push usermak77@bonardo.net
push dateFri, 22 Feb 2019 20:03:45 +0000
treeherderautoland@62bec7b76cab [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersadw
bugs1525035
milestone67.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 1525035 - Handle IME composition in Quantum Bar. r=adw Differential Revision: https://phabricator.services.mozilla.com/D20826
browser/components/urlbar/UrlbarInput.jsm
browser/components/urlbar/UrlbarUtils.jsm
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -109,27 +109,31 @@ class UrlbarInput {
     // our handleEvent at the right time.
     this.eventBufferer = new UrlbarEventBufferer(this);
     this.inputField.addEventListener("blur", this.eventBufferer);
     this.inputField.addEventListener("keydown", this.eventBufferer);
 
     const inputFieldEvents = [
       "focus", "input", "keyup", "mouseover", "paste", "scrollend", "select",
       "overflow", "underflow", "dragstart", "dragover", "drop",
+      "compositionstart", "compositionend",
     ];
     for (let name of inputFieldEvents) {
       this.inputField.addEventListener(name, this);
     }
 
     this.addEventListener("mousedown", this);
     this.view.panel.addEventListener("popupshowing", this);
     this.view.panel.addEventListener("popuphidden", this);
 
     this.inputField.controllers.insertControllerAt(0, new CopyCutController(this));
     this._initPasteAndGo();
+
+    // Tracks IME composition.
+    this._compositionState == UrlbarUtils.COMPOSITION.NONE;
   }
 
   /**
    * Shortens the given value, usually by removing http:// and trailing slashes,
    * such that calling nsIURIFixup::createFixupURI with the result will produce
    * the same URI.
    *
    * @param {string} val
@@ -984,16 +988,36 @@ class UrlbarInput {
     }
     this.removeAttribute("actiontype");
 
     if (!value && this.view.isOpen) {
       this.view.close();
       return;
     }
 
+    // During composition with an IME, the following events happen in order:
+    // 1. a compositionstart event
+    // 2. some input events
+    // 3. a compositionend event
+    // 4. an input event
+
+    // We should do nothing during composition.
+    if (this._compositionState == UrlbarUtils.COMPOSITION.COMPOSING) {
+      return;
+    }
+
+    if (this._compositionState == UrlbarUtils.COMPOSITION.COMMIT) {
+      this._compositionState = UrlbarUtils.COMPOSITION.NONE;
+    }
+
+    // Note: if in the future we should re-implement the legacy optimization
+    // where we didn't search again when the string is the same, skip it if we
+    // are committing a composition; since the search was canceled on
+    // composition start, we should restart it.
+
     // XXX Fill in lastKey, and add anything else we need.
     this.startQuery({
       lastKey: null,
     });
   }
 
   _on_select(event) {
     if (!Services.clipboard.supportsSelectionClipboard()) {
@@ -1082,16 +1106,36 @@ class UrlbarInput {
     this.controller.handleKeyNavigation(event);
     this._toggleActionOverride(event);
   }
 
   _on_keyup(event) {
     this._toggleActionOverride(event);
   }
 
+  _on_compositionstart(event) {
+    if (this._compositionState == UrlbarUtils.COMPOSITION.COMPOSING) {
+      throw new Error("Trying to start a nested composition?");
+    }
+    this._compositionState = UrlbarUtils.COMPOSITION.COMPOSING;
+
+    // Close the view. This will also stop searching.
+    this.closePopup();
+  }
+
+  _on_compositionend(event) {
+    if (this._compositionState != UrlbarUtils.COMPOSITION.COMPOSING) {
+      throw new Error("Trying to stop a non existing composition?");
+    }
+
+    // We can't yet retrieve the committed value from the editor, since it isn't
+    // completely committed yet. We'll handle it at the next input event.
+    this._compositionState = UrlbarUtils.COMPOSITION.COMMIT;
+  }
+
   _on_popupshowing() {
     this.setAttribute("open", "true");
   }
 
   _on_popuphidden() {
     this.removeAttribute("open");
   }
 
--- a/browser/components/urlbar/UrlbarUtils.jsm
+++ b/browser/components/urlbar/UrlbarUtils.jsm
@@ -102,16 +102,23 @@ var UrlbarUtils = {
   },
 
   // This defines icon locations that are common used in the UI.
   ICON: {
     DEFAULT: Ci.nsIFaviconService.FAVICON_DEFAULT_URL,
     SEARCH_GLASS: "chrome://browser/skin/search-glass.svg",
   },
 
+  // IME composition states.
+  COMPOSITION: {
+    NONE: 1,
+    COMPOSING: 2,
+    COMMIT: 3,
+  },
+
   /**
    * Adds a url to history as long as it isn't in a private browsing window,
    * and it is valid.
    *
    * @param {string} url The url to add to history.
    * @param {nsIDomWindow} window The window from where the url is being added.
    */
   addToUrlbarHistory(url, window) {