Bug 857823 - rip out more obsolete FormHelper code, add a new deck transisioning check in cao, and add support in FormHelperUI for delaying menu display until the view updates. r=fryn
authorJim Mathies <jmathies@mozilla.com>
Fri, 05 Apr 2013 05:33:43 -0500
changeset 127788 3d0b269794a9f738bc74cb50038872c33a943bb0
parent 127787 a6225409a345dec7aabd015379f24ad181c98fca
child 127789 c680d2e04a83a28f8ec13024982c035aec444e53
push id24512
push userryanvm@gmail.com
push dateFri, 05 Apr 2013 20:13:49 +0000
treeherdermozilla-central@139b6ba547fa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfryn
bugs857823
milestone23.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 857823 - rip out more obsolete FormHelper code, add a new deck transisioning check in cao, and add support in FormHelperUI for delaying menu display until the view updates. r=fryn
browser/metro/base/content/ContentAreaObserver.js
browser/metro/base/content/browser.xul
browser/metro/base/content/contenthandlers/FormHelper.js
browser/metro/base/content/helperui/FormHelperUI.js
browser/metro/profile/metro.js
--- a/browser/metro/base/content/ContentAreaObserver.js
+++ b/browser/metro/base/content/ContentAreaObserver.js
@@ -22,22 +22,33 @@
   *  The area of the window dedicated to web content; this is equal to the
   *  innerWidth/Height minus any toolbars or similar chrome.
   *
   *  styles: viewable-width, viewable-height
   *  events: ViewableSizeChanged
   *
   *  The portion of the content area that is not obscured by the on-screen
   *  keyboard.
