Merge latest green fx-team changeset and mozilla-central; a=merge
authorEd Morley <emorley@mozilla.com>
Wed, 20 Aug 2014 15:14:31 +0100
changeset 214889 cbbc380f1e1ce8d92d95e3b90becbf848b9fa376
parent 214888 41c331550b324aa9dbed9bce046d7f0dbed475ad (current diff)
parent 214871 df54644fad383559f0acce72c40fd0a902d0bbf1 (diff)
child 214909 72afaf22a760a87930a820b712962b913d50a98d
child 214920 34da96e649b570a084744e0d75e9706a0be10a3d
child 214948 38769be77c601a02fe9285462679f8894e920622
push idunknown
push userunknown
push dateunknown
reviewersmerge
milestone34.0a1
Merge latest green fx-team changeset and mozilla-central; a=merge
content/media/AudioNodeEngine.cpp
content/media/AudioNodeEngine.h
content/media/AudioNodeEngineNEON.cpp
content/media/AudioNodeEngineNEON.h
content/media/AudioNodeExternalInputStream.cpp
content/media/AudioNodeExternalInputStream.h
content/media/AudioNodeStream.cpp
content/media/AudioNodeStream.h
dom/bindings/test/test_bug923904.html
dom/system/gonk/MozMtpStorage.cpp
dom/system/gonk/MozMtpStorage.h
layout/reftests/font-features/font-features-oldsyntax-1.html
layout/reftests/font-features/font-features-oldsyntax-2.html
layout/reftests/font-features/font-features-oldsyntax-3.html
layout/reftests/font-features/font-features-oldsyntax-4.html
--- a/accessible/jsat/AccessFu.css
+++ b/accessible/jsat/AccessFu.css
@@ -4,19 +4,24 @@
 
 #virtual-cursor-box {
   position: fixed;
   border: 1px solid orange;
   pointer-events: none;
   display: none;
   border-radius: 2px;
   box-shadow: 1px 1px 1px #444;
+  display: none;
 }
 
-#virtual-cursor-inset {
+#virtual-cursor-box.show {
+  display: block;
+}
+
+#virtual-cursor-box > div {
   border-radius: 1px;
   box-shadow: inset 1px 1px 1px #444;
   display: block;
   box-sizing: border-box;
   width: 100%;
   height: 100%;
   pointer-events: none;
 }
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -389,53 +389,39 @@ this.AccessFu = { // jshint ignore:line
   // Layerview is focused
   _focused: false,
 
   // Keep track of message managers tha already have a 'content-script.js'
   // injected.
   _processedMessageManagers: [],
 
   /**
-   * Adjusts the given bounds relative to the given browser. Converts from
-   * screen or device pixels to either device or CSS pixels.
+   * Adjusts the given bounds relative to the given browser.
    * @param {Rect} aJsonBounds the bounds to adjust
    * @param {browser} aBrowser the browser we want the bounds relative to
    * @param {bool} aToCSSPixels whether to convert to CSS pixels (as opposed to
    *               device pixels)
-   * @param {bool} aFromDevicePixels whether to convert from device pixels (as
-   *               opposed to screen pixels)
    */
   adjustContentBounds:
-    function(aJsonBounds, aBrowser, aToCSSPixels, aFromDevicePixels) {
+    function(aJsonBounds, aBrowser, aToCSSPixels) {
       let bounds = new Rect(aJsonBounds.left, aJsonBounds.top,
                             aJsonBounds.right - aJsonBounds.left,
                             aJsonBounds.bottom - aJsonBounds.top);
       let win = Utils.win;
       let dpr = win.devicePixelRatio;
-      let vp = Utils.getViewport(win);
       let offset = { left: -win.mozInnerScreenX, top: -win.mozInnerScreenY };
 
       if (!aBrowser.contentWindow) {
         // OOP browser, add offset of browser.
         // The offset of the browser element in relation to its parent window.
         let clientRect = aBrowser.getBoundingClientRect();
         let win = aBrowser.ownerDocument.defaultView;
         offset.left += clientRect.left + win.mozInnerScreenX;
         offset.top += clientRect.top + win.mozInnerScreenY;
       }
-
-      // Here we scale from screen pixels to layout device pixels by dividing by
-      // the resolution (caused by pinch-zooming). The resolution is the
-      // viewport zoom divided by the devicePixelRatio. If there's no viewport,
-      // then we're on a platform without pinch-zooming and we can just ignore
-      // this.
-      if (!aFromDevicePixels && vp) {
-        bounds = bounds.scale(vp.zoom / dpr, vp.zoom / dpr);
-      }
-
       // Add the offset; the offset is in CSS pixels, so multiply the
       // devicePixelRatio back in before adding to preserve unit consistency.
       bounds = bounds.translate(offset.left * dpr, offset.top * dpr);
 
       // If we want to get to CSS pixels from device pixels, this needs to be
       // further divided by the devicePixelRatio due to widget scaling.
       if (aToCSSPixels) {
         bounds = bounds.scale(1 / dpr, 1 / dpr);
@@ -540,44 +526,43 @@ var Output = {
         if (!this.highlightBox) {
           // Add highlight box
           highlightBox = Utils.win.document.
             createElementNS('http://www.w3.org/1999/xhtml', 'div');
           Utils.win.document.documentElement.appendChild(highlightBox);
           highlightBox.id = 'virtual-cursor-box';
 
           // Add highlight inset for inner shadow
-          let inset = Utils.win.document.
-            createElementNS('http://www.w3.org/1999/xhtml', 'div');
-          inset.id = 'virtual-cursor-inset';
+          highlightBox.appendChild(
+            Utils.win.document.createElementNS(
+              'http://www.w3.org/1999/xhtml', 'div'));
 
-          highlightBox.appendChild(inset);
           this.highlightBox = Cu.getWeakReference(highlightBox);
         } else {
           highlightBox = this.highlightBox.get();
         }
 
         let padding = aDetail.padding;
         let r = AccessFu.adjustContentBounds(aDetail.bounds, aBrowser, true);
 
         // First hide it to avoid flickering when changing the style.
-        highlightBox.style.display = 'none';
+        highlightBox.classList.remove('show');
         highlightBox.style.top = (r.top - padding) + 'px';
         highlightBox.style.left = (r.left - padding) + 'px';
         highlightBox.style.width = (r.width + padding*2) + 'px';
         highlightBox.style.height = (r.height + padding*2) + 'px';
-        highlightBox.style.display = 'block';
+        highlightBox.classList.add('show');
 
         break;
       }
       case 'tabstate-change':
       {
         let highlightBox = this.highlightBox ? this.highlightBox.get() : null;
         if (highlightBox) {
-          highlightBox.style.display = 'none';
+          highlightBox.classList.remove('show');
         }
         break;
       }
     }
   },
 
   get androidBridge() {
     delete this.androidBridge;
@@ -884,18 +869,17 @@ var Input = {
   sendContextMenuMessage: function sendContextMenuMessage() {
     let mm = Utils.getMessageManager(Utils.CurrentBrowser);
     mm.sendAsyncMessage('AccessFu:ContextMenu', {});
   },
 
   activateContextMenu: function activateContextMenu(aDetails) {
     if (Utils.MozBuildApp === 'mobile/android') {
       let p = AccessFu.adjustContentBounds(aDetails.bounds,
-                                           Utils.CurrentBrowser,
-                                           true, true).center();
+                                           Utils.CurrentBrowser, true).center();
       Services.obs.notifyObservers(null, 'Gesture:LongPress',
                                    JSON.stringify({x: p.x, y: p.y}));
     }
   },
 
   setEditState: function setEditState(aEditState) {
     this.editState = aEditState;
   },
@@ -910,18 +894,18 @@ var Input = {
     let mm = Utils.getMessageManager(Utils.CurrentBrowser);
     mm.sendAsyncMessage('AccessFu:Scroll',
       {page: aPage, horizontal: aHorizontal, origin: 'top'});
   },
 
   doScroll: function doScroll(aDetails) {
     let horizontal = aDetails.horizontal;
     let page = aDetails.page;
-    let p = AccessFu.adjustContentBounds(aDetails.bounds, Utils.CurrentBrowser,
-                                         true, true).center();
+    let p = AccessFu.adjustContentBounds(
+      aDetails.bounds, Utils.CurrentBrowser, true).center();
     Utils.winUtils.sendWheelEvent(p.x, p.y,
       horizontal ? page : 0, horizontal ? 0 : page, 0,
       Utils.win.WheelEvent.DOM_DELTA_PAGE, 0, 0, 0, 0);
   },
 
   get keyMap() {
     delete this.keyMap;
     this.keyMap = {
--- a/accessible/jsat/Utils.jsm
+++ b/accessible/jsat/Utils.jsm
@@ -250,25 +250,16 @@ this.Utils = { // jshint ignore:line
     try {
       return aBrowser.QueryInterface(Ci.nsIFrameLoaderOwner).
          frameLoader.messageManager;
     } catch (x) {
       return null;
     }
   },
 
-  getViewport: function getViewport(aWindow) {
-    switch (this.MozBuildApp) {
-      case 'mobile/android':
-        return aWindow.BrowserApp.selectedTab.getViewport();
-      default:
-        return null;
-    }
-  },
-
   getState: function getState(aAccessibleOrEvent) {
     if (aAccessibleOrEvent instanceof Ci.nsIAccessibleStateChangeEvent) {
       return new State(
         aAccessibleOrEvent.isExtraState ? 0 : aAccessibleOrEvent.state,
         aAccessibleOrEvent.isExtraState ? aAccessibleOrEvent.state : 0);
     } else {
       let state = {};
       let extState = {};
@@ -297,28 +288,47 @@ this.Utils = { // jshint ignore:line
 
   getVirtualCursor: function getVirtualCursor(aDocument) {
     let doc = (aDocument instanceof Ci.nsIAccessible) ? aDocument :
       this.AccRetrieval.getAccessibleFor(aDocument);
 
     return doc.QueryInterface(Ci.nsIAccessibleDocument).virtualCursor;
   },
 
-  getBounds: function getBounds(aAccessible) {
-      let objX = {}, objY = {}, objW = {}, objH = {};
-      aAccessible.getBounds(objX, objY, objW, objH);
-      return new Rect(objX.value, objY.value, objW.value, objH.value);
+  getContentResolution: function _getContentResolution(aAccessible) {
+    let resX = { value: 1 }, resY = { value: 1 };
+    aAccessible.document.window.QueryInterface(
+      Ci.nsIInterfaceRequestor).getInterface(
+      Ci.nsIDOMWindowUtils).getResolution(resX, resY);
+    return [resX.value, resY.value];
   },
 
-  getTextBounds: function getTextBounds(aAccessible, aStart, aEnd) {
-      let accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
-      let objX = {}, objY = {}, objW = {}, objH = {};
-      accText.getRangeExtents(aStart, aEnd, objX, objY, objW, objH,
-        Ci.nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE);
-      return new Rect(objX.value, objY.value, objW.value, objH.value);
+  getBounds: function getBounds(aAccessible, aPreserveContentScale) {
+    let objX = {}, objY = {}, objW = {}, objH = {};
+    aAccessible.getBounds(objX, objY, objW, objH);
+
+    let [scaleX, scaleY] = aPreserveContentScale ? [1, 1] :
+      this.getContentResolution(aAccessible);
+
+    return new Rect(objX.value, objY.value, objW.value, objH.value).scale(
+      scaleX, scaleY);
+  },
+
+  getTextBounds: function getTextBounds(aAccessible, aStart, aEnd,
+                                        aPreserveContentScale) {
+    let accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
+    let objX = {}, objY = {}, objW = {}, objH = {};
+    accText.getRangeExtents(aStart, aEnd, objX, objY, objW, objH,
+      Ci.nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE);
+
+    let [scaleX, scaleY] = aPreserveContentScale ? [1, 1] :
+      this.getContentResolution(aAccessible);
+
+    return new Rect(objX.value, objY.value, objW.value, objH.value).scale(
+      scaleX, scaleY);
   },
 
   /**
    * Get current display DPI.
    */
   get dpi() {
     delete this.dpi;
     this.dpi = this.winUtils.displayDPI;
--- a/accessible/jsat/content-script.js
+++ b/accessible/jsat/content-script.js
@@ -60,46 +60,38 @@ function forwardToChild(aMessage, aListe
     newJSON.x -= content.mozInnerScreenX;
     newJSON.y -= content.mozInnerScreenY;
   }
   mm.sendAsyncMessage(aMessage.name, newJSON);
   return true;
 }
 
 function activateContextMenu(aMessage) {
-  function sendContextMenuCoordinates(aAccessible) {
-    let bounds = Utils.getBounds(aAccessible);
-    sendAsyncMessage('AccessFu:ActivateContextMenu', {bounds: bounds});
-  }
-
   let position = Utils.getVirtualCursor(content.document).position;
   if (!forwardToChild(aMessage, activateContextMenu, position)) {
-    sendContextMenuCoordinates(position);
+    sendAsyncMessage('AccessFu:ActivateContextMenu',
+      { bounds: Utils.getBounds(position, true) });
   }
 }
 
 function presentCaretChange(aText, aOldOffset, aNewOffset) {
   if (aOldOffset !== aNewOffset) {
     let msg = Presentation.textSelectionChanged(aText, aNewOffset, aNewOffset,
                                                 aOldOffset, aOldOffset, true);
     sendAsyncMessage('AccessFu:Present', msg);
   }
 }
 
 function scroll(aMessage) {
-  function sendScrollCoordinates(aAccessible) {
-    let bounds = Utils.getBounds(aAccessible);
+  let position = Utils.getVirtualCursor(content.document).position;
+  if (!forwardToChild(aMessage, scroll, position)) {
     sendAsyncMessage('AccessFu:DoScroll',
-                     { bounds: bounds,
+                     { bounds: Utils.getBounds(position, true),
                        page: aMessage.json.page,
                        horizontal: aMessage.json.horizontal });
-  }
-
-  let position = Utils.getVirtualCursor(content.document).position;
-  if (!forwardToChild(aMessage, scroll, position)) {
     sendScrollCoordinates(position);
   }
 }
 
 function adjustRange(aMessage) {
   function sendUpDownKey(aAccessible) {
     let acc = Utils.getEmbeddedControl(aAccessible) || aAccessible;
     let elem = acc.DOMNode;
--- a/addon-sdk/source/lib/toolkit/loader.js
+++ b/addon-sdk/source/lib/toolkit/loader.js
@@ -402,28 +402,28 @@ const nodeResolve = iced(function nodeRe
   // Resolve again
   id = exports.resolve(id, requirer);
 
   // we assume that extensions are correct, i.e., a directory doesnt't have '.js'
   // and a js file isn't named 'file.json.js'
   let fullId = join(rootURI, id);
 
   let resolvedPath;
-  if (resolvedPath = loadAsFile(fullId))
+  if ((resolvedPath = loadAsFile(fullId)))
     return stripBase(rootURI, resolvedPath);
-  else if (resolvedPath = loadAsDirectory(fullId))
+  else if ((resolvedPath = loadAsDirectory(fullId)))
     return stripBase(rootURI, resolvedPath);
   // If manifest has dependencies, attempt to look up node modules
   // in the `dependencies` list
   else {
     let dirs = getNodeModulePaths(dirname(join(rootURI, requirer))).map(dir => join(dir, id));
     for (let i = 0; i < dirs.length; i++) {
-      if (resolvedPath = loadAsFile(dirs[i]))
+      if ((resolvedPath = loadAsFile(dirs[i])))
         return stripBase(rootURI, resolvedPath);
-      if (resolvedPath = loadAsDirectory(dirs[i]))
+      if ((resolvedPath = loadAsDirectory(dirs[i])))
         return stripBase(rootURI, resolvedPath);
     }
   }
 
   // We would not find lookup for things like `sdk/tabs`, as that's part of
   // the alias mapping. If during `generateMap`, the runtime lookup resolves
   // with `resolveURI` -- if during runtime, then `resolve` will throw.
   return void 0;
@@ -454,17 +454,17 @@ function loadAsFile (path) {
 function loadAsDirectory (path) {
   let found;
   try {
     // If `path/package.json` exists, parse the `main` entry
     // and attempt to load that
     let main = getManifestMain(JSON.parse(readURI(path + '/package.json')));
     if (main != null) {
       let tmpPath = join(path, main);
-      if (found = loadAsFile(tmpPath))
+      if ((found = loadAsFile(tmpPath)))
         return found
     }
     try {
       let tmpPath = path + '/index.js';
       readURI(tmpPath);
       return tmpPath;
     } catch (e) {}
   } catch (e) {
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -1196,13 +1196,12 @@ const kTransferCid = Components.ID("{1b4
 
 /**
   * Contract ID of the service implementing nsITransfer.
   */
 const kTransferContractId = "@mozilla.org/transfer;1";
 
 // Override Toolkit's nsITransfer implementation with the one from the
 // JavaScript API for downloads.  This will eventually be removed when
-// nsIDownloadManager will not be available anymore (bug 851471).  The
-// old code in this module will be removed in bug 899110.
+// nsIDownloadManager will not be available anymore (bug 851471).
 Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
                   .registerFactory(kTransferCid, "",
                                    kTransferContractId, null);
new file mode 100644
--- /dev/null
+++ b/b2g/config/dolphin/config.json
@@ -0,0 +1,38 @@
+{
+    "config_version": 2,
+    "mock_target": "mozilla-centos6-x86_64",
+    "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel", "git", "libxml2", "bc"],
+    "mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
+    "build_targets": ["kernelheader", ""],
+    "upload_files": [
+        "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
+        "{objdir}/dist/b2g-*.tar.gz",
+        "{workdir}/sources.xml"
+    ],
+    "public_upload_files": [
+        "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
+        "{objdir}/dist/b2g-*.tar.gz",
+        "{workdir}/sources.xml"
+    ],
+    "zip_files": [
+        ["{workdir}/out/target/product/scx15_sp7715ga/*.img", "out/target/product/scx15_sp7715ga/"],
+        "{workdir}/flash.sh",
+        "{workdir}/load-config.sh",
+        "{workdir}/.config",
+        "{workdir}/sources.xml"
+    ],
+    "env": {
+        "VARIANT": "user",
+        "MOZILLA_OFFICIAL": "1"
+    },
+    "b2g_manifest": "dolphin.xml",
+    "b2g_manifest_intree": true,
+    "additional_source_tarballs": [],
+    "gecko_l10n_root": "https://hg.mozilla.org/l10n-central",
+    "gaia": {
+        "l10n": {
+            "vcs": "hgtool",
+            "root": "https://hg.mozilla.org/gaia-l10n"
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/b2g/config/dolphin/sources.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
+  <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
+  <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
+  <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was git://github.com/apitrace/-->
+  <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
+  <!--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="1865c6639c51f0290d5778adef146147d5d6a5f0">
+    <copyfile dest="Makefile" src="core/root.mk"/>
+  </project>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="33d4b999f464fbad1c23d488da4689c5de9967ec"/>
+  <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
+  <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
+  <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
+  <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="0688d2e417602961fec3847db1d0788cd0bd49a4"/>
+  <!-- Stock Android things -->
+  <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
+  <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
+  <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
+  <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
+  <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
+  <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
+  <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
+  <project name="device/sample" path="device/sample" revision="1a3d8efa0ad32ec8f145367a3cf0f54b97385c3c"/>
+  <project name="platform/abi/cpp" path="abi/cpp" revision="18f1b5e28734183ff8073fe86dc46bc4ebba8a59"/>
+  <project name="platform/bionic" path="bionic" revision="86b1f589c313422a7da1812512b9ec8d1cf9ba3c"/>
+  <project name="platform/bootable/recovery" path="bootable/recovery" revision="1f68d4c6a5d2e72bc02fa837af94c0a51afa94de"/>
+  <project name="platform/external/aac" path="external/aac" revision="fa3eba16446cc8f2f5e2dfc20d86a49dbd37299e"/>
+  <project name="platform/external/bison" path="external/bison" revision="c2418b886165add7f5a31fc5609f0ce2d004a90e"/>
+  <project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="c50830cae1b748024eec7e73ad98a4e427f663c7"/>
+  <project name="platform/external/bsdiff" path="external/bsdiff" revision="23e322ab19fb7d74c2c37e40ce364d9f709bdcee"/>
+  <project name="platform/external/bzip2" path="external/bzip2" revision="1cb636bd8e9e5cdfd5d5b2909a122f6e80db62de"/>
+  <project name="platform/external/checkpolicy" path="external/checkpolicy" revision="0d73ef7049feee794f14cf1af88d05dae8139914"/>
+  <project name="platform/external/dhcpcd" path="external/dhcpcd" revision="84b7252b0a9d0edc9a1db1e0c518771d26b23058"/>
+  <project name="platform/external/dnsmasq" path="external/dnsmasq" revision="41d356427a632f5336384bfa45c8420ffc274f66"/>
+  <project name="platform/external/dropbear" path="external/dropbear" revision="a34ddbe3819bc465968f3676c734b405e655f8b7"/>
+  <project name="platform/external/e2fsprogs" path="external/e2fsprogs" revision="47478a2944a2a17c7fdebe9d92573db92013125c"/>
+  <project name="platform/external/elfutils" path="external/elfutils" revision="b23b2dfb354b3ccf5d1c5d39815f02e7048cf516"/>
+  <project name="platform/external/expat" path="external/expat" revision="0af0cb3bc7519e567bd9daff3dcd315ab0134a99"/>
+  <project name="platform/external/fdlibm" path="external/fdlibm" revision="0da5f683c9ddc9442af3b389b4220e91ccffb320"/>
+  <project name="platform/external/flac" path="external/flac" revision="ab37b6247df0e8c4ec0ccaa870e667f62c74975b"/>
+  <project name="platform/external/freetype" path="external/freetype" revision="899c67b6cfcd2010784fbf08c5415af16c526e0c"/>
+  <project name="platform/external/gcc-demangle" path="external/gcc-demangle" revision="9241386b62c353302c2f9eccda0672685b252b4d"/>
+  <project name="platform/external/genext2fs" path="external/genext2fs" revision="e11a9c7fe6f1cef99aad2f25afaea37b72fe9f93"/>
+  <project name="platform/external/giflib" path="external/giflib" revision="9aef3ea079a57c98a9207f8c3b95a5dc08ee74b5"/>
+  <project name="platform/external/gtest" path="external/gtest" revision="0f1ce3dd0b880b6ae0cf7f5413702b8ef542efb2"/>
+  <project name="platform/external/harfbuzz" path="external/harfbuzz" revision="858f2d28ac741ef139f74bdbdbcefa7560f17c91"/>
+  <project name="platform/external/harfbuzz_ng" path="external/harfbuzz_ng" revision="3309edccdbc2a92eb03a285abb27c1c1c4a88e43"/>
+  <project name="platform/external/iproute2" path="external/iproute2" revision="157d428913c3d738be481f12e8cbf9267b3b2862"/>
+  <project name="platform/external/ipsec-tools" path="external/ipsec-tools" revision="f4cb1ee4b00abbfb6f968dc25818c23b4b47e584"/>
+  <project name="platform/external/iptables" path="external/iptables" revision="93e814c9b08136846335ce463192d90ba59766bb"/>
+  <project name="platform/external/jack" path="external/jack" revision="5ceb2025ac5d25ed48183ac2d3dac4691fe761fb"/>
+  <project name="platform/external/jhead" path="external/jhead" revision="31b17e69a87e4caa50f9c6b1a47c84ef75f79d83"/>
+  <project name="platform/external/jpeg" path="external/jpeg" revision="68f6f73d3157cc0481826e03d0fae9586217a300"/>
+  <project name="platform/external/junit" path="external/junit" revision="3abf41974d8aae44b3bbd15d83487894253d287d"/>
+  <project name="platform/external/libgsm" path="external/libgsm" revision="50761abed8f4734970874165b386cfd4d9599db4"/>
+  <project name="platform/external/liblzf" path="external/liblzf" revision="6946aa575b0949d045722794850896099d937cbb"/>
+  <project name="platform/external/libnfc-nxp" path="external/libnfc-nxp" revision="9e987ccb716624d658f98abc7db2097e11e3d8ed"/>
+  <project name="platform/external/libnl-headers" path="external/libnl-headers" revision="6ccf7349d61f73ac26a0675d735d903ab919c658"/>
+  <project name="platform/external/libogg" path="external/libogg" revision="ec0b24fb1468abe37be4164a6feb16568e036bde"/>
+  <project name="platform/external/libpcap" path="external/libpcap" revision="3a7bce5dda6a8db92c9248846d0255e68c3a5b2a"/>
+  <project name="platform/external/libpng" path="external/libpng" revision="b5e7fb4c103b3898cb78e9f7615cf7893626a5e9"/>
+  <project name="platform/external/libselinux" path="external/libselinux" revision="1e2cf2c4a2d15a9b1ca2d353b99fb6884413ffe1"/>
+  <project name="platform/external/libsepol" path="external/libsepol" revision="8fd7c65a336d45d5225f32363a9f26c1e3e60c3c"/>
+  <project name="platform/external/libvpx" path="external/libvpx" revision="5e563eddf3e143a4b670766b49f676ce39023322"/>
+  <project name="platform/external/mdnsresponder" path="external/mdnsresponder" revision="c46f53f5e072f23051c4eedef730386f7634dc11"/>
+  <project name="platform/external/mksh" path="external/mksh" revision="f8c396c4d446a038358106a301b329607a04633d"/>
+  <project name="platform/external/netcat" path="external/netcat" revision="444644cfa9a2f3002863caa168fb2d6b34dfd1e8"/>
+  <project name="platform/external/netperf" path="external/netperf" revision="58ecd3b7c76263900e38921360e334a416aec362"/>
+  <project name="platform/external/openssl" path="external/openssl" revision="bb8428f762b3632f493572c4f73957e1281ade79"/>
+  <project name="platform/external/protobuf" path="external/protobuf" revision="48ee66d295979372ed0234cefda42385daae8312"/>
+  <project name="platform/external/safe-iop" path="external/safe-iop" revision="aa0725fb1da35e47676b6da30009322eb5ed59be"/>
+  <project name="platform/external/scrypt" path="external/scrypt" revision="eb05b73c3bba21fff55529813109de4bad5ddbd1"/>
+  <project name="platform/external/sepolicy" path="external/sepolicy" revision="f3525622103090156a6bbd9a8609be8b009d223f"/>
+  <project name="platform/external/sfntly" path="external/sfntly" revision="30d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cd"/>
+  <project name="platform/external/skia" path="external/skia" revision="97c714a01e32e6aee7faf9c57fbbd4d95b41d353"/>
+  <project name="platform/external/sonivox" path="external/sonivox" revision="2dbbd3bac0f0e819d196a80cc7855054148ef8b6"/>
+  <project name="platform/external/speex" path="external/speex" revision="fb7db5853ffb841a4d32fea8b5c3a43e6b875cae"/>
+  <project name="platform/external/sqlite" path="external/sqlite" revision="ac0e0d5f866fbce0ebf00d0ddd615464849aa83b"/>
+  <project name="platform/external/stlport" path="external/stlport" revision="628e14d37c5b239839a466e81c74bf66255b770b"/>
+  <project name="platform/external/strace" path="external/strace" revision="1a4e05d53dec658a061acb9869cb1eb1342cd09d"/>
+  <project name="platform/external/svox" path="external/svox" revision="838228cc17b5798e51bc20d06e54dbd781e441db"/>
+  <project name="platform/external/tagsoup" path="external/tagsoup" revision="68c2ec9e0acdb3214b7fb91dbab8c9fab8736817"/>
+  <project name="platform/external/tcpdump" path="external/tcpdump" revision="532b8f38c144da9a298260a5d8978ab9e8e3856c"/>
+  <project name="platform/external/tinyalsa" path="external/tinyalsa" revision="aa08b9c35638a32de0444a940cf47708e4ba0eda"/>
+  <project name="platform/external/tinycompress" path="external/tinycompress" revision="a85e245a09c028d36cbf04f233be10bc583691f5"/>
+  <project name="platform/external/tinyxml" path="external/tinyxml" revision="494e448824844d866e805831d1d5f5acb654065c"/>
+  <project name="platform/external/tinyxml2" path="external/tinyxml2" revision="c74b546f5af36968ffa56d7fd4529f4273b96f48"/>
+  <project name="platform/external/tremolo" path="external/tremolo" revision="0499204aa97d3e2978ee77d869dd033acb2196e2"/>
+  <project name="platform/external/webp" path="external/webp" revision="513e97bd307573e2adc776eb5368bd129aceaa4a"/>
+  <project name="platform/external/webrtc" path="external/webrtc" revision="446452f84e9cc4c75d8e80f6f05e24793397a19d"/>
+  <project name="platform/external/yaffs2" path="external/yaffs2" revision="a2cff2275e1b501ff478b03757d6e4f05fddc2db"/>
+  <project name="platform/external/zlib" path="external/zlib" revision="a5c7131da47c991585a6c6ac0c063b6d7d56e3fc"/>
+  <project name="platform/frameworks/base" path="frameworks/base" revision="2d12cb68a6c680e1ef50c6fbd19f782f67aec9de"/>
+  <project name="platform/frameworks/native" path="frameworks/native" revision="b6018ccb81af66e0523a4bfdc45f0bd2ab472b55"/>
+  <project name="platform/frameworks/opt/emoji" path="frameworks/opt/emoji" revision="dbbe673145107e99883f62bafd70c5f43f11065c"/>
+  <project name="platform/frameworks/wilhelm" path="frameworks/wilhelm" revision="aac6c4bb59a6577c97cbda68699829b507b7490d"/>
+  <project name="platform/hardware/libhardware" path="hardware/libhardware" revision="fbeca55f4695dd07c0291213403533b8fbca4885"/>
+  <project name="platform/hardware/libhardware_legacy" path="hardware/libhardware_legacy" revision="6e98e2d0762a8e6dc12df228261fd741db98531f"/>
+  <project name="platform/libcore" path="libcore" revision="e195beab082c09217318fc19250caeaf4c1bd800"/>
+  <project name="platform/libnativehelper" path="libnativehelper" revision="feeb36c2bd4adfe285f98f5de92e0f3771b2c115"/>
+  <project name="platform/ndk" path="ndk" revision="e58ef003be4306bb53a8c11331146f39e4eab31f"/>
+  <project name="platform/prebuilts/misc" path="prebuilts/misc" revision="ee724654c72825f8d732ba45caf75ca59e06975d"/>
+  <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
+  <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="1a982dd6b02b939c75cd116d2d9de97e6ff3de24"/>
+  <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="cfcef469537869947abb9aa1d656774cc2678d4c"/>
+  <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
+  <project name="platform/system/extras" path="system/extras" revision="10e78a05252b3de785f88c2d0b9ea8a428009c50"/>
+  <project name="platform/system/media" path="system/media" revision="7ff72c2ea2496fa50b5e8a915e56e901c3ccd240"/>
+  <project name="platform/system/netd" path="system/netd" revision="3ae56364946d4a5bf5a5f83f12f9a45a30398e33"/>
+  <project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
+  <project name="platform/system/vold" path="system/vold" revision="118dec582647895a863dbbce8ec26bc7af457bbe"/>
+  <!--original fetch url was http://sprdsource.spreadtrum.com:8085/b2g/android-->
+  <remote fetch="https://git.mozilla.org/external/sprd-aosp" name="sprd-aosp"/>
+  <default remote="sprd-aosp" revision="sprdb2g_gonk4.4" sync-j="4"/>
+  <!-- Stock Android things -->
+  <project name="platform/external/icu4c" path="external/icu4c" revision="2bb01561780583cc37bc667f0ea79f48a122d8a2"/>
+  <!-- dolphin specific things -->
+  <project name="device/sprd" path="device/sprd" revision="054d217fc6efdeff296742b58b5bda427d9d4384"/>
+  <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="4e58336019b5cbcfd134caf55b142236cf986618"/>
+  <project name="platform/frameworks/av" path="frameworks/av" revision="cbd80d8c03fc639dd810b17c4b682c67abc06ee8"/>
+  <project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/>
+  <project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/>
+  <project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/>
+  <project name="kernel/common" path="kernel" revision="7cd1a292befc685e8be55996cedad1386037cbea"/>
+  <project name="platform/system/core" path="system/core" revision="b5de04ae22343b6bdaa3455aee291bdf9a872738"/>
+  <project name="u-boot" path="u-boot" revision="81522506a5ade829a18bcc8d1f1813129010b6fe"/>
+  <project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="7feb3df0e150053e0143ef525f6e082bda320aea"/>
+  <project name="vendor/sprd/open-source" path="vendor/sprd/open-source" revision="da06ca296bccf13e1f775ca5e7ba9b6d98069fc8"/>
+  <project name="vendor/sprd/partner" path="vendor/sprd/partner" revision="8649c7145972251af11b0639997edfecabfc7c2e"/>
+  <project name="vendor/sprd/proprietories" path="vendor/sprd/proprietories" revision="d994b716d979a5b57b11a61cc05d31fe7ca61d38"/>
+</manifest>
--- 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="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="df39c463259d348396ef7f143c2c780eeb8f02d8"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="33d4b999f464fbad1c23d488da4689c5de9967ec"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="f0592d4814d738e3f8d840915ef799c13601bdef"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0688d2e417602961fec3847db1d0788cd0bd49a4"/>
   <!-- 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="7eef86294cd794ab9e6a53d218c238bfc63c3a6d">
     <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="df39c463259d348396ef7f143c2c780eeb8f02d8"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="33d4b999f464fbad1c23d488da4689c5de9967ec"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0688d2e417602961fec3847db1d0788cd0bd49a4"/>
   <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="1865c6639c51f0290d5778adef146147d5d6a5f0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="df39c463259d348396ef7f143c2c780eeb8f02d8"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="33d4b999f464fbad1c23d488da4689c5de9967ec"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <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="0688d2e417602961fec3847db1d0788cd0bd49a4"/>
--- 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="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="df39c463259d348396ef7f143c2c780eeb8f02d8"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="33d4b999f464fbad1c23d488da4689c5de9967ec"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="f0592d4814d738e3f8d840915ef799c13601bdef"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0688d2e417602961fec3847db1d0788cd0bd49a4"/>
   <!-- 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
@@ -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="7eef86294cd794ab9e6a53d218c238bfc63c3a6d">
     <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="df39c463259d348396ef7f143c2c780eeb8f02d8"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="33d4b999f464fbad1c23d488da4689c5de9967ec"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0688d2e417602961fec3847db1d0788cd0bd49a4"/>
   <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": "0aa0d2ae3f0ee2215c18808c88d9366666536e9b", 
+    "revision": "03a4bc3b7d10bcc197511ac7accdb05346a0b9dd", 
     "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="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="df39c463259d348396ef7f143c2c780eeb8f02d8"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="33d4b999f464fbad1c23d488da4689c5de9967ec"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <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="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0688d2e417602961fec3847db1d0788cd0bd49a4"/>
   <!-- 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="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="df39c463259d348396ef7f143c2c780eeb8f02d8"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="33d4b999f464fbad1c23d488da4689c5de9967ec"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <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="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <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="7eef86294cd794ab9e6a53d218c238bfc63c3a6d">
     <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="df39c463259d348396ef7f143c2c780eeb8f02d8"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="33d4b999f464fbad1c23d488da4689c5de9967ec"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0688d2e417602961fec3847db1d0788cd0bd49a4"/>
   <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="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="df39c463259d348396ef7f143c2c780eeb8f02d8"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="33d4b999f464fbad1c23d488da4689c5de9967ec"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <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="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0688d2e417602961fec3847db1d0788cd0bd49a4"/>
   <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/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -975,17 +975,21 @@ pref("browser.safebrowsing.gethashURL", 
 pref("browser.safebrowsing.reportURL", "https://safebrowsing.google.com/safebrowsing/report?");
 pref("browser.safebrowsing.reportGenericURL", "http://%LOCALE%.phish-generic.mozilla.com/?hl=%LOCALE%");
 pref("browser.safebrowsing.reportErrorURL", "http://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%");
 pref("browser.safebrowsing.reportPhishURL", "http://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%");
 pref("browser.safebrowsing.reportMalwareURL", "http://%LOCALE%.malware-report.mozilla.com/?hl=%LOCALE%");
 pref("browser.safebrowsing.reportMalwareErrorURL", "http://%LOCALE%.malware-error.mozilla.com/?hl=%LOCALE%");
 
 pref("browser.safebrowsing.malware.reportURL", "https://safebrowsing.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
+
+// Turn off remote lookups in beta and stable channel.
+#ifndef RELEASE_BUILD
 pref("browser.safebrowsing.appRepURL", "https://sb-ssl.google.com/safebrowsing/clientreport/download?key=%GOOGLE_API_KEY%");
+#endif
 
 #ifdef MOZILLA_OFFICIAL
 // Normally the "client ID" sent in updates is appinfo.name, but for
 // official Firefox releases from Mozilla we use a special identifier.
 pref("browser.safebrowsing.id", "navclient-auto-ffox");
 #endif
 
 // Name of the about: page contributed by safebrowsing to handle display of error
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -433,16 +433,23 @@ var gPopupBlockerObserver = {
 
     if (!this._reportButton && gURLBar)
       this._reportButton = document.getElementById("page-report-button");
 
     if (!gBrowser.selectedBrowser.blockedPopups) {
       // Hide the icon in the location bar (if the location bar exists)
       if (gURLBar)
         this._reportButton.hidden = true;
+
+      // Hide the notification box (if it's visible).
+      var notificationBox = gBrowser.getNotificationBox();
+      var notification = notificationBox.getNotificationWithValue("popup-blocked");
+      if (notification) {
+        notificationBox.removeNotification(notification, false);
+      }
       return;
     }
 
     if (gURLBar)
       this._reportButton.hidden = false;
 
     // Only show the notification again if we've not already shown it. Since
     // notifications are per-browser, we don't need to worry about re-adding
--- a/browser/devtools/shared/AppCacheUtils.jsm
+++ b/browser/devtools/shared/AppCacheUtils.jsm
@@ -288,17 +288,24 @@ AppCacheUtils.prototype = {
     let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
                .getService(Ci.nsIWindowMediator);
     let win = wm.getMostRecentWindow("navigator:browser");
     win.gBrowser.selectedTab = win.gBrowser.addTab(
       "about:cache-entry?storage=appcache&context=&eid=&uri=" + key);
   },
 
   clearAll: function ACU_clearAll() {
-    Services.cache.evictEntries(Ci.nsICache.STORE_OFFLINE);
+    if (!Services.prefs.getBoolPref("browser.cache.disk.enable")) {
+      throw new Error(l10n.GetStringFromName("cacheDisabled"));
+    }
+
+    let appCacheStorage = Services.cache2.appCacheStorage(LoadContextInfo.default, null);
+    appCacheStorage.asyncEvictStorage({
+      onCacheEntryDoomed: function(result) {}
+    });
   },
 
   _getManifestURI: function ACU__getManifestURI() {
     let deferred = promise.defer();
 
     let getURI = () => {
       let htmlNode = this.doc.querySelector("html[manifest]");
       if (htmlNode) {
--- a/browser/devtools/styleinspector/test/browser_computedview_select-and-copy-styles.js
+++ b/browser/devtools/styleinspector/test/browser_computedview_select-and-copy-styles.js
@@ -10,17 +10,17 @@ XPCOMUtils.defineLazyGetter(this, "osStr
   return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
 });
 
 let test = asyncTest(function*() {
   yield addTab("data:text/html;charset=utf-8,computed view copy test");
 
   info("Creating the test document");
   content.document.body.innerHTML = '<style type="text/css"> ' +
-    'span { font-variant: small-caps; color: #000000; } ' +
+    'span { font-variant-caps: small-caps; color: #000000; } ' +
     '.nomatches {color: #ff0000;}</style> <div id="first" style="margin: 10em; ' +
     'font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA">\n' +
     '<h1>Some header text</h1>\n' +
     '<p id="salutation" style="font-size: 12pt">hi.</p>\n' +
     '<p id="body" style="font-size: 12pt">I am a test-case. This text exists ' +
     'solely to provide some things to <span style="color: yellow">' +
     'highlight</span> and <span style="font-weight: bold">count</span> ' +
     'style list-items in the box at right. If you are reading this, ' +
@@ -53,17 +53,17 @@ function checkCopySelection(view) {
   range.setStart(props[1], 0);
   range.setEnd(props[3], 3);
   contentDocument.defaultView.getSelection().addRange(range);
 
   info("Checking that cssHtmlTree.siBoundCopy() returns the correct clipboard value");
 
   let expectedPattern = "font-family: helvetica,sans-serif;[\\r\\n]+" +
                         "font-size: 16px;[\\r\\n]+" +
-                        "font-variant: small-caps;[\\r\\n]*";
+                        "font-variant-caps: small-caps;[\\r\\n]*";
 
   return waitForClipboard(() => {
     fireCopyEvent(props[0]);
   }, () => {
     return checkClipboardData(expectedPattern);
   }).then(() => {}, () => {
     failedClipboard(expectedPattern);
   });
@@ -75,17 +75,17 @@ function checkSelectAll(view) {
   let contentDoc = view.styleDocument;
   let prop = contentDoc.querySelector(".property-view");
 
   info("Checking that _SelectAll() then copy returns the correct clipboard value");
   view._onSelectAll();
   let expectedPattern = "color: #FF0;[\\r\\n]+" +
                         "font-family: helvetica,sans-serif;[\\r\\n]+" +
                         "font-size: 16px;[\\r\\n]+" +
-                        "font-variant: small-caps;[\\r\\n]*";
+                        "font-variant-caps: small-caps;[\\r\\n]*";
 
   return waitForClipboard(() => {
     fireCopyEvent(prop);
   }, () => {
     return checkClipboardData(expectedPattern);
   }).then(() => {}, () => {
     failedClipboard(expectedPattern);
   });
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -811,16 +811,17 @@ bin/libfreebl_32int64_3.so
 @BINPATH@/webapprt/chrome/@AB_CD@@JAREXT@
 @BINPATH@/webapprt/chrome/@AB_CD@.manifest
 @BINPATH@/webapprt/components/CommandLineHandler.js
 @BINPATH@/webapprt/components/ContentPermission.js
 @BINPATH@/webapprt/components/DirectoryProvider.js
 @BINPATH@/webapprt/components/PaymentUIGlue.js
 @BINPATH@/webapprt/components/components.manifest
 @BINPATH@/webapprt/defaults/preferences/prefs.js
+@BINPATH@/webapprt/modules/DownloadView.jsm
 @BINPATH@/webapprt/modules/Startup.jsm
 @BINPATH@/webapprt/modules/WebappRT.jsm
 @BINPATH@/webapprt/modules/WebappManager.jsm
 @BINPATH@/webapprt/modules/RemoteDebugger.jsm
 @BINPATH@/webapprt/modules/WebRTCHandler.jsm
 #endif
 
 #ifdef MOZ_METRO
--- a/build/sanitizers/lsan_suppressions.txt
+++ b/build/sanitizers/lsan_suppressions.txt
@@ -23,22 +23,53 @@ leak:pixman_implementation_lookup_compos
 
 # Bug 987918 - Font shutdown leaks when CLEANUP_MEMORY is not enabled.
 leak:libfontconfig.so
 leak:GI___strdup
 # The symbol is really __GI___strdup, but if you have the leading _, it doesn't suppress it.
 
 
 ###
-### Many leaks only affect some test suites.  The suite annotations are not checked.
+### Bug 979928 - WebRTC leaks. m2, m3.
 ###
 
-# Bug 979928 - WebRTC is leaky. m2, m3
-leak:/media/mtransport/
-leak:/media/webrtc/signaling/
+# WebRTC leaks added for Mochitest 2.
+leak:NR_reg_init
+leak:fsmdef_init
+leak:r_log_register
+leak:nr_reg_set
+leak:ccsnap_device_init
+leak:ccsnap_line_init
+leak:media/webrtc/signaling/src/sipcc/core/common/init.c
+leak:cprPostMessage
+leak:mozilla::NrIceStunServer::Create
+
+# Additional WebRTC leak suppressions added for Mochitest 3.
+leak:mozilla::TransportLayerDtls::Setup
+leak:mozilla::NrIceTurnServer::Create
+# There are about 228KB of leaks from the call to |pmsg->sdp = cpr_malloc(sdp_size);|
+# in send_message_helper.
+leak:send_message_helper
+leak:fsmdef_ev_createoffer
+leak:fsmdef_ev_setremotedesc
+leak:fsmdef_ev_setlocaldesc
+leak:fsmdef_ev_createanswer
+# About 70KB of leaks under this stack.
+leak:vcmRxAllocICE_s
+leak:vcmRxStartICE_m
+# About 50KB of leaks under this stack.
+leak:ccsnap_EscapeStrToLocaleStr
+leak:gsmsdp_add_default_audio_formats_to_local_sdp
+leak:gsmsdp_add_default_video_formats_to_local_sdp
+leak:CCAPI_CallInfo_getMediaStreams
+
+
+###
+### Many leaks only affect some test suites.  The suite annotations are not checked.
+###
 
 # Bug 981195 - Small leak in the parser. m4
 leak:TypeCompartment::fixObjectType
 
 # Bug 982111 - WebM is leaking. m1
 leak:nestegg_read_packet
 
 # Bug 987385 - Various plugin leaks. m3
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -723,30 +723,30 @@ public:
   void ScrollIntoView()
   {
     ScrollIntoView(true);
   }
   void ScrollIntoView(bool aTop);
   int32_t ScrollTop()
   {
     nsIScrollableFrame* sf = GetScrollFrame();
-    return sf ? sf->GetScrollPositionCSSPixels().y : 0;
+    return sf ? sf->GetScrollPositionCSSPixels().y.value : 0;
   }
   void SetScrollTop(int32_t aScrollTop)
   {
     nsIScrollableFrame* sf = GetScrollFrame();
     if (sf) {
       sf->ScrollToCSSPixels(CSSIntPoint(sf->GetScrollPositionCSSPixels().x,
                                         aScrollTop));
     }
   }
   int32_t ScrollLeft()
   {
     nsIScrollableFrame* sf = GetScrollFrame();
-    return sf ? sf->GetScrollPositionCSSPixels().x : 0;
+    return sf ? sf->GetScrollPositionCSSPixels().x.value : 0;
   }
   void SetScrollLeft(int32_t aScrollLeft)
   {
     nsIScrollableFrame* sf = GetScrollFrame();
     if (sf) {
       sf->ScrollToCSSPixels(CSSIntPoint(aScrollLeft,
                                         sf->GetScrollPositionCSSPixels().y));
     }
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -400,54 +400,27 @@ public:
   static bool CanCallerAccess(nsIDOMNode *aNode);
   static bool CanCallerAccess(nsINode* aNode);
 
   // Check if the (JS) caller can access aWindow.
   // aWindow can be either outer or inner window.
   static bool CanCallerAccess(nsPIDOMWindow* aWindow);
 
   /**
-   * Get the window through the JS context that's currently on the stack.
-   * If there's no JS context currently on the stack, returns null.
-   */
-  static nsPIDOMWindow *GetWindowFromCaller();
-
-  /**
-   * The two GetDocumentFrom* functions below allow a caller to get at a
-   * document that is relevant to the currently executing script.
-   *
    * GetDocumentFromCaller gets its document by looking at the last called
    * function and finding the document that the function itself relates to.
    * For example, consider two windows A and B in the same origin. B has a
    * function which does something that ends up needing the current document.
    * If a script in window A were to call B's function, GetDocumentFromCaller
    * would find that function (in B) and return B's document.
    *
-   * GetDocumentFromContext gets its document by looking at the currently
-   * executing context's global object and returning its document. Thus,
-   * given the example above, GetDocumentFromCaller would see that the
-   * currently executing script was in window A, and return A's document.
-   */
-  /**
-   * Get the document from the currently executing function. This will return
-   * the document that the currently executing function is in/from.
-   *
    * @return The document or null if no JS Context.
    */
   static nsIDocument* GetDocumentFromCaller();
 
-  /**
-   * Get the document through the JS context that's currently on the stack.
-   * If there's no JS context currently on the stack it will return null.
-   * This will return the document of the calling script.
-   *
-   * @return The document or null if no JS context
-   */
-  static nsIDocument* GetDocumentFromContext();
-
   // Check if a node is in the document prolog, i.e. before the document
   // element.
   static bool InProlog(nsINode *aNode);
 
   static nsIParserService* GetParserService();
 
   static nsNameSpaceManager* NameSpaceManager()
   {
@@ -2274,19 +2247,17 @@ private:
 
   static nsILineBreaker* sLineBreaker;
   static nsIWordBreaker* sWordBreaker;
 
   static nsIBidiKeyboard* sBidiKeyboard;
 
   static bool sInitialized;
   static uint32_t sScriptBlockerCount;
-#ifdef DEBUG
   static uint32_t sDOMNodeRemovedSuppressCount;
-#endif
   static uint32_t sMicroTaskLevel;
   // Not an nsCOMArray because removing elements from those is slower
   static nsTArray< nsCOMPtr<nsIRunnable> >* sBlockedScriptRunners;
   static uint32_t sRunnersCountAtFirstBlocker;
   static uint32_t sScriptBlockerCountWhereRunnersPrevented;
 
   static nsIInterfaceRequestor* sSameOriginChecker;
 
@@ -2333,24 +2304,20 @@ public:
 private:
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 class MOZ_STACK_CLASS nsAutoScriptBlockerSuppressNodeRemoved :
                           public nsAutoScriptBlocker {
 public:
   nsAutoScriptBlockerSuppressNodeRemoved() {
-#ifdef DEBUG
     ++nsContentUtils::sDOMNodeRemovedSuppressCount;
-#endif
   }
   ~nsAutoScriptBlockerSuppressNodeRemoved() {
-#ifdef DEBUG
     --nsContentUtils::sDOMNodeRemovedSuppressCount;
-#endif
   }
 };
 
 class MOZ_STACK_CLASS nsAutoMicroTask
 {
 public:
   nsAutoMicroTask()
   {
--- a/content/base/public/nsINodeList.h
+++ b/content/base/public/nsINodeList.h
@@ -3,19 +3,17 @@
  * 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/. */
 
 #ifndef nsINodeList_h___
 #define nsINodeList_h___
 
 #include "nsIDOMNodeList.h"
 #include "nsWrapperCache.h"
-
-class nsIContent;
-class nsINode;
+#include "nsIContent.h"
 
 // IID for the nsINodeList interface
 #define NS_INODELIST_IID \
 { 0xadb5e54c, 0x6e96, 0x4102, \
  { 0x8d, 0x40, 0xe0, 0x12, 0x3d, 0xcf, 0x48, 0x7a } }
 
 /**
  * An internal interface for a reasonably fast indexOf.
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -681,17 +681,17 @@ WebSocket::Init(JSContext* aCx,
 
   // Don't allow https:// to open ws://
   if (!mSecure &&
       !Preferences::GetBool("network.websocket.allowInsecureFromHTTPS",
                             false)) {
     // Confirmed we are opening plain ws:// and want to prevent this from a
     // secure context (e.g. https). Check the principal's uri to determine if
     // we were loaded from https.
-    nsCOMPtr<nsIGlobalObject> globalObject(BrokenGetEntryGlobal());
+    nsCOMPtr<nsIGlobalObject> globalObject(GetEntryGlobal());
     if (globalObject) {
       nsCOMPtr<nsIPrincipal> principal(globalObject->PrincipalOrNull());
       if (principal) {
         nsCOMPtr<nsIURI> uri;
         principal->GetURI(getter_AddRefs(uri));
         if (uri) {
           bool originIsHttps = false;
           rv = uri->SchemeIs("https", &originIsHttps);
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -209,19 +209,17 @@ nsCOMArray<nsIAtom>* nsContentUtils::sUs
 nsIStringBundleService *nsContentUtils::sStringBundleService;
 nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT];
 nsIContentPolicy *nsContentUtils::sContentPolicyService;
 bool nsContentUtils::sTriedToGetContentPolicy = false;
 nsILineBreaker *nsContentUtils::sLineBreaker;
 nsIWordBreaker *nsContentUtils::sWordBreaker;
 nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nullptr;
 uint32_t nsContentUtils::sScriptBlockerCount = 0;
-#ifdef DEBUG
 uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0;
-#endif
 uint32_t nsContentUtils::sMicroTaskLevel = 0;
 nsTArray< nsCOMPtr<nsIRunnable> >* nsContentUtils::sBlockedScriptRunners = nullptr;
 uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0;
 nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nullptr;
 
 bool nsContentUtils::sIsHandlingKeyBoardEvent = false;
 bool nsContentUtils::sAllowXULXBL_for_file = false;
 
@@ -1948,61 +1946,30 @@ nsContentUtils::TraceSafeJSContext(JSTra
   }
   if (JSObject* global = js::DefaultObjectForContextOrNull(cx)) {
     JS::AssertGCThingMustBeTenured(global);
     JS_CallUnbarrieredObjectTracer(aTrc, &global, "safe context");
     MOZ_ASSERT(global == js::DefaultObjectForContextOrNull(cx));
   }
 }
 
-nsPIDOMWindow *
-nsContentUtils::GetWindowFromCaller()
-{
-  JSContext *cx = GetCurrentJSContext();
-  if (cx) {
-    nsCOMPtr<nsPIDOMWindow> win =
-      do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
-    return win;
-  }
-
-  return nullptr;
-}
-
 nsIDocument*
 nsContentUtils::GetDocumentFromCaller()
 {
   AutoJSContext cx;
 
   nsCOMPtr<nsPIDOMWindow> win =
     do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(cx)));
   if (!win) {
     return nullptr;
   }
 
   return win->GetExtantDoc();
 }
 
-nsIDocument*
-nsContentUtils::GetDocumentFromContext()
-{
-  JSContext *cx = GetCurrentJSContext();
-  if (cx) {
-    nsIScriptGlobalObject *sgo = nsJSUtils::GetDynamicScriptGlobal(cx);
-
-    if (sgo) {
-      nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(sgo);
-      if (pwin) {
-        return pwin->GetExtantDoc();
-      }
-    }
-  }
-
-  return nullptr;
-}
-
 bool
 nsContentUtils::IsCallerChrome()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (SubjectPrincipal() == sSystemPrincipal) {
     return true;
   }
 
@@ -3915,40 +3882,37 @@ nsContentUtils::HasMutationListeners(nsI
 void
 nsContentUtils::MaybeFireNodeRemoved(nsINode* aChild, nsINode* aParent,
                                      nsIDocument* aOwnerDoc)
 {
   NS_PRECONDITION(aChild, "Missing child");
   NS_PRECONDITION(aChild->GetParentNode() == aParent, "Wrong parent");
   NS_PRECONDITION(aChild->OwnerDoc() == aOwnerDoc, "Wrong owner-doc");
 
-  // This checks that IsSafeToRunScript is true since we don't want to fire
-  // events when that is false. We can't rely on EventDispatcher to assert
-  // this in this situation since most of the time there are no mutation
-  // event listeners, in which case we won't even attempt to dispatch events.
-  // However this also allows for two exceptions. First off, we don't assert
-  // if the mutation happens to native anonymous content since we never fire
-  // mutation events on such content anyway.
-  // Second, we don't assert if sDOMNodeRemovedSuppressCount is true since
-  // that is a know case when we'd normally fire a mutation event, but can't
-  // make that safe and so we suppress it at this time. Ideally this should
-  // go away eventually.
-  NS_ASSERTION((aChild->IsNodeOfType(nsINode::eCONTENT) &&
-               static_cast<nsIContent*>(aChild)->
-                 IsInNativeAnonymousSubtree()) ||
-               IsSafeToRunScript() ||
-               sDOMNodeRemovedSuppressCount,
-               "Want to fire DOMNodeRemoved event, but it's not safe");
-
   // Having an explicit check here since it's an easy mistake to fall into,
   // and there might be existing code with problems. We'd rather be safe
   // than fire DOMNodeRemoved in all corner cases. We also rely on it for
   // nsAutoScriptBlockerSuppressNodeRemoved.
   if (!IsSafeToRunScript()) {
-    WarnScriptWasIgnored(aOwnerDoc);
+    // This checks that IsSafeToRunScript is true since we don't want to fire
+    // events when that is false. We can't rely on EventDispatcher to assert
+    // this in this situation since most of the time there are no mutation
+    // event listeners, in which case we won't even attempt to dispatch events.
+    // However this also allows for two exceptions. First off, we don't assert
+    // if the mutation happens to native anonymous content since we never fire
+    // mutation events on such content anyway.
+    // Second, we don't assert if sDOMNodeRemovedSuppressCount is true since
+    // that is a know case when we'd normally fire a mutation event, but can't
+    // make that safe and so we suppress it at this time. Ideally this should
+    // go away eventually.
+    if (!(aChild->IsContent() && aChild->AsContent()->IsInNativeAnonymousSubtree()) &&
+        !sDOMNodeRemovedSuppressCount) {
+      NS_ERROR("Want to fire DOMNodeRemoved event, but it's not safe");
+      WarnScriptWasIgnored(aOwnerDoc);
+    }
     return;
   }
 
   if (HasMutationListeners(aChild,
         NS_EVENT_BITS_MUTATION_NODEREMOVED, aParent)) {
     InternalMutationEvent mutation(true, NS_MUTATION_NODEREMOVED);
     mutation.mRelatedNode = do_QueryInterface(aParent);
 
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -1424,20 +1424,20 @@ nsHTMLDocument::Open(JSContext* cx,
 
   bool inUnload;
   shell->GetIsInUnload(&inUnload);
   if (inUnload) {
     nsCOMPtr<nsIDocument> ret = this;
     return ret.forget();
   }
 
-  // Note: We want to use GetDocumentFromContext here because this document
+  // Note: We want to use GetEntryDocument here because this document
   // should inherit the security information of the document that's opening us,
   // (since if it's secure, then it's presumably trusted).
-  nsCOMPtr<nsIDocument> callerDoc = nsContentUtils::GetDocumentFromContext();
+  nsCOMPtr<nsIDocument> callerDoc = GetEntryDocument();
   if (!callerDoc) {
     // If we're called from C++ or in some other way without an originating
     // document we can't do a document.open w/o changing the principal of the
     // document to something like about:blank (as that's the only sane thing to
     // do when we don't know the origin of this call), and since we can't
     // change the principals of a document for security reasons we'll have to
     // refuse to go ahead with this call.
 
--- a/content/media/gmp/GMPChild.cpp
+++ b/content/media/gmp/GMPChild.cpp
@@ -123,24 +123,25 @@ GMPChild::Init(const std::string& aPlugi
                base::ProcessHandle aParentProcessHandle,
                MessageLoop* aIOLoop,
                IPC::Channel* aChannel)
 {
   if (!Open(aChannel, aParentProcessHandle, aIOLoop)) {
     return false;
   }
 
+#ifdef MOZ_CRASHREPORTER
+  SendPCrashReporterConstructor(CrashReporter::CurrentThreadId());
+#endif
+
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
   mPluginPath = aPluginPath;
   return true;
 #endif
 
-#ifdef MOZ_CRASHREPORTER
-  SendPCrashReporterConstructor(CrashReporter::CurrentThreadId());
-#endif
 #if defined(XP_WIN)
   mozilla::SandboxTarget::Instance()->StartSandbox();
 #endif
 
   return LoadPluginLibrary(aPluginPath);
 }
 
 bool
--- a/content/media/mediasource/SourceBufferResource.h
+++ b/content/media/mediasource/SourceBufferResource.h
@@ -70,34 +70,30 @@ private:
       return nullptr;
     }
   };
 
   class ResourceQueue : private nsDeque {
   public:
     ResourceQueue() :
       nsDeque(new ResourceQueueDeallocator()),
+      mLogicalLength(0),
       mOffset(0)
     {
     }
 
     // Returns the logical byte offset of the start of the data.
     inline uint64_t GetOffset() {
       return mOffset;
     }
 
     // Returns the length of all items in the queue plus the offset.
     // This is the logical length of the resource.
     inline uint64_t GetLength() {
-      uint64_t s = mOffset;
-      for (uint32_t i = 0; i < GetSize(); ++i) {
-        ResourceItem* item = ResourceAt(i);
-        s += item->mData.Length();
-      }
-      return s;
+      return mLogicalLength;
     }
 
     // Copies aCount bytes from aOffset in the queue into aDest.
     inline void CopyData(uint64_t aOffset, uint32_t aCount, char* aDest) {
       uint32_t offset = 0;
       uint32_t start = GetAtOffset(aOffset, &offset);
       uint32_t end = std::min(GetAtOffset(aOffset + aCount, nullptr) + 1, GetSize());
       for (uint32_t i = start; i < end; ++i) {
@@ -108,16 +104,17 @@ private:
           offset = 0;
           aCount -= bytes;
           aDest += bytes;
         }
       }
     }
 
     inline void PushBack(ResourceItem* aItem) {
+      mLogicalLength += aItem->mData.Length();
       nsDeque::Push(aItem);
     }
 
     // Evict data in queue if the total queue size is greater than
     // aThreshold past the offset. Returns true if some data was
     // actually evicted.
     inline bool Evict(uint64_t aOffset, uint32_t aThreshold) {
       bool evicted = false;
@@ -179,18 +176,20 @@ private:
       }
       return GetSize();
     }
 
     inline ResourceItem* PopFront() {
       return static_cast<ResourceItem*>(nsDeque::PopFront());
     }
 
-    // Logical offset into the resource of the first element
-    // in the queue.
+    // Logical length of the resource.
+    uint64_t mLogicalLength;
+
+    // Logical offset into the resource of the first element in the queue.
     uint64_t mOffset;
   };
 
 public:
   SourceBufferResource(nsIPrincipal* aPrincipal,
                        const nsACString& aType);
 protected:
   ~SourceBufferResource();
--- a/content/media/moz.build
+++ b/content/media/moz.build
@@ -62,19 +62,16 @@ MOCHITEST_MANIFESTS += ['test/mochitest.
 MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
 
 EXPORTS += [
     'AbstractMediaDecoder.h',
     'AudioChannelFormat.h',
     'AudioCompactor.h',
     'AudioEventTimeline.h',
     'AudioMixer.h',
-    'AudioNodeEngine.h',
-    'AudioNodeExternalInputStream.h',
-    'AudioNodeStream.h',
     'AudioSampleFormat.h',
     'AudioSegment.h',
     'AudioStream.h',
     'BufferDecoder.h',
     'BufferMediaResource.h',
     'DecoderTraits.h',
     'DOMMediaStream.h',
     'EncodedBufferCache.h',
@@ -125,19 +122,16 @@ EXPORTS.mozilla.dom += [
     'VideoStreamTrack.h',
     'VideoTrack.h',
     'VideoTrackList.h',
 ]
 
 UNIFIED_SOURCES += [
     'AudioChannelFormat.cpp',
     'AudioCompactor.cpp',
-    'AudioNodeEngine.cpp',
-    'AudioNodeExternalInputStream.cpp',
-    'AudioNodeStream.cpp',
     'AudioSegment.cpp',
     'AudioSink.cpp',
     'AudioStream.cpp',
     'AudioStreamTrack.cpp',
     'AudioTrack.cpp',
     'AudioTrackList.cpp',
     'BufferDecoder.cpp',
     'DOMMediaStream.cpp',
@@ -180,20 +174,16 @@ UNIFIED_SOURCES += [
 # Latency.cpp needs to be built separately because it forces NSPR logging.
 SOURCES += [
     'DecoderTraits.cpp',
     'Latency.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
-if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['BUILD_ARM_NEON']:
-    SOURCES += ['AudioNodeEngineNEON.cpp']
-    SOURCES['AudioNodeEngineNEON.cpp'].flags += ['-mfpu=neon']
-
 MSVC_ENABLE_PGO = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/content/base/src',
     '/layout/generic',
rename from content/media/AudioNodeEngine.cpp
rename to content/media/webaudio/AudioNodeEngine.cpp
rename from content/media/AudioNodeEngine.h
rename to content/media/webaudio/AudioNodeEngine.h
rename from content/media/AudioNodeEngineNEON.cpp
rename to content/media/webaudio/AudioNodeEngineNEON.cpp
rename from content/media/AudioNodeEngineNEON.h
rename to content/media/webaudio/AudioNodeEngineNEON.h
rename from content/media/AudioNodeExternalInputStream.cpp
rename to content/media/webaudio/AudioNodeExternalInputStream.cpp
rename from content/media/AudioNodeExternalInputStream.h
rename to content/media/webaudio/AudioNodeExternalInputStream.h
rename from content/media/AudioNodeStream.cpp
rename to content/media/webaudio/AudioNodeStream.cpp
rename from content/media/AudioNodeStream.h
rename to content/media/webaudio/AudioNodeStream.h
--- a/content/media/webaudio/moz.build
+++ b/content/media/webaudio/moz.build
@@ -14,16 +14,19 @@ MOCHITEST_MANIFESTS += [
 ]
 
 MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 EXPORTS += [
     'AudioContext.h',
+    'AudioNodeEngine.h',
+    'AudioNodeExternalInputStream.h',
+    'AudioNodeStream.h',
     'AudioParamTimeline.h',
     'MediaBufferDecoder.h',
     'ThreeDPoint.h',
     'WebAudioUtils.h',
 ]
 
 EXPORTS.mozilla += [
     'FFTBlock.h',
@@ -60,16 +63,19 @@ EXPORTS.mozilla.dom += [
 UNIFIED_SOURCES += [
     'AnalyserNode.cpp',
     'AudioBuffer.cpp',
     'AudioBufferSourceNode.cpp',
     'AudioContext.cpp',
     'AudioDestinationNode.cpp',
     'AudioListener.cpp',
     'AudioNode.cpp',
+    'AudioNodeEngine.cpp',
+    'AudioNodeExternalInputStream.cpp',
+    'AudioNodeStream.cpp',
     'AudioParam.cpp',
     'AudioProcessingEvent.cpp',
     'BiquadFilterNode.cpp',
     'ChannelMergerNode.cpp',
     'ChannelSplitterNode.cpp',
     'ConvolverNode.cpp',
     'DelayBuffer.cpp',
     'DelayNode.cpp',
@@ -85,13 +91,20 @@ UNIFIED_SOURCES += [
     'PannerNode.cpp',
     'PeriodicWave.cpp',
     'ScriptProcessorNode.cpp',
     'ThreeDPoint.cpp',
     'WaveShaperNode.cpp',
     'WebAudioUtils.cpp',
 ]
 
+if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['BUILD_ARM_NEON']:
+    SOURCES += ['AudioNodeEngineNEON.cpp']
+    SOURCES['AudioNodeEngineNEON.cpp'].flags += ['-mfpu=neon']
+
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
+LOCAL_INCLUDES += [
+    '..'
+]
--- a/content/media/webaudio/test/mochitest.ini
+++ b/content/media/webaudio/test/mochitest.ini
@@ -123,16 +123,17 @@ skip-if = (toolkit == 'gonk' && !debug)
 [test_pannerNode_equalPower.html]
 [test_pannerNodeAbove.html]
 [test_pannerNodeChannelCount.html]
 [test_pannerNodeHRTFSymmetry.html]
 [test_pannerNodeTail.html]
 [test_periodicWave.html]
 [test_scriptProcessorNode.html]
 [test_scriptProcessorNodeChannelCount.html]
+[test_scriptProcessorNodePassThrough.html]
 [test_scriptProcessorNode_playbackTime1.html]
 [test_scriptProcessorNodeZeroInputOutput.html]
 [test_scriptProcessorNodeNotConnected.html]
 [test_singleSourceDest.html]
 [test_stereoPanningWithGain.html]
 [test_waveDecoder.html]
 [test_waveShaper.html]
 [test_waveShaperNoCurve.html]
--- a/content/media/webaudio/test/test_scriptProcessorNode.html
+++ b/content/media/webaudio/test/test_scriptProcessorNode.html
@@ -21,17 +21,17 @@ addLoadEvent(function() {
   var buffer = null;
 
   var sourceSP = context.createScriptProcessor(2048);
   sourceSP.addEventListener("audioprocess", function(e) {
     // generate the audio
     for (var i = 0; i < 2048; ++i) {
       // Make sure our first sample won't be zero
       e.outputBuffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * (i + 1) / context.sampleRate);
-      e.outputBuffer.getChannelData(0)[i] = Math.sin(880 * 2 * Math.PI * (i + 1) / context.sampleRate);
+      e.outputBuffer.getChannelData(1)[i] = Math.sin(880 * 2 * Math.PI * (i + 1) / context.sampleRate);
     }
     // Remember our generated audio
     buffer = e.outputBuffer;
 
     sourceSP.removeEventListener("audioprocess", arguments.callee);
   }, false);
 
   expectException(function() {
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_scriptProcessorNodePassThrough.html
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test ScriptProcessorNode with passthrough</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// We do not use our generic graph test framework here because
+// the testing logic here is sort of complicated, and would
+// not be easy to map to OfflineAudioContext, as ScriptProcessorNodes
+// can experience delays.
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  var context = new AudioContext();
+  var buffer = null;
+
+  var sourceSP = context.createScriptProcessor(2048);
+  sourceSP.addEventListener("audioprocess", function(e) {
+    // generate the audio
+    for (var i = 0; i < 2048; ++i) {
+      // Make sure our first sample won't be zero
+      e.outputBuffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * (i + 1) / context.sampleRate);
+      e.outputBuffer.getChannelData(1)[i] = Math.sin(880 * 2 * Math.PI * (i + 1) / context.sampleRate);
+    }
+    // Remember our generated audio
+    buffer = e.outputBuffer;
+
+    sourceSP.removeEventListener("audioprocess", arguments.callee);
+  }, false);
+
+  function findFirstNonZeroSample(buffer) {
+    for (var i = 0; i < buffer.length; ++i) {
+      if (buffer.getChannelData(0)[i] != 0) {
+        return i;
+      }
+    }
+    return buffer.length;
+  }
+
+  var sp = context.createScriptProcessor(2048);
+  sourceSP.connect(sp);
+
+  var spWrapped = SpecialPowers.wrap(sp);
+  ok("passThrough" in spWrapped, "ScriptProcessorNode should support the passThrough API");
+  spWrapped.passThrough = true;
+
+  sp.onaudioprocess = function() {
+    ok(false, "The audioprocess event must never be dispatched on the passthrough ScriptProcessorNode");
+  };
+
+  var sp2 = context.createScriptProcessor(2048);
+  sp.connect(sp2);
+  sp2.connect(context.destination);
+
+  var emptyBuffer = context.createBuffer(1, 2048, context.sampleRate);
+
+  sp2.onaudioprocess = function(e) {
+    // Because of the initial latency added by the second script processor node,
+    // we will never see any generated audio frames in the first callback.
+    compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
+    compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
+
+    sp2.onaudioprocess = function(e) {
+      var firstNonZero = findFirstNonZeroSample(e.inputBuffer);
+      ok(firstNonZero <= 2048, "First non-zero sample within range");
+
+      compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0), firstNonZero);
+      compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0), firstNonZero);
+      compareChannels(e.inputBuffer.getChannelData(0), buffer.getChannelData(0), 2048 - firstNonZero, firstNonZero, 0);
+      compareChannels(e.inputBuffer.getChannelData(1), buffer.getChannelData(1), 2048 - firstNonZero, firstNonZero, 0);
+
+      if (firstNonZero == 0) {
+        // If we did not experience any delays, the test is done!
+        sp2.onaudioprocess = null;
+
+        SimpleTest.finish();
+      } else if (firstNonZero != 2048) {
+        // In case we just saw a zero buffer this time, wait one more round
+        sp2.onaudioprocess = function(e) {
+          compareChannels(e.inputBuffer.getChannelData(0), buffer.getChannelData(0), firstNonZero, 0, 2048 - firstNonZero);
+          compareChannels(e.inputBuffer.getChannelData(1), buffer.getChannelData(1), firstNonZero, 0, 2048 - firstNonZero);
+          compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0), undefined, firstNonZero);
+          compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0), undefined, firstNonZero);
+
+          sp2.onaudioprocess = null;
+
+          SimpleTest.finish();
+        };
+      }
+    };
+  };
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/media/webm/WebMBufferedParser.cpp
+++ b/content/media/webm/WebMBufferedParser.cpp
@@ -55,17 +55,17 @@ void WebMBufferedParser::Append(const un
       } else {
         mClusterIDPos = 0;
       }
       // Cluster ID found, it's likely this is a valid sync point.  If this
       // is a spurious match, the later parse steps will encounter an error
       // and return to CLUSTER_SYNC.
       if (mClusterIDPos == sizeof(CLUSTER_ID)) {
         mClusterIDPos = 0;
-        mClusterOffset = mCurrentOffset + (p - aBuffer) - 1;
+        mClusterOffset = mCurrentOffset + (p - aBuffer) - sizeof(CLUSTER_ID);
         mState = READ_VINT;
         mNextState = TIMECODE_SYNC;
       }
       break;
     case READ_VINT: {
       unsigned char c = *p++;
       uint32_t mask;
       mVIntLength = VIntLength(c, &mask);
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1960,26 +1960,26 @@ Navigator::GetMozCameras(ErrorResult& aR
     }
 
     mCameraManager = nsDOMCameraManager::CreateInstance(mWindow);
   }
 
   return mCameraManager;
 }
 
-already_AddRefed<workers::ServiceWorkerContainer>
+already_AddRefed<ServiceWorkerContainer>
 Navigator::ServiceWorker()
 {
   MOZ_ASSERT(mWindow);
 
   if (!mServiceWorkerContainer) {
-    mServiceWorkerContainer = new workers::ServiceWorkerContainer(mWindow);
+    mServiceWorkerContainer = new ServiceWorkerContainer(mWindow);
   }
 
-  nsRefPtr<workers::ServiceWorkerContainer> ref = mServiceWorkerContainer;
+  nsRefPtr<ServiceWorkerContainer> ref = mServiceWorkerContainer;
   return ref.forget();
 }
 
 size_t
 Navigator::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   size_t n = aMallocSizeOf(this);
 
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -31,16 +31,17 @@ class nsIPrincipal;
 namespace mozilla {
 namespace dom {
 class Geolocation;
 class systemMessageCallback;
 struct MediaStreamConstraints;
 class WakeLock;
 class ArrayBufferViewOrBlobOrStringOrFormData;
 struct MobileIdOptions;
+class ServiceWorkerContainer;
 }
 }
 
 #ifdef MOZ_B2G_RIL
 class nsIDOMMozIccManager;
 #endif // MOZ_B2G_RIL
 
 //*****************************************************************************
@@ -99,20 +100,16 @@ class TimeManager;
 } // namespace time
 
 namespace system {
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
 class AudioChannelManager;
 #endif
 } // namespace system
 
-namespace workers {
-class ServiceWorkerContainer;
-} // namespace workers
-
 class Navigator : public nsIDOMNavigator
                 , public nsIMozNavigatorNetwork
                 , public nsWrapperCache
 {
 public:
   Navigator(nsPIDOMWindow *aInnerWindow);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -257,17 +254,17 @@ public:
                        ErrorResult& aRv);
   void MozGetUserMediaDevices(const MediaStreamConstraints& aConstraints,
                               MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
                               NavigatorUserMediaErrorCallback& aOnError,
                               uint64_t aInnerWindowID,
                               ErrorResult& aRv);
 #endif // MOZ_MEDIA_NAVIGATOR
 
-  already_AddRefed<workers::ServiceWorkerContainer> ServiceWorker();
+  already_AddRefed<ServiceWorkerContainer> ServiceWorker();
 
   bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
                     JS::Handle<jsid> aId,
                     JS::MutableHandle<JSPropertyDescriptor> aDesc);
   void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
                            ErrorResult& aRv);
   void GetLanguages(nsTArray<nsString>& aLanguages);
   void GetAcceptLanguages(nsTArray<nsString>& aLanguages);
@@ -335,17 +332,17 @@ private:
 #endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   nsRefPtr<system::AudioChannelManager> mAudioChannelManager;
 #endif
   nsRefPtr<nsDOMCameraManager> mCameraManager;
   nsCOMPtr<nsIDOMNavigatorSystemMessages> mMessagesManager;
   nsTArray<nsRefPtr<nsDOMDeviceStorage> > mDeviceStorageStores;
   nsRefPtr<time::TimeManager> mTimeManager;
-  nsRefPtr<workers::ServiceWorkerContainer> mServiceWorkerContainer;
+  nsRefPtr<ServiceWorkerContainer> mServiceWorkerContainer;
   nsCOMPtr<nsPIDOMWindow> mWindow;
 
   // Hashtable for saving cached objects newresolve created, so we don't create
   // the object twice if asked for it twice, whether due to use of "delete" or
   // due to Xrays.  We could probably use a nsJSThingHashtable here, but then
   // we'd need to figure out exactly how to trace that, and that seems to be
   // rocket science.  :(
   nsInterfaceHashtable<nsStringHashKey, nsISupports> mCachedResolveResults;
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -117,37 +117,28 @@ ScriptSettingsStackEntry::ScriptSettings
 ScriptSettingsStackEntry::~ScriptSettingsStackEntry()
 {
   // We must have an actual JS global for the entire time this is on the stack.
   MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->GetGlobalJSObject());
 
   ScriptSettingsStack::Pop(this);
 }
 
-// This mostly gets the entry global, but doesn't entirely match the spec in
-// certain edge cases. It's good enough for some purposes, but not others. If
-// you want to call this function, ping bholley and describe your use-case.
 nsIGlobalObject*
-BrokenGetEntryGlobal()
+GetEntryGlobal()
 {
-  // We need the current JSContext in order to check the JS for
-  // scripted frames that may have appeared since anyone last
-  // manipulated the stack. If it's null, that means that there
-  // must be no entry global on the stack.
-  JSContext *cx = nsContentUtils::GetCurrentJSContextForThread();
-  if (!cx) {
-    MOZ_ASSERT(ScriptSettingsStack::EntryGlobal() == nullptr);
-    return nullptr;
-  }
-
-  return nsJSUtils::GetDynamicScriptGlobal(cx);
+  return ScriptSettingsStack::EntryGlobal();
 }
 
-// Note: When we're ready to expose it, GetEntryGlobal will look similar to
-// GetIncumbentGlobal below.
+nsIDocument*
+GetEntryDocument()
+{
+  nsCOMPtr<nsPIDOMWindow> entryWin = do_QueryInterface(GetEntryGlobal());
+  return entryWin ? entryWin->GetExtantDoc() : nullptr;
+}
 
 nsIGlobalObject*
 GetIncumbentGlobal()
 {
   // We need the current JSContext in order to check the JS for
   // scripted frames that may have appeared since anyone last
   // manipulated the stack. If it's null, that means that there
   // must be no entry global on the stack, and therefore no incumbent
@@ -166,16 +157,32 @@ GetIncumbentGlobal()
     return xpc::GetNativeForGlobal(global);
   }
 
   // Ok, nothing from the JS engine. Let's use whatever's on the
   // explicit stack.
   return ScriptSettingsStack::IncumbentGlobal();
 }
 
+nsIGlobalObject*
+GetCurrentGlobal()
+{
+  JSContext *cx = nsContentUtils::GetCurrentJSContextForThread();
+  if (!cx) {
+    return nullptr;
+  }
+
+  JSObject *global = JS::CurrentGlobalOrNull(cx);
+  if (!global) {
+    return nullptr;
+  }
+
+  return xpc::GetNativeForGlobal(global);
+}
+
 nsIPrincipal*
 GetWebIDLCallerPrincipal()
 {
   MOZ_ASSERT(NS_IsMainThread());
   ScriptSettingsStackEntry *entry = ScriptSettingsStack::EntryPoint();
 
   // If we have an entry point that is not NoJSAPI, we know it must be an
   // AutoEntryScript.
--- a/dom/base/ScriptSettings.h
+++ b/dom/base/ScriptSettings.h
@@ -15,16 +15,17 @@
 
 #include "mozilla/Maybe.h"
 
 #include "jsapi.h"
 
 class nsPIDOMWindow;
 class nsGlobalWindow;
 class nsIScriptContext;
+class nsIDocument;
 
 namespace mozilla {
 namespace dom {
 
 // For internal use only - use AutoJSAPI instead.
 namespace danger {
 
 /**
@@ -58,27 +59,67 @@ private:
 
 /*
  * System-wide setup/teardown routines. Init and Destroy should be invoked
  * once each, at startup and shutdown (respectively).
  */
 void InitScriptSettings();
 void DestroyScriptSettings();
 
-// This mostly gets the entry global, but doesn't entirely match the spec in
-// certain edge cases. It's good enough for some purposes, but not others. If
-// you want to call this function, ping bholley and describe your use-case.
-nsIGlobalObject* BrokenGetEntryGlobal();
+// To implement a web-compatible browser, it is often necessary to obtain the
+// global object that is "associated" with the currently-running code. This
+// process is made more complicated by the fact that, historically, different
+// algorithms have operated with different definitions of the "associated"
+// global.
+//
+// HTML5 formalizes this into two concepts: the "incumbent global" and the
+// "entry global". The incumbent global corresponds to the global of the
+// current script being executed, whereas the entry global corresponds to the
+// global of the script where the current JS execution began.
+//
+// There is also a potentially-distinct third global that is determined by the
+// current compartment. This roughly corresponds with the notion of Realms in
+// ECMAScript.
+//
+// Suppose some event triggers an event listener in window |A|, which invokes a
+// scripted function in window |B|, which invokes the |window.location.href|
+// setter in window |C|. The entry global would be |A|, the incumbent global
+// would be |B|, and the current compartment would be that of |C|.
+//
+// In general, it's best to use to use the most-closely-associated global
+// unless the spec says to do otherwise. In 95% of the cases, the global of
+// the current compartment (GetCurrentGlobal()) is the right thing. For
+// example, WebIDL constructors (new C.XMLHttpRequest()) are initialized with
+// the global of the current compartment (i.e. |C|).
+//
+// The incumbent global is very similar, but differs in a few edge cases. For
+// example, if window |B| does |C.location.href = "..."|, the incumbent global
+// used for the navigation algorithm is B, because no script from |C| was ever run.
+//
+// The entry global is used for various things like computing base URIs, mostly
+// for historical reasons.
+//
+// Note that all of these functions return bonafide global objects. This means
+// that, for Windows, they always return the inner.
 
-// Note: We don't yet expose GetEntryGlobal, because in order for it to be
-// correct, we first need to replace a bunch of explicit cx pushing in the
-// browser with AutoEntryScript. But GetIncumbentGlobal is simpler, because it
-// can mostly be inferred from the JS stack.
+// Returns the global associated with the top-most Candidate Entry Point on
+// the Script Settings Stack. See the HTML spec. This may be null.
+nsIGlobalObject* GetEntryGlobal();
+
+// If the entry global is a window, returns its extant document. Otherwise,
+// returns null.
+nsIDocument* GetEntryDocument();
+
+// Returns the global associated with the top-most entry of the the Script
+// Settings Stack. See the HTML spec. This may be null.
 nsIGlobalObject* GetIncumbentGlobal();
 
+// Returns the global associated with the current compartment. This may be null.
+nsIGlobalObject* GetCurrentGlobal();
+
 // JS-implemented WebIDL presents an interesting situation with respect to the
 // subject principal. A regular C++-implemented API can simply examine the
 // compartment of the most-recently-executed script, and use that to infer the
 // responsible party. However, JS-implemented APIs are run with system
 // principal, and thus clobber the subject principal of the script that
 // invoked the API. So we have to do some extra work to keep track of this
 // information.
 //
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -2496,21 +2496,16 @@ OldBindingConstructorEnabled(const nsGlo
       expose = nsContentUtils::IsSystemPrincipal(aWin->GetPrincipal());
     }
 
     if (!expose) {
       return false;
     }
   }
 
-  // Don't expose CSSFontFeatureValuesRule unless the pref is enabled
-  if (aStruct->mDOMClassInfoID == eDOMClassInfo_CSSFontFeatureValuesRule_id) {
-    return nsCSSFontFeatureValuesRule::PrefEnabled();
-  }
-
   return true;
 }
 
 static nsresult
 LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global,
                      nsPIDOMWindow *win,
                      JS::MutableHandle<JSPropertyDescriptor> desc);
 
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -415,17 +415,17 @@ nsFocusManager::GetFocusedElement(nsIDOM
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFocusManager::GetLastFocusMethod(nsIDOMWindow* aWindow, uint32_t* aLastFocusMethod)
 {
   // the focus method is stored on the inner window
   nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
-  if (window)
+  if (window && window->IsOuterWindow())
     window = window->GetCurrentInnerWindow();
   if (!window)
     window = mFocusedWindow;
 
   *aLastFocusMethod = window ? window->GetFocusMethod() : 0;
 
   NS_ASSERTION((*aLastFocusMethod & FOCUSMETHOD_MASK) == *aLastFocusMethod,
                "invalid focus method");
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1477,20 +1477,21 @@ nsGlobalWindow::CleanUp()
 
   mOpener = nullptr;             // Forces Release
   if (mContext) {
     mContext = nullptr;            // Forces Release
   }
   mChromeEventHandler = nullptr; // Forces Release
   mParentTarget = nullptr;
 
-  nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
-
-  if (inner) {
-    inner->CleanUp();
+  if (IsOuterWindow()) {
+    nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
+    if (inner) {
+      inner->CleanUp();
+    }
   }
 
   if (IsInnerWindow()) {
     DisableGamepadUpdates();
     mHasGamepad = false;
   } else {
     MOZ_ASSERT(!mHasGamepad);
   }
@@ -5910,25 +5911,18 @@ nsGlobalWindow::RefreshCompartmentPrinci
 
   JS_SetCompartmentPrincipals(js::GetObjectCompartment(GetWrapperPreserveColor()),
                               nsJSPrincipals::get(mDoc->NodePrincipal()));
 }
 
 static already_AddRefed<nsIDocShellTreeItem>
 GetCallerDocShellTreeItem()
 {
-  JSContext *cx = nsContentUtils::GetCurrentJSContext();
-  nsCOMPtr<nsIDocShellTreeItem> callerItem;
-
-  if (cx) {
-    nsCOMPtr<nsIWebNavigation> callerWebNav =
-      do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
-
-    callerItem = do_QueryInterface(callerWebNav);
-  }
+  nsCOMPtr<nsIWebNavigation> callerWebNav = do_GetInterface(GetEntryGlobal());
+  nsCOMPtr<nsIDocShellTreeItem> callerItem = do_QueryInterface(callerWebNav);
 
   return callerItem.forget();
 }
 
 bool
 nsGlobalWindow::WindowExists(const nsAString& aName,
                              bool aLookForCallerOnJSStack)
 {
@@ -6552,17 +6546,17 @@ nsGlobalWindow::Focus(ErrorResult& aErro
     baseWin->GetVisibility(&isVisible);
   }
 
   if (!isVisible) {
     // A hidden tab is being focused, ignore this call.
     return;
   }
 
-  nsIDOMWindow *caller = nsContentUtils::GetWindowFromCaller();
+  nsCOMPtr<nsIDOMWindow> caller = do_QueryInterface(GetEntryGlobal());
   nsCOMPtr<nsIDOMWindow> opener;
   GetOpener(getter_AddRefs(opener));
 
   // Enforce dom.disable_window_flip (for non-chrome), but still allow the
   // window which opened us to raise us at times when popups are allowed
   // (bugs 355482 and 369306).
   bool canFocus = CanSetProperty("dom.disable_window_flip") ||
                     (opener == caller &&
@@ -7530,30 +7524,17 @@ nsGlobalWindow::FireAbuseEvents(bool aBl
 
   // build the URI of the would-have-been popup window
   // (see nsWindowWatcher::URIfromURL)
 
   // first, fetch the opener's base URI
 
   nsIURI *baseURL = nullptr;
 
-  JSContext *cx = nsContentUtils::GetCurrentJSContext();
-  nsCOMPtr<nsPIDOMWindow> contextWindow;
-
-  if (cx) {
-    nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
-    if (currentCX) {
-      contextWindow = do_QueryInterface(currentCX->GetGlobalObject());
-    }
-  }
-  if (!contextWindow) {
-    contextWindow = this;
-  }
-
-  nsCOMPtr<nsIDocument> doc = contextWindow->GetDoc();
+  nsCOMPtr<nsIDocument> doc = GetEntryDocument();
   if (doc)
     baseURL = doc->GetDocBaseURI();
 
   // use the base URI to build what would have been the popup's URI
   nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
   if (ios)
     ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), 0, baseURL,
                 getter_AddRefs(popupURI));
@@ -8248,17 +8229,17 @@ nsGlobalWindow::PostMessageMoz(JSContext
       return;
     }
   }
 
   // Convert the provided origin string into a URI for comparison purposes.
   nsCOMPtr<nsIPrincipal> providedPrincipal;
 
   if (aTargetOrigin.EqualsASCII("/")) {
-    providedPrincipal = BrokenGetEntryGlobal()->PrincipalOrNull();
+    providedPrincipal = GetEntryGlobal()->PrincipalOrNull();
     if (NS_WARN_IF(!providedPrincipal))
       return;
   }
 
   // "*" indicates no specific origin is required.
   else if (!aTargetOrigin.EqualsASCII("*")) {
     nsCOMPtr<nsIURI> originURI;
     if (NS_FAILED(NS_NewURI(getter_AddRefs(originURI), aTargetOrigin))) {
@@ -12798,21 +12779,17 @@ nsGlobalWindow::GetScrollFrame()
     return presShell->GetRootScrollFrameAsScrollable();
   }
   return nullptr;
 }
 
 nsresult
 nsGlobalWindow::SecurityCheckURL(const char *aURL)
 {
-  nsCOMPtr<nsPIDOMWindow> sourceWindow;
-  JSContext* topCx = nsContentUtils::GetCurrentJSContext();
-  if (topCx) {
-    sourceWindow = do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(topCx));
-  }
+  nsCOMPtr<nsPIDOMWindow> sourceWindow = do_QueryInterface(GetEntryGlobal());
   if (!sourceWindow) {
     sourceWindow = this;
   }
   AutoJSContext cx;
   nsGlobalWindow* sourceWin = static_cast<nsGlobalWindow*>(sourceWindow.get());
   JSAutoCompartment ac(cx, sourceWin->GetGlobalJSObject());
 
   // Resolve the baseURI, which could be relative to the calling window.
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -594,16 +594,17 @@ public:
 
   nsGlobalWindow *GetOuterWindowInternal()
   {
     return static_cast<nsGlobalWindow *>(GetOuterWindow());
   }
 
   nsGlobalWindow *GetCurrentInnerWindowInternal() const
   {
+    MOZ_ASSERT(IsOuterWindow());
     return static_cast<nsGlobalWindow *>(mInnerWindow);
   }
 
   nsGlobalWindow *EnsureInnerWindowInternal()
   {
     return static_cast<nsGlobalWindow *>(EnsureInnerWindow());
   }
 
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -552,56 +552,48 @@ NS_ScriptErrorReporter(JSContext *cx,
             xpc->MarkErrorUnreported(cx);
             return;
           }
         }
       }
     }
   }
 
-  // XXX this means we are not going to get error reports on non DOM contexts
-  nsIScriptContext *context = nsJSUtils::GetDynamicScriptContext(cx);
-
   JS::Rooted<JS::Value> exception(cx);
   ::JS_GetPendingException(cx, &exception);
 
-  // Note: we must do this before running any more code on cx (if cx is the
-  // dynamic script context).
+  // Note: we must do this before running any more code on cx.
   ::JS_ClearPendingException(cx);
 
-  if (context) {
-    nsIScriptGlobalObject *globalObject = context->GetGlobalObject();
-
-    if (globalObject) {
-
-      nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(globalObject);
-      if (win) {
-        win = win->GetCurrentInnerWindow();
-      }
-      nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
-        do_QueryInterface(globalObject);
-      NS_ASSERTION(scriptPrincipal, "Global objects must implement "
-                   "nsIScriptObjectPrincipal");
-      nsContentUtils::AddScriptRunner(
-        new ScriptErrorEvent(JS_GetRuntime(cx),
-                             report,
-                             message,
-                             nsJSPrincipals::get(report->originPrincipals),
-                             scriptPrincipal->GetPrincipal(),
-                             win,
-                             exception,
-                             /* We do not try to report Out Of Memory via a dom
-                              * event because the dom event handler would
-                              * encounter an OOM exception trying to process the
-                              * event, and then we'd need to generate a new OOM
-                              * event for that new OOM instance -- this isn't
-                              * pretty.
-                              */
-                             report->errorNumber != JSMSG_OUT_OF_MEMORY));
-    }
+  MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
+  nsCOMPtr<nsIGlobalObject> globalObject = GetEntryGlobal();
+  if (globalObject) {
+
+    nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(globalObject);
+    MOZ_ASSERT_IF(win, win->IsInnerWindow());
+    nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
+      do_QueryInterface(globalObject);
+    NS_ASSERTION(scriptPrincipal, "Global objects must implement "
+                 "nsIScriptObjectPrincipal");
+    nsContentUtils::AddScriptRunner(
+      new ScriptErrorEvent(JS_GetRuntime(cx),
+                           report,
+                           message,
+                           nsJSPrincipals::get(report->originPrincipals),
+                           scriptPrincipal->GetPrincipal(),
+                           win,
+                           exception,
+                           /* We do not try to report Out Of Memory via a dom
+                            * event because the dom event handler would
+                            * encounter an OOM exception trying to process the
+                            * event, and then we'd need to generate a new OOM
+                            * event for that new OOM instance -- this isn't
+                            * pretty.
+                            */
+                           report->errorNumber != JSMSG_OUT_OF_MEMORY));
   }
 
   if (nsContentUtils::DOMWindowDumpEnabled()) {
     // Print it to stderr as well, for the benefit of those invoking
     // mozilla with -console.
     nsAutoCString error;
     error.AssignLiteral("JavaScript ");
     if (JSREPORT_IS_STRICT(report->flags))
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -58,31 +58,16 @@ nsJSUtils::GetStaticScriptContext(JSObje
 {
   nsIScriptGlobalObject *nativeGlobal = GetStaticScriptGlobal(aObj);
   if (!nativeGlobal)
     return nullptr;
 
   return nativeGlobal->GetScriptContext();
 }
 
-nsIScriptGlobalObject *
-nsJSUtils::GetDynamicScriptGlobal(JSContext* aContext)
-{
-  nsIScriptContext *scriptCX = GetDynamicScriptContext(aContext);
-  if (!scriptCX)
-    return nullptr;
-  return scriptCX->GetGlobalObject();
-}
-
-nsIScriptContext *
-nsJSUtils::GetDynamicScriptContext(JSContext *aContext)
-{
-  return GetScriptContextFromJSContext(aContext);
-}
-
 uint64_t
 nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext)
 {
   if (!aContext)
     return 0;
 
   uint64_t innerWindowID = 0;
 
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -27,20 +27,16 @@ class nsJSUtils
 public:
   static bool GetCallingLocation(JSContext* aContext, const char* *aFilename,
                                  uint32_t* aLineno);
 
   static nsIScriptGlobalObject *GetStaticScriptGlobal(JSObject* aObj);
 
   static nsIScriptContext *GetStaticScriptContext(JSObject* aObj);
 
-  static nsIScriptGlobalObject *GetDynamicScriptGlobal(JSContext *aContext);
-
-  static nsIScriptContext *GetDynamicScriptContext(JSContext *aContext);
-
   /**
    * Retrieve the inner window ID based on the given JSContext.
    *
    * @param JSContext aContext
    *        The JSContext from which you want to find the inner window ID.
    *
    * @returns uint64_t the inner window ID.
    */
--- a/dom/base/nsLocation.cpp
+++ b/dom/base/nsLocation.cpp
@@ -23,39 +23,33 @@
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsError.h"
 #include "nsDOMClassInfoID.h"
 #include "nsReadableUtils.h"
 #include "nsITextToSubURI.h"
 #include "nsJSUtils.h"
 #include "nsContentUtils.h"
+#include "nsGlobalWindow.h"
 #include "mozilla/Likely.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsNullPrincipal.h"
 #include "ScriptSettings.h"
 #include "mozilla/dom/LocationBinding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static nsresult
 GetDocumentCharacterSetForURI(const nsAString& aHref, nsACString& aCharset)
 {
   aCharset.Truncate();
 
-  JSContext *cx = nsContentUtils::GetCurrentJSContext();
-  if (cx) {
-    nsCOMPtr<nsPIDOMWindow> window =
-      do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
-    NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
-
-    if (nsIDocument* doc = window->GetDoc()) {
-      aCharset = doc->GetDocumentCharacterSet();
-    }
+  if (nsIDocument* doc = GetEntryDocument()) {
+    aCharset = doc->GetDocumentCharacterSet();
   }
 
   return NS_OK;
 }
 
 nsLocation::nsLocation(nsPIDOMWindow* aWindow, nsIDocShell *aDocShell)
   : mInnerWindow(aWindow)
 {
@@ -540,33 +534,33 @@ nsLocation::SetHrefWithBase(const nsAStr
      * we want to do a replace load, in such a situation. 
      * In other cases, for example if a event handler or a JS timer
      * had a location.href in it, we want to do a normal load,
      * so that the new url will be appended to Session History.
      * This solution is tricky. Hopefully it isn't going to bite
      * anywhere else. This is part of solution for bug # 39938, 72197
      * 
      */
-    bool inScriptTag=false;
-    JSContext *cx = nsContentUtils::GetCurrentJSContext();
-    if (cx) {
-      nsIScriptContext *scriptContext =
-        nsJSUtils::GetDynamicScriptContext(cx);
+    bool inScriptTag = false;
+    nsIScriptContext* scriptContext = nullptr;
+    nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(GetEntryGlobal());
+    if (win) {
+      scriptContext = static_cast<nsGlobalWindow*>(win.get())->GetContextInternal();
+    }
 
-      if (scriptContext) {
-        if (scriptContext->GetProcessingScriptTag()) {
-          // Now check to make sure that the script is running in our window,
-          // since we only want to replace if the location is set by a
-          // <script> tag in the same window.  See bug 178729.
-          nsCOMPtr<nsIScriptGlobalObject> ourGlobal =
-            docShell ? docShell->GetScriptGlobalObject() : nullptr;
-          inScriptTag = (ourGlobal == scriptContext->GetGlobalObject());
-        }
-      }  
-    } //cx
+    if (scriptContext) {
+      if (scriptContext->GetProcessingScriptTag()) {
+        // Now check to make sure that the script is running in our window,
+        // since we only want to replace if the location is set by a
+        // <script> tag in the same window.  See bug 178729.
+        nsCOMPtr<nsIScriptGlobalObject> ourGlobal =
+          docShell ? docShell->GetScriptGlobalObject() : nullptr;
+        inScriptTag = (ourGlobal == scriptContext->GetGlobalObject());
+      }
+    }
 
     return SetURI(newUri, aReplace || inScriptTag);
   }
 
   return result;
 }
 
 NS_IMETHODIMP
@@ -1015,32 +1009,30 @@ nsLocation::ValueOf(nsIDOMLocation** aRe
   nsCOMPtr<nsIDOMLocation> loc(this);
   loc.forget(aReturn);
   return NS_OK;
 }
 
 nsresult
 nsLocation::GetSourceBaseURL(JSContext* cx, nsIURI** sourceURL)
 {
-
   *sourceURL = nullptr;
-  nsCOMPtr<nsIScriptGlobalObject> sgo = nsJSUtils::GetDynamicScriptGlobal(cx);
-  // If this JS context doesn't have an associated DOM window, we effectively
-  // have no script entry point stack. This doesn't generally happen with the DOM,
+  nsIDocument* doc = GetEntryDocument();
+  // If there's no entry document, we either have no Script Entry Point or one
+  // that isn't a DOM Window.  This doesn't generally happen with the DOM,
   // but can sometimes happen with extension code in certain IPC configurations.
   // If this happens, try falling back on the current document associated with
   // the docshell. If that fails, just return null and hope that the caller passed
   // an absolute URI.
-  if (!sgo && GetDocShell()) {
-    sgo = GetDocShell()->GetScriptGlobalObject();
+  if (!doc && GetDocShell()) {
+    nsCOMPtr<nsPIDOMWindow> docShellWin = do_QueryInterface(GetDocShell()->GetScriptGlobalObject());
+    if (docShellWin) {
+      doc = docShellWin->GetDoc();
+    }
   }
-  NS_ENSURE_TRUE(sgo, NS_OK);
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(sgo);
-  NS_ENSURE_TRUE(window, NS_ERROR_UNEXPECTED);
-  nsIDocument* doc = window->GetDoc();
   NS_ENSURE_TRUE(doc, NS_OK);
   *sourceURL = doc->GetBaseURI().take();
   return NS_OK;
 }
 
 bool
 nsLocation::CallerSubsumes()
 {
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -187,22 +187,17 @@ public:
   // Internal getter/setter for the frame element, this version of the
   // getter crosses chrome boundaries whereas the public scriptable
   // one doesn't for security reasons.
   mozilla::dom::Element* GetFrameElementInternal() const;
   void SetFrameElementInternal(mozilla::dom::Element* aFrameElement);
 
   bool IsLoadingOrRunningTimeout() const
   {
-    const nsPIDOMWindow *win = GetCurrentInnerWindow();
-
-    if (!win) {
-      win = this;
-    }
-
+    const nsPIDOMWindow* win = IsInnerWindow() ? this : GetCurrentInnerWindow();
     return !win->mIsDocumentLoaded || win->mRunningTimeout;
   }
 
   // Check whether a document is currently loading
   bool IsLoading() const
   {
     const nsPIDOMWindow *win;
 
@@ -294,16 +289,17 @@ public:
 
   nsPIDOMWindow *GetOuterWindow()
   {
     return mIsInnerWindow ? mOuterWindow.get() : this;
   }
 
   nsPIDOMWindow *GetCurrentInnerWindow() const
   {
+    MOZ_ASSERT(IsOuterWindow());
     return mInnerWindow;
   }
 
   nsPIDOMWindow *EnsureInnerWindow()
   {
     NS_ASSERTION(IsOuterWindow(), "EnsureInnerWindow called on inner window");
     // GetDoc forces inner window creation if there isn't one already
     GetDoc();
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -51,17 +51,18 @@ AddNonJSSizeOfWindowAndItsDescendents(ns
 {
   // Measure the window.
   nsWindowSizes windowSizes(moz_malloc_size_of);
   aWindow->AddSizeOfIncludingThis(&windowSizes);
   windowSizes.addToTabSizes(aSizes);
 
   // Measure the inner window, if there is one.
   nsWindowSizes innerWindowSizes(moz_malloc_size_of);
-  nsGlobalWindow* inner = aWindow->GetCurrentInnerWindowInternal();
+  nsGlobalWindow* inner = aWindow->IsOuterWindow() ? aWindow->GetCurrentInnerWindowInternal()
+                                                   : nullptr;
   if (inner) {
     inner->AddSizeOfIncludingThis(&innerWindowSizes);
     innerWindowSizes.addToTabSizes(aSizes);
   }
 
   nsCOMPtr<nsIDOMWindowCollection> frames;
   nsresult rv = aWindow->GetFrames(getter_AddRefs(frames));
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2640,10 +2640,17 @@ AssertReturnTypeMatchesJitinfo(const JSJ
   default:
     // Someone messed up their jitinfo type.
     MOZ_ASSERT(false, "Unexpected JSValueType stored in jitinfo");
     break;
   }
 }
 #endif
 
+bool
+CallerSubsumes(JSObject *aObject)
+{
+  nsIPrincipal* objPrin = nsContentUtils::ObjectPrincipal(js::UncheckedUnwrap(aObject));
+  return nsContentUtils::SubjectPrincipal()->Subsumes(objPrin);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2932,12 +2932,24 @@ AssertReturnTypeMatchesJitinfo(const JSJ
                                JS::Handle<JS::Value> aValue);
 #endif
 
 // Returns true if aObj's global has any of the permissions named in aPermissions
 // set to nsIPermissionManager::ALLOW_ACTION. aPermissions must be null-terminated.
 bool
 CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
 
+bool
+CallerSubsumes(JSObject* aObject);
+
+MOZ_ALWAYS_INLINE bool
+CallerSubsumes(JS::Handle<JS::Value> aValue)
+{
+  if (!aValue.isObject()) {
+    return true;
+  }
+  return CallerSubsumes(&aValue.toObject());
+}
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1048,21 +1048,16 @@ DOMInterfaces = {
     ]
 },
 
 'ServiceWorker': {
     'nativeType': 'mozilla::dom::workers::ServiceWorker',
     'headerFile': 'mozilla/dom/workers/bindings/ServiceWorker.h',
 },
 
-'ServiceWorkerContainer': {
-    'nativeType': 'mozilla::dom::workers::ServiceWorkerContainer',
-    'headerFile': 'mozilla/dom/ServiceWorkerContainer.h',
-},
-
 'ServiceWorkerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
     'workers': True,
 },
 
 'SharedWorker': {
     'nativeType': 'mozilla::dom::workers::SharedWorker',
     'headerFile': 'mozilla/dom/workers/bindings/SharedWorker.h',
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3567,16 +3567,19 @@ class JSToNativeConversionInfo():
 
           ${val} is a handle to the JS::Value in question
           ${holderName} replaced by the holder's name, if any
           ${declName} replaced by the declaration's name
           ${haveValue} replaced by an expression that evaluates to a boolean
                        for whether we have a JS::Value.  Only used when
                        defaultValue is not None or when True is passed for
                        checkForValue to instantiateJSToNativeConversion.
+          ${passedToJSImpl} replaced by an expression that evaluates to a boolean
+                            for whether this value is being passed to a JS-
+                            implemented interface.
 
         declType: A CGThing representing the native C++ type we're converting
                   to.  This is allowed to be None if the conversion code is
                   supposed to be used as-is.
 
         holderType: A CGThing representing the type of a "holder" which will
                     hold a possible reference to the C++ thing whose type we
                     returned in declType, or  None if no such holder is needed.
@@ -3822,32 +3825,45 @@ def getJSToNativeConversionInfo(type, de
                 # Our caller will handle it
                 pass
             else:
                 assert defaultValue is None
 
         return templateBody
 
     # A helper function for converting things that look like a JSObject*.
-    def handleJSObjectType(type, isMember, failureCode):
+    def handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription):
         if not isMember:
             if isOptional:
                 # We have a specialization of Optional that will use a
                 # Rooted for the storage here.
                 declType = CGGeneric("JS::Handle<JSObject*>")
             else:
                 declType = CGGeneric("JS::Rooted<JSObject*>")
             declArgs = "cx"
         else:
             assert (isMember in
                     ("Sequence", "Variadic", "Dictionary", "OwningUnion", "MozMap"))
             # We'll get traced by the sequence or dictionary or union tracer
             declType = CGGeneric("JSObject*")
             declArgs = None
         templateBody = "${declName} = &${val}.toObject();\n"
+
+        # For JS-implemented APIs, we refuse to allow passing objects that the
+        # API consumer does not subsume.
+        if not isinstance(descriptorProvider, Descriptor) or descriptorProvider.interface.isJSImplemented():
+            templateBody = fill("""
+                            if ($${passedToJSImpl} && !CallerSubsumes($${val})) {
+                              ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
+                              $*{exceptionCode}
+                            }
+                            """,
+                            sourceDescription=sourceDescription,
+                            exceptionCode=exceptionCode) + templateBody
+
         setToNullCode = "${declName} = nullptr;\n"
         template = wrapObjectTemplate(templateBody, type, setToNullCode,
                                       failureCode)
         return JSToNativeConversionInfo(template, declType=declType,
                                         dealWithOptional=isOptional,
                                         declArgs=declArgs)
 
     assert not (isEnforceRange and isClamp)  # These are mutually exclusive
@@ -3912,17 +3928,18 @@ def getJSToNativeConversionInfo(type, de
             arrayRef = "${declName}"
 
         elementConversion = string.Template(elementInfo.template).substitute({
                 "val": "temp",
                 "declName": "slot",
                 # We only need holderName here to handle isExternal()
                 # interfaces, which use an internal holder for the
                 # conversion even when forceOwningType ends up true.
-                "holderName": "tempHolder"
+                "holderName": "tempHolder",
+                "passedToJSImpl": "${passedToJSImpl}"
             })
 
         # NOTE: Keep this in sync with variadic conversions as needed
         templateBody = fill(
             """
             JS::ForOfIterator iter(cx);
             if (!iter.init($${val}, JS::ForOfIterator::AllowNonIterable)) {
               $*{exceptionCode}
@@ -4016,17 +4033,18 @@ def getJSToNativeConversionInfo(type, de
             mozMapRef = "${declName}"
 
         valueConversion = string.Template(valueInfo.template).substitute({
                 "val": "temp",
                 "declName": "slot",
                 # We only need holderName here to handle isExternal()
                 # interfaces, which use an internal holder for the
                 # conversion even when forceOwningType ends up true.
-                "holderName": "tempHolder"
+                "holderName": "tempHolder",
+                "passedToJSImpl": "${passedToJSImpl}"
             })
 
         templateBody = fill(
             """
             ${mozMapType} &mozMap = ${mozMapRef};
 
             JS::Rooted<JSObject*> mozMapObj(cx, &$${val}.toObject());
             JS::AutoIdArray ids(cx, JS_Enumerate(cx, mozMapObj));
@@ -4109,30 +4127,30 @@ def getJSToNativeConversionInfo(type, de
         names = []
 
         interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes)
         if len(interfaceMemberTypes) > 0:
             interfaceObject = []
             for memberType in interfaceMemberTypes:
                 name = getUnionMemberName(memberType)
                 interfaceObject.append(
-                    CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext" %
+                    CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext" %
                               (unionArgumentObj, name)))
                 names.append(name)
             interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"),
                                         pre="done = ", post=";\n\n", reindent=True)
         else:
             interfaceObject = None
 
         arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes)
         if len(arrayObjectMemberTypes) > 0:
             assert len(arrayObjectMemberTypes) == 1
             name = getUnionMemberName(arrayObjectMemberTypes[0])
             arrayObject = CGGeneric(
-                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
+                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
                 (unionArgumentObj, name))
             names.append(name)
         else:
             arrayObject = None
 
         dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
         if len(dateObjectMemberTypes) > 0:
             assert len(dateObjectMemberTypes) == 1
@@ -4146,52 +4164,54 @@ def getJSToNativeConversionInfo(type, de
             dateObject = None
 
         callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
         if len(callbackMemberTypes) > 0:
             assert len(callbackMemberTypes) == 1
             memberType = callbackMemberTypes[0]
             name = getUnionMemberName(memberType)
             callbackObject = CGGeneric(
-                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
+                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
                 (unionArgumentObj, name))
             names.append(name)
         else:
             callbackObject = None
 
         dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
         if len(dictionaryMemberTypes) > 0:
             assert len(dictionaryMemberTypes) == 1
             name = getUnionMemberName(dictionaryMemberTypes[0])
             setDictionary = CGGeneric(
-                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
+                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
                 (unionArgumentObj, name))
             names.append(name)
         else:
             setDictionary = None
 
         mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes)
         if len(mozMapMemberTypes) > 0:
             assert len(mozMapMemberTypes) == 1
             name = getUnionMemberName(mozMapMemberTypes[0])
             mozMapObject = CGGeneric(
-                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
+                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
                 (unionArgumentObj, name))
             names.append(name)
         else:
             mozMapObject = None
 
         objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
         if len(objectMemberTypes) > 0:
             assert len(objectMemberTypes) == 1
             # Very important to NOT construct a temporary Rooted here, since the
             # SetToObject call can call a Rooted constructor and we need to keep
             # stack discipline for Rooted.
-            object = CGGeneric("%s.SetToObject(cx, &${val}.toObject());\n"
-                               "done = true;\n" % unionArgumentObj)
+            object = CGGeneric("if (!%s.SetToObject(cx, &${val}.toObject(), ${passedToJSImpl})) {\n"
+                               "%s"
+                               "}\n"
+                               "done = true;\n" % (unionArgumentObj, indent(exceptionCode)))
             names.append(objectMemberTypes[0].name)
         else:
             object = None
 
         hasObjectTypes = interfaceObject or arrayObject or dateObject or callbackObject or object or mozMapObject
         if hasObjectTypes:
             # "object" is not distinguishable from other types
             assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject)
@@ -4420,17 +4440,17 @@ def getJSToNativeConversionInfo(type, de
         assert not isEnforceRange and not isClamp
 
         descriptor = descriptorProvider.getDescriptor(
             type.unroll().inner.identifier.name)
 
         if descriptor.nativeType == 'JSObject':
             # XXXbz Workers code does this sometimes
             assert descriptor.workers
-            return handleJSObjectType(type, isMember, failureCode)
+            return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
 
         if descriptor.interface.isCallback():
             name = descriptor.interface.identifier.name
             if type.nullable() or isCallbackReturnValue:
                 declType = CGGeneric("nsRefPtr<%s>" % name)
             else:
                 declType = CGGeneric("OwningNonNull<%s>" % name)
             conversion = indent(CGCallbackTempRoot(name).define())
@@ -4502,17 +4522,17 @@ def getJSToNativeConversionInfo(type, de
                 templateBody += str(FailureFatalCastableObjectUnwrapper(
                     descriptor,
                     "&${val}.toObject()",
                     "${declName}",
                     exceptionCode,
                     isCallbackReturnValue,
                     firstCap(sourceDescription)))
         elif descriptor.workers:
-            return handleJSObjectType(type, isMember, failureCode)
+            return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
         else:
             # Either external, or new-binding non-castable.  We always have a
             # holder for these, because we don't actually know whether we have
             # to addref when unwrapping or not.  So we just pass an
             # getter_AddRefs(nsRefPtr) to XPConnect and if we'll need a release
             # it'll put a non-null pointer in there.
             if forceOwningType:
                 # Don't return a holderType in this case; our declName
@@ -4821,32 +4841,45 @@ def getJSToNativeConversionInfo(type, de
             declType = "JS::Value"
         else:
             assert not isMember
             declType = "JS::Rooted<JS::Value>"
             declArgs = "cx"
 
         assert not isOptional
         templateBody = "${declName} = ${val};\n"
+
+        # For JS-implemented APIs, we refuse to allow passing objects that the
+        # API consumer does not subsume.
+        if not isinstance(descriptorProvider, Descriptor) or descriptorProvider.interface.isJSImplemented():
+            templateBody = fill("""
+                            if ($${passedToJSImpl} && !CallerSubsumes($${val})) {
+                              ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
+                              $*{exceptionCode}
+                            }
+                            """,
+                            sourceDescription=sourceDescription,
+                            exceptionCode=exceptionCode) + templateBody
+
         # We may not have a default value if we're being converted for
         # a setter, say.
         if defaultValue:
             if isinstance(defaultValue, IDLNullValue):
                 defaultHandling = "${declName} = JS::NullValue();\n"
             else:
                 assert isinstance(defaultValue, IDLUndefinedValue)
                 defaultHandling = "${declName} = JS::UndefinedValue();\n"
             templateBody = handleDefault(templateBody, defaultHandling)
         return JSToNativeConversionInfo(templateBody,
                                         declType=CGGeneric(declType),
                                         declArgs=declArgs)
 
     if type.isObject():
         assert not isEnforceRange and not isClamp
-        return handleJSObjectType(type, isMember, failureCode)
+        return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
 
     if type.isDictionary():
         # There are no nullable dictionaries
         assert not type.nullable() or isCallbackReturnValue
         # All optional dictionaries always have default values, so we
         # should be able to assume not isOptional here.
         assert not isOptional
         # In the callback return value case we never have to worry
@@ -4886,17 +4919,17 @@ def getJSToNativeConversionInfo(type, de
                 "!%s(cx, ${val})" % dictionaryTest).define() + "\n"
         else:
             template = ""
 
         dictLoc = "${declName}"
         if type.nullable():
             dictLoc += ".SetValue()"
 
-        template += ('if (!%s.Init(cx, %s, "%s")) {\n'
+        template += ('if (!%s.Init(cx, %s, "%s", ${passedToJSImpl})) {\n'
                      "%s"
                      "}\n" % (dictLoc, val, firstCap(sourceDescription),
                               exceptionCodeIndented.define()))
 
         if type.nullable():
             declType = CGTemplatedType("Nullable", declType)
             template = CGIfElseWrapper("${val}.isNullOrUndefined()",
                                        CGGeneric("${declName}.SetNull();\n"),
@@ -5162,17 +5195,18 @@ class CGArgumentConverter(CGThing):
 
         replacer = {
             "index": index,
             "argc": "args.length()"
         }
         self.replacementVariables = {
             "declName": "arg%d" % index,
             "holderName": ("arg%d" % index) + "_holder",
-            "obj": "obj"
+            "obj": "obj",
+            "passedToJSImpl": toStringBool(isJSImplementedDescriptor(descriptorProvider))
         }
         self.replacementVariables["val"] = string.Template(
             "args[${index}]").substitute(replacer)
         haveValueCheck = string.Template(
             "args.hasDefined(${index})").substitute(replacer)
         self.replacementVariables["haveValue"] = haveValueCheck
         self.descriptorProvider = descriptorProvider
         if self.argument.optional and not self.argument.defaultValue:
@@ -5240,17 +5274,18 @@ class CGArgumentConverter(CGThing):
             string.Template(typeConversion.template).substitute({
                 "val": val,
                 "declName": "slot",
                 # We only need holderName here to handle isExternal()
                 # interfaces, which use an internal holder for the
                 # conversion even when forceOwningType ends up true.
                 "holderName": "tempHolder",
                 # Use the same ${obj} as for the variadic arg itself
-                "obj": replacer["obj"]
+                "obj": replacer["obj"],
+                "passedToJSImpl": toStringBool(isJSImplementedDescriptor(self.descriptorProvider))
             }), 4)
 
         variadicConversion += ("  }\n"
                                "}\n")
         return variadicConversion
 
 
 def getMaybeWrapValueFuncForType(type):
@@ -6736,17 +6771,18 @@ class CGMethodCall(CGThing):
                                                 isNullOrUndefined=isNullOrUndefined,
                                                 isOptional=argIsOptional,
                                                 sourceDescription=(argDesc % (distinguishingIndex + 1))),
                     {
                         "declName": "arg%d" % distinguishingIndex,
                         "holderName": ("arg%d" % distinguishingIndex) + "_holder",
                         "val": distinguishingArg,
                         "obj": "obj",
-                        "haveValue": "args.hasDefined(%d)" % distinguishingIndex
+                        "haveValue": "args.hasDefined(%d)" % distinguishingIndex,
+                        "passedToJSImpl": toStringBool(isJSImplementedDescriptor(descriptor))
                     },
                     checkForValue=argIsOptional)
                 caseBody.append(CGIndenter(testCode, indent))
 
                 # If we got this far, we know we unwrapped to the right
                 # C++ type, so just do the call.  Start conversion with
                 # distinguishingIndex + 1, since we already converted
                 # distinguishingIndex.
@@ -8311,19 +8347,32 @@ def getUnionTypeTemplateVars(unionType, 
                 mType = eObject;
                 """)
         else:
             body = dedent("""
                 MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);
                 mUnion.mValue.mObject.SetValue(cx, obj);
                 mUnion.mType = mUnion.eObject;
                 """)
-        setter = ClassMethod("SetToObject", "void",
+
+        # It's a bit sketchy to do the security check after setting the value,
+        # but it keeps the code cleaner and lets us avoid rooting |obj| over the
+        # call to CallerSubsumes().
+        body = body + dedent("""
+            if (passedToJSImpl && !CallerSubsumes(obj)) {
+              ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "%s");
+              return false;
+            }
+            return true;
+            """)
+
+        setter = ClassMethod("SetToObject", "bool",
                              [Argument("JSContext*", "cx"),
-                              Argument("JSObject*", "obj")],
+                              Argument("JSObject*", "obj"),
+                              Argument("bool", "passedToJSImpl", default="false")],
                              inline=True, bodyInHeader=True,
                              body=body)
 
     else:
         # Important: we need to not have our declName involve
         # maybe-GCing operations.
         if conversionInfo.holderType is not None:
             holderArgs = conversionInfo.holderArgs
@@ -8333,17 +8382,18 @@ def getUnionTypeTemplateVars(unionType, 
         else:
             initHolder = ""
 
         jsConversion = fill(
             initHolder + conversionInfo.template,
             val="value",
             declName="memberSlot",
             holderName=(holderName if ownsMembers else "%s.ref()" % holderName),
-            destroyHolder=destroyHolder)
+            destroyHolder=destroyHolder,
+            passedToJSImpl="passedToJSImpl")
 
         jsConversion = fill(
             """
             tryNext = false;
             { // scope for memberSlot
               ${structType}& memberSlot = RawSetAs${name}(${ctorArgs});
               $*{jsConversion}
             }
@@ -8352,17 +8402,18 @@ def getUnionTypeTemplateVars(unionType, 
             structType=structType,
             name=name,
             ctorArgs=ctorArgs,
             jsConversion=jsConversion)
 
         setter = ClassMethod("TrySetTo" + name, "bool",
                              [Argument("JSContext*", "cx"),
                               Argument("JS::Handle<JS::Value>", "value"),
-                              Argument("bool&", "tryNext")],
+                              Argument("bool&", "tryNext"),
+                              Argument("bool", "passedToJSImpl", default="false")],
                              inline=not ownsMembers,
                              bodyInHeader=not ownsMembers,
                              body=jsConversion)
 
     return {
         "name": name,
         "structType": structType,
         "externalType": externalType,
@@ -9458,17 +9509,18 @@ class CGProxySpecialOperation(CGPerSigna
                 sourceDescription=("value being assigned to %s setter" %
                                    descriptor.interface.identifier.name))
             if argumentMutableValue is None:
                 argumentMutableValue = "desc.value()"
             templateValues = {
                 "declName": argument.identifier.name,
                 "holderName": argument.identifier.name + "_holder",
                 "val": argumentMutableValue,
-                "obj": "obj"
+                "obj": "obj",
+                "passedToJSImpl": "false"
             }
             self.cgRoot.prepend(instantiateJSToNativeConversion(info, templateValues))
         elif operation.isGetter() or operation.isDeleter():
             if foundVar is None:
                 self.cgRoot.prepend(CGGeneric("bool found;\n"))
 
     def getArguments(self):
         args = [(a, a.identifier.name) for a in self.arguments]
@@ -11082,17 +11134,18 @@ class CGDictionary(CGThing):
                 """,
                 memberInits="\n".join(memberInits))
 
         body += "return true;\n"
 
         return ClassMethod("Init", "bool", [
             Argument('JSContext*', 'cx'),
             Argument('JS::Handle<JS::Value>', 'val'),
-            Argument('const char*', 'sourceDescription', default='"Value"')
+            Argument('const char*', 'sourceDescription', default='"Value"'),
+            Argument('bool', 'passedToJSImpl', default='false')
         ], body=body)
 
     def initFromJSONMethod(self):
         return ClassMethod(
             "Init", "bool",
             [Argument('const nsAString&', 'aJSON')],
             body=dedent("""
                 MOZ_ASSERT(NS_IsMainThread());
@@ -11317,17 +11370,18 @@ class CGDictionary(CGThing):
     def getMemberConversion(self, memberInfo):
         member, conversionInfo = memberInfo
         replacements = {
             "val": "temp.ref()",
             "declName": self.makeMemberName(member.identifier.name),
             # We need a holder name for external interfaces, but
             # it's scoped down to the conversion so we can just use
             # anything we want.
-            "holderName": "holder"
+            "holderName": "holder",
+            "passedToJSImpl": "passedToJSImpl"
         }
         # We can't handle having a holderType here
         assert conversionInfo.holderType is None
         if conversionInfo.dealWithOptional:
             replacements["declName"] = "(" + replacements["declName"] + ".Value())"
         if member.defaultValue:
             replacements["haveValue"] = "!isNull && !temp->isUndefined()"
 
@@ -11453,16 +11507,21 @@ class CGDictionary(CGThing):
                 trace = CGGeneric('%s.TraceDictionary(trc);\n' % memberData)
             elif type.isUnion():
                 trace = CGGeneric('%s.TraceUnion(trc);\n' % memberData)
             else:
                 assert type.isSpiderMonkeyInterface()
                 trace = CGGeneric('%s.TraceSelf(trc);\n' % memberData)
             if type.nullable():
                 trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable)
+        elif type.isMozMap():
+            # If you implement this, add a MozMap<object> to
+            # TestInterfaceJSDictionary and test it in test_bug1036214.html
+            # to make sure we end up with the correct security properties.
+            assert False
         else:
             assert False  # unknown type
 
         if not member.defaultValue:
             trace = CGIfWrapper(trace, "%s.WasPassed()" % memberLoc)
 
         return trace.define()
 
@@ -13384,17 +13443,18 @@ class CallbackMember(CGNativeMember):
     def getResultConversion(self):
         replacements = {
             "val": "rval",
             "holderName": "rvalHolder",
             "declName": "rvalDecl",
             # We actually want to pass in a null scope object here, because
             # wrapping things into our current compartment (that of mCallback)
             # is what we want.
-            "obj": "nullptr"
+            "obj": "nullptr",
+            "passedToJSImpl": "false"
         }
 
         if isJSImplementedDescriptor(self.descriptorProvider):
             isCallbackReturnValue = "JSImpl"
         else:
             isCallbackReturnValue = "Callback"
         sourceDescription = "return value of %s" % self.getPrettyName()
         convertType = instantiateJSToNativeConversion(
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -53,8 +53,9 @@ MSG_DEF(MSG_INVALID_ADVANCE_COUNT, 0, "0
 MSG_DEF(MSG_DEFINEPROPERTY_ON_GSP, 0, "Not allowed to define a property on the named properties object.")
 MSG_DEF(MSG_INVALID_URL, 1, "{0} is not a valid URL.")
 MSG_DEF(MSG_METADATA_NOT_CONFIGURED, 0, "Either size or lastModified should be true.")
 MSG_DEF(MSG_INVALID_READ_SIZE, 0, "0 (Zero) is not a valid read size.")
 MSG_DEF(MSG_HEADERS_IMMUTABLE, 0, "Headers are immutable and cannot be modified.")
 MSG_DEF(MSG_INVALID_HEADER_NAME, 1, "{0} is an invalid header name.")
 MSG_DEF(MSG_INVALID_HEADER_VALUE, 1, "{0} is an invalid header value.")
 MSG_DEF(MSG_INVALID_HEADER_SEQUENCE, 0, "Headers require name/value tuples when being initialized by a sequence.")
+MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, "Permission denied to pass cross-origin object as {0}.")
--- a/dom/bindings/test/TestInterfaceJS.js
+++ b/dom/bindings/test/TestInterfaceJS.js
@@ -4,51 +4,49 @@
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
 
 "use strict";
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
-var gGlobal = this;
-function checkGlobal(obj) {
-  if (Object(obj) === obj && Cu.getGlobalForObject(obj) != gGlobal) {
-    // This message may not make it to the caller in a useful form, so dump
-    // as well.
-    var msg = "TestInterfaceJS received an object from a different scope!";
-    dump(msg + "\n");
-    throw new Error(msg);
-  }
-}
-
 function TestInterfaceJS(anyArg, objectArg) {}
 
 TestInterfaceJS.prototype = {
   classID: Components.ID("{2ac4e026-cf25-47d5-b067-78d553c3cad8}"),
   contractID: "@mozilla.org/dom/test-interface-js;1",
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
 
-  __init: function (anyArg, objectArg) {
+  __init: function (anyArg, objectArg, dictionaryArg) {
     this._anyAttr = undefined;
     this._objectAttr = null;
     this._anyArg = anyArg;
     this._objectArg = objectArg;
-    checkGlobal(anyArg);
-    checkGlobal(objectArg);
+    this._dictionaryArg = dictionaryArg;
   },
 
   get anyArg() { return this._anyArg; },
   get objectArg() { return this._objectArg; },
+  get dictionaryArg() { return this._dictionaryArg; },
   get anyAttr() { return this._anyAttr; },
-  set anyAttr(val) { checkGlobal(val); this._anyAttr = val; },
+  set anyAttr(val) { this._anyAttr = val; },
   get objectAttr() { return this._objectAttr; },
-  set objectAttr(val) { checkGlobal(val); this._objectAttr = val; },
-  pingPongAny: function(any) { checkGlobal(any); return any; },
-  pingPongObject: function(obj) { checkGlobal(obj); return obj; },
+  set objectAttr(val) { this._objectAttr = val; },
+  get dictionaryAttr() { return this._dictionaryAttr; },
+  set dictionaryAttr(val) { this._dictionaryAttr = val; },
+  pingPongAny: function(any) { return any; },
+  pingPongObject: function(obj) { return obj; },
+  pingPongObjectOrString: function(objectOrString) { return objectOrString; },
+  pingPongDictionary: function(dict) { return dict; },
+  pingPongDictionaryOrLong: function(dictOrLong) { return dictOrLong.anyMember || dictOrLong; },
+  pingPongMap: function(map) { return JSON.stringify(map); },
+  objectSequenceLength: function(seq) { return seq.length; },
+  anySequenceLength: function(seq) { return seq.length; },
+
 
   getCallerPrincipal: function() { return Cu.getWebIDLCallerPrincipal().origin; },
 
   convertSVS: function(svs) { return svs; },
 
   pingPongUnion: function(x) { return x; },
   pingPongUnionContainingNull: function(x) { return x; },
   pingPongNullableUnion: function(x) { return x; },
--- a/dom/bindings/test/mochitest.ini
+++ b/dom/bindings/test/mochitest.ini
@@ -12,20 +12,18 @@ support-files =
 [test_bug560072.html]
 [test_bug707564.html]
 [test_bug742191.html]
 [test_bug759621.html]
 [test_bug773326.html]
 [test_bug788369.html]
 [test_bug852846.html]
 [test_bug862092.html]
-# When bug 923904 lands, this test can be turned on, but only for debug builds
-# where we have our test component. So this should become skip-if = debug == false.
-[test_bug923904.html]
-skip-if = true
+[test_bug1036214.html]
+skip-if = debug == false
 [test_bug1041646.html]
 [test_barewordGetsWindow.html]
 [test_callback_default_thisval.html]
 [test_cloneAndImportNode.html]
 [test_defineProperty.html]
 [test_enums.html]
 [test_exceptionThrowing.html]
 [test_exception_messages.html]
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/test_bug1036214.html
@@ -0,0 +1,123 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1036214
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1036214</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for subsumes-checking |any| and |object| for js-implemented WebIDL. **/
+  SimpleTest.waitForExplicitFinish();
+  var xoObjects = [];
+  function setup() {
+    xoObjects.push(window[0]);
+    xoObjects.push(window[0].location);
+    xoObjects.push(SpecialPowers.unwrap(SpecialPowers.wrap(window[0]).document));
+    xoObjects.push(SpecialPowers);
+    xoObjects.push(SpecialPowers.wrap);
+    SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, go);
+  }
+
+  function checkThrows(f, msg) {
+    try {
+      f();
+      ok(false, "Should have thrown: " + msg);
+    } catch (e) {
+      ok(true, "Threw correctly: " + msg);
+      ok(/denied|insecure/.test(e), "Threw security exception: " + e);
+    }
+  }
+
+  function go() {
+
+    //
+    // Test the basics of the test interface.
+    //
+
+    var any = { a: 11 };
+    var obj = { b: 22, c: "str" };
+    var obj2 = { foo: "baz" };
+    var myDict = { anyMember: 42, objectMember: { answer: 42 }, objectOrStringMember: { answer: "anobject" },
+                   anySequenceMember: [{}, 1, "thirdinsequence"],
+                   innerDictionary: { innerObject: { answer: "rabbithole" } } };
+    var t = new TestInterfaceJS(any, obj, myDict);
+    is(Object.getPrototypeOf(t), TestInterfaceJS.prototype, "Prototype setup works correctly");
+    is(t.anyArg, any, "anyArg is correct");
+    is(t.objectArg, obj, "objectArg is correct");
+    is(t.dictionaryArg.anyMember, 42, "dictionaryArg looks correct");
+    is(t.dictionaryArg.objectMember.answer, 42, "dictionaryArg looks correct");
+    t.anyAttr = 2;
+    is(t.anyAttr, 2, "ping-pong any attribute works");
+    t.objAttr = obj2;
+    is(t.objAttr, obj2, "ping-pong object attribute works");
+    t.dictionaryAttr = myDict;
+    is(t.dictionaryAttr.anyMember, 42, "ping-pong dictionary attribute works");
+    is(t.dictionaryAttr.objectMember.answer, 42, "ping-pong dictionary attribute works");
+
+    is(any, t.pingPongAny(any), "ping-pong works with any");
+    is(obj, t.pingPongObject(obj), "ping-pong works with obj");
+    is(obj, t.pingPongObjectOrString(obj), "ping-pong works with obj or string");
+    is("foo", t.pingPongObjectOrString("foo"), "ping-pong works with obj or string");
+    is(t.pingPongDictionary(myDict).anyMember, 42, "ping pong works with dict");
+    is(t.pingPongDictionary(myDict).objectMember.answer, 42, "ping pong works with dict");
+    is(t.pingPongDictionary(myDict).objectOrStringMember.answer, "anobject", "ping pong works with dict");
+    is(t.pingPongDictionary(myDict).anySequenceMember[2], "thirdinsequence", "ping pong works with dict");
+    is(t.pingPongDictionary(myDict).innerDictionary.innerObject.answer, "rabbithole", "ping pong works with layered dicts");
+    is(t.pingPongDictionaryOrLong({anyMember: 42}), 42, "ping pong (dict or long) works with dict");
+    is(t.pingPongDictionaryOrLong(42), 42, "ping pong (dict or long) works with long");
+    ok(/canary/.test(t.pingPongMap({ someVal: 42, someOtherVal: "canary" })), "ping pong works with mozmap");
+    is(t.objectSequenceLength([{}, {}, {}]), 3, "ping pong works with object sequence");
+    is(t.anySequenceLength([42, 'string', {}, undefined]), 4, "ping pong works with any sequence");
+
+    //
+    // Test that we throw in the cross-origin cases.
+    //
+
+    xoObjects.forEach(function(xoObj) {
+      var blank = new TestInterfaceJS();
+      checkThrows(() => new TestInterfaceJS(xoObj, undefined), "any param for constructor");
+      checkThrows(() => new TestInterfaceJS(undefined, xoObj), "obj param for constructor");
+      checkThrows(() => new TestInterfaceJS(undefined, undefined, { anyMember: xoObj }), "any dict param for constructor");
+      checkThrows(() => new TestInterfaceJS(undefined, undefined, { objectMember: xoObj }), "object dict param for constructor");
+      checkThrows(() => new TestInterfaceJS(undefined, undefined, { objectOrStringMember: xoObj }), "union dict param for constructor");
+      checkThrows(() => new TestInterfaceJS(undefined, undefined, { anySequenceMember: [0, xoObj, 'hi' ] }), "sequence dict param for constructor");
+      checkThrows(() => new TestInterfaceJS(undefined, undefined, { innerDictionary: { innerObject: xoObj } }), "inner dict param for constructor");
+      checkThrows(() => t.anyAttr = xoObj, "anyAttr");
+      checkThrows(() => t.objectAttr = xoObj, "objAttr");
+      checkThrows(() => t.dictionaryAttr = { anyMember: xoObj }, "dictionaryAttr any");
+      checkThrows(() => t.dictionaryAttr = { objectMember: xoObj }, "dictionaryAttr object");
+      checkThrows(() => t.pingPongAny(xoObj), "pingpong any");
+      checkThrows(() => t.pingPongObject(xoObj), "pingpong obj");
+      checkThrows(() => t.pingPongObjectOrString(xoObj), "pingpong union");
+      checkThrows(() => t.pingPongDictionary({ anyMember: xoObj }), "dictionary pingpong any");
+      checkThrows(() => t.pingPongDictionary({ objectMember: xoObj }), "dictionary pingpong object");
+      checkThrows(() => t.pingPongDictionary({ anyMember: xoObj, objectMember: xoObj }), "dictionary pingpong both");
+      checkThrows(() => t.pingPongDictionary({ objectOrStringMember: xoObj }), "dictionary pingpong objectorstring");
+      checkThrows(() => t.pingPongDictionaryOrLong({ objectMember: xoObj }), "unionable dictionary");
+      checkThrows(() => t.pingPongDictionaryOrLong({ anyMember: xoObj }), "unionable dictionary");
+      checkThrows(() => t.pingPongMap({ someMember: 42, someOtherMember: {}, crossOriginMember: xoObj }), "mozmap");
+      checkThrows(() => t.objectSequenceLength([{}, {}, xoObj, {}]), "object sequence");
+      checkThrows(() => t.anySequenceLength([42, 'someString', xoObj, {}]), "any sequence");
+    });
+
+
+    SimpleTest.finish();
+  }
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1036214">Mozilla Bug 1036214</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+<iframe id="ifr" onload="setup();" src="http://example.org/tests/js/xpconnect/tests/mochitest/file_empty.html"></iframe>
+</body>
+</html>
deleted file mode 100644
--- a/dom/bindings/test/test_bug923904.html
+++ /dev/null
@@ -1,66 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=923904
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 923904</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <script type="application/javascript">
-
-  /** Test for cloning of |any| and |object| for JS-Implemented WebIDL. **/
-  SimpleTest.waitForExplicitFinish();
-  SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, go);
-
-  function go() {
-    var someAny = { a: 11 };
-    var someObj = { b: 22, c: "str" };
-    var t = new TestInterfaceJS(someAny, someObj);
-    is(Object.getPrototypeOf(t), TestInterfaceJS.prototype, "Prototype setup works correctly");
-    is(t.anyArg.toSource(), someAny.toSource(), "anyArg comes back looking like what we sent");
-    is(t.objectArg.toSource(), someObj.toSource(), "objectArg comes back looking like what we sent");
-    isnot(t.anyArg, t.anyArg, "get a new anyArg each time");
-    isnot(t.objectArg, t.objectArg, "get a new objectArg each time");
-
-    t.anyAttr = 2;
-    is(t.anyAttr, 2, "ping-pong works");
-    testObjectCloned(t, 'anyAttr');
-    testObjectCloned(t, 'objectAttr');
-
-    is(someAny.toSource(), t.pingPongAny(someAny).toSource(), "ping-pong works with any");
-    is(someObj.toSource(), t.pingPongObject(someObj).toSource(), "ping-pong works with obj");
-    isnot(someAny, t.pingPongAny(someAny), "Clone works for ping-pong any");
-    isnot(someObj, t.pingPongObject(someObj), "Clone works for ping-pong obj");
-
-    SimpleTest.finish();
-  }
-
-  function testObjectCloned(iface, propname) {
-    var obj = { prop: 42 };
-    iface[propname] = obj;
-    is(iface[propname].prop, 42, "objects come back as well");
-    is(iface[propname].__proto__, Object.prototype, "vanilla object");
-    isnot(iface[propname], obj, "Should not be the original object");
-    isnot(iface[propname], iface[propname], "Should get cloned each time");
-    try {
-      iface[propname] = { stringProp: "hi", reflectorProp: document };
-      ok(false, "Should throw when trying to clone reflector");
-    } catch (e) {
-      ok(/cloned/.test(e), "Should throw clone error: " + e);
-    }
-  }
-
-  </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=923904">Mozilla Bug 923904</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1980,17 +1980,17 @@ CanvasRenderingContext2D::ArcTo(double x
   bool anticlockwise;
 
   if (p0 == p1 || p1 == p2 || radius == 0) {
     LineTo(p1.x, p1.y);
     return;
   }
 
   // Check for colinearity
-  dir = (p2.x - p1.x) * (p0.y - p1.y) + (p2.y - p1.y) * (p1.x - p0.x);
+  dir = (p2.x - p1.x).value * (p0.y - p1.y).value + (p2.y - p1.y).value * (p1.x - p0.x).value;
   if (dir == 0) {
     LineTo(p1.x, p1.y);
     return;
   }
 
 
   // XXX - Math for this code was already available from the non-azure code
   // and would be well tested. Perhaps converting to bezier directly might
@@ -4495,17 +4495,17 @@ CanvasPath::ArcTo(double x1, double y1, 
   bool anticlockwise;
 
   if (p0 == p1 || p1 == p2 || radius == 0) {
     LineTo(p1.x, p1.y);
     return;
   }
 
   // Check for colinearity
-  dir = (p2.x - p1.x) * (p0.y - p1.y) + (p2.y - p1.y) * (p1.x - p0.x);
+  dir = (p2.x - p1.x).value * (p0.y - p1.y).value + (p2.y - p1.y).value * (p1.x - p0.x).value;
   if (dir == 0) {
     LineTo(p1.x, p1.y);
     return;
   }
 
 
   // XXX - Math for this code was already available from the non-azure code
   // and would be well tested. Perhaps converting to bezier directly might
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -785,17 +785,17 @@ protected:
     */
   bool NeedToDrawShadow()
   {
     const ContextState& state = CurrentState();
 
     // The spec says we should not draw shadows if the operator is OVER.
     // If it's over and the alpha value is zero, nothing needs to be drawn.
     return NS_GET_A(state.shadowColor) != 0 &&
-      (state.shadowBlur != 0 || state.shadowOffset.x != 0 || state.shadowOffset.y != 0);
+      (state.shadowBlur != 0.f || state.shadowOffset.x != 0.f || state.shadowOffset.y != 0.f);
   }
 
   mozilla::gfx::CompositionOp UsedOperation()
   {
     if (NeedToDrawShadow()) {
       // In this case the shadow rendering will use the operator.
       return mozilla::gfx::CompositionOp::OP_OVER;
     }
--- a/dom/cellbroadcast/src/CellBroadcast.cpp
+++ b/dom/cellbroadcast/src/CellBroadcast.cpp
@@ -83,16 +83,18 @@ CellBroadcast::CellBroadcast(nsPIDOMWind
 CellBroadcast::~CellBroadcast()
 {
   MOZ_ASSERT(mProvider && mListener);
 
   mListener->Disconnect();
   mProvider->UnregisterCellBroadcastMsg(mListener);
 }
 
+NS_IMPL_ISUPPORTS_INHERITED0(CellBroadcast, DOMEventTargetHelper)
+
 JSObject*
 CellBroadcast::WrapObject(JSContext* aCx)
 {
   return MozCellBroadcastBinding::Wrap(aCx, this);
 }
 
 // Forwarded nsICellBroadcastListener methods
 
--- a/dom/cellbroadcast/src/CellBroadcast.h
+++ b/dom/cellbroadcast/src/CellBroadcast.h
@@ -12,40 +12,43 @@
 #include "nsICellBroadcastProvider.h"
 #include "js/TypeDecls.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
-class CellBroadcast MOZ_FINAL : public DOMEventTargetHelper
+class CellBroadcast MOZ_FINAL : public DOMEventTargetHelper,
+                                private nsICellBroadcastListener
 {
   /**
-   * Class CellBroadcast doesn't actually inherit nsICellBroadcastListener.
+   * Class CellBroadcast doesn't actually expose nsICellBroadcastListener.
    * Instead, it owns an nsICellBroadcastListener derived instance mListener
    * and passes it to nsICellBroadcastProvider. The onreceived events are first
    * delivered to mListener and then forwarded to its owner, CellBroadcast. See
    * also bug 775997 comment #51.
    */
   class Listener;
 
+  // MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
+  ~CellBroadcast();
+
 public:
+  NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSICELLBROADCASTLISTENER
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
 
   static already_AddRefed<CellBroadcast>
   Create(nsPIDOMWindow* aOwner, ErrorResult& aRv);
 
   CellBroadcast() MOZ_DELETE;
   CellBroadcast(nsPIDOMWindow *aWindow,
                 nsICellBroadcastProvider* aProvider);
-  // MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
-  ~CellBroadcast();
 
   nsPIDOMWindow*
   GetParentObject() const { return GetOwner(); }
 
   virtual JSObject*
   WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   IMPL_EVENT_HANDLER(received)
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -1590,18 +1590,19 @@ EventStateManager::GenerateDragGesture(n
         pixelThresholdX = 5;
       if (!pixelThresholdY)
         pixelThresholdY = 5;
     }
 
     // fire drag gesture if mouse has moved enough
     LayoutDeviceIntPoint pt = aEvent->refPoint +
       LayoutDeviceIntPoint::FromUntyped(aEvent->widget->WidgetToScreenOffset());
-    if (DeprecatedAbs(pt.x - mGestureDownPoint.x) > pixelThresholdX ||
-        DeprecatedAbs(pt.y - mGestureDownPoint.y) > pixelThresholdY) {
+    LayoutDeviceIntPoint distance = pt - mGestureDownPoint;
+    if (Abs(distance.x.value) > SafeCast<uint32_t>(pixelThresholdX) ||
+        Abs(distance.y.value) > SafeCast<uint32_t>(pixelThresholdY)) {
       if (Prefs::ClickHoldContextMenu()) {
         // stop the click-hold before we fire off the drag gesture, in case
         // it takes a long time
         KillClickHoldTimer();
       }
 
       nsCOMPtr<nsISupports> container = aPresContext->GetContainerWeak();
       nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(container);
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -3,28 +3,28 @@
  * 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 "domstubs.idl"
 
 interface nsIDocument;
 interface nsIURI;
 
-[uuid(cc539f1e-1ce6-4af5-bf94-195b30bde010)]
+[uuid(9b5acea4-2601-4ac7-8836-4352ceb88178)]
 interface nsIServiceWorkerManager : nsISupports
 {
   // Returns a Promise
   nsISupports register(in nsIDOMWindow aWindow, in DOMString aScope, in DOMString aScriptURI);
 
   // Returns a Promise
   nsISupports unregister(in nsIDOMWindow aWindow, in DOMString aScope);
 
-  // aTarget MUST be a ServiceWorkerContainer.
-  [noscript] void AddContainerEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
-  [noscript] void RemoveContainerEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
+  // aTarget MUST be a ServiceWorkerRegistration.
+  [noscript] void AddRegistrationEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
+  [noscript] void RemoveRegistrationEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
 
   /**
    * Call this to request that document `aDoc` be controlled by a ServiceWorker
    * if a registration exists for it's scope.
    *
    * This MUST only be called once per document!
    */
   [notxpcom,nostdcall] void MaybeStartControlling(in nsIDocument aDoc);
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -2097,22 +2097,22 @@ MediaManager::MediaCaptureWindowStateInt
   // We need to return the union of all streams in all innerwindows that
   // correspond to that outerwindow.
 
   // Iterate the docshell tree to find all the child windows, find
   // all the listeners for each one, get the booleans, and merge the
   // results.
   nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
   if (piWin) {
-    if (piWin->GetCurrentInnerWindow() || piWin->IsInnerWindow()) {
+    if (piWin->IsInnerWindow() || piWin->GetCurrentInnerWindow()) {
       uint64_t windowID;
-      if (piWin->GetCurrentInnerWindow()) {
+      if (piWin->IsInnerWindow()) {
+        windowID = piWin->WindowID();
+      } else {
         windowID = piWin->GetCurrentInnerWindow()->WindowID();
-      } else {
-        windowID = piWin->WindowID();
       }
       StreamListeners* listeners = GetActiveWindows()->Get(windowID);
       if (listeners) {
         uint32_t length = listeners->Length();
         for (uint32_t i = 0; i < length; ++i) {
           nsRefPtr<GetUserMediaCallbackMediaStreamListener> listener =
             listeners->ElementAt(i);
           if (listener->CapturingVideo()) {
--- a/dom/mobileconnection/src/MobileConnection.cpp
+++ b/dom/mobileconnection/src/MobileConnection.cpp
@@ -86,16 +86,19 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MobileConnection,
                                                 DOMEventTargetHelper)
   tmp->Shutdown();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mVoice)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mData)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MobileConnection)
+  // MobileConnection does not expose nsIMobileConnectionListener. mListener is
+  // the exposed nsIMobileConnectionListener and forwards the calls it receives
+  // to us.
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(MobileConnection, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(MobileConnection, DOMEventTargetHelper)
 
 MobileConnection::MobileConnection(nsPIDOMWindow* aWindow, uint32_t aClientId)
   : DOMEventTargetHelper(aWindow)
   , mClientId(aClientId)
--- a/dom/mobileconnection/src/MobileConnection.h
+++ b/dom/mobileconnection/src/MobileConnection.h
@@ -12,20 +12,21 @@
 #include "mozilla/dom/MozMobileConnectionBinding.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIMobileConnectionProvider.h"
 #include "nsWeakPtr.h"
 
 namespace mozilla {
 namespace dom {
 
-class MobileConnection MOZ_FINAL : public DOMEventTargetHelper
+class MobileConnection MOZ_FINAL : public DOMEventTargetHelper,
+                                   private nsIMobileConnectionListener
 {
   /**
-   * Class MobileConnection doesn't actually inherit
+   * Class MobileConnection doesn't actually expose
    * nsIMobileConnectionListener. Instead, it owns an
    * nsIMobileConnectionListener derived instance mListener and passes it to
    * nsIMobileConnectionProvider. The onreceived events are first delivered to
    * mListener and then forwarded to its owner, MobileConnection. See also bug
    * 775997 comment #51.
    */
   class Listener;
 
--- a/dom/smil/test/smilTestUtils.js
+++ b/dom/smil/test/smilTestUtils.js
@@ -50,39 +50,43 @@ var SMILUtil =
     if (attr.attrType == "XML") {
       // XXXdholbert This is appropriate for mapped attributes, but not
       // for other attributes.
       return SMILUtil.getComputedStyleWrapper(elem, attr.attrName);
     }
   },
 
   // Smart wrapper for getComputedStyle, which will generate a "fake" computed
-  // style for recognized shorthand properties (font, overflow, marker)
+  // style for recognized shorthand properties (font, font-variant, overflow, marker)
   getComputedStyleWrapper : function(elem, propName)
   {
     // Special cases for shorthand properties (which aren't directly queriable
     // via getComputedStyle)
     var computedStyle;
     if (propName == "font") {
-      var subProps = ["font-style", "font-variant", "font-weight",
+      var subProps = ["font-style", "font-variant-caps", "font-weight",
                       "font-size", "line-height", "font-family"];
       for (var i in subProps) {
         var subPropStyle = SMILUtil.getComputedStyleSimple(elem, subProps[i]);
         if (subPropStyle) {
           if (subProps[i] == "line-height") {
             // There needs to be a "/" before line-height
             subPropStyle = "/ " + subPropStyle;
           }
           if (!computedStyle) {
             computedStyle = subPropStyle;
           } else {
             computedStyle = computedStyle + " " + subPropStyle;
           }
         }
       }
+    } else if (propName == "font-variant") {
+      // xxx - this isn't completely correct but it's sufficient for what's
+      //       being tested here
+      computedStyle = SMILUtil.getComputedStyleSimple(elem, "font-variant-caps");
     } else if (propName == "marker") {
       var subProps = ["marker-end", "marker-mid", "marker-start"];
       for (var i in subProps) {
         if (!computedStyle) {
           computedStyle = SMILUtil.getComputedStyleSimple(elem, subProps[i]);
         } else {
           is(computedStyle, SMILUtil.getComputedStyleSimple(elem, subProps[i]),
              "marker sub-properties should match each other " +
--- a/dom/system/gonk/AutoMounter.cpp
+++ b/dom/system/gonk/AutoMounter.cpp
@@ -11,30 +11,27 @@
 #include <unistd.h>
 
 #include <arpa/inet.h>
 #include <linux/types.h>
 #include <linux/netlink.h>
 #include <netinet/in.h>
 #include <sys/socket.h>
 #include <android/log.h>
-#include <cutils/properties.h>
 
 #include "AutoMounter.h"
 #include "nsVolumeService.h"
 #include "AutoMounterSetting.h"
 #include "base/message_loop.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/FileUtils.h"
 #include "mozilla/Hal.h"
 #include "mozilla/StaticPtr.h"
 #include "MozMtpServer.h"
-#include "MozMtpStorage.h"
 #include "nsAutoPtr.h"
-#include "nsCharSeparatedTokenizer.h"
 #include "nsMemory.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "OpenFileFinder.h"
 #include "Volume.h"
 #include "VolumeManager.h"
 
@@ -88,23 +85,16 @@ USING_MTP_NAMESPACE
 #define DBG(args...)  __android_log_print(ANDROID_LOG_DEBUG, "AutoMounter" , ## args)
 #else
 #define DBG(args...)
 #endif
 
 namespace mozilla {
 namespace system {
 
-#define SYS_USB_CONFIG          "sys.usb.config"
-#define PERSIST_SYS_USB_CONFIG  "persist.sys.usb.config"
-
-#define USB_FUNC_ADB  "adb"
-#define USB_FUNC_MTP  "mtp"
-#define USB_FUNC_UMS  "mass_storage"
-
 class AutoMounter;
 
 static void SetAutoMounterStatus(int32_t aStatus);
 
 /***************************************************************************/
 
 inline const char* SwitchStateStr(const SwitchEvent& aEvent)
 {
@@ -120,68 +110,46 @@ IsUsbCablePluggedIn()
   // Use this code when bug 745078 gets fixed (or use whatever the
   // appropriate method is)
   return GetCurrentSwitchEvent(SWITCH_USB) == SWITCH_STATE_ON;
 #else
   // Until then, just go read the file directly
   if (access(ICS_SYS_USB_STATE, F_OK) == 0) {
     char usbState[20];
     if (ReadSysFile(ICS_SYS_USB_STATE, usbState, sizeof(usbState))) {
-      DBG("IsUsbCablePluggedIn: state = '%s'", usbState);
-      return strcmp(usbState, "CONFIGURED") == 0 ||
-             strcmp(usbState, "CONNECTED") == 0;
+      return strcmp(usbState, "CONFIGURED") == 0;
     }
     ERR("Error reading file '%s': %s", ICS_SYS_USB_STATE, strerror(errno));
     return false;
   }
   bool configured;
   if (ReadSysFile(GB_SYS_USB_CONFIGURED, &configured)) {
     return configured;
   }
   ERR("Error reading file '%s': %s", GB_SYS_USB_CONFIGURED, strerror(errno));
   return false;
 #endif
 }
 
-static bool
-IsUsbConfigured()
-{
-  if (access(ICS_SYS_USB_STATE, F_OK) == 0) {
-    char usbState[20];
-    if (ReadSysFile(ICS_SYS_USB_STATE, usbState, sizeof(usbState))) {
-      DBG("IsUsbConfigured: state = '%s'", usbState);
-      return strcmp(usbState, "CONFIGURED") == 0;
-    }
-    ERR("Error reading file '%s': %s", ICS_SYS_USB_STATE, strerror(errno));
-    return false;
-  }
-  bool configured;
-  if (ReadSysFile(GB_SYS_USB_CONFIGURED, &configured)) {
-    return configured;
-  }
-  ERR("Error reading file '%s': %s", GB_SYS_USB_CONFIGURED, strerror(errno));
-  return false;
-}
-
 /***************************************************************************/
 
 // The AutoVolumeManagerStateObserver allows the AutoMounter to know when
 // the volume manager changes state (i.e. it has finished initialization)
 class AutoVolumeManagerStateObserver : public VolumeManager::StateObserver
 {
 public:
   virtual void Notify(const VolumeManager::StateChangedEvent& aEvent);
 };
 
 // The AutoVolumeEventObserver allows the AutoMounter to know about card
 // insertion and removal, as well as state changes in the volume.
 class AutoVolumeEventObserver : public Volume::EventObserver
 {
 public:
-  virtual void Notify(Volume* const& aEvent);
+  virtual void Notify(Volume * const & aEvent);
 };
 
 class AutoMounterResponseCallback : public VolumeResponseCallback
 {
 public:
   AutoMounterResponseCallback()
     : mErrorCount(0)
   {
@@ -201,18 +169,17 @@ private:
 class AutoMounter
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(AutoMounter)
 
   typedef nsTArray<RefPtr<Volume>> VolumeArray;
 
   AutoMounter()
-    : mState(STATE_IDLE),
-      mResponseCallback(new AutoMounterResponseCallback),
+    : mResponseCallback(new AutoMounterResponseCallback),
       mMode(AUTOMOUNTER_DISABLE)
   {
     VolumeManager::RegisterStateObserver(&mVolumeManagerStateObserver);
     Volume::RegisterObserver(&mVolumeEventObserver);
 
     // It's possible that the VolumeManager is already in the READY state,
     // so we call CheckVolumeSettings here to cover that case. Otherwise,
     // we'll pick it up when the VolumeManage state changes to VOLUMES_READY.
@@ -260,55 +227,42 @@ public:
 
         // Note: eventually CheckVolumeSettings will call
         //       AutoMounter::SetSharingMode, which will in turn call
         //       UpdateState if needed.
       }
     }
   }
 
-  void UpdateState();
-
-  void ConfigureUsbFunction(const char* aUsbFunc);
-
   void StartMtpServer();
   void StopMtpServer();
 
-  void StartUmsSharing();
-  void StopUmsSharing();
-
+  void UpdateState();
 
   const char* ModeStr(int32_t aMode)
   {
     switch (aMode) {
       case AUTOMOUNTER_DISABLE:                 return "Disable";
-      case AUTOMOUNTER_ENABLE_UMS:              return "Enable-UMS";
+      case AUTOMOUNTER_ENABLE:                  return "Enable";
       case AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED:  return "DisableWhenUnplugged";
-      case AUTOMOUNTER_ENABLE_MTP:              return "Enable-MTP";
     }
     return "??? Unknown ???";
   }
 
-  bool IsModeEnabled(int32_t aMode)
-  {
-    return aMode == AUTOMOUNTER_ENABLE_MTP ||
-           aMode == AUTOMOUNTER_ENABLE_UMS;
-  }
-
   void SetMode(int32_t aMode)
   {
     if ((aMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) &&
         (mMode == AUTOMOUNTER_DISABLE)) {
       // If it's already disabled, then leave it as disabled.
       // AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED implies "enabled until unplugged"
       aMode = AUTOMOUNTER_DISABLE;
     }
 
-    if (aMode == AUTOMOUNTER_DISABLE &&
-        mMode == AUTOMOUNTER_ENABLE_UMS && IsUsbCablePluggedIn()) {
+    if ((aMode == AUTOMOUNTER_DISABLE) &&
+        (mMode == AUTOMOUNTER_ENABLE) && IsUsbCablePluggedIn()) {
       // On many devices (esp non-Samsung), we can't force the disable, so we
       // need to defer until the USB cable is actually unplugged.
       // See bug 777043.
       //
       // Otherwise our attempt to disable it will fail, and we'll wind up in a bad
       // state where the AutoMounter thinks that Sharing has been turned off, but
       // the files are actually still being Shared because the attempt to unshare
       // failed.
@@ -387,74 +341,20 @@ public:
     vol->SetUnmountRequested(true);
     DBG("Calling UpdateState due to volume %s unmounting set to %d",
         vol->NameStr(), (int)vol->IsUnmountRequested());
     UpdateState();
   }
 
 private:
 
-  enum STATE
-  {
-    // IDLE - Nothing is being shared
-    STATE_IDLE,
-
-    // We've detected that conditions are right to enable mtp. So we've
-    // set sys.usb.config to include mtp, and we're waiting for the USB
-    // subsystem to be "configured". Once mtp shows up in
-    //  then we know
-    // that its been configured and we can open /dev/mtp_usb
-    STATE_MTP_CONFIGURING,
-
-    // mtp has been configured (i.e. mtp now shows up in
-    // /sys/devices/virtual/android_usb/android0/functions so we can start
-    // the mtp server.
-    STATE_MTP_STARTED,
-
-    // The mtp server has reported sessionStarted. We'll leave this state
-    // when we receive sessionEnded.
-    STATE_MTP_CONNECTED,
-
-    // We've added mass_storage (aka UMS) to sys.usb.config and we're waiting for
-    // mass_storage to appear in /sys/devices/virtual/android_usb/android0/functions
-    STATE_UMS_CONFIGURING,
-
-    // mass_storage has been configured and we can start sharing once the user
-    // enables it.
-    STATE_UMS_CONFIGURED,
-  };
-
-  const char *StateStr(STATE aState)
-  {
-    switch (aState) {
-      case STATE_IDLE:            return "IDLE";
-      case STATE_MTP_CONFIGURING: return "MTP_CONFIGURING";
-      case STATE_MTP_CONNECTED:   return "MTP_CONNECTED";
-      case STATE_MTP_STARTED:     return "MTP_STARTED";
-      case STATE_UMS_CONFIGURING: return "UMS_CONFIGURING";
-      case STATE_UMS_CONFIGURED:  return "UMS_CONFIGURED";
-    }
-    return "STATE_???";
-  }
-
-  void SetState(STATE aState)
-  {
-    const char *oldStateStr = StateStr(mState);
-    mState = aState;
-    const char *newStateStr = StateStr(mState);
-    LOG("AutoMounter state changed from %s to %s", oldStateStr, newStateStr);
-  }
-
-  STATE                           mState;
-
   AutoVolumeEventObserver         mVolumeEventObserver;
   AutoVolumeManagerStateObserver  mVolumeManagerStateObserver;
   RefPtr<VolumeResponseCallback>  mResponseCallback;
   int32_t                         mMode;
-  MozMtpStorage::Array            mMozMtpStorage;
 };
 
 static StaticRefPtr<AutoMounter> sAutoMounter;
 static StaticRefPtr<MozMtpServer> sMozMtpServer;
 
 /***************************************************************************/
 
 void
@@ -500,114 +400,32 @@ AutoMounterResponseCallback::ResponseRec
       aCommand->CmdStr(), ResponseCode(), ResponseStr().get());
 
   if (++mErrorCount < kMaxErrorCount) {
     DBG("Calling UpdateState due to VolumeResponseCallback::OnError");
     sAutoMounter->UpdateState();
   }
 }
 
-static bool
-IsUsbFunctionEnabled(const char* aConfig, const char* aUsbFunc)
-{
-  nsAutoCString config(aConfig);
-  nsCCharSeparatedTokenizer tokenizer(config, ',');
-
-  while (tokenizer.hasMoreTokens()) {
-    nsAutoCString token(tokenizer.nextToken());
-    if (token.Equals(aUsbFunc)) {
-      DBG("IsUsbFunctionEnabled('%s', '%s'): returning true", aConfig, aUsbFunc);
-      return true;
-    }
-  }
-  DBG("IsUsbFunctionEnabled('%s', '%s'): returning false", aConfig, aUsbFunc);
-  return false;
-}
-
-static void
-SetUsbFunction(const char* aUsbFunc)
-{
-  char oldSysUsbConfig[PROPERTY_VALUE_MAX];
-  property_get(SYS_USB_CONFIG, oldSysUsbConfig, "");
-
-  if (IsUsbFunctionEnabled(oldSysUsbConfig, aUsbFunc)) {
-    // The function is already configured. Nothing else to do.
-    DBG("SetUsbFunction('%s') - already set - nothing to do", aUsbFunc);
-    return;
-  }
-
-  char newSysUsbConfig[PROPERTY_VALUE_MAX];
-
-  if (strcmp(aUsbFunc, USB_FUNC_MTP) == 0) {
-    // We're enabling MTP. For this we'll wind up using mtp, or mtp,adb
-    strlcpy(newSysUsbConfig, USB_FUNC_MTP, sizeof(newSysUsbConfig));
-  } else if (strcmp(aUsbFunc, USB_FUNC_UMS) == 0) {
-    // We're enabling UMS. For this we make the assumption that the persisted
-    // property has mass_storage enabled.
-    property_get(PERSIST_SYS_USB_CONFIG, newSysUsbConfig, "");
-  } else {
-    printf_stderr("AutoMounter::SetUsbFunction Unrecognized aUsbFunc '%s'\n", aUsbFunc);
-    MOZ_ASSERT(0);
-    return;
-  }
-
-  // Make sure the new value that we write into sys.usb.config keeps the adb
-  // (or non-adb) of the current string.
-
-  if (IsUsbFunctionEnabled(oldSysUsbConfig, USB_FUNC_ADB)) {
-    // ADB was turned on - keep it on.
-    if (!IsUsbFunctionEnabled(newSysUsbConfig, USB_FUNC_ADB)) {
-      // Add adb to the new string
-      strlcat(newSysUsbConfig, ",", sizeof(newSysUsbConfig));
-      strlcat(newSysUsbConfig, USB_FUNC_ADB, sizeof(newSysUsbConfig));
-    }
-  } else {
-    // ADB was turned off - keep it off
-    if (IsUsbFunctionEnabled(newSysUsbConfig, USB_FUNC_ADB)) {
-      // Remove ADB from the new string.
-      if (strcmp(newSysUsbConfig, USB_FUNC_ADB) == 0) {
-        newSysUsbConfig[0] = '\0';
-      } else {
-        nsAutoCString withoutAdb(newSysUsbConfig);
-        withoutAdb.ReplaceSubstring( "," USB_FUNC_ADB, "");
-        strlcpy(newSysUsbConfig, withoutAdb.get(), sizeof(newSysUsbConfig));
-      }
-    }
-  }
-
-  LOG("SetUsbFunction(%s) %s to '%s'", aUsbFunc, SYS_USB_CONFIG, newSysUsbConfig);
-  property_set(SYS_USB_CONFIG, newSysUsbConfig);
-}
-
 void
 AutoMounter::StartMtpServer()
 {
   if (sMozMtpServer) {
     // Mtp Server is already running - nothing to do
     return;
   }
   LOG("Starting MtpServer");
   sMozMtpServer = new MozMtpServer();
   sMozMtpServer->Run();
-
-  VolumeArray::index_type volIndex;
-  VolumeArray::size_type  numVolumes = VolumeManager::NumVolumes();
-  for (volIndex = 0; volIndex < numVolumes; volIndex++) {
-    RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex);
-    nsRefPtr<MozMtpStorage> storage = new MozMtpStorage(vol, sMozMtpServer);
-    mMozMtpStorage.AppendElement(storage);
-  }
 }
 
 void
 AutoMounter::StopMtpServer()
 {
   LOG("Stopping MtpServer");
-
-  mMozMtpStorage.Clear();
   sMozMtpServer = nullptr;
 }
 
 /***************************************************************************/
 
 void
 AutoMounter::UpdateState()
 {
@@ -642,196 +460,76 @@ AutoMounter::UpdateState()
   }
 
   if (mResponseCallback->IsPending()) {
     // We only deal with one outstanding volume command at a time,
     // so we need to wait for it to finish.
     return;
   }
 
-  // Calling setprop sys.usb.config mtp,adb (or adding mass_storage) will
-  // cause /sys/devices/virtual/android_usb/android0/state to go:
-  // CONFIGURED -> DISCONNECTED -> CONNECTED -> CONFIGURED
-  //
-  // Since IsUsbCablePluggedIn returns state == CONFIGURED, it will look
-  // like a cable pull and replugin.
-
-  bool umsAvail = false;
-  bool umsConfigured = false;
-  bool umsEnabled = false;
-  bool mtpAvail = false;
-  bool mtpConfigured = false;
-  bool mtpEnabled = false;
-  bool usbCablePluggedIn = IsUsbCablePluggedIn();
+  bool  umsAvail = false;
+  bool  umsEnabled = false;
+  bool  mtpAvail = false;
+  bool  mtpEnabled = false;
 
   if (access(ICS_SYS_USB_FUNCTIONS, F_OK) == 0) {
     char functionsStr[60];
     if (!ReadSysFile(ICS_SYS_USB_FUNCTIONS, functionsStr, sizeof(functionsStr))) {
       ERR("Error reading file '%s': %s", ICS_SYS_USB_FUNCTIONS, strerror(errno));
       functionsStr[0] = '\0';
     }
-    DBG("UpdateState: USB functions: '%s'", functionsStr);
-
-    bool  usbConfigured = IsUsbConfigured();
     umsAvail = (access(ICS_SYS_UMS_DIRECTORY, F_OK) == 0);
     if (umsAvail) {
-      umsConfigured = usbConfigured && strstr(functionsStr, USB_FUNC_UMS) != nullptr;
-      umsEnabled = (mMode == AUTOMOUNTER_ENABLE_UMS) ||
-                   (mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) && umsConfigured;
-    } else {
-      umsConfigured = false;
-      umsEnabled = false;
+      umsEnabled = strstr(functionsStr, "mass_storage") != nullptr;
     }
-
     mtpAvail = (access(ICS_SYS_MTP_DIRECTORY, F_OK) == 0);
     if (mtpAvail) {
-      mtpConfigured = usbConfigured && strstr(functionsStr, USB_FUNC_MTP) != nullptr;
-      mtpEnabled = (mMode == AUTOMOUNTER_ENABLE_MTP) ||
-                   (mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) && mtpConfigured;
-    } else {
-      mtpConfigured = false;
-      mtpEnabled = false;
-    }
-  }
-
-  bool enabled = mtpEnabled || umsEnabled;
-
-  if (mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) {
-    // DISABLE_WHEN_UNPLUGGED implies already enabled.
-    enabled = usbCablePluggedIn;
-    if (!usbCablePluggedIn) {
-      mMode = AUTOMOUNTER_DISABLE;
-      mtpEnabled = false;
-      umsEnabled = false;
+      mtpEnabled = strstr(functionsStr, "mtp") != nullptr;
     }
   }
 
-  DBG("UpdateState: ums:A%dC%dE%d mtp:A%dC%dE%d mode:%d usb:%d mState:%s",
-      umsAvail, umsConfigured, umsEnabled,
-      mtpAvail, mtpConfigured, mtpEnabled,
-      mMode, usbCablePluggedIn, StateStr(mState));
-
-  switch (mState) {
-
-    case STATE_IDLE:
-      if (!usbCablePluggedIn) {
-        // Stay in the IDLE state. We'll get a CONNECTED or CONFIGURED
-        // UEvent when the usb cable is plugged in.
-        break;
-      }
-      if (mtpEnabled) {
-        if (mtpConfigured) {
-          // The USB layer has already been configured. Now we can go ahead
-          // and start the MTP server. This particular codepath will not
-          // normally be taken, but it could happen if you stop and restart
-          // b2g while sys.usb.config is set to enable mtp.
-          StartMtpServer();
-          SetState(STATE_MTP_STARTED);
-        } else {
-          // The MTP USB layer is configuring. Wait for it to finish
-          // before we start the MTP server.
-          SetUsbFunction(USB_FUNC_MTP);
-          SetState(STATE_MTP_CONFIGURING);
-        }
-      } else if (umsConfigured) {
-        // UMS is already configured.
-        SetState(STATE_UMS_CONFIGURED);
-      } else if (umsAvail) {
-        // We do this whether or not UMS is enabled. With UMS, it's the
-        // sharing of the volume which is significant. What is important
-        // is that we don't leave it in MTP mode when MTP isn't enabled.
-        SetUsbFunction(USB_FUNC_UMS);
-        SetState(STATE_UMS_CONFIGURING);
-      }
-      break;
+  bool usbCablePluggedIn = IsUsbCablePluggedIn();
+  bool enabled = (mMode == AUTOMOUNTER_ENABLE);
 
-    case STATE_MTP_CONFIGURING:
-      // While configuring, the USB configuration state will change from
-      // CONFIGURED -> CONNECTED -> DISCONNECTED -> CONNECTED -> CONFIGURED
-      // so we don't check for cable unplugged here.
-      if (mtpEnabled && mtpConfigured) {
-        // The USB layer has been configured. Now we can go ahead and start
-        // the MTP server.
-        StartMtpServer();
-        SetState(STATE_MTP_STARTED);
-      }
-      break;
-
-    case STATE_MTP_STARTED:
-      if (usbCablePluggedIn) {
-        if (mtpConfigured && mtpEnabled) {
-          // Everything is still good. Leave the MTP server running
-          break;
-        }
-        DBG("STATE_MTP_STARTED: About to StopMtpServer "
-            "mtpConfigured = %d mtpEnabled = %d usbCablePluggedIn: %d",
-            mtpConfigured, mtpEnabled, usbCablePluggedIn);
-        StopMtpServer();
-        if (umsAvail) {
-          // Switch back to UMS
-          SetUsbFunction(USB_FUNC_UMS);
-          SetState(STATE_UMS_CONFIGURING);
-          break;
-        }
-      }
-      SetState(STATE_IDLE);
-      break;
-
-    case STATE_UMS_CONFIGURING:
-      // While configuring, the USB configuration state will change from
-      // CONFIGURED -> CONNECTED -> DISCONNECTED -> CONNECTED -> CONFIGURED
-      // so we don't check for cable unplugged here.
-      if (umsConfigured) {
-        SetState(STATE_UMS_CONFIGURED);
-      }
-      break;
-
-    case STATE_UMS_CONFIGURED:
-      if (usbCablePluggedIn) {
-        if (mtpEnabled) {
-          // MTP was enabled. Start reconfiguring.
-          SetState(STATE_MTP_CONFIGURING);
-          SetUsbFunction(USB_FUNC_MTP);
-          break;
-        }
-        if (umsConfigured && umsEnabled) {
-          // This is the normal state when UMS is enabled.
-          break;
-        }
-      }
-      SetState(STATE_IDLE);
-      break;
-
-    default:
-      SetState(STATE_IDLE);
-      break;
+  if (mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) {
+    enabled = usbCablePluggedIn;
+    if (!usbCablePluggedIn) {
+      mMode = AUTOMOUNTER_DISABLE;
+    }
   }
 
-  bool tryToShare = umsEnabled && usbCablePluggedIn;
-  LOG("UpdateState: ums:A%dC%dE%d mtp:A%dC%dE%d mode:%d usb:%d tryToShare:%d state:%s",
-      umsAvail, umsConfigured, umsEnabled,
-      mtpAvail, mtpConfigured, mtpEnabled,
-      mMode, usbCablePluggedIn, tryToShare, StateStr(mState));
+  bool tryToShare = (((umsAvail && umsEnabled) || (mtpAvail && mtpEnabled))
+                  && enabled && usbCablePluggedIn);
+  LOG("UpdateState: ums:%d%d mtp:%d%d mode:%d usbCablePluggedIn:%d tryToShare:%d",
+      umsAvail, umsEnabled, mtpAvail, mtpEnabled, mMode, usbCablePluggedIn, tryToShare);
+
+  if (mtpAvail && mtpEnabled) {
+    if (enabled && usbCablePluggedIn) {
+      StartMtpServer();
+    } else {
+      StopMtpServer();
+    }
+    return;
+  }
 
   bool filesOpen = false;
   static unsigned filesOpenDelayCount = 0;
   VolumeArray::index_type volIndex;
   VolumeArray::size_type  numVolumes = VolumeManager::NumVolumes();
   for (volIndex = 0; volIndex < numVolumes; volIndex++) {
     RefPtr<Volume>  vol = VolumeManager::GetVolume(volIndex);
     Volume::STATE   volState = vol->State();
 
     if (vol->State() == nsIVolume::STATE_MOUNTED) {
       LOG("UpdateState: Volume %s is %s and %s @ %s gen %d locked %d sharing %s",
           vol->NameStr(), vol->StateStr(),
           vol->MediaPresent() ? "inserted" : "missing",
           vol->MountPoint().get(), vol->MountGeneration(),
           (int)vol->IsMountLocked(),
-          vol->CanBeShared() ? (vol->IsSharingEnabled() ?
-                                 (vol->IsSharing() ? "en-y" : "en-n") : "dis") : "x");
+          vol->CanBeShared() ? (vol->IsSharingEnabled() ? (vol->IsSharing() ? "en-y" : "en-n") : "dis") : "x");
       if (vol->IsSharing() && !usbCablePluggedIn) {
         // We call SetIsSharing(true) below to indicate intent to share. This
         // causes a state change which notifys apps, and they'll close any
         // open files, which will initiate the change away from the mounted
         // state and into the sharing state. Normally, when the volume
         // transitions back to the mounted state, then vol->mIsSharing gets set
         // to false. However, if the user pulls the USB cable before we
         // actually start sharing, then the volume never actually leaves
@@ -1237,17 +935,16 @@ AutoMounterUnmountVolume(const nsCString
       NewRunnableFunction(AutoMounterUnmountVolumeIOThread,
                           aVolumeName));
 }
 
 void
 ShutdownAutoMounter()
 {
   if (sAutoMounter) {
-    DBG("ShutdownAutoMounter: About to StopMtpServer");
     sAutoMounter->StopMtpServer();
   }
   sAutoMounterSetting = nullptr;
   sUsbCableObserver = nullptr;
 
   XRE_GetIOMessageLoop()->PostTask(
       FROM_HERE,
       NewRunnableFunction(ShutdownAutoMounterIOThread));
--- a/dom/system/gonk/AutoMounter.h
+++ b/dom/system/gonk/AutoMounter.h
@@ -9,19 +9,18 @@
 
 class nsCString;
 
 namespace mozilla {
 namespace system {
 
 // AutoMounter modes
 #define AUTOMOUNTER_DISABLE                 0
-#define AUTOMOUNTER_ENABLE_UMS              1
+#define AUTOMOUNTER_ENABLE                  1
 #define AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED  2
-#define AUTOMOUNTER_ENABLE_MTP              3
 
 // Automounter statuses
 #define AUTOMOUNTER_STATUS_DISABLED         0
 #define AUTOMOUNTER_STATUS_ENABLED          1
 #define AUTOMOUNTER_STATUS_FILES_OPEN       2
 
 /**
  * Initialize the automounter. This causes some of the phone's
--- a/dom/system/gonk/MozMtpDatabase.cpp
+++ b/dom/system/gonk/MozMtpDatabase.cpp
@@ -35,42 +35,44 @@ ObjectPropertyAsStr(MtpObjectProperty aP
     case MTP_PROPERTY_WIDTH:            return "MTP_PROPERTY_WIDTH";
     case MTP_PROPERTY_HEIGHT:           return "MTP_PROPERTY_HEIGHT";
     case MTP_PROPERTY_IMAGE_BIT_DEPTH:  return "MTP_PROPERTY_IMAGE_BIT_DEPTH";
     case MTP_PROPERTY_DISPLAY_NAME:     return "MTP_PROPERTY_DISPLAY_NAME";
   }
   return "MTP_PROPERTY_???";
 }
 
-MozMtpDatabase::MozMtpDatabase()
+MozMtpDatabase::MozMtpDatabase(const char *aDir)
 {
-  MTP_LOG("constructed");
+  MTP_LOG("");
 
   // We use the index into the array as the handle. Since zero isn't a valid
   // index, we stick a dummy entry there.
 
   RefPtr<DbEntry> dummy;
 
   mDb.AppendElement(dummy);
+
+  ReadVolume("sdcard", aDir);
 }
 
 //virtual
 MozMtpDatabase::~MozMtpDatabase()
 {
-  MTP_LOG("destructed");
+  MTP_LOG("");
 }
 
 void
 MozMtpDatabase::AddEntry(DbEntry *entry)
 {
   entry->mHandle = GetNextHandle();
   MOZ_ASSERT(mDb.Length() == entry->mHandle);
   mDb.AppendElement(entry);
 
-  MTP_LOG("Handle: 0x%08x Parent: 0x%08x Path:'%s'",
+  MTP_LOG("AddEntry: Handle: 0x%08x Parent: 0x%08x Path:'%s'",
           entry->mHandle, entry->mParent, entry->mPath.get());
 }
 
 TemporaryRef<MozMtpDatabase::DbEntry>
 MozMtpDatabase::GetEntry(MtpObjectHandle aHandle)
 {
   RefPtr<DbEntry> entry;
 
@@ -113,108 +115,87 @@ GetPathWithoutFileName(const nsCString& 
   }
 
   MTP_LOG("returning '%s'", path.get());
 
   return path;
 }
 
 void
-MozMtpDatabase::AddDirectory(MtpStorageID aStorageID,
-                             const char* aPath,
-                             MtpObjectHandle aParent)
+MozMtpDatabase::ParseDirectory(const char *aDir, MtpObjectHandle aParent)
 {
   ScopedCloseDir dir;
 
-  if (!(dir = PR_OpenDir(aPath))) {
-    MTP_ERR("Unable to open directory '%s'", aPath);
+  if (!(dir = PR_OpenDir(aDir))) {
+    MTP_ERR("Unable to open directory '%s'", aDir);
     return;
   }
 
   PRDirEntry* dirEntry;
   while ((dirEntry = PR_ReadDir(dir, PR_SKIP_BOTH))) {
-    nsPrintfCString filename("%s/%s", aPath, dirEntry->name);
+    nsPrintfCString filename("%s/%s", aDir, dirEntry->name);
     PRFileInfo64 fileInfo;
     if (PR_GetFileInfo64(filename.get(), &fileInfo) != PR_SUCCESS) {
       MTP_ERR("Unable to retrieve file information for '%s'", filename.get());
       continue;
     }
 
     RefPtr<DbEntry> entry = new DbEntry;
 
-    entry->mStorageID = aStorageID;
+    entry->mStorageID = MTP_STORAGE_FIXED_RAM;
     entry->mParent = aParent;
     entry->mObjectName = dirEntry->name;
     entry->mDisplayName = dirEntry->name;
     entry->mPath = filename;
     entry->mDateCreated = fileInfo.creationTime;
     entry->mDateModified = fileInfo.modifyTime;
 
     if (fileInfo.type == PR_FILE_FILE) {
       entry->mObjectFormat = MTP_FORMAT_DEFINED;
       //TODO: Check how 64-bit filesize are dealt with
       entry->mObjectSize = fileInfo.size;
       AddEntry(entry);
     } else if (fileInfo.type == PR_FILE_DIRECTORY) {
       entry->mObjectFormat = MTP_FORMAT_ASSOCIATION;
       entry->mObjectSize = 0;
       AddEntry(entry);
-      AddDirectory(aStorageID, filename.get(), entry->mHandle);
+      ParseDirectory(filename.get(), entry->mHandle);
     }
   }
 }
 
 void
-MozMtpDatabase::AddStorage(MtpStorageID aStorageID,
-                           const char* aPath,
-                           const char* aName)
+MozMtpDatabase::ReadVolume(const char *volumeName, const char *aDir)
 {
   //TODO: Add an assert re thread being run on
 
   PRFileInfo  fileInfo;
 
-  if (PR_GetFileInfo(aPath, &fileInfo) != PR_SUCCESS) {
-    MTP_ERR("'%s' doesn't exist", aPath);
+  if (PR_GetFileInfo(aDir, &fileInfo) != PR_SUCCESS) {
+    MTP_ERR("'%s' doesn't exist", aDir);
     return;
   }
   if (fileInfo.type != PR_FILE_DIRECTORY) {
-    MTP_ERR("'%s' isn't a directory", aPath);
+    MTP_ERR("'%s' isn't a directory", aDir);
     return;
   }
 
-#if 0
   RefPtr<DbEntry> entry = new DbEntry;
 
-  entry->mStorageID = aStorageID;
+  entry->mStorageID = MTP_STORAGE_FIXED_RAM;
   entry->mParent = MTP_PARENT_ROOT;
-  entry->mObjectName = aName;
-  entry->mDisplayName = aName;
-  entry->mPath = aPath;
+  entry->mObjectName = volumeName;
+  entry->mDisplayName = volumeName;
+  entry->mPath = aDir;
   entry->mObjectFormat = MTP_FORMAT_ASSOCIATION;
   entry->mObjectSize = 0;
 
   AddEntry(entry);
 
-  AddDirectory(aStorageID, aPath, entry->mHandle);
-#else
-  AddDirectory(aStorageID, aPath, MTP_PARENT_ROOT);
-#endif
-}
-
-void
-MozMtpDatabase::RemoveStorage(MtpStorageID aStorageID)
-{
-  DbArray::size_type numEntries = mDb.Length();
-  DbArray::index_type entryIndex;
-  for (entryIndex = 1; entryIndex < numEntries; entryIndex++) {
-    RefPtr<DbEntry> entry = mDb[entryIndex];
-    if (entry && entry->mStorageID == aStorageID) {
-      mDb[entryIndex] = nullptr;
-    }
-  }
+  ParseDirectory(aDir, entry->mHandle);
 }
 
 // called from SendObjectInfo to reserve a database entry for the incoming file
 //virtual
 MtpObjectHandle
 MozMtpDatabase::beginSendObject(const char* aPath,
                               MtpObjectFormat aFormat,
                               MtpObjectHandle aParent,
@@ -246,75 +227,61 @@ MozMtpDatabase::beginSendObject(const ch
 
 // called to report success or failure of the SendObject file transfer
 // success should signal a notification of the new object's creation,
 // failure should remove the database entry created in beginSendObject
 
 //virtual
 void
 MozMtpDatabase::endSendObject(const char* aPath,
-                              MtpObjectHandle aHandle,
-                              MtpObjectFormat aFormat,
-                              bool aSucceeded)
+                            MtpObjectHandle aHandle,
+                            MtpObjectFormat aFormat,
+                            bool succeeded)
 {
   MTP_LOG("Handle: 0x%08x Path: '%s'", aHandle, aPath);
-  if (!aSucceeded) {
+  if (!succeeded) {
     RemoveEntry(aHandle);
   }
 }
 
 //virtual
 MtpObjectHandleList*
 MozMtpDatabase::getObjectList(MtpStorageID aStorageID,
-                              MtpObjectFormat aFormat,
-                              MtpObjectHandle aParent)
+                            MtpObjectFormat aFormat,
+                            MtpObjectHandle aParent)
 {
   MTP_LOG("StorageID: 0x%08x Format: 0x%04x Parent: 0x%08x",
           aStorageID, aFormat, aParent);
 
   //TODO: Optimize
 
   ScopedDeletePtr<MtpObjectHandleList> list;
 
   list = new MtpObjectHandleList();
 
-  // Note: objects in the topmost directory of each storage area have a parent
-  //       of MTP_PARENT_ROOT. So we need to filter on storage ID as well.
-
   DbArray::size_type numEntries = mDb.Length();
   DbArray::index_type entryIndex;
   for (entryIndex = 1; entryIndex < numEntries; entryIndex++) {
     RefPtr<DbEntry> entry = mDb[entryIndex];
-    if (entry && entry->mStorageID == aStorageID && entry->mParent == aParent) {
+    if (entry && entry->mParent == aParent) {
       list->push(entry->mHandle);
     }
   }
   return list.forget();
 }
 
 //virtual
 int
 MozMtpDatabase::getNumObjects(MtpStorageID aStorageID,
-                              MtpObjectFormat aFormat,
-                              MtpObjectHandle aParent)
+                            MtpObjectFormat aFormat,
+                            MtpObjectHandle aParent)
 {
   MTP_LOG("");
 
-  int count = 0;
-
-  DbArray::size_type numEntries = mDb.Length();
-  DbArray::index_type entryIndex;
-  for (entryIndex = 1; entryIndex < numEntries; entryIndex++) {
-    RefPtr<DbEntry> entry = mDb[entryIndex];
-    if (entry && entry->mStorageID == aStorageID) {
-      count++;
-    }
-  }
-
-  return count;
+  return mDb.Length() - 1;
 }
 
 //virtual
 MtpObjectFormatList*
 MozMtpDatabase::getSupportedPlaybackFormats()
 {
   static const uint16_t init_data[] = {MTP_FORMAT_UNDEFINED, MTP_FORMAT_ASSOCIATION, MTP_FORMAT_PNG};
 
@@ -372,18 +339,18 @@ MozMtpDatabase::getSupportedDeviceProper
   MtpDevicePropertyList *list = new MtpDevicePropertyList();
   list->appendArray(init_data, MOZ_ARRAY_LENGTH(init_data));
   return list;
 }
 
 //virtual
 MtpResponseCode
 MozMtpDatabase::getObjectPropertyValue(MtpObjectHandle aHandle,
-                                       MtpObjectProperty aProperty,
-                                       MtpDataPacket& aPacket)
+                                     MtpObjectProperty aProperty,
+                                     MtpDataPacket& aPacket)
 {
   RefPtr<DbEntry> entry = GetEntry(aHandle);
   if (!entry) {
     MTP_ERR("Invalid Handle: 0x%08x", aHandle);
     return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
   }
 
   MTP_LOG("Handle: 0x%08x '%s' Property: %s 0x%08x",
@@ -445,18 +412,18 @@ GetTypeOfObjectProp(MtpObjectProperty aP
   }
 
   return type;
 }
 
 //virtual
 MtpResponseCode
 MozMtpDatabase::setObjectPropertyValue(MtpObjectHandle aHandle,
-                                       MtpObjectProperty aProperty,
-                                       MtpDataPacket& aPacket)
+                                     MtpObjectProperty aProperty,
+                                     MtpDataPacket& aPacket)
 {
   MTP_LOG("Handle: 0x%08x Property: 0x%08x", aHandle, aProperty);
 
   // Only support file name change
   if (aProperty != MTP_PROPERTY_OBJECT_FILE_NAME) {
     MTP_ERR("property 0x%x not supported", aProperty);
     return  MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
   }
@@ -491,26 +458,26 @@ MozMtpDatabase::setObjectPropertyValue(M
   entry->mDisplayName = entry->mObjectName;
 
   return MTP_RESPONSE_OK;
 }
 
 //virtual
 MtpResponseCode
 MozMtpDatabase::getDevicePropertyValue(MtpDeviceProperty aProperty,
-                                       MtpDataPacket& aPacket)
+                                     MtpDataPacket& aPacket)
 {
   MTP_LOG("(GENERAL ERROR)");
   return MTP_RESPONSE_GENERAL_ERROR;
 }
 
 //virtual
 MtpResponseCode
 MozMtpDatabase::setDevicePropertyValue(MtpDeviceProperty aProperty,
-                                       MtpDataPacket& aPacket)
+                                     MtpDataPacket& aPacket)
 {
   MTP_LOG("(NOT SUPPORTED)");
   return MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
 }
 
 //virtual
 MtpResponseCode
 MozMtpDatabase::resetDeviceProperty(MtpDeviceProperty aProperty)
@@ -595,23 +562,23 @@ MozMtpDatabase::QueryEntries(MozMtpDatab
     default:
       MOZ_ASSERT(!"Invalid MatchType");
   }
 }
 
 //virtual
 MtpResponseCode
 MozMtpDatabase::getObjectPropertyList(MtpObjectHandle aHandle,
-                                      uint32_t aFormat,
-                                      uint32_t aProperty,
-                                      int aGroupCode,
-                                      int aDepth,
-                                      MtpDataPacket& aPacket)
+                                    uint32_t aFormat,
+                                    uint32_t aProperty,
+                                    int aGroupCode,
+                                    int aDepth,
+                                    MtpDataPacket& aPacket)
 {
-  MTP_LOG("Handle: 0x%08x Format: 0x%08x aProperty: 0x%08x aGroupCode: %d aDepth %d",
+  MTP_LOG("Handle: 0x%08x Format: 0x%08x aProperty: 0x%08x aGroupCode: %d aDepth %d (NOT SUPPORTED)",
           aHandle, aFormat, aProperty, aGroupCode, aDepth);
 
   if (aDepth > 1) {
     return MTP_RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED;
   }
   if (aGroupCode != 0) {
     return MTP_RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED;
   }
@@ -754,17 +721,17 @@ MozMtpDatabase::getObjectPropertyList(Mt
     }
   }
   return MTP_RESPONSE_OK;
 }
 
 //virtual
 MtpResponseCode
 MozMtpDatabase::getObjectInfo(MtpObjectHandle aHandle,
-                              MtpObjectInfo& aInfo)
+                            MtpObjectInfo& aInfo)
 {
   RefPtr<DbEntry> entry = GetEntry(aHandle);
   if (!entry) {
     MTP_ERR("Handle 0x%08x is invalid", aHandle);
     return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
   }
 
   MTP_LOG("Handle: 0x%08x Display:'%s' Object:'%s'", aHandle, entry->mDisplayName.get(), entry->mObjectName.get());
@@ -808,19 +775,19 @@ MozMtpDatabase::getThumbnail(MtpObjectHa
   aOutThumbSize = 0;
 
   return nullptr;
 }
 
 //virtual
 MtpResponseCode
 MozMtpDatabase::getObjectFilePath(MtpObjectHandle aHandle,
-                                  MtpString& aOutFilePath,
-                                  int64_t& aOutFileLength,
-                                  MtpObjectFormat& aOutFormat)
+                                MtpString& aOutFilePath,
+                                int64_t& aOutFileLength,
+                                MtpObjectFormat& aOutFormat)
 {
   RefPtr<DbEntry> entry = GetEntry(aHandle);
   if (!entry) {
     MTP_ERR("Handle 0x%08x is invalid", aHandle);
     return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
   }
 
   MTP_LOG("Handle: 0x%08x FilePath: '%s'", aHandle, entry->mPath.get());
@@ -839,20 +806,16 @@ MozMtpDatabase::deleteFile(MtpObjectHand
   RefPtr<DbEntry> entry = GetEntry(aHandle);
   if (!entry) {
     MTP_ERR("Invalid Handle: 0x%08x", aHandle);
     return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
   }
 
   MTP_LOG("Handle: 0x%08x '%s'", aHandle, entry->mPath.get());
 
-  //TODO: MtpServer::doDeleteObject calls us, and then calls a private
-  //      method (deletePath) which recursively deletes the path.
-  // We need to tell device storage that these files are gone
-
   // File deletion will happen in lower level implementation.
   // The only thing we need to do is removing the entry from the db.
   RemoveEntry(aHandle);
 
   return MTP_RESPONSE_OK;
 }
 
 #if 0
@@ -886,17 +849,17 @@ MozMtpDatabase::getObjectReferences(MtpO
 {
   MTP_LOG("Handle: 0x%08x (returning nullptr)", aHandle);
   return nullptr;
 }
 
 //virtual
 MtpResponseCode
 MozMtpDatabase::setObjectReferences(MtpObjectHandle aHandle,
-                                    MtpObjectHandleList* aReferences)
+                                  MtpObjectHandleList* aReferences)
 {
   MTP_LOG("Handle: 0x%08x (NOT SUPPORTED)", aHandle);
   return MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
 }
 
 //virtual
 MtpProperty*
 MozMtpDatabase::getObjectPropertyDesc(MtpObjectProperty aProperty,
--- a/dom/system/gonk/MozMtpDatabase.h
+++ b/dom/system/gonk/MozMtpDatabase.h
@@ -17,19 +17,17 @@
 
 BEGIN_MTP_NAMESPACE // mozilla::system::mtp
 
 using namespace android;
 
 class MozMtpDatabase : public MtpDatabase
 {
 public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozMtpDatabase)
-
-  MozMtpDatabase();
+  MozMtpDatabase(const char *aDir);
   virtual ~MozMtpDatabase();
 
   // called from SendObjectInfo to reserve a database entry for the incoming file
   virtual MtpObjectHandle beginSendObject(const char* aPath,
                                           MtpObjectFormat aFormat,
                                           MtpObjectHandle aParent,
                                           MtpStorageID aStorageID,
                                           uint64_t aSize,
@@ -103,24 +101,21 @@ public:
                                              MtpObjectFormat aFormat);
 
   virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty aProperty);
 
   virtual void sessionStarted();
 
   virtual void sessionEnded();
 
-  void AddStorage(MtpStorageID aStorageID, const char* aPath, const char *aName);
-  void RemoveStorage(MtpStorageID aStorageID);
-
 private:
 
   struct DbEntry
   {
-    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DbEntry)
+    NS_INLINE_DECL_REFCOUNTING(DbEntry)
 
     MtpObjectHandle mHandle;        // uint32_t
     MtpStorageID    mStorageID;     // uint32_t
     nsCString       mObjectName;
     MtpObjectFormat mObjectFormat;  // uint16_t
     MtpObjectHandle mParent;        // uint32_t
     uint64_t        mObjectSize;
     nsCString       mDisplayName;
@@ -152,14 +147,15 @@ private:
   nsCString BaseName(const nsCString& aPath);
 
 
   MtpObjectHandle GetNextHandle()
   {
     return mDb.Length();
   }
 
-  void AddDirectory(MtpStorageID aStorageID, const char *aPath, MtpObjectHandle aParent);
+  void ParseDirectory(const char *aDir, MtpObjectHandle aParent);
+  void ReadVolume(const char *aVolumeName, const char *aDir);
 };
 
 END_MTP_NAMESPACE
 
 #endif // mozilla_system_mozmtpdatabase_h__
--- a/dom/system/gonk/MozMtpServer.cpp
+++ b/dom/system/gonk/MozMtpServer.cpp
@@ -11,93 +11,70 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
 #include <errno.h>
 #include <stdio.h>
 #include <unistd.h>
 
 #include <cutils/properties.h>
-#include <private/android_filesystem_config.h>
 
-#include "base/message_loop.h"
 #include "mozilla/FileUtils.h"
 #include "mozilla/Scoped.h"
-#include "mozilla/StaticPtr.h"
-#include "nsAutoPtr.h"
 #include "nsThreadUtils.h"
-#include "nsXULAppAPI.h"
-
-#include "Volume.h"
 
 using namespace android;
 using namespace mozilla;
-BEGIN_MTP_NAMESPACE
+USING_MTP_NAMESPACE
 
 class MtpServerRunnable : public nsRunnable
 {
 public:
-  MtpServerRunnable(int aMtpUsbFd, MozMtpServer* aMozMtpServer)
-    : mMozMtpServer(aMozMtpServer),
-      mMtpUsbFd(aMtpUsbFd)
-  {
-  }
-
   nsresult Run()
   {
-    nsRefPtr<RefCountedMtpServer> server = mMozMtpServer->GetMtpServer();
+    const char *mtpUsbFilename = "/dev/mtp_usb";
+    const char *productName = "FirefoxOS";
+    const char *storageDir = "/storage/sdcard";
+
+    mFd = open(mtpUsbFilename, O_RDWR);
+    if (mFd.get() < 0) {
+      MTP_LOG("open of '%s' failed", mtpUsbFilename);
+      return NS_OK;
+    }
+
+    MTP_LOG("MozMtpServer open done, fd: %d. Start reading.", mFd.get());
+
+    ScopedDeletePtr<MozMtpDatabase> database;
+    ScopedDeletePtr<MtpServer> server;
+    ScopedDeletePtr<MtpStorage> storage;
+
+    database = new MozMtpDatabase(storageDir);
+    server = new MtpServer(mFd.get(), database, false, 1023, 0664, 0775);
+    storage = new MtpStorage(MTP_STORAGE_FIXED_RAM,       // id
+                             storageDir,                  // filePath
+                             productName,                 // description
+                             100uLL * 1024uLL * 1024uLL,  // reserveSpace
+                             false,                       // removable
+                             2uLL * 1024uLL * 1024uLL * 1024uLL); // maxFileSize
+
+    server->addStorage(storage);
 
     MTP_LOG("MozMtpServer started");
     server->run();
     MTP_LOG("MozMtpServer finished");
 
     return NS_OK;
   }
 
 private:
-  nsRefPtr<MozMtpServer> mMozMtpServer;
-  ScopedClose mMtpUsbFd; // We want to hold this open while the server runs
+  ScopedClose mFd;
 };
 
-already_AddRefed<RefCountedMtpServer>
-MozMtpServer::GetMtpServer()
-{
-  nsRefPtr<RefCountedMtpServer> server = mMtpServer;
-  return server.forget();
-}
-
-already_AddRefed<MozMtpDatabase>
-MozMtpServer::GetMozMtpDatabase()
-{
-  nsRefPtr<MozMtpDatabase> db = mMozMtpDatabase;
-  return db.forget();
-}
-
 void
 MozMtpServer::Run()
 {
-  MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
-
-  const char *mtpUsbFilename = "/dev/mtp_usb";
-  ScopedClose mtpUsbFd(open(mtpUsbFilename, O_RDWR));
-  if (mtpUsbFd.get() < 0) {
-    MTP_ERR("open of '%s' failed", mtpUsbFilename);
-    return;
-  }
-  MTP_LOG("Opened '%s' fd %d", mtpUsbFilename, mtpUsbFd.get());
-
-  mMozMtpDatabase = new MozMtpDatabase();
-  mMtpServer = new RefCountedMtpServer(mtpUsbFd.get(),        // fd
-                                       mMozMtpDatabase.get(), // MtpDatabase
-                                       false,                 // ptp?
-                                       AID_MEDIA_RW,          // file group
-                                       0664,                  // file permissions
-                                       0775);                 // dir permissions
-
   nsresult rv = NS_NewNamedThread("MtpServer", getter_AddRefs(mServerThread));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
   MOZ_ASSERT(mServerThread);
-  mServerThread->Dispatch(new MtpServerRunnable(mtpUsbFd.forget(), this), NS_DISPATCH_NORMAL);
+  mServerThread->Dispatch(new MtpServerRunnable(), 0);
 }
-
-END_MTP_NAMESPACE
--- a/dom/system/gonk/MozMtpServer.h
+++ b/dom/system/gonk/MozMtpServer.h
@@ -3,58 +3,30 @@
 /* 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/. */
 
 #ifndef mozilla_system_mozmtpserver_h__
 #define mozilla_system_mozmtpserver_h__
 
 #include "MozMtpCommon.h"
-#include "MozMtpDatabase.h"
 
-#include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIThread.h"
 
-namespace mozilla {
-namespace system {
-  class Volume;
-}
-}
-
 BEGIN_MTP_NAMESPACE
-using namespace android;
-
-class RefCountedMtpServer : public MtpServer
-{
-public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMtpServer)
-
-  RefCountedMtpServer(int aFd, MtpDatabase* aDatabase, bool aPtp,
-                      int aFileGroup, int aFilePerm, int aDirectoryPerm)
-    : MtpServer(aFd, aDatabase, aPtp, aFileGroup, aFilePerm, aDirectoryPerm)
-  {
-  }
-};
 
 class MozMtpServer
 {
 public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozMtpServer)
+  NS_INLINE_DECL_REFCOUNTING(MozMtpServer)
 
   void Run();
 
-//  void UpdateStorage(android::MtpStorageID id, Volume *vol);
-
-  already_AddRefed<RefCountedMtpServer> GetMtpServer();
-  already_AddRefed<MozMtpDatabase> GetMozMtpDatabase();
-
 private:
-  nsRefPtr<RefCountedMtpServer> mMtpServer;
-  nsRefPtr<MozMtpDatabase> mMozMtpDatabase;
   nsCOMPtr<nsIThread> mServerThread;
 };
 
 END_MTP_NAMESPACE
 
 #endif  // mozilla_system_mozmtpserver_h__
 
 
deleted file mode 100644
--- a/dom/system/gonk/MozMtpStorage.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* 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/. */
-
-#include "MozMtpStorage.h"
-#include "MozMtpDatabase.h"
-#include "MozMtpServer.h"
-
-#include "base/message_loop.h"
-#include "nsXULAppAPI.h"
-
-BEGIN_MTP_NAMESPACE
-using namespace android;
-
-MozMtpStorage::MozMtpStorage(Volume* aVolume, MozMtpServer* aMozMtpServer)
-  : mMozMtpServer(aMozMtpServer),
-    mVolume(aVolume)
-{
-  MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
-
-  // The MtpStorageID has the physical volume in the top 16 bits, and the
-  // logical volumein the lower 16 bits. We treat each volume as a separate
-  // phsyical storage;
-  mStorageID = mVolume->Id() << 16 | 1;
-
-  MTP_LOG("Storage constructed for Volume %s mStorageID 0x%08x",
-          aVolume->NameStr(), mStorageID);
-
-  Volume::RegisterObserver(this);
-
-  // Get things in sync
-  Notify(mVolume);
-}
-
-MozMtpStorage::~MozMtpStorage()
-{
-  MTP_LOG("Storage destructed for Volume %s mStorageID 0x%08x",
-          mVolume->NameStr(), mStorageID);
-
-  Volume::UnregisterObserver(this);
-  if (mMtpStorage) {
-    StorageUnavailable();
-  }
-}
-
-// virtual
-void
-MozMtpStorage::Notify(Volume* const& aVolume)
-{
-  MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
-
-  if (aVolume != mVolume) {
-    // Not our volume
-    return;
-  }
-  Volume::STATE volState = aVolume->State();
-
-  MTP_LOG("Volume %s mStorageID 0x%08x state changed to %s SharingEnabled: %d",
-          aVolume->NameStr(), mStorageID, aVolume->StateStr(),
-          aVolume->IsSharingEnabled());
-
-  if (mMtpStorage) {
-    if (volState != nsIVolume::STATE_MOUNTED || !aVolume->IsSharingEnabled()) {
-      // The volume is no longer accessible. We need to remove this storage
-      // from the MTP server
-      StorageUnavailable();
-    }
-  } else {
-    if (volState == nsIVolume::STATE_MOUNTED && aVolume->IsSharingEnabled()) {
-      // The volume is accessible. Tell the MTP server.
-      StorageAvailable();
-    }
-  }
-}
-
-void
-MozMtpStorage::StorageAvailable()
-{
-  MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
-
-  nsCString mountPoint = mVolume->MountPoint();
-
-  MTP_LOG("Adding Volume %s mStorageID 0x%08x mountPoint %s to MozMtpDatabase",
-          mVolume->NameStr(), mStorageID, mountPoint.get());
-
-  nsRefPtr<MozMtpDatabase> db = mMozMtpServer->GetMozMtpDatabase();
-  db->AddStorage(mStorageID, mountPoint.get(), mVolume->NameStr());
-
-  MOZ_ASSERT(!mMtpStorage);
-
-  //TODO: For now we assume that the storage removable unless we're sure it's
-  //      not. Bug 1033952 will add an isRemovable attribute to the Volume
-  //      and then we'll know properly.
-
-  //TODO: Figure out what to do about maxFileSize.
-
-  mMtpStorage.reset(new MtpStorage(mStorageID,         // id
-                                   mountPoint.get(),   // filePath
-                                   mVolume->NameStr(), // description
-                                   1024uLL * 1024uLL,  // reserveSpace
-                                   true,               // removable
-                                   2uLL * 1024uLL * 1024uLL * 1024uLL)); // maxFileSize
-  nsRefPtr<RefCountedMtpServer> server = mMozMtpServer->GetMtpServer();
-
-  MTP_LOG("Adding Volume %s mStorageID 0x%08x mountPoint %s to MtpServer",
-          mVolume->NameStr(), mStorageID, mountPoint.get());
-  server->addStorage(mMtpStorage.get());
-}
-
-void
-MozMtpStorage::StorageUnavailable()
-{
-  MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
-  MOZ_ASSERT(mMtpStorage);
-
-  MTP_LOG("Removing mStorageID 0x%08x from MtpServer", mStorageID);
-
-  nsRefPtr<RefCountedMtpServer> server = mMozMtpServer->GetMtpServer();
-  server->removeStorage(mMtpStorage.get());
-
-  MTP_LOG("Removing mStorageID 0x%08x from MozMtpDatabse", mStorageID);
-
-  nsRefPtr<MozMtpDatabase> db = mMozMtpServer->GetMozMtpDatabase();
-  db->RemoveStorage(mStorageID);
-
-  mMtpStorage = nullptr;
-}
-
-END_MTP_NAMESPACE
-
-
deleted file mode 100644
--- a/dom/system/gonk/MozMtpStorage.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* 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/. */
-
-#ifndef mozilla_system_mozmtpstorage_h__
-#define mozilla_system_mozmtpstorage_h__
-
-#include "MozMtpCommon.h"
-
-#include "nsAutoPtr.h"
-#include "mozilla/UniquePtr.h"
-
-#include "Volume.h"
-
-BEGIN_MTP_NAMESPACE
-using namespace android;
-
-class MozMtpServer;
-
-class MozMtpStorage : public Volume::EventObserver
-{
-public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozMtpStorage)
-
-  MozMtpStorage(Volume* aVolume, MozMtpServer* aMozMtpServer);
-
-  typedef nsTArray<nsRefPtr<MozMtpStorage> > Array;
-
-private:
-  virtual ~MozMtpStorage();
-  virtual void Notify(Volume* const& aEvent);
-
-  void StorageAvailable();
-  void StorageUnavailable();
-
-  nsRefPtr<MozMtpServer>  mMozMtpServer;
-  UniquePtr<MtpStorage>   mMtpStorage;
-  RefPtr<Volume>          mVolume;
-  MtpStorageID            mStorageID;
-};
-
-END_MTP_NAMESPACE
-
-#endif  // mozilla_system_mozmtpstorage_h__
-
-
--- a/dom/system/gonk/Volume.cpp
+++ b/dom/system/gonk/Volume.cpp
@@ -45,34 +45,31 @@ Volume::EventObserverList Volume::mEvent
 //
 // If the Volume (IOThread) recieves a volume update where the generation
 // number mismatches, then the update is simply ignored.
 //
 // When a Volume (IOThread) initially becomes mounted, we assume it to
 // be locked until we get our first update from nsVolume (MainThread).
 static int32_t sMountGeneration = 0;
 
-static uint32_t sNextId = 1;
-
 // We don't get media inserted/removed events at startup. So we
 // assume it's present, and we'll be told that it's missing.
 Volume::Volume(const nsCSubstring& aName)
   : mMediaPresent(true),
     mState(nsIVolume::STATE_INIT),
     mName(aName),
     mMountGeneration(-1),
     mMountLocked(true),  // Needs to agree with nsVolume::nsVolume
     mSharingEnabled(false),
     mFormatRequested(false),
     mMountRequested(false),
     mUnmountRequested(false),
     mCanBeShared(true),
     mIsSharing(false),
-    mIsFormatting(false),
-    mId(sNextId++)
+    mIsFormatting(false)
 {
   DBG("Volume %s: created", NameStr());
 }
 
 void
 Volume::SetIsSharing(bool aIsSharing)
 {
   if (aIsSharing == mIsSharing) {
@@ -138,17 +135,16 @@ Volume::SetMediaPresent(bool aMediaPrese
 
 void
 Volume::SetSharingEnabled(bool aSharingEnabled)
 {
   mSharingEnabled = aSharingEnabled;
 
   LOG("SetSharingMode for volume %s to %d canBeShared = %d",
       NameStr(), (int)mSharingEnabled, (int)mCanBeShared);
-  mEventObserverList.Broadcast(this);
 }
 
 void
 Volume::SetFormatRequested(bool aFormatRequested)
 {
   mFormatRequested = aFormatRequested;
 
   LOG("SetFormatRequested for volume %s to %d CanBeFormatted = %d",
@@ -178,24 +174,24 @@ Volume::SetState(Volume::STATE aNewState
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
   if (aNewState == mState) {
     return;
   }
   if (aNewState == nsIVolume::STATE_MOUNTED) {
     mMountGeneration = ++sMountGeneration;
-    LOG("Volume %s (%u): changing state from %s to %s @ '%s' (%d observers) "
+    LOG("Volume %s: changing state from %s to %s @ '%s' (%d observers) "
         "mountGeneration = %d, locked = %d",
-        NameStr(), mId, StateStr(mState),
+        NameStr(), StateStr(mState),
         StateStr(aNewState), mMountPoint.get(), mEventObserverList.Length(),
         mMountGeneration, (int)mMountLocked);
   } else {
-    LOG("Volume %s (%u): changing state from %s to %s (%d observers)",
-        NameStr(), mId, StateStr(mState),
+    LOG("Volume %s: changing state from %s to %s (%d observers)",
+        NameStr(), StateStr(mState),
         StateStr(aNewState), mEventObserverList.Length());
   }
 
   switch (aNewState) {
      case nsIVolume::STATE_NOMEDIA:
        // Cover the startup case where we don't get insertion/removal events
        mMediaPresent = false;
        mIsSharing = false;
--- a/dom/system/gonk/Volume.h
+++ b/dom/system/gonk/Volume.h
@@ -39,18 +39,16 @@ public:
 
   const nsCString& Name() const { return mName; }
   const char* NameStr() const   { return mName.get(); }
 
   // The mount point is the name of the directory where the volume is mounted.
   // (i.e. path that leads to the files stored on the volume).
   const nsCString& MountPoint() const { return mMountPoint; }
 
-  uint32_t Id() const                 { return mId; }
-
   int32_t MountGeneration() const     { return mMountGeneration; }
   bool IsMountLocked() const          { return mMountLocked; }
   bool MediaPresent() const           { return mMediaPresent; }
   bool CanBeShared() const            { return mCanBeShared; }
   bool CanBeFormatted() const         { return CanBeShared(); }
   bool CanBeMounted() const           { return CanBeShared(); }
   bool IsSharingEnabled() const       { return mCanBeShared && mSharingEnabled; }
   bool IsFormatRequested() const      { return CanBeFormatted() && mFormatRequested; }
@@ -107,17 +105,16 @@ private:
   bool              mMountLocked;
   bool              mSharingEnabled;
   bool              mFormatRequested;
   bool              mMountRequested;
   bool              mUnmountRequested;
   bool              mCanBeShared;
   bool              mIsSharing;
   bool              mIsFormatting;
-  uint32_t          mId;                // Unique ID (used by MTP)
 
   static EventObserverList mEventObserverList;
 };
 
 } // system
 } // mozilla
 
 #endif  // mozilla_system_volumemanager_h__
--- a/dom/system/gonk/moz.build
+++ b/dom/system/gonk/moz.build
@@ -38,17 +38,16 @@ EXPORTS += [
 SOURCES += [
     'AudioChannelManager.cpp',
     'AudioManager.cpp',
     'AutoMounter.cpp',
     'AutoMounterSetting.cpp',
     'GonkGPSGeolocationProvider.cpp',
     'MozMtpDatabase.cpp',
     'MozMtpServer.cpp',
-    'MozMtpStorage.cpp',
     'NetworkUtils.cpp',
     'NetworkWorker.cpp',
     'nsVolume.cpp',
     'nsVolumeMountLock.cpp',
     'nsVolumeService.cpp',
     'nsVolumeStat.cpp',
     'OpenFileFinder.cpp',
     'SystemWorkerManager.cpp',
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -591,16 +591,17 @@ this.READ_RECORD_ABSOLUTE_MODE = 4;
 
 // GET_RESPONSE mandatory response size for EF, see TS 51.011 clause 9,
 // 'Response data in case of an EF.'
 this.GET_RESPONSE_EF_SIZE_BYTES = 15;
 
 // EF path
 this.EF_PATH_MF_SIM       = "3f00";
 this.EF_PATH_DF_PHONEBOOK = "5f3a";
+this.EF_PATH_GRAPHICS     = "5f50";
 this.EF_PATH_DF_TELECOM   = "7f10";
 this.EF_PATH_DF_GSM       = "7f20";
 this.EF_PATH_DF_CDMA      = "7f25";
 this.EF_PATH_ADF_USIM     = "7fff";
 
 // Status code of sw1 for ICC I/O,
 // see GSM11.11 and TS 51.011 clause 9.4, and ISO 7816-4
 this.ICC_STATUS_NORMAL_ENDING = 0x90;
@@ -667,16 +668,29 @@ this.ICC_USIM_EFANR_TAG   = 0xc4;
 this.ICC_USIM_EFPBC_TAG   = 0xc5;
 this.ICC_USIM_EFGRP_TAG   = 0xc6;
 this.ICC_USIM_EFAAS_TAG   = 0xc7;
 this.ICC_USIM_EFGSD_TAG   = 0xc8;
 this.ICC_USIM_EFUID_TAG   = 0xc9;
 this.ICC_USIM_EFEMAIL_TAG = 0xca;
 this.ICC_USIM_EFCCP1_TAG  = 0xcb;
 
+// ICC image coding scheme
+// TS 31.102, sub-clause 4.6.1.1
+this.ICC_IMG_CODING_SCHEME_BASIC              = 0x11;
+this.ICC_IMG_CODING_SCHEME_COLOR              = 0x21;
+this.ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY = 0x22;
+
+// ICC image header size per coding scheme
+// TS 31.102, Annex B
+this.ICC_IMG_HEADER_SIZE_BASIC = 2;
+this.ICC_IMG_HEADER_SIZE_COLOR = 6;
+
+this.ICC_CLUT_ENTRY_SIZE = 3;
+
 this.USIM_PBR_ANR = "anr";
 this.USIM_PBR_ANR0 = "anr0";
 this.USIM_PBR_EMAIL = "email";
 
 // Current supported fields. Adding more fields to read will increasing I/O
 // time dramatically, do check the performance is acceptable when you add
 // more fields.
 this.USIM_PBR_FIELDS = [USIM_PBR_EMAIL, USIM_PBR_ANR0];
@@ -1241,31 +1255,33 @@ this.GECKO_ICC_SERVICES = {
     CBMI: 14,
     GID1: 15,
     SPN: 17,
     SDN: 18,
     DATA_DOWNLOAD_SMS_CB: 25,
     DATA_DOWNLOAD_SMS_PP: 26,
     CBMIR: 30,
     BDN: 31,
+    IMG: 39,
     PNN: 51,
     OPL: 52,
     MDN: 53,
     MWIS: 54,
     SPDI: 56
   },
   usim: {
     FDN: 2,
     SDN: 4,
     BDN: 6,
     CBMI: 15,
     CBMIR: 16,
     GID1: 17,
     SPN: 19,
     MSISDN: 21,
+    IMG: 22,
     DATA_DOWNLOAD_SMS_PP: 28,
     DATA_DOWNLOAD_SMS_CB: 29,
     PNN: 45,
     OPL: 46,
     MDN: 47,
     MWIS: 48,
     SPDI: 51
   },
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -5429,17 +5429,20 @@ RilObject.prototype = {
         command: cmdDetails,
         resultCode: STK_RESULT_OK});
       return;
     }
 
     cmdDetails.rilMessageType = "stkcommand";
     cmdDetails.options =
       this.context.StkCommandParamsFactory.createParam(cmdDetails, ctlvs);
-    this.sendChromeMessage(cmdDetails);
+
+    if (!cmdDetails.options || !cmdDetails.options.pending) {
+      this.sendChromeMessage(cmdDetails);
+    }
   },
 
   /**
    * Send messages to the main thread.
    */
   sendChromeMessage: function(message) {
     message.rilMessageClientId = this.context.clientId;
     postMessage(message);
@@ -10820,16 +10823,57 @@ StkCommandParamsFactoryObject.prototype 
       menu.isHelpAvailable = true;
     }
 
     ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_NEXT_ACTION_IND, ctlvs);
     if (ctlv) {
       menu.nextActionList = ctlv.value;
     }
 
+    let iconId;
+    let ids = [];
+    ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+    if (ctlv) {
+      iconId = ctlv.value;
+      menu.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
+      ids[0] = iconId.identifier;
+    }
+
+    let iconIdList;
+    ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID_LIST, ctlvs);
+    if (ctlv) {
+      iconIdList = ctlv.value;
+      menu.itemIconSelfExplanatory = iconIdList.qualifier == 0 ? true : false;
+      ids = ids.concat(iconIdList.identifiers);
+    }
+
+    if (!ids.length ||
+        !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
+      return menu;
+    }
+
+    let onerror = (function() {
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    let onsuccess = (function(result) {
+      if (iconId) {
+        menu.icons = result.shift();
+      }
+
+      for (let i = 0; i < result.length; i++) {
+        menu.items[i].icons = result[i];
+      }
+
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    menu.pending = true;
+    this.context.IconLoader.loadIcons(ids, onsuccess, onerror);
+
     return menu;
   },
 
   processDisplayText: function(cmdDetails, ctlvs) {
     let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper;
     let textMsg = {};
 
     let ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_TEXT_STRING, ctlvs);
@@ -10856,32 +10900,73 @@ StkCommandParamsFactoryObject.prototype 
       textMsg.isHighPriority = true;
     }
 
     // User clear.
     if (cmdDetails.commandQualifier & 0x80) {
       textMsg.userClear = true;
     }
 
+    ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+    if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
+      return textMsg;
+    }
+
+    let iconId = ctlv.value;
+    textMsg.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
+
+    let onerror = (function() {
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    let onsuccess = (function(result) {
+      textMsg.icons = result[0];
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    textMsg.pending = true;
+    this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
+
     return textMsg;
   },
 
   processSetUpIdleModeText: function(cmdDetails, ctlvs) {
+    let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper;
     let textMsg = {};
 
-    let ctlv = this.context.StkProactiveCmdHelper.searchForTag(
-        COMPREHENSIONTLV_TAG_TEXT_STRING, ctlvs);
+    let ctlv = StkProactiveCmdHelper.searchForTag(
+      COMPREHENSIONTLV_TAG_TEXT_STRING, ctlvs);
     if (!ctlv) {
       this.context.RIL.sendStkTerminalResponse({
         command: cmdDetails,
         resultCode: STK_RESULT_REQUIRED_VALUES_MISSING});
       throw new Error("Stk Set Up Idle Text: Required value missing : Text String");
     }
     textMsg.text = ctlv.value.textString;
 
+    ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+    if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
+      return textMsg;
+    }
+
+    let iconId = ctlv.value;
+    textMsg.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
+
+    let onerror = (function() {
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    let onsuccess = (function(result) {
+      textMsg.icons = result[0];
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    textMsg.pending = true;
+    this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
+
     return textMsg;
   },
 
   processGetInkey: function(cmdDetails, ctlvs) {
     let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper;
     let input = {};
 
     let ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_TEXT_STRING, ctlvs);
@@ -10919,16 +11004,36 @@ StkCommandParamsFactoryObject.prototype 
       input.isYesNoRequested = true;
     }
 
     // Help information available.
     if (cmdDetails.commandQualifier & 0x80) {
       input.isHelpAvailable = true;
     }
 
+    ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+    if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
+      return input;
+    }
+
+    let iconId = ctlv.value;
+    input.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
+
+    let onerror = (function() {
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    let onsuccess = (function(result) {
+      input.icons = result[0];
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    input.pending = true;
+    this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
+
     return input;
   },
 
   processGetInput: function(cmdDetails, ctlvs) {
     let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper;
     let input = {};
 
     let ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_TEXT_STRING, ctlvs);
@@ -10971,28 +11076,70 @@ StkCommandParamsFactoryObject.prototype 
       input.isPacked = true;
     }
 
     // Help information available.
     if (cmdDetails.commandQualifier & 0x80) {
       input.isHelpAvailable = true;
     }
 
+    ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+    if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
+      return input;
+    }
+
+    let iconId = ctlv.value;
+    input.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
+
+    let onerror = (function() {
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    let onsuccess = (function(result) {
+      input.icons = result[0];
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    input.pending = true;
+    this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
+
     return input;
   },
 
   processEventNotify: function(cmdDetails, ctlvs) {
+    let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper;
     let textMsg = {};
 
-    let ctlv = this.context.StkProactiveCmdHelper.searchForTag(
-        COMPREHENSIONTLV_TAG_ALPHA_ID, ctlvs);
+    let ctlv = StkProactiveCmdHelper.searchForTag(
+      COMPREHENSIONTLV_TAG_ALPHA_ID, ctlvs);
     if (ctlv) {
       textMsg.text = ctlv.value.identifier;
     }
 
+    ctlv = StkProactiveCmdHelper.searchForTag(
+      COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+    if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
+      return textMsg;
+    }
+
+    let iconId = ctlv.value;
+    textMsg.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
+
+    let onerror = (function() {
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    let onsuccess = (function(result) {
+      textMsg.icons = result[0];
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    textMsg.pending = true;
+    this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
+
     return textMsg;
   },
 
   processSetupCall: function(cmdDetails, ctlvs) {
     let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper;
     let call = {};
     let iter = Iterator(ctlvs);
 
@@ -11016,16 +11163,36 @@ StkCommandParamsFactoryObject.prototype 
     call.address = ctlv.value.number;
 
     // see 3GPP TS 31.111 section 6.4.13
     ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_DURATION, ctlvs);
     if (ctlv) {
       call.duration = ctlv.value;
     }
 
+    ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+    if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
+      return call;
+    }
+
+    let iconId = ctlv.value;
+    call.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
+
+    let onerror = (function() {
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    let onsuccess = (function(result) {
+      call.icons = result[0];
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    call.pending = true;
+    this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
+
     return call;
   },
 
   processLaunchBrowser: function(cmdDetails, ctlvs) {
     let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper;
     let browser = {};
 
     let ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_URL, ctlvs);
@@ -11039,25 +11206,45 @@ StkCommandParamsFactoryObject.prototype 
 
     ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ALPHA_ID, ctlvs);
     if (ctlv) {
       browser.confirmMessage = ctlv.value.identifier;
     }
 
     browser.mode = cmdDetails.commandQualifier & 0x03;
 
+    ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+    if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
+      return browser;
+    }
+
+    let iconId = ctlv.value;
+    browser.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
+
+    let onerror = (function() {
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    let onsuccess = (function(result) {
+      browser.icons = result[0];
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    browser.pending = true;
+    this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
+
     return browser;
   },
 
   processPlayTone: function(cmdDetails, ctlvs) {
     let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper;
     let playTone = {};
 
     let ctlv = StkProactiveCmdHelper.searchForTag(
-        COMPREHENSIONTLV_TAG_ALPHA_ID, ctlvs);
+      COMPREHENSIONTLV_TAG_ALPHA_ID, ctlvs);
     if (ctlv) {
       playTone.text = ctlv.value.identifier;
     }
 
     ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_TONE, ctlvs);
     if (ctlv) {
       playTone.tone = ctlv.value.tone;
     }
@@ -11066,16 +11253,37 @@ StkCommandParamsFactoryObject.prototype 
         COMPREHENSIONTLV_TAG_DURATION, ctlvs);
     if (ctlv) {
       playTone.duration = ctlv.value;
     }
 
     // vibrate is only defined in TS 102.223
     playTone.isVibrate = (cmdDetails.commandQualifier & 0x01) !== 0x00;
 
+    ctlv = StkProactiveCmdHelper.searchForTag(
+      COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+    if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
+      return playTone;
+    }
+
+    let iconId = ctlv.value;
+    playTone.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
+
+    let onerror = (function() {
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    let onsuccess = (function(result) {
+      playTone.icons = result[0];
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    playTone.pending = true;
+    this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
+
     return playTone;
   },
 
   /**
    * Construct a param for Provide Local Information
    *
    * @param cmdDetails
    *        The value object of CommandDetails TLV.
@@ -11114,24 +11322,45 @@ StkCommandParamsFactoryObject.prototype 
     * Construct a param for BIP commands.
     *
     * @param cmdDetails
     *        The value object of CommandDetails TLV.
     * @param ctlvs
     *        The all TLVs in this proactive command.
     */
   processBipMessage: function(cmdDetails, ctlvs) {
+    let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper;
     let bipMsg = {};
 
-    let ctlv = this.context.StkProactiveCmdHelper.searchForTag(
-        COMPREHENSIONTLV_TAG_ALPHA_ID, ctlvs);
+    let ctlv = StkProactiveCmdHelper.searchForTag(
+      COMPREHENSIONTLV_TAG_ALPHA_ID, ctlvs);
     if (ctlv) {
       bipMsg.text = ctlv.value.identifier;
     }
 
+    ctlv = StkProactiveCmdHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+    if (!ctlv || !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) {
+      return bipMsg;
+    }
+
+    let iconId = ctlv.value;
+    bipMsg.iconSelfExplanatory = iconId.qualifier == 0 ? true : false;
+
+    let onerror = (function() {
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    let onsuccess = (function(result) {
+      bipMsg.icons = result[0];
+      this.context.RIL.sendChromeMessage(cmdDetails);
+    }).bind(this);
+
+    bipMsg.pending = true;
+    this.context.IconLoader.loadIcons([iconId.identifier], onsuccess, onerror);
+
     return bipMsg;
   }
 };
 StkCommandParamsFactoryObject.prototype[STK_CMD_REFRESH] = function STK_CMD_REFRESH(cmdDetails, ctlvs) {
   return this.processRefresh(cmdDetails, ctlvs);
 };
 StkCommandParamsFactoryObject.prototype[STK_CMD_POLL_INTERVAL] = function STK_CMD_POLL_INTERVAL(cmdDetails, ctlvs) {
   return this.processPollInterval(cmdDetails, ctlvs);
@@ -11467,16 +11696,62 @@ StkProactiveCmdHelperObject.prototype = 
       eventList.push(GsmPDUHelper.readHexOctet());
     }
     return {
       eventList: eventList
     };
   },
 
   /**
+   * Icon Id.
+   *
+   * | Byte  | Description          | Length |
+   * |  1    | Icon Identifier Tag  |   1    |
+   * |  2    | Length = 02          |   1    |
+   * |  3    | Icon qualifier       |   1    |
+   * |  4    | Icon identifier      |   1    |
+   */
+  retrieveIconId: function(length) {
+    if (!length) {
+      return null;
+    }
+
+    let iconId = {
+      qualifier: this.context.GsmPDUHelper.readHexOctet(),
+      identifier: this.context.GsmPDUHelper.readHexOctet()
+    };
+    return iconId;
+  },
+
+  /**
+   * Icon Id List.
+   *
+   * | Byte  | Description          | Length |
+   * |  1    | Icon Identifier Tag  |   1    |
+   * |  2    | Length = X           |   1    |
+   * |  3    | Icon qualifier       |   1    |
+   * |  4~   | Icon identifier      |  X-1   |
+   * | 4+X-2 |                      |        |
+   */
+  retrieveIconIdList: function(length) {
+    if (!length) {
+      return null;
+    }
+
+    let iconIdList = {
+      qualifier: this.context.GsmPDUHelper.readHexOctet(),
+      identifiers: []
+    };
+    for (let i = 0; i < length - 1; i++) {
+      iconIdList.identifiers.push(this.context.GsmPDUHelper.readHexOctet());
+    }
+    return iconIdList;
+  },
+
+  /**
    * Timer Identifier.
    *
    * | Byte  | Description          | Length |
    * |  1    | Timer Identifier Tag |   1    |
    * |  2    | Length = 01          |   1    |
    * |  3    | Timer Identifier     |   1    |
    */
   retrieveTimerId: function(length) {
@@ -11601,16 +11876,22 @@ StkProactiveCmdHelperObject.prototype[CO
   return this.retrieveFileList(length);
 };
 StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_DEFAULT_TEXT] = function COMPREHENSIONTLV_TAG_DEFAULT_TEXT(length) {
   return this.retrieveDefaultText(length);
 };
 StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_EVENT_LIST] = function COMPREHENSIONTLV_TAG_EVENT_LIST(length) {
   return this.retrieveEventList(length);
 };
+StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ICON_ID] = function COMPREHENSIONTLV_TAG_ICON_ID(length) {
+  return this.retrieveIconId(length);
+};
+StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ICON_ID_LIST] = function COMPREHENSIONTLV_TAG_ICON_ID_LIST(length) {
+  return this.retrieveIconIdList(length);
+};
 StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER] = function COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER(length) {
   return this.retrieveTimerId(length);
 };
 StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_TIMER_VALUE] = function COMPREHENSIONTLV_TAG_TIMER_VALUE(length) {
   return this.retrieveTimerValue(length);
 };
 StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE] = function COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE(length) {
   return this.retrieveImmediaResponse(length);
@@ -12135,16 +12416,18 @@ ICCFileHelperObject.prototype = {
     switch (fileId) {
       case ICC_EF_ICCID:
         return EF_PATH_MF_SIM;
       case ICC_EF_ADN:
       case ICC_EF_SDN: // Fall through.
         return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM;
       case ICC_EF_PBR:
         return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK;
+      case ICC_EF_IMG:
+        return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_GRAPHICS;
     }
     return null;
   },
 
   /**
    * This function handles EFs for SIM.
    */
   getSimEFPath: function(fileId) {
@@ -13259,16 +13542,165 @@ SimRecordHelperObject.prototype = {
     }
 
     this.context.ICCIOHelper.loadTransparentEF({
       fileId: ICC_EF_SPN,
       callback: callback.bind(this)
     });
   },
 
+  readIMG: function(recordNumber, onsuccess, onerror) {
+    function callback(options) {
+      let RIL = this.context.RIL;
+      let Buf = this.context.Buf;
+      let GsmPDUHelper = this.context.GsmPDUHelper;
+      let strLen = Buf.readInt32();
+      // Each octet is encoded into two chars.
+      let octetLen = strLen / 2;
+
+      let numInstances = GsmPDUHelper.readHexOctet();
+
+      // Correct data length should be 9n+1 or 9n+2. See TS 31.102, sub-clause
+      // 4.6.1.1.
+      if (octetLen != (9 * numInstances + 1) ||
+          octetLen != (9 * numInstances + 2)) {
+        if (onerror) {
+          onerror();
+        }
+        return;
+      }
+
+      let imgDescriptors = [];
+      for (let i = 0; i < numInstances; i++) {
+        imgDescriptors[i] = {
+          width: GsmPDUHelper.readHexOctet(),
+          height: GsmPDUHelper.readHexOctet(),
+          codingScheme: GsmPDUHelper.readHexOctet(),
+          fileId: (GsmPDUHelper.readHexOctet() << 8) |
+                  GsmPDUHelper.readHexOctet(),
+          offset: (GsmPDUHelper.readHexOctet() << 8) |
+                  GsmPDUHelper.readHexOctet(),
+          dataLen: (GsmPDUHelper.readHexOctet() << 8) |
+                   GsmPDUHelper.readHexOctet()
+        };
+      }
+      Buf.readStringDelimiter(strLen);
+
+      let instances = [];
+      let currentInstance = 0;
+      let readNextInstance = (function(img) {
+        instances[currentInstance] = img;
+        currentInstance++;
+
+        if (currentInstance < numInstances) {
+          let imgDescriptor = imgDescriptors[currentInstance];
+          this.readIIDF(imgDescriptor.fileId,
+                        imgDescriptor.offset,
+                        imgDescriptor.dataLen,
+                        imgDescriptor.codingScheme,
+                        readNextInstance,
+                        onerror);
+        } else {
+          if (onsuccess) {
+            onsuccess(instances);
+          }
+        }
+      }).bind(this);
+
+      this.readIIDF(imgDescriptors[0].fileId,
+                    imgDescriptors[0].offset,
+                    imgDescriptors[0].dataLen,
+                    imgDescriptors[0].codingScheme,
+                    readNextInstance,
+                    onerror);
+    }
+
+    this.context.ICCIOHelper.loadLinearFixedEF({
+      fileId: ICC_EF_IMG,
+      recordNumber: recordNumber,
+      callback: callback.bind(this),
+      onerror: onerror
+    });
+  },
+
+  readIIDF: function(fileId, offset, dataLen, codingScheme, onsuccess, onerror) {
+    // Valid fileId is '4FXX', see TS 31.102, clause 4.6.1.2.
+    if ((fileId >> 8) != 0x4F) {
+      if (onerror) {
+        onerror();
+      }
+      return;
+    }
+
+    function callback() {
+      let Buf = this.context.Buf;
+      let RIL = this.context.RIL;
+      let GsmPDUHelper = this.context.GsmPDUHelper;
+      let strLen = Buf.readInt32();
+      // Each octet is encoded into two chars.
+      let octetLen = strLen / 2;
+
+      if (octetLen < offset + dataLen) {
+        // Data length is not enough. See TS 31.102, clause 4.6.1.1, the
+        // paragraph "Bytes 8 and 9: Length of Image Instance Data."
+        if (onerror) {
+          onerror();
+        }
+        return;
+      }
+
+      Buf.seekIncoming(offset * Buf.PDU_HEX_OCTET_SIZE);
+
+      let rawData = {
+        width: GsmPDUHelper.readHexOctet(),
+        height: GsmPDUHelper.readHexOctet(),
+        codingScheme: codingScheme
+      };
+
+      switch (codingScheme) {
+        case ICC_IMG_CODING_SCHEME_BASIC:
+          rawData.body = GsmPDUHelper.readHexOctetArray(
+            dataLen - ICC_IMG_HEADER_SIZE_BASIC);
+          Buf.seekIncoming((octetLen - offset - dataLen) * Buf.PDU_HEX_OCTET_SIZE);
+          break;
+
+        case ICC_IMG_CODING_SCHEME_COLOR:
+        case ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY:
+          rawData.bitsPerImgPoint = GsmPDUHelper.readHexOctet();
+          let num = GsmPDUHelper.readHexOctet();
+          // The value 0 shall be interpreted as 256. See TS 31.102, Annex B.2.
+          rawData.numOfClutEntries = (num === 0) ? 0x100 : num;
+          rawData.clutOffset = (GsmPDUHelper.readHexOctet() << 8) |
+                               GsmPDUHelper.readHexOctet();
+          rawData.body = GsmPDUHelper.readHexOctetArray(
+              dataLen - ICC_IMG_HEADER_SIZE_COLOR);
+
+          Buf.seekIncoming((rawData.clutOffset - offset - dataLen) *
+                           Buf.PDU_HEX_OCTET_SIZE);
+          let clut = GsmPDUHelper.readHexOctetArray(rawData.numOfClutEntries *
+                                                    ICC_CLUT_ENTRY_SIZE);
+
+          rawData.clut = clut;
+      }
+
+      Buf.readStringDelimiter(strLen);
+
+      if (onsuccess) {
+        onsuccess(rawData);
+      }
+    }
+
+    this.context.ICCIOHelper.loadTransparentEF({
+      fileId: fileId,
+      pathId: this.context.ICCFileHelper.getEFPath(ICC_EF_IMG),
+      callback: callback.bind(this),
+      onerror: onerror
+    });
+  },
+
   /**
    * Read the (U)SIM Service Table from the (U)SIM.
    */
   readSST: function() {
     function callback() {
       let Buf = this.context.Buf;
       let RIL = this.context.RIL;
 
@@ -15292,16 +15724,120 @@ ICCContactHelperObject.prototype = {
     let gotIAPCb = function gotIAPCb(iap) {
       iap[pbr[field].indexInIAP] = value;
       ICCRecordHelper.updateIAP(pbr.iap.fileId, recordNumber, iap, onsuccess, onerror);
     }.bind(this);
     ICCRecordHelper.readIAP(pbr.iap.fileId, recordNumber, gotIAPCb, onerror);
   },
 };
 
+function IconLoaderObject(aContext) {
+  this.context = aContext;
+}
+IconLoaderObject.prototype = {
+  context: null,
+
+  /**
+   * Load icons.
+   *
+   * @param recordNumbers Array of the record identifiers of EF_IMG.
+   * @param onsuccess     Callback to be called when success.
+   * @param onerror       Callback to be called when error.
+   */
+  loadIcons: function(recordNumbers, onsuccess, onerror) {
+    if (!recordNumbers || !recordNumbers.length) {
+      if (onerror) {
+        onerror();
+      }
+      return;
+    }
+
+    this._start({
+      recordNumbers: recordNumbers,
+      onsuccess: onsuccess,
+      onerror: onerror});
+  },
+
+  _start: function(options) {
+    let callback = (function(icons) {
+      if (!options.icons) {
+        options.icons = [];
+      }
+      for (let i = 0; i < icons.length; i++) {
+        icons[i] = this._parseRawData(icons[i]);
+      }
+      options.icons[options.currentRecordIndex] = icons;
+      options.currentRecordIndex++;
+
+      let recordNumbers = options.recordNumbers;
+      if (options.currentRecordIndex < recordNumbers.length) {
+        let recordNumber = recordNumbers[options.currentRecordIndex];
+        this.context.SimRecordHelper.readIMG(recordNumber,
+                                             callback,
+                                             options.onerror);
+      } else {
+        if (options.onsuccess) {
+          options.onsuccess(options.icons);
+        }
+      }
+    }).bind(this);
+
+    options.currentRecordIndex = 0;
+    this.context.SimRecordHelper.readIMG(options.recordNumbers[0],
+                                         callback,
+                                         options.onerror);
+  },
+
+  _parseRawData: function(rawData) {
+    let codingScheme = rawData.codingScheme;
+
+    switch (codingScheme) {
+      case ICC_IMG_CODING_SCHEME_BASIC:
+        return {pixels: rawData.body,
+                width: rawData.width,
+                height: rawData.height};
+
+      case ICC_IMG_CODING_SCHEME_COLOR:
+      case ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY:
+        let bitsPerImgPoint = rawData.bitsPerImgPoint;
+        let mask = 0xff >> (8 - bitsPerImgPoint);
+        let bitsStartOffset = 8 - bitsPerImgPoint;
+        let bitIndex = bitsStartOffset;
+        let numOfClutEntries = rawData.numOfClutEntries;
+        let clut = rawData.clut;
+        let body = rawData.body;
+        let numOfPixels = rawData.width * rawData.height;
+        let pixelIndex = 0;
+        let currentByteIndex = 0;
+        let currentByte = body[currentByteIndex++];
+
+        let pixels = [];
+        while (pixelIndex < numOfPixels) {
+          // Reassign data and index for every byte (8 bits).
+          if (bitIndex < 0) {
+            currentByte = body[currentByteIndex++];
+            bitIndex = bitsStartOffset;
+          }
+          let clutEntry = ((currentByte >> bitIndex) & mask);
+          let clutIndex = clutEntry * ICC_CLUT_ENTRY_SIZE;
+          let alpha = codingScheme == ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY &&
+                      clutEntry == numOfClutEntries - 1;
+          pixels[pixelIndex++] = {red: clut[clutIndex],
+                                  green: clut[clutIndex + 1],
+                                  blue: clut[clutIndex + 2],
+                                  alpha: alpha ? 0x00 : 0xff};
+          bitIndex -= bitsPerImgPoint;
+        }
+        return {pixels: pixels,
+                width: rawData.width,
+                height: rawData.height};
+    }
+  },
+};
+
 /**
  * Global stuff.
  */
 
 function Context(aClientId) {
   this.clientId = aClientId;
 
   this.Buf = new BufObject(this);
@@ -15321,17 +15857,17 @@ Context.prototype = {
 };
 
 (function() {
   let lazySymbols = [
     "BerTlvHelper", "BitBufferHelper", "CdmaPDUHelper",
     "ComprehensionTlvHelper", "GsmPDUHelper", "ICCContactHelper",
     "ICCFileHelper", "ICCIOHelper", "ICCPDUHelper", "ICCRecordHelper",
     "ICCUtilsHelper", "RuimRecordHelper", "SimRecordHelper",
-    "StkCommandParamsFactory", "StkProactiveCmdHelper",
+    "StkCommandParamsFactory", "StkProactiveCmdHelper", "IconLoader",
   ];
 
   for (let i = 0; i < lazySymbols.length; i++) {
     let symbol = lazySymbols[i];
     Object.defineProperty(Context.prototype, symbol, {
       get: function() {
         let real = new GLOBAL[symbol + "Object"](this);
         Object.defineProperty(this, symbol, {
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_icc_IconLoader.js
@@ -0,0 +1,869 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Verify IconLoader.loadIcons with recordNumbers array length being 1.
+ * Query images of one record at a time.
+ */
+add_test(function test_load_icon_basic() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ril = context.RIL;
+  let iconLoader = context.IconLoader;
+  let simRecordHelper = context.SimRecordHelper;
+
+  let test_data = [
+    {rawData: [
+       {codingScheme: ICC_IMG_CODING_SCHEME_BASIC,
+        width: 0x10,
+        height: 0x10,
+        body: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+               0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b,
+               0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff,
+               0xff, 0x00, 0x00, 0xff, 0xff]}],
+     expected: [
+       {width: 0x10,
+        height: 0x10,
+        pixels: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+                 0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b,
+                 0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff,
+                 0xff, 0x00, 0x00, 0xff, 0xff]}]},
+    {rawData: [
+       {codingScheme: ICC_IMG_CODING_SCHEME_COLOR,
+        width: 0x10,
+        height: 0x10,
+        bitsPerImgPoint: 0x04,
+        numOfClutEntries: 0x10,
+        body: [0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xcf, 0xfc, 0xcc, 0xfc, 0xcc,
+               0xcf, 0xcf, 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf,
+               0xcc, 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcc,
+               0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcf, 0xcc,
+               0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcf, 0xcc, 0xcf,
+               0xfc, 0xcc, 0xfc, 0xcc, 0xcf, 0xcf, 0xfc, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+               0x99, 0x99],
+        clut: [0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
+               0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x80,
+               0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80,
+               0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00,
+               0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff,
+               0xff, 0xff, 0xff]}],
+     expected: [
+       {width: 0x10,
+        height: 0x10,
+        pixels: [
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff}]}]},
+    {rawData: [
+       {codingScheme: ICC_IMG_CODING_SCHEME_COLOR,
+        width: 0x03,
+        height: 0x03,
+        bitsPerImgPoint: 0x05,
+        numOfClutEntries: 0x20,
+        body: [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88],
+        clut: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+               0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
+               0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a,
+               0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+               0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
+               0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+               0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+               0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+               0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+               0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+               0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f]},
+       {codingScheme: ICC_IMG_CODING_SCHEME_BASIC,
+        width: 0x10,
+        height: 0x10,
+        body: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+               0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b,
+               0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff,
+               0xff, 0x00, 0x00, 0xff, 0xff]}],
+     expected: [
+       {width: 0x03,
+        height: 0x03,
+        pixels: [
+          {red: 0x00, green: 0x01, blue: 0x02, alpha: 0xff},
+          {red: 0x06, green: 0x07, blue: 0x08, alpha: 0xff},
+          {red: 0x0c, green: 0x0d, blue: 0x0e, alpha: 0xff},
+          {red: 0x12, green: 0x13, blue: 0x14, alpha: 0xff},
+          {red: 0x18, green: 0x19, blue: 0x1a, alpha: 0xff},
+          {red: 0x1e, green: 0x1f, blue: 0x20, alpha: 0xff},
+          {red: 0x24, green: 0x25, blue: 0x26, alpha: 0xff},
+          {red: 0x2a, green: 0x2b, blue: 0x2c, alpha: 0xff},
+          {red: 0x33, green: 0x34, blue: 0x35, alpha: 0xff}]},
+       {width: 0x10,
+        height: 0x10,
+        pixels: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+                 0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b,
+                 0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff,
+                 0xff, 0x00, 0x00, 0xff, 0xff]}]},
+    {rawData: [
+       {codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY,
+        width: 0x04,
+        height: 0x04,
+        bitsPerImgPoint: 0x04,
+        numOfClutEntries: 0x10,
+        body: [0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88],
+        clut: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+               0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
+               0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a,
+               0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+               0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
+               0x2d, 0x2e, 0x2f]}],
+     expected: [
+       {width: 0x04,
+        height: 0x04,
+        pixels: [
+          {red: 0x2d, green: 0x2e, blue: 0x2f, alpha: 0x00},
+          {red: 0x2d, green: 0x2e, blue: 0x2f, alpha: 0x00},
+          {red: 0x2a, green: 0x2b, blue: 0x2c, alpha: 0xff},
+          {red: 0x2a, green: 0x2b, blue: 0x2c, alpha: 0xff},
+          {red: 0x27, green: 0x28, blue: 0x29, alpha: 0xff},
+          {red: 0x27, green: 0x28, blue: 0x29, alpha: 0xff},
+          {red: 0x24, green: 0x25, blue: 0x26, alpha: 0xff},
+          {red: 0x24, green: 0x25, blue: 0x26, alpha: 0xff},
+          {red: 0x21, green: 0x22, blue: 0x23, alpha: 0xff},
+          {red: 0x21, green: 0x22, blue: 0x23, alpha: 0xff},
+          {red: 0x1e, green: 0x1f, blue: 0x20, alpha: 0xff},
+          {red: 0x1e, green: 0x1f, blue: 0x20, alpha: 0xff},
+          {red: 0x1b, green: 0x1c, blue: 0x1d, alpha: 0xff},
+          {red: 0x1b, green: 0x1c, blue: 0x1d, alpha: 0xff},
+          {red: 0x18, green: 0x19, blue: 0x1a, alpha: 0xff},
+          {red: 0x18, green: 0x19, blue: 0x1a, alpha: 0xff}]}]}];
+
+  function do_test(test_data, expected) {
+    simRecordHelper.readIMG = function fakeReadIMG(recordNumber, onsuccess, onerror) {
+      onsuccess(test_data);
+    };
+
+    let onsuccess = function(icons) {
+      // Query one record at a time.
+      do_check_eq(icons.length, 1);
+      do_check_eq(icons[0].length, expected.length);
+      for (let i = 0; i < icons[0].length; i++) {
+        // Read the i_th image of the record.
+        let icon = icons[0][i];
+        let exp = expected[i];
+        do_check_eq(icon.width, exp.width);
+        do_check_eq(icon.height, exp.height);
+        do_check_eq(icon.pixels.length, exp.pixels.length);
+        for (let j = 0; j < icon.pixels.length; j++) {
+          if (typeof icon.pixels[j] === "object") {
+            do_check_eq(icon.pixels[j].red, exp.pixels[j].red);
+            do_check_eq(icon.pixels[j].green, exp.pixels[j].green);
+            do_check_eq(icon.pixels[j].blue, exp.pixels[j].blue);
+            do_check_eq(icon.pixels[j].alpha, exp.pixels[j].alpha);
+          } else {
+            do_check_eq(icon.pixels[j], exp.pixels[j]);
+          }
+        }
+      }
+    };
+
+    iconLoader.loadIcons([0], onsuccess);
+  }
+
+  for (let i = 0; i < test_data.length; i++) {
+    do_test(test_data[i].rawData, test_data[i].expected);
+  }
+
+  run_next_test();
+});
+
+/**
+ * Verify IconLoader.loadIcons.
+ */
+add_test(function test_load_icons() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ril = context.RIL;
+  let iconLoader = context.IconLoader;
+  let simRecordHelper = context.SimRecordHelper;
+
+  let test_data = {
+    rawData: [
+      // Record 1.
+      [{codingScheme: ICC_IMG_CODING_SCHEME_BASIC,
+        width: 0x10,
+        height: 0x10,
+        body: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+               0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b,
+               0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff,
+               0xff, 0x00, 0x00, 0xff, 0xff]}],
+      // Record 2.
+      [{codingScheme: ICC_IMG_CODING_SCHEME_COLOR,
+        width: 0x10,
+        height: 0x10,
+        bitsPerImgPoint: 0x04,
+        numOfClutEntries: 0x10,
+        body: [0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xcf, 0xfc, 0xcc, 0xfc, 0xcc,
+               0xcf, 0xcf, 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf,
+               0xcc, 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcc,
+               0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcf, 0xcc,
+               0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcf, 0xcc, 0xcf,
+               0xfc, 0xcc, 0xfc, 0xcc, 0xcf, 0xcf, 0xfc, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff,
+               0xff, 0xff, 0xff, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+               0x99, 0x99],
+        clut: [0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00,
+               0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x80,
+               0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80,
+               0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00,
+               0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff,
+               0xff, 0xff, 0xff]}],
+      // Record 3.
+      [{codingScheme: ICC_IMG_CODING_SCHEME_COLOR,
+        width: 0x03,
+        height: 0x03,
+        bitsPerImgPoint: 0x05,
+        numOfClutEntries: 0x20,
+        body: [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88],
+        clut: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+               0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
+               0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a,
+               0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+               0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
+               0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+               0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+               0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+               0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+               0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+               0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f]},
+       {codingScheme: ICC_IMG_CODING_SCHEME_BASIC,
+        width: 0x10,
+        height: 0x10,
+        body: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+               0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b,
+               0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff,
+               0xff, 0x00, 0x00, 0xff, 0xff]}],
+      // Record 4.
+      [{codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY,
+        width: 0x04,
+        height: 0x04,
+        bitsPerImgPoint: 0x04,
+        numOfClutEntries: 0x10,
+        body: [0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88],
+        clut: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+               0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
+               0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a,
+               0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+               0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
+               0x2d, 0x2e, 0x2f]}]],
+    expected: [
+      // Record 1.
+      [{width: 0x10,
+        height: 0x10,
+        pixels: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+                 0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b,
+                 0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff,
+                 0xff, 0x00, 0x00, 0xff, 0xff]}],
+      // Record 2.
+      [{width: 0x10,
+        height: 0x10,
+        pixels: [
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0x00, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0x00, green: 0xff, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0xff, blue: 0xff, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff},
+          {red: 0xff, green: 0x00, blue: 0x00, alpha: 0xff}]}],
+      // Record 3.
+      [{width: 0x03,
+        height: 0x03,
+        pixels: [
+          {red: 0x00, green: 0x01, blue: 0x02, alpha: 0xff},
+          {red: 0x06, green: 0x07, blue: 0x08, alpha: 0xff},
+          {red: 0x0c, green: 0x0d, blue: 0x0e, alpha: 0xff},
+          {red: 0x12, green: 0x13, blue: 0x14, alpha: 0xff},
+          {red: 0x18, green: 0x19, blue: 0x1a, alpha: 0xff},
+          {red: 0x1e, green: 0x1f, blue: 0x20, alpha: 0xff},
+          {red: 0x24, green: 0x25, blue: 0x26, alpha: 0xff},
+          {red: 0x2a, green: 0x2b, blue: 0x2c, alpha: 0xff},
+          {red: 0x33, green: 0x34, blue: 0x35, alpha: 0xff}]},
+       {width: 0x10,
+        height: 0x10,
+        pixels: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+                 0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b,
+                 0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff,
+                 0xff, 0x00, 0x00, 0xff, 0xff]}],
+      // Record 4.
+      [{width: 0x04,
+        height: 0x04,
+        pixels: [
+          {red: 0x2d, green: 0x2e, blue: 0x2f, alpha: 0x00},
+          {red: 0x2d, green: 0x2e, blue: 0x2f, alpha: 0x00},
+          {red: 0x2a, green: 0x2b, blue: 0x2c, alpha: 0xff},
+          {red: 0x2a, green: 0x2b, blue: 0x2c, alpha: 0xff},
+          {red: 0x27, green: 0x28, blue: 0x29, alpha: 0xff},
+          {red: 0x27, green: 0x28, blue: 0x29, alpha: 0xff},
+          {red: 0x24, green: 0x25, blue: 0x26, alpha: 0xff},
+          {red: 0x24, green: 0x25, blue: 0x26, alpha: 0xff},
+          {red: 0x21, green: 0x22, blue: 0x23, alpha: 0xff},
+          {red: 0x21, green: 0x22, blue: 0x23, alpha: 0xff},
+          {red: 0x1e, green: 0x1f, blue: 0x20, alpha: 0xff},
+          {red: 0x1e, green: 0x1f, blue: 0x20, alpha: 0xff},
+          {red: 0x1b, green: 0x1c, blue: 0x1d, alpha: 0xff},
+          {red: 0x1b, green: 0x1c, blue: 0x1d, alpha: 0xff},
+          {red: 0x18, green: 0x19, blue: 0x1a, alpha: 0xff},
+          {red: 0x18, green: 0x19, blue: 0x1a, alpha: 0xff}]}]]};
+
+  function do_test() {
+    simRecordHelper.readIMG = function fakeReadIMG(recordNumber, onsuccess, onerror) {
+      onsuccess(test_data.rawData[recordNumber]);
+    };
+
+    let onsuccess = function(icons) {
+      do_check_eq(icons.length, test_data.expected.length);
+      for (let i = 0; i < icons.length; i++) {
+        for (let j = 0; j < icons[i].length; j++) {
+          // Read the j_th image from the i_th record.
+          let icon = icons[i][j];
+          let expected = test_data.expected[i][j];
+          do_check_eq(icon.width, expected.width);
+          do_check_eq(icon.height, expected.height);
+          do_check_eq(icon.pixels.length, expected.pixels.length);
+          for (let k = 0; k < icon.pixels.length; k++) {
+            if (typeof icon.pixels[k] === "object") {
+              do_check_eq(icon.pixels[k].red, expected.pixels[k].red);
+              do_check_eq(icon.pixels[k].green, expected.pixels[k].green);
+              do_check_eq(icon.pixels[k].blue, expected.pixels[k].blue);
+              do_check_eq(icon.pixels[k].alpha, expected.pixels[k].alpha);
+            } else {
+              do_check_eq(icon.pixels[k], expected.pixels[k]);
+            }
+          }
+        }
+      }
+    };
+
+    let recordNumbers = [0, 1, 2, 3];
+    iconLoader.loadIcons(recordNumbers, onsuccess);
+  }
+
+  do_test();
+  run_next_test();
+});
--- a/dom/system/gonk/tests/test_ril_worker_icc_SimRecordHelper.js
+++ b/dom/system/gonk/tests/test_ril_worker_icc_SimRecordHelper.js
@@ -597,8 +597,677 @@ add_test(function test_update_display_co
   ril.operator.mnc = 01;
   do_test_spn(0x00, true, true);
   do_test_spn(0x01, true, true);
   do_test_spn(0x02, true, false);
   do_test_spn(0x03, true, false);
 
   run_next_test();
 });
+
+/**
+ * Verify reading EF_IMG and EF_IIDF with ICC_IMG_CODING_SCHEME_BASIC
+ */
+add_test(function test_reading_img_basic() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let record = context.SimRecordHelper;
+  let helper = context.GsmPDUHelper;
+  let ril    = context.RIL;
+  let buf    = context.Buf;
+  let io     = context.ICCIOHelper;
+
+  let test_data = [
+    {img: [0x01, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x06],
+     iidf: [
+       [/* Header */
+        0x05, 0x05,
+        /* Image body */
+        0x11, 0x33, 0x55, 0xfe]],
+     expected: [
+       {width: 0x05,
+        height: 0x05,
+        codingScheme: ICC_IMG_CODING_SCHEME_BASIC,
+        body: [0x11, 0x33, 0x55, 0xfe]}]},
+    {img: [0x02, 0x10, 0x01, 0x11, 0x4f, 0x04, 0x00, 0x05, 0x00, 0x04, 0x10,
+           0x01, 0x11, 0x4f, 0x05, 0x00, 0x05, 0x00, 0x04],
+     iidf: [
+       [/* Data offset */
+        0xff, 0xff, 0xff, 0xff, 0xff,
+        /* Header */
+        0x10, 0x01,
+        /* Image body */
+        0x11, 0x99,
+        /* Trailing data */
+        0xff, 0xff, 0xff],
+       [/* Data offset */
+        0xff, 0xff, 0xff, 0xff, 0xff,
+        /* Header */
+        0x10, 0x01,
+        /* Image body */
+        0x99, 0x11]],
+     expected: [
+       {width: 0x10,
+        height: 0x01,
+        codingScheme: ICC_IMG_CODING_SCHEME_BASIC,
+        body: [0x11, 0x99]},
+       {width: 0x10,
+        height: 0x01,
+        codingScheme: ICC_IMG_CODING_SCHEME_BASIC,
+        body: [0x99, 0x11]}]},
+    {img: [0x01, 0x28, 0x20, 0x11, 0x4f, 0xac, 0x00, 0x0b, 0x00, 0xa2],
+     iidf: [
+       [/* Data offset */
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        /* Header */
+        0x28, 0x20,
+        /* Image body */
+        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+        0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+        0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+        0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+        0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+        0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41,
+        0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+        0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+        0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x00, 0x01, 0x02,
+        0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+        0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+        0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+        0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
+        0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+        0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f]],
+     expected: [
+       {width: 0x28,
+        height: 0x20,
+        codingScheme: ICC_IMG_CODING_SCHEME_BASIC,
+        body: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+               0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+               0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+               0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+               0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31,
+               0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+               0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+               0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+               0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+               0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x00, 0x01, 0x02, 0x03,
+               0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+               0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+               0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21,
+               0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+               0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+               0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f]}]}];
+
+  function do_test(img, iidf, expected) {
+    io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) {
+      // Write data size
+      buf.writeInt32(img.length * 2);
+
+      // Write data
+      for (let i = 0; i < img.length; i++) {
+        helper.writeHexOctet(img[i]);
+      }
+
+      // Write string delimiter
+      buf.writeStringDelimiter(img.length * 2);
+
+      if (options.callback) {
+        options.callback(options);
+      }
+    };
+
+    let instanceIndex = 0;
+    io.loadTransparentEF = function fakeLoadTransparentEF(options) {
+      // Write data size
+      buf.writeInt32(iidf[instanceIndex].length * 2);
+
+      // Write data
+      for (let i = 0; i < iidf[instanceIndex].length; i++) {
+        helper.writeHexOctet(iidf[instanceIndex][i]);
+      }
+
+      // Write string delimiter
+      buf.writeStringDelimiter(iidf[instanceIndex].length * 2);
+
+      instanceIndex++;
+
+      if (options.callback) {
+        options.callback(options);
+      }
+    };
+
+    let onsuccess = function(icons) {
+      do_check_eq(icons.length, expected.length);
+      for (let i = 0; i < icons.length; i++) {
+        let icon = icons[i];
+        let exp = expected[i];
+        do_check_eq(icon.width, exp.width);
+        do_check_eq(icon.height, exp.height);
+        do_check_eq(icon.codingScheme, exp.codingScheme);
+
+        do_check_eq(icon.body.length, exp.body.length);
+        for (let j = 0; j < icon.body.length; j++) {
+          do_check_eq(icon.body[j], exp.body[j]);
+        }
+      }
+    };
+    record.readIMG(0, onsuccess);
+  }
+
+  for (let i = 0; i< test_data.length; i++) {
+    do_test(test_data[i].img, test_data[i].iidf, test_data[i].expected);
+  }
+  run_next_test();
+});
+
+/**
+ * Verify reading EF_IMG and EF_IIDF with the case data length is not enough
+ */
+add_test(function test_reading_img_length_error() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let record = context.SimRecordHelper;
+  let helper = context.GsmPDUHelper;
+  let ril    = context.RIL;
+  let buf    = context.Buf;
+  let io     = context.ICCIOHelper;
+ 
+  // Offset is 0x0004.
+  let img_test = [0x01, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x04, 0x00, 0x06];
+  let iidf_test = [0xff, 0xff, 0xff, // Offset length not enough.
+                   0x05, 0x05, 0x11, 0x22, 0x33, 0xfe];
+
+  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) {
+    // Write data size
+    buf.writeInt32(img_test.length * 2);
+
+    // Write data
+    for (let i = 0; i < img_test.length; i++) {
+      helper.writeHexOctet(img_test[i]);
+    }
+
+    // Write string delimiter
+    buf.writeStringDelimiter(img_test.length * 2);
+
+    if (options.callback) {
+      options.callback(options);
+    }
+  };
+
+  io.loadTransparentEF = function fakeLoadTransparentEF(options) {
+    // Write data size
+    buf.writeInt32(iidf_test.length * 2);
+
+    // Write data
+    for (let i = 0; i < iidf_test.length; i++) {
+      helper.writeHexOctet(iidf_test[i]);
+    }
+
+    // Write string delimiter
+    buf.writeStringDelimiter(iidf_test.length * 2);
+
+    if (options.callback) {
+      options.callback(options);
+    }
+  };
+
+  let onsuccess = function() {
+    do_print("onsuccess shouldn't be called.");
+    do_check_true(false);
+  };
+
+  let onerror = function() {
+    do_print("onerror called as expected.");
+    do_check_true(true);
+  };
+
+  record.readIMG(0, onsuccess, onerror);
+
+  run_next_test();
+});
+
+/**
+ * Verify reading EF_IMG and EF_IIDF with an invalid fileId
+ */
+add_test(function test_reading_img_invalid_fileId() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let record = context.SimRecordHelper;
+  let helper = context.GsmPDUHelper;
+  let ril    = context.RIL;
+  let buf    = context.Buf;
+  let io     = context.ICCIOHelper;
+
+  // Test invalid fileId: 0x5f00.
+  let img_test = [0x01, 0x05, 0x05, 0x11, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x06];
+  let iidf_test = [0x05, 0x05, 0x11, 0x22, 0x33, 0xfe];
+
+  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) {
+    // Write data size
+    buf.writeInt32(img_test.length * 2);
+
+    // Write data
+    for (let i = 0; i < img_test.length; i++) {
+      helper.writeHexOctet(img_test[i]);
+    }
+
+    // Write string delimiter
+    buf.writeStringDelimiter(img_test.length * 2);
+
+    if (options.callback) {
+      options.callback(options);
+    }
+  };
+
+  io.loadTransparentEF = function fakeLoadTransparentEF(options) {
+    // Write data size
+    buf.writeInt32(iidf_test.length * 2);
+
+    // Write data
+    for (let i = 0; i < iidf_test.length; i++) {
+      helper.writeHexOctet(iidf_test[i]);
+    }
+
+    // Write string delimiter
+    buf.writeStringDelimiter(iidf_test.length * 2);
+
+    if (options.callback) {
+      options.callback(options);
+    }
+  };
+
+  let onsuccess = function() {
+    do_print("onsuccess shouldn't be called.");
+    do_check_true(false);
+  };
+
+  let onerror = function() {
+    do_print("onerror called as expected.");
+    do_check_true(true);
+  };
+
+  record.readIMG(0, onsuccess, onerror);
+
+  run_next_test();
+});
+
+/**
+ * Verify reading EF_IMG with a wrong record length
+ */
+add_test(function test_reading_img_wrong_record_length() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let record = context.SimRecordHelper;
+  let helper = context.GsmPDUHelper;
+  let ril    = context.RIL;
+  let buf    = context.Buf;
+  let io     = context.ICCIOHelper;
+
+  let test_data = [
+    [0x01, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x06,
+     0xff, 0xff],
+    [0x02, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x06]];
+
+  function do_test(img) {
+    io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) {
+      // Write data size
+      buf.writeInt32(img.length * 2);
+
+      // Write data
+      for (let i = 0; i < img.length; i++) {
+        helper.writeHexOctet(img[i]);
+      }
+
+      // Write string delimiter
+      buf.writeStringDelimiter(img.length * 2);
+
+      if (options.callback) {
+        options.callback(options);
+      }
+    };
+
+    let onsuccess = function() {
+      do_print("onsuccess shouldn't be called.");
+      do_check_true(false);
+    };
+
+    let onerror = function() {
+      do_print("onerror called as expected.");
+      do_check_true(true);
+    };
+
+    record.readIMG(0, onsuccess, onerror);
+  }
+
+  for (let i = 0; i < test_data.length; i++) {
+    do_test(test_data[i]);
+  }
+  run_next_test();
+});
+
+/**
+ * Verify reading EF_IMG and EF_IIDF with ICC_IMG_CODING_SCHEME_COLOR
+ */
+add_test(function test_reading_img_color() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let record = context.SimRecordHelper;
+  let helper = context.GsmPDUHelper;
+  let ril    = context.RIL;
+  let buf    = context.Buf;
+  let io     = context.ICCIOHelper;
+
+  let test_data = [
+    {img: [0x01, 0x05, 0x05, 0x21, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x13],
+     iidf: [
+       [/* Header */
+        0x05, 0x05, 0x03, 0x08, 0x00, 0x13,
+        /* Image body */
+        0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0,
+        0xb0, 0xc0, 0xd0,
+        /* Clut entries */
+        0x00, 0x01, 0x02,
+        0x10, 0x11, 0x12,
+        0x20, 0x21, 0x22,
+        0x30, 0x31, 0x32,
+        0x40, 0x41, 0x42,
+        0x50, 0x51, 0x52,
+        0x60, 0x61, 0x62,
+        0x70, 0x71, 0x72]],
+     expected: [
+       {width: 0x05,
+        height: 0x05,
+        codingScheme: ICC_IMG_CODING_SCHEME_COLOR,
+        bitsPerImgPoint: 0x03,
+        numOfClutEntries: 0x08,
+        body: [0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0,
+               0xc0, 0xd0],
+        clut: [0x00, 0x01, 0x02,
+               0x10, 0x11, 0x12,
+               0x20, 0x21, 0x22,
+               0x30, 0x31, 0x32,
+               0x40, 0x41, 0x42,
+               0x50, 0x51, 0x52,
+               0x60, 0x61, 0x62,
+               0x70, 0x71, 0x72]}]},
+    {img: [0x02, 0x01, 0x06, 0x21, 0x4f, 0x33, 0x00, 0x02, 0x00, 0x08, 0x01,
+           0x06, 0x21, 0x4f, 0x44, 0x00, 0x02, 0x00, 0x08],
+     iidf: [
+       [/* Data offset */
+        0xff, 0xff,
+        /* Header */
+        0x01, 0x06, 0x02, 0x04, 0x00, 0x0d,
+        /* Image body */
+        0x40, 0x50,
+        /* Clut offset */
+        0xaa, 0xbb, 0xcc,
+        /* Clut entries */
+        0x01, 0x03, 0x05,
+        0x21, 0x23, 0x25,
+        0x41, 0x43, 0x45,
+        0x61, 0x63, 0x65],
+       [/* Data offset */
+        0xff, 0xff,
+        /* Header */
+        0x01, 0x06, 0x02, 0x04, 0x00, 0x0d,
+        /* Image body */
+        0x4f, 0x5f,
+        /* Clut offset */
+        0xaa, 0xbb, 0xcc,
+        /* Clut entries */
+        0x11, 0x13, 0x15,
+        0x21, 0x23, 0x25,
+        0x41, 0x43, 0x45,
+        0x61, 0x63, 0x65]],
+      expected: [
+        {width: 0x01,
+         height: 0x06,
+         codingScheme: ICC_IMG_CODING_SCHEME_COLOR,
+         bitsPerImgPoint: 0x02,
+         numOfClutEntries: 0x04,
+         body: [0x40, 0x50],
+         clut: [0x01, 0x03, 0x05,
+                0x21, 0x23, 0x25,
+                0x41, 0x43, 0x45,
+                0x61, 0x63, 0x65]},
+        {width: 0x01,
+         height: 0x06,
+         codingScheme: ICC_IMG_CODING_SCHEME_COLOR,
+         bitsPerImgPoint: 0x02,
+         numOfClutEntries: 0x04,
+         body: [0x4f, 0x5f],
+         clut: [0x11, 0x13, 0x15,
+                0x21, 0x23, 0x25,
+                0x41, 0x43, 0x45,
+                0x61, 0x63, 0x65]}]}];
+
+  function do_test(img, iidf, expected) {
+    io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) {
+      // Write data size
+      buf.writeInt32(img.length * 2);
+
+      // Write data
+      for (let i = 0; i < img.length; i++) {
+        helper.writeHexOctet(img[i]);
+      }
+
+      // Write string delimiter
+      buf.writeStringDelimiter(img.length * 2);
+
+      if (options.callback) {
+        options.callback(options);
+      }
+    };
+
+    let instanceIndex = 0;
+    io.loadTransparentEF = function fakeLoadTransparentEF(options) {
+      // Write data size
+      buf.writeInt32(iidf[instanceIndex].length * 2);
+
+      // Write data
+      for (let i = 0; i < iidf[instanceIndex].length; i++) {
+        helper.writeHexOctet(iidf[instanceIndex][i]);
+      }
+
+      // Write string delimiter
+      buf.writeStringDelimiter(iidf[instanceIndex].length * 2);
+
+      instanceIndex++;
+
+      if (options.callback) {
+        options.callback(options);
+      }
+    };
+
+    let onsuccess = function(icons) {
+      do_check_eq(icons.length, expected.length);
+      for (let i = 0; i < icons.length; i++) {
+        let icon = icons[i];
+        let exp = expected[i];
+        do_check_eq(icon.width, exp.width);
+        do_check_eq(icon.height, exp.height);
+        do_check_eq(icon.codingScheme, exp.codingScheme);
+
+        do_check_eq(icon.body.length, exp.body.length);
+        for (let j = 0; j < icon.body.length; j++) {
+          do_check_eq(icon.body[j], exp.body[j]);
+        }
+
+        do_check_eq(icon.clut.length, exp.clut.length);
+        for (let j = 0; j < icon.clut.length; j++) {
+          do_check_eq(icon.clut[j], exp.clut[j]);
+        }
+      }
+    };
+
+    record.readIMG(0, onsuccess);
+  }
+
+  for (let i = 0; i< test_data.length; i++) {
+    do_test(test_data[i].img, test_data[i].iidf, test_data[i].expected);
+  }
+  run_next_test();
+});
+
+/**
+ * Verify reading EF_IMG and EF_IIDF with
+ * ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY
+ */
+add_test(function test_reading_img_color() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let record = context.SimRecordHelper;
+  let helper = context.GsmPDUHelper;
+  let ril    = context.RIL;
+  let buf    = context.Buf;
+  let io     = context.ICCIOHelper;
+
+  let test_data = [
+    {img: [0x01, 0x05, 0x05, 0x22, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x13],
+     iidf: [
+       [/* Header */
+        0x05, 0x05, 0x03, 0x08, 0x00, 0x13,
+        /* Image body */
+        0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0,
+        0xb0, 0xc0, 0xd0,
+        /* Clut entries */
+        0x00, 0x01, 0x02,
+        0x10, 0x11, 0x12,
+        0x20, 0x21, 0x22,
+        0x30, 0x31, 0x32,
+        0x40, 0x41, 0x42,
+        0x50, 0x51, 0x52,
+        0x60, 0x61, 0x62,
+        0x70, 0x71, 0x72]],
+     expected: [
+       {width: 0x05,
+        height: 0x05,
+        codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY,
+        bitsPerImgPoint: 0x03,
+        numOfClutEntries: 0x08,
+        body: [0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90,
+               0xa0, 0xb0, 0xc0, 0xd0],
+        clut: [0x00, 0x01, 0x02,
+               0x10, 0x11, 0x12,
+               0x20, 0x21, 0x22,
+               0x30, 0x31, 0x32,
+               0x40, 0x41, 0x42,
+               0x50, 0x51, 0x52,
+               0x60, 0x61, 0x62,
+               0x70, 0x71, 0x72]}]},
+    {img: [0x02, 0x01, 0x06, 0x22, 0x4f, 0x33, 0x00, 0x02, 0x00, 0x08, 0x01,
+           0x06, 0x22, 0x4f, 0x33, 0x00, 0x02, 0x00, 0x08],
+     iidf: [
+       [/* Data offset */
+        0xff, 0xff,
+        /* Header */
+        0x01, 0x06, 0x02, 0x04, 0x00, 0x0d,
+        /* Image body */
+        0x40, 0x50,
+        /* Clut offset */
+        0x0a, 0x0b, 0x0c,
+        /* Clut entries */
+        0x01, 0x03, 0x05,
+        0x21, 0x23, 0x25,
+        0x41, 0x43, 0x45,
+        0x61, 0x63, 0x65],
+       [/* Data offset */
+        0xff, 0xff,
+        /* Header */
+        0x01, 0x06, 0x02, 0x04, 0x00, 0x0d,
+        /* Image body */
+        0x4f, 0x5f,
+        /* Clut offset */
+        0x0a, 0x0b, 0x0c,
+        /* Clut entries */
+        0x11, 0x13, 0x15,
+        0x21, 0x23, 0x25,
+        0x41, 0x43, 0x45,
+        0x61, 0x63, 0x65]],
+     expected: [
+       {width: 0x01,
+        height: 0x06,
+        codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY,
+        bitsPerImgPoint: 0x02,
+        numOfClutEntries: 0x04,
+        body: [0x40, 0x50],
+        clut: [0x01, 0x03, 0x05,
+               0x21, 0x23, 0x25,
+               0x41, 0x43, 0x45,
+               0x61, 0x63, 0x65]},
+       {width: 0x01,
+        height: 0x06,
+        codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY,
+        bitsPerImgPoint: 0x02,
+        numOfClutEntries: 0x04,
+        body: [0x4f, 0x5f],
+        clut: [0x11, 0x13, 0x15,
+               0x21, 0x23, 0x25,
+               0x41, 0x43, 0x45,
+               0x61, 0x63, 0x65]}]}];
+
+  function do_test(img, iidf, expected) {
+    io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) {
+      // Write data size
+      buf.writeInt32(img.length * 2);
+
+      // Write data
+      for (let i = 0; i < img.length; i++) {
+        helper.writeHexOctet(img[i]);
+      }
+
+      // Write string delimiter
+      buf.writeStringDelimiter(img.length * 2);
+
+      if (options.callback) {
+        options.callback(options);
+      }
+    };
+
+    let instanceIndex = 0;
+    io.loadTransparentEF = function fakeLoadTransparentEF(options) {
+      // Write data size
+      buf.writeInt32(iidf[instanceIndex].length * 2);
+
+      // Write data
+      for (let i = 0; i < iidf[instanceIndex].length; i++) {
+        helper.writeHexOctet(iidf[instanceIndex][i]);
+      }
+
+      // Write string delimiter
+      buf.writeStringDelimiter(iidf[instanceIndex].length * 2);
+
+      instanceIndex++;
+
+      if (options.callback) {
+        options.callback(options);
+      }
+    };
+
+    let onsuccess = function(icons) {
+      do_check_eq(icons.length, expected.length);
+      for (let i = 0; i < icons.length; i++) {
+        let icon = icons[i];
+        let exp = expected[i];
+        do_check_eq(icon.width, exp.width);
+        do_check_eq(icon.height, exp.height);
+        do_check_eq(icon.codingScheme, exp.codingScheme);
+
+        do_check_eq(icon.body.length, exp.body.length);
+        for (let j = 0; j < icon.body.length; j++) {
+          do_check_eq(icon.body[j], exp.body[j]);
+        }
+
+        do_check_eq(icon.clut.length, exp.clut.length);
+        for (let j = 0; j < icon.clut.length; j++) {
+          do_check_eq(icon.clut[j], exp.clut[j]);
+        }
+      }
+    };
+
+    record.readIMG(0, onsuccess);
+  }
+
+  for (let i = 0; i< test_data.length; i++) {
+    do_test(test_data[i].img, test_data[i].iidf, test_data[i].expected);
+  }
+  run_next_test();
+});
--- a/dom/system/gonk/tests/test_ril_worker_stk.js
+++ b/dom/system/gonk/tests/test_ril_worker_stk.js
@@ -409,25 +409,30 @@ add_test(function test_stk_proactive_com
  * Verify Proactive Command : Play Tone
  */
 add_test(function test_stk_proactive_command_play_tone() {
   let worker = newUint8Worker();
   let context = worker.ContextPool._contexts[0];
   let pduHelper = context.GsmPDUHelper;
   let berHelper = context.BerTlvHelper;
   let stkHelper = context.StkProactiveCmdHelper;
+  let ril = context.RIL;
+  ril.iccInfoPrivate.sst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                            0x00, 0x10];
+  ril.appType = CARD_APPTYPE_SIM;
 
   let tone_1 = [
     0xD0,
-    0x1B,
+    0x1F,
     0x81, 0x03, 0x01, 0x20, 0x00,
     0x82, 0x02, 0x81, 0x03,
     0x85, 0x09, 0x44, 0x69, 0x61, 0x6C, 0x20, 0x54, 0x6F, 0x6E, 0x65,
     0x8E, 0x01, 0x01,
-    0x84, 0x02, 0x01, 0x05];
+    0x84, 0x02, 0x01, 0x05,
+    0x9E, 0x02, 0x00, 0x01];
 
   for (let i = 0; i < tone_1.length; i++) {
     pduHelper.writeHexOctet(tone_1[i]);
   }
 
   let berTlv = berHelper.decode(tone_1.length);
   let ctlvs = berTlv.value;
   let tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
@@ -440,16 +445,20 @@ add_test(function test_stk_proactive_com
 
   tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_TONE, ctlvs);
   do_check_eq(tlv.value.tone, STK_TONE_TYPE_DIAL_TONE);
 
   tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_DURATION, ctlvs);
   do_check_eq(tlv.value.timeUnit, STK_TIME_UNIT_SECOND);
   do_check_eq(tlv.value.timeInterval, 5);
 
+  tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+  do_check_eq(tlv.value.qualifier, 0x00);
+  do_check_eq(tlv.value.identifier, 0x01);
+
   run_next_test();
 });
 
 /**
  * Verify Proactive Command : Poll Interval
  */
 add_test(function test_stk_proactive_command_poll_interval() {
   let worker = newUint8Worker();
@@ -487,36 +496,45 @@ add_test(function test_stk_proactive_com
  * Verify Proactive Command: Display Text
  */
 add_test(function test_read_septets_to_string() {
   let worker = newUint8Worker();
   let context = worker.ContextPool._contexts[0];
   let pduHelper = context.GsmPDUHelper;
   let berHelper = context.BerTlvHelper;
   let stkHelper = context.StkProactiveCmdHelper;
+  let ril = context.RIL;
+  ril.iccInfoPrivate.sst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                            0x00, 0x10];
+  ril.appType = CARD_APPTYPE_SIM;
 
   let display_text_1 = [
     0xd0,
-    0x28,
+    0x2c,
     0x81, 0x03, 0x01, 0x21, 0x80,
     0x82, 0x02, 0x81, 0x02,
     0x0d, 0x1d, 0x00, 0xd3, 0x30, 0x9b, 0xfc, 0x06, 0xc9, 0x5c, 0x30, 0x1a,
     0xa8, 0xe8, 0x02, 0x59, 0xc3, 0xec, 0x34, 0xb9, 0xac, 0x07, 0xc9, 0x60,
     0x2f, 0x58, 0xed, 0x15, 0x9b, 0xb9, 0x40,
+    0x9e, 0x02, 0x00, 0x01
   ];
 
   for (let i = 0; i < display_text_1.length; i++) {
     pduHelper.writeHexOctet(display_text_1[i]);
   }
 
   let berTlv = berHelper.decode(display_text_1.length);
   let ctlvs = berTlv.value;
   let tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_TEXT_STRING, ctlvs);
   do_check_eq(tlv.value.textString, "Saldo 2.04 E. Validez 20/05/13. ");
 
+  tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+  do_check_eq(tlv.value.qualifier, 0x00);
+  do_check_eq(tlv.value.identifier, 0x01);
+
   run_next_test();
 });
 
 /**
  * Verify Proactive Command: Set Up Event List.
  */
 add_test(function test_stk_proactive_command_event_list() {
   let worker = newUint8Worker();
@@ -557,25 +575,30 @@ add_test(function test_stk_proactive_com
  */
 add_test(function test_stk_proactive_command_get_input() {
   let worker = newUint8Worker();
   let context = worker.ContextPool._contexts[0];
   let pduHelper = context.GsmPDUHelper;
   let berHelper = context.BerTlvHelper;
   let stkHelper = context.StkProactiveCmdHelper;
   let stkCmdHelper = context.StkCommandParamsFactory;
+  let ril = context.RIL;
+  ril.iccInfoPrivate.sst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                            0x00, 0x10];
+  ril.appType = CARD_APPTYPE_SIM;
 
   let get_input_1 = [
     0xD0,
-    0x1E,
+    0x22,
     0x81, 0x03, 0x01, 0x23, 0x8F,
     0x82, 0x02, 0x81, 0x82,
     0x8D, 0x05, 0x04, 0x54, 0x65, 0x78, 0x74,
     0x91, 0x02, 0x01, 0x10,
-    0x17, 0x08, 0x04, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74];
+    0x17, 0x08, 0x04, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74,
+    0x9E, 0x02, 0x00, 0x01];
 
   for (let i = 0; i < get_input_1.length; i++) {
     pduHelper.writeHexOctet(get_input_1[i]);
   }
 
   let berTlv = berHelper.decode(get_input_1.length);
   let ctlvs = berTlv.value;
   let tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
@@ -588,16 +611,20 @@ add_test(function test_stk_proactive_com
   do_check_eq(input.isUCS2, true);
   do_check_eq(input.hideInput, true);
   do_check_eq(input.isPacked, true);
   do_check_eq(input.isHelpAvailable, true);
   do_check_eq(input.minLength, 0x01);
   do_check_eq(input.maxLength, 0x10);
   do_check_eq(input.defaultText, "Default");
 
+  tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+  do_check_eq(tlv.value.qualifier, 0x00);
+  do_check_eq(tlv.value.identifier, 0x01);
+
   let get_input_2 = [
     0xD0,
     0x11,
     0x81, 0x03, 0x01, 0x23, 0x00,
     0x82, 0x02, 0x81, 0x82,
     0x8D, 0x00,
     0x91, 0x02, 0x01, 0x10,
     0x17, 0x00];
@@ -656,28 +683,34 @@ add_test(function test_stk_proactive_com
  */
 add_test(function test_stk_proactive_command_select_item() {
   let worker = newUint8Worker();
   let context = worker.ContextPool._contexts[0];
   let pduHelper = context.GsmPDUHelper;
   let berHelper = context.BerTlvHelper;
   let stkHelper = context.StkProactiveCmdHelper;
   let stkFactory = context.StkCommandParamsFactory;
+  let ril = context.RIL;
+  ril.iccInfoPrivate.sst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                            0x00, 0x10];
+  ril.appType = CARD_APPTYPE_SIM;
 
   let select_item_1 = [
     0xD0,
-    0x33,
+    0x3C,
     0x81, 0x03, 0x01, 0x24, 0x00,
     0x82, 0x02, 0x81, 0x82,
     0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65,
     0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31,
     0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32,
     0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33,
     0x18, 0x03, 0x10, 0x15, 0x20,
-    0x90, 0x01, 0x01
+    0x90, 0x01, 0x01,
+    0x9E, 0x02, 0x00, 0x01,
+    0x9F, 0x03, 0x00, 0x01, 0x02
   ];
 
   for(let i = 0 ; i < select_item_1.length; i++) {
     pduHelper.writeHexOctet(select_item_1[i]);
   }
 
   let berTlv = berHelper.decode(select_item_1.length);
   let ctlvs = berTlv.value;
@@ -694,16 +727,25 @@ add_test(function test_stk_proactive_com
   do_check_eq(menu.items[1].text, "item 2");
   do_check_eq(menu.items[2].identifier, 3);
   do_check_eq(menu.items[2].text, "item 3");
   do_check_eq(menu.nextActionList[0], STK_CMD_SET_UP_CALL);
   do_check_eq(menu.nextActionList[1], STK_CMD_LAUNCH_BROWSER);
   do_check_eq(menu.nextActionList[2], STK_CMD_PLAY_TONE);
   do_check_eq(menu.defaultItem, 0x00);
 
+  tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+  do_check_eq(tlv.value.qualifier, 0x00);
+  do_check_eq(tlv.value.identifier, 0x01);
+
+  tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID_LIST, ctlvs);
+  do_check_eq(tlv.value.qualifier, 0x00);
+  do_check_eq(tlv.value.identifiers[0], 0x01);
+  do_check_eq(tlv.value.identifiers[1], 0x02);
+
   let select_item_2 = [
     0xD0,
     0x33,
     0x81, 0x03, 0x01, 0x24, 0x00,
     0x82, 0x02, 0x81, 0x82,
     0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65,
     0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31,
     0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32,
@@ -744,27 +786,33 @@ add_test(function test_stk_proactive_com
  */
 add_test(function test_stk_proactive_command_set_up_menu() {
   let worker = newUint8Worker();
   let context = worker.ContextPool._contexts[0];
   let pduHelper = context.GsmPDUHelper;
   let berHelper = context.BerTlvHelper;
   let stkHelper = context.StkProactiveCmdHelper;
   let stkFactory = context.StkCommandParamsFactory;
+  let ril = context.RIL;
+  ril.iccInfoPrivate.sst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                            0x00, 0x10];
+  ril.appType = CARD_APPTYPE_SIM;
 
   let set_up_menu_1 = [
     0xD0,
-    0x30,
+    0x39,
     0x81, 0x03, 0x01, 0x25, 0x00,
     0x82, 0x02, 0x81, 0x82,
     0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65,
     0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31,
     0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32,
     0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33,
-    0x18, 0x03, 0x10, 0x15, 0x20
+    0x18, 0x03, 0x10, 0x15, 0x20,
+    0x9E, 0x02, 0x00, 0x01,
+    0x9F, 0x03, 0x00, 0x01, 0x02
   ];
 
   for(let i = 0 ; i < set_up_menu_1.length; i++) {
     pduHelper.writeHexOctet(set_up_menu_1[i]);
   }
 
   let berTlv = berHelper.decode(set_up_menu_1.length);
   let ctlvs = berTlv.value;
@@ -780,16 +828,25 @@ add_test(function test_stk_proactive_com
   do_check_eq(menu.items[1].identifier, 2);
   do_check_eq(menu.items[1].text, "item 2");
   do_check_eq(menu.items[2].identifier, 3);
   do_check_eq(menu.items[2].text, "item 3");
   do_check_eq(menu.nextActionList[0], STK_CMD_SET_UP_CALL);
   do_check_eq(menu.nextActionList[1], STK_CMD_LAUNCH_BROWSER);
   do_check_eq(menu.nextActionList[2], STK_CMD_PLAY_TONE);
 
+  tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+  do_check_eq(tlv.value.qualifier, 0x00);
+  do_check_eq(tlv.value.identifier, 0x01);
+
+  tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID_LIST, ctlvs);
+  do_check_eq(tlv.value.qualifier, 0x00);
+  do_check_eq(tlv.value.identifiers[0], 0x01);
+  do_check_eq(tlv.value.identifiers[1], 0x02);
+
   let set_up_menu_2 = [
     0xD0,
     0x30,
     0x81, 0x03, 0x01, 0x25, 0x00,
     0x82, 0x02, 0x81, 0x82,
     0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65,
     0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31,
     0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32,
@@ -828,41 +885,50 @@ add_test(function test_stk_proactive_com
  */
 add_test(function test_stk_proactive_command_set_up_call() {
   let worker = newUint8Worker();
   let context = worker.ContextPool._contexts[0];
   let pduHelper = context.GsmPDUHelper;
   let berHelper = context.BerTlvHelper;
   let stkHelper = context.StkProactiveCmdHelper;
   let cmdFactory = context.StkCommandParamsFactory;
+  let ril = context.RIL;
+  ril.iccInfoPrivate.sst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                            0x00, 0x10];
+  ril.appType = CARD_APPTYPE_SIM;
 
   let set_up_call_1 = [
     0xD0,
-    0x29,
+    0x2d,
     0x81, 0x03, 0x01, 0x10, 0x04,
     0x82, 0x02, 0x81, 0x82,
     0x05, 0x0A, 0x44, 0x69, 0x73, 0x63, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74,
     0x86, 0x09, 0x81, 0x10, 0x32, 0x04, 0x21, 0x43, 0x65, 0x1C, 0x2C,
-    0x05, 0x07, 0x4D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65];
+    0x05, 0x07, 0x4D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+    0x9E, 0x02, 0x00, 0x01];
 
   for (let i = 0 ; i < set_up_call_1.length; i++) {
     pduHelper.writeHexOctet(set_up_call_1[i]);
   }
 
   let berTlv = berHelper.decode(set_up_call_1.length);
   let ctlvs = berTlv.value;
   let tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
   do_check_eq(tlv.value.commandNumber, 0x01);
   do_check_eq(tlv.value.typeOfCommand, STK_CMD_SET_UP_CALL);
 
   let setupCall = cmdFactory.createParam(tlv.value, ctlvs);
   do_check_eq(setupCall.address, "012340123456,1,2");
   do_check_eq(setupCall.confirmMessage, "Disconnect");
   do_check_eq(setupCall.callMessage, "Message");
 
+  tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_ICON_ID, ctlvs);
+  do_check_eq(tlv.value.qualifier, 0x00);
+  do_check_eq(tlv.value.identifier, 0x01);
+
   run_next_test();
 });
 
 /**
  * Verify Proactive Command : Timer Management
  */
 add_test(function test_stk_proactive_command_timer_management() {
   let worker = newUint8Worker();
--- a/dom/system/gonk/tests/xpcshell.ini
+++ b/dom/system/gonk/tests/xpcshell.ini
@@ -5,16 +5,17 @@ tail =
 [test_ril_worker_buf.js]
 [test_ril_worker_icc_CardLock.js]
 [test_ril_worker_icc_BerTlvHelper.js]
 [test_ril_worker_icc_GsmPDUHelper.js]
 [test_ril_worker_icc_ICCContactHelper.js]
 [test_ril_worker_icc_ICCIOHelper.js]
 [test_ril_worker_icc_ICCPDUHelper.js]
 [test_ril_worker_icc_ICCRecordHelper.js]
+[test_ril_worker_icc_IconLoader.js]
 [test_ril_worker_icc_ICCUtilsHelper.js]
 [test_ril_worker_icc_SimRecordHelper.js]
 [test_ril_worker_sms.js]
 # Bug 916067 - B2G RIL: test_ril_worker_sms.js takes too long to finish
 skip-if = true
 [test_ril_worker_sms_cdma.js]
 [test_ril_worker_sms_cdmapduhelper.js]
 [test_ril_worker_sms_nl_tables.js]
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -361,16 +361,18 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN
                                                 DOMEventTargetHelper)
   tmp->Shutdown();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCalls)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallsList)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mGroup)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Telephony)
+  // Telephony does not expose nsITelephonyListener.  mListener is the exposed
+  // nsITelephonyListener and forwards the calls it receives to us.
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(Telephony, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(Telephony, DOMEventTargetHelper)
 
 NS_IMPL_ISUPPORTS(Telephony::Listener, nsITelephonyListener)
 NS_IMPL_ISUPPORTS(Telephony::Callback, nsITelephonyCallback)
 
--- a/dom/telephony/Telephony.h
+++ b/dom/telephony/Telephony.h
@@ -19,20 +19,21 @@
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class OwningTelephonyCallOrTelephonyCallGroup;
 
-class Telephony MOZ_FINAL : public DOMEventTargetHelper
+class Telephony MOZ_FINAL : public DOMEventTargetHelper,
+                            private nsITelephonyListener
 {
   /**
-   * Class Telephony doesn't actually inherit nsITelephonyListener.
+   * Class Telephony doesn't actually expose nsITelephonyListener.
    * Instead, it owns an nsITelephonyListener derived instance mListener
    * and passes it to nsITelephonyService. The onreceived events are first
    * delivered to mListener and then forwarded to its owner, Telephony. See
    * also bug 775997 comment #51.
    */
   class Listener;
 
   class Callback;
--- a/dom/voicemail/Voicemail.cpp
+++ b/dom/voicemail/Voicemail.cpp
@@ -64,16 +64,18 @@ Voicemail::Voicemail(nsPIDOMWindow* aWin
 Voicemail::~Voicemail()
 {
   MOZ_ASSERT(mProvider && mListener);
 
   mListener->Disconnect();
   mProvider->UnregisterVoicemailMsg(mListener);
 }
 
+NS_IMPL_ISUPPORTS_INHERITED0(Voicemail, DOMEventTargetHelper)
+
 JSObject*
 Voicemail::WrapObject(JSContext* aCx)
 {
   return MozVoicemailBinding::Wrap(aCx, this);
 }
 
 bool
 Voicemail::IsValidServiceId(uint32_t aServiceId) const
--- a/dom/voicemail/Voicemail.h
+++ b/dom/voicemail/Voicemail.h
@@ -17,36 +17,38 @@ struct JSContext;
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class MozVoicemailStatus;
 
-class Voicemail MOZ_FINAL : public DOMEventTargetHelper
+class Voicemail MOZ_FINAL : public DOMEventTargetHelper,
+                            private nsIVoicemailListener
 {
   /**
-   * Class Voicemail doesn't actually inherit nsIVoicemailListener. Instead, it
+   * Class Voicemail doesn't actually expose nsIVoicemailListener. Instead, it
    * owns an nsIVoicemailListener derived instance mListener and passes it to
    * nsIVoicemailProvider. The onreceived events are first delivered to
    * mListener and then forwarded to its owner, Voicemail. See also bug 775997
    * comment #51.
    */
   class Listener;
 
+  virtual ~Voicemail();
+
 public:
+  NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIVOICEMAILLISTENER
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
 
   Voicemail(nsPIDOMWindow* aWindow, nsIVoicemailProvider* aProvider);
 
-  virtual ~Voicemail();
-
   nsPIDOMWindow*
   GetParentObject() const
   {
     return GetOwner();
   }
 
   virtual JSObject*
   WrapObject(JSContext* aCx) MOZ_OVERRIDE;
--- a/dom/webidl/ServiceWorkerContainer.webidl
+++ b/dom/webidl/ServiceWorkerContainer.webidl
@@ -3,39 +3,37 @@
  * 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/.
  *
  * The origin of this IDL file is
  * http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html
  *
  */
 
-[Pref="dom.serviceWorkers.enabled"]
-interface ServiceWorkerContainer {
+[Pref="dom.serviceWorkers.enabled",
+ Exposed=Window]
+interface ServiceWorkerContainer : EventTarget {
   // FIXME(nsm):
   // https://github.com/slightlyoff/ServiceWorker/issues/198
   // and discussion at https://etherpad.mozilla.org/serviceworker07apr
-  [Unforgeable] readonly attribute ServiceWorker? installing;
-  [Unforgeable] readonly attribute ServiceWorker? waiting;
-  [Unforgeable] readonly attribute ServiceWorker? active;
   [Unforgeable] readonly attribute ServiceWorker? controller;
 
   [Throws]
-  readonly attribute Promise<any> ready;
-
-  [Throws]
-  Promise<any> getAll();
+  readonly attribute Promise<ServiceWorkerRegistration> ready;
 
   [Throws]
-  Promise<ServiceWorker> register(DOMString url, optional RegistrationOptionList options);
+  Promise<ServiceWorkerRegistration> register(ScalarValueString scriptURL,
+                                              optional RegistrationOptionList options);
 
   [Throws]
-  Promise<any> unregister(DOMString? scope);
+  Promise<ServiceWorkerRegistration> getRegistration(optional ScalarValueString documentURL = "");
 
-  attribute EventHandler onupdatefound;
+  [Throws]
+   Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
+
   attribute EventHandler oncontrollerchange;
   attribute EventHandler onreloadpage;
   attribute EventHandler onerror;
 };
 
 // Testing only.
 partial interface ServiceWorkerContainer {
   [Throws,Pref="dom.serviceWorkers.testing.enabled"]
@@ -44,10 +42,10 @@ partial interface ServiceWorkerContainer
   [Throws,Pref="dom.serviceWorkers.testing.enabled"]
   DOMString getScopeForUrl(DOMString url);
 
   [Throws,Pref="dom.serviceWorkers.testing.enabled"]
   DOMString getControllingWorkerScriptURLForPath(DOMString path);
 };
 
 dictionary RegistrationOptionList {
-  DOMString scope = "/*";
+  ScalarValueString scope = "/*";
 };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/ServiceWorkerRegistration.webidl
@@ -0,0 +1,25 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html
+ *
+ */
+
+[Pref="dom.serviceWorkers.enabled",
+ Exposed=Window]
+interface ServiceWorkerRegistration : EventTarget {
+  [Unforgeable] readonly attribute ServiceWorker? installing;
+  [Unforgeable] readonly attribute ServiceWorker? waiting;
+  [Unforgeable] readonly attribute ServiceWorker? active;
+
+  readonly attribute ScalarValueString scope;
+
+  [Throws]
+  Promise<boolean> unregister();
+
+  // event
+  attribute EventHandler onupdatefound;
+};
--- a/dom/webidl/TestInterfaceJS.webidl
+++ b/dom/webidl/TestInterfaceJS.webidl
@@ -1,24 +1,37 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+dictionary TestInterfaceJSUnionableDictionary {
+  object objectMember;
+  any anyMember;
+};
+
 [JSImplementation="@mozilla.org/dom/test-interface-js;1",
  Pref="dom.expose_test_interfaces",
- Constructor(optional any anyArg, optional object objectArg)]
+ Constructor(optional any anyArg, optional object objectArg, optional TestInterfaceJSDictionary dictionaryArg)]
 interface TestInterfaceJS {
   readonly attribute any anyArg;
   readonly attribute object objectArg;
+  [Cached, Pure] readonly attribute TestInterfaceJSDictionary dictionaryArg;
   attribute any anyAttr;
   attribute object objectAttr;
+  [Cached, Pure] attribute TestInterfaceJSDictionary dictionaryAttr;
   any pingPongAny(any arg);
-  object pingPongObject(any obj);
+  object pingPongObject(object obj);
+  any pingPongObjectOrString((object or DOMString) objOrString);
+  TestInterfaceJSDictionary pingPongDictionary(optional TestInterfaceJSDictionary dict);
+  long pingPongDictionaryOrLong(optional (TestInterfaceJSUnionableDictionary or long) dictOrLong);
+  DOMString pingPongMap(MozMap<any> map);
+  long objectSequenceLength(sequence<object> seq);
+  long anySequenceLength(sequence<any> seq);
 
   // For testing bug 968335.
   DOMString getCallerPrincipal();
 
   DOMString convertSVS(ScalarValueString svs);
 
   (TestInterfaceJS or long) pingPongUnion((TestInterfaceJS or long) something);
   (DOMString or TestInterfaceJS?) pingPongUnionContainingNull((TestInterfaceJS? or DOMString) something);
new file mode 100644
--- /dev/null
+++ b/dom/webidl/TestInterfaceJSDictionaries.webidl
@@ -0,0 +1,27 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//
+// These dictionaries are in a separate WebIDL file to avoid circular include
+// problems. One of the dictionary includes a union as a member, so that
+// dictionary's header needs to include UnionTypes.h. But the API in
+// TestInterfaceJS also declares a union of dictionaries, so _that_
+// dictionary's header needs to be included _by_ UnionTypes.h. The solution
+// is to separate those two dictionaries into separate header files.
+//
+
+dictionary TestInterfaceJSDictionary2 {
+  object innerObject;
+};
+
+dictionary TestInterfaceJSDictionary {
+  TestInterfaceJSDictionary2 innerDictionary;
+  object objectMember;
+  any anyMember;
+  (object or DOMString) objectOrStringMember;
+  sequence<any> anySequenceMember;
+};
+
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -321,16 +321,17 @@ WEBIDL_FILES = [
     'RTCStatsReport.webidl',
     'Screen.webidl',
     'ScriptProcessorNode.webidl',
     'ScrollAreaEvent.webidl',
     'Selection.webidl',
     'ServiceWorker.webidl',
     'ServiceWorkerContainer.webidl',
     'ServiceWorkerGlobalScope.webidl',
+    'ServiceWorkerRegistration.webidl',
     'SettingsManager.webidl',
     'ShadowRoot.webidl',
     'SharedWorker.webidl',
     'SharedWorkerGlobalScope.webidl',
     'SimpleGestureEvent.webidl',
     'SourceBuffer.webidl',
     'SourceBufferList.webidl',
     'Storage.webidl',
@@ -558,17 +559,17 @@ WEBIDL_FILES += [
     'StyleRuleChangeEvent.webidl',
     'StyleSheetApplicableStateChangeEvent.webidl',
     'StyleSheetChangeEvent.webidl',
 ]
 
 # We only expose our prefable test interfaces in debug builds, just to be on
 # the safe side.
 if CONFIG['MOZ_DEBUG']:
-    WEBIDL_FILES += ['TestInterfaceJS.webidl']
+    WEBIDL_FILES += ['TestInterfaceJS.webidl', 'TestInterfaceJSDictionaries.webidl']
 
 if CONFIG['MOZ_B2G_BT']:
     if CONFIG['MOZ_B2G_BT_API_V2']:
         WEBIDL_FILES += [
             'BluetoothAdapter2.webidl',
             'BluetoothClassOfDevice.webidl',
             'BluetoothDevice2.webidl',
             'BluetoothDiscoveryHandle.webidl',
new file mode 100644
--- /dev/null
+++ b/dom/workers/ServiceWorkerCommon.h
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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/. */
+
+#ifndef mozilla_dom_ServiceWorkerCommon_h
+#define mozilla_dom_ServiceWorkerCommon_h
+
+namespace mozilla {
+namespace dom {
+
+// Use multiples of 2 since they can be bitwise ORed when calling
+// InvalidateServiceWorkerRegistrationWorker.
+MOZ_BEGIN_ENUM_CLASS(WhichServiceWorker)
+  INSTALLING_WORKER = 1,
+  WAITING_WORKER    = 2,
+  ACTIVE_WORKER     = 4,
+MOZ_END_ENUM_CLASS(WhichServiceWorker)
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(WhichServiceWorker)
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_ServiceWorkerCommon_h
--- a/dom/workers/ServiceWorkerContainer.cpp
+++ b/dom/workers/ServiceWorkerContainer.cpp
@@ -17,40 +17,34 @@
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ServiceWorkerContainerBinding.h"
 #include "mozilla/dom/workers/bindings/ServiceWorker.h"
 
 #include "ServiceWorker.h"
 
 namespace mozilla {
 namespace dom {
-namespace workers {
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorkerContainer)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper,
-                                   mInstallingWorker,
-                                   mWaitingWorker,
-                                   mActiveWorker,
                                    mControllerWorker)
 
 ServiceWorkerContainer::ServiceWorkerContainer(nsPIDOMWindow* aWindow)
   : mWindow(aWindow)
 {
   SetIsDOMBinding();
-  StartListeningForEvents();
 }
 
 ServiceWorkerContainer::~ServiceWorkerContainer()
 {
-  StopListeningForEvents();
 }
 
 JSObject*
 ServiceWorkerContainer::WrapObject(JSContext* aCx)
 {
   return ServiceWorkerContainerBinding::Wrap(aCx, this);
 }
 
@@ -72,178 +66,65 @@ ServiceWorkerContainer::Register(const n
     return nullptr;
   }
 
   nsRefPtr<Promise> ret = static_cast<Promise*>(promise.get());
   MOZ_ASSERT(ret);
   return ret.forget();
 }
 
-already_AddRefed<Promise>
-ServiceWorkerContainer::Unregister(const nsAString& aScope,
-                                   ErrorResult& aRv)
-{
-  nsCOMPtr<nsISupports> promise;
-
-  nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
-  if (!swm) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return nullptr;
-  }
-
-  aRv = swm->Unregister(mWindow, aScope, getter_AddRefs(promise));
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  nsRefPtr<Promise> ret = static_cast<Promise*>(promise.get());
-  MOZ_ASSERT(ret);
-  return ret.forget();
-}
-
-already_AddRefed<workers::ServiceWorker>
-ServiceWorkerContainer::GetInstalling()
-{
-  if (!mInstallingWorker) {
-    mInstallingWorker = GetWorkerReference(WhichServiceWorker::INSTALLING_WORKER);
-  }
-
-  nsRefPtr<ServiceWorker> ret = mInstallingWorker;
-  return ret.forget();
-}
-
-already_AddRefed<workers::ServiceWorker>
-ServiceWorkerContainer::GetWaiting()
-{
-  if (!mWaitingWorker) {
-    mWaitingWorker = GetWorkerReference(WhichServiceWorker::WAITING_WORKER);
-  }
-
-  nsRefPtr<ServiceWorker> ret = mWaitingWorker;
-  return ret.forget();
-}
-
-already_AddRefed<workers::ServiceWorker>
-ServiceWorkerContainer::GetActive()
-{
-  if (!mActiveWorker) {
-    mActiveWorker = GetWorkerReference(WhichServiceWorker::ACTIVE_WORKER);
-  }
-
-  nsRefPtr<ServiceWorker> ret = mActiveWorker;
-  return ret.forget();
-}
-
 already_AddRefed<workers::ServiceWorker>
 ServiceWorkerContainer::GetController()
 {
   if (!mControllerWorker) {
     nsresult rv;
     nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
     if (!swm) {
       return nullptr;
     }
 
     nsCOMPtr<nsISupports> serviceWorker;
     rv = swm->GetDocumentController(mWindow, getter_AddRefs(serviceWorker));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return nullptr;
     }
 
-    mControllerWorker = static_cast<ServiceWorker*>(serviceWorker.get());
+    mControllerWorker =
+      static_cast<workers::ServiceWorker*>(serviceWorker.get());
   }
 
-  nsRefPtr<ServiceWorker> ref = mControllerWorker;
+  nsRefPtr<workers::ServiceWorker> ref = mControllerWorker;
   return ref.forget();
 }
 
 already_AddRefed<Promise>
-ServiceWorkerContainer::GetAll(ErrorResult& aRv)
+ServiceWorkerContainer::GetRegistrations(ErrorResult& aRv)
+{
+  // FIXME(nsm): Bug 1002571
+  aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+  return nullptr;
+}
+
+already_AddRefed<Promise>
+ServiceWorkerContainer::GetRegistration(const nsAString& aDocumentURL,
+                                        ErrorResult& aRv)
 {
   // FIXME(nsm): Bug 1002571
   aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   return nullptr;
 }
 
 already_AddRefed<Promise>
 ServiceWorkerContainer::GetReady(ErrorResult& aRv)
 {
   // FIXME(nsm): Bug 1025077
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
   return Promise::Create(global, aRv);
 }
 
-// XXXnsm, maybe this can be optimized to only add when a event handler is
-// registered.
-void
-ServiceWorkerContainer::StartListeningForEvents()
-{
-  nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
-  if (swm) {
-    swm->AddContainerEventListener(mWindow->GetDocumentURI(), this);
-  }
-}
-
-void
-ServiceWorkerContainer::StopListeningForEvents()
-{
-  nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
-  if (swm) {
-    swm->RemoveContainerEventListener(mWindow->GetDocumentURI(), this);
-  }
-}
-
-void
-ServiceWorkerContainer::InvalidateWorkerReference(WhichServiceWorker aWhichOnes)
-{
-  if (aWhichOnes & WhichServiceWorker::INSTALLING_WORKER) {
-    mInstallingWorker = nullptr;
-  }
-
-  if (aWhichOnes & WhichServiceWorker::WAITING_WORKER) {
-    mWaitingWorker = nullptr;
-  }
-
-  if (aWhichOnes & WhichServiceWorker::ACTIVE_WORKER) {
-    mActiveWorker = nullptr;
-  }
-}
-
-already_AddRefed<workers::ServiceWorker>
-ServiceWorkerContainer::GetWorkerReference(WhichServiceWorker aWhichOne)
-{
-  nsresult rv;
-  nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
-  if (!swm) {
-    return nullptr;
-  }
-
-  nsCOMPtr<nsISupports> serviceWorker;
-  switch(aWhichOne) {
-    case WhichServiceWorker::INSTALLING_WORKER:
-      rv = swm->GetInstalling(mWindow, getter_AddRefs(serviceWorker));
-      break;
-    case WhichServiceWorker::WAITING_WORKER:
-      rv = swm->GetWaiting(mWindow, getter_AddRefs(serviceWorker));
-      break;
-    case WhichServiceWorker::ACTIVE_WORKER:
-      rv = swm->GetActive(mWindow, getter_AddRefs(serviceWorker));
-      break;
-    default:
-      MOZ_CRASH("Invalid enum value");
-  }
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return nullptr;
-  }
-
-  nsRefPtr<ServiceWorker> ref = static_cast<ServiceWorker*>(serviceWorker.get());
-  return ref.forget();
-}
-
 // Testing only.
 already_AddRefed<Promise>
 ServiceWorkerContainer::ClearAllServiceWorkerData(ErrorResult& aRv)
 {
   aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   return nullptr;
 }
 
@@ -266,11 +147,10 @@ ServiceWorkerContainer::GetScopeForUrl(c
 void
 ServiceWorkerContainer::GetControllingWorkerScriptURLForPath(
                                                         const nsAString& aPath,
                                                         nsString& aScriptURL,
                                                         ErrorResult& aRv)
 {
   aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 }
-} // namespace workers
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/ServiceWorkerContainer.h
+++ b/dom/workers/ServiceWorkerContainer.h
@@ -1,41 +1,38 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* 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/. */
 
-#ifndef mozilla_dom_workers_serviceworkercontainer_h__
-#define mozilla_dom_workers_serviceworkercontainer_h__
+#ifndef mozilla_dom_serviceworkercontainer_h__
+#define mozilla_dom_serviceworkercontainer_h__
 
 #include "mozilla/DOMEventTargetHelper.h"
 
-#include "ServiceWorkerManager.h"
-
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class Promise;
 struct RegistrationOptionList;
 
 namespace workers {
-
 class ServiceWorker;
+}
 
 // Lightweight serviceWorker APIs collection.
 class ServiceWorkerContainer MOZ_FINAL : public DOMEventTargetHelper
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
 
-  IMPL_EVENT_HANDLER(updatefound)
   IMPL_EVENT_HANDLER(controllerchange)
   IMPL_EVENT_HANDLER(reloadpage)
   IMPL_EVENT_HANDLER(error)
 
   explicit ServiceWorkerContainer(nsPIDOMWindow* aWindow);
 
   nsPIDOMWindow*
   GetParentObject() const
@@ -46,83 +43,49 @@ public:
   JSObject*
   WrapObject(JSContext* aCx);
 
   already_AddRefed<Promise>
   Register(const nsAString& aScriptURL,
            const RegistrationOptionList& aOptions,
            ErrorResult& aRv);
 
-  already_AddRefed<Promise>
-  Unregister(const nsAString& scope, ErrorResult& aRv);
-
-  already_AddRefed<ServiceWorker>
-  GetInstalling();
-
-  already_AddRefed<ServiceWorker>
-  GetWaiting();
-
-  already_AddRefed<ServiceWorker>
-  GetActive();
-
-  already_AddRefed<ServiceWorker>
+  already_AddRefed<workers::ServiceWorker>
   GetController();
 
   already_AddRefed<Promise>
-  GetAll(ErrorResult& aRv);
+  GetRegistration(const nsAString& aDocumentURL,
+                  ErrorResult& aRv);
+
+  already_AddRefed<Promise>
+  GetRegistrations(ErrorResult& aRv);
 
   already_AddRefed<Promise>
   GetReady(ErrorResult& aRv);
 
-  nsIURI*
-  GetDocumentURI() const
-  {
-    return mWindow->GetDocumentURI();
-  }
-
-  void
-  InvalidateWorkerReference(WhichServiceWorker aWhichOnes);
-
-  already_AddRefed<workers::ServiceWorker>
-  GetWorkerReference(WhichServiceWorker aWhichOne);
-
   // Testing only.
   already_AddRefed<Promise>
   ClearAllServiceWorkerData(ErrorResult& aRv);
 
   // Testing only.
   void
   GetScopeForUrl(const nsAString& aUrl, nsString& aScope, ErrorResult& aRv);
 
   // Testing only.
   void
   GetControllingWorkerScriptURLForPath(const nsAString& aPath,
                                        nsString& aScriptURL,
                                        ErrorResult& aRv);
 private:
   ~ServiceWorkerContainer();
 
-  void
-  StartListeningForEvents();
-
-  void
-  StopListeningForEvents();
-
   nsCOMPtr<nsPIDOMWindow> mWindow;
 
-  // The following properties are cached here to ensure JS equality is satisfied
-  // instead of acquiring a new worker instance from the ServiceWorkerManager
-  // for every access. A null value is considered a cache miss.
-  // These three may change to a new worker at any time.
-  nsRefPtr<ServiceWorker> mInstallingWorker;
-  nsRefPtr<ServiceWorker> mWaitingWorker;
-  nsRefPtr<ServiceWorker> mActiveWorker;
   // This only changes when a worker hijacks everything in its scope by calling
   // replace().
   // FIXME(nsm): Bug 982711. Provide API to let SWM invalidate this.
-  nsRefPtr<ServiceWorker> mControllerWorker;
+  nsRefPtr<workers::ServiceWorker> mControllerWorker;
 };
 
-} // namespace workers
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_workers_serviceworkercontainer_h__ */
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -19,29 +19,29 @@
 
 #include "nsContentUtils.h"
 #include "nsNetUtil.h"
 #include "nsProxyRelease.h"
 #include "nsTArray.h"
 
 #include "RuntimeService.h"
 #include "ServiceWorker.h"
-#include "ServiceWorkerContainer.h"
+#include "ServiceWorkerRegistration.h"
 #include "ServiceWorkerEvents.h"
 #include "WorkerInlines.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 BEGIN_WORKERS_NAMESPACE
 
-NS_IMPL_ISUPPORTS0(ServiceWorkerRegistration)
+NS_IMPL_ISUPPORTS0(ServiceWorkerRegistrationInfo)
 
 UpdatePromise::UpdatePromise()
   : mState(Pending)
 {
   MOZ_COUNT_CTOR(UpdatePromise);
 }
 
 UpdatePromise::~UpdatePromise()
@@ -75,44 +75,52 @@ UpdatePromise::ResolveAllPromises(const 
       MOZ_ASSERT(go);
 
       AutoSafeJSContext cx;
       JS::Rooted<JSObject*> global(cx, go->GetGlobalJSObject());
       JSAutoCompartment ac(cx, global);
 
       GlobalObject domGlobal(cx, global);
 
+      // The service worker is created and kept alive as a SharedWorker.
       nsRefPtr<ServiceWorker> serviceWorker;
       nsresult rv = rs->CreateServiceWorker(domGlobal,
                                             NS_ConvertUTF8toUTF16(aScriptSpec),
                                             aScope,
                                             getter_AddRefs(serviceWorker));
       if (NS_WARN_IF(NS_FAILED(rv))) {
         pendingPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
         continue;
       }
 
-      pendingPromise->MaybeResolve(serviceWorker);
+      // Since ServiceWorkerRegistration is only exposed to windows we can be
+      // certain about this cast.
+      nsCOMPtr<nsPIDOMWindow> window =
+        do_QueryInterface(pendingPromise->GetParentObject());
+      nsRefPtr<ServiceWorkerRegistration> swr =
+        new ServiceWorkerRegistration(window, NS_ConvertUTF8toUTF16(aScope));
+
+      pendingPromise->MaybeResolve(swr);
     }
   }
 }
 
 void
 UpdatePromise::RejectAllPromises(nsresult aRv)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(mState == Pending);
   mState = Rejected;
 
   nsTArray<WeakPtr<Promise>> array;
   array.SwapElements(mPromises);
   for (uint32_t i = 0; i < array.Length(); ++i) {
     WeakPtr<Promise>& pendingPromise = array.ElementAt(i);
     if (pendingPromise) {
-      // Since ServiceWorkerContainer is only exposed to windows we can be
+      // Since ServiceWorkerRegistration is only exposed to windows we can be
       // certain about this cast.
       nsCOMPtr<nsPIDOMWindow> window =
         do_QueryInterface(pendingPromise->GetParentObject());
       MOZ_ASSERT(window);
       nsRefPtr<DOMError> domError = new DOMError(window, aRv);
       pendingPromise->MaybeRejectBrokenly(domError);
     }
   }
@@ -124,17 +132,17 @@ UpdatePromise::RejectAllPromises(const E
   MOZ_ASSERT(mState == Pending);
   mState = Rejected;
 
   nsTArray<WeakPtr<Promise>> array;
   array.SwapElements(mPromises);
   for (uint32_t i = 0; i < array.Length(); ++i) {
     WeakPtr<Promise>& pendingPromise = array.ElementAt(i);
     if (pendingPromise) {
-      // Since ServiceWorkerContainer is only exposed to windows we can be
+      // Since ServiceWorkerRegistration is only exposed to windows we can be
       // certain about this cast.
       nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(pendingPromise->GetParentObject());
       MOZ_ASSERT(go);
 
       AutoJSAPI jsapi;
       jsapi.Init(go);
 
       JSContext* cx = jsapi.cx();
@@ -203,28 +211,28 @@ public:
 
 // Allows newer calls to Update() to 'abort' older calls.
 // Each call to Update() creates the instance which handles creating the
 // worker and queues up a runnable to resolve the update promise once the
 // worker has successfully been parsed.
 class ServiceWorkerUpdateInstance MOZ_FINAL : public nsISupports
 {
   // Owner of this instance.
-  ServiceWorkerRegistration* mRegistration;
+  ServiceWorkerRegistrationInfo* mRegistration;
   nsCString mScriptSpec;
   nsCOMPtr<nsPIDOMWindow> mWindow;
 
   bool mAborted;
 
   ~ServiceWorkerUpdateInstance() {}
 
 public:
   NS_DECL_ISUPPORTS
 
-  ServiceWorkerUpdateInstance(ServiceWorkerRegistration *aRegistration,
+  ServiceWorkerUpdateInstance(ServiceWorkerRegistrationInfo *aRegistration,
                               nsPIDOMWindow* aWindow)
     : mRegistration(aRegistration),
       // Capture the current script spec in case register() gets called.
       mScriptSpec(aRegistration->mScriptSpec),
       mWindow(aWindow),
       mAborted(false)
   {
     AssertIsOnMainThread();
@@ -292,23 +300,23 @@ NS_IMPL_ISUPPORTS0(ServiceWorkerUpdateIn
 NS_IMETHODIMP
 FinishFetchOnMainThreadRunnable::Run()
 {
   AssertIsOnMainThread();
   mUpdateInstance->FetchDone();
   return NS_OK;
 }
 
-ServiceWorkerRegistration::ServiceWorkerRegistration(const nsACString& aScope)
+ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(const nsACString& aScope)
   : mControlledDocumentsCounter(0),
     mScope(aScope),
     mPendingUninstall(false)
 { }
 
-ServiceWorkerRegistration::~ServiceWorkerRegistration()
+ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo()
 {
   MOZ_ASSERT(!IsControllingDocuments());
 }
 
 //////////////////////////
 // ServiceWorkerManager //
 //////////////////////////
 
@@ -334,17 +342,17 @@ ServiceWorkerManager::~ServiceWorkerMana
   mDomainMap.Clear();
 }
 
 /* static */ PLDHashOperator
 ServiceWorkerManager::CleanupServiceWorkerInformation(const nsACString& aDomain,
                                                       ServiceWorkerDomainInfo* aDomainInfo,
                                                       void *aUnused)
 {
-  aDomainInfo->mServiceWorkerRegistrations.Clear();
+  aDomainInfo->mServiceWorkerRegistrationInfos.Clear();
   return PL_DHASH_NEXT;
 }
 
 /*
  * Implements the async aspects of the register algorithm.
  */
 class RegisterRunnable : public nsRunnable
 {
@@ -371,17 +379,17 @@ public:
         mPromise->MaybeReject(rv);
         return NS_OK;
       }
 
       domainInfo = new ServiceWorkerManager::ServiceWorkerDomainInfo;
       swm->mDomainMap.Put(domain, domainInfo);
     }
 
-    nsRefPtr<ServiceWorkerRegistration> registration =
+    nsRefPtr<ServiceWorkerRegistrationInfo> registration =
       domainInfo->GetRegistration(mScope);
 
     nsCString spec;
     nsresult rv = mScriptURI->GetSpec(spec);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       mPromise->MaybeReject(rv);
       return NS_OK;
     }
@@ -407,17 +415,21 @@ public:
                                               info->GetScriptSpec(),
                                               registration->mScope,
                                               getter_AddRefs(serviceWorker));
 
           if (NS_WARN_IF(NS_FAILED(rv))) {
             return NS_ERROR_FAILURE;
           }
 
-          mPromise->MaybeResolve(serviceWorker);
+          nsRefPtr<ServiceWorkerRegistration> swr =
+            new ServiceWorkerRegistration(mWindow,
+                                          NS_ConvertUTF8toUTF16(registration->mScope));
+
+          mPromise->MaybeResolve(swr);
           return NS_OK;
         }
       }
     } else {
       registration = domainInfo->CreateNewRegistration(mScope);
     }
 
     registration->mScriptSpec = spec;
@@ -523,41 +535,41 @@ ServiceWorkerManager::Register(nsIDOMWin
 
   nsRefPtr<nsIRunnable> registerRunnable =
     new RegisterRunnable(window, cleanedScope, scriptURI, promise);
   promise.forget(aPromise);
   return NS_DispatchToCurrentThread(registerRunnable);
 }
 
 void
-ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistration* aRegistration,
+ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistrationInfo* aRegistration,
                                                    nsresult aRv)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aRegistration->HasUpdatePromise());
   aRegistration->mUpdatePromise->RejectAllPromises(aRv);
   aRegistration->mUpdatePromise = nullptr;
 }
 
 void
-ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistration* aRegistration,
+ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistrationInfo* aRegistration,
                                                    const ErrorEventInit& aErrorDesc)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aRegistration->HasUpdatePromise());
   aRegistration->mUpdatePromise->RejectAllPromises(aErrorDesc);
   aRegistration->mUpdatePromise = nullptr;
 }
 
 /*
  * Update() does not return the Promise that the spec says it should. Callers
  * may access the registration's (new) Promise after calling this method.
  */
 NS_IMETHODIMP
-ServiceWorkerManager::Update(ServiceWorkerRegistration* aRegistration,
+ServiceWorkerManager::Update(ServiceWorkerRegistrationInfo* aRegistration,
                              nsPIDOMWindow* aWindow)
 {
   if (aRegistration->HasUpdatePromise()) {
     NS_WARNING("Already had a UpdatePromise. Aborting that one!");
     RejectUpdatePromiseObservers(aRegistration, NS_ERROR_DOM_ABORT_ERR);
     MOZ_ASSERT(aRegistration->mUpdateInstance);
     aRegistration->mUpdateInstance->Abort();
     aRegistration->mUpdateInstance = nullptr;
@@ -566,33 +578,33 @@ ServiceWorkerManager::Update(ServiceWork
   if (aRegistration->mInstallingWorker) {
     // FIXME(nsm): Terminate the worker. We still haven't figured out worker
     // instance ownership when not associated with a window, so let's wait on
     // this.
     // FIXME(nsm): We should be setting the state on the actual worker
     // instance.
     // FIXME(nsm): Fire "statechange" on installing worker instance.
     aRegistration->mInstallingWorker = nullptr;
-    InvalidateServiceWorkerContainerWorker(aRegistration,
-                                           WhichServiceWorker::INSTALLING_WORKER);
+    InvalidateServiceWorkerRegistrationWorker(aRegistration,
+                                              WhichServiceWorker::INSTALLING_WORKER);
   }
 
   aRegistration->mUpdatePromise = new UpdatePromise();
   // FIXME(nsm): Bug 931249. If we don't need to fetch & install, resolve
   // promise and skip this.
   // FIXME(nsm): Bug 931249. Force cache update if > 1 day.
 
   aRegistration->mUpdateInstance =
     new ServiceWorkerUpdateInstance(aRegistration, aWindow);
   aRegistration->mUpdateInstance->Update();
 
   return NS_OK;
 }
 
-// If we return an error, ServiceWorkerContainer will reject the Promise.
+// If we return an error, ServiceWorkerREgistration will reject the Promise.
 NS_IMETHODIMP
 ServiceWorkerManager::Unregister(nsIDOMWindow* aWindow, const nsAString& aScope,
                                  nsISupports** aPromise)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
 
   // XXXnsm Don't allow chrome callers for now.
@@ -608,34 +620,34 @@ already_AddRefed<ServiceWorkerManager>
 ServiceWorkerManager::GetInstance()
 {
   nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
   nsRefPtr<ServiceWorkerManager> concrete = do_QueryObject(swm);
   return concrete.forget();
 }
 
 void
-ServiceWorkerManager::ResolveRegisterPromises(ServiceWorkerRegistration* aRegistration,
+ServiceWorkerManager::ResolveRegisterPromises(ServiceWorkerRegistrationInfo* aRegistration,
                                               const nsACString& aWorkerScriptSpec)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aRegistration->HasUpdatePromise());
   if (aRegistration->mUpdatePromise->IsRejected()) {
     aRegistration->mUpdatePromise = nullptr;
     return;
   }
 
   aRegistration->mUpdatePromise->ResolveAllPromises(aWorkerScriptSpec,
                                                     aRegistration->mScope);
   aRegistration->mUpdatePromise = nullptr;
 }
 
 // Must NS_Free() aString
 void
-ServiceWorkerManager::FinishFetch(ServiceWorkerRegistration* aRegistration,
+ServiceWorkerManager::FinishFetch(ServiceWorkerRegistrationInfo* aRegistration,
                                   nsPIDOMWindow* aWindow)
 {
   AssertIsOnMainThread();
 
   MOZ_ASSERT(aRegistration->HasUpdatePromise());
   MOZ_ASSERT(aRegistration->mUpdateInstance);
   aRegistration->mUpdateInstance = nullptr;
   if (aRegistration->mUpdatePromise->IsRejected()) {
@@ -683,17 +695,17 @@ ServiceWorkerManager::HandleError(JSCont
 
   nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(uri);
   if (!domainInfo) {
     return;
   }
 
   nsCString scope;
   scope.Assign(aScope);
-  nsRefPtr<ServiceWorkerRegistration> registration = domainInfo->GetRegistration(scope);
+  nsRefPtr<ServiceWorkerRegistrationInfo> registration = domainInfo->GetRegistration(scope);
   MOZ_ASSERT(registration);
 
   RootedDictionary<ErrorEventInit> init(aCx);
   init.mMessage = aMessage;
   init.mFilename = aFilename;
   init.mLineno = aLineNumber;
   init.mColno = aColumnNumber;
 
@@ -712,21 +724,21 @@ ServiceWorkerManager::HandleError(JSCont
     registration->mUpdateInstance = nullptr;
   } else {
     // FIXME(nsm): Bug 983497 Fire 'error' on ServiceWorkerContainers.
   }
 }
 
 class FinishInstallRunnable MOZ_FINAL : public nsRunnable
 {
-  nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
+  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
 
 public:
   explicit FinishInstallRunnable(
-    const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
+    const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
     : mRegistration(aRegistration)
   {
     MOZ_ASSERT(!NS_IsMainThread());
   }
 
   NS_IMETHOD
   Run() MOZ_OVERRIDE
   {
@@ -735,20 +747,20 @@ public:
     nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     swm->FinishInstall(mRegistration.get());
     return NS_OK;
   }
 };
 
 class FinishActivationRunnable : public nsRunnable
 {
-  nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
+  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
 
 public:
-  FinishActivationRunnable(const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
+  FinishActivationRunnable(const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
     : mRegistration(aRegistration)
   {
     MOZ_ASSERT(!NS_IsMainThread());
   }
 
   NS_IMETHODIMP
   Run()
   {
@@ -758,53 +770,53 @@ public:
     nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     swm->FinishActivate(mRegistration.get());
     return NS_OK;
   }
 };
 
 class CancelServiceWorkerInstallationRunnable MOZ_FINAL : public nsRunnable
 {
-  nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
+  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
 
 public:
   explicit CancelServiceWorkerInstallationRunnable(
-    const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
+    const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
     : mRegistration(aRegistration)
   {
   }
 
   NS_IMETHOD
   Run() MOZ_OVERRIDE
   {
     AssertIsOnMainThread();
     // FIXME(nsm): Change installing worker state to redundant.
     // FIXME(nsm): Fire statechange.
     mRegistration->mInstallingWorker = nullptr;
     nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    swm->InvalidateServiceWorkerContainerWorker(mRegistration,
-                                                WhichServiceWorker::INSTALLING_WORKER);
+    swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
+                                                   WhichServiceWorker::INSTALLING_WORKER);
     return NS_OK;
   }
 };
 
 /*
  * Used to handle InstallEvent::waitUntil() and proceed with installation.
  */
 class FinishInstallHandler MOZ_FINAL : public PromiseNativeHandler
 {
-  nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
+  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
 
   virtual
   ~FinishInstallHandler()
   { }
 
 public:
   explicit FinishInstallHandler(
-    const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
+    const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
     : mRegistration(aRegistration)
   {
     MOZ_ASSERT(!NS_IsMainThread());
   }
 
   void
   ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
   {
@@ -822,20 +834,20 @@ public:
     nsRefPtr<CancelServiceWorkerInstallationRunnable> r =
       new CancelServiceWorkerInstallationRunnable(mRegistration);
     NS_DispatchToMainThread(r);
   }
 };
 
 class FinishActivateHandler : public PromiseNativeHandler
 {
-  nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
+  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
 
 public:
-  FinishActivateHandler(const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
+  FinishActivateHandler(const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
     : mRegistration(aRegistration)
   {
     MOZ_ASSERT(!NS_IsMainThread());
   }
 
   virtual
   ~FinishActivateHandler()
   { }
@@ -861,23 +873,23 @@ public:
 /*
  * Fires 'install' event on the ServiceWorkerGlobalScope. Modifies busy count
  * since it fires the event. This is ok since there can't be nested
  * ServiceWorkers, so the parent thread -> worker thread requirement for
  * runnables is satisfied.
  */
 class InstallEventRunnable MOZ_FINAL : public WorkerRunnable
 {
-  nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
+  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
   nsCString mScope;
 
 public:
   InstallEventRunnable(
     WorkerPrivate* aWorkerPrivate,
-    const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
+    const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
       : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
         mRegistration(aRegistration),
         mScope(aRegistration.get()->mScope) // copied for access on worker thread.
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(aWorkerPrivate);
   }
 
@@ -930,21 +942,21 @@ private:
       new FinishInstallHandler(mRegistration);
     waitUntilPromise->AppendNativeHandler(handler);
     return true;
   }
 };
 
 class ActivateEventRunnable : public WorkerRunnable
 {
-  nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
+  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
 
 public:
   ActivateEventRunnable(WorkerPrivate* aWorkerPrivate,
-                        const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
+                        const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
       : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
         mRegistration(aRegistration)
   {
     MOZ_ASSERT(aWorkerPrivate);
   }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
@@ -993,27 +1005,27 @@ private:
 
     nsRefPtr<FinishActivateHandler> handler = new FinishActivateHandler(mRegistration);
     waitUntilPromise->AppendNativeHandler(handler);
     return true;
   }
 };
 
 void
-ServiceWorkerManager::Install(ServiceWorkerRegistration* aRegistration,
+ServiceWorkerManager::Install(ServiceWorkerRegistrationInfo* aRegistration,
                               ServiceWorkerInfo* aServiceWorkerInfo)
 {
   AssertIsOnMainThread();
   aRegistration->mInstallingWorker = aServiceWorkerInfo;
   MOZ_ASSERT(aRegistration->mInstallingWorker);
-  InvalidateServiceWorkerContainerWorker(aRegistration,
-                                         WhichServiceWorker::INSTALLING_WORKER);
+  InvalidateServiceWorkerRegistrationWorker(aRegistration,
+                                            WhichServiceWorker::INSTALLING_WORKER);
 
-  nsMainThreadPtrHandle<ServiceWorkerRegistration> handle(
-    new nsMainThreadPtrHolder<ServiceWorkerRegistration>(aRegistration));
+  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> handle(
+    new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(aRegistration));
 
   nsRefPtr<ServiceWorker> serviceWorker;
   nsresult rv =
     CreateServiceWorker(aServiceWorkerInfo->GetScriptSpec(),
                         aRegistration->mScope,
                         getter_AddRefs(serviceWorker));
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -1037,74 +1049,74 @@ ServiceWorkerManager::Install(ServiceWor
   // the event dispatch. On the other hand, networking, IDB and so on do keep
   // the worker alive, so the waitUntil() is only relevant if the Promise is
   // gated on those actions. I (nsm) am not sure if it is worth requiring
   // a special spec mention saying the install event should keep the worker
   // alive indefinitely purely on the basis of calling waitUntil(), since
   // a wait is likely to be required only when performing networking or storage
   // transactions in the first place.
 
-  FireEventOnServiceWorkerContainers(aRegistration,
-                                     NS_LITERAL_STRING("updatefound"));
+  FireEventOnServiceWorkerRegistrations(aRegistration,
+                                        NS_LITERAL_STRING("updatefound"));
 }
 
 class ActivationRunnable : public nsRunnable
 {
-  nsRefPtr<ServiceWorkerRegistration> mRegistration;
+  nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
 public:
-  explicit ActivationRunnable(ServiceWorkerRegistration* aRegistration)
+  explicit ActivationRunnable(ServiceWorkerRegistrationInfo* aRegistration)
     : mRegistration(aRegistration)
   {
   }
 
   NS_IMETHODIMP
   Run() MOZ_OVERRIDE
   {
     if (mRegistration->mCurrentWorker) {
       // FIXME(nsm). Steps 3.1-3.4 of the algorithm.
     }
 
     mRegistration->mCurrentWorker = mRegistration->mWaitingWorker.forget();
 
     nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    swm->InvalidateServiceWorkerContainerWorker(mRegistration,
-                                                WhichServiceWorker::ACTIVE_WORKER | WhichServiceWorker::WAITING_WORKER);
+    swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
+                                                   WhichServiceWorker::ACTIVE_WORKER | WhichServiceWorker::WAITING_WORKER);
 
     // FIXME(nsm): Steps 7 of the algorithm.
 
-    swm->FireEventOnServiceWorkerContainers(mRegistration,
-                                            NS_LITERAL_STRING("controllerchange"));
+    swm->FireEventOnServiceWorkerRegistrations(mRegistration,
+                                               NS_LITERAL_STRING("controllerchange"));
 
     MOZ_ASSERT(mRegistration->mCurrentWorker);
     nsRefPtr<ServiceWorker> serviceWorker;
     nsresult rv =
       swm->CreateServiceWorker(mRegistration->mCurrentWorker->GetScriptSpec(),
                                mRegistration->mScope,
                                getter_AddRefs(serviceWorker));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    nsMainThreadPtrHandle<ServiceWorkerRegistration> handle(
-      new nsMainThreadPtrHolder<ServiceWorkerRegistration>(mRegistration));
+    nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> handle(
+      new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(mRegistration));
 
     nsRefPtr<ActivateEventRunnable> r =
       new ActivateEventRunnable(serviceWorker->GetWorkerPrivate(), handle);
 
     AutoSafeJSContext cx;
     if (!r->Dispatch(cx)) {
       return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
   }
 };
 
 void
-ServiceWorkerManager::FinishInstall(ServiceWorkerRegistration* aRegistration)
+ServiceWorkerManager::FinishInstall(ServiceWorkerRegistrationInfo* aRegistration)
 {
   AssertIsOnMainThread();
 
   if (aRegistration->mWaitingWorker) {
     // FIXME(nsm): Actually update the state of active ServiceWorker instances.
   }
 
   if (!aRegistration->mInstallingWorker) {
@@ -1113,18 +1125,18 @@ ServiceWorkerManager::FinishInstall(Serv
     // a different script leading to [[Update]] terminating the
     // installingWorker and setting it to null. The FinishInstallRunnable may
     // already have been dispatched, hence the check.
     return;
   }
 
   aRegistration->mWaitingWorker = aRegistration->mInstallingWorker.forget();
   MOZ_ASSERT(aRegistration->mWaitingWorker);
-  InvalidateServiceWorkerContainerWorker(aRegistration,
-                                         WhichServiceWorker::WAITING_WORKER | WhichServiceWorker::INSTALLING_WORKER);
+  InvalidateServiceWorkerRegistrationWorker(aRegistration,
+                                            WhichServiceWorker::WAITING_WORKER | WhichServiceWorker::INSTALLING_WORKER);
 
   // FIXME(nsm): Actually update state of active ServiceWorker instances to
   // installed.
   // FIXME(nsm): Fire statechange on the instances.
 
   // FIXME(nsm): Handle replace().
 
   if (!aRegistration->IsControllingDocuments()) {
@@ -1135,17 +1147,17 @@ ServiceWorkerManager::FinishInstall(Serv
     if (NS_WARN_IF(NS_FAILED(rv))) {
       // FIXME(nsm): Handle error.
       // How likely is this to happen and can we really do anything about it?
     }
   }
 }
 
 void
-ServiceWorkerManager::FinishActivate(ServiceWorkerRegistration* aRegistration)
+ServiceWorkerManager::FinishActivate(ServiceWorkerRegistrationInfo* aRegistration)
 {
   // FIXME(nsm): Set aRegistration->mCurrentWorker state to activated.
   // Fire statechange.
 }
 
 NS_IMETHODIMP
 ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
                                                    const nsACString& aScriptSpec,
@@ -1173,32 +1185,32 @@ ServiceWorkerManager::CreateServiceWorke
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   serviceWorker.forget(aServiceWorker);
   return rv;
 }
 
-already_AddRefed<ServiceWorkerRegistration>
-ServiceWorkerManager::GetServiceWorkerRegistration(nsPIDOMWindow* aWindow)
+already_AddRefed<ServiceWorkerRegistrationInfo>
+ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsPIDOMWindow* aWindow)
 {
   nsCOMPtr<nsIDocument> document = aWindow->GetExtantDoc();
-  return GetServiceWorkerRegistration(document);
+  return GetServiceWorkerRegistrationInfo(document);
 }
 
-already_AddRefed<ServiceWorkerRegistration>
-ServiceWorkerManager::GetServiceWorkerRegistration(nsIDocument* aDoc)
+already_AddRefed<ServiceWorkerRegistrationInfo>
+ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsIDocument* aDoc)
 {
   nsCOMPtr<nsIURI> documentURI = aDoc->GetDocumentURI();
-  return GetServiceWorkerRegistration(documentURI);
+  return GetServiceWorkerRegistrationInfo(documentURI);
 }
 
-already_AddRefed<ServiceWorkerRegistration>
-ServiceWorkerManager::GetServiceWorkerRegistration(nsIURI* aURI)
+already_AddRefed<ServiceWorkerRegistrationInfo>
+ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsIURI* aURI)
 {
   nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aURI);
   if (!domainInfo) {
     return nullptr;
   }
 
   nsCString spec;
   nsresult rv = aURI->GetSpec(spec);
@@ -1206,18 +1218,18 @@ ServiceWorkerManager::GetServiceWorkerRe
     return nullptr;
   }
 
   nsCString scope = FindScopeForPath(domainInfo->mOrderedScopes, spec);
   if (scope.IsEmpty()) {
     return nullptr;
   }
 
-  nsRefPtr<ServiceWorkerRegistration> registration;
-  domainInfo->mServiceWorkerRegistrations.Get(scope, getter_AddRefs(registration));
+  nsRefPtr<ServiceWorkerRegistrationInfo> registration;
+  domainInfo->mServiceWorkerRegistrationInfos.Get(scope, getter_AddRefs(registration));
   // ordered scopes and registrations better be in sync.
   MOZ_ASSERT(registration);
 
   return registration.forget();
 }
 
 namespace {
 /*
@@ -1352,18 +1364,18 @@ ServiceWorkerManager::MaybeStartControll
     return;
   }
 
   nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDoc);
   if (!domainInfo) {
     return;
   }
 
-  nsRefPtr<ServiceWorkerRegistration> registration =
-    GetServiceWorkerRegistration(aDoc);
+  nsRefPtr<ServiceWorkerRegistrationInfo> registration =
+    GetServiceWorkerRegistrationInfo(aDoc);
   if (registration && registration->mCurrentWorker) {
     MOZ_ASSERT(!domainInfo->mControlledDocuments.Contains(aDoc));
     registration->StartControllingADocument();
     // Use the already_AddRefed<> form of Put to avoid the addref-deref since
     // we don't need the registration pointer in this function anymore.
     domainInfo->mControlledDocuments.Put(aDoc, registration.forget());
   }
 }
@@ -1376,17 +1388,17 @@ ServiceWorkerManager::MaybeStopControlli
     return;
   }
 
   nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDoc);
   if (!domainInfo) {
     return;
   }
 
-  nsRefPtr<ServiceWorkerRegistration> registration;
+  nsRefPtr<ServiceWorkerRegistrationInfo> registration;
   domainInfo->mControlledDocuments.Remove(aDoc, getter_AddRefs(registration));
   // A document which was uncontrolled does not maintain that state itself, so
   // it will always call MaybeStopControlling() even if there isn't an
   // associated registration. So this check is required.
   if (registration) {
     registration->StopControllingADocument();
   }
 }
@@ -1395,75 +1407,76 @@ NS_IMETHODIMP
 ServiceWorkerManager::GetScopeForUrl(const nsAString& aUrl, nsAString& aScope)
 {
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_NewURI(getter_AddRefs(uri), aUrl, nullptr, nullptr);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return NS_ERROR_FAILURE;
   }
 
-  nsRefPtr<ServiceWorkerRegistration> r = GetServiceWorkerRegistration(uri);
+  nsRefPtr<ServiceWorkerRegistrationInfo> r = GetServiceWorkerRegistrationInfo(uri);
   if (!r) {
       return NS_ERROR_FAILURE;
   }
 
   aScope = NS_ConvertUTF8toUTF16(r->mScope);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-ServiceWorkerManager::AddContainerEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
+ServiceWorkerManager::AddRegistrationEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
 {
   MOZ_ASSERT(aDocumentURI);
   nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDocumentURI);
   if (!domainInfo) {
     nsCString domain;
     nsresult rv = aDocumentURI->GetHost(domain);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     domainInfo = new ServiceWorkerDomainInfo;
     mDomainMap.Put(domain, domainInfo);
   }
 
   MOZ_ASSERT(domainInfo);
 
-  ServiceWorkerContainer* container = static_cast<ServiceWorkerContainer*>(aListener);
-  domainInfo->mServiceWorkerContainers.AppendElement(container);
+  // TODO: this is very very bad:
+  ServiceWorkerRegistration* registration = static_cast<ServiceWorkerRegistration*>(aListener);
+  domainInfo->mServiceWorkerRegistrations.AppendElement(registration);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-ServiceWorkerManager::RemoveContainerEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
+ServiceWorkerManager::RemoveRegistrationEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
 {
   MOZ_ASSERT(aDocumentURI);
   nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDocumentURI);
   if (!domainInfo) {
     return NS_OK;
   }
 
-  ServiceWorkerContainer* container = static_cast<ServiceWorkerContainer*>(aListener);
-  domainInfo->mServiceWorkerContainers.RemoveElement(container);
+  ServiceWorkerRegistration* registration = static_cast<ServiceWorkerRegistration*>(aListener);
+  domainInfo->mServiceWorkerRegistrations.RemoveElement(registration);
   return NS_OK;
 }
 
 void
-ServiceWorkerManager::FireEventOnServiceWorkerContainers(
-  ServiceWorkerRegistration* aRegistration,
+ServiceWorkerManager::FireEventOnServiceWorkerRegistrations(
+  ServiceWorkerRegistrationInfo* aRegistration,
   const nsAString& aName)
 {
   AssertIsOnMainThread();
   nsRefPtr<ServiceWorkerDomainInfo> domainInfo =
     GetDomainInfo(aRegistration->mScriptSpec);
 
   if (domainInfo) {
-    nsTObserverArray<ServiceWorkerContainer*>::ForwardIterator it(domainInfo->mServiceWorkerContainers);
+    nsTObserverArray<ServiceWorkerRegistration*>::ForwardIterator it(domainInfo->mServiceWorkerRegistrations);
     while (it.HasMore()) {
-      nsRefPtr<ServiceWorkerContainer> target = it.GetNext();
+      nsRefPtr<ServiceWorkerRegistration> target = it.GetNext();
       nsIURI* targetURI = target->GetDocumentURI();
       if (!targetURI) {
         NS_WARNING("Controlled domain cannot have page with null URI!");
         continue;
       }
 
       nsCString path;
       nsresult rv = targetURI->GetSpec(path);
@@ -1489,18 +1502,18 @@ ServiceWorkerManager::FireEventOnService
 NS_IMETHODIMP
 ServiceWorkerManager::GetServiceWorkerForWindow(nsIDOMWindow* aWindow,
                                                 WhichServiceWorker aWhichWorker,
                                                 nsISupports** aServiceWorker)
 {
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
   MOZ_ASSERT(window);
 
-  nsRefPtr<ServiceWorkerRegistration> registration =
-    GetServiceWorkerRegistration(window);
+  nsRefPtr<ServiceWorkerRegistrationInfo> registration =
+    GetServiceWorkerRegistrationInfo(window);
 
   if (!registration) {
     return NS_ERROR_FAILURE;
   }
 
   nsRefPtr<ServiceWorkerInfo> info;
   if (aWhichWorker == WhichServiceWorker::INSTALLING_WORKER) {
     info = registration->mInstallingWorker;
@@ -1544,17 +1557,17 @@ ServiceWorkerManager::GetDocumentControl
 
   nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
 
   nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(doc);
   if (!domainInfo) {
     return NS_ERROR_FAILURE;
   }
 
-  nsRefPtr<ServiceWorkerRegistration> registration;
+  nsRefPtr<ServiceWorkerRegistrationInfo> registration;
   if (!domainInfo->mControlledDocuments.Get(doc, getter_AddRefs(registration))) {
     return NS_ERROR_FAILURE;
   }
 
   // If the document is controlled, the current worker MUST be non-null.
   MOZ_ASSERT(registration->mCurrentWorker);
 
   nsRefPtr<ServiceWorker> serviceWorker;
@@ -1610,17 +1623,17 @@ ServiceWorkerManager::CreateServiceWorke
 
   rv = info.mBaseURI->GetHost(info.mDomain);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // FIXME(nsm): Create correct principal based on app-ness.
   // Would it make sense to store the nsIPrincipal of the first register() in
-  // the ServiceWorkerRegistration and use that?
+  // the ServiceWorkerRegistrationInfo and use that?
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   rv = ssm->GetNoAppCodebasePrincipal(info.mBaseURI, getter_AddRefs(info.mPrincipal));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   AutoSafeJSContext cx;
 
@@ -1637,27 +1650,27 @@ ServiceWorkerManager::CreateServiceWorke
     return rv;
   }
 
   serviceWorker.forget(aServiceWorker);
   return NS_OK;
 }
 
 void
-ServiceWorkerManager::InvalidateServiceWorkerContainerWorker(ServiceWorkerRegistration* aRegistration,
-                                                             WhichServiceWorker aWhichOnes)
+ServiceWorkerManager::InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration,
+                                                                WhichServiceWorker aWhichOnes)
 {
   AssertIsOnMainThread();
   nsRefPtr<ServiceWorkerDomainInfo> domainInfo =
     GetDomainInfo(aRegistration->mScriptSpec);
 
   if (domainInfo) {
-    nsTObserverArray<ServiceWorkerContainer*>::ForwardIterator it(domainInfo->mServiceWorkerContainers);
+    nsTObserverArray<ServiceWorkerRegistration*>::ForwardIterator it(domainInfo->mServiceWorkerRegistrations);
     while (it.HasMore()) {
-      nsRefPtr<ServiceWorkerContainer> target = it.GetNext();
+      nsRefPtr<ServiceWorkerRegistration> target = it.GetNext();
 
       nsIURI* targetURI = target->GetDocumentURI();
       nsCString path;
       nsresult rv = targetURI->GetSpec(path);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         continue;
       }
 
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -11,28 +11,31 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/LinkedList.h"