Merge mozilla-central to mozilla-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 29 Dec 2014 16:17:28 +0100
changeset 221483 8530f5b7443b0c801a8c145ca2a88975bdd20ffb
parent 221456 09606692e15489a6d18a4f11404e9d99cf2a0afa (current diff)
parent 221482 a4a5d4fb5e2e379149a1a13e97502a226adefe1c (diff)
child 221484 47185628a395f5351d9422d3d63d78e5bf44ed76
push id53352
push usercbook@mozilla.com
push dateMon, 29 Dec 2014 15:17:49 +0000
treeherdermozilla-inbound@8530f5b7443b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone37.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 mozilla-central to mozilla-inbound
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/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="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="bdedbaf9f18a43c091ede770407d68d38582fe29"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ea413f7cdec44db0e241c0820e0aca2daeac436c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <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="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
--- 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="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="bdedbaf9f18a43c091ede770407d68d38582fe29"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea413f7cdec44db0e241c0820e0aca2daeac436c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <!-- 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="0e94c080bee081a50aa2097527b0b40852f9143f">
     <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="bdedbaf9f18a43c091ede770407d68d38582fe29"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ea413f7cdec44db0e241c0820e0aca2daeac436c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <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"/>
--- 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="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="bdedbaf9f18a43c091ede770407d68d38582fe29"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ea413f7cdec44db0e241c0820e0aca2daeac436c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <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="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
--- 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="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="bdedbaf9f18a43c091ede770407d68d38582fe29"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea413f7cdec44db0e241c0820e0aca2daeac436c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-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="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="bdedbaf9f18a43c091ede770407d68d38582fe29"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ea413f7cdec44db0e241c0820e0aca2daeac436c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <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="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/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="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="bdedbaf9f18a43c091ede770407d68d38582fe29"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ea413f7cdec44db0e241c0820e0aca2daeac436c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <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": "f434a7b8fede62f8849f68e71f52b8f1de912aae", 
+    "revision": "9741ec155a3fd7bf8c90ec32e20e9d1b7aa7fcb0", 
     "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="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="bdedbaf9f18a43c091ede770407d68d38582fe29"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea413f7cdec44db0e241c0820e0aca2daeac436c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
--- 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="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="bdedbaf9f18a43c091ede770407d68d38582fe29"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea413f7cdec44db0e241c0820e0aca2daeac436c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <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/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/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="0e94c080bee081a50aa2097527b0b40852f9143f">
     <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="bdedbaf9f18a43c091ede770407d68d38582fe29"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ea413f7cdec44db0e241c0820e0aca2daeac436c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <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"/>
--- 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="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="bdedbaf9f18a43c091ede770407d68d38582fe29"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea413f7cdec44db0e241c0820e0aca2daeac436c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f11d3c6500659e3232fbe6fe7ea0204c40ab7fdd"/>
   <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/devtools/webaudioeditor/test/browser.ini
+++ b/browser/devtools/webaudioeditor/test/browser.ini
@@ -5,31 +5,36 @@ support-files =
   doc_complex-context.html
   doc_simple-node-creation.html
   doc_buffer-and-array.html
   doc_media-node-creation.html
   doc_destroy-nodes.html
   doc_connect-param.html
   doc_connect-multi-param.html
   doc_iframe-context.html
+  doc_automation.html
   440hz_sine.ogg
   head.js
 
 [browser_audionode-actor-get-param-flags.js]
 [browser_audionode-actor-get-params-01.js]
 [browser_audionode-actor-get-params-02.js]
 [browser_audionode-actor-get-set-param.js]
 [browser_audionode-actor-get-type.js]
 [browser_audionode-actor-is-source.js]
 [browser_audionode-actor-bypass.js]
 [browser_audionode-actor-connectnode-disconnect.js]
 [browser_audionode-actor-connectparam.js]
+[browser_audionode-actor-add-automation-event.js]
+[browser_audionode-actor-get-automation-data-01.js]
+[browser_audionode-actor-get-automation-data-02.js]
 [browser_webaudio-actor-simple.js]
 [browser_webaudio-actor-destroy-node.js]
 [browser_webaudio-actor-connect-param.js]