+  *
+  * ContentAreaObserver also manages soft keyboard related events. Events
+  * fired include:
+  *
+  *  KeyboardChanged - fired after the visibility of the soft keyboard changes
+  *  and after any view related changes are made to accomidate view dim
+  *  changes as a result.
+  *
+  *  MozDeckOffsetChanging, MozDeckOffsetChanged - interim events fired when
+  *  the browser deck is being repositioned to move focused elements out of
+  *  the way of the keyboard.
   */
 
 var ContentAreaObserver = {
   styles: {},
-  _keyboardState: false,
   _shiftAmount: 0,
+  _deckTransitioning: false,
 
   /*
    * Properties
    */
 
   get width() {
     return window.innerWidth || 1366;
   },
@@ -57,16 +68,20 @@ var ContentAreaObserver = {
   get viewableHeight() {
     return this._getViewableHeightForContent(this.contentHeight);
   },
 
   get isKeyboardOpened() {
     return MetroUtils.keyboardVisible;
   },
 
+  get isKeyboardTransitioning() {
+    return this._deckTransitioning;
+  },
+
   /*
    * Public apis
    */
 
   init: function init() {
     window.addEventListener("resize", this, false);
 
     // Message manager msgs we listen for
@@ -153,49 +168,48 @@ var ContentAreaObserver = {
     aBrowser.classList.add("content-height");
   },
 
   /*
    * Event handling
    */
 
   _onKeyboardDisplayChanging: function _onKeyboardDisplayChanging(aNewState) {
-    this._keyboardState = aNewState;
-
-    this._dispatchWindowEvent("KeyboardChanged", aNewState);
-
     this.updateViewableArea();
 
     if (!aNewState) {
       this._shiftBrowserDeck(0);
       return;
     }
 
     // Request info about the target form element to see if we
     // need to reposition the browser above the keyboard.
     Browser.selectedBrowser.messageManager.sendAsyncMessage("Browser:RepositionInfoRequest", {
       viewHeight: this.viewableHeight,
     });
   },
 
   _onRepositionResponse: function _onRepositionResponse(aJsonMsg) {
-    if (!aJsonMsg.reposition || !this._keyboardState) {
+    if (!aJsonMsg.reposition || !this.isKeyboardOpened) {
       this._shiftBrowserDeck(0);
       return;
     }
     this._shiftBrowserDeck(aJsonMsg.raiseContent);
   },
 
   observe: function cao_observe(aSubject, aTopic, aData) {
     // Note these are fired before the transition starts. Also per MS specs
     // we should not do anything "heavy" here. We have about 100ms before
     // windows just ignores the event and starts the animation.
     switch (aTopic) {
       case "metro_softkeyboard_hidden":
       case "metro_softkeyboard_shown":
+        // Mark that we are in a transition state. Auto-complete and other
+        // popups will wait for an event before displaying anything.
+        this._deckTransitioning = true;
         // This also insures tap events are delivered before we fire
         // this event. Form repositioning requires the selection handler
         // be running before we send this.
         let self = this;
         let state = aTopic == "metro_softkeyboard_shown";
         Util.executeSoon(function () {
           self._onKeyboardDisplayChanging(state);
         });
@@ -221,27 +235,34 @@ var ContentAreaObserver = {
     }
   },
 
   /*
    * Internal helpers
    */
 
   _shiftBrowserDeck: function _shiftBrowserDeck(aAmount) {
+    if (aAmount == 0) {
+      this._deckTransitioning = false;
+      this._dispatchWindowEvent("KeyboardChanged", this.isKeyboardOpened);
+    }
+
     if (this._shiftAmount == aAmount)
       return;
 
     this._shiftAmount = aAmount;
     this._dispatchWindowEvent("MozDeckOffsetChanging", aAmount);
 
     // Elements.browsers is the deck all browsers sit in
     let self = this;
     Elements.browsers.addEventListener("transitionend", function () {
       Elements.browsers.removeEventListener("transitionend", arguments.callee, true);
+      self._deckTransitioning = false;
       self._dispatchWindowEvent("MozDeckOffsetChanged", aAmount);
+      self._dispatchWindowEvent("KeyboardChanged", self.isKeyboardOpened);
     }, true);
 
     // selectAtPoint bug 858471
     //Elements.browsers.style.transform = "translateY(" + (-1 * aAmount) + "px)";
     Elements.browsers.style.marginTop = "" + (-1 * aAmount) + "px";
   },
 
   _dispatchWindowEvent: function _dispatchWindowEvent(aEventName, aDetail) {
--- a/browser/metro/base/content/browser.xul
+++ b/browser/metro/base/content/browser.xul
@@ -458,21 +458,16 @@
         </hbox>
       </settings>
       <setting pref="signon.rememberSignons" title="&optionsHeader.privacy.passwords.label;" type="bool"/>
       <settings id="prefs-donottrack" label="&optionsHeader.privacy.doNotTrack.title;">
         <setting pref="privacy.donottrackheader.enabled" title="&optionsHeader.privacy.doNotTrack.label;" type="bool"/>
       </settings>
     </flyoutpanel>
 
-    <!-- Form Helper form validation helper popup -->
-    <arrowbox id="form-helper-validation-container" class="arrowbox-dark" flex="1" hidden="true" offset="0" top="0" left="0">
-      <label/>
-    </arrowbox>
-
 #ifdef MOZ_SERVICES_SYNC
     <box id="syncsetup-container" class="perm-modal-block" hidden="true">
       <dialog id="syncsetup-dialog" class="content-dialog" flex="1">
         <vbox class="prompt-inner">
           <hbox class="prompt-title">
             <description>&sync.setup.title;</description>
           </hbox>
           <vbox id="syncsetup-simple" class="syncsetup-page" flex="1">
--- a/browser/metro/base/content/contenthandlers/FormHelper.js
+++ b/browser/metro/base/content/contenthandlers/FormHelper.js
@@ -3,18 +3,16 @@
  * 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/. */
 
 let Ci = Components.interfaces;
 let Cc = Components.classes;
 
 dump("### FormHelper.js loaded\n");
 
-const kPrefFormHelperEnabled = "formhelper.enabled";
-
 let HTMLTextAreaElement = Ci.nsIDOMHTMLTextAreaElement;
 let HTMLInputElement = Ci.nsIDOMHTMLInputElement;
 let HTMLSelectElement = Ci.nsIDOMHTMLSelectElement;
 let HTMLIFrameElement = Ci.nsIDOMHTMLIFrameElement;
 let HTMLDocument = Ci.nsIDOMHTMLDocument;
 let HTMLHtmlElement = Ci.nsIDOMHTMLHtmlElement;
 let HTMLBodyElement = Ci.nsIDOMHTMLBodyElement;
 let HTMLLabelElement = Ci.nsIDOMHTMLLabelElement;
@@ -23,38 +21,32 @@ let HTMLOptGroupElement = Ci.nsIDOMHTMLO
 let HTMLOptionElement = Ci.nsIDOMHTMLOptionElement;
 let XULMenuListElement = Ci.nsIDOMXULMenuListElement;
 
 /**
  * Responsible of navigation between forms fields and of the opening of the assistant
  */
 function FormAssistant() {
   addMessageListener("FormAssist:Closed", this);
-  addMessageListener("FormAssist:Previous", this);
-  addMessageListener("FormAssist:Next", this);
   addMessageListener("FormAssist:ChoiceSelect", this);
   addMessageListener("FormAssist:ChoiceChange", this);
   addMessageListener("FormAssist:AutoComplete", this);
-  addMessageListener("Content:SetWindowSize", this);
+  addMessageListener("FormAssist:Update", this);
 
   /* Listen text events in order to update the autocomplete suggestions as soon
    * a key is entered on device
    */
   addEventListener("text", this, false);
-
   addEventListener("keypress", this, true);
   addEventListener("keyup", this, false);
   addEventListener("focus", this, true);
   addEventListener("blur", this, true);
   addEventListener("pageshow", this, false);
   addEventListener("pagehide", this, false);
   addEventListener("submit", this, false);
-
-  this._enabled = Services.prefs.prefHasUserValue(kPrefFormHelperEnabled) ?
-                    Services.prefs.getBoolPref(kPrefFormHelperEnabled) : false;
 };
 
 FormAssistant.prototype = {
   _els: Cc["@mozilla.org/eventlistenerservice;1"].getService(Ci.nsIEventListenerService),
   _open: false,
   _focusSync: false,
   _debugEvents: false,
   _selectWrapper: null,
@@ -90,19 +82,16 @@ FormAssistant.prototype = {
       // example, in this "fun" case just do nothing if the element is hidden
       if (self._isVisibleElement(gFocusManager.focusedElement))
         sendAsyncMessage("FormAssist:Show", self._getJSON());
     });
     return this._currentElement;
   },
 
   open: function formHelperOpen(aElement, aEvent) {
-    this._enabled = Services.prefs.prefHasUserValue(kPrefFormHelperEnabled) ?
-                    Services.prefs.getBoolPref(kPrefFormHelperEnabled) : false;
-
     // If the click is on an option element we want to check if the parent
     // is a valid target.
     if (aElement instanceof HTMLOptionElement &&
         aElement.parentNode instanceof HTMLSelectElement &&
         !aElement.disabled) {
       aElement = aElement.parentNode;
     }
 
@@ -130,18 +119,17 @@ FormAssistant.prototype = {
     }
 
     // Look for a top editable element
     if (this._isEditable(aElement)) {
       aElement = this._getTopLevelEditable(aElement);
     }
 
     // We only work with choice lists or elements with autocomplete suggestions
-    if (!this._enabled &&
-        !this._isSelectElement(aElement) &&
+    if (!this._isSelectElement(aElement) &&
         !this._isAutocomplete(aElement)) {
       return this.close();
     }
 
     // Enable the assistant
     this.currentElement = aElement;
     return this._open = true;
   },
@@ -155,32 +143,25 @@ FormAssistant.prototype = {
 
     return this._open;
   },
 
   receiveMessage: function receiveMessage(aMessage) {
     if (this._debugEvents) Util.dumpLn(aMessage.name);
 
     let currentElement = this.currentElement;
-    if ((!this._enabled &&
-         !this._isAutocomplete(currentElement) &&
+    if ((!this._isAutocomplete(currentElement) &&
          !getWrapperForElement(currentElement)) ||
         !currentElement) {
       return;
     }
 
     let json = aMessage.json;
 
     switch (aMessage.name) {
-      case "Content:SetWindowSize":
-        // If the CSS viewport change just show the current element to the new
-        // position
-        sendAsyncMessage("FormAssist:Resize", this._getJSON());
-        break;
-
       case "FormAssist:ChoiceSelect": {
         this._selectWrapper = getWrapperForElement(currentElement);
         this._selectWrapper.select(json.index, json.selected);
         break;
       }
 
       case "FormAssist:ChoiceChange": {
         // ChoiceChange could happened once we have move to another element or
@@ -216,32 +197,23 @@ FormAssistant.prototype = {
         currentElement.dispatchEvent(event);
         break;
       }
 
       case "FormAssist:Closed":
         currentElement.blur();
         this._open = false;
         break;
+
+      case "FormAssist:Update":
+        sendAsyncMessage("FormAssist:Show", this._getJSON());
+        break;
     }
   },
 
-  _hasKeyListener: function _hasKeyListener(aElement) {
-    let els = this._els;
-    let listeners = els.getListenerInfoFor(aElement, {});
-    for (let i = 0; i < listeners.length; i++) {
-      let listener = listeners[i];
-      if (["keyup", "keydown", "keypress"].indexOf(listener.type) != -1
-          && !listener.inSystemEventGroup) {
-        return true;
-      }
-    }
-    return false;
-  },
-
   handleEvent: function formHelperHandleEvent(aEvent) {
     if (this._debugEvents) Util.dumpLn(aEvent.type, this.currentElement);
     // focus changes should be taken into account only if the user has done a
     // manual operation like manually clicking
     let shouldIgnoreFocus = (aEvent.type == "focus" && !this._open && !this.focusSync);
     if ((!this._open && aEvent.type != "focus") || shouldIgnoreFocus) {
       return;
     }
@@ -304,33 +276,26 @@ FormAssistant.prototype = {
           // we should close the form assistant.
           let focusedElement = gFocusManager.getFocusedElementForWindow(content, true, {});
           if (!focusedElement)
             self.close();
         }, 0, this);
         break;
 
       case "text":
-        if (this._isValidatable(aEvent.target))
-          sendAsyncMessage("FormAssist:ValidationMessage", this._getJSON());
-
         if (this._isAutocomplete(aEvent.target))
           sendAsyncMessage("FormAssist:AutoComplete", this._getJSON());
         break;
 
       case "keyup":
         // There is no need to handle keys if there is not element currently
         // used by the form assistant
         if (!currentElement)
           return;
 
-        if (this._isValidatable(aEvent.target)) {
-          sendAsyncMessage("FormAssist:ValidationMessage", this._getJSON());
-        }
-
         if (this._isAutocomplete(aEvent.target)) {
           sendAsyncMessage("FormAssist:AutoComplete", this._getJSON());
         }
 
         let caretRect = this._getCaretRect();
         if (!caretRect.isEmpty())
           sendAsyncMessage("FormAssist:Update", { caretRect: caretRect });
     }
@@ -340,16 +305,18 @@ FormAssistant.prototype = {
     let self = this;
     let timer = new Util.Timeout(function() {
       aCallback(self);
     });
     timer.once(0);
   },
 
   _isEditable: function formHelperIsEditable(aElement) {
+    if (!aElement)
+      return false;
     let canEdit = false;
 
     if (aElement.isContentEditable || aElement.designMode == "on") {
       canEdit = true;
     } else if (aElement instanceof HTMLIFrameElement &&
                (aElement.contentDocument.body.isContentEditable ||
                 aElement.contentDocument.designMode == "on")) {
       canEdit = true;
@@ -376,24 +343,16 @@ FormAssistant.prototype = {
       // Return the container frame if we are into a nested editable frame
       if (element && element instanceof HTMLBodyElement && element.ownerDocument.defaultView != content.document.defaultView)
         return element.ownerDocument.defaultView.frameElement;
     }
 
     return aElement;
   },
 
-  _isValidatable: function(aElement) {
-    return this.invalidSubmit &&
-           (aElement instanceof HTMLInputElement ||
-            aElement instanceof HTMLTextAreaElement ||
-            aElement instanceof HTMLSelectElement ||
-            aElement instanceof HTMLButtonElement);
-  },
-
   _isAutocomplete: function formHelperIsAutocomplete(aElement) {
     if (aElement instanceof HTMLInputElement) {
       if (aElement.getAttribute("type") == "password")
         return false;
 
       let autocomplete = aElement.getAttribute("autocomplete");
       let allowedValues = ["off", "false", "disabled"];
       if (allowedValues.indexOf(autocomplete) == -1)
@@ -523,17 +482,18 @@ FormAssistant.prototype = {
         }
       }
     }
     return elRect;
   },
 
   _getLabels: function formHelperGetLabels() {
     let associatedLabels = [];
-
+    if (!this.currentElement)
+      return associatedLabels;
     let element = this.currentElement;
     let labels = element.ownerDocument.getElementsByTagName("label");
     for (let i=0; i<labels.length; i++) {
       let label = labels[i];
       if ((label.control == element || label.getAttribute("for") == element.id) && this._isVisibleElement(label)) {
         associatedLabels.push({
           rect: getBoundingContentRect(label),
           title: label.textContent
@@ -555,24 +515,21 @@ FormAssistant.prototype = {
         id: element.id,
         name: element.name,
         title: labels.length ? labels[0].title : "",
         value: element.value,
         maxLength: element.maxLength,
         type: (element.getAttribute("type") || "").toLowerCase(),
         choices: choices,
         isAutocomplete: this._isAutocomplete(element),
-        validationMessage: this.invalidSubmit ? element.validationMessage : null,
         list: this._getListSuggestions(element),
         rect: this._getRect(),
         caretRect: this._getCaretRect(),
         editable: editable
       },
-      hasPrevious: false,
-      hasNext: false
     };
   },
 
   /**
    * For each radio button group, remove all but the checked button
    * if there is one, or the first button otherwise.
    */
   _filterRadioButtons: function(aNodes) {
--- a/browser/metro/base/content/helperui/FormHelperUI.js
+++ b/browser/metro/base/content/helperui/FormHelperUI.js
@@ -1,81 +1,60 @@
 /* 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/. */
 
 /*
  * Responsible for filling in form information.
- *  - When an element is focused, the browser view zooms in to the control.
- *  - The caret positionning and the view are sync to keep the type
- *    in text into view for input fields (text/textarea).
+ *  - displays select popups
  *  - Provides autocomplete box for input fields.
  */
 
 const kBrowserFormZoomLevelMin = 0.8;
 const kBrowserFormZoomLevelMax = 2.0;
 
-// Prefs
-const kPrefFormHelperEnabled = "formhelper.enabled";
-const kPrefFormHelperMode = "formhelper.mode";
-const kPrefFormHelperZoom = "formhelper.autozoom";
-const kPrefFormHelperZoomCaret = "formhelper.autozoom.caret";
-
 var FormHelperUI = {
   _debugEvents: false,
   _currentBrowser: null,
   _currentElement: null,
   _currentCaretRect: null,
   _currentElementRect: null,
+  _open: false,
 
   type: "form",
 
-  get enabled() {
-    return Services.prefs.getBoolPref(kPrefFormHelperEnabled);
-  },
-
   init: function formHelperInit() {
     // Listen for form assistant messages from content
     messageManager.addMessageListener("FormAssist:Show", this);
     messageManager.addMessageListener("FormAssist:Hide", this);
     messageManager.addMessageListener("FormAssist:Update", this);
-    messageManager.addMessageListener("FormAssist:Resize", this);
     messageManager.addMessageListener("FormAssist:AutoComplete", this);
-    messageManager.addMessageListener("FormAssist:ValidationMessage", this);
 
     // Listen for events where form assistant should be closed or updated
     let tabs = Elements.tabList;
     tabs.addEventListener("TabSelect", this, true);
     tabs.addEventListener("TabClose", this, true);
     Elements.browsers.addEventListener("URLChanged", this, true);
     Elements.browsers.addEventListener("SizeChanged", this, true);
 
     // Listen some events to show/hide arrows
     Elements.browsers.addEventListener("PanBegin", this, false);
     Elements.browsers.addEventListener("PanFinished", this, false);
-
-    // Dynamically enabled/disabled the form helper if needed depending on
-    // the size of the screen
-    let mode = Services.prefs.getIntPref(kPrefFormHelperMode);
-    let state = (mode == 2) ? false : !!mode;
-    Services.prefs.setBoolPref(kPrefFormHelperEnabled, state);
   },
 
   /*
    * Open of the form helper proper. Currently doesn't display anything
    * on metro since the nav buttons are off.
    */
-  show: function formHelperShow(aElement, aHasPrevious, aHasNext) {
+  show: function formHelperShow(aElement) {
     // Delay the operation until all resize operations generated by the
-    // keyboard apparition are done. This avoid doing unuseful zooming
-    // operations.
-    if (aElement.editable &&
-        (MetroUtils.immersive && !ContentAreaObserver.isKeyboardOpened &&
-         !InputSourceHelper.isPrecise)) {
-      this._waitForKeyboard(aElement, aHasPrevious, aHasNext);
+    // keyboard apparition are done.
+    if (!InputSourceHelper.isPrecise && aElement.editable &&
+        ContentAreaObserver.isKeyboardTransitioning) {
+      this._waitForKeyboard(aElement);
       return;
     }
 
     this._currentBrowser = Browser.selectedBrowser;
     this._currentCaretRect = null;
 
     let lastElement = this._currentElement || null;
 
@@ -83,46 +62,62 @@ var FormHelperUI = {
       id: aElement.id,
       name: aElement.name,
       title: aElement.title,
       value: aElement.value,
       maxLength: aElement.maxLength,
       type: aElement.type,
       choices: aElement.choices,
       isAutocomplete: aElement.isAutocomplete,
-      validationMessage: aElement.validationMessage,
       list: aElement.list,
       rect: aElement.rect
     };
 
-    this._zoom(Rect.fromRect(aElement.rect), Rect.fromRect(aElement.caretRect));
     this._updateContainerForSelect(lastElement, this._currentElement);
     this._updatePopupsFor(this._currentElement);
 
     // Prevent the view to scroll automatically while typing
     this._currentBrowser.scrollSync = false;
+
+    this._open = true;
   },
 
   hide: function formHelperHide() {
+    this._open = false;
+
     SelectHelperUI.hide();
     AutofillMenuUI.hide();
 
     // Restore the scroll synchonisation
     if (this._currentBrowser)
       this._currentBrowser.scrollSync = true;
 
     // reset current Element and Caret Rect
     this._currentElementRect = null;
     this._currentCaretRect = null;
 
     this._updateContainerForSelect(this._currentElement, null);
     if (this._currentBrowser)
       this._currentBrowser.messageManager.sendAsyncMessage("FormAssist:Closed", { });
   },
 
+  _onShowRequest: function _onShowRequest(aJsonMsg) {
+    if (aJsonMsg.current.choices) {
+      // Note, aJsonMsg.current.rect is translated from browser to client
+      // in the SelectHelperUI code.
+      SelectHelperUI.show(aJsonMsg.current.choices, aJsonMsg.current.title,
+                          aJsonMsg.current.rect);
+    } else {
+      this._currentBrowser = getBrowser();
+      this._currentElementRect =
+        Rect.fromRect(this._currentBrowser.rectBrowserToClient(aJsonMsg.current.rect));
+      this.show(aJsonMsg.current);
+    }
+  },
+
   /*
    * Events
    */
 
   handleEvent: function formHelperHandleEvent(aEvent) {
     if (this._debugEvents) Util.dumpLn(aEvent.type);
 
     if (!this._open)
@@ -140,156 +135,55 @@ var FormHelperUI = {
         if (aEvent.detail && aEvent.target == getBrowser())
           this.hide();
         break;
     }
   },
 
   receiveMessage: function formHelperReceiveMessage(aMessage) {
     if (this._debugEvents) Util.dumpLn(aMessage.name);
-    let allowedMessages = ["FormAssist:Show", "FormAssist:Hide",
-                           "FormAssist:AutoComplete", "FormAssist:ValidationMessage"];
-    if (!this._open && allowedMessages.indexOf(aMessage.name) == -1)
-      return;
+    let json = aMessage.json;
 
-    let json = aMessage.json;
     switch (aMessage.name) {
       case "FormAssist:Show":
-        // if the user has manually disabled the Form Assistant UI we still
-        // want to show a UI for <select /> element and still want to show
-        // autocomplete suggestions but not managed by FormHelperUI
-        if (this.enabled) {
-          this.show(json.current, json.hasPrevious, json.hasNext)
-        } else if (json.current.choices) {
-          SelectHelperUI.show(json.current.choices, json.current.title, json.current.rect);
-        } else {
-          this._currentElementRect = Rect.fromRect(json.current.rect);
-          this._currentBrowser = getBrowser();
-          this._updatePopupsFor(json.current);
-        }
+        this._onShowRequest(json);
         break;
 
       case "FormAssist:Hide":
-        if (this.enabled) {
-          this.hide();
-        }
-        break;
-
-      case "FormAssist:Resize":
-        if (!ContentAreaObserver.isKeyboardOpened)
-          return;
-
-        let element = json.current;
-        this._zoom(Rect.fromRect(element.rect), Rect.fromRect(element.caretRect));
-        break;
-
-      case "FormAssist:ValidationMessage":
-        this._updatePopupsFor(json.current, { fromInput: true });
+        this.hide();
         break;
 
       case "FormAssist:AutoComplete":
-        this._updatePopupsFor(json.current, { fromInput: true });
-        break;
-
-       case "FormAssist:Update":
-        if (!ContentAreaObserver.isKeyboardOpened)
-          return;
-        //this._zoom(null, Rect.fromRect(json.caretRect));
+        this.show(json.current);
         break;
     }
   },
 
   doAutoComplete: function formHelperDoAutoComplete(aData) {
     this._currentBrowser.messageManager.sendAsyncMessage("FormAssist:AutoComplete",
       { value: aData });
   },
 
-  get _open() {
-    // XXX we don't have the ability to test zooming
-    return true;
-  },
-
-  /*
-   * Update all popups based on the type of form element we are
-   * dealing with.
-   */
-  _updatePopupsFor: function _formHelperUpdatePopupsFor(aElement, options) {
-    options = options || {};
-
-    let fromInput = 'fromInput' in options && options.fromInput;
-
-    // The order of the updates matters here. If the popup update was
-    // triggered from user input (e.g. key press in an input element),
-    // we first check if there are input suggestions then check for
-    // a validation message. The idea here is that the validation message
-    // will be shown straight away once the invalid element is focused
-    // and suggestions will be shown as user inputs data. Only one popup
-    // is shown at a time. If both are not shown, then we ensure any
-    // previous popups are hidden.
-    let noPopupsShown = fromInput ?
-                        (!this._updateSuggestionsFor(aElement) &&
-                         !this._updateFormValidationFor(aElement)) :
-                        (!this._updateFormValidationFor(aElement) &&
-                         !this._updateSuggestionsFor(aElement));
-
-    if (noPopupsShown) {
+  _updatePopupsFor: function _formHelperUpdatePopupsFor(aElement) {
+    if (!this._updateSuggestionsFor(aElement)) {
       AutofillMenuUI.hide();
     }
   },
 
   /*
    * Populates the autofill menu for this element.
    */
   _updateSuggestionsFor: function _formHelperUpdateSuggestionsFor(aElement) {
     let suggestions = this._getAutocompleteSuggestions(aElement);
     if (!suggestions.length)
       return false;
-
-    // the scrollX/scrollY position can change because of the animated zoom so
-    // delay the suggestions positioning
-    /*
-    if (AnimatedZoom.isZooming()) {
-      let self = this;
-      this._waitForZoom(function() {
-        self._updateSuggestionsFor(aElement);
-      });
-      return true;
-    }
-    */
-    
     AutofillMenuUI.show(this._currentElementRect, suggestions);
     return true;
   },
 
-  _updateFormValidationFor: function _formHelperUpdateFormValidationFor(aElement) {
-    if (!aElement.validationMessage)
-      return false;
-    /*
-    // the scrollX/scrollY position can change because of the animated zoom so
-    // delay the suggestions positioning
-    if (AnimatedZoom.isZooming()) {
-      let self = this;
-      this._waitForZoom(function() {
-        self._updateFormValidationFor(aElement);
-      });
-      return true;
-    }
-
-    let validationContainer = document.getElementById("form-helper-validation-container");
-
-    // Update label with form validation message
-    validationContainer.firstChild.value = aElement.validationMessage;
-
-    ContentPopupHelper.popup = validationContainer;
-    ContentPopupHelper.anchorTo(this._currentElementRect);
-    */
-
-    return false;
-  },
-
   /*
    * Retrieve the autocomplete list from the autocomplete service for an element
    */
   _getAutocompleteSuggestions: function _formHelperGetAutocompleteSuggestions(aElement) {
     if (!aElement.isAutocomplete) {
       return [];
     }
 
@@ -326,129 +220,17 @@ var FormHelperUI = {
     let currentHasChoices = aCurrentElement && (aCurrentElement.choices != null);
 
     if (currentHasChoices)
       SelectHelperUI.show(aCurrentElement.choices, aCurrentElement.title, aCurrentElement.rect);
     else if (lastHasChoices)
       SelectHelperUI.hide();
   },
 
-  /*
-   * Zoom and move viewport so that element is legible and touchable.
-   */
-  _zoom: function _formHelperZoom(aElementRect, aCaretRect) {
-    let browser = getBrowser();
-    let zoomRect = Rect.fromRect(browser.getBoundingClientRect());
-
-    this._currentElementRect = aElementRect;
-
-    // Zoom to a specified Rect
-    let autozoomEnabled = Services.prefs.getBoolPref(kPrefFormHelperZoom);
-    if (aElementRect && Browser.selectedTab.allowZoom && autozoomEnabled) {
-      this._currentElementRect = aElementRect;
-
-      // Zoom to an element by keeping the caret into view
-      let zoomLevel = Browser.selectedTab.clampZoomLevel(this._getZoomLevelForRect(aElementRect));
-
-      zoomRect = Browser._getZoomRectForPoint(aElementRect.center().x, aElementRect.y, zoomLevel);
-      AnimatedZoom.animateTo(zoomRect);
-    } else if (aElementRect && !Browser.selectedTab.allowZoom && autozoomEnabled) {
-      this._currentElementRect = aElementRect;
-
-      // Even if zooming is disabled we could need to reposition the view in
-      // order to keep the element on-screen
-      zoomRect = Browser._getZoomRectForPoint(aElementRect.center().x, aElementRect.y, browser.scale);
-      AnimatedZoom.animateTo(zoomRect);
-    }
-
-    this._ensureCaretVisible(aCaretRect);
-  },
-
-  _ensureCaretVisible: function _ensureCaretVisible(aCaretRect) {
-    if (!aCaretRect || !Services.prefs.getBoolPref(kPrefFormHelperZoomCaret))
-      return;
-
-    // the scrollX/scrollY position can change because of the animated zoom so
-    // delay the caret adjustment
-    if (AnimatedZoom.isZooming()) {
-      let self = this;
-      this._waitForZoom(function() {
-        self._ensureCaretVisible(aCaretRect);
-      });
-      return;
-    }
-
-    let browser = getBrowser();
-    let zoomRect = Rect.fromRect(browser.getBoundingClientRect());
-
-    this._currentCaretRect = aCaretRect;
-    let caretRect = aCaretRect.clone().scale(browser.scale, browser.scale);
-
-    let scroll = browser.getRootView().getPosition();
-    zoomRect = new Rect(scroll.x, scroll.y, zoomRect.width, zoomRect.height);
-    if (zoomRect.contains(caretRect))
-      return;
-
-    let [deltaX, deltaY] = this._getOffsetForCaret(caretRect, zoomRect);
-    if (deltaX != 0 || deltaY != 0) {
-      let view = browser.getRootView();
-      view.scrollBy(deltaX, deltaY);
-    }
-  },
-
-  _waitForZoom: function _formHelperWaitForZoom(aCallback) {
-    let currentElement = this._currentElement;
-    let self = this;
-    window.addEventListener("AnimatedZoomEnd", function() {
-      window.removeEventListener("AnimatedZoomEnd", arguments.callee, true);
-      // Ensure the current element has not changed during this interval
-      if (self._currentElement != currentElement)
-        return;
-
-      aCallback();
-    }, true);
-  },
-
-  _getZoomLevelForRect: function _getZoomLevelForRect(aRect) {
-    const margin = 30;
-    let zoomLevel = getBrowser().getBoundingClientRect().width / (aRect.width + margin);
-
-    // Clamp the zoom level relatively to the default zoom level of the page
-    let defaultZoomLevel = Browser.selectedTab.getDefaultZoomLevel();
-    return Util.clamp(zoomLevel, (defaultZoomLevel * kBrowserFormZoomLevelMin),
-                                 (defaultZoomLevel * kBrowserFormZoomLevelMax));
-  },
-
-  _getOffsetForCaret: function _formHelperGetOffsetForCaret(aCaretRect, aRect) {
-    // Determine if we need to move left or right to bring the caret into view
-    let deltaX = 0;
-    if (aCaretRect.right > aRect.right)
-      deltaX = aCaretRect.right - aRect.right;
-    if (aCaretRect.left < aRect.left)
-      deltaX = aCaretRect.left - aRect.left;
-
-    // Determine if we need to move up or down to bring the caret into view
-    let deltaY = 0;
-    if (aCaretRect.bottom > aRect.bottom)
-      deltaY = aCaretRect.bottom - aRect.bottom;
-    if (aCaretRect.top < aRect.top)
-      deltaY = aCaretRect.top - aRect.top;
-
-    return [deltaX, deltaY];
-  },
-
-  _waitForKeyboard: function formHelperWaitForKeyboard(aElement, aHasPrevious, aHasNext) {
+  _waitForKeyboard: function formHelperWaitForKeyboard(aElement) {
     let self = this;
     window.addEventListener("KeyboardChanged", function(aEvent) {
       window.removeEventListener("KeyboardChanged", arguments.callee, false);
-
-      if (AnimatedZoom.isZooming()) {
-        self._waitForZoom(function() {
-          self.show(aElement, aHasPrevious, aHasNext);
-        });
-        return;
-      }
-
-      self.show(aElement, aHasPrevious, aHasNext);
+      self._currentBrowser.messageManager.sendAsyncMessage("FormAssist:Update", {});
     }, false);
   }
 };
 
--- a/browser/metro/profile/metro.js
+++ b/browser/metro/profile/metro.js
@@ -19,26 +19,16 @@ pref("metro.debug.treatmouseastouch", fa
 pref("metro.debug.colorizeInputOverlay", false);
 pref("metro.debug.selection.displayRanges", false);
 pref("metro.debug.selection.dumpRanges", false);
 pref("metro.debug.selection.dumpEvents", false);
 
 // Enable off main thread compositing
 pref("layers.offmainthreadcomposition.enabled", false);
 
-// Form helper options: 0 = disabled, 1 = enabled, 2 = dynamic depending on screen size
-pref("formhelper.mode", 0);
-// Auto zoom to form elements when they take focus 
-pref("formhelper.autozoom", true);
-// Auto zoom to the caret
-pref("formhelper.autozoom.caret", false);
-
-// form autocomplete service
-pref("browser.formfill.enable", true);
-
 // Enable Microsoft TSF support by default for imes.
 pref("intl.enable_tsf_support", true);
 
 pref("general.autoScroll", true);
 pref("general.smoothScroll", true);
 pref("general.smoothScroll.durationToIntervalRatio", 200);
 pref("mousewheel.enable_pixel_scrolling", true);