Merge m-c to inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 18 Apr 2014 22:08:16 -0400
changeset 197840 5f558788549ed778f676b6cd7dcf28cb36e8cf7d
parent 197839 7c5d076dd141770a70e7235e6ac7fe589ca5034e (current diff)
parent 197811 582b2d81ebe148856358b97f5395dd714c2efa5c (diff)
child 197841 8a8c87fcd2d900c15c9de53a47b7e1aac48b5ffe
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone31.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
Merge m-c to inbound.
toolkit/components/places/tests/unit/test_PlacesUtils_nodeIsXXX_invalidArg.js
--- a/accessible/tests/mochitest/autocomplete.js
+++ b/accessible/tests/mochitest/autocomplete.js
@@ -194,16 +194,21 @@ AutoCompleteResult.prototype =
     return null;
   },
 
   getImageAt: function(aIndex)
   {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex)
+  {
+    return this.getValueAt(aIndex);
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: function(iid) {
     if (iid.equals(nsISupports) ||
         iid.equals(nsIAutoCompleteResult))
       return this;
 
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -778,20 +778,16 @@ var CustomEventManager = {
           JSON.stringify({ callerID: detail.chromeEventID,
                            keyword: detail.keyword,
                            manifestURL: detail.manifestURL,
                            selectedApps: detail.peers }));
         break;
       case 'inputmethod-update-layouts':
         KeyboardHelper.handleEvent(detail);
         break;
-      case 'nfc-hardware-state-change':
-        Services.obs.notifyObservers(null, 'nfc-hardware-state-change',
-          JSON.stringify({ nfcHardwareState: detail.nfcHardwareState }));
-        break;
     }
   }
 }
 
 var AlertsHelper = {
   _listeners: {},
   _count: 0,
 
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
@@ -126,11 +126,11 @@
   <!-- Emulator specific things -->
   <project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="09485b73629856b21b2ed6073e327ab0e69a1189"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="8afce6d5d48b71b6e7cb917179fb6147fb747521"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="72e3a520e3c700839f07ba0113fd527b923c3330"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="6a7ada569fd37c09ed4bbee6eb78cea5b467b229"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="baaf899afb158b9530690002f3656e958e3eb047"/>
   <project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
 </manifest>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="52c909ccead537f8f9dbf634f3e6639078a8b0bd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -13,17 +13,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "26f2c60c0ba0e64114467663c33c82360c13f4cf", 
+    "revision": "38d1561fe26c12f371c44a47c498722ce06518c2", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
@@ -122,17 +122,17 @@
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
   <!-- Nexus 4 specific things -->
   <project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="6a7ada569fd37c09ed4bbee6eb78cea5b467b229"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="baaf899afb158b9530690002f3656e958e3eb047"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="b0a528d839cfd9d170d092fe3743b5252b4243a6"/>
   <project name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="380945eaa249a2dbdde0daa4c8adb8ca325edba6"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="6f3b0272cefaffeaed2a7d2bb8f633059f163ddc"/>
   <project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="16da8262c997a5a0d797885788a64a0771b26910"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="689b476ba3eb46c34b81343295fe144a0e81a18e"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="76c94ac5dc3b8e17cc23d9cc3e2662b0d5d28b2e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7e93b6de9633a162b735252e8182974456f741f4"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -117,47 +117,48 @@ tabbrowser {
 }
 
 .tabbrowser-tab:not([pinned]):not([fadein]) {
   max-width: 0.1px;
   min-width: 0.1px;
   visibility: hidden;
 }
 
-.tab-background {
-  /* Explicitly set the visibility to override the value (collapsed)
-   * we inherit from #TabsToolbar[collapsed] upon opening a browser window. */
-  visibility: visible;
-  /* The transition is only delayed for opening tabs. */
-  transition: visibility 0ms 25ms;
-}
-
-.tab-background:not([fadein]):not([pinned]) {
-  visibility: hidden;
-  /* Closing tabs are hidden without a delay. */
-  transition-delay: 0ms;
-}
-
+.tab-background,
 .tab-close-button,
 .tab-label {
   /* Explicitly set the visibility to override the value (collapsed)
    * we inherit from #TabsToolbar[collapsed] upon opening a browser window. */
   visibility: visible;
+}
+
+.tab-background[fadein] {
+  /* This transition is only wanted for opening tabs. */
+  transition: visibility 0ms 25ms;
+}
+
+.tab-background:not([fadein]) {
+  visibility: hidden;
+}
+
+.tab-close-button[fadein],
+.tab-label[fadein] {
+  /* This transition is only wanted for opening tabs. */
   transition: opacity 70ms 230ms,
               visibility 0ms 230ms;
 }
 
-.tab-close-button:not([fadein]):not([pinned]),
-.tab-label:not([fadein]):not([pinned]) {
+.tab-close-button:not([fadein]),
+.tab-label:not([fadein]) {
   visibility: collapse;
   opacity: .6;
 }
 
-.tab-throbber:not([fadein]):not([pinned]),
-.tab-icon-image:not([fadein]):not([pinned]) {
+.tab-throbber:not([fadein]),
+.tab-icon-image:not([fadein]) {
   display: none;
 }
 
 .tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned] {
   position: fixed !important;
   display: block; /* position:fixed already does this (bug 579776), but let's be explicit */
 }
 
--- a/browser/base/content/newtab/page.js
+++ b/browser/base/content/newtab/page.js
@@ -14,19 +14,20 @@ let gPage = {
    */
   init: function Page_init() {
     // Add ourselves to the list of pages to receive notifications.
     gAllPages.register(this);
 
     // Listen for 'unload' to unregister this page.
     addEventListener("unload", this, false);
 
-    // Listen for toggle button clicks.
-    let button = document.getElementById("newtab-toggle");
-    button.addEventListener("click", this, false);
+    // XXX bug 991111 - Not all click events are correctly triggered when
+    // listening from xhtml nodes -- in particular middle clicks on sites, so
+    // listen from the xul window and filter then delegate
+    addEventListener("click", this, false);
 
     // Initialize sponsored panel
     this._sponsoredPanel = document.getElementById("sponsored-panel");
     let link = this._sponsoredPanel.querySelector(".text-link");
     link.addEventListener("click", () => this._sponsoredPanel.hidePopup());
 
     // Check if the new tab feature is enabled.
     let enabled = gAllPages.enabled;
@@ -191,17 +192,32 @@ let gPage = {
   handleEvent: function Page_handleEvent(aEvent) {
     switch (aEvent.type) {
       case "unload":
         if (this._mutationObserver)
           this._mutationObserver.disconnect();
         gAllPages.unregister(this);
         break;
       case "click":
-        gAllPages.enabled = !gAllPages.enabled;
+        let {button, target} = aEvent;
+        if (target.id == "newtab-toggle") {
+          if (button == 0) {
+            gAllPages.enabled = !gAllPages.enabled;
+          }
+          break;
+        }
+
+        // Go up ancestors until we find a Site or not
+        while (target) {
+          if (target.hasOwnProperty("_newtabSite")) {
+            target._newtabSite.onClick(aEvent);
+            break;
+          }
+          target = target.parentNode;
+        }
         break;
       case "dragover":
         if (gDrag.isValid(aEvent) && gDrag.draggedSite)
           aEvent.preventDefault();
         break;
       case "drop":
         if (gDrag.isValid(aEvent) && gDrag.draggedSite) {
           aEvent.preventDefault();
--- a/browser/base/content/newtab/sites.js
+++ b/browser/base/content/newtab/sites.js
@@ -165,20 +165,16 @@ Site.prototype = {
    * Adds event handlers for the site and its buttons.
    */
   _addEventHandlers: function Site_addEventHandlers() {
     // Register drag-and-drop event handlers.
     this._node.addEventListener("dragstart", this, false);
     this._node.addEventListener("dragend", this, false);
     this._node.addEventListener("mouseover", this, false);
 
-    // XXX bug 991111 - Not all click events are correctly triggered when
-    // listening from the xhtml node, so listen from the xul window and filter
-    addEventListener("click", this, false);
-
     // Specially treat the sponsored icon to prevent regular hover effects
     let sponsored = this._querySelector(".newtab-control-sponsored");
     sponsored.addEventListener("mouseover", () => {
       this.cell.node.setAttribute("ignorehover", "true");
     });
     sponsored.addEventListener("mouseout", () => {
       this.cell.node.removeAttribute("ignorehover");
     });
@@ -213,21 +209,29 @@ Site.prototype = {
       Services.telemetry.getHistogramById("NEWTAB_PAGE_DIRECTORY_TYPE_CLICKED")
                         .add(typeIndex);
     }
   },
 
   /**
    * Handles site click events.
    */
-  _onClick: function Site_onClick(aEvent) {
-    let target = aEvent.target;
+  onClick: function Site_onClick(aEvent) {
+    let {button, target} = aEvent;
     if (target.classList.contains("newtab-link") ||
         target.parentElement.classList.contains("newtab-link")) {
-      this._recordSiteClicked(this.cell.index);
+      // Record for primary and middle clicks
+      if (button == 0 || button == 1) {
+        this._recordSiteClicked(this.cell.index);
+      }
+      return;
+    }
+
+    // Only handle primary clicks for the remaining targets
+    if (button != 0) {
       return;
     }
 
     aEvent.preventDefault();
     if (aEvent.target.classList.contains("newtab-control-block"))
       this.block();
     else if (target.classList.contains("newtab-control-sponsored"))
       gPage.showSponsoredPanel(target);
@@ -237,23 +241,16 @@ Site.prototype = {
       this.pin();
   },
 
   /**
    * Handles all site events.
    */
   handleEvent: function Site_handleEvent(aEvent) {
     switch (aEvent.type) {
-      case "click":
-        // Check the bitmask if the click event is for the site's descendants
-        if (this._node.compareDocumentPosition(aEvent.target) &
-            this._node.DOCUMENT_POSITION_CONTAINED_BY) {
-          this._onClick(aEvent);
-        }
-        break;
       case "mouseover":
         this._node.removeEventListener("mouseover", this, false);
         this._speculativeConnect();
         break;
       case "dragstart":
         gDrag.start(this, aEvent);
         break;
       case "dragend":
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -285,17 +285,16 @@
 
       <method name="unpinTab">
         <parameter name="aTab"/>
         <body><![CDATA[
           if (!aTab.pinned)
             return;
 
           this.moveTabTo(aTab, this._numPinnedTabs - 1);
-          aTab.setAttribute("fadein", "true");
           aTab.removeAttribute("pinned");
           aTab.style.MozMarginStart = "";
           this.tabContainer._unlockTabSizing();
           this.tabContainer._positionPinnedTabs();
           this.tabContainer.adjustTabstrip();
 
           // Bug 961867 - [e10s] Implement the logic for app tabs
           if (!gMultiProcessBrowser)
--- a/browser/base/content/test/newtab/browser.ini
+++ b/browser/base/content/test/newtab/browser.ini
@@ -12,16 +12,17 @@ skip-if = e10s # Bug ?????? - about:newt
 [browser_newtab_bug734043.js]
 [browser_newtab_bug735987.js]
 skip-if = os == "mac" # Intermittent failures, bug 898317
 [browser_newtab_bug752841.js]
 [browser_newtab_bug765628.js]
 [browser_newtab_bug876313.js]
 [browser_newtab_bug991111.js]
 [browser_newtab_bug991210.js]
+[browser_newtab_bug998387.js]
 [browser_newtab_disable.js]
 [browser_newtab_drag_drop.js]
 [browser_newtab_drag_drop_ext.js]
 [browser_newtab_drop_preview.js]
 [browser_newtab_focus.js]
 [browser_newtab_perwindow_private_browsing.js]
 [browser_newtab_reset.js]
 [browser_newtab_sponsored_icon_click.js]
--- a/browser/base/content/test/newtab/browser_newtab_bug991111.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug991111.js
@@ -3,17 +3,17 @@
 
 function runTests() {
   yield setLinks("0");
   yield addNewTabPageTab();
 
   // Remember if the click handler was triggered
   let cell = getCell(0);
   let clicked = false;
-  cell.site._onClick = e => {
+  cell.site.onClick = e => {
     clicked = true;
     executeSoon(TestRunner.next);
   };
 
   // Send a middle-click and make sure it happened
   yield EventUtils.synthesizeMouseAtCenter(cell.node, {button: 1}, getContentWindow());
   ok(clicked, "middle click triggered click listener");
 }
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_bug998387.js
@@ -0,0 +1,25 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function runTests() {
+  yield setLinks("0");
+  yield addNewTabPageTab();
+
+  // Remember if the click handler was triggered
+  let {site} = getCell(0);
+  let origOnClick = site.onClick;
+  let clicked = false;
+  site.onClick = e => {
+    origOnClick.call(site, e);
+    clicked = true;
+    executeSoon(TestRunner.next);
+  };
+
+  // Send a middle-click and make sure it happened
+  let block = getContentDocument().querySelector(".newtab-control-block");
+  yield EventUtils.synthesizeMouseAtCenter(block, {button: 1}, getContentWindow());
+  ok(clicked, "middle click triggered click listener");
+
+  // Make sure the cell didn't actually get blocked
+  checkGrid("0");
+}
--- a/browser/devtools/debugger/test/browser.ini
+++ b/browser/devtools/debugger/test/browser.ini
@@ -144,16 +144,17 @@ support-files =
 [browser_dbg_global-method-override.js]
 [browser_dbg_globalactor.js]
 [browser_dbg_host-layout.js]
 [browser_dbg_iframes.js]
 [browser_dbg_instruments-pane-collapse.js]
 [browser_dbg_listaddons.js]
 [browser_dbg_listtabs-01.js]
 [browser_dbg_listtabs-02.js]
+[browser_dbg_listtabs-03.js]
 [browser_dbg_location-changes-01-simple.js]
 [browser_dbg_location-changes-02-blank.js]
 [browser_dbg_location-changes-03-new.js]
 [browser_dbg_location-changes-04-breakpoint.js]
 [browser_dbg_multiple-windows.js]
 [browser_dbg_navigation.js]
 [browser_dbg_no-page-sources.js]
 [browser_dbg_on-pause-highlight.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_listtabs-03.js
@@ -0,0 +1,80 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure the listTabs request works as specified.
+ */
+
+const TAB1_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
+
+let gTab1, gTab1Actor, gTab2, gTab2Actor, gClient;
+
+function listTabs() {
+  let deferred = promise.defer();
+
+  gClient.listTabs(aResponse => {
+    deferred.resolve(aResponse.tabs);
+  });
+
+  return deferred.promise;
+}
+
+function request(params) {
+  let deferred = promise.defer();
+  gClient.request(params, deferred.resolve);
+  return deferred.promise;
+}
+
+function test() {
+  if (!DebuggerServer.initialized) {
+    DebuggerServer.init(() => true);
+    DebuggerServer.addBrowserActors();
+  }
+
+  let transport = DebuggerServer.connectPipe();
+  gClient = new DebuggerClient(transport);
+  gClient.connect(Task.async(function*(aType, aTraits) {
+    is(aType, "browser",
+      "Root actor should identify itself as a browser.");
+    let tab = yield addTab(TAB1_URL);
+
+    let tabs = yield listTabs();
+    is(tabs.length, 2, "Should be two tabs");
+    let tabGrip = tabs.filter(a => a.url ==TAB1_URL).pop();
+    ok(tabGrip, "Should have an actor for the tab");
+
+    let response = yield request({ to: tabGrip.actor, type: "attach" });
+    is(response.type, "tabAttached", "Should have attached");
+
+    tabs = yield listTabs();
+
+    response = yield request({ to: tabGrip.actor, type: "detach" });
+    is(response.type, "detached", "Should have detached");
+
+    let newGrip = tabs.filter(a => a.url ==TAB1_URL).pop();
+    is(newGrip.actor, tabGrip.actor, "Should have the same actor for the same tab");
+
+    response = yield request({ to: tabGrip.actor, type: "attach" });
+    is(response.type, "tabAttached", "Should have attached");
+    response = yield request({ to: tabGrip.actor, type: "detach" });
+    is(response.type, "detached", "Should have detached");
+
+    yield removeTab(tab);
+    yield closeConnection();
+    finish();
+  }));
+}
+
+function closeConnection() {
+  let deferred = promise.defer();
+  gClient.close(deferred.resolve);
+  return deferred.promise;
+}
+
+registerCleanupFunction(function() {
+  gTab1 = null;
+  gTab1Actor = null;
+  gTab2 = null;
+  gTab2Actor = null;
+  gClient = null;
+});
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -48,16 +48,17 @@
 #include "nsCrossSiteListenerProxy.h"
 #include "nsSandboxFlags.h"
 #include "nsContentTypeParser.h"
 #include "nsINetworkSeer.h"
 #include "mozilla/dom/EncodingUtils.h"
 
 #include "mozilla/CORSMode.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/unused.h"
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gCspPRLog;
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -809,21 +810,20 @@ NotifyOffThreadScriptLoadCompletedRunnab
   }
 
   return rv;
 }
 
 static void
 OffThreadScriptLoaderCallback(void *aToken, void *aCallbackData)
 {
-  NotifyOffThreadScriptLoadCompletedRunnable* aRunnable =
-    static_cast<NotifyOffThreadScriptLoadCompletedRunnable*>(aCallbackData);
+  nsRefPtr<NotifyOffThreadScriptLoadCompletedRunnable> aRunnable =
+    dont_AddRef(static_cast<NotifyOffThreadScriptLoadCompletedRunnable*>(aCallbackData));
   aRunnable->SetToken(aToken);
   NS_DispatchToMainThread(aRunnable);
-  NS_RELEASE(aRunnable);
 }
 
 nsresult
 nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest)
 {
   if (!aRequest->mElement->GetScriptAsync() || aRequest->mIsInline) {
     return NS_ERROR_FAILURE;
   }
@@ -843,31 +843,29 @@ nsScriptLoader::AttemptAsyncScriptParse(
 
   JS::CompileOptions options(cx);
   FillCompileOptionsForRequest(aRequest, global, &options);
 
   if (!JS::CanCompileOffThread(cx, options, aRequest->mScriptText.Length())) {
     return NS_ERROR_FAILURE;
   }
 
-  NotifyOffThreadScriptLoadCompletedRunnable* runnable =
+  nsRefPtr<NotifyOffThreadScriptLoadCompletedRunnable> runnable =
     new NotifyOffThreadScriptLoadCompletedRunnable(aRequest, this);
 
-  // This reference will be consumed by OffThreadScriptLoaderCallback.
-  NS_ADDREF(runnable);
-
   if (!JS::CompileOffThread(cx, options,
                             aRequest->mScriptText.get(), aRequest->mScriptText.Length(),
                             OffThreadScriptLoaderCallback,
                             static_cast<void*>(runnable))) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   mDocument->BlockOnload();
 
+  unused << runnable.forget();
   return NS_OK;
 }
 
 nsresult
 nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest, void **aOffThreadToken)
 {
   NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
                "Processing requests when running scripts is unsafe.");
--- a/dom/apps/src/InterAppCommService.js
+++ b/dom/apps/src/InterAppCommService.js
@@ -71,31 +71,28 @@ function InterAppCommService() {
   //
   // For example:
   //
   // {
   //   "foo": {
   //     "app://subApp1.gaiamobile.org/manifest.webapp": {
   //       pageURL: "app://subApp1.gaiamobile.org/handler.html",
   //       description: "blah blah",
-  //       appStatus: Ci.nsIPrincipal.APP_STATUS_CERTIFIED,
   //       rules: { ... }
   //     },
   //     "app://subApp2.gaiamobile.org/manifest.webapp": {
   //       pageURL: "app://subApp2.gaiamobile.org/handler.html",
   //       description: "blah blah",
-  //       appStatus: Ci.nsIPrincipal.APP_STATUS_PRIVILEGED,
   //       rules: { ... }
   //     }
   //   },
   //   "bar": {
   //     "app://subApp3.gaiamobile.org/manifest.webapp": {
   //       pageURL: "app://subApp3.gaiamobile.org/handler.html",
   //       description: "blah blah",
-  //       appStatus: Ci.nsIPrincipal.APP_STATUS_INSTALLED,
   //       rules: { ... }
   //     }
   //   }
   // }
   //
   // TODO Bug 908999 - Update registered connections when app gets uninstalled.
   this._registeredConnections = {};
 
@@ -209,38 +206,37 @@ function InterAppCommService() {
   //     }
   //   }
   // }
   this._messagePortPairs = {};
 }
 
 InterAppCommService.prototype = {
   registerConnection: function(aKeyword, aHandlerPageURI, aManifestURI,
-                               aDescription, aAppStatus, aRules) {
+                               aDescription, aRules) {
     let manifestURL = aManifestURI.spec;
     let pageURL = aHandlerPageURI.spec;
 
     if (DEBUG) {
       debug("registerConnection: aKeyword: " + aKeyword +
             " manifestURL: " + manifestURL + " pageURL: " + pageURL +
-            " aDescription: " + aDescription + " aAppStatus: " + aAppStatus +
+            " aDescription: " + aDescription +
             " aRules.minimumAccessLevel: " + aRules.minimumAccessLevel +
             " aRules.manifestURLs: " + aRules.manifestURLs +
             " aRules.installOrigins: " + aRules.installOrigins);
     }
 
     let subAppManifestURLs = this._registeredConnections[aKeyword];
     if (!subAppManifestURLs) {
       subAppManifestURLs = this._registeredConnections[aKeyword] = {};
     }
 
     subAppManifestURLs[manifestURL] = {
       pageURL: pageURL,
       description: aDescription,
-      appStatus: aAppStatus,
       rules: aRules,
       manifestURL: manifestURL
     };
   },
 
   _matchMinimumAccessLevel: function(aRules, aAppStatus) {
     if (!aRules || !aRules.minimumAccessLevel) {
       if (DEBUG) {
@@ -295,77 +291,76 @@ InterAppCommService.prototype = {
     if (DEBUG) {
       debug("rules.manifestURLs is not matched!" +
             " manifestURLs: " + manifestURLs +
             " aManifestURL : " + aManifestURL);
     }
     return false;
   },
 
-  _matchInstallOrigins: function(aRules, aManifestURL) {
+  _matchInstallOrigins: function(aRules, aInstallOrigin) {
     if (!aRules || !Array.isArray(aRules.installOrigins)) {
       if (DEBUG) {
         debug("rules.installOrigins is not available. No need to match.");
       }
       return true;
     }
 
-    let installOrigin =
-      appsService.getAppByManifestURL(aManifestURL).installOrigin;
-
     let installOrigins = aRules.installOrigins;
-    if (installOrigins.indexOf(installOrigin) != -1) {
+    if (installOrigins.indexOf(aInstallOrigin) != -1) {
       return true;
     }
 
     if (DEBUG) {
       debug("rules.installOrigins is not matched!" +
-            " aManifestURL: " + aManifestURL +
             " installOrigins: " + installOrigins +
-            " installOrigin : " + installOrigin);
+            " installOrigin : " + aInstallOrigin);
     }
     return false;
   },
 
-  _matchRules: function(aPubAppManifestURL, aPubAppStatus, aPubRules,
-                        aSubAppManifestURL, aSubAppStatus, aSubRules) {
+  _matchRules: function(aPubAppManifestURL, aPubRules,
+                        aSubAppManifestURL, aSubRules) {
+    let pubApp = appsService.getAppByManifestURL(aPubAppManifestURL);
+    let subApp = appsService.getAppByManifestURL(aSubAppManifestURL);
+
     // TODO Bug 907068 In the initiative step, we only expose this API to
     // certified apps to meet the time line. Eventually, we need to make
     // it available for the non-certified apps as well. For now, only the
     // certified apps can match the rules.
-    if (aPubAppStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED ||
-        aSubAppStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED) {
+    if (pubApp.appStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED ||
+        subApp.appStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED) {
       if (DEBUG) {
         debug("Only certified apps are allowed to do connections.");
       }
       return false;
     }
 
     if (!aPubRules && !aSubRules) {
       if (DEBUG) {
         debug("No rules for publisher and subscriber. No need to match.");
       }
       return true;
     }
 
     // Check minimumAccessLevel.
-    if (!this._matchMinimumAccessLevel(aPubRules, aSubAppStatus) ||
-        !this._matchMinimumAccessLevel(aSubRules, aPubAppStatus)) {
+    if (!this._matchMinimumAccessLevel(aPubRules, subApp.appStatus) ||
+        !this._matchMinimumAccessLevel(aSubRules, pubApp.appStatus)) {
       return false;
     }
 
     // Check manifestURLs.
     if (!this._matchManifestURLs(aPubRules, aSubAppManifestURL) ||
         !this._matchManifestURLs(aSubRules, aPubAppManifestURL)) {
       return false;
     }
 
     // Check installOrigins.
-    if (!this._matchInstallOrigins(aPubRules, aSubAppManifestURL) ||
-        !this._matchInstallOrigins(aSubRules, aPubAppManifestURL)) {
+    if (!this._matchInstallOrigins(aPubRules, subApp.installOrigin) ||
+        !this._matchInstallOrigins(aSubRules, pubApp.installOrigin)) {
       return false;
     }
 
     // Check developers.
     // TODO Do we really want to check this? This one seems naive.
 
     if (DEBUG) debug("All rules are matched.");
     return true;
@@ -447,17 +442,16 @@ InterAppCommService.prototype = {
   },
 
   _connect: function(aMessage, aTarget) {
     let keyword = aMessage.keyword;
     let pubRules = aMessage.rules;
     let pubAppManifestURL = aMessage.manifestURL;
     let outerWindowID = aMessage.outerWindowID;
     let requestID = aMessage.requestID;
-    let pubAppStatus = aMessage.appStatus;
 
     let subAppManifestURLs = this._registeredConnections[keyword];
     if (!subAppManifestURLs) {
       if (DEBUG) {
         debug("No apps are subscribed for this connection. Returning.");
       }
       this._dispatchMessagePorts(keyword, pubAppManifestURL, [],
                                  aTarget, outerWindowID, requestID);
@@ -481,22 +475,21 @@ InterAppCommService.prototype = {
         if (DEBUG) {
           debug("Don't need to select again. Skipping: " + subAppManifestURL);
         }
         continue;
       }
 
       // Only rule-matched publishers/subscribers are allowed to connect.
       let subscribedInfo = subAppManifestURLs[subAppManifestURL];
-      let subAppStatus = subscribedInfo.appStatus;
       let subRules = subscribedInfo.rules;
 
       let matched =
-        this._matchRules(pubAppManifestURL, pubAppStatus, pubRules,
-                         subAppManifestURL, subAppStatus, subRules);
+        this._matchRules(pubAppManifestURL, pubRules,
+                         subAppManifestURL, subRules);
       if (!matched) {
         if (DEBUG) {
           debug("Rules are not matched. Skipping: " + subAppManifestURL);
         }
         continue;
       }
 
       appsToSelect.push({
new file mode 100644
--- /dev/null
+++ b/dom/apps/src/ScriptPreloader.jsm
@@ -0,0 +1,76 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const Cu = Components.utils;
+const Ci = Components.interfaces;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Promise.jsm");
+
+this.EXPORTED_SYMBOLS = ["ScriptPreloader"];
+
+function debug(aMsg) {
+  //dump("--*-- ScriptPreloader: " + aMsg + "\n");
+}
+
+this.ScriptPreloader = {
+#ifdef MOZ_B2G
+  _enabled: true,
+#else
+  _enabled: false,
+#endif
+
+  preload: function(aApp, aManifest) {
+    debug("Preloading " + aApp.origin);
+    let deferred = Promise.defer();
+
+    if (!this._enabled) {
+      deferred.resolve();
+      return deferred.promise;
+    }
+
+    if (aManifest.precompile &&
+        Array.isArray(aManifest.precompile) &&
+        aManifest.precompile.length > 0) {
+      let origin = Services.io.newURI(aApp.origin, null, null);
+      let toLoad = aManifest.precompile.length;
+      let principal =
+        Services.scriptSecurityManager
+                .getAppCodebasePrincipal(origin, aApp.localId, false);
+
+      aManifest.precompile.forEach((aPath) => {
+        let uri = Services.io.newURI(aPath, null, origin);
+        debug("Script to compile: " + uri.spec);
+        try {
+          Services.scriptloader.precompileScript(uri, principal,
+            (aSubject, aTopic, aData) => {
+              let uri = aSubject.QueryInterface(Ci.nsIURI);
+              debug("Done compiling " + uri.spec);
+
+              toLoad--;
+              if (toLoad == 0) {
+                deferred.resolve();
+              }
+            });
+        } catch (e) {
+          // Resolve the promise if precompileScript throws.
+          deferred.resolve();
+        }
+      });
+    } else {
+      // The precompile field is not an array, let the developer know.
+      // We don't want to have to enable debug for that to show up.
+      if (aManifest.precompile) {
+        Cu.reportError("ASM.JS compilation failed: the 'precompile' manifest " +
+                       "property should be an array of script uris.\n");
+      }
+      deferred.resolve();
+    }
+
+    return deferred.promise;
+  }
+}
--- a/dom/apps/src/Webapps.js
+++ b/dom/apps/src/Webapps.js
@@ -481,17 +481,16 @@ WebappsApplication.prototype = {
 
   connect: function(aKeyword, aRules) {
     return this.createPromise(function (aResolve, aReject) {
       cpmm.sendAsyncMessage("Webapps:Connect",
                             { keyword: aKeyword,
                               rules: aRules,
                               manifestURL: this.manifestURL,
                               outerWindowID: this._id,
-                              appStatus: this._appStatus,
                               requestID: this.getPromiseResolverId({
                                 resolve: aResolve,
                                 reject: aReject
                               })});
     }.bind(this));
   },
 
   getConnections: function() {
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -56,16 +56,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   "resource://gre/modules/SystemMessagePermissionsChecker.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "WebappOSUtils",
   "resource://gre/modules/WebappOSUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
   "resource://gre/modules/NetUtil.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "ScriptPreloader",
+                                  "resource://gre/modules/ScriptPreloader.jsm");
+
 #ifdef MOZ_WIDGET_GONK
 XPCOMUtils.defineLazyGetter(this, "libcutils", function() {
   Cu.import("resource://gre/modules/systemlibs.js");
   return libcutils;
 });
 #endif
 
 function debug(aMsg) {
@@ -729,17 +732,16 @@ this.DOMApplicationRegistry = {
         msgmgr.registerPage("connection", handlerPageURI, manifestURI);
       }
 
       interAppCommService.
         registerConnection(keyword,
                            handlerPageURI,
                            manifestURI,
                            connection.description,
-                           AppsUtils.getAppManifestStatus(manifest),
                            connection.rules);
     }
   },
 
   _registerSystemMessages: function(aManifest, aApp) {
     this._registerSystemMessagesForEntryPoint(aManifest, aApp, null);
 
     if (!aManifest.entry_points) {
@@ -1484,17 +1486,19 @@ this.DOMApplicationRegistry = {
           for (let prop in app.staged) {
             app[prop] = app.staged[prop];
           }
           delete app.staged;
         }
 
         delete app.retryingDownload;
 
-        this._saveApps().then(() => {
+        // Update the asm.js scripts we need to compile.
+        ScriptPreloader.preload(app, aData)
+          .then(() => this._saveApps()).then(() => {
           // Update the handlers and permissions for this app.
           this.updateAppHandlers(aOldManifest, aData, app);
 
           AppsUtils.loadJSONAsync(staged.path).then((aUpdateManifest) => {
             let appObject = AppsUtils.cloneAppObject(app);
             appObject.updateManifest = aUpdateManifest;
             this.notifyUpdateHandlers(appObject, aData, appFile.path);
           });
@@ -2590,23 +2594,29 @@ onInstallSuccessAck: function onInstallS
       this.updateDataStore(this.webapps[aId].localId, aNewApp.origin,
                            aNewApp.manifestURL, aManifest, aNewApp.appStatus);
 
       this.broadcastMessage("Webapps:UpdateState", {
         app: app,
         manifest: aManifest,
         manifestURL: aNewApp.manifestURL
       });
-      this.broadcastMessage("Webapps:FireEvent", {
-        eventType: ["downloadsuccess", "downloadapplied"],
-        manifestURL: aNewApp.manifestURL
-      });
-      if (aInstallSuccessCallback) {
-        aInstallSuccessCallback(aManifest, zipFile.path);
-      }
+
+      // Check if we have asm.js code to preload for this application.
+      ScriptPreloader.preload(aNewApp, aManifest)
+                     .then(() => {
+          this.broadcastMessage("Webapps:FireEvent", {
+            eventType: ["downloadsuccess", "downloadapplied"],
+            manifestURL: aNewApp.manifestURL
+          });
+          if (aInstallSuccessCallback) {
+            aInstallSuccessCallback(aManifest, zipFile.path);
+          }
+        }
+      );
     });
   },
 
   _nextLocalId: function() {
     let id = Services.prefs.getIntPref("dom.mozApps.maxLocalId") + 1;
 
     while (this.getManifestURLByLocalId(id)) {
       id++;
--- a/dom/apps/src/moz.build
+++ b/dom/apps/src/moz.build
@@ -31,16 +31,17 @@ EXTRA_JS_MODULES += [
     'PermissionsInstaller.jsm',
     'PermissionsTable.jsm',
     'StoreTrustAnchor.jsm',
 ]
 
 EXTRA_PP_JS_MODULES += [
     'AppsUtils.jsm',
     'OperatorApps.jsm',
+    'ScriptPreloader.jsm',
     'Webapps.jsm',
 ]
 
 FAIL_ON_WARNINGS = True
 
 FINAL_LIBRARY = 'gklayout'
 
 LOCAL_INCLUDES += [
--- a/dom/interfaces/apps/nsIInterAppCommService.idl
+++ b/dom/interfaces/apps/nsIInterAppCommService.idl
@@ -11,30 +11,27 @@ interface nsIURI;
  *
  * This interface contains helpers for Inter-App Communication API [1] related
  * purposes. A singleton service of this interface will be instantiated during
  * the system boot-up, which plays the role of the central service receiving
  * messages from and interacting with the content processes.
  *
  * [1] https://wiki.mozilla.org/WebAPI/Inter_App_Communication_Alt_proposal
  */
-[scriptable, uuid(7fdd8b68-0b0a-11e3-9b4c-afbc236da250)]
+[scriptable, uuid(b3d711a4-c6a4-11e3-8fd3-738e7fbcb6d6)]
 interface nsIInterAppCommService : nsISupports
 {
   /*
    * Registration of a page that wants to be connected to other apps through
    * the Inter-App Communication API.
    *
    * @param keyword        The connection's keyword.
    * @param handlerPageURI The URI of the handler's page.
    * @param manifestURI    The webapp's manifest URI.
    * @param description    The connection's description.
-   * @param appStatus      The app status can be Ci.nsIPrincipal.APP_STATUS_[
-   *                       NOT_INSTALLED, INSTALLED, PRIVILEGED, CERTIFIED].
    * @param rules          The connection's rules.
    */
   void registerConnection(in DOMString      keyword,
                           in nsIURI         handlerPageURI,
                           in nsIURI         manifestURI,
                           in DOMString      description,
-                          in unsigned short appStatus,
                           in jsval          rules);
 };
--- a/dom/system/gonk/Nfc.js
+++ b/dom/system/gonk/Nfc.js
@@ -411,17 +411,16 @@ XPCOMUtils.defineLazyGetter(this, "gMess
 
 function Nfc() {
   debug("Starting Worker");
   this.worker = new ChromeWorker("resource://gre/modules/nfc_worker.js");
   this.worker.onerror = this.onerror.bind(this);
   this.worker.onmessage = this.onmessage.bind(this);
 
   Services.obs.addObserver(this, NFC.TOPIC_MOZSETTINGS_CHANGED, false);
-  Services.obs.addObserver(this, NFC.TOPIC_HARDWARE_STATE, false);
 
   gMessageManager.init(this);
   let lock = gSettingsService.createLock();
   lock.get(NFC.SETTING_NFC_ENABLED, this);
   // Maps sessionId (that are generated from nfcd) with a unique guid : 'SessionToken'
   this.sessionTokenMap = {};
   this.targetsByRequestId = {};
 
@@ -652,36 +651,19 @@ Nfc.prototype = {
     switch (topic) {
       case NFC.TOPIC_MOZSETTINGS_CHANGED:
         let setting = JSON.parse(data);
         if (setting) {
           let setting = JSON.parse(data);
           this.handle(setting.key, setting.value);
         }
         break;
-      case NFC.TOPIC_HARDWARE_STATE:
-        let state = JSON.parse(data);
-        if (state) {
-          let level = this.hardwareStateToPowerlevel(state.nfcHardwareState);
-          this.setConfig({ powerLevel: level });
-        }
-        break;
     }
   },
 
   setConfig: function setConfig(prop) {
     this.sendToWorker("config", prop);
-  },
-
-  hardwareStateToPowerlevel: function hardwareStateToPowerlevel(state) {
-    switch (state) {
-      case 0:   return NFC.NFC_POWER_LEVEL_DISABLED;
-      case 1:   return NFC.NFC_POWER_LEVEL_ENABLED;
-      case 2:   return NFC.NFC_POWER_LEVEL_ENABLED;
-      case 3:   return NFC.NFC_POWER_LEVEL_LOW;
-      default:  return NFC.NFC_POWER_LEVEL_UNKNOWN;
-    }
   }
 };
 
 if (NFC_ENABLED) {
   this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Nfc]);
 }
--- a/dom/system/gonk/nfc_consts.js
+++ b/dom/system/gonk/nfc_consts.js
@@ -40,34 +40,38 @@ this.NFC_RESPONSE_CONFIG = 1001;
 this.NFC_RESPONSE_READ_NDEF_DETAILS = 1002;
 this.NFC_RESPONSE_READ_NDEF = 1003;
 
 this.NFC_NOTIFICATION_INITIALIZED = 2000;
 this.NFC_NOTIFICATION_TECH_DISCOVERED = 2001;
 this.NFC_NOTIFICATION_TECH_LOST = 2002;
 
 this.NFC_TECHS = {
-  0:'NDEF',
-  1:'NDEF_WRITEABLE',
-  2:'NDEF_FORMATABLE',
-  3:'P2P'
+  0:"NDEF",
+  1:"NDEF_WRITEABLE",
+  2:"NDEF_FORMATABLE",
+  3:"P2P",
+  4:"NFC_A",
+  5:"NFC_B",
+  6:"NFC_F",
+  7:"NFC_V",
+  8:"NFC_ISO_DEP"
 };
 
 // TODO: Bug 933595. Fill-in all error codes for Gonk/nfcd protocol
 this.GECKO_NFC_ERROR_SUCCESS             = 0;
 this.GECKO_NFC_ERROR_GENERIC_FAILURE     = 1;
 
 // NFC powerlevels must match config PDUs.
 this.NFC_POWER_LEVEL_UNKNOWN        = -1;
 this.NFC_POWER_LEVEL_DISABLED       = 0;
 this.NFC_POWER_LEVEL_LOW            = 1;
 this.NFC_POWER_LEVEL_ENABLED        = 2;
 
 this.TOPIC_MOZSETTINGS_CHANGED      = "mozsettings-changed";
 this.TOPIC_XPCOM_SHUTDOWN           = "xpcom-shutdown";
-this.TOPIC_HARDWARE_STATE           = "nfc-hardware-state-change";
 this.SETTING_NFC_ENABLED            = "nfc.enabled";
 
 this.NFC_PEER_EVENT_READY = 0x01;
 this.NFC_PEER_EVENT_LOST  = 0x02;
 
 // Allow this file to be imported via Components.utils.import().
 this.EXPORTED_SYMBOLS = Object.keys(this);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4341,16 +4341,18 @@ JS::ReadOnlyCompileOptions::copyPODOptio
     forEval = rhs.forEval;
     noScriptRval = rhs.noScriptRval;
     selfHostingMode = rhs.selfHostingMode;
     canLazilyParse = rhs.canLazilyParse;
     strictOption = rhs.strictOption;
     extraWarningsOption = rhs.extraWarningsOption;
     werrorOption = rhs.werrorOption;
     asmJSOption = rhs.asmJSOption;
+    forceAsync = rhs.forceAsync;
+    installedFile = rhs.installedFile;
     sourcePolicy = rhs.sourcePolicy;
     introductionType = rhs.introductionType;
     introductionLineno = rhs.introductionLineno;
     introductionOffset = rhs.introductionOffset;
     hasIntroductionInfo = rhs.hasIntroductionInfo;
 }
 
 JSPrincipals *
--- a/js/xpconnect/idl/mozIJSSubScriptLoader.idl
+++ b/js/xpconnect/idl/mozIJSSubScriptLoader.idl
@@ -1,17 +1,21 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * 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/. */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(b21f1579-d994-4e99-a85d-a685140f3ec1)]
+interface nsIURI;
+interface nsIPrincipal;
+interface nsIObserver;
+
+[scriptable, uuid(19533e7b-f321-4ef1-bc59-6e812dc2a733)]
 interface mozIJSSubScriptLoader : nsISupports
 {
     /**
      * This method should only be called from JS!
      * In JS, the signature looks like:
      * rv loadSubScript (url [, obj] [, charset]);
      * @param url the url of the sub-script, it MUST be either a file:,
      *            resource:, or chrome: url, and MUST be local.
@@ -34,9 +38,27 @@ interface mozIJSSubScriptLoader : nsISup
      * @param optionsObject an object with parameters. Valid parameters are:
      *                      - charset: specifying the character encoding of the file (default: ASCII)
      *                      - target:  an object to evaluate onto (default: global object of the caller)
      *                      - ignoreCache: if set to true, will bypass the cache for reading the file.
      * @retval rv the value returned by the sub-script
      */
     [implicit_jscontext]
     jsval loadSubScriptWithOptions(in AString url, in jsval options);
+
+    /*
+     * Compiles a JS script off the main thread and calls back the
+     * observer once it's done.
+     * The script will be cached in temporary or persistent storage depending
+     * on the principal used.
+     * We fire the notification callback in all cases - there is no fatal
+     * error there.
+     * @param uri       the uri of the script to load.
+     * @param principal the principal from which we get the app id if any.
+     * @param observer  this observer will be called once the script has
+     *                  been precompiled. The notification topic will be
+     *                  'script-precompiled' and the subject the uri of the
+     *                  script as a nsIURI.
+     */
+    void precompileScript(in nsIURI uri,
+                          in nsIPrincipal principal,
+                          in nsIObserver observer);
 };
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -13,30 +13,34 @@
 #include "nsIIOService.h"
 #include "nsIChannel.h"
 #include "nsIInputStream.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsIFileURL.h"
 #include "nsScriptLoader.h"
 #include "nsIScriptSecurityManager.h"
+#include "nsThreadUtils.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "js/OldDebugAPI.h"
 #include "nsJSPrincipals.h"
 #include "xpcpublic.h" // For xpc::SystemErrorReporter
 #include "xpcprivate.h" // For xpc::OptionsBase
+#include "jswrapper.h"
 
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
+#include "mozilla/unused.h"
 
 using namespace mozilla::scache;
 using namespace JS;
 using namespace xpc;
+using namespace mozilla;
 
 class MOZ_STACK_CLASS LoadSubScriptOptions : public OptionsBase {
 public:
     LoadSubScriptOptions(JSContext *cx = xpc_GetSafeJSContext(),
                          JSObject *options = nullptr)
         : OptionsBase(cx, options)
         , target(cx)
         , charset(NullString())
@@ -360,8 +364,216 @@ mozJSSubScriptLoader::DoLoadSubScriptWit
     }
 
     if (cache && ok && writeScript) {
         WriteCachedScript(cache, cachePath, cx, mSystemPrincipal, script);
     }
 
     return NS_OK;
 }
+
+/**
+  * Let us compile scripts from a URI off the main thread.
+  */
+
+class ScriptPrecompiler : public nsIStreamLoaderObserver
+{
+public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSISTREAMLOADEROBSERVER
+
+    ScriptPrecompiler(nsIObserver* aObserver,
+                      nsIPrincipal* aPrincipal,
+                      nsIChannel* aChannel)
+        : mObserver(aObserver)
+        , mPrincipal(aPrincipal)
+        , mChannel(aChannel)
+    {}
+
+    virtual ~ScriptPrecompiler()
+    {}
+
+    static void OffThreadCallback(void *aToken, void *aData);
+
+    /* Sends the "done" notification back. Main thread only. */
+    void SendObserverNotification();
+
+private:
+    nsRefPtr<nsIObserver> mObserver;
+    nsRefPtr<nsIPrincipal> mPrincipal;
+    nsRefPtr<nsIChannel> mChannel;
+    nsString mScript;
+};
+
+NS_IMPL_ISUPPORTS1(ScriptPrecompiler, nsIStreamLoaderObserver);
+
+class NotifyPrecompilationCompleteRunnable : public nsRunnable
+{
+public:
+    NS_DECL_NSIRUNNABLE
+
+    NotifyPrecompilationCompleteRunnable(ScriptPrecompiler* aPrecompiler)
+        : mPrecompiler(aPrecompiler)
+        , mToken(nullptr)
+    {}
+
+    void SetToken(void* aToken) {
+        MOZ_ASSERT(aToken && !mToken);
+        mToken = aToken;
+    }
+
+protected:
+    nsRefPtr<ScriptPrecompiler> mPrecompiler;
+    void* mToken;
+};
+
+/* RAII helper class to send observer notifications */
+class AutoSendObserverNotification {
+public:
+    AutoSendObserverNotification(ScriptPrecompiler* aPrecompiler)
+        : mPrecompiler(aPrecompiler)
+    {}
+
+    ~AutoSendObserverNotification() {
+        if (mPrecompiler) {
+            mPrecompiler->SendObserverNotification();
+        }
+    }
+
+    void Disarm() {
+        mPrecompiler = nullptr;
+    }
+
+private:
+    ScriptPrecompiler* mPrecompiler;
+};
+
+NS_IMETHODIMP
+NotifyPrecompilationCompleteRunnable::Run(void)
+{
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(mPrecompiler);
+
+    AutoSendObserverNotification notifier(mPrecompiler);
+
+    if (mToken) {
+        JSRuntime *rt = XPCJSRuntime::Get()->Runtime();
+        NS_ENSURE_TRUE(rt, NS_ERROR_FAILURE);
+        JS::FinishOffThreadScript(nullptr, rt, mToken);
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+ScriptPrecompiler::OnStreamComplete(nsIStreamLoader* aLoader,
+                                    nsISupports* aContext,
+                                    nsresult aStatus,
+                                    uint32_t aLength,
+                                    const uint8_t* aString)
+{
+    AutoSendObserverNotification notifier(this);
+
+    // Just notify that we are done with this load.
+    NS_ENSURE_SUCCESS(aStatus, NS_OK);
+
+    // Convert data to jschar* and prepare to call CompileOffThread.
+    nsAutoString hintCharset;
+    nsresult rv =
+        nsScriptLoader::ConvertToUTF16(mChannel, aString, aLength,
+                                       hintCharset, nullptr, mScript);
+
+    NS_ENSURE_SUCCESS(rv, NS_OK);
+
+    // Our goal is to cache persistently the compiled script and to avoid quota
+    // checks. Since the caching mechanism decide the persistence type based on
+    // the principal, we create a new global with the app's principal.
+    // We then enter its compartment to compile with its principal.
+    AutoSafeJSContext cx;
+    RootedValue v(cx);
+    SandboxOptions sandboxOptions;
+    sandboxOptions.sandboxName.AssignASCII("asm.js precompilation");
+    sandboxOptions.invisibleToDebugger = true;
+    rv = CreateSandboxObject(cx, &v, mPrincipal, sandboxOptions);
+    NS_ENSURE_SUCCESS(rv, NS_OK);
+
+    JSAutoCompartment ac(cx, js::UncheckedUnwrap(&v.toObject()));
+
+    JS::CompileOptions options(cx, JSVERSION_DEFAULT);
+    options.setSourcePolicy(CompileOptions::NO_SOURCE);
+    options.forceAsync = true;
+    options.compileAndGo = true;
+    options.installedFile = true;
+
+    nsCOMPtr<nsIURI> uri;
+    mChannel->GetURI(getter_AddRefs(uri));
+    nsAutoCString spec;
+    uri->GetSpec(spec);
+    options.setFile(spec.get());
+
+    if (!JS::CanCompileOffThread(cx, options, mScript.Length())) {
+        NS_WARNING("Can't compile script off thread!");
+        return NS_OK;
+    }
+
+    nsRefPtr<NotifyPrecompilationCompleteRunnable> runnable =
+        new NotifyPrecompilationCompleteRunnable(this);
+
+    if (!JS::CompileOffThread(cx, options,
+                              mScript.get(), mScript.Length(),
+                              OffThreadCallback,
+                              static_cast<void*>(runnable))) {
+        NS_WARNING("Failed to compile script off thread!");
+        return NS_OK;
+    }
+
+    unused << runnable.forget();
+    notifier.Disarm();
+
+    return NS_OK;
+}
+
+/* static */
+void
+ScriptPrecompiler::OffThreadCallback(void* aToken, void* aData)
+{
+    nsRefPtr<NotifyPrecompilationCompleteRunnable> runnable =
+        dont_AddRef(static_cast<NotifyPrecompilationCompleteRunnable*>(aData));
+    runnable->SetToken(aToken);
+
+    NS_DispatchToMainThread(runnable);
+}
+
+void
+ScriptPrecompiler::SendObserverNotification()
+{
+    MOZ_ASSERT(mChannel && mObserver);
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsCOMPtr<nsIURI> uri;
+    mChannel->GetURI(getter_AddRefs(uri));
+    mObserver->Observe(uri, "script-precompiled", nullptr);
+}
+
+NS_IMETHODIMP
+mozJSSubScriptLoader::PrecompileScript(nsIURI* aURI,
+                                       nsIPrincipal* aPrincipal,
+                                       nsIObserver *aObserver)
+{
+    nsCOMPtr<nsIChannel> channel;
+    nsresult rv = NS_NewChannel(getter_AddRefs(channel),
+                                aURI, nullptr, nullptr, nullptr,
+                                nsIRequest::LOAD_NORMAL, nullptr);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsRefPtr<ScriptPrecompiler> loadObserver =
+        new ScriptPrecompiler(aObserver, aPrincipal, channel);
+
+    nsCOMPtr<nsIStreamLoader> loader;
+    rv = NS_NewStreamLoader(getter_AddRefs(loader), loadObserver);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIStreamListener> listener = loader.get();
+    rv = channel->AsyncOpen(listener, nullptr);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+}
--- a/mobile/android/base/fxa/FirefoxAccounts.java
+++ b/mobile/android/base/fxa/FirefoxAccounts.java
@@ -7,16 +7,17 @@ package org.mozilla.gecko.fxa;
 import java.io.File;
 import java.util.EnumSet;
 import java.util.concurrent.CountDownLatch;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.fxa.authenticator.AccountPickler;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.fxa.sync.FxAccountSyncAdapter;
+import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.Utils;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.os.Bundle;
@@ -56,16 +57,23 @@ public class FirefoxAccounts {
   public static final EnumSet<SyncHint> NOW = EnumSet.of(
       SyncHint.SCHEDULE_NOW);
 
   public static final EnumSet<SyncHint> FORCE = EnumSet.of(
       SyncHint.SCHEDULE_NOW,
       SyncHint.IGNORE_LOCAL_RATE_LIMIT,
       SyncHint.IGNORE_REMOTE_SERVER_BACKOFF);
 
+  public interface SyncStatusListener {
+    public Context getContext();
+    public Account getAccount();
+    public void onSyncStarted();
+    public void onSyncFinished();
+  }
+
   /**
    * Returns true if a FirefoxAccount exists, false otherwise.
    *
    * @param context Android context.
    * @return true if at least one Firefox account exists.
    */
   public static boolean firefoxAccountsExist(final Context context) {
     return getFirefoxAccounts(context).length > 0;
@@ -195,34 +203,65 @@ public class FirefoxAccounts {
   }
 
   /**
    * Request a sync for the given Android Account.
    * <p>
    * Any hints are strictly optional: the actual requested sync is scheduled by
    * the Android sync scheduler, and the sync mechanism may ignore hints as it
    * sees fit.
+   * <p>
+   * It is safe to call this method from any thread.
    *
    * @param account to sync.
    * @param syncHints to pass to sync.
    * @param stagesToSync stage names to sync.
    * @param stagesToSkip stage names to skip.
    */
-  public static void requestSync(Account account, EnumSet<SyncHint> syncHints, String[] stagesToSync, String[] stagesToSkip) {
+  public static void requestSync(final Account account, EnumSet<SyncHint> syncHints, String[] stagesToSync, String[] stagesToSkip) {
     if (account == null) {
       throw new IllegalArgumentException("account must not be null");
     }
     if (syncHints == null) {
       throw new IllegalArgumentException("syncHints must not be null");
     }
 
     final Bundle extras = new Bundle();
     putHintsToSync(extras, syncHints);
     Utils.putStageNamesToSync(extras, stagesToSync, stagesToSkip);
 
     Logger.info(LOG_TAG, "Requesting sync.");
     logSyncHints(syncHints);
 
-    for (String authority : AndroidFxAccount.getAndroidAuthorities()) {
-      ContentResolver.requestSync(account, authority, extras);
-    }
+    // We get strict mode warnings on some devices, so make the request on a
+    // background thread.
+    ThreadPool.run(new Runnable() {
+      @Override
+      public void run() {
+        for (String authority : AndroidFxAccount.getAndroidAuthorities()) {
+          ContentResolver.requestSync(account, authority, extras);
+        }
+      }
+    });
+  }
+
+  /**
+   * Start notifying <code>syncStatusListener</code> of sync status changes.
+   * <p>
+   * Only a weak reference to <code>syncStatusListener</code> is held.
+   *
+   * @param syncStatusListener to start notifying.
+   */
+  public static void addSyncStatusListener(SyncStatusListener syncStatusListener) {
+    // startObserving null-checks its argument.
+    FxAccountSyncStatusHelper.getInstance().startObserving(syncStatusListener);
+  }
+
+  /**
+   * Stop notifying <code>syncStatusListener</code> of sync status changes.
+   *
+   * @param syncStatusListener to stop notifying.
+   */
+  public static void removeSyncStatusListener(SyncStatusListener syncStatusListener) {
+    // stopObserving null-checks its argument.
+    FxAccountSyncStatusHelper.getInstance().stopObserving(syncStatusListener);
   }
 }
--- a/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountConfirmAccountActivity.java
@@ -16,16 +16,17 @@ import org.mozilla.gecko.background.fxa.
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.fxa.login.Engaged;
 import org.mozilla.gecko.fxa.login.State;
 import org.mozilla.gecko.fxa.login.State.Action;
 import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
 import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
 
+import android.accounts.Account;
 import android.app.Activity;
 import android.content.Context;
 import android.os.Bundle;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -38,17 +39,17 @@ public class FxAccountConfirmAccountActi
 
   // Set in onCreate.
   protected TextView verificationLinkTextView;
   protected View resendLink;
 
   // Set in onResume.
   protected AndroidFxAccount fxAccount;
 
-  protected final SyncStatusDelegate syncStatusDelegate = new SyncStatusDelegate();
+  protected final InnerSyncStatusDelegate syncStatusDelegate = new InnerSyncStatusDelegate();
 
   public FxAccountConfirmAccountActivity() {
     super(CANNOT_RESUME_WHEN_NO_ACCOUNTS_EXIST);
   }
 
   /**
    * {@inheritDoc}
    */
@@ -97,36 +98,41 @@ public class FxAccountConfirmAccountActi
     super.onPause();
     FxAccountSyncStatusHelper.getInstance().stopObserving(syncStatusDelegate);
 
     if (fxAccount != null) {
       fxAccount.requestSync(FirefoxAccounts.SOON);
     }
   }
 
-  protected class SyncStatusDelegate implements FxAccountSyncStatusHelper.Delegate {
+  protected class InnerSyncStatusDelegate implements FirefoxAccounts.SyncStatusListener {
     protected final Runnable refreshRunnable = new Runnable() {
       @Override
       public void run() {
         refresh();
       }
     };
 
     @Override
-    public AndroidFxAccount getAccount() {
-      return fxAccount;
+    public Context getContext() {
+      return FxAccountConfirmAccountActivity.this;
     }
 
     @Override
-    public void handleSyncStarted() {
+    public Account getAccount() {
+      return fxAccount.getAndroidAccount();
+    }
+
+    @Override
+    public void onSyncStarted() {
       Logger.info(LOG_TAG, "Got sync started message; ignoring.");
     }
 
     @Override
-    public void handleSyncFinished() {
+    public void onSyncFinished() {
       if (fxAccount == null) {
         return;
       }
       Logger.info(LOG_TAG, "Got sync finished message; refreshing.");
       runOnUiThread(refreshRunnable);
     }
   }
 
--- a/mobile/android/base/fxa/activities/FxAccountStatusFragment.java
+++ b/mobile/android/base/fxa/activities/FxAccountStatusFragment.java
@@ -14,17 +14,19 @@ import org.mozilla.gecko.background.pref
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.fxa.login.Married;
 import org.mozilla.gecko.fxa.login.State;
 import org.mozilla.gecko.fxa.sync.FxAccountSyncStatusHelper;
 import org.mozilla.gecko.sync.SyncConfiguration;
 
+import android.accounts.Account;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.os.Handler;
 import android.preference.CheckBoxPreference;
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceClickListener;
 import android.preference.PreferenceCategory;
@@ -67,17 +69,17 @@ public class FxAccountStatusFragment ext
   // Used to post delayed sync requests.
   protected Handler handler;
 
   // Member variable so that re-posting pushes back the already posted instance.
   // This Runnable references the fxAccount above, but it is not specific to a
   // single account. (That is, it does not capture a single account instance.)
   protected Runnable requestSyncRunnable;
 
-  protected final SyncStatusDelegate syncStatusDelegate = new SyncStatusDelegate();
+  protected final InnerSyncStatusDelegate syncStatusDelegate = new InnerSyncStatusDelegate();
 
   protected Preference ensureFindPreference(String key) {
     Preference preference = findPreference(key);
     if (preference == null) {
       throw new IllegalStateException("Could not find preference with key: " + key);
     }
     return preference;
   }
@@ -235,40 +237,45 @@ public class FxAccountStatusFragment ext
   }
 
   protected void showConnected() {
     syncCategory.setTitle(R.string.fxaccount_status_sync_enabled);
     showOnlyOneErrorPreference(null);
     setCheckboxesEnabled(true);
   }
 
-  protected class SyncStatusDelegate implements FxAccountSyncStatusHelper.Delegate {
+  protected class InnerSyncStatusDelegate implements FirefoxAccounts.SyncStatusListener {
     protected final Runnable refreshRunnable = new Runnable() {
       @Override
       public void run() {
         refresh();
       }
     };
 
     @Override
-    public AndroidFxAccount getAccount() {
-      return fxAccount;
+    public Context getContext() {
+      return FxAccountStatusFragment.this.getActivity();
     }
 
     @Override
-    public void handleSyncStarted() {
+    public Account getAccount() {
+      return fxAccount.getAndroidAccount();
+    }
+
+    @Override
+    public void onSyncStarted() {
       if (fxAccount == null) {
         return;
       }
       Logger.info(LOG_TAG, "Got sync started message; refreshing.");
       getActivity().runOnUiThread(refreshRunnable);
     }
 
     @Override
-    public void handleSyncFinished() {
+    public void onSyncFinished() {
       if (fxAccount == null) {
         return;
       }
       Logger.info(LOG_TAG, "Got sync finished message; refreshing.");
       getActivity().runOnUiThread(refreshRunnable);
     }
   }
 
--- a/mobile/android/base/fxa/sync/FxAccountSyncStatusHelper.java
+++ b/mobile/android/base/fxa/sync/FxAccountSyncStatusHelper.java
@@ -3,77 +3,65 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.sync;
 
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.WeakHashMap;
 
+import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 
 import android.content.ContentResolver;
 import android.content.SyncStatusObserver;
 
 /**
  * Abstract away some details of Android's SyncStatusObserver.
  * <p>
  * Provides a simplified sync started/sync finished delegate.
- * <p>
- * We would prefer to register multiple observers, but it's of limited value
- * right now, so we support only a single observer, and we are as tolerant as
- * possible of non-paired add/remove calls.
  */
 public class FxAccountSyncStatusHelper implements SyncStatusObserver {
   @SuppressWarnings("unused")
   private static final String LOG_TAG = FxAccountSyncStatusHelper.class.getSimpleName();
 
   protected static FxAccountSyncStatusHelper sInstance = null;
 
   public synchronized static FxAccountSyncStatusHelper getInstance() {
     if (sInstance == null) {
       sInstance = new FxAccountSyncStatusHelper();
     }
     return sInstance;
   }
 
-  public interface Delegate {
-    public AndroidFxAccount getAccount();
-    public void handleSyncStarted();
-    public void handleSyncFinished();
-  }
-
   // Used to unregister this as a listener.
   protected Object handle = null;
 
   // Maps delegates to whether their underlying Android account was syncing the
   // last time we observed a status change.
-  protected Map<Delegate, Boolean> delegates = new WeakHashMap<Delegate, Boolean>();
+  protected Map<FirefoxAccounts.SyncStatusListener, Boolean> delegates = new WeakHashMap<FirefoxAccounts.SyncStatusListener, Boolean>();
 
   @Override
   public synchronized void onStatusChanged(int which) {
-    for (Entry<Delegate, Boolean> entry : delegates.entrySet()) {
-      final Delegate delegate = entry.getKey();
-      final AndroidFxAccount fxAccount = delegate.getAccount();
-      if (fxAccount == null) {
-        continue;
-      }
+    for (Entry<FirefoxAccounts.SyncStatusListener, Boolean> entry : delegates.entrySet()) {
+      final FirefoxAccounts.SyncStatusListener delegate = entry.getKey();
+      final AndroidFxAccount fxAccount = new AndroidFxAccount(delegate.getContext(), delegate.getAccount());
       final boolean active = fxAccount.isCurrentlySyncing();
       // Remember for later.
       boolean wasActiveLastTime = entry.getValue();
       // It's okay to update the value of an entry while iterating the entrySet.
       entry.setValue(active);
 
       if (active && !wasActiveLastTime) {
         // We've started a sync.
-        delegate.handleSyncStarted();
+        delegate.onSyncStarted();
       }
       if (!active && wasActiveLastTime) {
         // We've finished a sync.
-        delegate.handleSyncFinished();
+        delegate.onSyncFinished();
       }
     }
   }
 
   protected void addListener() {
     final int mask = ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
     if (this.handle != null) {
       throw new IllegalStateException("Already registered this as an observer?");
@@ -84,30 +72,30 @@ public class FxAccountSyncStatusHelper i
   protected void removeListener() {
     Object handle = this.handle;
     this.handle = null;
     if (handle != null) {
       ContentResolver.removeStatusChangeListener(handle);
     }
   }
 
-  public synchronized void startObserving(Delegate delegate) {
+  public synchronized void startObserving(FirefoxAccounts.SyncStatusListener delegate) {
     if (delegate == null) {
       throw new IllegalArgumentException("delegate must not be null");
     }
     if (delegates.containsKey(delegate)) {
       return;
     }
     // If we are the first delegate to the party, start listening.
     if (delegates.isEmpty()) {
       addListener();
     }
     delegates.put(delegate, Boolean.FALSE);
   }
 
-  public synchronized void stopObserving(Delegate delegate) {
+  public synchronized void stopObserving(FirefoxAccounts.SyncStatusListener delegate) {
     delegates.remove(delegate);
     // If we are the last delegate leaving the party, stop listening.
     if (delegates.isEmpty()) {
       removeListener();
     }
   }
 }
--- a/toolkit/components/autocomplete/nsAutoCompleteController.cpp
+++ b/toolkit/components/autocomplete/nsAutoCompleteController.cpp
@@ -405,17 +405,17 @@ nsAutoCompleteController::HandleKeyNavig
 
       if (completeSelection)
       {
         int32_t selectedIndex;
         popup->GetSelectedIndex(&selectedIndex);
         if (selectedIndex >= 0) {
           //  A result is selected, so fill in its value
           nsAutoString value;
-          if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, true, value))) {
+          if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, false, value))) {
             input->SetTextValue(value);
             input->SelectTextRange(value.Length(), value.Length());
           }
         } else {
           // Nothing is selected, so fill in the last typed value
           input->SetTextValue(mSearchString);
           input->SelectTextRange(mSearchString.Length(), mSearchString.Length());
         }
@@ -476,17 +476,17 @@ nsAutoCompleteController::HandleKeyNavig
     if (isOpen) {
       int32_t selectedIndex;
       popup->GetSelectedIndex(&selectedIndex);
       bool shouldComplete;
       input->GetCompleteDefaultIndex(&shouldComplete);
       if (selectedIndex >= 0) {
         // The pop-up is open and has a selection, take its value
         nsAutoString value;
-        if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, true, value))) {
+        if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, false, value))) {
           input->SetTextValue(value);
           input->SelectTextRange(value.Length(), value.Length());
         }
       }
       else if (shouldComplete) {
         // We usually try to preserve the casing of what user has typed, but
         // if he wants to autocomplete, we will replace the value with the
         // actual autocomplete result.
@@ -574,17 +574,17 @@ nsAutoCompleteController::HandleDelete(b
     // There are still rows in the popup, select the current index again.
     popup->SetSelectedIndex(index);
 
     // Complete to the new current value.
     bool shouldComplete = false;
     input->GetCompleteDefaultIndex(&shouldComplete);
     if (shouldComplete) {
       nsAutoString value;
-      if (NS_SUCCEEDED(GetResultValueAt(index, true, value))) {
+      if (NS_SUCCEEDED(GetResultValueAt(index, false, value))) {
         CompleteValue(value);
       }
     }
 
     // Invalidate the popup.
     popup->Invalidate();
   } else {
     // Nothing left in the popup, clear any pending search timers and
@@ -611,25 +611,25 @@ nsAutoCompleteController::GetResultAt(in
   *aResult = mResults[searchIndex];
   NS_ENSURE_TRUE(*aResult, NS_ERROR_FAILURE);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteController::GetValueAt(int32_t aIndex, nsAString & _retval)
 {
-  GetResultLabelAt(aIndex, false, _retval);
+  GetResultLabelAt(aIndex, _retval);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteController::GetLabelAt(int32_t aIndex, nsAString & _retval)
 {
-  GetResultLabelAt(aIndex, false, _retval);
+  GetResultLabelAt(aIndex, _retval);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteController::GetCommentAt(int32_t aIndex, nsAString & _retval)
 {
   int32_t rowIndex;
@@ -658,16 +658,28 @@ nsAutoCompleteController::GetImageAt(int
   nsIAutoCompleteResult* result;
   nsresult rv = GetResultAt(aIndex, &result, &rowIndex);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return result->GetImageAt(rowIndex, _retval);
 }
 
 NS_IMETHODIMP
+nsAutoCompleteController::GetFinalCompleteValueAt(int32_t aIndex,
+                                                  nsAString & _retval)
+{
+  int32_t rowIndex;
+  nsIAutoCompleteResult* result;
+  nsresult rv = GetResultAt(aIndex, &result, &rowIndex);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return result->GetFinalCompleteValueAt(rowIndex, _retval);
+}
+
+NS_IMETHODIMP
 nsAutoCompleteController::SetSearchString(const nsAString &aSearchString)
 {
   mSearchString = aSearchString;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteController::GetSearchString(nsAString &aSearchString)
@@ -1176,19 +1188,24 @@ nsAutoCompleteController::EnterMatch(boo
 
     int32_t selectedIndex;
     popup->GetSelectedIndex(&selectedIndex);
     if (selectedIndex >= 0) {
       // If completeselectedindex is false or a row was selected from the popup,
       // enter it into the textbox. If completeselectedindex is true, or
       // EnterMatch was called via other means, for instance pressing Enter,
       // don't fill in the value as it will have already been filled in as
-      // needed.
-      if (!completeSelection || aIsPopupSelection)
-        GetResultValueAt(selectedIndex, true, value);
+      // needed, unless the final complete value differs.
+      nsAutoString finalValue, inputValue;
+      GetResultValueAt(selectedIndex, true, finalValue);
+      input->GetTextValue(inputValue);
+      if (!completeSelection || aIsPopupSelection ||
+          !finalValue.Equals(inputValue)) {
+        value = finalValue;
+      }
     }
     else if (shouldComplete) {
       // We usually try to preserve the casing of what user has typed, but
       // if he wants to autocomplete, we will replace the value with the
       // actual autocomplete result.
       // The user wants explicitely to use that result, so this ensures
       // association of the result with the autocompleted text.
       nsAutoString defaultIndexValue;
@@ -1201,17 +1218,17 @@ nsAutoCompleteController::EnterMatch(boo
       // we have to find the first default match and enter it instead
       for (uint32_t i = 0; i < mResults.Length(); ++i) {
         nsIAutoCompleteResult *result = mResults[i];
 
         if (result) {
           int32_t defaultIndex;
           result->GetDefaultIndex(&defaultIndex);
           if (defaultIndex >= 0) {
-            result->GetValueAt(defaultIndex, value);
+            result->GetFinalCompleteValueAt(defaultIndex, value);
             break;
           }
         }
       }
     }
   }
 
   nsCOMPtr<nsIObserverService> obsSvc =
@@ -1544,28 +1561,20 @@ nsAutoCompleteController::GetFinalDefaul
 
   result->GetValueAt(defaultIndex, _retval);
   nsAutoString inputValue;
   mInput->GetTextValue(inputValue);
   if (!_retval.Equals(inputValue, nsCaseInsensitiveStringComparator())) {
     return NS_ERROR_FAILURE;
   }
 
-  // Hack: For typeAheadResults allow the comment to be used as the final
-  // defaultComplete value if provided, otherwise fall back to the usual
-  // value.  This allows to provide a different complete text when the user
-  // confirms the match.  Don't rely on this for production code, since it's a
-  // temporary solution that needs a dedicated API (bug 754265).
-  bool isTypeAheadResult = false;
-  nsAutoString commentValue;
-  if (NS_SUCCEEDED(result->GetTypeAheadResult(&isTypeAheadResult)) &&
-      isTypeAheadResult &&
-      NS_SUCCEEDED(result->GetCommentAt(defaultIndex, commentValue)) &&
-      !commentValue.IsEmpty()) {
-    _retval = commentValue;
+  nsAutoString finalCompleteValue;
+  rv = result->GetFinalCompleteValueAt(defaultIndex, finalCompleteValue);
+  if (NS_SUCCEEDED(rv)) {
+    _retval = finalCompleteValue;
   }
 
   MOZ_ASSERT(FindInReadable(inputValue, _retval, nsCaseInsensitiveStringComparator()),
              "Return value must include input value.");
   return NS_OK;
 }
 
 nsresult
@@ -1620,48 +1629,53 @@ nsAutoCompleteController::CompleteValue(
   }
 
   mInput->SelectTextRange(mSearchStringLength, endSelect);
 
   return NS_OK;
 }
 
 nsresult
-nsAutoCompleteController::GetResultLabelAt(int32_t aIndex, bool aValueOnly, nsAString & _retval)
+nsAutoCompleteController::GetResultLabelAt(int32_t aIndex, nsAString & _retval)
 {
-  return GetResultValueLabelAt(aIndex, aValueOnly, false, _retval);
+  return GetResultValueLabelAt(aIndex, false, false, _retval);
 }
 
 nsresult
-nsAutoCompleteController::GetResultValueAt(int32_t aIndex, bool aValueOnly, nsAString & _retval)
+nsAutoCompleteController::GetResultValueAt(int32_t aIndex, bool aGetFinalValue,
+                                           nsAString & _retval)
 {
-  return GetResultValueLabelAt(aIndex, aValueOnly, true, _retval);
+  return GetResultValueLabelAt(aIndex, aGetFinalValue, true, _retval);
 }
 
 nsresult
-nsAutoCompleteController::GetResultValueLabelAt(int32_t aIndex, bool aValueOnly,
-                                                bool aGetValue, nsAString & _retval)
+nsAutoCompleteController::GetResultValueLabelAt(int32_t aIndex,
+                                                bool aGetFinalValue,
+                                                bool aGetValue,
+                                                nsAString & _retval)
 {
   NS_ENSURE_TRUE(aIndex >= 0 && (uint32_t) aIndex < mRowCount, NS_ERROR_ILLEGAL_VALUE);
 
   int32_t rowIndex;
   nsIAutoCompleteResult *result;
   nsresult rv = GetResultAt(aIndex, &result, &rowIndex);
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint16_t searchResult;
   result->GetSearchResult(&searchResult);
 
   if (searchResult == nsIAutoCompleteResult::RESULT_FAILURE) {
-    if (aValueOnly)
+    if (aGetValue)
       return NS_ERROR_FAILURE;
     result->GetErrorDescription(_retval);
   } else if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS ||
              searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
-    if (aGetValue)
+    if (aGetFinalValue)
+      result->GetFinalCompleteValueAt(rowIndex, _retval);
+    else if (aGetValue)
       result->GetValueAt(rowIndex, _retval);
     else
       result->GetLabelAt(rowIndex, _retval);
   }
 
   return NS_OK;
 }
 
--- a/toolkit/components/autocomplete/nsAutoCompleteController.h
+++ b/toolkit/components/autocomplete/nsAutoCompleteController.h
@@ -54,22 +54,21 @@ protected:
   nsresult EnterMatch(bool aIsPopupSelection);
   nsresult RevertTextValue();
 
   nsresult CompleteDefaultIndex(int32_t aResultIndex);
   nsresult CompleteValue(nsString &aValue);
 
   nsresult GetResultAt(int32_t aIndex, nsIAutoCompleteResult** aResult,
                        int32_t* aRowIndex);
-  nsresult GetResultValueAt(int32_t aIndex, bool aValueOnly,
+  nsresult GetResultValueAt(int32_t aIndex, bool aGetFinalValue,
                             nsAString & _retval);
-  nsresult GetResultLabelAt(int32_t aIndex, bool aValueOnly,
-                            nsAString & _retval);
+  nsresult GetResultLabelAt(int32_t aIndex, nsAString & _retval);
 private:
-  nsresult GetResultValueLabelAt(int32_t aIndex, bool aValueOnly,
+  nsresult GetResultValueLabelAt(int32_t aIndex, bool aGetFinalValue,
                                  bool aGetValue, nsAString & _retval);
 protected:
 
   /**
    * Gets and validates the defaultComplete result and the relative
    * defaultIndex value.
    *
    * @param aResultIndex
--- a/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp
+++ b/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp
@@ -85,17 +85,18 @@ nsAutoCompleteSimpleResult::SetTypeAhead
   mTypeAheadResult = aTypeAheadResult;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteSimpleResult::AppendMatch(const nsAString& aValue,
                                         const nsAString& aComment,
                                         const nsAString& aImage,
-                                        const nsAString& aStyle)
+                                        const nsAString& aStyle,
+                                        const nsAString& aFinalCompleteValue)
 {
   CheckInvariants();
 
   if (! mValues.AppendElement(aValue))
     return NS_ERROR_OUT_OF_MEMORY;
   if (! mComments.AppendElement(aComment)) {
     mValues.RemoveElementAt(mValues.Length() - 1);
     return NS_ERROR_OUT_OF_MEMORY;
@@ -106,16 +107,23 @@ nsAutoCompleteSimpleResult::AppendMatch(
     return NS_ERROR_OUT_OF_MEMORY;
   }
   if (! mStyles.AppendElement(aStyle)) {
     mValues.RemoveElementAt(mValues.Length() - 1);
     mComments.RemoveElementAt(mComments.Length() - 1);
     mImages.RemoveElementAt(mImages.Length() - 1);
     return NS_ERROR_OUT_OF_MEMORY;
   }
+  if (!mFinalCompleteValues.AppendElement(aFinalCompleteValue)) {
+    mValues.RemoveElementAt(mValues.Length() - 1);
+    mComments.RemoveElementAt(mComments.Length() - 1);
+    mImages.RemoveElementAt(mImages.Length() - 1);
+    mStyles.RemoveElementAt(mStyles.Length() - 1);
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteSimpleResult::GetMatchCount(uint32_t *aMatchCount)
 {
   CheckInvariants();
 
@@ -166,16 +174,29 @@ nsAutoCompleteSimpleResult::GetStyleAt(i
   NS_ENSURE_TRUE(aIndex >= 0 && aIndex < int32_t(mStyles.Length()),
                  NS_ERROR_ILLEGAL_VALUE);
   CheckInvariants();
   _retval = mStyles[aIndex];
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsAutoCompleteSimpleResult::GetFinalCompleteValueAt(int32_t aIndex,
+                                                    nsAString& _retval)
+{
+  NS_ENSURE_TRUE(aIndex >= 0 && aIndex < int32_t(mFinalCompleteValues.Length()),
+                 NS_ERROR_ILLEGAL_VALUE);
+  CheckInvariants();
+  _retval = mFinalCompleteValues[aIndex];
+  if (_retval.Length() == 0)
+    _retval = mValues[aIndex];
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsAutoCompleteSimpleResult::SetListener(nsIAutoCompleteSimpleResultListener* aListener)
 {
   mListener = aListener;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteSimpleResult::RemoveValueAt(int32_t aRowIndex,
@@ -184,14 +205,15 @@ nsAutoCompleteSimpleResult::RemoveValueA
   NS_ENSURE_TRUE(aRowIndex >= 0 && aRowIndex < int32_t(mValues.Length()),
                  NS_ERROR_ILLEGAL_VALUE);
 
   nsAutoString removedValue(mValues[aRowIndex]);
   mValues.RemoveElementAt(aRowIndex);
   mComments.RemoveElementAt(aRowIndex);
   mImages.RemoveElementAt(aRowIndex);
   mStyles.RemoveElementAt(aRowIndex);
+  mFinalCompleteValues.RemoveElementAt(aRowIndex);
 
   if (mListener)
     mListener->OnValueRemoved(this, removedValue, aRemoveFromDb);
 
   return NS_OK;
 }
--- a/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h
+++ b/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h
@@ -16,16 +16,17 @@
 class nsAutoCompleteSimpleResult MOZ_FINAL : public nsIAutoCompleteSimpleResult
 {
 public:
   nsAutoCompleteSimpleResult();
   inline void CheckInvariants() {
     NS_ASSERTION(mValues.Length() == mComments.Length(), "Arrays out of sync");
     NS_ASSERTION(mValues.Length() == mImages.Length(),   "Arrays out of sync");
     NS_ASSERTION(mValues.Length() == mStyles.Length(),   "Arrays out of sync");
+    NS_ASSERTION(mValues.Length() == mFinalCompleteValues.Length(), "Arrays out of sync");
   }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIAUTOCOMPLETERESULT
   NS_DECL_NSIAUTOCOMPLETESIMPLERESULT
 
 private:
   ~nsAutoCompleteSimpleResult() {}
@@ -34,16 +35,17 @@ protected:
 
   // What we really want is an array of structs with value/comment/image/style contents.
   // But then we'd either have to use COM or manage object lifetimes ourselves.
   // Having four arrays of string simplifies this, but is stupid.
   nsTArray<nsString> mValues;
   nsTArray<nsString> mComments;
   nsTArray<nsString> mImages;
   nsTArray<nsString> mStyles;
+  nsTArray<nsString> mFinalCompleteValues;
 
   nsString mSearchString;
   nsString mErrorDescription;
   int32_t mDefaultIndex;
   uint32_t mSearchResult;
 
   bool mTypeAheadResult;
 
--- a/toolkit/components/autocomplete/nsIAutoCompleteController.idl
+++ b/toolkit/components/autocomplete/nsIAutoCompleteController.idl
@@ -1,17 +1,17 @@
 /* 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/. */
 
 #include "nsISupports.idl"
 
 interface nsIAutoCompleteInput;
 
-[scriptable, uuid(dd2c4489-e4bd-4702-86bc-e1691744e556)]
+[scriptable, uuid(ff9f8465-204a-47a6-b3c9-0628b3856684)]
 interface nsIAutoCompleteController : nsISupports
 {
   /*
    * Possible values for the searchStatus attribute
    */
   const unsigned short STATUS_NONE = 1;
   const unsigned short STATUS_SEARCHING = 2;
   const unsigned short STATUS_COMPLETE_NO_MATCH = 3;
@@ -130,12 +130,18 @@ interface nsIAutoCompleteController : ns
   AString getStyleAt(in long index);
 
   /*
    * Get the url of the image of the result at a given index in the last completed search
    */
   AString getImageAt(in long index);
 
   /*
+   * For the last completed search, get the final value that should be completed
+   * when the user confirms the match at the given index
+   */
+  AString getFinalCompleteValueAt(in long index);
+
+  /*
    * Get / set the current search string.  Note, setting will not start searching
    */
   attribute AString searchString;
 };
--- a/toolkit/components/autocomplete/nsIAutoCompleteResult.idl
+++ b/toolkit/components/autocomplete/nsIAutoCompleteResult.idl
@@ -1,15 +1,15 @@
 /* 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/. */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(7b43fad1-c735-4b45-9383-c3f057fed20d)]
+[scriptable, uuid(9203c031-c4e7-4537-a4ec-81443d623d5a)]
 interface nsIAutoCompleteResult : nsISupports
 {
   /**
    * Possible values for the searchResult attribute
    */
   const unsigned short RESULT_IGNORED = 1; /* indicates invalid searchString */
   const unsigned short RESULT_FAILURE = 2; /* indicates failure */
   const unsigned short RESULT_NOMATCH = 3; /* indicates success with no matches
@@ -77,14 +77,20 @@ interface nsIAutoCompleteResult : nsISup
   AString getStyleAt(in long index);
 
   /**
    * Get the image of the result at the given index
    */
   AString getImageAt(in long index);
 
   /**
+   * Get the final value that should be completed when the user confirms
+   * the match at the given index.
+   */
+  AString getFinalCompleteValueAt(in long index);
+
+  /**
    * Remove the value at the given index from the autocomplete results.
    * If removeFromDb is set to true, the value should be removed from
    * persistent storage as well.
    */
   void removeValueAt(in long rowIndex, in boolean removeFromDb);
 };
--- a/toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl
+++ b/toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl
@@ -9,17 +9,17 @@ interface nsIAutoCompleteSimpleResultLis
 
 /**
  * This class implements nsIAutoCompleteResult and provides simple methods
  * for setting the value and result items. It can be used whenever some basic
  * auto complete results are needed that can be pre-generated and filled into
  * an array.
  */
 
-[scriptable, uuid(c738dc26-aa71-4561-a3fd-b5a0e4aa80d2)]
+[scriptable, uuid(fe8802f9-c2b7-4141-8e5b-280df3f62251)]
 interface nsIAutoCompleteSimpleResult : nsIAutoCompleteResult
 {
   /**
    * A writer for the readonly attribute 'searchString' which should contain
    * the string that the user typed.
    */
   void setSearchString(in AString aSearchString);
 
@@ -43,22 +43,35 @@ interface nsIAutoCompleteSimpleResult : 
 
   /**
    * A writer for the readonly attribute 'typeAheadResult', typically set
    * because a result is only intended for type-ahead completion.
    */
   void setTypeAheadResult(in boolean aHidden);
 
   /**
-   * Appends a result item consisting of the given value, comment, image and style.
-   * This is how you add results.  Note:  image and style are optional. 
+   * Appends a match consisting of the given value, comment, image, style and
+   * the value to use for defaultIndex completion.
+   * @param aValue
+   *        The value to autocomplete to
+   * @param aComment
+   *        Comment shown in the autocomplete widget to describe this match
+   * @param aImage
+   *        Image shown in the autocomplete widget for this match.
+   * @param aStyle
+   *        Describes how to style the match in the autocomplete widget
+   * @param aFinalCompleteValue
+   *        Value used when the user confirms selecting this match. If not
+   *        provided, aValue will be used.
    */
-  void appendMatch(in AString aValue, in AString aComment, 
-                   [optional] in AString aImage, 
-                   [optional] in AString aStyle);
+  void appendMatch(in AString aValue,
+                   in AString aComment,
+                   [optional] in AString aImage,
+                   [optional] in AString aStyle,
+                   [optional] in AString aFinalCompleteValue);
 
   /**
    * Sets a listener for changes in the result.
    */
   void setListener(in nsIAutoCompleteSimpleResultListener aListener);
 };
 
 [scriptable, uuid(004efdc5-1989-4874-8a7a-345bf2fa33af)]
--- a/toolkit/components/autocomplete/tests/unit/head_autocomplete.js
+++ b/toolkit/components/autocomplete/tests/unit/head_autocomplete.js
@@ -73,17 +73,18 @@ function AutoCompleteResultBase(aValues)
   this._values = aValues;
 }
 AutoCompleteResultBase.prototype = {
   
   // Arrays
   _values: null,
   _comments: [],
   _styles: [],
-  
+  _finalCompleteValues: [],
+
   searchString: "",
   searchResult: null,
   
   defaultIndex: -1,
   
   _typeAheadResult: false,
   get typeAheadResult() {
     return this._typeAheadResult;
@@ -108,16 +109,20 @@ AutoCompleteResultBase.prototype = {
   getStyleAt: function(aIndex) {
     return this._styles[aIndex];
   },
   
   getImageAt: function(aIndex) {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex) {
+    return this._finalCompleteValues[aIndex] || this._values[aIndex];
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteResult])
 }
 
 /** 
  * nsIAutoCompleteSearch implementation that always returns
--- a/toolkit/components/autocomplete/tests/unit/test_378079.js
+++ b/toolkit/components/autocomplete/tests/unit/test_378079.js
@@ -118,16 +118,20 @@ AutoCompleteResult.prototype = {
   getStyleAt: function(aIndex) {
     return this._styles[aIndex];
   },
   
   getImageAt: function(aIndex) {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex) {
+    return this.getValueAt(aIndex);
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: function(iid) {
     if (iid.equals(Ci.nsISupports) ||
         iid.equals(Ci.nsIAutoCompleteResult))
       return this;
 
--- a/toolkit/components/autocomplete/tests/unit/test_393191.js
+++ b/toolkit/components/autocomplete/tests/unit/test_393191.js
@@ -117,16 +117,20 @@ AutoCompleteResult.prototype = {
   getStyleAt: function(aIndex) {
     return this._styles[aIndex];
   },
   
   getImageAt: function(aIndex) {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex) {
+    return this.getValueAt(aIndex);
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: function(iid) {
     if (iid.equals(Ci.nsISupports) ||
         iid.equals(Ci.nsIAutoCompleteResult))
       return this;
 
--- a/toolkit/components/autocomplete/tests/unit/test_440866.js
+++ b/toolkit/components/autocomplete/tests/unit/test_440866.js
@@ -116,16 +116,20 @@ AutoCompleteResult.prototype = {
   getStyleAt: function(aIndex) {
     return this._styles[aIndex];
   },
 
   getImageAt: function(aIndex) {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex) {
+    return this.getValueAt(aIndex);
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: function(iid) {
     if (iid.equals(Ci.nsISupports) ||
         iid.equals(Ci.nsIAutoCompleteResult))
       return this;
 
--- a/toolkit/components/autocomplete/tests/unit/test_autocomplete_multiple.js
+++ b/toolkit/components/autocomplete/tests/unit/test_autocomplete_multiple.js
@@ -105,16 +105,20 @@ AutoCompleteResult.prototype = {
   getStyleAt: function(aIndex) {
     return this._styles[aIndex];
   },
   
   getImageAt: function(aIndex) {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex) {
+    return this.getValueAt(aIndex);
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: function(iid) {
     if (iid.equals(Ci.nsISupports) ||
         iid.equals(Ci.nsIAutoCompleteResult))
       return this;
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/autocomplete/tests/unit/test_finalCompleteValue.js
@@ -0,0 +1,54 @@
+/* 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/. */
+
+function AutoCompleteResult(aValues, aFinalCompleteValues) {
+  this._values = aValues;
+  this._finalCompleteValues = aFinalCompleteValues;
+}
+AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
+
+function AutoCompleteInput(aSearches) {
+  this.searches = aSearches;
+  this.popup.selectedIndex = 0;
+}
+AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
+
+function run_test() {
+  run_next_test();
+}
+
+add_test(function test_handleEnter() {
+  doSearch("moz", "mozilla.com", "http://www.mozilla.com", function(aController) {
+    do_check_eq(aController.input.textValue, "moz");
+    do_check_eq(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com");
+    aController.handleEnter(false);
+    do_check_eq(aController.input.textValue, "http://www.mozilla.com");
+  });
+});
+
+function doSearch(aSearchString, aResultValue, aFinalCompleteValue, aOnCompleteCallback) {
+  let search = new AutoCompleteSearchBase(
+    "search",
+    new AutoCompleteResult([ aResultValue ], [ aFinalCompleteValue ])
+  );
+  registerAutoCompleteSearch(search);
+
+  let controller = Cc["@mozilla.org/autocomplete/controller;1"].
+                   getService(Ci.nsIAutoCompleteController);  
+  
+  // Make an AutoCompleteInput that uses our searches and confirms results.
+  let input = new AutoCompleteInput([ search.name ]);
+  input.textValue = aSearchString;
+
+  controller.input = input;
+  controller.startSearch(aSearchString);
+
+  input.onSearchComplete = function onSearchComplete() {
+    aOnCompleteCallback(controller);
+
+    // Clean up.
+    unregisterAutoCompleteSearch(search);
+    run_next_test();
+  };
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/components/autocomplete/tests/unit/test_finalCompleteValue_forceComplete.js
@@ -0,0 +1,56 @@
+/* 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/. */
+
+function AutoCompleteResult(aValues, aFinalCompleteValues) {
+  this._values = aValues;
+  this._finalCompleteValues = aFinalCompleteValues;
+  this.defaultIndex = 0;
+}
+AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
+
+function AutoCompleteInput(aSearches) {
+  this.searches = aSearches;
+  this.popup.selectedIndex = -1;
+}
+AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
+
+function run_test() {
+  run_next_test();
+}
+
+add_test(function test_handleEnter() {
+  doSearch("", "mozilla.com", "http://www.mozilla.com", function(aController) {
+    do_check_eq(aController.input.textValue, "");
+    do_check_eq(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com");
+    aController.input.forceComplete = true;
+    aController.handleEnter(false);
+    do_check_eq(aController.input.textValue, "http://www.mozilla.com");
+  });
+});
+
+function doSearch(aSearchString, aResultValue, aFinalCompleteValue, aOnCompleteCallback) {
+  let search = new AutoCompleteSearchBase(
+    "search",
+    new AutoCompleteResult([ aResultValue ], [ aFinalCompleteValue ])
+  );
+  registerAutoCompleteSearch(search);
+
+  let controller = Cc["@mozilla.org/autocomplete/controller;1"].
+                   getService(Ci.nsIAutoCompleteController);  
+  
+  // Make an AutoCompleteInput that uses our searches and confirms results.
+  let input = new AutoCompleteInput([ search.name ]);
+  input.textValue = aSearchString;
+
+  controller.input = input;
+  controller.startSearch(aSearchString);
+
+  input.onSearchComplete = function onSearchComplete() {
+    aOnCompleteCallback(controller);
+
+    // Clean up.
+    unregisterAutoCompleteSearch(search);
+    run_next_test();
+  };
+}
--- a/toolkit/components/autocomplete/tests/unit/test_finalDefaultCompleteValue.js
+++ b/toolkit/components/autocomplete/tests/unit/test_finalDefaultCompleteValue.js
@@ -1,17 +1,16 @@
 /* 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/. */
 
-function AutoCompleteResult(aValues, aComments) {
+function AutoCompleteResult(aValues, aFinalCompleteValues) {
   this._values = aValues;
-  this._comments = aComments;
+  this._finalCompleteValues = aFinalCompleteValues;
   this.defaultIndex = 0;
-  this._typeAheadResult = true;
 }
 AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
 
 function AutoCompleteInput(aSearches) {
   this.searches = aSearches;
   this.popup.selectedIndex = -1;
   this.completeDefaultIndex = true;
 }
@@ -32,20 +31,20 @@ add_test(function test_keyNavigation() {
 add_test(function test_handleEnter() {
   doSearch("moz", "mozilla.com", "http://www.mozilla.com", function(aController) {
     do_check_eq(aController.input.textValue, "mozilla.com");
     aController.handleEnter(false);
     do_check_eq(aController.input.textValue, "http://www.mozilla.com");
   });
 });
 
-function doSearch(aSearchString, aResultValue, aCommentValue, aOnCompleteCallback) {
+function doSearch(aSearchString, aResultValue, aFinalCompleteValue, aOnCompleteCallback) {
   let search = new AutoCompleteSearchBase(
     "search",
-    new AutoCompleteResult([ aResultValue ], [ aCommentValue ], 0)
+    new AutoCompleteResult([ aResultValue ], [ aFinalCompleteValue ])
   );
   registerAutoCompleteSearch(search);
 
   let controller = Cc["@mozilla.org/autocomplete/controller;1"].
                    getService(Ci.nsIAutoCompleteController);  
   
   // Make an AutoCompleteInput that uses our searches and confirms results.
   let input = new AutoCompleteInput([ search.name ]);
--- a/toolkit/components/autocomplete/tests/unit/test_popupSelectionVsDefaultCompleteValue.js
+++ b/toolkit/components/autocomplete/tests/unit/test_popupSelectionVsDefaultCompleteValue.js
@@ -1,23 +1,22 @@
 /* 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/. */
 
-function AutoCompleteTypeAheadResult(aValues, aComments) {
+function AutoCompleteTypeAheadResult(aValues, aFinalCompleteValues) {
   this._values = aValues;
-  this._comments = aComments;
+  this._finalCompleteValues = aFinalCompleteValues;
   this.defaultIndex = 0;
   this._typeAheadResult = true;
 }
 AutoCompleteTypeAheadResult.prototype = Object.create(AutoCompleteResultBase.prototype);
 
-function AutoCompleteResult(aValues, aComments) {
+function AutoCompleteResult(aValues) {
   this._values = aValues;
-  this._comments = aComments;
 }
 AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
 
 function AutoCompleteInput(aSearches) {
   this.searches = aSearches;
   this.popupOpen = true;
   this.completeDefaultIndex = true;
   this.completeSelectedIndex = true;
@@ -40,17 +39,17 @@ function doSearch(aSearchString, aOnComp
   let typeAheadSearch = new AutoCompleteSearchBase(
     "typeAheadSearch",
     new AutoCompleteTypeAheadResult([ "mozilla.com" ], [ "http://www.mozilla.com" ])
   );
   registerAutoCompleteSearch(typeAheadSearch);
 
   let search = new AutoCompleteSearchBase(
     "search",
-    new AutoCompleteResult([ "mozilla.org" ], [ "http://www.mozilla.org" ])
+    new AutoCompleteResult([ "mozilla.org" ])
   );
   registerAutoCompleteSearch(search);
 
   let controller = Cc["@mozilla.org/autocomplete/controller;1"].
                    getService(Ci.nsIAutoCompleteController);
 
   // Make an AutoCompleteInput that uses our searches and confirms results.
   let input = new AutoCompleteInput([ typeAheadSearch.name, search.name ]);
--- a/toolkit/components/autocomplete/tests/unit/test_previousResult.js
+++ b/toolkit/components/autocomplete/tests/unit/test_previousResult.js
@@ -116,16 +116,20 @@ AutoCompleteResult.prototype = {
   getStyleAt: function(aIndex) {
     return this._styles[aIndex];
   },
   
   getImageAt: function(aIndex) {
     return "";
   },
 
+  getFinalCompleteValueAt: function(aIndex) {
+    return this.getValueAt(aIndex);
+  },
+
   removeValueAt: function (aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
   QueryInterface: function(iid) {
     if (iid.equals(Ci.nsISupports) ||
         iid.equals(Ci.nsIAutoCompleteResult))
       return this;
 
--- a/toolkit/components/autocomplete/tests/unit/xpcshell.ini
+++ b/toolkit/components/autocomplete/tests/unit/xpcshell.ini
@@ -6,14 +6,16 @@ tail =
 [test_378079.js]
 [test_393191.js]
 [test_440866.js]
 [test_463023.js]
 [test_660156.js]
 [test_autocomplete_multiple.js]
 [test_badDefaultIndex.js]
 [test_completeDefaultIndex_casing.js]
+[test_finalCompleteValue.js]
+[test_finalCompleteValue_forceComplete.js]
 [test_finalDefaultCompleteValue.js]
 [test_hiddenResult.js]
 [test_immediate_search.js]
 [test_popupSelectionVsDefaultCompleteValue.js]
 [test_previousResult.js]
 [test_stopSearch.js]
--- a/toolkit/components/filepicker/nsFileView.cpp
+++ b/toolkit/components/filepicker/nsFileView.cpp
@@ -167,16 +167,21 @@ NS_IMETHODIMP nsFileResult::GetStyleAt(i
   return NS_OK;
 }
 
 NS_IMETHODIMP nsFileResult::GetImageAt(int32_t index, nsAString & aImage)
 {
   aImage.Truncate();
   return NS_OK;
 }
+NS_IMETHODIMP nsFileResult::GetFinalCompleteValueAt(int32_t index,
+                                                    nsAString & aValue)
+{
+  return GetValueAt(index, aValue);
+}
 
 NS_IMETHODIMP nsFileResult::RemoveValueAt(int32_t rowIndex, bool removeFromDb)
 {
   return NS_OK;
 }
 
 class nsFileComplete MOZ_FINAL : public nsIAutoCompleteSearch
 {
--- a/toolkit/components/passwordmgr/nsLoginManager.js
+++ b/toolkit/components/passwordmgr/nsLoginManager.js
@@ -606,16 +606,20 @@ UserAutoCompleteResult.prototype = {
     getStyleAt : function (index) {
         return "";
     },
 
     getImageAt : function (index) {
         return "";
     },
 
+    getFinalCompleteValueAt : function (index) {
+        return this.getValueAt(index);
+    },
+
     removeValueAt : function (index, removeFromDB) {
         if (index < 0 || index >= this.logins.length)
             throw "Index out of range.";
 
         var [removedLogin] = this.logins.splice(index, 1);
 
         this.matchCount--;
         if (this.defaultIndex > this.logins.length)
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -151,73 +151,58 @@ this.PlacesUtils = {
 
   /**
    * Determines whether or not a ResultNode is a Bookmark folder.
    * @param   aNode
    *          A result node
    * @returns true if the node is a Bookmark folder, false otherwise
    */
   nodeIsFolder: function PU_nodeIsFolder(aNode) {
-    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
-      throw new Error("Invalid Places node");
-    }
     return (aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER ||
             aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT);
   },
 
   /**
    * Determines whether or not a ResultNode represents a bookmarked URI.
    * @param   aNode
    *          A result node
    * @returns true if the node represents a bookmarked URI, false otherwise
    */
   nodeIsBookmark: function PU_nodeIsBookmark(aNode) {
-    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
-      throw new Error("Invalid Places node");
-    }
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_URI &&
            aNode.itemId != -1;
   },
 
   /**
    * Determines whether or not a ResultNode is a Bookmark separator.
    * @param   aNode
    *          A result node
    * @returns true if the node is a Bookmark separator, false otherwise
    */
   nodeIsSeparator: function PU_nodeIsSeparator(aNode) {
-    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
-      throw new Error("Invalid Places node");
-    }
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR;
   },
 
   /**
    * Determines whether or not a ResultNode is a URL item.
    * @param   aNode
    *          A result node
    * @returns true if the node is a URL item, false otherwise
    */
   nodeIsURI: function PU_nodeIsURI(aNode) {
-    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
-      throw new Error("Invalid Places node");
-    }
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_URI;
   },
 
   /**
    * Determines whether or not a ResultNode is a Query item.
    * @param   aNode
    *          A result node
    * @returns true if the node is a Query item, false otherwise
    */
   nodeIsQuery: function PU_nodeIsQuery(aNode) {
-    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
-      throw new Error("Invalid Places node");
-    }
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY;
   },
 
   /**
    * Generator for a node's ancestors.
    * @param aNode
    *        A result node
    */
@@ -367,19 +352,16 @@ this.PlacesUtils = {
   /**
    * Determines if a node is read only (children cannot be inserted, sometimes
    * they cannot be removed depending on the circumstance)
    * @param   aNode
    *          A result node
    * @returns true if the node is readonly, false otherwise
    */
   nodeIsReadOnly: function PU_nodeIsReadOnly(aNode) {
-    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
-      throw new Error("Invalid Places node");
-    }
     let itemId = aNode.itemId;
     if (itemId != -1) {
       return this._readOnly.indexOf(itemId) != -1;
     }
 
     if (this.nodeIsQuery(aNode) &&
         asQuery(aNode).queryOptions.resultType !=
         Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS)
@@ -389,71 +371,59 @@ this.PlacesUtils = {
 
   /**
    * Determines whether or not a ResultNode is a host container.
    * @param   aNode
    *          A result node
    * @returns true if the node is a host container, false otherwise
    */
   nodeIsHost: function PU_nodeIsHost(aNode) {
-    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
-      throw new Error("Invalid Places node");
-    }
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY &&
            aNode.parent &&
            asQuery(aNode.parent).queryOptions.resultType ==
              Ci.nsINavHistoryQueryOptions.RESULTS_AS_SITE_QUERY;
   },
 
   /**
    * Determines whether or not a ResultNode is a day container.
    * @param   node
    *          A NavHistoryResultNode
    * @returns true if the node is a day container, false otherwise
    */
   nodeIsDay: function PU_nodeIsDay(aNode) {
-    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
-      throw new Error("Invalid Places node");
-    }
     var resultType;
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY &&
            aNode.parent &&
            ((resultType = asQuery(aNode.parent).queryOptions.resultType) ==
                Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_QUERY ||
              resultType == Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_SITE_QUERY);
   },
 
   /**
    * Determines whether or not a result-node is a tag container.
    * @param   aNode
    *          A result-node
    * @returns true if the node is a tag container, false otherwise
    */
   nodeIsTagQuery: function PU_nodeIsTagQuery(aNode) {
-    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
-      throw new Error("Invalid Places node");
-    }
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY &&
            asQuery(aNode).queryOptions.resultType ==
              Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS;
   },
 
   /**
    * Determines whether or not a ResultNode is a container.
    * @param   aNode
    *          A result node
    * @returns true if the node is a container item, false otherwise
    */
   containerTypes: [Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
                    Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT,
                    Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY],
   nodeIsContainer: function PU_nodeIsContainer(aNode) {
-    if (!(aNode instanceof Ci.nsINavHistoryResultNode)) {
-      throw new Error("Invalid Places node");
-    }
     return this.containerTypes.indexOf(aNode.type) != -1;
   },
 
   /**
    * Determines whether or not a ResultNode is an history related container.
    * @param   node
    *          A result node
    * @returns true if the node is an history related container, false otherwise
--- a/toolkit/components/places/nsPlacesAutoComplete.js
+++ b/toolkit/components/places/nsPlacesAutoComplete.js
@@ -1399,19 +1399,17 @@ urlInlineComplete.prototype = {
         let untrimmedHost = row.getResultByIndex(1);
         // If the untrimmed value doesn't preserve the user's input just
         // ignore it and complete to the found host.
         if (untrimmedHost &&
             !untrimmedHost.toLowerCase().contains(ac._originalSearchString.toLowerCase())) {
           untrimmedHost = null;
         }
 
-        // TODO (bug 754265): this is a temporary solution introduced while
-        // waiting for a propert dedicated API.
-        ac._result.appendMatch(ac._strippedPrefix + trimmedHost, untrimmedHost);
+        ac._result.appendMatch(ac._strippedPrefix + trimmedHost, "", "", "", untrimmedHost);
 
         // handleCompletion() will cause the result listener to be called, and
         // will display the result in the UI.
       },
 
       handleError: function (aError) {
         Components.utils.reportError(
           "URL Inline Complete: An async statement encountered an " +
@@ -1475,19 +1473,17 @@ urlInlineComplete.prototype = {
         // If the untrimmed value doesn't preserve the user's input just
         // ignore it and complete to the found url.
         let untrimmedURL = prefix + url;
         if (untrimmedURL &&
             !untrimmedURL.toLowerCase().contains(ac._originalSearchString.toLowerCase())) {
           untrimmedURL = null;
          }
 
-        // TODO (bug 754265): this is a temporary solution introduced while
-        // waiting for a propert dedicated API.
-        ac._result.appendMatch(ac._strippedPrefix + url, untrimmedURL);
+        ac._result.appendMatch(ac._strippedPrefix + url, "", "", "", untrimmedURL);
 
         // handleCompletion() will cause the result listener to be called, and
         // will display the result in the UI.
       },
 
       handleError: function(aError) {
         Components.utils.reportError(
           "URL Inline Complete: An async statement encountered an " +
--- a/toolkit/components/places/nsTaggingService.js
+++ b/toolkit/components/places/nsTaggingService.js
@@ -538,16 +538,23 @@ TagAutoCompleteResult.prototype = {
   /**
    * Get the image for the result at the given index
    */
   getImageAt: function PTACR_getImageAt(index) {
     return null;
   },
 
   /**
+   * Get the image for the result at the given index
+   */
+  getFinalCompleteValueAt: function PTACR_getFinalCompleteValueAt(index) {
+    return this.getValueAt(index);
+  },
+
+  /**
    * Remove the value at the given index from the autocomplete results.
    * If removeFromDb is set to true, the value should be removed from
    * persistent storage as well.
    */
   removeValueAt: function PTACR_removeValueAt(index, removeFromDb) {
     this._results.splice(index, 1);
     this._comments.splice(index, 1);
   },
deleted file mode 100644
--- a/toolkit/components/places/tests/unit/test_PlacesUtils_nodeIsXXX_invalidArg.js
+++ /dev/null
@@ -1,24 +0,0 @@
-
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-function run_test() {
- let nodeIsMethods = [
-  "nodeIsFolder",
-  "nodeIsBookmark",
-  "nodeIsSeparator",
-  "nodeIsURI",
-  "nodeIsQuery",
-  "nodeIsReadOnly",
-  "nodeIsHost",
-  "nodeIsDay",
-  "nodeIsTagQuery",
-  "nodeIsContainer",
-  "nodeIsHistoryContainer",
-  "nodeIsQuery"
- ];
- for (let methodName of nodeIsMethods) {
-  Assert.throws(() => PlacesUtils[methodName](true), /Invalid Places node/);
- }
-}
-
--- a/toolkit/components/places/tests/unit/xpcshell.ini
+++ b/toolkit/components/places/tests/unit/xpcshell.ini
@@ -112,17 +112,16 @@ fail-if = os == "android"
 skip-if = true
 [test_null_interfaces.js]
 [test_onItemChanged_tags.js]
 [test_pageGuid_bookmarkGuid.js]
 [test_frecency_observers.js]
 [test_placeURIs.js]
 [test_PlacesUtils_asyncGetBookmarkIds.js]
 [test_PlacesUtils_lazyobservers.js]
-[test_PlacesUtils_nodeIsXXX_invalidArg.js]
 [test_placesTxn.js]
 [test_preventive_maintenance.js]
 # Bug 676989: test hangs consistently on Android
 skip-if = os == "android"
 [test_preventive_maintenance_checkAndFixDatabase.js]
 # Bug 676989: test hangs consistently on Android
 skip-if = os == "android"
 [test_preventive_maintenance_runTasks.js]
--- a/toolkit/components/satchel/nsFormAutoComplete.js
+++ b/toolkit/components/satchel/nsFormAutoComplete.js
@@ -471,16 +471,20 @@ FormAutoCompleteResult.prototype = {
         return "";
     },
 
     getImageAt : function (index) {
         this._checkIndexBounds(index);
         return "";
     },
 
+    getFinalCompleteValueAt : function (index) {
+        return this.getValueAt(index);
+    },
+
     removeValueAt : function (index, removeFromDB) {
         this._checkIndexBounds(index);
 
         let [removedEntry] = this.entries.splice(index, 1);
 
         if (removeFromDB) {
           this.formHistory.update({ op: "remove",
                                     fieldname: this.fieldName,
--- a/toolkit/components/satchel/nsFormAutoCompleteResult.jsm
+++ b/toolkit/components/satchel/nsFormAutoCompleteResult.jsm
@@ -147,16 +147,25 @@ FormAutoCompleteResult.prototype = {
    * @return          the image url at the specified index
    */
   getImageAt: function(index) {
     this._checkIndexBounds(index);
     return "";
   },
 
   /**
+   * Retrieves a result
+   * @param  index    the index of the result requested
+   * @return          the result at the specified index
+   */
+  getFinalCompleteValueAt: function(index) {
+    return this.getValueAt(index);
+  },
+
+  /**
    * Removes a result from the resultset
    * @param  index    the index of the result to remove
    */
   removeValueAt: function(index, removeFromDatabase) {
     this._checkIndexBounds(index);
     // Forward the removeValueAt call to the underlying result if we have one
     // Note: this assumes that the form history results were added to the top
     // of our arrays.
--- a/toolkit/content/tests/chrome/test_autocomplete2.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete2.xul
@@ -39,16 +39,17 @@ nsAutoCompleteSimpleResult.prototype = {
  searchResult: ACR.RESULT_FAILURE,
  defaultIndex: -1,
  errorDescription: null,
  matchCount: 0,
  getValueAt: function() { return this._param; },
  getCommentAt: function() { return null; },
  getStyleAt: function() { return null; },
  getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
  getLabelAt: function() { return null; },
  removeValueAt: function() {}
 };
 
 // A basic autocomplete implementation that either returns one result or none
 var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
 var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple"
 var autoCompleteSimple = {
--- a/toolkit/content/tests/chrome/test_autocomplete3.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete3.xul
@@ -39,16 +39,17 @@ nsAutoCompleteSimpleResult.prototype = {
  searchResult: ACR.RESULT_FAILURE,
  defaultIndex: 0,
  errorDescription: null,
  matchCount: 0,
  getValueAt: function() { return this._param; },
  getCommentAt: function() { return null; },
  getStyleAt: function() { return null; },
  getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
  getLabelAt: function() { return null; },
  removeValueAt: function() {}
 };
 
 // A basic autocomplete implementation that either returns one result or none
 var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
 var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple"
 var autoCompleteSimple = {
--- a/toolkit/content/tests/chrome/test_autocomplete4.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete4.xul
@@ -41,16 +41,17 @@ nsAutoCompleteSimpleResult.prototype = {
  searchResult: ACR.RESULT_FAILURE,
  defaultIndex: 0,
  errorDescription: null,
  matchCount: 0,
  getValueAt: function() { return this._param; },
  getCommentAt: function() { return null; },
  getStyleAt: function() { return null; },
  getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
  getLabelAt: function() { return null; },
  removeValueAt: function() {}
 };
 
 // A basic autocomplete implementation that either returns one result or none
 var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
 var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple"
 var autoCompleteSimple = {
--- a/toolkit/content/tests/chrome/test_autocomplete5.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete5.xul
@@ -37,16 +37,17 @@ nsAutoCompleteSimpleResult.prototype = {
  searchResult: ACR.RESULT_FAILURE,
  defaultIndex: -1,
  errorDescription: null,
  matchCount: 0,
  getValueAt: function() { return this._param; },
  getCommentAt: function() { return null; },
  getStyleAt: function() { return null; },
  getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
  getLabelAt: function() { return null; },
  removeValueAt: function() {}
 };
 
 // A basic autocomplete implementation that either returns one result or none
 var autoCompleteSimpleID = Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
 var autoCompleteSimpleName = "@mozilla.org/autocomplete/search;1?name=simple"
 var autoCompleteSimple = {
--- a/toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul
@@ -37,16 +37,17 @@ autoCompleteSimpleResult.prototype = {
  searchResult: Components.interfaces.nsIAutoCompleteResult.RESULT_FAILURE,
  defaultIndex: 0,
  errorDescription: null,
  matchCount: 0,
  getValueAt: function() { return this._param; },
  getCommentAt: function() { return null; },
  getStyleAt: function() { return null; },
  getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function() { return this.getValueAt(); },
  getLabelAt: function() { return null; },
  removeValueAt: function() {}
 };
 
 // A basic autocomplete implementation that returns one result.
 let autoCompleteSimple = {
   classID: Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca"),
   contractID: "@mozilla.org/autocomplete/search;1?name=simple",
--- a/toolkit/content/tests/chrome/test_autocomplete_with_composition_on_textbox.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete_with_composition_on_textbox.xul
@@ -52,16 +52,17 @@ nsAutoCompleteSimpleResult.prototype = {
  searchResult: nsIAutoCompleteResult.RESULT_FAILURE,
  defaultIndex: 0,
  errorDescription: null,
  matchCount: 0,
  getValueAt: function(aIndex) { return aIndex == 0 ? this._value : null; },
  getCommentAt: function() { return null; },
  getStyleAt: function() { return null; },
  getImageAt: function() { return null; },
+ getFinalCompleteValueAt: function(aIndex) { return this.getValueAt(aIndex); },
  getLabelAt: function() { return null; },
  removeValueAt: function() {}
 };
 
 // A basic autocomplete implementation that either returns one result or none
 var autoCompleteSimpleID =
   Components.ID("0a2afbdb-f30e-47d1-9cb1-0cd160240aca");
 var autoCompleteSimpleName =
--- a/toolkit/content/widgets/videocontrols.css
+++ b/toolkit/content/widgets/videocontrols.css
@@ -29,16 +29,20 @@
   font: normal normal normal 100%/normal sans-serif !important;
   text-decoration: none !important;
 }
 
 .controlsSpacer[hideCursor] {
   cursor: none;
 }
 
+.controlsOverlay[scaled] {
+  -moz-box-align: center;
+}
+
 /* CSS Transitions
  *
  * These are overriden by the default theme; the rules here just 
  * provide a fallback to drive the required transitionend event
  * (in case a 3rd party theme does not provide transitions).
  */
 .controlBar:not([immediate]) {
   transition-property: opacity;
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -320,16 +320,17 @@
                 scrubberThumb  : null,
                 scrubber       : null,
                 progressBar    : null,
                 bufferBar      : null,
                 statusOverlay  : null,
                 controlsSpacer : null,
                 clickToPlay    : null,
                 stats          : {},
+                controlsOverlay : null,
                 fullscreenButton : null,
 
                 randomID : 0,
                 videoEvents : ["play", "pause", "ended", "volumechange", "loadeddata",
                                "loadstart", "timeupdate", "progress",
                                "playing", "waiting", "canplay", "canplaythrough",
                                "seeking", "seeked", "emptied", "loadedmetadata",
                                "error", "suspend", "stalled",
@@ -1385,20 +1386,46 @@
                     }
 
                     let minHeightForControlBar = this._controlBarHeight;
                     let minWidthOnlyPlayPause = this._playButtonWidth + this._muteButtonWidth;
 
                     let videoHeight = isAudioOnly ? minHeightForControlBar : this.video.clientHeight;
                     let videoWidth = isAudioOnly ? minWidthAllControls : this.video.clientWidth;
 
-                    if ((this._overlayPlayButtonHeight + this._controlBarHeight) > videoHeight || this._overlayPlayButtonWidth > videoWidth)
+                    // Adapt the size of the controls to the size of the video
+                    if (this.video.readyState >= this.video.HAVE_METADATA) {
+                      if (!this.isAudioOnly && this.video.videoWidth && this.video.videoHeight) {
+                        var rect = this.video.getBoundingClientRect();
+                        var widthRatio = rect.width / this.video.videoWidth;
+                        var heightRatio = rect.height / this.video.videoHeight;
+                        var width = this.video.videoWidth * Math.min(widthRatio, heightRatio);
+
+                        this.controlsOverlay.setAttribute("scaled", true);
+                        this.controlsOverlay.style.width = width + "px";
+                        this.controlsSpacer.style.width = width + "px";
+                        this.controlBar.style.width = width + "px";
+                      } else {
+                        this.controlsOverlay.removeAttribute("scaled");
+                        this.controlsOverlay.style.width = "";
+                        this.controlsSpacer.style.width = "";
+                        this.controlBar.style.width = "";
+                      }
+                    }
+
+                    if ((this._overlayPlayButtonHeight + this._controlBarHeight) > videoHeight ||
+                        this._overlayPlayButtonWidth > videoWidth) {
                         this.clickToPlay.hidden = true;
-                    else if (this.clickToPlay.hidden && !this.video.played.length)
+                    } else if (this.clickToPlay.hidden &&
+                               !this.video.played.length &&
+                               this.video.paused) {
+                        // Check this.video.paused to handle when a video is
+                        // playing but hasn't processed any frames yet
                         this.clickToPlay.hidden = false;
+                    }
 
                     let size = "normal";
                     if (videoHeight < minHeightForControlBar)
                         size = "hidden";
                     else if (videoWidth < minWidthOnlyPlayPause)
                         size = "hidden";
                     else if (videoWidth < minWidthAllControls)
                         size = "small";
@@ -1417,16 +1444,17 @@
                     this.progressBar   = document.getAnonymousElementByAttribute(binding, "class", "progressBar");
                     this.bufferBar     = document.getAnonymousElementByAttribute(binding, "class", "bufferBar");
                     this.scrubber      = document.getAnonymousElementByAttribute(binding, "class", "scrubber");
                     this.scrubberThumb = document.getAnonymousElementByAttribute(this.scrubber, "class", "scale-thumb");
                     this.durationLabel = document.getAnonymousElementByAttribute(binding, "class", "durationLabel");
                     this.positionLabel = document.getAnonymousElementByAttribute(binding, "class", "positionLabel");
                     this.statusOverlay = document.getAnonymousElementByAttribute(binding, "class", "statusOverlay");
                     this.statsOverlay  = document.getAnonymousElementByAttribute(binding, "class", "statsOverlay");
+                    this.controlsOverlay = document.getAnonymousElementByAttribute(binding, "class", "controlsOverlay");
                     this.controlsSpacer     = document.getAnonymousElementByAttribute(binding, "class", "controlsSpacer");
                     this.clickToPlay        = document.getAnonymousElementByAttribute(binding, "class", "clickToPlay");
                     this.fullscreenButton   = document.getAnonymousElementByAttribute(binding, "class", "fullscreenButton");
                     this.volumeForeground   = document.getAnonymousElementByAttribute(binding, "anonid", "volumeForeground");
 
                     this.statsTable       = document.getAnonymousElementByAttribute(binding, "class", "statsTable");
                     this.stats.filename   = document.getAnonymousElementByAttribute(binding, "class", "statFilename");
                     this.stats.size       = document.getAnonymousElementByAttribute(binding, "class", "statSize");
--- a/toolkit/devtools/server/actors/webbrowser.js
+++ b/toolkit/devtools/server/actors/webbrowser.js
@@ -937,19 +937,25 @@ TabActor.prototype = {
    * the page.
    *
    * @param nsIDOMWindow aWindow
    *        The window object you want to check.
    * @return boolean
    *         True if the window.console object is native, or false otherwise.
    */
   hasNativeConsoleAPI: function BTA_hasNativeConsoleAPI(aWindow) {
-    // Do not expose WebConsoleActor function directly as it is always
-    // loaded after the BrowserTabActor
-    return WebConsoleActor.prototype.hasNativeConsoleAPI(aWindow);
+    let isNative = false;
+    try {
+      // We are very explicitly examining the "console" property of
+      // the non-Xrayed object here.
+      let console = aWindow.wrappedJSObject.console;
+      isNative = console instanceof aWindow.Console;
+    }
+    catch (ex) { }
+    return isNative;
   }
 };
 
 /**
  * The request types this actor can handle.
  */
 TabActor.prototype.requestTypes = {
   "attach": TabActor.prototype.onAttach,
--- a/toolkit/devtools/server/actors/webconsole.js
+++ b/toolkit/devtools/server/actors/webconsole.js
@@ -1,48 +1,54 @@
 /* -*- js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-let Cc = Components.classes;
-let Ci = Components.interfaces;
-let Cu = Components.utils;
+let {Cc, Ci, Cu} = require("chrome");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
+let { DebuggerServer, ActorPool } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
+// Symbols from script.js
+let { ThreadActor, EnvironmentActor, ObjectActor, LongStringActor } = DebuggerServer;
+
+Cu.import("resource://gre/modules/jsdebugger.jsm");
+addDebuggerToGlobal(this);
 
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyGetter(this, "NetworkMonitor", () => {
-  return devtools.require("devtools/toolkit/webconsole/network-monitor")
+  return require("devtools/toolkit/webconsole/network-monitor")
          .NetworkMonitor;
 });
 XPCOMUtils.defineLazyGetter(this, "NetworkMonitorChild", () => {
-  return devtools.require("devtools/toolkit/webconsole/network-monitor")
+  return require("devtools/toolkit/webconsole/network-monitor")
          .NetworkMonitorChild;
 });
 XPCOMUtils.defineLazyGetter(this, "ConsoleProgressListener", () => {
-  return devtools.require("devtools/toolkit/webconsole/network-monitor")
+  return require("devtools/toolkit/webconsole/network-monitor")
          .ConsoleProgressListener;
 });
+XPCOMUtils.defineLazyGetter(this, "events", () => {
+  return require("sdk/event/core");
+});
 
 for (let name of ["WebConsoleUtils", "ConsoleServiceListener",
                   "ConsoleAPIListener", "JSTermHelpers", "JSPropertyProvider",
                   "ConsoleReflowListener"]) {
   Object.defineProperty(this, name, {
     get: function(prop) {
       if (prop == "WebConsoleUtils") {
         prop = "Utils";
       }
-      return devtools.require("devtools/toolkit/webconsole/utils")[prop];
+      return require("devtools/toolkit/webconsole/utils")[prop];
     }.bind(null, name),
     configurable: true,
     enumerable: true
   });
 }
 
 
 /**
@@ -1823,11 +1829,17 @@ NetworkEventActor.prototype.requestTypes
   "getRequestCookies": NetworkEventActor.prototype.onGetRequestCookies,
   "getRequestPostData": NetworkEventActor.prototype.onGetRequestPostData,
   "getResponseHeaders": NetworkEventActor.prototype.onGetResponseHeaders,
   "getResponseCookies": NetworkEventActor.prototype.onGetResponseCookies,
   "getResponseContent": NetworkEventActor.prototype.onGetResponseContent,
   "getEventTimings": NetworkEventActor.prototype.onGetEventTimings,
 };
 
-DebuggerServer.addTabActor(WebConsoleActor, "consoleActor");
-DebuggerServer.addGlobalActor(WebConsoleActor, "consoleActor");
+exports.register = function(handle) {
+  handle.addGlobalActor(WebConsoleActor, "consoleActor");
+  handle.addTabActor(WebConsoleActor, "consoleActor");
+};
 
+exports.unregister = function(handle) {
+  handle.removeGlobalActor(WebConsoleActor, "consoleActor");
+  handle.removeTabActor(WebConsoleActor, "consoleActor");
+};
--- a/toolkit/devtools/server/main.js
+++ b/toolkit/devtools/server/main.js
@@ -355,34 +355,34 @@ var DebuggerServer = {
 
   /**
    * Install tab actors in documents loaded in content childs
    */
   addChildActors: function () {
     // In case of apps being loaded in parent process, DebuggerServer is already
     // initialized and browser actors are already loaded,
     // but childtab.js hasn't been loaded yet.
-    if (!("WebConsoleActor" in this)) {
+    if (!DebuggerServer.tabActorFactories.hasOwnProperty("consoleActor")) {
       this.addTabActors();
     }
     // But webbrowser.js and childtab.js aren't loaded from shell.js.
     if (!("BrowserTabActor" in this)) {
       this.addActors("resource://gre/modules/devtools/server/actors/webbrowser.js");
     }
     if (!("ContentActor" in this)) {
       this.addActors("resource://gre/modules/devtools/server/actors/childtab.js");
     }
   },
 
   /**
    * Install tab actors.
    */
   addTabActors: function() {
     this.addActors("resource://gre/modules/devtools/server/actors/script.js");
-    this.addActors("resource://gre/modules/devtools/server/actors/webconsole.js");
+    this.registerModule("devtools/server/actors/webconsole");
     this.registerModule("devtools/server/actors/inspector");
     this.registerModule("devtools/server/actors/call-watcher");
     this.registerModule("devtools/server/actors/canvas");
     this.registerModule("devtools/server/actors/webgl");
     this.registerModule("devtools/server/actors/webaudio");
     this.registerModule("devtools/server/actors/stylesheets");
     this.registerModule("devtools/server/actors/styleeditor");
     this.registerModule("devtools/server/actors/storage");