+[browser_webaudio-actor-automation-event.js]
 
 [browser_wa_destroy-node-01.js]
 
 [browser_wa_first-run.js]
 [browser_wa_reset-01.js]
 [browser_wa_reset-02.js]
 [browser_wa_reset-03.js]
 [browser_wa_reset-04.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webaudioeditor/test/browser_audionode-actor-add-automation-event.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test AudioNode#addAutomationEvent();
+ */
+
+add_task(function*() {
+  let { target, front } = yield initBackend(SIMPLE_CONTEXT_URL);
+  let [_, [destNode, oscNode, gainNode]] = yield Promise.all([
+    front.setup({ reload: true }),
+    get3(front, "create-node")
+  ]);
+  let count = 0;
+  let counter = () => count++;
+  front.on("automation-event", counter);
+
+  let t0 = 0, t1 = 0.1, t2 = 0.2, t3 = 0.3, t4 = 0.4, t5 = 0.6, t6 = 0.7, t7 = 1;
+  let curve = [-1, 0, 1];
+  yield oscNode.addAutomationEvent("frequency", "setValueAtTime", [0.2, t0]);
+  yield oscNode.addAutomationEvent("frequency", "setValueAtTime", [0.3, t1]);
+  yield oscNode.addAutomationEvent("frequency", "setValueAtTime", [0.4, t2]);
+  yield oscNode.addAutomationEvent("frequency", "linearRampToValueAtTime", [1, t3]);
+  yield oscNode.addAutomationEvent("frequency", "linearRampToValueAtTime", [0.15, t4]);
+  yield oscNode.addAutomationEvent("frequency", "exponentialRampToValueAtTime", [0.75, t5]);
+  yield oscNode.addAutomationEvent("frequency", "exponentialRampToValueAtTime", [0.5, t6]);
+  yield oscNode.addAutomationEvent("frequency", "setValueCurveAtTime", [curve, t7, t7 - t6]);
+  yield oscNode.addAutomationEvent("frequency", "setTargetAtTime", [20, 2, 5]);
+
+  ok(true, "successfully set automation events for valid automation events");
+
+  try {
+    yield oscNode.addAutomationEvent("frequency", "notAMethod", 20, 2, 5);
+    ok(false, "non-automation methods should not be successful");
+  } catch (e) {
+    ok(/invalid/.test(e.message), "AudioNode:addAutomationEvent fails for invalid automation methods");
+  }
+
+  try {
+    yield oscNode.addAutomationEvent("invalidparam", "setValueAtTime", 0.2, t0);
+    ok(false, "automating non-AudioParams should not be successful");
+  } catch (e) {
+    ok(/invalid/.test(e.message), "AudioNode:addAutomationEvent fails for a non AudioParam");
+  }
+
+  front.off("automation-event", counter);
+
+  is(count, 9,
+    "when calling `addAutomationEvent`, the WebAudioActor should still fire `automation-event`.");
+
+  yield removeTab(target.tab);
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webaudioeditor/test/browser_audionode-actor-get-automation-data-01.js
@@ -0,0 +1,53 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test AudioNode#addAutomationEvent() checking automation values, also using
+ * a curve as the last event to check duration spread.
+ */
+
+add_task(function*() {
+  let { target, front } = yield initBackend(SIMPLE_CONTEXT_URL);
+  let [_, [destNode, oscNode, gainNode]] = yield Promise.all([
+    front.setup({ reload: true }),
+    get3(front, "create-node")
+  ]);
+
+  let t0 = 0, t1 = 0.1, t2 = 0.2, t3 = 0.3, t4 = 0.4, t5 = 0.6, t6 = 0.7, t7 = 1;
+  let curve = [-1, 0, 1];
+  yield oscNode.addAutomationEvent("frequency", "setValueAtTime", [0.2, t0]);
+  yield oscNode.addAutomationEvent("frequency", "setValueAtTime", [0.3, t1]);
+  yield oscNode.addAutomationEvent("frequency", "setValueAtTime", [0.4, t2]);
+  yield oscNode.addAutomationEvent("frequency", "linearRampToValueAtTime", [1, t3]);
+  yield oscNode.addAutomationEvent("frequency", "linearRampToValueAtTime", [0.15, t4]);
+  yield oscNode.addAutomationEvent("frequency", "exponentialRampToValueAtTime", [0.75, t5]);
+  yield oscNode.addAutomationEvent("frequency", "exponentialRampToValueAtTime", [0.05, t6]);
+  // End with a curve here so we can get proper results on the last event (which takes into account
+  // duration)
+  yield oscNode.addAutomationEvent("frequency", "setValueCurveAtTime", [curve, t6, t7 - t6]);
+
+  let { events, values } = yield oscNode.getAutomationData("frequency");
+
+  is(events.length, 8, "8 recorded events returned.");
+  is(values.length, 2000, "2000 value points returned.");
+
+  checkAutomationValue(values, 0.05, 0.2);
+  checkAutomationValue(values, 0.1, 0.3);
+  checkAutomationValue(values, 0.15, 0.3);
+  checkAutomationValue(values, 0.2, 0.4);
+  checkAutomationValue(values, 0.25, 0.7);
+  checkAutomationValue(values, 0.3, 1);
+  checkAutomationValue(values, 0.35, 0.575);
+  checkAutomationValue(values, 0.4, 0.15);
+  checkAutomationValue(values, 0.45, 0.15 * Math.pow(0.75/0.15,0.05/0.2));
+  checkAutomationValue(values, 0.5, 0.15 * Math.pow(0.75/0.15,0.5));
+  checkAutomationValue(values, 0.55, 0.15 * Math.pow(0.75/0.15,0.15/0.2));
+  checkAutomationValue(values, 0.6, 0.75);
+  checkAutomationValue(values, 0.65, 0.75 * Math.pow(0.05/0.75, 0.5));
+  checkAutomationValue(values, 0.705, -1); // Increase this time a bit to prevent off by the previous exponential amount
+  checkAutomationValue(values, 0.8, 0);
+  checkAutomationValue(values, 0.9, 1);
+  checkAutomationValue(values, 1, 1);
+
+  yield removeTab(target.tab);
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webaudioeditor/test/browser_audionode-actor-get-automation-data-02.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test AudioNode#addAutomationEvent() when automation series ends with
+ * `setTargetAtTime`, which approaches its target to infinity.
+ */
+
+add_task(function*() {
+  let { target, front } = yield initBackend(SIMPLE_CONTEXT_URL);
+  let [_, [destNode, oscNode, gainNode]] = yield Promise.all([
+    front.setup({ reload: true }),
+    get3(front, "create-node")
+  ]);
+
+  let t0 = 0, t1 = 0.1, t2 = 0.2, t3 = 0.3, t4 = 0.4, t5 = 0.6, t6 = 0.7, t7 = 1;
+  yield oscNode.addAutomationEvent("frequency", "setValueAtTime", [0.2, t0]);
+  yield oscNode.addAutomationEvent("frequency", "setValueAtTime", [0.3, t1]);
+  yield oscNode.addAutomationEvent("frequency", "setValueAtTime", [0.4, t2]);
+  yield oscNode.addAutomationEvent("frequency", "linearRampToValueAtTime", [1, t3]);
+  yield oscNode.addAutomationEvent("frequency", "linearRampToValueAtTime", [0.15, t4]);
+  yield oscNode.addAutomationEvent("frequency", "exponentialRampToValueAtTime", [0.75, t5]);
+  yield oscNode.addAutomationEvent("frequency", "exponentialRampToValueAtTime", [0.05, t6]);
+  // End with a setTargetAtTime event, as the target approaches infinity, which will
+  // give us more points to render than the default 2000
+  yield oscNode.addAutomationEvent("frequency", "setTargetAtTime", [1, t7, 0.5]);
+
+  let { events, values } = yield oscNode.getAutomationData("frequency");
+
+  is(events.length, 8, "8 recorded events returned.");
+  is(values.length, 4000, "6000 value points returned when ending with exponentiall approaching automator.");
+
+  checkAutomationValue(values, 1, 0.05);
+  checkAutomationValue(values, 2, 0.87);
+  checkAutomationValue(values, 3, 0.98);
+
+  yield removeTab(target.tab);
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webaudioeditor/test/browser_webaudio-actor-automation-event.js
@@ -0,0 +1,51 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test that the WebAudioActor receives and emits the `automation-event` events
+ * with correct arguments from the content.
+ */
+
+add_task(function*() {
+  let { target, front } = yield initBackend(AUTOMATION_URL);
+  let events = [];
+
+  let expected = [
+    ["setValueAtTime", 0.2, 0],
+    ["linearRampToValueAtTime", 1, 0.3],
+    ["exponentialRampToValueAtTime", 0.75, 0.6],
+    ["setValueCurveAtTime", [-1, 0 ,1], 0.7, 0.3],
+  ];
+
+  front.on("automation-event", onAutomationEvent);
+
+  let [_, __, [destNode, oscNode, gainNode], [connect1, connect2]] = yield Promise.all([
+    front.setup({ reload: true }),
+    once(front, "start-context"),
+    get3(front, "create-node"),
+    get2(front, "connect-node")
+  ]);
+
+  is(events.length, 4, "correct number of events fired");
+
+  function onAutomationEvent (e) {
+    let { eventName, paramName, args } = e;
+    let exp = expected[events.length];
+
+    is(eventName, exp[0], "correct eventName in event");
+    is(paramName, "frequency", "correct paramName in event");
+    is(args.length, exp.length - 1, "correct length in args");
+    args.forEach((a, i) => {
+      // In the case of an array
+      if (typeof a === "object") {
+        a.forEach((f, j) => is(f, exp[i + 1][j], "correct argument in args"));
+      } else {
+        is(a, exp[i + 1], "correct argument in args");
+      }
+    });
+    events.push([eventName].concat(args));
+  }
+
+  front.off("automation-event", onAutomationEvent);
+  yield removeTab(target.tab);
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webaudioeditor/test/doc_automation.html
@@ -0,0 +1,30 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>Web Audio Editor test page</title>
+  </head>
+
+  <body>
+
+    <script type="text/javascript;version=1.8">
+      "use strict";
+
+      let ctx = new AudioContext();
+      let osc = ctx.createOscillator();
+      let gain = ctx.createGain();
+      gain.gain.value = 0;
+      osc.frequency.setValueAtTime(0.2, 0);
+      osc.frequency.linearRampToValueAtTime(1, 0.3);
+      osc.frequency.exponentialRampToValueAtTime(0.75, 0.6);
+      osc.frequency.setValueCurveAtTime(new Float32Array([-1, 0, 1]), 0.7, 0.3);
+      osc.connect(gain);
+      gain.connect(ctx.destination);
+      osc.start(0);
+    </script>
+  </body>
+
+</html>
--- a/browser/devtools/webaudioeditor/test/head.js
+++ b/browser/devtools/webaudioeditor/test/head.js
@@ -4,17 +4,17 @@
 
 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
 
 // Enable logging for all the tests. Both the debugger server and frontend will
 // be affected by this pref.
 let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
-Services.prefs.setBoolPref("devtools.debugger.log", true);
+Services.prefs.setBoolPref("devtools.debugger.log", false);
 
 let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
 let { Promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
 
 let { WebAudioFront } = devtools.require("devtools/server/actors/webaudio");
@@ -25,16 +25,17 @@ const SIMPLE_CONTEXT_URL = EXAMPLE_URL +
 const COMPLEX_CONTEXT_URL = EXAMPLE_URL + "doc_complex-context.html";
 const SIMPLE_NODES_URL = EXAMPLE_URL + "doc_simple-node-creation.html";
 const MEDIA_NODES_URL = EXAMPLE_URL + "doc_media-node-creation.html";
 const BUFFER_AND_ARRAY_URL = EXAMPLE_URL + "doc_buffer-and-array.html";
 const DESTROY_NODES_URL = EXAMPLE_URL + "doc_destroy-nodes.html";
 const CONNECT_PARAM_URL = EXAMPLE_URL + "doc_connect-param.html";
 const CONNECT_MULTI_PARAM_URL = EXAMPLE_URL + "doc_connect-multi-param.html";
 const IFRAME_CONTEXT_URL = EXAMPLE_URL + "doc_iframe-context.html";
+const AUTOMATION_URL = EXAMPLE_URL + "doc_automation.html";
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 let gToolEnabled = Services.prefs.getBoolPref("devtools.webaudioeditor.enabled");
 
 gDevTools.testing = true;
 
@@ -389,16 +390,46 @@ function countGraphObjects (win) {
 */
 function forceCC () {
   SpecialPowers.DOMWindowUtils.cycleCollect();
   SpecialPowers.DOMWindowUtils.garbageCollect();
   SpecialPowers.DOMWindowUtils.garbageCollect();
 }
 
 /**
+ * Takes a `values` array of automation value entries,
+ * looking for the value at `time` seconds, checking
+ * to see if the value is close to `expected`.
+ */
+function checkAutomationValue (values, time, expected) {
+  // Remain flexible on values as we can approximate points
+  let EPSILON = 0.01;
+
+  let value = getValueAt(values, time);
+  ok(Math.abs(value - expected) < EPSILON, "Timeline value at " + time + " with value " + value + " should have value very close to " + expected);
+
+  /**
+   * Entries are ordered in `values` according to time, so if we can't find an exact point
+   * on a time of interest, return the point in between the threshold. This should
+   * get us a very close value.
+   */
+  function getValueAt (values, time) {
+    for (let i = 0; i < values.length; i++) {
+      if (values[i].t === time) {
+        return values[i].value;
+      }
+      if (values[i].t > time) {
+        return (values[i - 1].value + values[i].value) / 2;
+      }
+    }
+    return values[values.length - 1].value;
+  }
+}
+
+/**
  * List of audio node properties to test against expectations of the AudioNode actor
  */
 
 const NODE_DEFAULT_VALUES = {
   "AudioDestinationNode": {},
   "MediaElementAudioSourceNode": {},
   "MediaStreamAudioSourceNode": {},
   "MediaStreamAudioDestinationNode": {
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -549,26 +549,28 @@ menuitem:not([type]):not(.menuitem-toolt
   list-style-image: url("moz-icon://stock/gtk-about?size=menu");
 }
 
 #javascriptConsole {
   list-style-image: url("chrome://global/skin/console/console.png");
 }
 
 /* Primary toolbar buttons */
+.findbar-button,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 {
   -moz-appearance: none;
 }
 
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open="true"],
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:hover:active {
   padding: 3px;
 }
 
+.findbar-button > .toolbarbutton-text,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-badge-container > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-icon {
   -moz-margin-end: 0;
   padding: 2px 6px;
   border: 1px solid transparent;
   border-radius: 2px;
@@ -597,16 +599,17 @@ toolbarbutton[sdk-button="true"][cui-are
   width: 32px;
 }
 
 #nav-bar #PanelUI-menu-button {
   -moz-padding-start: 7px;
   -moz-padding-end: 5px;
 }
 
+.findbar-button:not(:-moz-any([checked="true"],[disabled="true"])):hover > .toolbarbutton-text,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open]:not([disabled=true]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):not([open]):hover > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):not([open]):hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-badge-container > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-icon {
   background: var(--toolbarbutton-hover-background);
   border-width: 1px;
   border-style: solid;
@@ -615,16 +618,17 @@ toolbarbutton[sdk-button="true"][cui-are
 }
 
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
   margin-top: 4px;
   margin-bottom: 4px;
 }
 
+.findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active) > .toolbarbutton-text,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open="true"]) > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon {
   background: var(--toolbarbutton-active-background);
   box-shadow: var(--toolbarbutton-active-boxshadow);
   border-width: 1px;
   border-style: solid;
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -573,55 +573,65 @@ toolbar .toolbarbutton-1:not([type="menu
 .toolbarbutton-1 > .toolbarbutton-menubutton-button,
 .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   -moz-box-orient: vertical;
   height: 24px;
   padding: 0;
   border: 0;
 }
 
+.findbar-button,
 toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],#back-button,#forward-button)),
 toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button,
 toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   border: 1px solid transparent;
   border-radius: @toolbarbuttonCornerRadius@;
   transition-property: background, border-color;
   transition-duration: 250ms;
 }
 
+.findbar-button {
+  background: none;
+  box-shadow: none;
+}
+
 toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],#back-button,#forward-button)) {
   padding: 0 4px;
 }
 
+.findbar-button:not(:-moz-any([checked="true"],[disabled="true"])):hover,
 toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],[disabled],[open],#back-button,#forward-button)):hover,
 toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]) > .toolbarbutton-menubutton-button[open] + .toolbarbutton-menubutton-dropmarker,
 toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button,
 toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker,
 toolbar .toolbaritem-combined-buttons:hover > .toolbarbutton-combined {
   border-color: var(--toolbarbutton-hover-bordercolor);
   box-shadow: var(--toolbarbutton-hover-boxshadow);
 }
 
+.findbar-button:not(:-moz-any([checked="true"],[disabled="true"])):hover,
 toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],[disabled],[open],#back-button,#forward-button)):hover,
 toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open]))[buttonover] > .toolbarbutton-menubutton-button,
 toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open],[buttonover])):hover > .toolbarbutton-menubutton-dropmarker {
   background: var(--toolbarbutton-hover-background);
 }
 
+.findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active),
 toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],[disabled],#back-button,#forward-button)):-moz-any(:hover:active,[open],[checked]),
 toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]) > .toolbarbutton-menubutton-button[open],
 toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open]))[buttonover]:active > .toolbarbutton-menubutton-button,
 toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open],[buttonover])):hover:active > .toolbarbutton-menubutton-dropmarker,
 toolbar .toolbarbutton-1[type="menu-button"][open]:not([disabled]) > .toolbarbutton-menubutton-dropmarker {
   background: var(--toolbarbutton-active-background);
   border-color: var(--toolbarbutton-active-bordercolor);
   box-shadow: var(--toolbarbutton-active-boxshadow);
   transition-duration: 10ms;
 }
 
+.findbar-button[checked="true"]:not(:active):hover,
 toolbar .toolbarbutton-1[checked]:not(:active):hover {
   background-color: var(--toolbarbutton-checkedhover-backgroundcolor);
   transition: background-color 250ms;
 }
 
 .toolbarbutton-1[type="menu-button"]:not([overflowedItem=true]) {
   padding: 0;
 }
--- a/browser/themes/shared/devedition.inc.css
+++ b/browser/themes/shared/devedition.inc.css
@@ -170,22 +170,24 @@
   color: var(--chrome-color);
 }
 
 #navigator-toolbox::after {
   background: var(--chrome-navigator-toolbox-separator-color);
 }
 
 #navigator-toolbox > toolbar:not(#TabsToolbar):not(#toolbar-menubar),
+.browserContainer > findbar,
 #browser-bottombox {
   background: var(--chrome-secondary-background-color) !important;
   color: var(--chrome-color);
 }
 
 #navigator-toolbox .toolbarbutton-1,
+.browserContainer > findbar .findbar-button,
 #PlacesToolbar toolbarbutton.bookmark-item {
   color: var(--chrome-color);
   text-shadow: var(--toolbarbutton-text-shadow);
 }
 
 /* Using toolbar[brighttext] instead of important to override linux */
 toolbar[brighttext] #downloads-indicator-counter {
   text-shadow: var(--toolbarbutton-text-shadow);
@@ -193,18 +195,20 @@ toolbar[brighttext] #downloads-indicator
 }
 
 #TabsToolbar {
   text-shadow: none !important;
   color: var(--chrome-color) !important; /* Make sure that the brighttext attribute is added */
 }
 
 /* URL bar and search bar*/
+/* XXX :root[devtoolstheme="dark"] is a workaround for bug 1096413 on the findbar. */
 #urlbar,
-#navigator-toolbox .searchbar-textbox {
+#navigator-toolbox .searchbar-textbox,
+:root[devtoolstheme="dark"] .browserContainer > findbar .findbar-textbox {
   background-color: var(--url-and-searchbar-background-color) !important;
   background-image: none !important;
   color: var(--url-and-searchbar-color);
   border: none !important;
   box-shadow: none !important;
 }
 
 window:not([chromehidden~="toolbar"]) #urlbar-wrapper {
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -620,16 +620,17 @@ toolbar[brighttext] .toolbarbutton-1 > .
   list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow-inverted.png");
 }
 
 .toolbarbutton-1 > .toolbarbutton-icon,
 .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
   -moz-margin-end: 0;
 }
 
+.findbar-button,
 #nav-bar .toolbarbutton-1,
 #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   -moz-appearance: none;
   border: none;
   padding: 0;
   background: none;
 }
 
@@ -662,16 +663,17 @@ toolbar[brighttext] .toolbarbutton-1 > .
   -moz-padding-end: 0;
 }
 
 #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   -moz-padding-start: 0;
   -moz-box-align: center;
 }
 
+.findbar-button > .toolbarbutton-text,
 #nav-bar .toolbarbutton-1 > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1 > .toolbarbutton-text,
 #nav-bar .toolbarbutton-1 > .toolbarbutton-badge-container,
 #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 @conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon {
   padding: 2px 6px;
   border: 1px solid;
@@ -700,17 +702,17 @@ toolbar[brighttext] .toolbarbutton-1 > .
                                       0 1px 0 hsla(210,54%,20%,0),
                                       0 0 2px hsla(210,54%,20%,0);
 
     --toolbarbutton-checkedhover-backgroundcolor: rgba(90%,90%,90%,.4);
 
     --toolbarbutton-combined-backgroundimage: linear-gradient(hsla(210,54%,20%,.2) 0, hsla(210,54%,20%,.2) 18px);
     --toolbarbutton-combined-boxshadow: 0 0 0 1px hsla(0,0%,100%,.2);
   }
-
+  .findbar-button > .toolbarbutton-text,
   #nav-bar .toolbarbutton-1 > .toolbarbutton-icon,
   #nav-bar .toolbarbutton-1 > .toolbarbutton-text,
   #nav-bar .toolbarbutton-1 > .toolbarbutton-badge-container,
   #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
   #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
     background-color: hsla(210,32%,93%,0);
     background-origin: padding-box;
     border-radius: 2px;
@@ -782,16 +784,17 @@ toolbarbutton[sdk-button="true"][cui-are
   background-repeat: no-repeat;
   background-size: 1px 16px;
 }
 
 @conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon {
   border-color: hsla(210,4%,10%,.1);
 }
 
+.findbar-button:not(:-moz-any([checked="true"],[disabled="true"])):hover > .toolbarbutton-text,
 #nav-bar .toolbarbutton-1:not([disabled=true]) > .toolbarbutton-menubutton-button[open] + .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-text,
 #nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container,
 @conditionalForwardWithUrlbar@ > #forward-button:not([open]):not(:active):not([disabled]):hover > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon {
@@ -830,32 +833,34 @@ toolbarbutton[sdk-button="true"][cui-are
     background-color: hsla(210,48%,96%,.75);
     box-shadow: 0 0 1px hsla(210,54%,20%,.03),
                 0 0 2px hsla(210,54%,20%,.1);
   }
 %ifdef WINDOWS_AERO
 }
 %endif
 
+.findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active) > .toolbarbutton-text,
 #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open]) > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container {
   background: var(--toolbarbutton-active-background);
   border-color: var(--toolbarbutton-active-bordercolor);
   box-shadow: var(--toolbarbutton-active-boxshadow);
   transition-duration: 10ms;
 }
 
 %ifdef WINDOWS_AERO
 @media (-moz-os-version: windows-vista),
        (-moz-os-version: windows-win7) {
 %endif
   /* < Win8 */
+  .findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active) > .toolbarbutton-text,
   #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open]) > .toolbarbutton-icon,
   #nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon,
   #nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
   #nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
   #nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container {
     text-shadow: none;
     transition: none;
   }
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -562,26 +562,26 @@ this.RESPONSE_DATA_RFU_3 = 7;
 this.RESPONSE_DATA_ACCESS_CONDITION_1 = 8;
 this.RESPONSE_DATA_ACCESS_CONDITION_2 = 9;
 this.RESPONSE_DATA_ACCESS_CONDITION_3 = 10;
 this.RESPONSE_DATA_FILE_STATUS = 11;
 this.RESPONSE_DATA_LENGTH = 12;
 this.RESPONSE_DATA_STRUCTURE = 13;
 this.RESPONSE_DATA_RECORD_LENGTH = 14;
 
-// Types of files  TS 11.11 9.3
-this.EF_TYPE_TRANSPARENT = 0;
-this.EF_TYPE_LINEAR_FIXED = 1;
-this.EF_TYPE_CYCLIC = 3;
+// Structure of files  TS 11.11 9.3
+this.EF_STRUCTURE_TRANSPARENT = 0;
+this.EF_STRUCTURE_LINEAR_FIXED = 1;
+this.EF_STRUCTURE_CYCLIC = 3;
 
 // TS 102.221 11.1.1.4.3 Table 11.5: File descriptor byte.
 this.UICC_EF_STRUCTURE = {};
-this.UICC_EF_STRUCTURE[this.EF_TYPE_TRANSPARENT]= 1;
-this.UICC_EF_STRUCTURE[this.EF_TYPE_LINEAR_FIXED]= 2;
-this.UICC_EF_STRUCTURE[this.EF_TYPE_CYCLIC]= 6;
+this.UICC_EF_STRUCTURE[this.EF_STRUCTURE_TRANSPARENT]= 1;
+this.UICC_EF_STRUCTURE[this.EF_STRUCTURE_LINEAR_FIXED]= 2;
+this.UICC_EF_STRUCTURE[this.EF_STRUCTURE_CYCLIC]= 6;
 
 // Status code of EFsms
 // see 3GPP TS 51.011 clause 10.5.3
 this.EFSMS_STATUS_FREE       = 0x00;
 this.EFSMS_STATUS_READ       = 0x01;
 this.EFSMS_STATUS_TO_BE_READ = 0x03;
 this.EFSMS_STATUS_TO_BE_SENT = 0x07;
 
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -12276,18 +12276,18 @@ BerTlvHelperObject.prototype = {
     // structure of file.
     let fileStructure = fileDescriptorByte & 0x07;
 
     let fileDescriptor = {
       fileStructure: fileStructure
     };
     // byte 5 ~ 7 are mandatory for linear fixed and cyclic files, otherwise
     // they are not applicable.
-    if (fileStructure === UICC_EF_STRUCTURE[EF_TYPE_LINEAR_FIXED] ||
-        fileStructure === UICC_EF_STRUCTURE[EF_TYPE_CYCLIC]) {
+    if (fileStructure === UICC_EF_STRUCTURE[EF_STRUCTURE_LINEAR_FIXED] ||
+        fileStructure === UICC_EF_STRUCTURE[EF_STRUCTURE_CYCLIC]) {
       fileDescriptor.recordLength = (GsmPDUHelper.readHexOctet() << 8) +
                                      GsmPDUHelper.readHexOctet();
       fileDescriptor.numOfRecords = GsmPDUHelper.readHexOctet();
     }
 
     return fileDescriptor;
   },
 
@@ -12497,17 +12497,17 @@ ICCIOHelperObject.prototype = {
       options.command = ICC_COMMAND_READ_RECORD;
       options.p1 = options.recordNumber || 1; // Record number
       options.p2 = READ_RECORD_ABSOLUTE_MODE;
       options.p3 = options.recordSize;
       options.callback = cb || options.callback;
       this.context.RIL.iccIO(options);
     }).bind(this);
 
-    options.type = EF_TYPE_LINEAR_FIXED;
+    options.structure = EF_STRUCTURE_LINEAR_FIXED;
     options.pathId = this.context.ICCFileHelper.getEFPath(options.fileId);
     if (options.recordSize) {
       readRecord(options);
       return;
     }
 
     cb = options.callback;
     options.callback = readRecord;
@@ -12539,17 +12539,17 @@ ICCIOHelperObject.prototype = {
    *        The callback function shall be called when failure.
    */
   updateLinearFixedEF: function(options) {
     if (!options.fileId || !options.recordNumber) {
       throw new Error("Unexpected fileId " + options.fileId +
                       " or recordNumber " + options.recordNumber);
     }
 
-    options.type = EF_TYPE_LINEAR_FIXED;
+    options.structure = EF_STRUCTURE_LINEAR_FIXED;
     options.pathId = this.context.ICCFileHelper.getEFPath(options.fileId);
     let cb = options.callback;
     options.callback = function callback(options) {
       options.callback = cb;
       options.command = ICC_COMMAND_UPDATE_RECORD;
       options.p1 = options.recordNumber;
       options.p2 = READ_RECORD_ABSOLUTE_MODE;
       options.p3 = options.recordSize;
@@ -12564,17 +12564,17 @@ ICCIOHelperObject.prototype = {
    * @param fileId
    *        The file to operate on, one of the ICC_EF_* constants.
    * @param callback [optional]
    *        The callback function shall be called when the record(s) is read.
    * @param onerror [optional]
    *        The callback function shall be called when failure.
    */
   loadTransparentEF: function(options) {
-    options.type = EF_TYPE_TRANSPARENT;
+    options.structure = EF_STRUCTURE_TRANSPARENT;
     let cb = options.callback;
     options.callback = function callback(options) {
       options.callback = cb;
       options.command = ICC_COMMAND_READ_BINARY;
       options.p2 = 0x00;
       options.p3 = options.fileSize;
       this.context.RIL.iccIO(options);
     }.bind(this);
@@ -12649,23 +12649,25 @@ ICCIOHelperObject.prototype = {
   processUSimGetResponse: function(options, octetLen) {
     let BerTlvHelper = this.context.BerTlvHelper;
 
     let berTlv = BerTlvHelper.decode(octetLen);
     // See TS 102 221 Table 11.4 for the content order of getResponse.
     let iter = Iterator(berTlv.value);
     let tlv = BerTlvHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG,
                                             iter);
-    if (!tlv || (tlv.value.fileStructure !== UICC_EF_STRUCTURE[options.type])) {
-      throw new Error("Expected EF type " + UICC_EF_STRUCTURE[options.type] +
+    if (!tlv ||
+        (tlv.value.fileStructure !== UICC_EF_STRUCTURE[options.structure])) {
+      throw new Error("Expected EF structure " +
+                      UICC_EF_STRUCTURE[options.structure] +
                       " but read " + tlv.value.fileStructure);
     }
 
-    if (tlv.value.fileStructure === UICC_EF_STRUCTURE[EF_TYPE_LINEAR_FIXED] ||
-        tlv.value.fileStructure === UICC_EF_STRUCTURE[EF_TYPE_CYCLIC]) {
+    if (tlv.value.fileStructure === UICC_EF_STRUCTURE[EF_STRUCTURE_LINEAR_FIXED] ||
+        tlv.value.fileStructure === UICC_EF_STRUCTURE[EF_STRUCTURE_CYCLIC]) {
       options.recordSize = tlv.value.recordLength;
       options.totalRecords = tlv.value.numOfRecords;
     }
 
     tlv = BerTlvHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter);
     if (!tlv || (tlv.value.fileId !== options.fileId)) {
       throw new Error("Expected file ID " + options.fileId.toString(16) +
                       " but read " + fileId.toString(16));
@@ -12711,25 +12713,26 @@ ICCIOHelperObject.prototype = {
     // Skip 1 byte RFU, data[7],
     //      3 bytes Access conditions, data[8] data[9] data[10],
     //      1 byte File status, data[11],
     //      1 byte Length of the following data, data[12].
     Buf.seekIncoming(((RESPONSE_DATA_STRUCTURE - RESPONSE_DATA_FILE_TYPE - 1) *
         Buf.PDU_HEX_OCTET_SIZE));
 
     // Read Structure of EF, data[13]
-    let efType = GsmPDUHelper.readHexOctet();
-    if (efType != options.type) {
-      throw new Error("Expected EF type " + options.type + " but read " + efType);
-    }
-
-    // TODO: Bug 952025.
+    let efStructure = GsmPDUHelper.readHexOctet();
+    if (efStructure != options.structure) {
+      throw new Error("Expected EF structure " + options.structure +
+                      " but read " + efStructure);
+    }
+
     // Length of a record, data[14].
     // Only available for LINEAR_FIXED and CYCLIC.
-    if (efType == EF_TYPE_LINEAR_FIXED || efType == EF_TYPE_CYCLIC) {
+    if (efStructure == EF_STRUCTURE_LINEAR_FIXED ||
+        efStructure == EF_STRUCTURE_CYCLIC) {
       options.recordSize = GsmPDUHelper.readHexOctet();
       options.totalRecords = options.fileSize / options.recordSize;
     } else {
       Buf.seekIncoming(1 * Buf.PDU_HEX_OCTET_SIZE);
     }
   },
 
   /**
--- a/dom/system/gonk/tests/test_ril_worker_icc_BerTlvHelper.js
+++ b/dom/system/gonk/tests/test_ril_worker_icc_BerTlvHelper.js
@@ -30,17 +30,17 @@ add_test(function test_fcp_template_for_
 
   for (let i = 0; i < tag_test.length; i++) {
     pduHelper.writeHexOctet(tag_test[i]);
   }
 
   let berTlv = berHelper.decode(tag_test.length);
   let iter = Iterator(berTlv.value);
   let tlv = berHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, iter);
-  do_check_eq(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_TYPE_TRANSPARENT]);
+  do_check_eq(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_STRUCTURE_TRANSPARENT]);
 
   tlv = berHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter);
   do_check_eq(tlv.value.fileId, 0x2FE2);
 
   tlv = berHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter);
   do_check_eq(tlv.value.fileSizeData, 0x0A);
 
   run_next_test();
@@ -68,17 +68,17 @@ add_test(function test_fcp_template_for_
 
   for (let i = 0; i < tag_test.length; i++) {
     pduHelper.writeHexOctet(tag_test[i]);
   }
 
   let berTlv = berHelper.decode(tag_test.length);
   let iter = Iterator(berTlv.value);
   let tlv = berHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, iter);
-  do_check_eq(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_TYPE_LINEAR_FIXED]);
+  do_check_eq(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_STRUCTURE_LINEAR_FIXED]);
   do_check_eq(tlv.value.recordLength, 0x1A);
   do_check_eq(tlv.value.numOfRecords, 0x01);
 
   tlv = berHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter);
   do_check_eq(tlv.value.fileId, 0x6F40);
 
   tlv = berHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter);
   do_check_eq(tlv.value.fileSizeData, 0x1A);
--- a/dom/system/gonk/tests/test_ril_worker_icc_ICCIOHelper.js
+++ b/dom/system/gonk/tests/test_ril_worker_icc_ICCIOHelper.js
@@ -118,17 +118,17 @@ add_test(function test_icc_io_get_respon
     let strLen = responseArray[i].length * 2;
     buf.writeInt32(strLen);
     for (let j = 0; j < responseArray[i].length; j++) {
       pduHelper.writeHexOctet(responseArray[i][j]);
     }
     buf.writeStringDelimiter(strLen);
 
     let options = {fileId: ICC_EF_ICCID,
-                   type: EF_TYPE_TRANSPARENT};
+                   structure: EF_STRUCTURE_TRANSPARENT};
     iccioHelper.processICCIOGetResponse(options);
 
     do_check_eq(options.fileSize, 0x0A);
   }
 
   run_next_test();
 });
 
@@ -156,17 +156,17 @@ add_test(function test_icc_io_get_respon
     let strLen = responseArray[i].length * 2;
     buf.writeInt32(strLen);
     for (let j = 0; j < responseArray[i].length; j++) {
       pduHelper.writeHexOctet(responseArray[i][j]);
     }
     buf.writeStringDelimiter(strLen);
 
     let options = {fileId: ICC_EF_MSISDN,
-                   type: EF_TYPE_LINEAR_FIXED};
+                   structure: EF_STRUCTURE_LINEAR_FIXED};
     iccioHelper.processICCIOGetResponse(options);
 
     do_check_eq(options.fileSize, 0x1A);
     do_check_eq(options.recordSize, 0x1A);
     do_check_eq(options.totalRecords, 0x01);
   }
 
   run_next_test();
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -406,17 +406,22 @@ loadListener.prototype = {
 // Hacky method that tries to determine if this user is in a US geography, and
 // using an en-US build.
 function getIsUS() {
   let geoSpecificDefaults = false;
   try {
     geoSpecificDefaults = Services.prefs.getBoolPref("browser.search.geoSpecificDefaults");
   } catch(e) {}
 
-  if (!geoSpecificDefaults) {
+  let distroID;
+  try {
+    distroID = Services.prefs.getCharPref("distribution.id");
+  } catch (e) {}
+
+  if (!geoSpecificDefaults || distroID) {
     return false;
   }
 
   // If we've set the pref before, just return that result.
   let cachePref = "browser.search.isUS";
   try {
     return Services.prefs.getBoolPref(cachePref);
   } catch(e) {}
--- a/toolkit/content/widgets/findbar.xml
+++ b/toolkit/content/widgets/findbar.xml
@@ -170,25 +170,25 @@
         <xul:toolbarbutton anonid="find-next"
                            class="findbar-find-next tabbable"
                            tooltiptext="&next.tooltip;"
                            oncommand="onFindAgainCommand(false);"
                            disabled="true"
                            xbl:inherits="accesskey=findnextaccesskey"/>
       </xul:hbox>
       <xul:toolbarbutton anonid="highlight"
-                         class="findbar-highlight tabbable"
+                         class="findbar-highlight findbar-button tabbable"
                          label="&highlightAll.label;"
                          accesskey="&highlightAll.accesskey;"
                          tooltiptext="&highlightAll.tooltiptext;"
                          oncommand="toggleHighlight(this.checked);"
                          type="checkbox"
                          xbl:inherits="accesskey=highlightaccesskey"/>
       <xul:toolbarbutton anonid="find-case-sensitive"
-                         class="findbar-case-sensitive tabbable"
+                         class="findbar-case-sensitive findbar-button tabbable"
                          label="&caseSensitive.label;"
                          accesskey="&caseSensitive.accesskey;"
                          tooltiptext="&caseSensitive.tooltiptext;"
                          oncommand="_setCaseSensitivity(this.checked ? 1 : 0);"
                          type="checkbox"
                          xbl:inherits="accesskey=matchcaseaccesskey"/>
       <xul:label anonid="match-case-status" class="findbar-find-fast"/>
       <xul:label anonid="found-matches" class="findbar-find-fast found-matches" hidden="true"/>
--- a/toolkit/devtools/server/actors/webaudio.js
+++ b/toolkit/devtools/server/actors/webaudio.js
@@ -8,32 +8,41 @@ const {Cc, Ci, Cu, Cr} = require("chrome
 const Services = require("Services");
 
 const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 const events = require("sdk/event/core");
 const { on: systemOn, off: systemOff } = require("sdk/system/events");
 const protocol = require("devtools/server/protocol");
 const { CallWatcherActor, CallWatcherFront } = require("devtools/server/actors/call-watcher");
 const { ThreadActor } = require("devtools/server/actors/script");
+const AutomationTimeline = require("./utils/automation-timeline");
 
 const { on, once, off, emit } = events;
 const { types, method, Arg, Option, RetVal } = protocol;
 
+const AUTOMATION_GRANULARITY = 2000;
+const AUTOMATION_GRANULARITY_MAX = 6000;
+
 const AUDIO_GLOBALS = [
-  "AudioContext", "AudioNode"
+  "AudioContext", "AudioNode", "AudioParam"
 ];
 
 const NODE_CREATION_METHODS = [
   "createBufferSource", "createMediaElementSource", "createMediaStreamSource",
   "createMediaStreamDestination", "createScriptProcessor", "createAnalyser",
   "createGain", "createDelay", "createBiquadFilter", "createWaveShaper",
   "createPanner", "createConvolver", "createChannelSplitter", "createChannelMerger",
   "createDynamicsCompressor", "createOscillator"
 ];
 
+const AUTOMATION_METHODS = [
+  "setValueAtTime", "linearRampToValueAtTime", "exponentialRampToValueAtTime",
+  "setTargetAtTime", "setValueCurveAtTime"
+];
+
 const NODE_ROUTING_METHODS = [
   "connect", "disconnect"
 ];
 
 const NODE_PROPERTIES = {
   "OscillatorNode": {
     "type": {},
     "frequency": {},
@@ -125,21 +134,31 @@ let AudioNodeActor = exports.AudioNodeAc
     protocol.Actor.prototype.initialize.call(this, conn);
 
     // Store ChromeOnly property `id` to identify AudioNode,
     // rather than storing a strong reference, and store a weak
     // ref to underlying node for controlling.
     this.nativeID = node.id;
     this.node = Cu.getWeakReference(node);
 
+    // Stores the AutomationTimelines for this node's AudioParams.
+    this.automation = {};
+
     try {
       this.type = getConstructorName(node);
     } catch (e) {
       this.type = "";
     }
+
+    // Create automation timelines for all AudioParams
+    Object.keys(NODE_PROPERTIES[this.type])
+      .filter(isAudioParam.bind(null, node))
+      .forEach(paramName => {
+        this.automation[paramName] = new AutomationTimeline(node[paramName].defaultValue);
+      });
   },
 
   /**
    * Returns the name of the audio type.
    * Examples: "OscillatorNode", "MediaElementAudioSourceNode"
    */
   getType: method(function () {
     return this.type;
@@ -207,20 +226,23 @@ let AudioNodeActor = exports.AudioNodeAc
   setParam: method(function (param, value) {
     let node = this.node.get();
 
     if (node === null) {
       return CollectedAudioNodeError();
     }
 
     try {
-      if (isAudioParam(node, param))
+      if (isAudioParam(node, param)) {
         node[param].value = value;
-      else
+        this.automation[param].setValue(value);
+      }
+      else {
         node[param] = value;
+      }
       return undefined;
     } catch (e) {
       return constructError(e);
     }
   }, {
     request: {
       param: Arg(0, "string"),
       value: Arg(1, "nullable:primitive")
@@ -279,17 +301,17 @@ let AudioNodeActor = exports.AudioNodeAc
     request: { param: Arg(0, "string") },
     response: { flags: RetVal("nullable:primitive") }
   }),
 
   /**
    * Get an array of objects each containing a `param` and `value` property,
    * corresponding to a property name and current value of the audio node.
    */
-  getParams: method(function (param) {
+  getParams: method(function () {
     let props = Object.keys(NODE_PROPERTIES[this.type]);
     return props.map(prop =>
       ({ param: prop, value: this.getParam(prop), flags: this.getParamFlags(prop) }));
   }, {
     response: { params: RetVal("json") }
   }),
 
   /**
@@ -367,18 +389,143 @@ let AudioNodeActor = exports.AudioNodeAc
       // patched method that fires the webaudio actor's `disconnect` event.
       XPCNativeWrapper.unwrap(node).disconnect(output);
     } catch (e) {
       return constructError(e);
     }
   }, {
     request: { output: Arg(0, "nullable:number") },
     response: { error: RetVal("nullable:json") }
-  })
+  }),
+
+  getAutomationData: method(function (paramName) {
+    let timeline = this.automation[paramName];
+    let events = timeline.events;
+    let values = [];
+    let i = 0;
+
+    if (!timeline) {
+      return null;
+    }
+
+    if (!timeline.events.length) {
+      return { events, values };
+    }
+
+    let firstEvent = events[0];
+    let lastEvent = events[timeline.events.length - 1];
+    // `setValueCurveAtTime` will have a duration value -- other
+    // events will have duration of `0`.
+    let timeDelta = (lastEvent.time + lastEvent.duration) - firstEvent.time;
+    let scale = timeDelta / AUTOMATION_GRANULARITY;
+
+    for (; i < AUTOMATION_GRANULARITY; i++) {
+      let t = firstEvent.time + (i * scale);
+      let value = timeline.getValueAtTime(t);
+      values.push({ t, value });
+    }
+
+    // If the last event is setTargetAtTime, the automation
+    // doesn't actually begin until the event's time, and exponentially
+    // approaches the target value. In this case, we add more values
+    // until we're "close enough" to the target.
+    if (lastEvent.type === "setTargetAtTime") {
+      for (; i < AUTOMATION_GRANULARITY_MAX; i++) {
+        let t = firstEvent.time + (++i * scale);
+        let value = timeline.getValueAtTime(t);
+        values.push({ t, value });
+      }
+    }
+
+    return { events, values };
+  }, {
+    request: { paramName: Arg(0, "string") },
+    response: { values: RetVal("nullable:json") }
+  }),
+
+  /**
+   * Called via WebAudioActor, registers an automation event
+   * for the AudioParam called.
+   *
+   * @param String paramName
+   *        Name of the AudioParam.
+   * @param String eventName
+   *        Name of the automation event called.
+   * @param Array args
+   *        Arguments passed into the automation call.
+   */
+  addAutomationEvent: method(function (paramName, eventName, args=[]) {
+    let node = this.node.get();
+    let timeline = this.automation[paramName];
 
+    if (node === null) {
+      return CollectedAudioNodeError();
+    }
+
+    if (!timeline || !node[paramName][eventName]) {
+      return InvalidCommandError();
+    }
+
+    try {
+      // Using the unwrapped node and parameter, the corresponding
+      // WebAudioActor event will be fired, subsequently calling
+      // `_recordAutomationEvent`. Some finesse is required to handle
+      // the cast of TypedArray arguments over the protocol, which is
+      // taken care of below. The event will cast the argument back
+      // into an array to be broadcasted from WebAudioActor, but the
+      // double-casting will only occur when starting from `addAutomationEvent`,
+      // which is only used in tests.
+      let param = XPCNativeWrapper.unwrap(node[paramName]);
+
+      // If calling `setValueCurveAtTime`, the first argument
+      // is a Float32Array, which won't be able to be serialized
+      // over the protocol. Cast a normal array to a Float32Array here.
+      if (eventName === "setValueCurveAtTime") {
+        let contentGlobal = Cu.getGlobalForObject(param);
+        // Since we cannot iterate over and modify the actual Float32Array
+        // in the content, we'll have to pass in an array to the constructor
+        // from the same context, since we can iterate over non-TypedArrays.
+        let contentArray = copyInto(new contentGlobal.Array(), args[0]);
+
+        // Create a Float32Array from the content, seeding with an array
+        // from the same scope.
+        let curve = new contentGlobal.Float32Array(contentArray);
+        args[0] = curve;
+      }
+
+      param[eventName].apply(param, args);
+    } catch (e) {
+      return constructError(e);
+    }
+  }, {
+    request: {
+      paramName: Arg(0, "string"),
+      eventName: Arg(1, "string"),
+      args: Arg(2, "nullable:json")
+    },
+    response: { error: RetVal("nullable:json") }
+  }),
+
+  /**
+   * Registers the automation event in the AudioNodeActor's
+   * internal timeline. Called when setting automation via
+   * `addAutomationEvent`, or from the WebAudioActor's listening
+   * to the event firing via content.
+   *
+   * @param String paramName
+   *        Name of the AudioParam.
+   * @param String eventName
+   *        Name of the automation event called.
+   * @param Array args
+   *        Arguments passed into the automation call.
+   */
+  _recordAutomationEvent: function (paramName, eventName, args) {
+    let timeline = this.automation[paramName];
+    timeline[eventName].apply(timeline, args);
+  }
 });
 
 /**
  * The corresponding Front object for the AudioNodeActor.
  */
 let AudioNodeFront = protocol.FrontClass(AudioNodeActor, {
   initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client, form);
@@ -470,20 +617,23 @@ let WebAudioActor = exports.WebAudioActo
     // All Web Audio nodes inherit from AudioNode's prototype, so
     // hook into the `connect` and `disconnect` methods
     if (WebAudioFront.NODE_ROUTING_METHODS.has(name)) {
       this._handleRoutingCall(functionCall);
     }
     else if (WebAudioFront.NODE_CREATION_METHODS.has(name)) {
       this._handleCreationCall(functionCall);
     }
+    else if (WebAudioFront.AUTOMATION_METHODS.has(name)) {
+      this._handleAutomationCall(functionCall);
+    }
   },
 
   _handleRoutingCall: function(functionCall) {
-    let { caller, args, window, name } = functionCall.details;
+    let { caller, args, name } = functionCall.details;
     let source = caller;
     let dest = args[0];
     let isAudioParam = dest ? getConstructorName(dest) === "AudioParam" : false;
 
     // audionode.connect(param)
     if (name === "connect" && isAudioParam) {
       this._onConnectParam(source, dest);
     }
@@ -508,16 +658,36 @@ let WebAudioActor = exports.WebAudioActo
       // and trigger a `create-node` event for the context destination
       this._onStartContext();
       this._onCreateNode(caller.destination);
       this._firstNodeCreated = true;
     }
     this._onCreateNode(result);
   },
 
+  _handleAutomationCall: function (functionCall) {
+    let { caller, name, args } = functionCall.details;
+    let wrappedParam = new XPCNativeWrapper(caller);
+
+    // Sanitize arguments, as these should all be numbers,
+    // with the exception of a TypedArray, which needs
+    // casted to an Array
+    args = sanitizeAutomationArgs(args);
+
+    let nodeActor = this._getActorByNativeID(wrappedParam._parentID);
+    nodeActor._recordAutomationEvent(wrappedParam._paramName, name, args);
+
+    this._onAutomationEvent({
+      node: nodeActor,
+      paramName: wrappedParam._paramName,
+      eventName: name,
+      args: args
+    });
+  },
+
   /**
    * Stops listening for document global changes and puts this actor
    * to hibernation. This method is called automatically just before the
    * actor is destroyed.
    */
   finalize: method(function() {
     if (!this._initialized) {
       return;
@@ -566,16 +736,23 @@ let WebAudioActor = exports.WebAudioActo
     },
     "create-node": {
       type: "createNode",
       source: Arg(0, "audionode")
     },
     "destroy-node": {
       type: "destroyNode",
       source: Arg(0, "audionode")
+    },
+    "automation-event": {
+      type: "automationEvent",
+      node: Option(0, "audionode"),
+      paramName: Option(0, "string"),
+      eventName: Option(0, "string"),
+      args: Option(0, "json")
     }
   },
 
   /**
    * Helper for constructing an AudioNodeActor, assigning to
    * internal weak map, and tracking via `manage` so it is assigned
    * an `actorID`.
    */
@@ -707,16 +884,28 @@ let WebAudioActor = exports.WebAudioActo
    * Ensures that the new global has recording on
    * so we can proxy the function calls.
    */
   _onGlobalCreated: function () {
     this._callWatcher.resumeRecording();
   },
 
   /**
+   * Fired when an automation event is added to an AudioNode.
+   */
+  _onAutomationEvent: function ({node, paramName, eventName, args}) {
+    emit(this, "automation-event",  {
+      node: node,
+      paramName: paramName,
+      eventName: eventName,
+      args: args
+    });
+  },
+
+  /**
    * Called when the underlying ContentObserver fires `global-destroyed`
    * so we can cleanup some things between the global being destroyed and
    * when the actor's `finalize` method gets called.
    */
   _onGlobalDestroyed: function ({id}) {
     if (this._callWatcher._tracedWindowId !== id) {
       return;
     }
@@ -733,16 +922,17 @@ let WebAudioActor = exports.WebAudioActo
  */
 let WebAudioFront = exports.WebAudioFront = protocol.FrontClass(WebAudioActor, {
   initialize: function(client, { webaudioActor }) {
     protocol.Front.prototype.initialize.call(this, client, { actor: webaudioActor });
     this.manage(this);
   }
 });
 
+WebAudioFront.AUTOMATION_METHODS = new Set(AUTOMATION_METHODS);
 WebAudioFront.NODE_CREATION_METHODS = new Set(NODE_CREATION_METHODS);
 WebAudioFront.NODE_ROUTING_METHODS = new Set(NODE_ROUTING_METHODS);
 
 /**
  * Determines whether or not property is an AudioParam.
  *
  * @param AudioNode node
  *        An AudioNode.
@@ -776,16 +966,23 @@ function constructError (err) {
  */
 function CollectedAudioNodeError () {
   return {
     message: "AudioNode has been garbage collected and can no longer be reached.",
     type: "UnreachableAudioNode"
   };
 }
 
+function InvalidCommandError () {
+  return {
+    message: "The command on AudioNode is invalid.",
+    type: "InvalidCommand"
+  };
+}
+
 /**
  * Takes an object and converts it's `toString()` form, like
  * "[object OscillatorNode]" or "[object Float32Array]",
  * or XrayWrapper objects like "[object XrayWrapper [object Array]]"
  * to a string of just the constructor name, like "OscillatorNode",
  * or "Float32Array".
  */
 function getConstructorName (obj) {
@@ -802,8 +999,42 @@ function createObjectGrip (value) {
     type: "object",
     preview: {
       kind: "ObjectWithText",
       text: ""
     },
     class: getConstructorName(value)
   };
 }
+
+/**
+ * Converts all TypedArrays of the array that cannot
+ * be passed over the wire into a normal Array equivilent.
+ */
+function sanitizeAutomationArgs (args) {
+  return args.reduce((newArgs, el) => {
+    newArgs.push(typeof el === "object" && getConstructorName(el) === "Float32Array" ? castToArray(el) : el);
+    return newArgs;
+  }, []);
+}
+
+/**
+ * Casts TypedArray to a normal array via a
+ * new scope.
+ */
+function castToArray (typedArray) {
+  // The Xray machinery for TypedArrays denies indexed access on the grounds
+  // that it's slow, and advises callers to do a structured clone instead.
+  let global = Cu.getGlobalForObject(this);
+  let safeView = Cu.cloneInto(typedArray.subarray(), global);
+  return copyInto([], safeView);
+}
+
+/**
+ * Copies values of an array-like `source` into
+ * a similarly array-like `dest`.
+ */
+function copyInto (dest, source) {
+  for (let i = 0; i < source.length; i++) {
+    dest[i] = source[i];
+  }
+  return dest;
+}