Merge m-c to fx-team.
authorRyan VanderMeulen <ryanvm@gmail.com>
Sat, 14 Sep 2013 23:08:59 -0400
changeset 160164 8a08b73e7616202f0b3f1471d5aa10fa2eb430eb
parent 160163 986c3e80530c24ee9d1fc64e3234db4418bc1fcf (current diff)
parent 160159 9366ee0396451492b3097fbb499b20fc5c63b82b (diff)
child 160165 2bdc2ba16e56b208e2e3c10782181585db58b024
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team.
dom/interfaces/events/nsIDOMDeviceLightEvent.idl
dom/interfaces/events/nsIDOMUserProximityEvent.idl
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -548,16 +548,17 @@ pref("media.omx.enabled", true);
 // Disable printing (particularly, window.print())
 pref("dom.disable_window_print", true);
 
 // Disable window.showModalDialog
 pref("dom.disable_window_showModalDialog", true);
 
 // Enable new experimental html forms
 pref("dom.experimental_forms", true);
+pref("dom.forms.number", true);
 
 // Turns on gralloc-based direct texturing for Gonk
 pref("gfx.gralloc.enabled", false);
 
 // XXXX REMOVE FOR PRODUCTION. Turns on GC and CC logging
 pref("javascript.options.mem.log", false);
 
 // Increase mark slice time from 10ms to 30ms
@@ -772,8 +773,11 @@ pref("b2g.adb.timeout-hours", 12);
 // Absolute path to the devtool unix domain socket file used
 // to communicate with a usb cable via adb forward
 pref("devtools.debugger.unix-domain-socket", "/data/local/debugger-socket");
 
 // enable Skia/GL (OpenGL-accelerated 2D drawing) for large enough 2d canvases,
 // falling back to Skia/software for smaller canvases
 pref("gfx.canvas.azure.backends", "skia");
 pref("gfx.canvas.azure.accelerated", true);
+
+// Enable Telephony API
+pref("dom.telephony.enabled", true);
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1378508419000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1379114379000">
   <emItems>
       <emItem  blockID="i350" id="sqlmoz@facebook.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
@@ -14,16 +14,20 @@
                     </versionRange>
                                 <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i71" id="youtube@2youtube.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i404" id="{a9bb9fa0-4122-4c75-bd9a-bc27db3f9155}">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i8" id="{B13721C7-F507-4982-B2E5-502A71474FED}">
                         <versionRange  minVersion=" " severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i107" os="WINNT" id="{ABDE892B-13A8-4d1b-88E6-365A6E755758}">
                         <versionRange  minVersion="0" maxVersion="15.0.5" severity="1">
                     </versionRange>
                   </emItem>
@@ -211,18 +215,18 @@
       <emItem  blockID="i39" id="{c2d64ff7-0ab8-4263-89c9-ea3b0f8f050c}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i42" id="{D19CA586-DD6C-4a0a-96F8-14644F340D60}">
                         <versionRange  minVersion="0.1" maxVersion="14.4.0" severity="1">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i93" id="{68b8676b-99a5-46d1-b390-22411d8bcd61}">
-                        <versionRange  minVersion="0" maxVersion="*">
+      <emItem  blockID="i449" id="gystqfr@ylgga.com">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i142" id="{a3a5c777-f583-4fef-9380-ab4add1bc2a8}">
                         <versionRange  minVersion="2.0.3" maxVersion="2.0.3">
                     </versionRange>
                                 <versionRange  minVersion="4.2" maxVersion="4.2" severity="3">
                     </versionRange>
                   </emItem>
@@ -420,17 +424,17 @@
       <emItem  blockID="i344" id="lrcsTube@hansanddeta.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i426" id="addlyrics@addlyrics.net">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
-      <emItem  blockID="i404" id="{a9bb9fa0-4122-4c75-bd9a-bc27db3f9155}">
+      <emItem  blockID="i448" id="{0134af61-7a0c-4649-aeca-90d776060cb3}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i83" id="flash@adobee.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i218" id="ffxtlbr@claro.com">
@@ -597,16 +601,20 @@
       <emItem  blockID="i167" id="{b64982b1-d112-42b5-b1e4-d3867c4533f8}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i101" id="{3a12052a-66ef-49db-8c39-e5b0bd5c83fa}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i93" id="{68b8676b-99a5-46d1-b390-22411d8bcd61}">
+                        <versionRange  minVersion="0" maxVersion="*">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i439" id="{d2cf9842-af95-48cd-b873-bfbb48cd7f5e}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i346" id="{a6e67e6f-8615-4fe0-a599-34a73fc3fba5}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -163,18 +163,24 @@ let AboutHomeListener = {
       case "settings":
         sendAsyncMessage("AboutHome:Settings");
         break;
     }
   },
 };
 AboutHomeListener.init(this);
 
+var global = this;
 
-var global = this;
+// Lazily load the finder code
+addMessageListener("Finder:Initialize", function () {
+  let {RemoteFinderListener} = Cu.import("resource://gre/modules/RemoteFinder.jsm", {});
+  new RemoteFinderListener(global);
+});
+
 
 let ClickEventHandler = {
   init: function init() {
     Cc["@mozilla.org/eventlistenerservice;1"]
       .getService(Ci.nsIEventListenerService)
       .addSystemEventListener(global, "click", this, true);
   },
 
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -60,28 +60,28 @@ function getBrowserForWindowId(aWindowID
 function getBrowserForWindow(aContentWindow) {
   return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIWebNavigation)
                        .QueryInterface(Ci.nsIDocShell)
                        .chromeEventHandler;
 }
 
 function handleRequest(aSubject, aTopic, aData) {
-  let {windowID: windowID, callID: callID} = JSON.parse(aData);
-
-  let params = aSubject.QueryInterface(Ci.nsIMediaStreamOptions);
+  let constraints = aSubject.getConstraints();
 
   Services.wm.getMostRecentWindow(null).navigator.mozGetUserMediaDevices(
+    constraints,
     function (devices) {
-      prompt(windowID, callID, params.audio, params.video || params.picture, devices);
+      prompt(aSubject.windowID, aSubject.callID, constraints.audio,
+             constraints.video || constraints.picture, devices);
     },
     function (error) {
       // bug 827146 -- In the future, the UI should catch NO_DEVICES_FOUND
       // and allow the user to plug in a device, instead of immediately failing.
-      denyRequest(callID, error);
+      denyRequest(aSubject.callID, error);
     }
   );
 }
 
 function denyRequest(aCallID, aError) {
   let msg = null;
   if (aError) {
     msg = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
--- a/build/pgo/index.html
+++ b/build/pgo/index.html
@@ -1,123 +1,13 @@
 <script>
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-   
- function quitHook()
- {
-   var xhr = new XMLHttpRequest();
-   xhr.open("GET", "http://" + location.host + "/server/shutdown", true);
-   xhr.onreadystatechange = function (event)
-     {
-       if (xhr.readyState == 4)
-         goQuitApplication();
-     };
-   xhr.send(null);
- }
-  
- function canQuitApplication()
- {
-   var os = Components.classes["@mozilla.org/observer-service;1"]
-     .getService(Components.interfaces.nsIObserverService);
-   if (!os) 
-   {
-     return true;
-   }
-   
-   try 
-   {
-     var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
-       .createInstance(Components.interfaces.nsISupportsPRBool);
-     os.notifyObservers(cancelQuit, "quit-application-requested", null);
-     
-     // Something aborted the quit process. 
-     if (cancelQuit.data)
-     {
-       return false;
-     }
-   }
-   catch (ex) 
-   {
-   }
-   os.notifyObservers(null, "quit-application-granted", null);
-   return true;
- }
- 
- function goQuitApplication()
- {
-   const privs = 'UniversalXPConnect';
- 
-   try
-   {
-     netscape.security.PrivilegeManager.enablePrivilege(privs);
-   }
-   catch(ex)
-   {
-     throw('goQuitApplication: privilege failure ' + ex);
-   }
- 
-   if (!canQuitApplication())
-   {
-     return false;
-   }
- 
-   const kAppStartup = '@mozilla.org/toolkit/app-startup;1';
-   const kAppShell   = '@mozilla.org/appshell/appShellService;1';
-   var   appService;
-   var   forceQuit;
- 
-   if (kAppStartup in Components.classes)
-   {
-     appService = Components.classes[kAppStartup].
-       getService(Components.interfaces.nsIAppStartup);
-     forceQuit  = Components.interfaces.nsIAppStartup.eForceQuit;
- 
-   }
-   else if (kAppShell in Components.classes)
-   {
-     appService = Components.classes[kAppShell].
-       getService(Components.interfaces.nsIAppShellService);
-     forceQuit = Components.interfaces.nsIAppShellService.eForceQuit;
-   }
-   else
-   {
-     throw 'goQuitApplication: no AppStartup/appShell';
-   }
- 
-   var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService();
- 
-   var windowManagerInterface = windowManager.
-     QueryInterface(Components.interfaces.nsIWindowMediator);
- 
-   var enumerator = windowManagerInterface.getEnumerator(null);
- 
-   while (enumerator.hasMoreElements())
-   {
-     var domWindow = enumerator.getNext();
-     if (("tryToClose" in domWindow) && !domWindow.tryToClose())
-     {
-       return false;
-     }
-     domWindow.close();
-   }
- 
-   try
-   {
-     appService.quit(forceQuit);
-   }
-   catch(ex)
-   {
-     throw('goQuitApplication: ' + ex);
-   }
- 
-   return true;
- }
- 
+
  var list = 
      [
   "blueprint/sample.html",
   "blueprint/forms.html",
   "blueprint/grid.html",
   "blueprint/elements.html",
   "js-input/3d-cube.html",
   "js-input/3d-morph.html",
@@ -157,17 +47,17 @@
      window.setTimeout(loadURL, interval); 
  };
  function loadURL () {
      w.close();
      w = window.open(list[idx++]);
      if (idx < list.length) {
      window.setTimeout(loadURL, interval);
      } else {
-         window.setTimeout(goQuitApplication, interval);
+         window.setTimeout(Quitter.quit, interval);
      }
  }
  var i;
  
  for(i=0; i < list.length;i++) {
      document.write(list[i]);
      document.write("<br>");
  }
--- a/build/pgo/profileserver.py
+++ b/build/pgo/profileserver.py
@@ -43,17 +43,17 @@ if __name__ == '__main__':
     prefs.update(Preferences.read_prefs(prefpath))
     interpolation = { "server": "%s:%d" % httpd.httpd.server_address,
                       "OOP": "false"}
     prefs = json.loads(json.dumps(prefs) % interpolation)
     for pref in prefs:
       prefs[pref] = Preferences.cast(prefs[pref])
     profile = FirefoxProfile(profile=profilePath,
                              preferences=prefs,
-                             #addons=[os.path.join(here, 'extension')],
+                             addons=[os.path.join(build.distdir, 'xpi-stage', 'quitter')],
                              locations=locations)
 
     env = os.environ.copy()
     env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
     env["XPCOM_DEBUG_BREAK"] = "warn"
     jarlog = os.getenv("JARLOG_FILE")
     if jarlog:
       env["MOZ_JAR_LOG_FILE"] = os.path.abspath(jarlog)
--- a/configure.in
+++ b/configure.in
@@ -2052,16 +2052,22 @@ ia64*-hpux*)
         MKSHLIB_FORCE_ALL=
         MKSHLIB_UNFORCE_ALL=
         DSO_LDOPTS=-SUBSYSTEM:WINDOWS
         _USE_CPP_INCLUDE_FLAG=1
         _DEFINES_CFLAGS='-FI $(DEPTH)/dist/include/mozilla-config.h -DMOZILLA_CLIENT'
         _DEFINES_CXXFLAGS='-FI $(DEPTH)/dist/include/mozilla-config.h -DMOZILLA_CLIENT'
         CFLAGS="$CFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)"
         CXXFLAGS="$CXXFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)"
+        if test "$_CC_SUITE" -ge "12"; then
+            dnl VS2013+ requires -FS when parallel building by make -jN.
+            dnl If nothing, compiler sometimes causes C1041 error.
+            CFLAGS="$CFLAGS -FS"
+            CXXFLAGS="$CXXFLAGS -FS"
+        fi
         # khuey says we can safely ignore MSVC warning C4251
         # MSVC warning C4244 (implicit type conversion may lose data) warns
         # and requires workarounds for perfectly valid code.  Also, GCC/clang
         # don't warn about it by default. So for consistency/sanity, we turn
         # it off on MSVC, too.
         # MSVC warning C4345 warns of newly conformant behavior as of VS2003.
         # MSVC warning C4351 warns of newly conformant behavior as of VS2005.
         # MSVC warning C4482 warns when an enum value is refered specifing the
@@ -5450,16 +5456,32 @@ MOZ_ARG_ENABLE_BOOL(media-plugins,
     MOZ_MEDIA_PLUGINS=1,
     MOZ_MEDIA_PLUGINS=)
 
 if test -n "$MOZ_MEDIA_PLUGINS"; then
   AC_DEFINE(MOZ_MEDIA_PLUGINS)
 fi
 
 dnl ========================================================
+dnl = Disable platform MP3 decoder on OSX
+dnl ========================================================
+if test "$MOZ_WIDGET_TOOLKIT" = "cocoa"; then
+  MOZ_APPLEMEDIA=1
+fi
+
+MOZ_ARG_DISABLE_BOOL(apple-media,
+[  --disable-apple-media  Disable support for Apple AudioToolbox/VideoToolbox],
+    MOZ_APPLEMEDIA=,
+    MOZ_APPLEMEDIA=1)
+
+if test -n "$MOZ_APPLEMEDIA"; then
+  AC_DEFINE(MOZ_APPLEMEDIA)
+fi
+
+dnl ========================================================
 dnl = Enable getUserMedia support
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(media-navigator,
 [  --enable-media-navigator  Enable support for getUserMedia],
     MOZ_MEDIA_NAVIGATOR=1,
     MOZ_MEDIA_NAVIGATOR=)
 
 if test -n "$MOZ_MEDIA_NAVIGATOR"; then
@@ -8746,16 +8768,17 @@ AC_SUBST(MOZ_WAVE)
 AC_SUBST(MOZ_VORBIS)
 AC_SUBST(MOZ_TREMOR)
 AC_SUBST(MOZ_OPUS)
 AC_SUBST(MOZ_WEBM)
 AC_SUBST(MOZ_DASH)
 AC_SUBST(MOZ_WMF)
 AC_SUBST(MOZ_DIRECTSHOW)
 AC_SUBST(MOZ_MEDIA_PLUGINS)
+AC_SUBST(MOZ_APPLEMEDIA)
 AC_SUBST(MOZ_OMX_PLUGIN)
 AC_SUBST(MOZ_VP8_ERROR_CONCEALMENT)
 AC_SUBST(MOZ_VP8_ENCODER)
 AC_SUBST(MOZ_VP8)
 AC_SUBST(MOZ_OGG)
 AC_SUBST(VPX_AS)
 AC_SUBST(VPX_ASFLAGS)
 AC_SUBST(VPX_DASH_C_FLAG)
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -759,17 +759,17 @@ public:
    *
    * @param aFlags      Extra flags for the dispatching event.  The true flags
    *                    will be respected.
    */
   static nsresult DispatchClickEvent(nsPresContext* aPresContext,
                                      nsInputEvent* aSourceEvent,
                                      nsIContent* aTarget,
                                      bool aFullDispatch,
-                                     const widget::EventFlags* aFlags,
+                                     const EventFlags* aFlags,
                                      nsEventStatus* aStatus);
 
   /**
    * Method to dispatch aEvent to aTarget. If aFullDispatch is true, the event
    * will be dispatched through the full dispatching of the presshell of the
    * aPresContext; if it's false the event will be dispatched only as a DOM
    * event.
    * If aPresContext is nullptr, this does nothing.
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -1400,17 +1400,17 @@ Element::DispatchEvent(nsPresContext* aP
 }
 
 /* static */
 nsresult
 Element::DispatchClickEvent(nsPresContext* aPresContext,
                             nsInputEvent* aSourceEvent,
                             nsIContent* aTarget,
                             bool aFullDispatch,
-                            const widget::EventFlags* aExtraEventFlags,
+                            const EventFlags* aExtraEventFlags,
                             nsEventStatus* aStatus)
 {
   NS_PRECONDITION(aTarget, "Must have target");
   NS_PRECONDITION(aSourceEvent, "Must have source event");
   NS_PRECONDITION(aStatus, "Null out param?");
 
   nsMouseEvent event(aSourceEvent->mFlags.mIsTrusted, NS_MOUSE_CLICK,
                      aSourceEvent->widget, nsMouseEvent::eReal);
@@ -1707,30 +1707,30 @@ Element::SetAttrAndNotify(int32_t aNames
     nsRefPtr<nsXBLBinding> binding = GetXBLBinding();
     if (binding) {
       binding->AttributeChanged(aName, aNamespaceID, false, aNotify);
     }
   }
 
   UpdateState(aNotify);
 
-  if (aNotify) {
-    nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType);
-  }
-
   if (aCallAfterSetAttr) {
     rv = AfterSetAttr(aNamespaceID, aName, &aValueForAfterSetAttr, aNotify);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
       OnSetDirAttr(this, &aValueForAfterSetAttr,
                    hadValidDir, hadDirAuto, aNotify);
     }
   }
 
+  if (aNotify) {
+    nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType);
+  }
+
   if (aFireMutation) {
     nsMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED);
 
     nsAutoString ns;
     nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
     Attr* attrNode =
       GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName));
     mutation.mRelatedNode = attrNode;
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -84,16 +84,17 @@ nsImageLoadingContent::nsImageLoadingCon
     mBroken(true),
     mUserDisabled(false),
     mSuppressed(false),
     mFireEventsOnDecode(false),
     mNewRequestsWillNeedAnimationReset(false),
     mStateChangerDepth(0),
     mCurrentRequestRegistered(false),
     mPendingRequestRegistered(false),
+    mFrameCreateCalled(false),
     mVisibleCount(0)
 {
   if (!nsContentUtils::GetImgLoaderForChannel(nullptr)) {
     mLoadingEnabled = false;
   }
 }
 
 void
@@ -231,18 +232,26 @@ nsImageLoadingContent::OnStopRequest(img
   // XXXkhuey should this be GetOurCurrentDoc?  Decoding if we're not in
   // the document seems silly.
   bool startedDecoding = false;
   nsIDocument* doc = GetOurOwnerDoc();
   nsIPresShell* shell = doc ? doc->GetShell() : nullptr;
   if (shell && shell->IsVisible() &&
       (!shell->DidInitialize() || shell->IsPaintingSuppressed())) {
 
-    if (NS_SUCCEEDED(mCurrentRequest->StartDecoding())) {
-      startedDecoding = true;
+    // If we've gotten a frame and that frame has called FrameCreate and that
+    // frame has been reflowed then we know that it checked it's own visibility
+    // so we can trust our visible count and we don't start decode if we are not
+    // visible.
+    nsIFrame* f = GetOurPrimaryFrame();
+    if (!mFrameCreateCalled || !f || (f->GetStateBits() & NS_FRAME_FIRST_REFLOW) ||
+        mVisibleCount > 0 || shell->AssumeAllImagesVisible()) {
+      if (NS_SUCCEEDED(mCurrentRequest->StartDecoding())) {
+        startedDecoding = true;
+      }
     }
   }
 
   // We want to give the decoder a chance to find errors. If we haven't found
   // an error yet and we've started decoding, either from the above
   // StartDecoding or from some other place, we must only fire these events
   // after we finish decoding.
   uint32_t reqStatus;
@@ -417,49 +426,47 @@ nsImageLoadingContent::GetRequest(int32_
   return result.ErrorCode();
 }
 
 NS_IMETHODIMP_(void)
 nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
 {
   NS_ASSERTION(aFrame, "aFrame is null");
 
+  mFrameCreateCalled = true;
+
   if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
     // Assume all images in popups are visible.
     IncrementVisibleCount();
   }
 
-  nsPresContext* presContext = aFrame->PresContext();
-  if (mVisibleCount == 0) {
-    presContext->PresShell()->EnsureImageInVisibleList(this);
-  }
-
-  // We pass the SKIP_FRAME_CHECK flag to TrackImage here because our primary
-  // frame pointer hasn't been setup yet when this is caled.
-  TrackImage(mCurrentRequest, SKIP_FRAME_CHECK);
-  TrackImage(mPendingRequest, SKIP_FRAME_CHECK);
+  TrackImage(mCurrentRequest);
+  TrackImage(mPendingRequest);
 
   // We need to make sure that our image request is registered, if it should
   // be registered.
+  nsPresContext* presContext = aFrame->PresContext();
   if (mCurrentRequest) {
     nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, mCurrentRequest,
                                                   &mCurrentRequestRegistered);
   }
 
   if (mPendingRequest) {
     nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, mPendingRequest,
                                                   &mPendingRequestRegistered);
   }
 }
 
 NS_IMETHODIMP_(void)
 nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
 {
   NS_ASSERTION(aFrame, "aFrame is null");
 
+  mFrameCreateCalled = false;
+
   // We need to make sure that our image request is deregistered.
   if (mCurrentRequest) {
     nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(),
                                           mCurrentRequest,
                                           &mCurrentRequestRegistered);
   }
 
   if (mPendingRequest) {
@@ -1276,26 +1283,26 @@ nsImageLoadingContent::UnbindFromTree(bo
   UntrackImage(mCurrentRequest);
   UntrackImage(mPendingRequest);
 
   if (mCurrentRequestFlags & REQUEST_BLOCKS_ONLOAD)
     doc->UnblockOnload(false);
 }
 
 void
-nsImageLoadingContent::TrackImage(imgIRequest* aImage, uint32_t aFlags /* = 0 */)
+nsImageLoadingContent::TrackImage(imgIRequest* aImage)
 {
   if (!aImage)
     return;
 
   MOZ_ASSERT(aImage == mCurrentRequest || aImage == mPendingRequest,
              "Why haven't we heard of this request?");
 
   nsIDocument* doc = GetOurCurrentDoc();
-  if (doc && ((aFlags & SKIP_FRAME_CHECK) || GetOurPrimaryFrame()) &&
+  if (doc && (mFrameCreateCalled || GetOurPrimaryFrame()) &&
       (mVisibleCount > 0)) {
     if (aImage == mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
       mCurrentRequestFlags |= REQUEST_IS_TRACKED;
       doc->AddImage(mCurrentRequest);
     }
     if (aImage == mPendingRequest && !(mPendingRequestFlags & REQUEST_IS_TRACKED)) {
       mPendingRequestFlags |= REQUEST_IS_TRACKED;
       doc->AddImage(mPendingRequest);
--- a/content/base/src/nsImageLoadingContent.h
+++ b/content/base/src/nsImageLoadingContent.h
@@ -323,26 +323,20 @@ protected:
    */
   static bool HaveSize(imgIRequest *aImage);
 
   /**
    * Adds/Removes a given imgIRequest from our document's tracker.
    *
    * No-op if aImage is null.
    *
-   * SKIP_FRAME_CHECK passed to TrackImage means we skip the check if we have a
-   * frame, there is only one valid use of this: when calling from FrameCreated.
-   *
    * REQUEST_DISCARD passed to UntrackImage means we request the discard of the
    * decoded data of the image.
    */
-  enum {
-    SKIP_FRAME_CHECK = 0x1
-  };
-  void TrackImage(imgIRequest* aImage, uint32_t aFlags = 0);
+  void TrackImage(imgIRequest* aImage);
   enum {
     REQUEST_DISCARD = 0x1
   };
   void UntrackImage(imgIRequest* aImage, uint32_t aFlags = 0);
 
   /* MEMBERS */
   nsRefPtr<imgRequestProxy> mCurrentRequest;
   nsRefPtr<imgRequestProxy> mPendingRequest;
@@ -414,12 +408,15 @@ private:
   /* The number of nested AutoStateChangers currently tracking our state. */
   uint8_t mStateChangerDepth;
 
   // Flags to indicate whether each of the current and pending requests are
   // registered with the refresh driver.
   bool mCurrentRequestRegistered;
   bool mPendingRequestRegistered;
 
+  // True when FrameCreate has been called but FrameDestroy has not.
+  bool mFrameCreateCalled;
+
   uint32_t mVisibleCount;
 };
 
 #endif // nsImageLoadingContent_h__
--- a/content/events/src/DOMWheelEvent.cpp
+++ b/content/events/src/DOMWheelEvent.cpp
@@ -8,38 +8,38 @@
 #include "nsGUIEvent.h"
 #include "prtime.h"
 
 namespace mozilla {
 namespace dom {
 
 DOMWheelEvent::DOMWheelEvent(EventTarget* aOwner,
                              nsPresContext* aPresContext,
-                             widget::WheelEvent* aWheelEvent)
+                             WheelEvent* aWheelEvent)
   : nsDOMMouseEvent(aOwner, aPresContext,
                     aWheelEvent ? aWheelEvent :
-                                  new widget::WheelEvent(false, 0, nullptr))
+                                  new WheelEvent(false, 0, nullptr))
 {
   if (aWheelEvent) {
     mEventIsInternal = false;
   } else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
     mEvent->refPoint.x = mEvent->refPoint.y = 0;
-    static_cast<widget::WheelEvent*>(mEvent)->inputSource =
+    static_cast<WheelEvent*>(mEvent)->inputSource =
       nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
   }
 }
 
 DOMWheelEvent::~DOMWheelEvent()
 {
   if (mEventIsInternal && mEvent) {
     MOZ_ASSERT(mEvent->eventStructType == NS_WHEEL_EVENT,
                "The mEvent must be WheelEvent");
-    delete static_cast<widget::WheelEvent*>(mEvent);
+    delete static_cast<WheelEvent*>(mEvent);
     mEvent = nullptr;
   }
 }
 
 NS_IMPL_ADDREF_INHERITED(DOMWheelEvent, nsDOMMouseEvent)
 NS_IMPL_RELEASE_INHERITED(DOMWheelEvent, nsDOMMouseEvent)
 
 NS_INTERFACE_MAP_BEGIN(DOMWheelEvent)
@@ -66,17 +66,17 @@ DOMWheelEvent::InitWheelEvent(const nsAS
 {
   nsresult rv =
     nsDOMMouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView,
                                     aDetail, aScreenX, aScreenY,
                                     aClientX, aClientY, aButton,
                                     aRelatedTarget, aModifiersList);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  widget::WheelEvent* wheelEvent = static_cast<widget::WheelEvent*>(mEvent);
+  WheelEvent* wheelEvent = static_cast<WheelEvent*>(mEvent);
   wheelEvent->deltaX = aDeltaX;
   wheelEvent->deltaY = aDeltaY;
   wheelEvent->deltaZ = aDeltaZ;
   wheelEvent->deltaMode = aDeltaMode;
 
   return NS_OK;
 }
 
@@ -158,26 +158,26 @@ DOMWheelEvent::Constructor(const GlobalO
                   modifierList);
   aRv = e->InitWheelEvent(aType, aParam.mBubbles, aParam.mCancelable,
                           aParam.mView, aParam.mDetail,
                           aParam.mScreenX, aParam.mScreenY,
                           aParam.mClientX, aParam.mClientY,
                           aParam.mButton, aParam.mRelatedTarget,
                           modifierList, aParam.mDeltaX,
                           aParam.mDeltaY, aParam.mDeltaZ, aParam.mDeltaMode);
-  static_cast<widget::WheelEvent*>(e->mEvent)->buttons = aParam.mButtons;
+  static_cast<WheelEvent*>(e->mEvent)->buttons = aParam.mButtons;
   e->SetTrusted(trusted);
   return e.forget();
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 
 nsresult NS_NewDOMWheelEvent(nsIDOMEvent** aInstancePtrResult,
                              mozilla::dom::EventTarget* aOwner,
                              nsPresContext* aPresContext,
-                             widget::WheelEvent *aEvent)
+                             WheelEvent *aEvent)
 {
   dom::DOMWheelEvent* it = new dom::DOMWheelEvent(aOwner, aPresContext, aEvent);
   return CallQueryInterface(it, aInstancePtrResult);
 }
--- a/content/events/src/DOMWheelEvent.h
+++ b/content/events/src/DOMWheelEvent.h
@@ -15,17 +15,17 @@ namespace mozilla {
 namespace dom {
 
 class DOMWheelEvent : public nsDOMMouseEvent,
                       public nsIDOMWheelEvent
 {
 public:
   DOMWheelEvent(mozilla::dom::EventTarget* aOwner,
                 nsPresContext* aPresContext,
-                widget::WheelEvent* aWheelEvent);
+                WheelEvent* aWheelEvent);
   virtual ~DOMWheelEvent();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMWheelEvent Interface
   NS_DECL_NSIDOMWHEELEVENT
   
   // Forward to base class
@@ -40,31 +40,31 @@ public:
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
   {
     return mozilla::dom::WheelEventBinding::Wrap(aCx, aScope, this);
   }
 
   double DeltaX()
   {
-    return static_cast<widget::WheelEvent*>(mEvent)->deltaX;
+    return static_cast<WheelEvent*>(mEvent)->deltaX;
   }
 
   double DeltaY()
   {
-    return static_cast<widget::WheelEvent*>(mEvent)->deltaY;
+    return static_cast<WheelEvent*>(mEvent)->deltaY;
   }
 
   double DeltaZ()
   {
-    return static_cast<widget::WheelEvent*>(mEvent)->deltaZ;
+    return static_cast<WheelEvent*>(mEvent)->deltaZ;
   }
 
   uint32_t DeltaMode()
   {
-    return static_cast<widget::WheelEvent*>(mEvent)->deltaMode;
+    return static_cast<WheelEvent*>(mEvent)->deltaMode;
   }
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_DOMWheelEvent_h__
--- a/content/events/src/TextComposition.cpp
+++ b/content/events/src/TextComposition.cpp
@@ -7,17 +7,16 @@
 #include "TextComposition.h"
 #include "nsContentEventHandler.h"
 #include "nsContentUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsGUIEvent.h"
 #include "nsIContent.h"
 #include "nsIMEStateManager.h"
 #include "nsIPresShell.h"
-#include "nsIWidget.h"
 #include "nsPresContext.h"
 
 namespace mozilla {
 
 /******************************************************************************
  * TextComposition
  ******************************************************************************/
 
--- a/content/events/src/TextComposition.h
+++ b/content/events/src/TextComposition.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_TextComposition_h
 #define mozilla_TextComposition_h
 
 #include "nsCOMPtr.h"
 #include "nsEvent.h"
 #include "nsINode.h"
+#include "nsIWidget.h"
 #include "nsTArray.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Attributes.h"
 
 class nsDispatchingCallback;
 class nsIMEStateManager;
 class nsIWidget;
 
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -596,20 +596,18 @@ nsDOMEvent::DuplicatePrivateData()
       nsMouseScrollEvent* mouseScrollEvent =
         new nsMouseScrollEvent(false, msg, nullptr);
       mouseScrollEvent->AssignMouseScrollEventData(*oldMouseScrollEvent, true);
       newEvent = mouseScrollEvent;
       break;
     }
     case NS_WHEEL_EVENT:
     {
-      widget::WheelEvent* oldWheelEvent =
-        static_cast<widget::WheelEvent*>(mEvent);
-      widget::WheelEvent* wheelEvent =
-        new widget::WheelEvent(false, msg, nullptr);
+      WheelEvent* oldWheelEvent = static_cast<WheelEvent*>(mEvent);
+      WheelEvent* wheelEvent = new WheelEvent(false, msg, nullptr);
       wheelEvent->AssignWheelEventData(*oldWheelEvent, true);
       newEvent = wheelEvent;
       break;
     }
     case NS_SCROLLPORT_EVENT:
     {
       nsScrollPortEvent* oldScrollPortEvent =
         static_cast<nsScrollPortEvent*>(mEvent);
--- a/content/events/src/nsDOMMouseEvent.cpp
+++ b/content/events/src/nsDOMMouseEvent.cpp
@@ -121,20 +121,20 @@ nsDOMMouseEvent::InitMouseEvent(const ns
                                 uint16_t aButton,
                                 nsIDOMEventTarget *aRelatedTarget,
                                 const nsAString& aModifiersList)
 {
   Modifiers modifiers = ComputeModifierState(aModifiersList);
 
   nsresult rv = InitMouseEvent(aType, aCanBubble, aCancelable, aView,
                                aDetail, aScreenX, aScreenY, aClientX, aClientY,
-                               (modifiers & widget::MODIFIER_CONTROL) != 0,
-                               (modifiers & widget::MODIFIER_ALT) != 0,
-                               (modifiers & widget::MODIFIER_SHIFT) != 0,
-                               (modifiers & widget::MODIFIER_META) != 0,
+                               (modifiers & MODIFIER_CONTROL) != 0,
+                               (modifiers & MODIFIER_ALT) != 0,
+                               (modifiers & MODIFIER_SHIFT) != 0,
+                               (modifiers & MODIFIER_META) != 0,
                                aButton, aRelatedTarget);
   NS_ENSURE_SUCCESS(rv, rv);
 
   switch(mEvent->eventStructType) {
     case NS_MOUSE_EVENT:
     case NS_MOUSE_SCROLL_EVENT:
     case NS_WHEEL_EVENT:
     case NS_DRAG_EVENT:
--- a/content/events/src/nsDOMUIEvent.cpp
+++ b/content/events/src/nsDOMUIEvent.cpp
@@ -401,35 +401,35 @@ nsDOMUIEvent::Deserialize(const IPC::Mes
   return true;
 }
 
 // XXX Following struct and array are used only in
 //     nsDOMUIEvent::ComputeModifierState(), but if we define them in it,
 //     we fail to build on Mac at calling mozilla::ArrayLength().
 struct nsModifierPair
 {
-  mozilla::widget::Modifier modifier;
+  mozilla::Modifier modifier;
   const char* name;
 };
 static const nsModifierPair kPairs[] = {
-  { widget::MODIFIER_ALT,        NS_DOM_KEYNAME_ALT },
-  { widget::MODIFIER_ALTGRAPH,   NS_DOM_KEYNAME_ALTGRAPH },
-  { widget::MODIFIER_CAPSLOCK,   NS_DOM_KEYNAME_CAPSLOCK },
-  { widget::MODIFIER_CONTROL,    NS_DOM_KEYNAME_CONTROL },
-  { widget::MODIFIER_FN,         NS_DOM_KEYNAME_FN },
-  { widget::MODIFIER_META,       NS_DOM_KEYNAME_META },
-  { widget::MODIFIER_NUMLOCK,    NS_DOM_KEYNAME_NUMLOCK },
-  { widget::MODIFIER_SCROLLLOCK, NS_DOM_KEYNAME_SCROLLLOCK },
-  { widget::MODIFIER_SHIFT,      NS_DOM_KEYNAME_SHIFT },
-  { widget::MODIFIER_SYMBOLLOCK, NS_DOM_KEYNAME_SYMBOLLOCK },
-  { widget::MODIFIER_OS,         NS_DOM_KEYNAME_OS }
+  { MODIFIER_ALT,        NS_DOM_KEYNAME_ALT },
+  { MODIFIER_ALTGRAPH,   NS_DOM_KEYNAME_ALTGRAPH },
+  { MODIFIER_CAPSLOCK,   NS_DOM_KEYNAME_CAPSLOCK },
+  { MODIFIER_CONTROL,    NS_DOM_KEYNAME_CONTROL },
+  { MODIFIER_FN,         NS_DOM_KEYNAME_FN },
+  { MODIFIER_META,       NS_DOM_KEYNAME_META },
+  { MODIFIER_NUMLOCK,    NS_DOM_KEYNAME_NUMLOCK },
+  { MODIFIER_SCROLLLOCK, NS_DOM_KEYNAME_SCROLLLOCK },
+  { MODIFIER_SHIFT,      NS_DOM_KEYNAME_SHIFT },
+  { MODIFIER_SYMBOLLOCK, NS_DOM_KEYNAME_SYMBOLLOCK },
+  { MODIFIER_OS,         NS_DOM_KEYNAME_OS }
 };
 
 /* static */
-mozilla::widget::Modifiers
+mozilla::Modifiers
 nsDOMUIEvent::ComputeModifierState(const nsAString& aModifiersList)
 {
   if (aModifiersList.IsEmpty()) {
     return 0;
   }
 
   // Be careful about the performance.  If aModifiersList is too long,
   // parsing it needs too long time.
--- a/content/events/src/nsDOMUIEvent.h
+++ b/content/events/src/nsDOMUIEvent.h
@@ -153,17 +153,17 @@ protected:
   CSSIntPoint mClientPoint;
   // Screenpoint is mEvent->refPoint.
   nsIntPoint mLayerPoint;
   CSSIntPoint mPagePoint;
   nsIntPoint mMovementPoint;
   bool mIsPointerLocked;
   CSSIntPoint mLastClientPoint;
 
-  typedef mozilla::widget::Modifiers Modifiers;
+  typedef mozilla::Modifiers Modifiers;
   static Modifiers ComputeModifierState(const nsAString& aModifiersList);
   bool GetModifierStateInternal(const nsAString& aKey);
 };
 
 #define NS_FORWARD_TO_NSDOMUIEVENT                          \
   NS_FORWARD_NSIDOMUIEVENT(nsDOMUIEvent::)                  \
   NS_FORWARD_TO_NSDOMEVENT_NO_SERIALIZATION_NO_DUPLICATION  \
   NS_IMETHOD DuplicatePrivateData()                         \
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -707,17 +707,17 @@ nsEventDispatcher::CreateEvent(mozilla::
     case NS_FOCUS_EVENT:
       return NS_NewDOMFocusEvent(aDOMEvent, aOwner, aPresContext,
                                  static_cast<nsFocusEvent*>(aEvent));
     case NS_MOUSE_SCROLL_EVENT:
       return NS_NewDOMMouseScrollEvent(aDOMEvent, aOwner, aPresContext,
                                  static_cast<nsInputEvent*>(aEvent));
     case NS_WHEEL_EVENT:
       return NS_NewDOMWheelEvent(aDOMEvent, aOwner, aPresContext,
-                                 static_cast<widget::WheelEvent*>(aEvent));
+                                 static_cast<WheelEvent*>(aEvent));
     case NS_DRAG_EVENT:
       return NS_NewDOMDragEvent(aDOMEvent, aOwner, aPresContext,
                                  static_cast<nsDragEvent*>(aEvent));
     case NS_TEXT_EVENT:
       return NS_NewDOMTextEvent(aDOMEvent, aOwner, aPresContext,
                                 static_cast<nsTextEvent*>(aEvent));
     case NS_CLIPBOARD_EVENT:
       return NS_NewDOMClipboardEvent(aDOMEvent, aOwner, aPresContext,
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -946,26 +946,31 @@ nsEventListenerManager::HandleEventSubTy
     nsIJSEventListener *jslistener = aListenerStruct->GetJSListener();
     result = CompileEventHandlerInternal(aListenerStruct,
                                          jslistener->GetEventContext() !=
                                            aPusher->GetCurrentScriptContext(),
                                          nullptr);
   }
 
   if (NS_SUCCEEDED(result)) {
-    nsAutoMicroTask mt;
+    if (mIsMainThreadELM) {
+      nsContentUtils::EnterMicroTask();
+    }
     // nsIDOMEvent::currentTarget is set in nsEventDispatcher.
     if (aListener.HasWebIDLCallback()) {
       ErrorResult rv;
       aListener.GetWebIDLCallback()->
         HandleEvent(aCurrentTarget, *(aDOMEvent->InternalDOMEvent()), rv);
       result = rv.ErrorCode();
     } else {
       result = aListener.GetXPCOMCallback()->HandleEvent(aDOMEvent);
     }
+    if (mIsMainThreadELM) {
+      nsContentUtils::LeaveMicroTask();
+    }
   }
 
   return result;
 }
 
 /**
 * Causes a check for event listeners and processing by them if they exist.
 * @param an event listener
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -250,54 +250,54 @@ struct DeltaValues
 {
   DeltaValues() : deltaX(0.0), deltaY(0.0) {}
 
   DeltaValues(double aDeltaX, double aDeltaY) :
     deltaX(aDeltaX), deltaY(aDeltaY)
   {
   }
 
-  explicit DeltaValues(widget::WheelEvent* aEvent) :
+  explicit DeltaValues(WheelEvent* aEvent) :
     deltaX(aEvent->deltaX), deltaY(aEvent->deltaY)
   {
   }
 
   double deltaX;
   double deltaY;
 };
 
 class nsMouseWheelTransaction {
 public:
   static nsIFrame* GetTargetFrame() { return sTargetFrame; }
   static void BeginTransaction(nsIFrame* aTargetFrame,
-                               widget::WheelEvent* aEvent);
+                               WheelEvent* aEvent);
   // Be careful, UpdateTransaction may fire a DOM event, therefore, the target
   // frame might be destroyed in the event handler.
-  static bool UpdateTransaction(widget::WheelEvent* aEvent);
+  static bool UpdateTransaction(WheelEvent* aEvent);
   static void EndTransaction();
   static void OnEvent(nsEvent* aEvent);
   static void Shutdown();
   static uint32_t GetTimeoutTime();
 
 
-  static DeltaValues AccelerateWheelDelta(widget::WheelEvent* aEvent,
+  static DeltaValues AccelerateWheelDelta(WheelEvent* aEvent,
                                           bool aAllowScrollSpeedOverride);
 
   enum {
     kScrollSeriesTimeout = 80
   };
 protected:
   static nsIntPoint GetScreenPoint(nsGUIEvent* aEvent);
   static void OnFailToScrollTarget();
   static void OnTimeout(nsITimer *aTimer, void *aClosure);
   static void SetTimeout();
   static uint32_t GetIgnoreMoveDelayTime();
   static int32_t GetAccelerationStart();
   static int32_t GetAccelerationFactor();
-  static DeltaValues OverrideSystemScrollSpeed(widget::WheelEvent* aEvent);
+  static DeltaValues OverrideSystemScrollSpeed(WheelEvent* aEvent);
   static double ComputeAcceleratedWheelDelta(double aDelta, int32_t aFactor);
 
   static nsWeakFrame sTargetFrame;
   static uint32_t    sTime;        // in milliseconds
   static uint32_t    sMouseMoved;  // in milliseconds
   static nsITimer*   sTimer;
   static int32_t     sScrollSeriesCounter;
 };
@@ -336,29 +336,29 @@ CanScrollOn(nsIScrollableFrame* aScrollF
   return (aDeltaX && (directions & nsIScrollableFrame::HORIZONTAL) &&
           CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(), aDeltaX)) ||
          (aDeltaY && (directions & nsIScrollableFrame::VERTICAL) &&
           CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(), aDeltaY));
 }
 
 void
 nsMouseWheelTransaction::BeginTransaction(nsIFrame* aTargetFrame,
-                                          widget::WheelEvent* aEvent)
+                                          WheelEvent* aEvent)
 {
   NS_ASSERTION(!sTargetFrame, "previous transaction is not finished!");
   sTargetFrame = aTargetFrame;
   sScrollSeriesCounter = 0;
   if (!UpdateTransaction(aEvent)) {
     NS_ERROR("BeginTransaction is called even cannot scroll the frame");
     EndTransaction();
   }
 }
 
 bool
-nsMouseWheelTransaction::UpdateTransaction(widget::WheelEvent* aEvent)
+nsMouseWheelTransaction::UpdateTransaction(WheelEvent* aEvent)
 {
   nsIScrollableFrame* sf = GetTargetFrame()->GetScrollTargetFrame();
   NS_ENSURE_TRUE(sf, false);
 
   if (!CanScrollOn(sf, aEvent->deltaX, aEvent->deltaY)) {
     OnFailToScrollTarget();
     // We should not modify the transaction state when the view will not be
     // scrolled actually.
@@ -533,17 +533,17 @@ nsMouseWheelTransaction::GetTimeoutTime(
 
 uint32_t
 nsMouseWheelTransaction::GetIgnoreMoveDelayTime()
 {
   return Preferences::GetUint("mousewheel.transaction.ignoremovedelay", 100);
 }
 
 DeltaValues
-nsMouseWheelTransaction::AccelerateWheelDelta(widget::WheelEvent* aEvent,
+nsMouseWheelTransaction::AccelerateWheelDelta(WheelEvent* aEvent,
                                               bool aAllowScrollSpeedOverride)
 {
   DeltaValues result(aEvent);
 
   // Don't accelerate the delta values if the event isn't line scrolling.
   if (aEvent->deltaMode != nsIDOMWheelEvent::DOM_DELTA_LINE) {
     return result;
   }
@@ -584,17 +584,17 @@ nsMouseWheelTransaction::GetAcceleration
 
 int32_t
 nsMouseWheelTransaction::GetAccelerationFactor()
 {
   return Preferences::GetInt("mousewheel.acceleration.factor", -1);
 }
 
 DeltaValues
-nsMouseWheelTransaction::OverrideSystemScrollSpeed(widget::WheelEvent* aEvent)
+nsMouseWheelTransaction::OverrideSystemScrollSpeed(WheelEvent* aEvent)
 {
   MOZ_ASSERT(sTargetFrame, "We don't have mouse scrolling transaction");
   MOZ_ASSERT(aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE);
 
   // If the event doesn't scroll to both X and Y, we don't need to do anything
   // here.
   if (!aEvent->deltaX && !aEvent->deltaY) {
     return DeltaValues(aEvent);
@@ -967,17 +967,17 @@ nsEventStateManager::PreHandleEvent(nsPr
     {
       NS_ASSERTION(aEvent->mFlags.mIsTrusted,
                    "Untrusted wheel event shouldn't be here");
 
       nsIContent* content = GetFocusedContent();
       if (content)
         mCurrentTargetContent = content;
 
-      widget::WheelEvent* wheelEvent = static_cast<widget::WheelEvent*>(aEvent);
+      WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent);
       WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
 
       // If we won't dispatch a DOM event for this event, nothing to do anymore.
       if (!NS_IsAllowedToDispatchDOMEvent(wheelEvent)) {
         break;
       }
 
       // Init lineOrPageDelta values for line scroll events for some devices
@@ -1383,17 +1383,17 @@ nsEventStateManager::DispatchCrossProces
     nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
     return remote->SendRealMouseEvent(*mouseEvent);
   }
   case NS_KEY_EVENT: {
     nsKeyEvent* keyEvent = static_cast<nsKeyEvent*>(aEvent);
     return remote->SendRealKeyEvent(*keyEvent);
   }
   case NS_WHEEL_EVENT: {
-    widget::WheelEvent* wheelEvent = static_cast<widget::WheelEvent*>(aEvent);
+    WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent);
     return remote->SendMouseWheelEvent(*wheelEvent);
   }
   case NS_TOUCH_EVENT: {
     // Let the child process synthesize a mouse event if needed, and
     // ensure we don't synthesize one in this process.
     *aStatus = nsEventStatus_eConsumeNoDefault;
     nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
     return remote->SendRealTouchEvent(*touchEvent);
@@ -2006,17 +2006,17 @@ nsEventStateManager::DetermineDragTarget
 
   // GetDragData determines if a selection, link or image in the content
   // should be dragged, and places the data associated with the drag in the
   // data transfer.
   // mGestureDownContent is the node where the mousedown event for the drag
   // occurred, and aSelectionTarget is the node to use when a selection is used
   bool canDrag;
   nsCOMPtr<nsIContent> dragDataNode;
-  bool wasAlt = (mGestureModifiers & widget::MODIFIER_ALT) != 0;
+  bool wasAlt = (mGestureModifiers & MODIFIER_ALT) != 0;
   nsresult rv = nsContentAreaDragDrop::GetDragData(window, mGestureDownContent,
                                                    aSelectionTarget, wasAlt,
                                                    aDataTransfer, &canDrag, aSelection,
                                                    getter_AddRefs(dragDataNode));
   if (NS_FAILED(rv) || !canDrag)
     return;
 
   // if GetDragData returned a node, use that as the node being dragged.
@@ -2326,17 +2326,17 @@ GetParentFrameToScroll(nsIFrame* aFrame)
       nsLayoutUtils::IsReallyFixedPos(aFrame))
     return aFrame->PresContext()->GetPresShell()->GetRootScrollFrame();
 
   return aFrame->GetParent();
 }
 
 void
 nsEventStateManager::DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
-                                                     widget::WheelEvent* aEvent,
+                                                     WheelEvent* aEvent,
                                                      nsEventStatus* aStatus)
 {
   MOZ_ASSERT(aEvent);
   MOZ_ASSERT(aStatus);
 
   if (!aTargetFrame || *aStatus == nsEventStatus_eConsumeNoDefault) {
     return;
   }
@@ -2451,17 +2451,17 @@ nsEventStateManager::DispatchLegacyMouse
   if (statusY == nsEventStatus_eConsumeDoDefault ||
       statusX == nsEventStatus_eConsumeDoDefault) {
     *aStatus = nsEventStatus_eConsumeDoDefault;
   }
 }
 
 void
 nsEventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
-                                         widget::WheelEvent* aEvent,
+                                         WheelEvent* aEvent,
                                          nsEventStatus* aStatus,
                                          int32_t aDelta,
                                          DeltaDirection aDeltaDirection)
 {
   nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
   if (!targetContent)
     targetContent = GetFocusedContent();
   if (!targetContent)
@@ -2486,17 +2486,17 @@ nsEventStateManager::SendLineScrollEvent
   event.inputSource = aEvent->inputSource;
 
   nsEventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
                               &event, nullptr, aStatus);
 }
 
 void
 nsEventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
-                                          widget::WheelEvent* aEvent,
+                                          WheelEvent* aEvent,
                                           nsEventStatus* aStatus,
                                           int32_t aPixelDelta,
                                           DeltaDirection aDeltaDirection)
 {
   nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
   if (!targetContent) {
     targetContent = GetFocusedContent();
     if (!targetContent)
@@ -2522,17 +2522,17 @@ nsEventStateManager::SendPixelScrollEven
   event.inputSource = aEvent->inputSource;
 
   nsEventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
                               &event, nullptr, aStatus);
 }
 
 nsIScrollableFrame*
 nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
-                                         widget::WheelEvent* aEvent,
+                                         WheelEvent* aEvent,
                                          ComputeScrollTargetOptions aOptions)
 {
   if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
     // If the user recently scrolled with the mousewheel, then they probably
     // want to scroll the same view as before instead of the view under the
     // cursor.  nsMouseWheelTransaction tracks the frame currently being
     // scrolled with the mousewheel. We consider the transaction ended when the
     // mouse moves more than "mousewheel.transaction.ignoremovedelay"
@@ -2610,17 +2610,17 @@ nsEventStateManager::ComputeScrollTarget
       aTargetFrame->PresContext()->FrameManager()->GetRootFrame());
   aOptions =
     static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT);
   return newFrame ? ComputeScrollTarget(newFrame, aEvent, aOptions) : nullptr;
 }
 
 nsSize
 nsEventStateManager::GetScrollAmount(nsPresContext* aPresContext,
-                                     widget::WheelEvent* aEvent,
+                                     WheelEvent* aEvent,
                                      nsIScrollableFrame* aScrollableFrame)
 {
   MOZ_ASSERT(aPresContext);
   MOZ_ASSERT(aEvent);
 
   bool isPage = (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE);
   if (aScrollableFrame) {
     return isPage ? aScrollableFrame->GetPageScrollAmount() :
@@ -2641,17 +2641,17 @@ nsEventStateManager::GetScrollAmount(nsP
   nsLayoutUtils::GetFontMetricsForFrame(rootFrame, getter_AddRefs(fm),
     nsLayoutUtils::FontSizeInflationFor(rootFrame));
   NS_ENSURE_TRUE(fm, nsSize(0, 0));
   return nsSize(fm->AveCharWidth(), fm->MaxHeight());
 }
 
 void
 nsEventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame,
-                                  widget::WheelEvent* aEvent)
+                                  WheelEvent* aEvent)
 {
   MOZ_ASSERT(aScrollableFrame);
   MOZ_ASSERT(aEvent);
 
   nsIFrame* scrollFrame = do_QueryFrame(aScrollableFrame);
   MOZ_ASSERT(scrollFrame);
   nsWeakFrame scrollFrameWeak(scrollFrame);
 
@@ -2728,30 +2728,30 @@ nsEventStateManager::DoScrollText(nsIScr
                                             -devPixelPageSize.height;
   }
 
   bool isDeltaModePixel =
     (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL);
 
   nsIScrollableFrame::ScrollMode mode;
   switch (aEvent->scrollType) {
-    case widget::WheelEvent::SCROLL_DEFAULT:
+    case WheelEvent::SCROLL_DEFAULT:
       if (isDeltaModePixel) {
         mode = nsIScrollableFrame::NORMAL;
       } else {
         mode = nsIScrollableFrame::SMOOTH;
       }
       break;
-    case widget::WheelEvent::SCROLL_SYNCHRONOUSLY:
+    case WheelEvent::SCROLL_SYNCHRONOUSLY:
       mode = nsIScrollableFrame::INSTANT;
       break;
-    case widget::WheelEvent::SCROLL_ASYNCHRONOUSELY:
+    case WheelEvent::SCROLL_ASYNCHRONOUSELY:
       mode = nsIScrollableFrame::NORMAL;
       break;
-    case widget::WheelEvent::SCROLL_SMOOTHLY:
+    case WheelEvent::SCROLL_SMOOTHLY:
       mode = nsIScrollableFrame::SMOOTH;
       break;
     default:
       MOZ_CRASH("Invalid scrollType value comes");
   }
 
   nsIntPoint overflow;
   aScrollableFrame->ScrollBy(actualDevPixelScrollAmount,
@@ -3154,17 +3154,17 @@ nsEventStateManager::PostHandleEvent(nsP
   case NS_WHEEL_WHEEL:
     {
       MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
 
       if (*aStatus == nsEventStatus_eConsumeNoDefault) {
         break;
       }
 
-      widget::WheelEvent* wheelEvent = static_cast<widget::WheelEvent*>(aEvent);
+      WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent);
       switch (WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent)) {
         case WheelPrefs::ACTION_SCROLL: {
           if (!wheelEvent->deltaX && !wheelEvent->deltaY) {
             break;
           }
           // For scrolling of default action, we should honor the mouse wheel
           // transaction.
           nsIScrollableFrame* scrollTarget =
@@ -5081,17 +5081,17 @@ nsEventStateManager::ClearGlobalActiveCo
 /******************************************************************/
 /* nsEventStateManager::DeltaAccumulator                          */
 /******************************************************************/
 
 void
 nsEventStateManager::DeltaAccumulator::InitLineOrPageDelta(
                                          nsIFrame* aTargetFrame,
                                          nsEventStateManager* aESM,
-                                         widget::WheelEvent* aEvent)
+                                         WheelEvent* aEvent)
 {
   MOZ_ASSERT(aESM);
   MOZ_ASSERT(aEvent);
 
   // Reset if the previous wheel event is too old.
   if (!mLastTime.IsNull()) {
     TimeDuration duration = TimeStamp::Now() - mLastTime;
     if (duration.ToMilliseconds() > nsMouseWheelTransaction::GetTimeoutTime()) {
@@ -5184,17 +5184,17 @@ nsEventStateManager::DeltaAccumulator::R
   mX = mY = 0.0;
   mPendingScrollAmountX = mPendingScrollAmountY = 0.0;
   mHandlingDeltaMode = UINT32_MAX;
   mHandlingPixelOnlyDevice = false;
 }
 
 nsIntPoint
 nsEventStateManager::DeltaAccumulator::ComputeScrollAmountForDefaultAction(
-                       widget::WheelEvent* aEvent,
+                       WheelEvent* aEvent,
                        const nsIntSize& aScrollAmountInDevPixels)
 {
   MOZ_ASSERT(aEvent);
 
   // If the wheel event is line scroll and the delta value is computed from
   // system settings, allow to override the system speed.
   bool allowScrollSpeedOverride =
     (!aEvent->customizedByUserPrefs &&
@@ -5268,39 +5268,39 @@ nsEventStateManager::WheelPrefs::~WheelP
 void
 nsEventStateManager::WheelPrefs::Reset()
 {
   memset(mInit, 0, sizeof(mInit));
 
 }
 
 nsEventStateManager::WheelPrefs::Index
-nsEventStateManager::WheelPrefs::GetIndexFor(widget::WheelEvent* aEvent)
+nsEventStateManager::WheelPrefs::GetIndexFor(WheelEvent* aEvent)
 {
   if (!aEvent) {
     return INDEX_DEFAULT;
   }
 
-  widget::Modifiers modifiers =
-    (aEvent->modifiers & (widget::MODIFIER_ALT |
-                          widget::MODIFIER_CONTROL |
-                          widget::MODIFIER_META |
-                          widget::MODIFIER_SHIFT |
-                          widget::MODIFIER_OS));
+  Modifiers modifiers =
+    (aEvent->modifiers & (MODIFIER_ALT |
+                          MODIFIER_CONTROL |
+                          MODIFIER_META |
+                          MODIFIER_SHIFT |
+                          MODIFIER_OS));
 
   switch (modifiers) {
-    case widget::MODIFIER_ALT:
+    case MODIFIER_ALT:
       return INDEX_ALT;
-    case widget::MODIFIER_CONTROL:
+    case MODIFIER_CONTROL:
       return INDEX_CONTROL;
-    case widget::MODIFIER_META:
+    case MODIFIER_META:
       return INDEX_META;
-    case widget::MODIFIER_SHIFT:
+    case MODIFIER_SHIFT:
       return INDEX_SHIFT;
-    case widget::MODIFIER_OS:
+    case MODIFIER_OS:
       return INDEX_OS;
     default:
       // If two or more modifier keys are pressed, we should use default
       // settings.
       return INDEX_DEFAULT;
   }
 }
 
@@ -5379,18 +5379,17 @@ nsEventStateManager::WheelPrefs::Init(
     actionOverrideX = -1;
   }
   mOverriddenActionsX[aIndex] = (actionOverrideX == -1)
                               ? static_cast<Action>(action)
                               : static_cast<Action>(actionOverrideX);
 }
 
 void
-nsEventStateManager::WheelPrefs::ApplyUserPrefsToDelta(
-                                   widget::WheelEvent* aEvent)
+nsEventStateManager::WheelPrefs::ApplyUserPrefsToDelta(WheelEvent* aEvent)
 {
   Index index = GetIndexFor(aEvent);
   Init(index);
 
   aEvent->deltaX *= mMultiplierX[index];
   aEvent->deltaY *= mMultiplierY[index];
   aEvent->deltaZ *= mMultiplierZ[index];
 
@@ -5407,17 +5406,17 @@ nsEventStateManager::WheelPrefs::ApplyUs
 
   aEvent->customizedByUserPrefs =
     ((mMultiplierX[index] != 1.0) || (mMultiplierY[index] != 1.0) ||
      (mMultiplierZ[index] != 1.0));
 }
 
 void
 nsEventStateManager::WheelPrefs::CancelApplyingUserPrefsFromOverflowDelta(
-                                                   widget::WheelEvent* aEvent)
+                                                   WheelEvent* aEvent)
 {
   Index index = GetIndexFor(aEvent);
   Init(index);
 
   // XXX If the multiplier pref value is negative, the scroll direction was
   //     changed and caused to scroll different direction.  In such case,
   //     this method reverts the sign of overflowDelta.  Does it make widget
   //     happy?  Although, widget can know the pref applied delta values by
@@ -5427,17 +5426,17 @@ nsEventStateManager::WheelPrefs::CancelA
     aEvent->overflowDeltaX /= mMultiplierX[index];
   }
   if (mMultiplierY[index]) {
     aEvent->overflowDeltaY /= mMultiplierY[index];
   }
 }
 
 nsEventStateManager::WheelPrefs::Action
-nsEventStateManager::WheelPrefs::ComputeActionFor(widget::WheelEvent* aEvent)
+nsEventStateManager::WheelPrefs::ComputeActionFor(WheelEvent* aEvent)
 {
   Index index = GetIndexFor(aEvent);
   Init(index);
 
   bool deltaXPreferred =
     (Abs(aEvent->deltaX) > Abs(aEvent->deltaY) &&
      Abs(aEvent->deltaX) > Abs(aEvent->deltaZ));
   Action* actions = deltaXPreferred ? mOverriddenActionsX : mActions;
@@ -5453,38 +5452,38 @@ nsEventStateManager::WheelPrefs::Compute
                                                        ACTION_NONE;
   }
 
   return actions[index];
 }
 
 bool
 nsEventStateManager::WheelPrefs::NeedToComputeLineOrPageDelta(
-                                   widget::WheelEvent* aEvent)
+                                   WheelEvent* aEvent)
 {
   Index index = GetIndexFor(aEvent);
   Init(index);
 
   return (mMultiplierX[index] != 1.0 && mMultiplierX[index] != -1.0) ||
          (mMultiplierY[index] != 1.0 && mMultiplierY[index] != -1.0);
 }
 
 bool
 nsEventStateManager::WheelPrefs::IsOverOnePageScrollAllowedX(
-                                   widget::WheelEvent* aEvent)
+                                   WheelEvent* aEvent)
 {
   Index index = GetIndexFor(aEvent);
   Init(index);
   return Abs(mMultiplierX[index]) >=
            MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
 }
 
 bool
 nsEventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
-                                   widget::WheelEvent* aEvent)
+                                   WheelEvent* aEvent)
 {
   Index index = GetIndexFor(aEvent);
   Init(index);
   return Abs(mMultiplierY[index]) >=
            MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
 }
 
 /******************************************************************/
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -84,17 +84,17 @@ public:
                            nsIFrame* aTargetFrame,
                            nsEventStatus* aStatus);
 
   /**
    * DispatchLegacyMouseScrollEvents() dispatches NS_MOUSE_SCROLL event and
    * NS_MOUSE_PIXEL_SCROLL event for compatiblity with old Gecko.
    */
   void DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
-                                       mozilla::widget::WheelEvent* aEvent,
+                                       mozilla::WheelEvent* aEvent,
                                        nsEventStatus* aStatus);
 
   void NotifyDestroyPresContext(nsPresContext* aPresContext);
   void SetPresContext(nsPresContext* aPresContext);
   void ClearFrameRefs(nsIFrame* aFrame);
 
   nsIFrame* GetEventTarget();
   already_AddRefed<nsIContent> GetEventTargetContent(nsEvent* aEvent);
@@ -352,51 +352,51 @@ protected:
   public:
     static WheelPrefs* GetInstance();
     static void Shutdown();
 
     /**
      * ApplyUserPrefsToDelta() overrides the wheel event's delta values with
      * user prefs.
      */
-    void ApplyUserPrefsToDelta(mozilla::widget::WheelEvent* aEvent);
+    void ApplyUserPrefsToDelta(mozilla::WheelEvent* aEvent);
 
     /**
      * If ApplyUserPrefsToDelta() changed the delta values with customized
      * prefs, the overflowDelta values would be inflated.
      * CancelApplyingUserPrefsFromOverflowDelta() cancels the inflation.
      */
     void CancelApplyingUserPrefsFromOverflowDelta(
-                                    mozilla::widget::WheelEvent* aEvent);
+                                    mozilla::WheelEvent* aEvent);
 
     /**
      * Computes the default action for the aEvent with the prefs.
      */
     enum Action MOZ_ENUM_TYPE(uint8_t)
     {
       ACTION_NONE = 0,
       ACTION_SCROLL,
       ACTION_HISTORY,
       ACTION_ZOOM,
       ACTION_LAST = ACTION_ZOOM
     };
-    Action ComputeActionFor(mozilla::widget::WheelEvent* aEvent);
+    Action ComputeActionFor(mozilla::WheelEvent* aEvent);
 
     /**
      * NeedToComputeLineOrPageDelta() returns if the aEvent needs to be
      * computed the lineOrPageDelta values.
      */
-    bool NeedToComputeLineOrPageDelta(mozilla::widget::WheelEvent* aEvent);
+    bool NeedToComputeLineOrPageDelta(mozilla::WheelEvent* aEvent);
 
     /**
      * IsOverOnePageScrollAllowed*() checks whether wheel scroll amount should
      * be rounded down to the page width/height (false) or not (true).
      */
-    bool IsOverOnePageScrollAllowedX(mozilla::widget::WheelEvent* aEvent);
-    bool IsOverOnePageScrollAllowedY(mozilla::widget::WheelEvent* aEvent);
+    bool IsOverOnePageScrollAllowedX(mozilla::WheelEvent* aEvent);
+    bool IsOverOnePageScrollAllowedY(mozilla::WheelEvent* aEvent);
 
   private:
     WheelPrefs();
     ~WheelPrefs();
 
     static int OnPrefChanged(const char* aPrefName, void* aClosure);
 
     enum Index
@@ -413,17 +413,17 @@ protected:
     /**
      * GetIndexFor() returns the index of the members which should be used for
      * the aEvent.  When only one modifier key of MODIFIER_ALT,
      * MODIFIER_CONTROL, MODIFIER_META, MODIFIER_SHIFT or MODIFIER_OS is
      * pressed, returns the index for the modifier.  Otherwise, this return the
      * default index which is used at either no modifier key is pressed or
      * two or modifier keys are pressed.
      */
-    Index GetIndexFor(mozilla::widget::WheelEvent* aEvent);
+    Index GetIndexFor(mozilla::WheelEvent* aEvent);
 
     /**
      * GetPrefNameBase() returns the base pref name for aEvent.
      * It's decided by GetModifierForPref() which modifier should be used for
      * the aEvent.
      *
      * @param aBasePrefName The result, must be "mousewheel.with_*." or
      *                      "mousewheel.default.".
@@ -466,46 +466,46 @@ protected:
   enum DeltaDirection
   {
     DELTA_DIRECTION_X = 0,
     DELTA_DIRECTION_Y
   };
 
   /**
    * SendLineScrollEvent() dispatches a DOMMouseScroll event for the
-   * widget::WheelEvent.  This method shouldn't be called for non-trusted
+   * WheelEvent.  This method shouldn't be called for non-trusted
    * wheel event because it's not necessary for compatiblity.
    *
    * @param aTargetFrame        The event target of wheel event.
    * @param aEvent              The original Wheel event.
    * @param aStatus             The event status, must not be
    *                            nsEventStatus_eConsumeNoDefault.
    * @param aDelta              The delta value of the event.
    * @param aDeltaDirection     The X/Y direction of dispatching event.
    */
   void SendLineScrollEvent(nsIFrame* aTargetFrame,
-                           mozilla::widget::WheelEvent* aEvent,
+                           mozilla::WheelEvent* aEvent,
                            nsEventStatus* aStatus,
                            int32_t aDelta,
                            DeltaDirection aDeltaDirection);
 
   /**
    * SendPixelScrollEvent() dispatches a MozMousePixelScroll event for the
-   * widget::WheelEvent.  This method shouldn't be called for non-trusted
+   * WheelEvent.  This method shouldn't be called for non-trusted
    * wheel event because it's not necessary for compatiblity.
    *
    * @param aTargetFrame        The event target of wheel event.
    * @param aEvent              The original Wheel event.
    * @param aStatus             The event status, must not be
    *                            nsEventStatus_eConsumeNoDefault.
    * @param aPixelDelta         The delta value of the event.
    * @param aDeltaDirection     The X/Y direction of dispatching event.
    */
   void SendPixelScrollEvent(nsIFrame* aTargetFrame,
-                            mozilla::widget::WheelEvent* aEvent,
+                            mozilla::WheelEvent* aEvent,
                             nsEventStatus* aStatus,
                             int32_t aPixelDelta,
                             DeltaDirection aDeltaDirection);
 
   /**
    * ComputeScrollTarget() returns the scrollable frame which should be
    * scrolled.
    *
@@ -539,40 +539,40 @@ protected:
     // Look for the nearest scrollable ancestor which can be scrollable with
     // aEvent.
     COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS     =
       (PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS | START_FROM_PARENT),
     COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS     =
       (PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS | START_FROM_PARENT)
   };
   nsIScrollableFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
-                                          mozilla::widget::WheelEvent* aEvent,
+                                          mozilla::WheelEvent* aEvent,
                                           ComputeScrollTargetOptions aOptions);
 
   /**
    * GetScrollAmount() returns the scroll amount in app uints of one line or
    * one page.  If the wheel event scrolls a page, returns the page width and
    * height.  Otherwise, returns line height for both its width and height.
    *
    * @param aScrollableFrame    A frame which will be scrolled by the event.
    *                            The result of ComputeScrollTarget() is
    *                            expected for this value.
    *                            This can be nullptr if there is no scrollable
    *                            frame.  Then, this method uses root frame's
    *                            line height or visible area's width and height.
    */
   nsSize GetScrollAmount(nsPresContext* aPresContext,
-                         mozilla::widget::WheelEvent* aEvent,
+                         mozilla::WheelEvent* aEvent,
                          nsIScrollableFrame* aScrollableFrame);
 
   /**
    * DoScrollText() scrolls the scrollable frame for aEvent.
    */
   void DoScrollText(nsIScrollableFrame* aScrollableFrame,
-                    mozilla::widget::WheelEvent* aEvent);
+                    mozilla::WheelEvent* aEvent);
 
   void DoScrollHistory(int32_t direction);
   void DoScrollZoom(nsIFrame *aTargetFrame, int32_t adjustment);
   nsresult GetMarkupDocumentViewer(nsIMarkupDocumentViewer** aMv);
   nsresult ChangeTextSize(int32_t change);
   nsresult ChangeFullZoom(int32_t change);
 
   /**
@@ -602,29 +602,29 @@ protected:
 
     /**
      * InitLineOrPageDelta() stores pixel delta values of WheelEvents which are
      * caused if it's needed.  And if the accumulated delta becomes a
      * line height, sets lineOrPageDeltaX and lineOrPageDeltaY automatically.
      */
     void InitLineOrPageDelta(nsIFrame* aTargetFrame,
                              nsEventStateManager* aESM,
-                             mozilla::widget::WheelEvent* aEvent);
+                             mozilla::WheelEvent* aEvent);
 
     /**
      * Reset() resets all members.
      */
     void Reset();
 
     /**
      * ComputeScrollAmountForDefaultAction() computes the default action's
      * scroll amount in device pixels with mPendingScrollAmount*.
      */
     nsIntPoint ComputeScrollAmountForDefaultAction(
-                 mozilla::widget::WheelEvent* aEvent,
+                 mozilla::WheelEvent* aEvent,
                  const nsIntSize& aScrollAmountInDevPixels);
 
   private:
     DeltaAccumulator() :
       mX(0.0), mY(0.0), mPendingScrollAmountX(0.0), mPendingScrollAmountY(0.0),
       mHandlingDeltaMode(UINT32_MAX), mHandlingPixelOnlyDevice(false)
     {
     }
@@ -758,17 +758,17 @@ private:
   mozilla::LayoutDeviceIntPoint mGestureDownPoint; // screen coordinates
   // The content to use as target if we start a d&d (what we drag).
   nsCOMPtr<nsIContent> mGestureDownContent;
   // The content of the frame where the mouse-down event occurred. It's the same
   // as the target in most cases but not always - for example when dragging
   // an <area> of an image map this is the image. (bug 289667)
   nsCOMPtr<nsIContent> mGestureDownFrameOwner;
   // State of keys when the original gesture-down happened
-  mozilla::widget::Modifiers mGestureModifiers;
+  mozilla::Modifiers mGestureModifiers;
   uint16_t mGestureDownButtons;
 
   nsCOMPtr<nsIContent> mLastLeftMouseDownContent;
   nsCOMPtr<nsIContent> mLastLeftMouseDownContentParent;
   nsCOMPtr<nsIContent> mLastMiddleMouseDownContent;
   nsCOMPtr<nsIContent> mLastMiddleMouseDownContentParent;
   nsCOMPtr<nsIContent> mLastRightMouseDownContent;
   nsCOMPtr<nsIContent> mLastRightMouseDownContentParent;
--- a/content/html/content/crashtests/crashtests.list
+++ b/content/html/content/crashtests/crashtests.list
@@ -43,13 +43,13 @@ load 795221-3.html
 load 795221-4.html
 load 795221-5.xml
 load 798802-1.html
 load 811226.html
 load 819745.html
 pref(dom.experimental_forms,true) load 828472.html
 load 828180.html
 load 837033.html
-pref(dom.experimental_forms_range,true) load 838256-1.html
+load 838256-1.html
 load 862084.html
 load 865147.html
 load 877910.html
 load 903106.html
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -4267,18 +4267,18 @@ HTMLInputElement::ParseAttribute(int32_t
       // XXX ARG!! This is major evilness. ParseAttribute
       // shouldn't set members. Override SetAttr instead
       int32_t newType;
       bool success = aResult.ParseEnumValue(aValue, kInputTypeTable, false);
       if (success) {
         newType = aResult.GetEnumValue();
         if ((IsExperimentalMobileType(newType) &&
              !Preferences::GetBool("dom.experimental_forms", false)) ||
-            (newType == NS_FORM_INPUT_RANGE &&
-             !Preferences::GetBool("dom.experimental_forms_range", false)) ||
+            (newType == NS_FORM_INPUT_NUMBER &&
+             !Preferences::GetBool("dom.forms.number", false)) ||
             (newType == NS_FORM_INPUT_COLOR &&
              !Preferences::GetBool("dom.forms.color", false))) {
           newType = kInputDefaultType->value;
           aResult.SetTo(newType, &aValue);
         }
       } else {
         newType = kInputDefaultType->value;
       }
--- a/content/html/content/src/HTMLLabelElement.cpp
+++ b/content/html/content/src/HTMLLabelElement.cpp
@@ -189,17 +189,17 @@ HTMLLabelElement::PostHandleEvent(nsEven
           //    (For compatibility with IE, we do only left click.  If
           //    we wanted to interpret the HTML spec very narrowly, we
           //    would do nothing.  If we wanted to do something
           //    sensible, we might send more events through like
           //    this.)  See bug 7554, bug 49897, and bug 96813.
           nsEventStatus status = aVisitor.mEventStatus;
           // Ok to use aVisitor.mEvent as parameter because DispatchClickEvent
           // will actually create a new event.
-          widget::EventFlags eventFlags;
+          EventFlags eventFlags;
           eventFlags.mMultipleActionsPrevented = true;
           DispatchClickEvent(aVisitor.mPresContext,
                              static_cast<nsInputEvent*>(aVisitor.mEvent),
                              content, false, &eventFlags, &status);
           // Do we care about the status this returned?  I don't think we do...
           // Don't run another <label> off of this click
           aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
         }
--- a/content/html/content/test/forms/test_experimental_forms_pref.html
+++ b/content/html/content/test/forms/test_experimental_forms_pref.html
@@ -16,27 +16,27 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script type="application/javascript">
 
   var input = document.createElement("input");
 
   SimpleTest.waitForExplicitFinish();
   SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", false]]}, function() {
-    input.type = "number";
-    is(input.type, "text", "input type shouldn't be number when the experimental forms are disabled");
-    is(input.getAttribute('type'), "number", "input 'type' attribute should not change");
+    input.type = "date";
+    is(input.type, "text", "input type shouldn't be date when the experimental forms are disabled");
+    is(input.getAttribute('type'), "date", "input 'type' attribute should not change");
 
     SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms",true]]}, function() {
-      // Change the type of input to text and then back to number, 
+      // Change the type of input to text and then back to date, 
       // so that HTMLInputElement::ParseAttribute gets called with the pref enabled.
       input.type = "text";
-      input.type = "number";
-      is(input.type, "number", "input type should be number when the experimental forms are enabled");
-      is(input.getAttribute('type'), "number", "input 'type' attribute should not change");
+      input.type = "date";
+      is(input.type, "date", "input type should be date when the experimental forms are enabled");
+      is(input.getAttribute('type'), "date", "input 'type' attribute should not change");
     
       SimpleTest.finish();
     });
   });
 
 </script>
 </pre>
 </body>
--- a/content/media/DecoderTraits.cpp
+++ b/content/media/DecoderTraits.cpp
@@ -51,16 +51,20 @@
 #ifdef MOZ_WMF
 #include "WMFDecoder.h"
 #include "WMFReader.h"
 #endif
 #ifdef MOZ_DIRECTSHOW
 #include "DirectShowDecoder.h"
 #include "DirectShowReader.h"
 #endif
+#ifdef MOZ_APPLEMEDIA
+#include "AppleDecoder.h"
+#include "AppleMP3Reader.h"
+#endif
 
 namespace mozilla
 {
 
 template <class String>
 static bool
 CodecListContains(char const *const * aCodecs, const String& aCodec)
 {
@@ -283,16 +287,48 @@ IsWMFSupportedType(const nsACString& aTy
 #ifdef MOZ_DIRECTSHOW
 static bool
 IsDirectShowSupportedType(const nsACString& aType)
 {
   return DirectShowDecoder::GetSupportedCodecs(aType, nullptr);
 }
 #endif
 
+#ifdef MOZ_APPLEMEDIA
+static const char * const gAppleMP3Types[] = {
+  "audio/mp3",
+  "audio/mpeg",
+  nullptr,
+};
+
+static const char * const gAppleMP3Codecs[] = {
+  "mp3",
+  nullptr
+};
+
+static bool
+IsAppleMediaSupportedType(const nsACString& aType,
+                     const char * const ** aCodecs = nullptr)
+{
+  if (MediaDecoder::IsAppleMP3Enabled()
+      && CodecListContains(gAppleMP3Types, aType)) {
+
+    if (aCodecs) {
+      *aCodecs = gAppleMP3Codecs;
+    }
+
+    return true;
+  }
+
+  // TODO MP4
+
+  return false;
+}
+#endif
+
 /* static */
 bool DecoderTraits::ShouldHandleMediaType(const char* aMIMEType)
 {
 #ifdef MOZ_WAVE
   if (IsWaveType(nsDependentCString(aMIMEType))) {
     // We should not return true for Wave types, since there are some
     // Wave codecs actually in use in the wild that we don't support, and
     // we should allow those to be handled by plugins or helper apps.
@@ -366,16 +402,21 @@ DecoderTraits::CanHandleMediaType(const 
     result = CANPLAY_MAYBE;
   }
 #endif
 #ifdef MOZ_DIRECTSHOW
   if (DirectShowDecoder::GetSupportedCodecs(nsDependentCString(aMIMEType), &codecList)) {
     result = CANPLAY_MAYBE;
   }
 #endif
+#ifdef MOZ_APPLEMEDIA
+  if (IsAppleMediaSupportedType(nsDependentCString(aMIMEType), &codecList)) {
+    result = CANPLAY_MAYBE;
+  }
+#endif
 #ifdef MOZ_MEDIA_PLUGINS
   if (MediaDecoder::IsMediaPluginsEnabled() &&
       GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), &codecList))
     result = CANPLAY_MAYBE;
 #endif
   if (result == CANPLAY_NO || !aHaveRequestedCodecs || !codecList) {
     return result;
   }
@@ -468,16 +509,21 @@ DecoderTraits::CreateDecoder(const nsACS
     decoder = new DirectShowDecoder();
   }
 #endif
 #ifdef MOZ_WMF
   if (IsWMFSupportedType(aType)) {
     decoder = new WMFDecoder();
   }
 #endif
+#ifdef MOZ_APPLEMEDIA
+  if (IsAppleMediaSupportedType(aType)) {
+    decoder = new AppleDecoder();
+  }
+#endif
 
   NS_ENSURE_TRUE(decoder != nullptr, nullptr);
   NS_ENSURE_TRUE(decoder->Init(aOwner), nullptr);
 
   return decoder.forget();
 }
 
 /* static */
@@ -528,16 +574,21 @@ MediaDecoderReader* DecoderTraits::Creat
     decoderReader = new DirectShowReader(aDecoder);
   } else
 #endif
 #ifdef MOZ_WMF
   if (IsWMFSupportedType(aType)) {
     decoderReader = new WMFReader(aDecoder);
   } else
 #endif
+#ifdef MOZ_APPLEMEDIA
+  if (IsAppleMediaSupportedType(aType)) {
+    decoderReader = new AppleMP3Reader(aDecoder);
+  } else
+#endif
 #ifdef MOZ_DASH
   // The DASH decoder is not supported.
 #endif
   if (false) {} // dummy if to take care of the dangling else
 
   return decoderReader;
 }
 
@@ -567,12 +618,15 @@ bool DecoderTraits::IsSupportedInVideoDo
 #endif
 #ifdef MOZ_WMF
     (IsWMFSupportedType(aType) &&
      Preferences::GetBool("media.windows-media-foundation.play-stand-alone", true)) ||
 #endif
 #ifdef MOZ_DIRECTSHOW
     IsDirectShowSupportedType(aType) ||
 #endif
+#ifdef MOZ_APPLEMEDIA
+    IsAppleMediaSupportedType(aType) ||
+#endif
     false;
 }
 
 }
--- a/content/media/MP3FrameParser.cpp
+++ b/content/media/MP3FrameParser.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 <algorithm>
 #include "nsMemory.h"
 #include "MP3FrameParser.h"
+#include "VideoUtils.h"
 
 namespace mozilla {
 
 // An ID3Buffer contains data of an ID3v2 header. The supplied buffer must
 // point to an ID3 header and at least the size of ID_HEADER_LENGTH. Run the
 // Parse method to read in the header's values.
 
 class ID3Buffer
@@ -79,16 +80,17 @@ public:
   };
 
   MP3Buffer(const uint8_t* aBuffer, uint32_t aLength)
   : mBuffer(aBuffer),
     mLength(aLength),
     mDurationUs(0),
     mNumFrames(0),
     mBitRateSum(0),
+    mSampleRate(0),
     mFrameSizeSum(0)
   {
     MOZ_ASSERT(mBuffer || !mLength);
   }
 
   nsresult Parse();
 
   int64_t GetDuration() const {
@@ -98,16 +100,20 @@ public:
   int64_t GetNumberOfFrames() const {
     return mNumFrames;
   }
 
   int64_t GetBitRateSum() const {
     return mBitRateSum;
   }
 
+  int16_t GetSampleRate() const {
+    return mSampleRate;
+  }
+
   int64_t GetFrameSizeSum() const {
     return mFrameSizeSum;
   }
 
 private:
 
   enum MP3FrameHeaderField {
     MP3_HDR_FIELD_SYNC,
@@ -128,16 +134,17 @@ private:
   static uint32_t ExtractBits(uint32_t aValue, uint32_t aOffset,
                               uint32_t aBits);
   static uint32_t ExtractFrameHeaderField(uint32_t aHeader,
                                           enum MP3FrameHeaderField aField);
   static uint32_t ExtractFrameHeader(const uint8_t* aBuffer);
   static nsresult DecodeFrameHeader(const uint8_t* aBuffer,
                                     uint32_t* aFrameSize,
                                     uint32_t* aBitRate,
+                                    uint16_t* aSampleRate,
                                     uint64_t* aDuration);
 
   static const uint16_t sBitRate[16];
   static const uint16_t sSampleRate[4];
 
   const uint8_t* mBuffer;
   uint32_t       mLength;
 
@@ -145,16 +152,19 @@ private:
   int64_t mDurationUs;
 
   // The number of frames in the range.
   int64_t mNumFrames;
 
   // The sum of all frame's bit rates.
   int64_t mBitRateSum;
 
+  // The number of audio samples per second
+  int16_t mSampleRate;
+
   // The sum of all frame's sizes in byte.
   int32_t mFrameSizeSum;
 };
 
 const uint16_t MP3Buffer::sBitRate[16] = {
   0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0
 };
 
@@ -202,16 +212,17 @@ uint32_t MP3Buffer::ExtractFrameHeader(c
   return (frameSync == uint32_t(MP3_HDR_CONST_FRAMESYNC)) *
          (version == uint32_t(MP3_HDR_CONST_VERSION)) *
          (layer == uint32_t(MP3_HDR_CONST_LAYER)) * !!bitRate * !!sampleRate * header;
 }
 
 nsresult MP3Buffer::DecodeFrameHeader(const uint8_t* aBuffer,
                                       uint32_t* aFrameSize,
                                       uint32_t* aBitRate,
+                                      uint16_t* aSampleRate,
                                       uint64_t* aDuration)
 {
   uint32_t header = ExtractFrameHeader(aBuffer);
 
   if (!header) {
     return NS_ERROR_INVALID_ARG;
   }
 
@@ -225,45 +236,52 @@ nsresult MP3Buffer::DecodeFrameHeader(co
   *aBitRate = bitRate;
 
   MOZ_ASSERT(aFrameSize);
   *aFrameSize = frameSize;
 
   MOZ_ASSERT(aDuration);
   *aDuration = (uint64_t(MP3_DURATION_CONST) * frameSize) / bitRate;
 
+  MOZ_ASSERT(aSampleRate);
+  *aSampleRate = sampleRate;
+
   return NS_OK;
 }
 
 nsresult MP3Buffer::Parse()
 {
   // We walk over the newly arrived data and sum up the
   // bit rates, sizes, durations, etc. of the contained
   // MP3 frames.
 
   const uint8_t* buffer = mBuffer;
   uint32_t length = mLength;
 
   while (length >= MP3_HEADER_LENGTH) {
 
     uint32_t frameSize;
     uint32_t bitRate;
+    uint16_t sampleRate;
     uint64_t duration;
 
-    nsresult rv = DecodeFrameHeader(buffer, &frameSize, &bitRate, &duration);
+    nsresult rv = DecodeFrameHeader(buffer, &frameSize, &bitRate,
+                                    &sampleRate, &duration);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     mBitRateSum += bitRate;
     mDurationUs += duration;
     ++mNumFrames;
 
     mFrameSizeSum += frameSize;
 
+    mSampleRate = sampleRate;
+
     if (frameSize <= length) {
       length -= frameSize;
     } else {
       length = 0;
     }
 
     buffer += frameSize;
   }
@@ -271,27 +289,34 @@ nsresult MP3Buffer::Parse()
   return NS_OK;
 }
 
 // Some MP3's have large ID3v2 tags, up to 150KB, so we allow lots of
 // skipped bytes to be read, just in case, before we give up and assume
 // we're not parsing an MP3 stream.
 static const uint32_t MAX_SKIPPED_BYTES = 200 * 1024;
 
+// The number of audio samples per MP3 frame. This is constant over all MP3
+// streams. With this constant, the stream's sample rate, and an estimated
+// number of frames in the stream, we can estimate the stream's duration
+// fairly accurately.
+static const uint32_t SAMPLES_PER_FRAME = 1152;
+
 MP3FrameParser::MP3FrameParser(int64_t aLength)
 : mBufferLength(0),
   mLock("MP3FrameParser.mLock"),
   mDurationUs(0),
   mBitRateSum(0),
+  mTotalFrameSize(0),
   mNumFrames(0),
   mOffset(0),
-  mUnhandled(0),
   mLength(aLength),
   mMP3Offset(-1),
   mSkippedBytes(0),
+  mSampleRate(0),
   mIsMP3(MAYBE_MP3)
 { }
 
 nsresult MP3FrameParser::ParseBuffer(const uint8_t* aBuffer,
                                      uint32_t aLength,
                                      int64_t aStreamOffset,
                                      uint32_t* aOutBytesRead)
 {
@@ -324,16 +349,18 @@ nsresult MP3FrameParser::ParseBuffer(con
     MP3Buffer mp3Buffer(buffer, length);
     if (NS_SUCCEEDED(mp3Buffer.Parse())) {
       headersParsed++;
       if (mMP3Offset == -1) {
         mMP3Offset = aStreamOffset + bufferOffset;
       }
       mDurationUs += mp3Buffer.GetDuration();
       mBitRateSum += mp3Buffer.GetBitRateSum();
+      mTotalFrameSize += mp3Buffer.GetFrameSizeSum();
+      mSampleRate = mp3Buffer.GetSampleRate();
       mNumFrames += mp3Buffer.GetNumberOfFrames();
       bufferOffset += mp3Buffer.GetFrameSizeSum();
     } else {
       // No ID3 or MP3 frame header here. Try the next byte.
       ++bufferOffset;
     }
   }
   if (headersParsed == 0) {
@@ -363,17 +390,17 @@ void MP3FrameParser::Parse(const char* a
     return;
   } else if (aOffset < lastChunkEnd) {
     // mOffset is within the new fragment, shorten range.
     aLength -= lastChunkEnd - aOffset;
     buffer += lastChunkEnd - aOffset;
     aOffset = lastChunkEnd;
   } else if (aOffset > lastChunkEnd) {
     // Fragment comes after current position, store difference.
-    mUnhandled += aOffset - lastChunkEnd;
+    mOffset += aOffset - lastChunkEnd;
     mSkippedBytes = 0;
   }
 
   if (mBufferLength > 0) {
     // We have some data which was left over from the last buffer we received.
     // Append to it, so that we have enough data to parse a complete header, and
     // try to parse it.
     uint32_t copyLength = std::min<size_t>(NS_ARRAY_LENGTH(mBuffer)-mBufferLength, aLength);
@@ -423,25 +450,28 @@ void MP3FrameParser::Parse(const char* a
 int64_t MP3FrameParser::GetDuration()
 {
   MutexAutoLock mon(mLock);
 
   if (!mNumFrames) {
     return -1; // Not a single frame decoded yet
   }
 
-  // Compute the duration of the unhandled fragments from
-  // the average bitrate.
-  int64_t avgBitRate = mBitRateSum / mNumFrames;
-  NS_ENSURE_TRUE(avgBitRate > 0, mDurationUs);
+  // Estimate the total number of frames in the file from the average frame
+  // size we've seen so far, and the length of the file.
+  double avgFrameSize = (double)mTotalFrameSize / mNumFrames;
 
-  MOZ_ASSERT(mLength >= mOffset);
-  int64_t unhandled = mUnhandled + (mLength-mOffset);
+  // Need to cut out the header here. Ignore everything up to the first MP3
+  // frames.
+  double estimatedFrames = (double)(mLength - mMP3Offset) / avgFrameSize;
 
-  return mDurationUs + (uint64_t(MP3Buffer::MP3_DURATION_CONST) * unhandled) / avgBitRate;
+  // The duration of each frame is constant over a given stream.
+  double usPerFrame = USECS_PER_S * SAMPLES_PER_FRAME / mSampleRate;
+
+  return estimatedFrames * usPerFrame;
 }
 
 int64_t MP3FrameParser::GetMP3Offset()
 {
   MutexAutoLock mon(mLock);
   return mMP3Offset;
 }
 
--- a/content/media/MP3FrameParser.h
+++ b/content/media/MP3FrameParser.h
@@ -74,36 +74,39 @@ private:
   uint32_t mBufferLength;
 
   // A low-contention lock for protecting the parser results
   Mutex mLock;
 
   // All fields below are protected by mLock
   uint64_t mDurationUs;
   uint64_t mBitRateSum;
+  uint64_t mTotalFrameSize;
   uint64_t mNumFrames;
 
   // Offset of the last data parsed. This is the end offset of the last data
   // block parsed, so it's the start offset we expect to get on the next
   // call to Parse().
   int64_t  mOffset;
 
-  // Count of the number of bytes that the parser hasn't seen so far. This
-  // happens when the stream seeks.
-  int64_t  mUnhandled;
+  // Total length of the stream in bytes.
   int64_t  mLength;
+
   // Offset of first MP3 frame in the bitstream. Has value -1 until the
   // first MP3 frame is found.
   int64_t mMP3Offset;
 
   // Count of bytes that have been parsed but skipped over because we couldn't
   // find a sync pattern or an ID3 header. If this gets too high, we assume
   // the stream either isn't MP3, or is corrupt.
   uint32_t mSkippedBytes;
 
+  // Number of audio samples per second. Fixed through the whole file.
+  uint16_t mSampleRate;
+
   enum eIsMP3 {
     MAYBE_MP3, // We're giving the stream the benefit of the doubt...
     DEFINITELY_MP3, // We've hit at least one ID3 tag or MP3 frame.
     NOT_MP3 // Not found any evidence of the stream being MP3.
   };
 
   eIsMP3 mIsMP3;
 
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -1269,17 +1269,16 @@ void MediaDecoder::SetDuration(double aD
 void MediaDecoder::SetMediaDuration(int64_t aDuration)
 {
   NS_ENSURE_TRUE_VOID(GetStateMachine());
   GetStateMachine()->SetDuration(aDuration);
 }
 
 void MediaDecoder::UpdateEstimatedMediaDuration(int64_t aDuration)
 {
-  MOZ_ASSERT(NS_IsMainThread());
   if (mPlayState <= PLAY_STATE_LOADING) {
     return;
   }
   NS_ENSURE_TRUE_VOID(GetStateMachine());
   GetStateMachine()->UpdateEstimatedDuration(aDuration);
 }
 
 void MediaDecoder::SetMediaSeekable(bool aMediaSeekable) {
@@ -1723,16 +1722,24 @@ MediaDecoder::IsDASHEnabled()
 #ifdef MOZ_WMF
 bool
 MediaDecoder::IsWMFEnabled()
 {
   return WMFDecoder::IsEnabled();
 }
 #endif
 
+#ifdef MOZ_APPLEMEDIA
+bool
+MediaDecoder::IsAppleMP3Enabled()
+{
+  return Preferences::GetBool("media.apple.mp3.enabled");
+}
+#endif
+
 class MediaReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD GetName(nsACString& aName)
   {
     aName.AssignLiteral("media");
--- a/content/media/MediaDecoder.h
+++ b/content/media/MediaDecoder.h
@@ -781,16 +781,20 @@ public:
 #ifdef MOZ_DASH
   static bool IsDASHEnabled();
 #endif
 
 #ifdef MOZ_WMF
   static bool IsWMFEnabled();
 #endif
 
+#ifdef MOZ_APPLEMEDIA
+  static bool IsAppleMP3Enabled();
+#endif
+
   // Schedules the state machine to run one cycle on the shared state
   // machine thread. Main thread only.
   nsresult ScheduleStateMachineThread();
 
   struct Statistics {
     // Estimate of the current playback rate (bytes/second).
     double mPlaybackRate;
     // Estimate of the current download rate (bytes/second). This
--- a/content/media/TextTrack.cpp
+++ b/content/media/TextTrack.cpp
@@ -2,25 +2,28 @@
 /* vim:set ts=2 sw=2 et tw=78: */
 /* 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 "mozilla/dom/TextTrack.h"
 #include "mozilla/dom/TextTrackBinding.h"
 #include "mozilla/dom/TextTrackCueList.h"
+#include "mozilla/dom/TextTrackRegion.h"
+#include "mozilla/dom/TextTrackRegionList.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED_3(TextTrack,
+NS_IMPL_CYCLE_COLLECTION_INHERITED_4(TextTrack,
                                      nsDOMEventTargetHelper,
                                      mParent,
                                      mCueList,
-                                     mActiveCueList)
+                                     mActiveCueList,
+                                     mRegionList)
 
 NS_IMPL_ADDREF_INHERITED(TextTrack, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(TextTrack, nsDOMEventTargetHelper)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TextTrack)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 TextTrack::TextTrack(nsISupports* aParent,
                      TextTrackKind aKind,
@@ -28,26 +31,28 @@ TextTrack::TextTrack(nsISupports* aParen
                      const nsAString& aLanguage)
   : mParent(aParent)
   , mKind(aKind)
   , mLabel(aLabel)
   , mLanguage(aLanguage)
   , mMode(TextTrackMode::Hidden)
   , mCueList(new TextTrackCueList(aParent))
   , mActiveCueList(new TextTrackCueList(aParent))
+  , mRegionList(new TextTrackRegionList(aParent))
 {
   SetIsDOMBinding();
 }
 
 TextTrack::TextTrack(nsISupports* aParent)
   : mParent(aParent)
   , mKind(TextTrackKind::Subtitles)
   , mMode(TextTrackMode::Disabled)
   , mCueList(new TextTrackCueList(aParent))
   , mActiveCueList(new TextTrackCueList(aParent))
+  , mRegionList(new TextTrackRegionList(aParent))
 {
   SetIsDOMBinding();
 }
 
 void
 TextTrack::Update(double aTime)
 {
   mCueList->Update(aTime);
@@ -80,10 +85,33 @@ TextTrack::RemoveCue(TextTrackCue& aCue)
 }
 
 void
 TextTrack::CueChanged(TextTrackCue& aCue)
 {
   //XXX: Implement Cue changed. Bug 867823.
 }
 
+void
+TextTrack::AddRegion(TextTrackRegion& aRegion)
+{
+  TextTrackRegion* region = mRegionList->GetRegionById(aRegion.Id());
+  if (!region) {
+    mRegionList->AddTextTrackRegion(&aRegion);
+    return;
+  }
+
+  region->CopyValues(aRegion);
+}
+
+void
+TextTrack::RemoveRegion(const TextTrackRegion& aRegion, ErrorResult& aRv)
+{
+  if (!mRegionList->GetRegionById(aRegion.Id())) {
+    aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
+    return;
+  }
+
+  mRegionList->RemoveTextTrackRegion(aRegion);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/content/media/TextTrack.h
+++ b/content/media/TextTrack.h
@@ -13,16 +13,18 @@
 #include "nsDOMEventTargetHelper.h"
 #include "nsString.h"
 
 namespace mozilla {
 namespace dom {
 
 class TextTrackCue;
 class TextTrackCueList;
+class TextTrackRegion;
+class TextTrackRegionList;
 
 class TextTrack MOZ_FINAL : public nsDOMEventTargetHelper
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TextTrack, nsDOMEventTargetHelper)
 
   TextTrack(nsISupports* aParent);
@@ -77,16 +79,27 @@ public:
   TextTrackCueList* GetActiveCues() const
   {
     if (mMode == TextTrackMode::Disabled) {
       return nullptr;
     }
     return mActiveCueList;
   }
 
+  TextTrackRegionList* GetRegions() const
+  {
+    if (mMode != TextTrackMode::Disabled) {
+      return mRegionList;
+    }
+    return nullptr;
+  }
+
+  void AddRegion(TextTrackRegion& aRegion);
+  void RemoveRegion(const TextTrackRegion& aRegion, ErrorResult& aRv);
+
   // Time is in seconds.
   void Update(double aTime);
 
   void AddCue(TextTrackCue& aCue);
   void RemoveCue(TextTrackCue& aCue);
   void CueChanged(TextTrackCue& aCue);
 
   IMPL_EVENT_HANDLER(cuechange)
@@ -98,14 +111,15 @@ private:
   nsString mLabel;
   nsString mLanguage;
   nsString mType;
   nsString mId;
   TextTrackMode mMode;
 
   nsRefPtr<TextTrackCueList> mCueList;
   nsRefPtr<TextTrackCueList> mActiveCueList;
+  nsRefPtr<TextTrackRegionList> mRegionList;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_TextTrack_h
new file mode 100644
--- /dev/null
+++ b/content/media/TextTrackRegion.cpp
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 et tw=78: */
+/* 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 "mozilla/dom/TextTrack.h"
+#include "mozilla/dom/TextTrackRegion.h"
+#include "mozilla/dom/TextTrackRegionBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(TextTrackRegion, mParent, mTrack)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(TextTrackRegion)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(TextTrackRegion)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextTrackRegion)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+JSObject*
+TextTrackRegion::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return TextTrackRegionBinding::Wrap(aCx, aScope, this);
+}
+
+already_AddRefed<TextTrackRegion>
+TextTrackRegion::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
+  if (!window) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<TextTrackRegion> region = new TextTrackRegion(aGlobal.GetAsSupports());
+  return region.forget();
+}
+
+TextTrackRegion::TextTrackRegion(nsISupports* aGlobal)
+  : mParent(aGlobal)
+  , mWidth(100)
+  , mLines(3)
+  , mRegionAnchorX(0)
+  , mRegionAnchorY(100)
+  , mViewportAnchorX(0)
+  , mViewportAnchorY(100)
+{
+  mTrack = new TextTrack(aGlobal);
+  SetIsDOMBinding();
+}
+
+void
+TextTrackRegion::CopyValues(TextTrackRegion& aRegion)
+{
+  mWidth = aRegion.Width();
+  mLines = aRegion.Lines();
+  mRegionAnchorX = aRegion.RegionAnchorX();
+  mRegionAnchorY = aRegion.RegionAnchorY();
+  mViewportAnchorX = aRegion.ViewportAnchorX();
+  mViewportAnchorY = aRegion.ViewportAnchorY();
+  mScroll = aRegion.Scroll();
+}
+
+} //namespace dom
+} //namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/content/media/TextTrackRegion.h
@@ -0,0 +1,192 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 et tw=78: */
+/* 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_TextTrackRegion_h
+#define mozilla_dom_TextTrackRegion_h
+
+#include "nsAutoPtr.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsString.h"
+#include "nsWrapperCache.h"
+#include "mozilla/ErrorResult.h"
+
+namespace mozilla {
+namespace dom {
+
+class GlobalObject;
+class TextTrack;
+
+class TextTrackRegion MOZ_FINAL : public nsISupports,
+                                  public nsWrapperCache
+{
+public:
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TextTrackRegion)
+
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+  nsISupports* GetParentObject() const
+  {
+    return mParent;
+  }
+
+  TextTrackRegion(nsISupports* aGlobal);
+
+  /** WebIDL Methods. */
+
+  static already_AddRefed<TextTrackRegion>
+  Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
+
+  TextTrack* GetTrack() const
+  {
+    return mTrack;
+  }
+
+  void  GetId(nsAString& aId) const
+  {
+    aId = mId;
+  }
+
+  void SetId(const nsAString& aId)
+  {
+    mId = aId;
+  }
+
+  double Lines() const
+  {
+    return mLines;
+  }
+
+  void SetLines(double aLines)
+  {
+    mLines = aLines;
+  }
+
+  double Width() const
+  {
+    return mWidth;
+  }
+
+  void SetWidth(double aWidth, ErrorResult& aRv)
+  {
+    if (!InvalidValue(aWidth, aRv)) {
+      mWidth = aWidth;
+    }
+  }
+
+  double RegionAnchorX() const
+  {
+    return mRegionAnchorX;
+  }
+
+  void SetRegionAnchorX(double aVal, ErrorResult& aRv)
+  {
+    if (!InvalidValue(aVal, aRv)) {
+      mRegionAnchorX = aVal;
+    }
+  }
+
+  double RegionAnchorY() const
+  {
+    return mRegionAnchorY;
+  }
+
+  void SetRegionAnchorY(double aVal, ErrorResult& aRv)
+  {
+    if (!InvalidValue(aVal, aRv)) {
+      mRegionAnchorY = aVal;
+    }
+  }
+
+  double ViewportAnchorX() const
+  {
+    return mViewportAnchorX;
+  }
+
+  void SetViewportAnchorX(double aVal, ErrorResult& aRv)
+  {
+    if (!InvalidValue(aVal, aRv)) {
+      mViewportAnchorX = aVal;
+    }
+  }
+
+  double ViewportAnchorY() const
+  {
+    return mViewportAnchorY;
+  }
+
+  void SetViewportAnchorY(double aVal, ErrorResult& aRv)
+  {
+    if (!InvalidValue(aVal, aRv)) {
+      mViewportAnchorY = aVal;
+    }
+  }
+
+  void GetScroll(nsAString& aScroll) const
+  {
+    aScroll = mScroll;
+  }
+
+  void SetScroll(const nsAString& aScroll, ErrorResult& aRv)
+  {
+    if (!aScroll.EqualsLiteral("") && !aScroll.EqualsLiteral("up")) {
+      aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+      return;
+    }
+
+    mScroll = aScroll;
+  }
+
+  /** end WebIDL Methods. */
+
+  // Helper to aid copying of a given TextTrackRegion's width, lines,
+  // anchor, viewport and scroll values.
+  void CopyValues(TextTrackRegion& aRegion);
+
+  // -----helpers-------
+  const nsAString& Scroll() const
+  {
+    return mScroll;
+  }
+
+  const nsAString& Id() const
+  {
+    return mId;
+  }
+
+
+private:
+  nsCOMPtr<nsISupports> mParent;
+  nsRefPtr<TextTrack> mTrack;
+  nsString mId;
+  double mWidth;
+  long mLines;
+  double mRegionAnchorX;
+  double mRegionAnchorY;
+  double mViewportAnchorX;
+  double mViewportAnchorY;
+  nsString mScroll;
+
+  // Helper to ensure new value is in the range: 0.0% - 100.0%; throws
+  // an IndexSizeError otherwise.
+  inline bool InvalidValue(double aValue, ErrorResult& aRv)
+  {
+    if(aValue < 0.0  || aValue > 100.0) {
+      aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+      return true;
+    }
+
+    return false;
+  }
+
+};
+
+} //namespace dom
+} //namespace mozilla
+
+#endif //mozilla_dom_TextTrackRegion_h
new file mode 100644
--- /dev/null
+++ b/content/media/TextTrackRegionList.cpp
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; 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/. */
+
+#include "mozilla/dom/TextTrackRegion.h"
+#include "mozilla/dom/TextTrackRegionList.h"
+#include "mozilla/dom/TextTrackRegionListBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(TextTrackRegionList,
+                                        mParent,
+                                        mTextTrackRegions)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(TextTrackRegionList)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(TextTrackRegionList)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextTrackRegionList)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+JSObject*
+TextTrackRegionList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return TextTrackRegionListBinding::Wrap(aCx, aScope, this);
+}
+
+TextTrackRegionList::TextTrackRegionList(nsISupports* aGlobal)
+  : mParent(aGlobal)
+{
+  SetIsDOMBinding();
+}
+
+TextTrackRegion*
+TextTrackRegionList::IndexedGetter(uint32_t aIndex, bool& aFound)
+{
+  aFound = aIndex < mTextTrackRegions.Length();
+  return aFound ? mTextTrackRegions[aIndex] : nullptr;
+}
+
+TextTrackRegion*
+TextTrackRegionList::GetRegionById(const nsAString& aId)
+{
+  if (aId.IsEmpty()) {
+    return nullptr;
+  }
+
+  for (uint32_t i = 0; i < Length(); ++i) {
+    if (aId.Equals(mTextTrackRegions[i]->Id())) {
+      return mTextTrackRegions[i];
+    }
+  }
+
+  return nullptr;
+}
+
+void
+TextTrackRegionList::AddTextTrackRegion(TextTrackRegion* aRegion)
+{
+  mTextTrackRegions.AppendElement(aRegion);
+}
+
+void
+TextTrackRegionList::RemoveTextTrackRegion(const TextTrackRegion& aRegion)
+{
+  mTextTrackRegions.RemoveElement(&aRegion);
+}
+
+} //namespace dom
+} //namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/media/TextTrackRegionList.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 et tw=78: */
+/* 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_TextTrackRegionList_h
+#define mozilla_dom_TextTrackRegionList_h
+
+#include "nsAutoPtr.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsTArray.h"
+#include "nsWrapperCache.h"
+
+namespace mozilla {
+namespace dom {
+
+class TextTrackRegion;
+
+class TextTrackRegionList MOZ_FINAL : public nsISupports,
+                                      public nsWrapperCache
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TextTrackRegionList)
+
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+  TextTrackRegionList(nsISupports* aGlobal);
+
+  nsISupports* GetParentObject() const
+  {
+    return mParent;
+  }
+
+  /** WebIDL Methods. */
+  uint32_t Length() const
+  {
+    return mTextTrackRegions.Length();
+  }
+
+  TextTrackRegion* IndexedGetter(uint32_t aIndex, bool& aFound);
+
+  TextTrackRegion* GetRegionById(const nsAString& aId);
+
+  /** end WebIDL Methods. */
+
+  void AddTextTrackRegion(TextTrackRegion* aRegion);
+
+  void RemoveTextTrackRegion(const TextTrackRegion& aRegion);
+
+private:
+  nsCOMPtr<nsISupports> mParent;
+  nsTArray<nsRefPtr<TextTrackRegion> > mTextTrackRegions;
+};
+
+} //namespace dom
+} //namespace mozilla
+
+#endif //mozilla_dom_TextTrackRegionList_h
new file mode 100644
--- /dev/null
+++ b/content/media/apple/AppleDecoder.cpp
@@ -0,0 +1,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/. */
+
+#include "AppleDecoder.h"
+#include "AppleMP3Reader.h"
+
+#include "MediaDecoderStateMachine.h"
+
+namespace mozilla {
+
+AppleDecoder::AppleDecoder()
+  : MediaDecoder()
+{
+}
+
+MediaDecoder *
+AppleDecoder::Clone()
+{
+  return new AppleDecoder();
+}
+
+MediaDecoderStateMachine *
+AppleDecoder::CreateStateMachine()
+{
+  // TODO MP4
+  return new MediaDecoderStateMachine(this, new AppleMP3Reader(this));
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/media/apple/AppleDecoder.h
@@ -0,0 +1,24 @@
+/* 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 __AppleDecoder_h__
+#define __AppleDecoder_h__
+
+#include "MediaDecoder.h"
+
+namespace mozilla {
+
+class AppleDecoder : public MediaDecoder
+{
+public:
+  AppleDecoder();
+
+  virtual MediaDecoder* Clone() MOZ_OVERRIDE;
+  virtual MediaDecoderStateMachine* CreateStateMachine() MOZ_OVERRIDE;
+
+};
+
+}
+
+#endif // __AppleDecoder_h__
new file mode 100644
--- /dev/null
+++ b/content/media/apple/AppleMP3Reader.cpp
@@ -0,0 +1,533 @@
+/* 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 "AppleMP3Reader.h"
+
+#include "nsISeekableStream.h"
+#include "MediaDecoder.h"
+
+// Number of bytes we will read and pass to the audio parser in each
+// |DecodeAudioData| call.
+#define AUDIO_READ_BYTES 4096
+
+// Maximum number of audio frames we will accept from the audio decoder in one
+// go.
+#define MAX_AUDIO_FRAMES 4096
+
+namespace mozilla {
+
+#ifdef PR_LOGGING
+extern PRLogModuleInfo* gMediaDecoderLog;
+#define LOGE(...) PR_LOG(gMediaDecoderLog, PR_LOG_ERROR, (__VA_ARGS__))
+#define LOGW(...) PR_LOG(gMediaDecoderLog, PR_LOG_WARNING, (__VA_ARGS__))
+#define LOGD(...) PR_LOG(gMediaDecoderLog, PR_LOG_DEBUG, (__VA_ARGS__))
+#else
+#define LOGE(...)
+#define LOGW(...)
+#define LOGD(...)
+#endif
+
+#define PROPERTY_ID_FORMAT "%c%c%c%c"
+#define PROPERTY_ID_PRINT(x) ((x) >> 24), \
+                             ((x) >> 16) & 0xff, \
+                             ((x) >> 8) & 0xff, \
+                             (x) & 0xff
+
+AppleMP3Reader::AppleMP3Reader(AbstractMediaDecoder *aDecoder)
+  : MediaDecoderReader(aDecoder)
+  , mStreamReady(false)
+  , mAudioFramesPerCompressedPacket(0)
+  , mCurrentAudioFrame(0)
+  , mAudioChannels(0)
+  , mAudioSampleRate(0)
+  , mAudioFileStream(nullptr)
+  , mAudioConverter(nullptr)
+  , mMP3FrameParser(mDecoder->GetResource()->GetLength())
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread");
+}
+
+AppleMP3Reader::~AppleMP3Reader()
+{
+  MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread");
+}
+
+
+/*
+ * The Apple audio decoding APIs are very callback-happy. When the parser has
+ * some metadata, it will call back to here.
+ */
+static void _AudioMetadataCallback(void *aThis,
+                                   AudioFileStreamID aFileStream,
+                                   AudioFileStreamPropertyID aPropertyID,
+                                   UInt32 *aFlags)
+{
+  ((AppleMP3Reader*)aThis)->AudioMetadataCallback(aFileStream, aPropertyID,
+                                                  aFlags);
+}
+
+/*
+ * Similar to above, this is called when the parser has enough data to parse
+ * one or more samples.
+ */
+static void _AudioSampleCallback(void *aThis,
+                                 UInt32 aNumBytes, UInt32 aNumPackets,
+                                 const void *aData,
+                                 AudioStreamPacketDescription *aPackets)
+{
+  ((AppleMP3Reader*)aThis)->AudioSampleCallback(aNumBytes, aNumPackets,
+                                                aData, aPackets);
+}
+
+
+/*
+ * If we're not at end of stream, read |aNumBytes| from the media resource,
+ * put it in |aData|, and return true.
+ * Otherwise, put as much data as is left into |aData|, set |aNumBytes| to the
+ * amount of data we have left, and return false.
+ *
+ * This function also calls NotifyBytesConsumed() on the media resource and
+ * passes the read data on to the MP3 frame parser for stream duration
+ * estimation.
+ */
+nsresult
+AppleMP3Reader::ReadAndNotify(uint32_t *aNumBytes, char *aData)
+{
+  MediaResource *resource = mDecoder->GetResource();
+
+  uint64_t offset = resource->Tell();
+
+  // Loop until we have all the data asked for, or we've reached EOS
+  uint32_t totalBytes = 0;
+  uint32_t numBytes;
+  do {
+    uint32_t bytesWanted = *aNumBytes - totalBytes;
+    nsresult rv = resource->Read(aData + totalBytes, bytesWanted, &numBytes);
+    totalBytes += numBytes;
+
+    if (NS_FAILED(rv)) {
+      *aNumBytes = 0;
+      return NS_ERROR_FAILURE;
+    }
+  } while(totalBytes < *aNumBytes && numBytes);
+
+  mDecoder->NotifyBytesConsumed(totalBytes);
+
+  // Pass the buffer to the MP3 frame parser to improve our duration estimate.
+  if (mMP3FrameParser.IsMP3()) {
+    mMP3FrameParser.Parse(aData, totalBytes, offset);
+    uint64_t duration = mMP3FrameParser.GetDuration();
+    if (duration != mDuration) {
+      LOGD("Updating media duration to %lluus\n", duration);
+      mDuration = duration;
+      ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+      mDecoder->UpdateEstimatedMediaDuration(duration);
+    }
+  }
+
+  *aNumBytes = totalBytes;
+
+  // We will have read some data in the last iteration iff we filled the buffer.
+  // XXX Maybe return a better value than NS_ERROR_FAILURE?
+  return numBytes ? NS_OK : NS_ERROR_FAILURE;
+}
+
+nsresult
+AppleMP3Reader::Init(MediaDecoderReader* aCloneDonor)
+{
+  AudioFileTypeID fileType = kAudioFileMP3Type;
+
+  OSStatus rv = AudioFileStreamOpen(this,
+                                    _AudioMetadataCallback,
+                                    _AudioSampleCallback,
+                                    fileType,
+                                    &mAudioFileStream);
+
+  if (rv) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+
+struct PassthroughUserData {
+  AppleMP3Reader *mReader;
+  UInt32 mNumPackets;
+  UInt32 mDataSize;
+  const void *mData;
+  AudioStreamPacketDescription *mPacketDesc;
+  bool mDone;
+};
+
+// Error value we pass through the decoder to signal that nothing has gone wrong
+// during decoding, but more data is needed.
+const UInt32 kNeedMoreData = 'MOAR';
+
+/*
+ * This function is called from |AudioConverterFillComplexBuffer|, which is
+ * called from |AudioSampleCallback| below, which in turn is called by
+ * |AudioFileStreamParseBytes|, which is called by |DecodeAudioData|.
+ *
+ * Mercifully, this is all synchronous.
+ *
+ * This callback is run when the AudioConverter (decoder) wants more MP3 packets
+ * to decode.
+ */
+/* static */ OSStatus
+AppleMP3Reader::PassthroughInputDataCallback(AudioConverterRef aAudioConverter,
+                                             UInt32 *aNumDataPackets /* in/out */,
+                                             AudioBufferList *aData /* in/out */,
+                                             AudioStreamPacketDescription **aPacketDesc,
+                                             void *aUserData)
+{
+  PassthroughUserData *userData = (PassthroughUserData *)aUserData;
+  if (userData->mDone) {
+    // We make sure this callback is run _once_, with all the data we received
+    // from |AudioFileStreamParseBytes|. When we return an error, the decoder
+    // simply passes the return value on to the calling method,
+    // |AudioSampleCallback|; and flushes all of the audio frames it had
+    // buffered. It does not change the decoder's state.
+    LOGD("requested too much data; returning\n");
+    *aNumDataPackets = 0;
+    return kNeedMoreData;
+  }
+
+  userData->mDone = true;
+
+  LOGD("AudioConverter wants %u packets of audio data\n", *aNumDataPackets);
+
+  *aNumDataPackets = userData->mNumPackets;
+  *aPacketDesc = userData->mPacketDesc;
+
+  aData->mBuffers[0].mNumberChannels = userData->mReader->mAudioChannels;
+  aData->mBuffers[0].mDataByteSize = userData->mDataSize;
+  aData->mBuffers[0].mData = const_cast<void *>(userData->mData);
+
+  return 0;
+}
+
+/*
+ * This callback is called when |AudioFileStreamParseBytes| has enough data to
+ * extract one or more MP3 packets.
+ */
+void
+AppleMP3Reader::AudioSampleCallback(UInt32 aNumBytes,
+                                    UInt32 aNumPackets,
+                                    const void *aData,
+                                    AudioStreamPacketDescription *aPackets)
+{
+  LOGD("got %u bytes, %u packets\n", aNumBytes, aNumPackets);
+
+  // 1 frame per packet * num channels * 32-bit float
+  uint32_t decodedSize = MAX_AUDIO_FRAMES * mAudioChannels * 4;
+
+  // descriptions for _decompressed_ audio packets. ignored.
+  nsAutoArrayPtr<AudioStreamPacketDescription>
+    packets(new AudioStreamPacketDescription[MAX_AUDIO_FRAMES]);
+
+  // This API insists on having MP3 packets spoon-fed to it from a callback.
+  // This structure exists only to pass our state and the result of the parser
+  // on to the callback above.
+  PassthroughUserData userData = { this, aNumPackets, aNumBytes, aData, aPackets, false };
+
+  do {
+    // Decompressed audio buffer
+    nsAutoArrayPtr<uint8_t> decoded(new uint8_t[decodedSize]);
+
+    AudioBufferList decBuffer;
+    decBuffer.mNumberBuffers = 1;
+    decBuffer.mBuffers[0].mNumberChannels = mAudioChannels;
+    decBuffer.mBuffers[0].mDataByteSize = decodedSize;
+    decBuffer.mBuffers[0].mData = decoded.get();
+
+    // in: the max number of packets we can handle from the decoder.
+    // out: the number of packets the decoder is actually returning.
+    UInt32 numFrames = MAX_AUDIO_FRAMES;
+
+    OSStatus rv = AudioConverterFillComplexBuffer(mAudioConverter,
+                                                  PassthroughInputDataCallback,
+                                                  &userData,
+                                                  &numFrames /* in/out */,
+                                                  &decBuffer,
+                                                  packets.get());
+
+    if (rv && rv != kNeedMoreData) {
+      LOGE("Error decoding audio stream: %x\n", rv);
+      break;
+    }
+
+    int64_t time = FramesToUsecs(mCurrentAudioFrame, mAudioSampleRate).value();
+    int64_t duration = FramesToUsecs(numFrames, mAudioSampleRate).value();
+
+    LOGD("pushed audio at time %lfs; duration %lfs\n",
+         (double)time / USECS_PER_S, (double)duration / USECS_PER_S);
+
+    AudioData *audio = new AudioData(mDecoder->GetResource()->Tell(),
+                                     time, duration, numFrames,
+                                     reinterpret_cast<AudioDataValue *>(decoded.forget()),
+                                     mAudioChannels);
+    mAudioQueue.Push(audio);
+
+    mCurrentAudioFrame += numFrames;
+
+    if (rv == kNeedMoreData) {
+      // No error; we just need more data.
+      LOGD("FillComplexBuffer out of data\n");
+      break;
+    }
+  } while (true);
+}
+
+bool
+AppleMP3Reader::DecodeAudioData()
+{
+  MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread");
+
+  // Read AUDIO_READ_BYTES if we can
+  char bytes[AUDIO_READ_BYTES];
+  uint32_t numBytes = AUDIO_READ_BYTES;
+
+  nsresult readrv = ReadAndNotify(&numBytes, bytes);
+
+  // This function calls |AudioSampleCallback| above, synchronously, when it
+  // finds compressed MP3 frame.
+  OSStatus rv = AudioFileStreamParseBytes(mAudioFileStream,
+                                          numBytes,
+                                          bytes,
+                                          0 /* flags */);
+
+  if (NS_FAILED(readrv)) {
+    mAudioQueue.Finish();
+    return false;
+  }
+
+  // DataUnavailable just means there wasn't enough data to demux anything.
+  // We should have more to push into the demuxer next time we're called.
+  if (rv && rv != kAudioFileStreamError_DataUnavailable) {
+    LOGE("AudioFileStreamParseBytes returned unknown error %x", rv);
+    return false;
+  }
+
+  return true;
+}
+
+bool
+AppleMP3Reader::DecodeVideoFrame(bool &aKeyframeSkip,
+                                 int64_t aTimeThreshold)
+{
+  MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread");
+  return false;
+}
+
+
+bool
+AppleMP3Reader::HasAudio()
+{
+  MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread");
+  return mStreamReady;
+}
+
+bool
+AppleMP3Reader::HasVideo()
+{
+  MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread");
+  return false;
+}
+
+
+/*
+ * Query the MP3 parser for a piece of metadata.
+ */
+static nsresult
+GetProperty(AudioFileStreamID aAudioFileStream,
+            AudioFileStreamPropertyID aPropertyID, void *aData)
+{
+  UInt32 size;
+  Boolean writeable;
+  OSStatus rv = AudioFileStreamGetPropertyInfo(aAudioFileStream, aPropertyID,
+                                               &size, &writeable);
+
+  if (rv) {
+    LOGW("Couldn't get property " PROPERTY_ID_FORMAT "\n",
+         PROPERTY_ID_PRINT(aPropertyID));
+    return NS_ERROR_FAILURE;
+  }
+
+  rv = AudioFileStreamGetProperty(aAudioFileStream, aPropertyID,
+                                  &size, aData);
+
+  return NS_OK;
+}
+
+
+nsresult
+AppleMP3Reader::ReadMetadata(VideoInfo* aInfo,
+                             MetadataTags** aTags)
+{
+  MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread");
+
+  *aTags = nullptr;
+
+  /*
+   * Feed bytes into the parser until we have all the metadata we need to
+   * set up the decoder. When the parser has enough data, it will
+   * synchronously call back to |AudioMetadataCallback| below.
+   */
+  OSStatus rv;
+  nsresult readrv;
+  do {
+    char bytes[AUDIO_READ_BYTES];
+    uint32_t numBytes = AUDIO_READ_BYTES;
+    readrv = ReadAndNotify(&numBytes, bytes);
+
+    rv = AudioFileStreamParseBytes(mAudioFileStream,
+                                   numBytes,
+                                   bytes,
+                                   0 /* flags */);
+
+    // We have to do our decoder setup from the callback. When it's done it will
+    // set mStreamReady.
+  } while (!mStreamReady && !rv && NS_SUCCEEDED(readrv));
+
+  if (rv) {
+    LOGE("Error decoding audio stream metadata\n");
+    return NS_ERROR_FAILURE;
+  }
+
+  if (!mAudioConverter) {
+    LOGE("Failed to setup the AudioToolbox audio decoder\n");
+    return NS_ERROR_FAILURE;
+  }
+
+  aInfo->mAudioRate = mAudioSampleRate;
+  aInfo->mAudioChannels = mAudioChannels;
+  aInfo->mHasAudio = mStreamReady;
+
+  {
+    ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+    mDecoder->SetMediaDuration(mDuration);
+  }
+
+  return NS_OK;
+}
+
+
+void
+AppleMP3Reader::AudioMetadataCallback(AudioFileStreamID aFileStream,
+                                      AudioFileStreamPropertyID aPropertyID,
+                                      UInt32 *aFlags)
+{
+  if (aPropertyID == kAudioFileStreamProperty_ReadyToProducePackets) {
+    /*
+     * The parser is ready to send us packets of MP3 audio.
+     *
+     * We need to set the decoder up here, because if
+     * |AudioFileStreamParseBytes| has enough audio data, then it will call
+     * |AudioSampleCallback| before we get back to |ReadMetadata|.
+     */
+    SetupDecoder();
+    mStreamReady = true;
+  }
+}
+
+
+void
+AppleMP3Reader::SetupDecoder()
+{
+  // Get input format description from demuxer
+  AudioStreamBasicDescription inputFormat, outputFormat;
+  GetProperty(mAudioFileStream, kAudioFileStreamProperty_DataFormat, &inputFormat);
+
+  outputFormat = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+  // Set output format
+#if defined(MOZ_SAMPLE_TYPE_FLOAT32)
+  outputFormat.mBitsPerChannel = 32;
+  outputFormat.mFormatFlags =
+    kLinearPCMFormatFlagIsFloat |
+    0;
+#else
+#error Unknown audio sample type
+#endif
+
+  mAudioSampleRate = outputFormat.mSampleRate = inputFormat.mSampleRate;
+  mAudioChannels
+    = outputFormat.mChannelsPerFrame = inputFormat.mChannelsPerFrame;
+  mAudioFramesPerCompressedPacket = inputFormat.mFramesPerPacket;
+
+  outputFormat.mFormatID = kAudioFormatLinearPCM;
+
+  // Set up the decoder so it gives us one sample per frame; this way, it will
+  // pass us all the samples it has in one go. Also makes it much easier to
+  // deinterlace.
+  outputFormat.mFramesPerPacket = 1;
+  outputFormat.mBytesPerPacket = outputFormat.mBytesPerFrame
+    = outputFormat.mChannelsPerFrame * outputFormat.mBitsPerChannel / 8;
+
+  OSStatus rv = AudioConverterNew(&inputFormat,
+                                  &outputFormat,
+                                  &mAudioConverter);
+
+  if (rv) {
+    LOGE("Error constructing audio format converter: %x\n", rv);
+    mAudioConverter = nullptr;
+    return;
+  }
+}
+
+
+nsresult
+AppleMP3Reader::Seek(int64_t aTime,
+                     int64_t aStartTime,
+                     int64_t aEndTime,
+                     int64_t aCurrentTime)
+{
+  MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread");
+  NS_ASSERTION(aStartTime < aEndTime,
+               "Seeking should happen over a positive range");
+
+  // Find the exact frame/packet that contains |aTime|.
+  mCurrentAudioFrame = aTime * mAudioSampleRate / USECS_PER_S;
+  SInt64 packet = mCurrentAudioFrame / mAudioFramesPerCompressedPacket;
+
+  // |AudioFileStreamSeek| will pass back through |byteOffset| the byte offset
+  // into the stream it expects next time it reads.
+  SInt64 byteOffset;
+  UInt32 flags = 0;
+
+  OSStatus rv = AudioFileStreamSeek(mAudioFileStream,
+                                    packet,
+                                    &byteOffset,
+                                    &flags);
+
+  if (rv) {
+    LOGE("Couldn't seek demuxer. Error code %x\n", rv);
+    return NS_ERROR_FAILURE;
+  }
+
+  LOGD("computed byte offset = %lld; estimated = %s\n",
+       byteOffset,
+       (flags & kAudioFileStreamSeekFlag_OffsetIsEstimated) ? "YES" : "NO");
+
+  mDecoder->GetResource()->Seek(nsISeekableStream::NS_SEEK_SET, byteOffset);
+
+  ResetDecode();
+
+  return NS_OK;
+}
+
+
+nsresult
+AppleMP3Reader::GetBuffered(dom::TimeRanges* aBuffered,
+                            int64_t aStartTime)
+{
+  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+  GetEstimatedBufferedTimeRanges(mDecoder->GetResource(),
+                                 mDecoder->GetMediaDuration(),
+                                 aBuffered);
+  return NS_OK;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/media/apple/AppleMP3Reader.h
@@ -0,0 +1,84 @@
+/* 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 __AppleMP3Reader_h__
+#define __AppleMP3Reader_h__
+
+#include "MediaDecoderReader.h"
+#include "MP3FrameParser.h"
+#include "VideoUtils.h"
+
+#include <AudioToolbox/AudioToolbox.h>
+
+namespace mozilla {
+
+class AppleMP3Reader : public MediaDecoderReader
+{
+public:
+  AppleMP3Reader(AbstractMediaDecoder *aDecoder);
+  virtual ~AppleMP3Reader() MOZ_OVERRIDE;
+
+  virtual nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE;
+
+  nsresult PushDataToDemuxer();
+
+  virtual bool DecodeAudioData() MOZ_OVERRIDE;
+  virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
+                                int64_t aTimeThreshold) MOZ_OVERRIDE;
+
+  virtual bool HasAudio() MOZ_OVERRIDE;
+  virtual bool HasVideo() MOZ_OVERRIDE;
+
+  virtual nsresult ReadMetadata(VideoInfo* aInfo,
+                                MetadataTags** aTags) MOZ_OVERRIDE;
+
+  virtual nsresult Seek(int64_t aTime,
+                        int64_t aStartTime,
+                        int64_t aEndTime,
+                        int64_t aCurrentTime) MOZ_OVERRIDE;
+
+  virtual nsresult GetBuffered(dom::TimeRanges* aBuffered,
+                               int64_t aStartTime) MOZ_OVERRIDE;
+
+  void AudioSampleCallback(UInt32 aNumBytes,
+                           UInt32 aNumPackets,
+                           const void *aData,
+                           AudioStreamPacketDescription *aPackets);
+
+  void AudioMetadataCallback(AudioFileStreamID aFileStream,
+                             AudioFileStreamPropertyID aPropertyID,
+                             UInt32 *aFlags);
+
+private:
+  void SetupDecoder();
+  nsresult ReadAndNotify(uint32_t *aNumBytes, char *aData);
+
+  static OSStatus PassthroughInputDataCallback(AudioConverterRef aAudioConverter,
+                                               UInt32 *aNumDataPackets,
+                                               AudioBufferList *aData,
+                                               AudioStreamPacketDescription **aPacketDesc,
+                                               void *aUserData);
+
+  // Initialisation has to be done in a callback, so we store the result here.
+  bool mStreamReady;
+
+  // Number of audio samples in an audio packet. Constant over all packets in a
+  // stream.
+  UInt32 mAudioFramesPerCompressedPacket;
+  // Store the next audio frame to be played; so we can keep time when seeking.
+  UInt64 mCurrentAudioFrame;
+  UInt32 mAudioChannels;
+  UInt32 mAudioSampleRate;
+
+  uint64_t mDuration;
+
+  AudioFileStreamID mAudioFileStream;
+  AudioConverterRef mAudioConverter;
+
+  MP3FrameParser mMP3FrameParser;
+};
+
+} // namespace mozilla
+
+#endif // __AppleMP3Reader_h__
new file mode 100644
--- /dev/null
+++ b/content/media/apple/Makefile.in
@@ -0,0 +1,7 @@
+# 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/.
+
+LDFLAGS += \
+    -framework AudioToolbox \
+    $(NULL)
new file mode 100644
--- /dev/null
+++ b/content/media/apple/moz.build
@@ -0,0 +1,24 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+MODULE = 'content'
+
+EXPORTS += [
+    'AppleDecoder.h',
+    'AppleMP3Reader.h',
+]
+
+CPP_SOURCES += [
+    'AppleDecoder.cpp',
+    'AppleMP3Reader.cpp',
+]
+
+LIBRARY_NAME = 'gkconapplemedia_s'
+
+FAIL_ON_WARNINGS = True
+
+LIBXUL_LIBRARY = True
+
--- a/content/media/moz.build
+++ b/content/media/moz.build
@@ -32,16 +32,19 @@ if CONFIG['MOZ_DIRECTSHOW']:
     PARALLEL_DIRS += ['directshow']
 
 if CONFIG['MOZ_MEDIA_PLUGINS']:
     PARALLEL_DIRS += ['plugins']
 
 if CONFIG['MOZ_WMF']:
     PARALLEL_DIRS += ['wmf']
 
+if CONFIG['MOZ_APPLEMEDIA']:
+    PARALLEL_DIRS += ['apple']
+
 PARALLEL_DIRS += ['webrtc']
 
 if CONFIG['MOZ_OMX_DECODER']:
     PARALLEL_DIRS += ['omx']
     PARALLEL_DIRS += ['omx/mediaresourcemanager']
 
 PARALLEL_DIRS += ['webspeech']
 
@@ -89,16 +92,18 @@ EXPORTS += [
 
 EXPORTS.mozilla.dom += [
     'AudioStreamTrack.h',
     'MediaStreamTrack.h',
     'TextTrack.h',
     'TextTrackCue.h',
     'TextTrackCueList.h',
     'TextTrackList.h',
+    'TextTrackRegion.h',
+    'TextTrackRegionList.h',
     'VideoPlaybackQuality.h',
     'VideoStreamTrack.h',
 ]
 
 CPP_SOURCES += [
     'AudioAvailableEventManager.cpp',
     'AudioChannelFormat.cpp',
     'AudioNodeEngine.cpp',
@@ -121,16 +126,18 @@ CPP_SOURCES += [
     'MediaResource.cpp',
     'MediaStreamGraph.cpp',
     'MediaStreamTrack.cpp',
     'StreamBuffer.cpp',
     'TextTrack.cpp',
     'TextTrackCue.cpp',
     'TextTrackCueList.cpp',
     'TextTrackList.cpp',
+    'TextTrackRegion.cpp',
+    'TextTrackRegionList.cpp',
     'VideoFrameContainer.cpp',
     'VideoPlaybackQuality.cpp',
     'VideoSegment.cpp',
     'VideoStreamTrack.cpp',
     'VideoUtils.cpp',
     'WebVTTLoadListener.cpp',
 ]
 
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -690,33 +690,39 @@ function mediaTestCleanup() {
 (function() {
   // Ensure that preload preferences are comsistent
   var prefService = SpecialPowers.wrap(SpecialPowers.Components)
                                  .classes["@mozilla.org/preferences-service;1"]
                                  .getService(SpecialPowers.Ci.nsIPrefService);
   var branch = prefService.getBranch("media.");
   var oldDefault = 2;
   var oldAuto = 3;
+  var oldAppleMedia = undefined;
   var oldGStreamer = undefined;
   var oldOpus = undefined;
 
+  try { oldAppleMedia = SpecialPowers.getBoolPref("media.apple.mp3.enabled"); } catch(ex) { }
   try { oldGStreamer = SpecialPowers.getBoolPref("media.gstreamer.enabled"); } catch(ex) { }
   try { oldDefault   = SpecialPowers.getIntPref("media.preload.default"); } catch(ex) { }
   try { oldAuto      = SpecialPowers.getIntPref("media.preload.auto"); } catch(ex) { }
   try { oldOpus      = SpecialPowers.getBoolPref("media.opus.enabled"); } catch(ex) { }
 
   SpecialPowers.setIntPref("media.preload.default", 2); // preload_metadata
   SpecialPowers.setIntPref("media.preload.auto", 3); // preload_enough
   // test opus playback iff the pref exists
   if (oldOpus !== undefined)
     SpecialPowers.setBoolPref("media.opus.enabled", true);
   if (oldGStreamer !== undefined)
     SpecialPowers.setBoolPref("media.gstreamer.enabled", true);
+  if (oldAppleMedia !== undefined)
+    SpecialPowers.setBoolPref("media.apple.mp3.enabled", true);
 
   window.addEventListener("unload", function() {
     if (oldGStreamer !== undefined)
       SpecialPowers.setBoolPref("media.gstreamer.enabled", oldGStreamer);
+    if (oldAppleMedia !== undefined)
+      SpecialPowers.setBoolPref("media.apple.mp3.enabled", oldAppleMedia);
     SpecialPowers.setIntPref("media.preload.default", oldDefault);
     SpecialPowers.setIntPref("media.preload.auto", oldAuto);
     if (oldOpus !== undefined)
       SpecialPowers.setBoolPref("media.opus.enabled", oldOpus);
   }, false);
  })();
--- a/content/media/test/test_can_play_type_mpeg.html
+++ b/content/media/test/test_can_play_type_mpeg.html
@@ -43,16 +43,17 @@ var haveMp4 = (getPref("media.windows-me
                getPref("media.gstreamer.enabled");
 // TODO:  Add "getPref("media.plugins.enabled")" once MP4 works on Gingerbread.
              
 check_mp4(document.getElementById('v'), haveMp4);
 
 var haveMp3 = getPref("media.directshow.enabled") ||
               (getPref("media.windows-media-foundation.enabled") && IsWindowsVistaOrLater()) ||
                getPref("media.omx.enabled") ||
-               getPref("media.gstreamer.enabled");
+               getPref("media.gstreamer.enabled") ||
+               getPref("media.apple.mp3.enabled");
 check_mp3(document.getElementById('v'), haveMp3);
 
 mediaTestCleanup();
 </script>
 </pre>
 </body>
 </html>
--- a/content/media/webspeech/recognition/SpeechRecognition.cpp
+++ b/content/media/webspeech/recognition/SpeechRecognition.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SpeechRecognition.h"
 
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 
 #include "mozilla/dom/SpeechRecognitionBinding.h"
+#include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "mozilla/MediaManager.h"
 #include "mozilla/Services.h"
 
 #include "AudioSegment.h"
 #include "endpointer.h"
 
 #include "GeneratedEvents.h"
 #include "nsIDOMSpeechRecognitionEvent.h"
@@ -706,21 +707,26 @@ SpeechRecognition::Start(ErrorResult& aR
 
   nsresult rv;
   mRecognitionService = do_GetService(speechRecognitionServiceCID.get(), &rv);
   NS_ENSURE_SUCCESS_VOID(rv);
 
   rv = mRecognitionService->Initialize(this->asWeakPtr());
   NS_ENSURE_SUCCESS_VOID(rv);
 
+  AutoSafeJSContext cx;
+  MediaStreamConstraintsInitializer constraints;
+  constraints.mAudio.SetAsBoolean() = true;
+
   if (!mTestConfig.mFakeFSMEvents) {
     MediaManager* manager = MediaManager::Get();
-    manager->GetUserMedia(false,
+    manager->GetUserMedia(cx,
+                          false,
                           GetOwner(),
-                          new GetUserMediaStreamOptions(),
+                          constraints,
                           new GetUserMediaSuccessCallback(this),
                           new GetUserMediaErrorCallback(this));
   }
 
   nsRefPtr<SpeechEvent> event = new SpeechEvent(this, EVENT_START);
   NS_DispatchToMainThread(event);
 }
 
@@ -917,66 +923,16 @@ SpeechRecognition::GetName(SpeechEvent* 
     "EVENT_RECOGNITIONSERVICE_ERROR"
   };
 
   MOZ_ASSERT(aEvent->mType < EVENT_COUNT);
   MOZ_ASSERT(ArrayLength(names) == EVENT_COUNT);
   return names[aEvent->mType];
 }
 
-NS_IMPL_ISUPPORTS1(SpeechRecognition::GetUserMediaStreamOptions, nsIMediaStreamOptions)
-
-NS_IMETHODIMP
-SpeechRecognition::GetUserMediaStreamOptions::GetFake(bool* aFake)
-{
-  *aFake = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-SpeechRecognition::GetUserMediaStreamOptions::GetAudio(bool* aAudio)
-{
-  *aAudio = true;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-SpeechRecognition::GetUserMediaStreamOptions::GetVideo(bool* aVideo)
-{
-  *aVideo = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-SpeechRecognition::GetUserMediaStreamOptions::GetPicture(bool* aPicture)
-{
-  *aPicture = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-SpeechRecognition::GetUserMediaStreamOptions::GetCamera(nsAString& aCamera)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-SpeechRecognition::GetUserMediaStreamOptions::GetAudioDevice(nsIMediaDevice** aAudioDevice)
-{
-  *aAudioDevice = nullptr;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-SpeechRecognition::GetUserMediaStreamOptions::GetVideoDevice(nsIMediaDevice** aVideoDevice)
-{
-  *aVideoDevice = nullptr;
-  return NS_OK;
-}
-
 SpeechEvent::~SpeechEvent()
 {
   delete mAudioSegment;
 }
 
 NS_IMETHODIMP
 SpeechEvent::Run()
 {
--- a/content/media/webspeech/recognition/SpeechRecognition.h
+++ b/content/media/webspeech/recognition/SpeechRecognition.h
@@ -171,26 +171,16 @@ private:
     STATE_RECOGNIZING,
     STATE_WAITING_FOR_RESULT,
     STATE_COUNT
   };
 
   void SetState(FSMState state);
   bool StateBetween(FSMState begin, FSMState end);
 
-  class GetUserMediaStreamOptions : public nsIMediaStreamOptions
-  {
-  public:
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIMEDIASTREAMOPTIONS
-
-    GetUserMediaStreamOptions() {}
-    virtual ~GetUserMediaStreamOptions() {}
-  };
-
   class GetUserMediaSuccessCallback : public nsIDOMGetUserMediaSuccessCallback
   {
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIDOMGETUSERMEDIASUCCESSCALLBACK
 
     GetUserMediaSuccessCallback(SpeechRecognition* aRecognition)
       : mRecognition(aRecognition)
--- a/content/xbl/src/nsXBLPrototypeHandler.cpp
+++ b/content/xbl/src/nsXBLPrototypeHandler.cpp
@@ -545,17 +545,17 @@ nsXBLPrototypeHandler::DispatchXULKeyCom
 
   // Copy the modifiers from the key event.
   nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
   if (!keyEvent) {
     NS_ERROR("Trying to execute a key handler for a non-key event!");
     return NS_ERROR_FAILURE;
   }
 
-  // XXX We should use widget::Modifiers for supporting all modifiers.
+  // XXX We should use mozilla::Modifiers for supporting all modifiers.
 
   bool isAlt = false;
   bool isControl = false;
   bool isShift = false;
   bool isMeta = false;
   keyEvent->GetAltKey(&isAlt);
   keyEvent->GetCtrlKey(&isControl);
   keyEvent->GetShiftKey(&isShift);
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -981,64 +981,67 @@ Navigator::GetGeolocation(ErrorResult& a
     return nullptr;
   }
 
   return mGeolocation;
 }
 
 #ifdef MOZ_MEDIA_NAVIGATOR
 void
-Navigator::MozGetUserMedia(nsIMediaStreamOptions* aParams,
-                           MozDOMGetUserMediaSuccessCallback* aOnSuccess,
-                           MozDOMGetUserMediaErrorCallback* aOnError,
+Navigator::MozGetUserMedia(JSContext* aCx,
+                           const MediaStreamConstraints& aConstraints,
+                           NavigatorUserMediaSuccessCallback& aOnSuccess,
+                           NavigatorUserMediaErrorCallback& aOnError,
                            ErrorResult& aRv)
 {
-  CallbackObjectHolder<MozDOMGetUserMediaSuccessCallback,
-                       nsIDOMGetUserMediaSuccessCallback> holder1(aOnSuccess);
+  CallbackObjectHolder<NavigatorUserMediaSuccessCallback,
+                       nsIDOMGetUserMediaSuccessCallback> holder1(&aOnSuccess);
   nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onsuccess =
     holder1.ToXPCOMCallback();
 
-  CallbackObjectHolder<MozDOMGetUserMediaErrorCallback,
-                       nsIDOMGetUserMediaErrorCallback> holder2(aOnError);
+  CallbackObjectHolder<NavigatorUserMediaErrorCallback,
+                       nsIDOMGetUserMediaErrorCallback> holder2(&aOnError);
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onerror = holder2.ToXPCOMCallback();
 
   if (!mWindow || !mWindow->GetOuterWindow() ||
       mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return;
   }
 
   bool privileged = nsContentUtils::IsChromeDoc(mWindow->GetExtantDoc());
 
   MediaManager* manager = MediaManager::Get();
-  aRv = manager->GetUserMedia(privileged, mWindow, aParams, onsuccess, onerror);
+  aRv = manager->GetUserMedia(aCx, privileged, mWindow, aConstraints,
+                              onsuccess, onerror);
 }
 
 void
-Navigator::MozGetUserMediaDevices(MozGetUserMediaDevicesSuccessCallback* aOnSuccess,
-                                  MozDOMGetUserMediaErrorCallback* aOnError,
+Navigator::MozGetUserMediaDevices(const MediaStreamConstraintsInternal& aConstraints,
+                                  MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
+                                  NavigatorUserMediaErrorCallback& aOnError,
                                   ErrorResult& aRv)
 {
   CallbackObjectHolder<MozGetUserMediaDevicesSuccessCallback,
-                       nsIGetUserMediaDevicesSuccessCallback> holder1(aOnSuccess);
+                       nsIGetUserMediaDevicesSuccessCallback> holder1(&aOnSuccess);
   nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onsuccess =
     holder1.ToXPCOMCallback();
 
-  CallbackObjectHolder<MozDOMGetUserMediaErrorCallback,
-                       nsIDOMGetUserMediaErrorCallback> holder2(aOnError);
+  CallbackObjectHolder<NavigatorUserMediaErrorCallback,
+                       nsIDOMGetUserMediaErrorCallback> holder2(&aOnError);
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onerror = holder2.ToXPCOMCallback();
 
   if (!mWindow || !mWindow->GetOuterWindow() ||
       mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return;
   }
 
   MediaManager* manager = MediaManager::Get();
-  aRv = manager->GetUserMediaDevices(mWindow, onsuccess, onerror);
+  aRv = manager->GetUserMediaDevices(mWindow, aConstraints, onsuccess, onerror);
 }
 #endif
 
 DesktopNotificationCenter*
 Navigator::GetMozNotification(ErrorResult& aRv)
 {
   if (mNotification) {
     return mNotification;
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -17,24 +17,25 @@
 #include "nsTArray.h"
 
 class nsPluginArray;
 class nsMimeTypeArray;
 class nsPIDOMWindow;
 class nsIDOMMozConnection;
 class nsIDOMMozMobileMessageManager;
 class nsIDOMNavigatorSystemMessages;
-class nsIMediaStreamOptions;
 class nsDOMCameraManager;
 class nsDOMDeviceStorage;
 
 namespace mozilla {
 namespace dom {
 class Geolocation;
 class systemMessageCallback;
+class MediaStreamConstraints;
+class MediaStreamConstraintsInternal;
 }
 }
 
 #ifdef MOZ_B2G_RIL
 class nsIDOMMozMobileConnection;
 class nsIDOMMozIccManager;
 #endif // MOZ_B2G_RIL
 
@@ -57,18 +58,18 @@ class FMRadio;
 
 class DesktopNotificationCenter;
 class MobileMessageManager;
 class MozIdleObserver;
 #ifdef MOZ_GAMEPAD
 class Gamepad;
 #endif // MOZ_GAMEPAD
 #ifdef MOZ_MEDIA_NAVIGATOR
-class MozDOMGetUserMediaSuccessCallback;
-class MozDOMGetUserMediaErrorCallback;
+class NavigatorUserMediaSuccessCallback;
+class NavigatorUserMediaErrorCallback;
 class MozGetUserMediaDevicesSuccessCallback;
 #endif // MOZ_MEDIA_NAVIGATOR
 
 namespace icc {
 #ifdef MOZ_B2G_RIL
 class IccManager;
 #endif
 }
@@ -235,22 +236,24 @@ public:
 #endif // MOZ_B2G_BT
 #ifdef MOZ_TIME_MANAGER
   time::TimeManager* GetMozTime(ErrorResult& aRv);
 #endif // MOZ_TIME_MANAGER
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   system::AudioChannelManager* GetMozAudioChannelManager(ErrorResult& aRv);
 #endif // MOZ_AUDIO_CHANNEL_MANAGER
 #ifdef MOZ_MEDIA_NAVIGATOR
-  void MozGetUserMedia(nsIMediaStreamOptions* aParams,
-                       MozDOMGetUserMediaSuccessCallback* aOnSuccess,
-                       MozDOMGetUserMediaErrorCallback* aOnError,
+  void MozGetUserMedia(JSContext* aCx,
+                       const MediaStreamConstraints& aConstraints,
+                       NavigatorUserMediaSuccessCallback& aOnSuccess,
+                       NavigatorUserMediaErrorCallback& aOnError,
                        ErrorResult& aRv);
-  void MozGetUserMediaDevices(MozGetUserMediaDevicesSuccessCallback* aOnSuccess,
-                              MozDOMGetUserMediaErrorCallback* aOnError,
+  void MozGetUserMediaDevices(const MediaStreamConstraintsInternal& aConstraints,
+                              MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
+                              NavigatorUserMediaErrorCallback& aOnError,
                               ErrorResult& aRv);
 #endif // MOZ_MEDIA_NAVIGATOR
   bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
                     JS::Handle<jsid> aId, JS::MutableHandle<JS::Value> aValue);
   void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
                            ErrorResult& aRv);
 
   // WebIDL helper methods
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -543,52 +543,52 @@ nsDOMWindowUtils::GetPresShellId(uint32_
   if (presShell) {
     *aPresShellId = presShell->GetPresShellId();
     return NS_OK;
   }
   return NS_ERROR_FAILURE;
 }
 
 /* static */
-mozilla::widget::Modifiers
+mozilla::Modifiers
 nsDOMWindowUtils::GetWidgetModifiers(int32_t aModifiers)
 {
-  widget::Modifiers result = 0;
+  Modifiers result = 0;
   if (aModifiers & nsIDOMWindowUtils::MODIFIER_SHIFT) {
-    result |= widget::MODIFIER_SHIFT;
+    result |= mozilla::MODIFIER_SHIFT;
   }
   if (aModifiers & nsIDOMWindowUtils::MODIFIER_CONTROL) {
-    result |= widget::MODIFIER_CONTROL;
+    result |= mozilla::MODIFIER_CONTROL;
   }
   if (aModifiers & nsIDOMWindowUtils::MODIFIER_ALT) {
-    result |= widget::MODIFIER_ALT;
+    result |= mozilla::MODIFIER_ALT;
   }
   if (aModifiers & nsIDOMWindowUtils::MODIFIER_META) {
-    result |= widget::MODIFIER_META;
+    result |= mozilla::MODIFIER_META;
   }
   if (aModifiers & nsIDOMWindowUtils::MODIFIER_ALTGRAPH) {
-    result |= widget::MODIFIER_ALTGRAPH;
+    result |= mozilla::MODIFIER_ALTGRAPH;
   }
   if (aModifiers & nsIDOMWindowUtils::MODIFIER_CAPSLOCK) {
-    result |= widget::MODIFIER_CAPSLOCK;
+    result |= mozilla::MODIFIER_CAPSLOCK;
   }
   if (aModifiers & nsIDOMWindowUtils::MODIFIER_FN) {
-    result |= widget::MODIFIER_FN;
+    result |= mozilla::MODIFIER_FN;
   }
   if (aModifiers & nsIDOMWindowUtils::MODIFIER_NUMLOCK) {
-    result |= widget::MODIFIER_NUMLOCK;
+    result |= mozilla::MODIFIER_NUMLOCK;
   }
   if (aModifiers & nsIDOMWindowUtils::MODIFIER_SCROLLLOCK) {
-    result |= widget::MODIFIER_SCROLLLOCK;
+    result |= mozilla::MODIFIER_SCROLLLOCK;
   }
   if (aModifiers & nsIDOMWindowUtils::MODIFIER_SYMBOLLOCK) {
-    result |= widget::MODIFIER_SYMBOLLOCK;
+    result |= mozilla::MODIFIER_SYMBOLLOCK;
   }
   if (aModifiers & nsIDOMWindowUtils::MODIFIER_OS) {
-    result |= widget::MODIFIER_OS;
+    result |= mozilla::MODIFIER_OS;
   }
   return result;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendMouseEvent(const nsAString& aType,
                                  float aX,
                                  float aY,
@@ -757,17 +757,17 @@ nsDOMWindowUtils::SendWheelEvent(float a
 
   // get the widget to send the event to
   nsPoint offset;
   nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
   if (!widget) {
     return NS_ERROR_NULL_POINTER;
   }
 
-  widget::WheelEvent wheelEvent(true, NS_WHEEL_WHEEL, widget);
+  WheelEvent wheelEvent(true, NS_WHEEL_WHEEL, widget);
   wheelEvent.modifiers = GetWidgetModifiers(aModifiers);
   wheelEvent.deltaX = aDeltaX;
   wheelEvent.deltaY = aDeltaY;
   wheelEvent.deltaZ = aDeltaZ;
   wheelEvent.deltaMode = aDeltaMode;
   wheelEvent.isMomentum =
     (aOptions & WHEEL_EVENT_CAUSED_BY_MOMENTUM) != 0;
   wheelEvent.isPixelOnlyDevice =
--- a/dom/base/nsDOMWindowUtils.h
+++ b/dom/base/nsDOMWindowUtils.h
@@ -44,12 +44,12 @@ protected:
                                   int32_t aClickCount,
                                   int32_t aModifiers,
                                   bool aIgnoreRootScrollFrame,
                                   float aPressure,
                                   unsigned short aInputSourceArg,
                                   bool aToWindow,
                                   bool *aPreventDefault);
 
-  static mozilla::widget::Modifiers GetWidgetModifiers(int32_t aModifiers);
+  static mozilla::Modifiers GetWidgetModifiers(int32_t aModifiers);
 };
 
 #endif
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1780,18 +1780,16 @@ addExternalIface('imgIRequest', nativeTy
 addExternalIface('LockedFile')
 addExternalIface('MediaList')
 addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
 addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
 addExternalIface('MozConnection', headerFile='nsIDOMConnection.h')
 addExternalIface('MozControllers', nativeType='nsIControllers')
 addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True)
 addExternalIface('MozIccManager', headerFile='nsIDOMIccManager.h')
-addExternalIface('MozMediaStreamOptions', nativeType='nsIMediaStreamOptions',
-                 headerFile='nsIDOMNavigatorUserMedia.h')
 addExternalIface('MozMobileConnection', headerFile='nsIDOMMobileConnection.h')
 addExternalIface('MozMobileMessageManager', headerFile='nsIDOMMobileMessageManager.h')
 addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
 addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
                  notflattened=True)
 addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
 addExternalIface('MozTelephony', nativeType='nsIDOMTelephony')
 addExternalIface('MozTreeBoxObject', nativeType='nsITreeBoxObject',
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -630,16 +630,20 @@ class CGHeaders(CGWrapper):
                     # member works.
                     declareIncludes.add("mozilla/dom/Nullable.h")
                 else:
                     bindingHeaders.add("mozilla/dom/Nullable.h")
             unrolled = t.unroll()
             if unrolled.isUnion():
                 # UnionConversions.h includes UnionTypes.h
                 bindingHeaders.add("mozilla/dom/UnionConversions.h")
+                if dictionary:
+                    # Our dictionary definition is in the header and
+                    # needs the union type.
+                    declareIncludes.add("mozilla/dom/UnionTypes.h")
             elif unrolled.isDate():
                 if dictionary or jsImplementedDescriptors:
                     headerSet = declareIncludes
                 else:
                     headerSet = bindingHeaders
                 headerSet.add("mozilla/dom/Date.h")
             elif unrolled.isInterface():
                 if unrolled.isSpiderMonkeyInterface():
--- a/dom/bluetooth/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth/BluetoothA2dpManager.cpp
@@ -320,33 +320,35 @@ BluetoothA2dpManager::HandleSinkProperty
       NotifyConnectionStatusChanged();
       mDeviceAddress.Truncate();
 
       // case 7 only
       if (prevState == SinkState::SINK_DISCONNECTING) {
         OnDisconnect(EmptyString());
       }
       break;
+    default:
+      break;
   }
 }
 
 void
 BluetoothA2dpManager::NotifyConnectionStatusChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Notify Gecko observers
   nsCOMPtr<nsIObserverService> obs =
     do_GetService("@mozilla.org/observer-service;1");
   NS_ENSURE_TRUE_VOID(obs);
 
   if (NS_FAILED(obs->NotifyObservers(this,
                                      BLUETOOTH_A2DP_STATUS_CHANGED_ID,
                                      mDeviceAddress.get()))) {
-    NS_WARNING("Failed to notify bluetooth-a2dp-status-changed observsers!");
+    BT_WARNING("Failed to notify bluetooth-a2dp-status-changed observsers!");
   }
 
   // Dispatch an event of status change
   DispatchStatusChangedEvent(
     NS_LITERAL_STRING(A2DP_STATUS_CHANGED_ID), mDeviceAddress, mA2dpConnected);
 }
 
 void
--- a/dom/bluetooth/BluetoothA2dpManager.h
+++ b/dom/bluetooth/BluetoothA2dpManager.h
@@ -39,20 +39,25 @@ public:
   virtual void GetAddress(nsAString& aDeviceAddress) MOZ_OVERRIDE;
   virtual bool IsConnected() MOZ_OVERRIDE;
   virtual void Connect(const nsAString& aDeviceAddress,
                        BluetoothProfileController* aController) MOZ_OVERRIDE;
   virtual void Disconnect(BluetoothProfileController* aController) MOZ_OVERRIDE;
   virtual void OnConnect(const nsAString& aErrorStr) MOZ_OVERRIDE;
   virtual void OnDisconnect(const nsAString& aErrorStr) MOZ_OVERRIDE;
 
-  // A2DP member functions
+  virtual void GetName(nsACString& aName)
+  {
+    aName.AssignLiteral("A2DP");
+  }
+
+  // A2DP-specific functions
   void HandleSinkPropertyChanged(const BluetoothSignal& aSignal);
 
-  // AVRCP member functions
+  // AVRCP-specific functions
   void SetAvrcpConnected(bool aConnected);
   bool IsAvrcpConnected();
   void UpdateMetaData(const nsAString& aTitle,
                       const nsAString& aArtist,
                       const nsAString& aAlbum,
                       uint32_t aMediaNumber,
                       uint32_t aTotalMediaCount,
                       uint32_t aDuration);
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -68,52 +68,52 @@ public:
   }
 
   virtual bool ParseSuccessfulReply(JS::Value* aValue)
   {
     *aValue = JSVAL_VOID;
 
     const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
     if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
-      NS_WARNING("Not a BluetoothNamedValue array!");
+      BT_WARNING("Not a BluetoothNamedValue array!");
       SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
       return false;
     }
 
     const InfallibleTArray<BluetoothNamedValue>& values =
       v.get_ArrayOfBluetoothNamedValue();
 
     nsTArray<nsRefPtr<BluetoothDevice> > devices;
     JSObject* JsDevices;
     for (uint32_t i = 0; i < values.Length(); i++) {
       const BluetoothValue properties = values[i].value();
       if (properties.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
-        NS_WARNING("Not a BluetoothNamedValue array!");
+        BT_WARNING("Not a BluetoothNamedValue array!");
         SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
         return false;
       }
       nsRefPtr<BluetoothDevice> d =
         BluetoothDevice::Create(mAdapterPtr->GetOwner(),
                                 mAdapterPtr->GetPath(),
                                 properties);
       devices.AppendElement(d);
     }
 
     nsresult rv;
     nsIScriptContext* sc = mAdapterPtr->GetContextForEventHandlers(&rv);
     if (!sc) {
-      NS_WARNING("Cannot create script context!");
+      BT_WARNING("Cannot create script context!");
       SetError(NS_LITERAL_STRING("BluetoothScriptContextError"));
       return false;
     }
 
     AutoPushJSContext cx(sc->GetNativeContext());
     rv = nsTArrayToJSArray(cx, devices, &JsDevices);
     if (!JsDevices) {
-      NS_WARNING("Cannot create JS array!");
+      BT_WARNING("Cannot create JS array!");
       SetError(NS_LITERAL_STRING("BluetoothError"));
       return false;
     }
 
     aValue->setObject(*JsDevices);
     return true;
   }
 
@@ -137,17 +137,17 @@ public:
   }
 
   virtual bool ParseSuccessfulReply(JS::Value* aValue)
   {
     *aValue = JSVAL_VOID;
 
     const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
     if (v.type() != BluetoothValue::Tbool) {
-      NS_WARNING("Not a boolean!");
+      BT_WARNING("Not a boolean!");
       SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
       return false;
     }
 
     aValue->setBoolean(v.get_bool());
     return true;
   }
 
@@ -247,17 +247,17 @@ BluetoothAdapter::SetPropertyByValue(con
     mUuids = value.get_ArrayOfnsString();
     nsresult rv;
     nsIScriptContext* sc = GetContextForEventHandlers(&rv);
     NS_ENSURE_SUCCESS_VOID(rv);
 
     AutoPushJSContext cx(sc->GetNativeContext());
     JS::Rooted<JSObject*> uuids(cx);
     if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, uuids.address()))) {
-      NS_WARNING("Cannot set JS UUIDs object!");
+      BT_WARNING("Cannot set JS UUIDs object!");
       return;
     }
     mJsUuids = uuids;
     Root();
   } else if (name.EqualsLiteral("Devices")) {
     mDeviceAddresses = value.get_ArrayOfnsString();
 
     uint32_t length = mDeviceAddresses.Length();
@@ -268,27 +268,27 @@ BluetoothAdapter::SetPropertyByValue(con
     nsresult rv;
     nsIScriptContext* sc = GetContextForEventHandlers(&rv);
     NS_ENSURE_SUCCESS_VOID(rv);
 
     AutoPushJSContext cx(sc->GetNativeContext());
     JS::Rooted<JSObject*> deviceAddresses(cx);
     if (NS_FAILED(nsTArrayToJSArray(cx, mDeviceAddresses,
                                     deviceAddresses.address()))) {
-      NS_WARNING("Cannot set JS Devices object!");
+      BT_WARNING("Cannot set JS Devices object!");
       return;
     }
     mJsDeviceAddresses = deviceAddresses;
     Root();
   } else {
 #ifdef DEBUG
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling adapter property: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(name));
-    NS_WARNING(warningMsg.get());
+    BT_WARNING(warningMsg.get());
 #endif
   }
 }
 
 // static
 already_AddRefed<BluetoothAdapter>
 BluetoothAdapter::Create(nsPIDOMWindow* aWindow, const BluetoothValue& aValue)
 {
@@ -299,17 +299,17 @@ BluetoothAdapter::Create(nsPIDOMWindow* 
   return adapter.forget();
 }
 
 void
 BluetoothAdapter::Notify(const BluetoothSignal& aData)
 {
   InfallibleTArray<BluetoothNamedValue> arr;
 
-  BT_LOG("[A] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
+  BT_LOGD("[A] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
 
   BluetoothValue v = aData.value();
   if (aData.name().EqualsLiteral("DeviceFound")) {
     nsRefPtr<BluetoothDevice> device = BluetoothDevice::Create(GetOwner(), mPath, aData.value());
     nsCOMPtr<nsIDOMEvent> event;
     NS_NewDOMBluetoothDeviceEvent(getter_AddRefs(event), this, nullptr, nullptr);
 
     nsCOMPtr<nsIDOMBluetoothDeviceEvent> e = do_QueryInterface(event);
@@ -354,17 +354,17 @@ BluetoothAdapter::Notify(const Bluetooth
     NS_ENSURE_SUCCESS_VOID(rv);
 
     DispatchTrustedEvent(event);
   } else {
 #ifdef DEBUG
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling adapter signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
-    NS_WARNING(warningMsg.get());
+    BT_WARNING(warningMsg.get());
 #endif
   }
 }
 
 already_AddRefed<DOMRequest>
 BluetoothAdapter::StartStopDiscovery(bool aStart, ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
@@ -384,17 +384,17 @@ BluetoothAdapter::StartStopDiscovery(boo
   }
   nsresult rv;
   if (aStart) {
     rv = bs->StartDiscoveryInternal(results);
   } else {
     rv = bs->StopDiscoveryInternal(results);
   }
   if (NS_FAILED(rv)) {
-    NS_WARNING("Start/Stop Discovery failed!");
+    BT_WARNING("Start/Stop Discovery failed!");
     aRv.Throw(rv);
     return nullptr;
   }
 
   // mDiscovering is not set here, we'll get a Property update from our external
   // protocol to tell us that it's been set.
 
   return request.forget();
@@ -411,30 +411,30 @@ BluetoothAdapter::StopDiscovery(ErrorRes
 {
   return StartStopDiscovery(false, aRv);
 }
 
 JS::Value
 BluetoothAdapter::GetDevices(JSContext* aContext, ErrorResult& aRv)
 {
   if (!mJsDeviceAddresses) {
-    NS_WARNING("Devices not yet set!\n");
+    BT_WARNING("Devices not yet set!\n");
     aRv.Throw(NS_ERROR_FAILURE);
     return JS::NullValue();
   }
 
   JS::ExposeObjectToActiveJS(mJsDeviceAddresses);
   return JS::ObjectValue(*mJsDeviceAddresses);
 }
 
 JS::Value
 BluetoothAdapter::GetUuids(JSContext* aContext, ErrorResult& aRv)
 {
   if (!mJsUuids) {
-    NS_WARNING("UUIDs not yet set!\n");
+    BT_WARNING("UUIDs not yet set!\n");
     aRv.Throw(NS_ERROR_FAILURE);
     return JS::NullValue();
   }
 
   JS::ExposeObjectToActiveJS(mJsUuids);
   return JS::ObjectValue(*mJsUuids);
 }
 
@@ -554,17 +554,17 @@ BluetoothAdapter::PairUnpair(bool aPair,
   if (aPair) {
     rv = bs->CreatePairedDeviceInternal(addr,
                                         kCreatePairedDeviceTimeout,
                                         results);
   } else {
     rv = bs->RemoveDeviceInternal(addr, results);
   }
   if (NS_FAILED(rv)) {
-    NS_WARNING("Pair/Unpair failed!");
+    BT_WARNING("Pair/Unpair failed!");
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
@@ -594,17 +594,17 @@ BluetoothAdapter::SetPinCode(const nsASt
     new BluetoothVoidReplyRunnable(request);
 
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   if (!bs->SetPinCodeInternal(aDeviceAddress, aPinCode, results)) {
-    NS_WARNING("SetPinCode failed!");
+    BT_WARNING("SetPinCode failed!");
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
@@ -622,17 +622,17 @@ BluetoothAdapter::SetPasskey(const nsASt
     new BluetoothVoidReplyRunnable(request);
 
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   if (bs->SetPasskeyInternal(aDeviceAddress, aPasskey, results)) {
-    NS_WARNING("SetPasskeyInternal failed!");
+    BT_WARNING("SetPasskeyInternal failed!");
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
@@ -652,17 +652,17 @@ BluetoothAdapter::SetPairingConfirmation
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   if (!bs->SetPairingConfirmationInternal(aDeviceAddress,
                                           aConfirmation,
                                           results)) {
-    NS_WARNING("SetPairingConfirmation failed!");
+    BT_WARNING("SetPairingConfirmation failed!");
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
@@ -742,17 +742,17 @@ BluetoothAdapter::SendFile(const nsAStri
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothVoidReplyRunnable> results =
     new BluetoothVoidReplyRunnable(request);
 
   BlobChild* actor =
     ContentChild::GetSingleton()->GetOrCreateActorForBlob(aBlob);
   if (!actor) {
-    NS_WARNING("Can't create actor");
+    BT_WARNING("Can't create actor");
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -3,44 +3,59 @@
 /* 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_bluetooth_bluetoothcommon_h__
 #define mozilla_dom_bluetooth_bluetoothcommon_h__
 
 #include "mozilla/Observer.h"
+#include "nsPrintfCString.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 
 extern bool gBluetoothDebugFlag;
 
 #define SWITCH_BT_DEBUG(V) (gBluetoothDebugFlag = V)
 
 #undef BT_LOG
 #if defined(MOZ_WIDGET_GONK)
 #include <android/log.h>
-#define BT_LOG(args...)                                              \
+/**
+ * Prints 'D'EBUG build logs, which show in DEBUG build only when
+ * developer setting 'Bluetooth output in adb' is enabled.
+ */
+#define BT_LOGD(args...)                                             \
   do {                                                               \
     if (gBluetoothDebugFlag) {                                       \
       __android_log_print(ANDROID_LOG_INFO, "GeckoBluetooth", args); \
     }                                                                \
   } while(0)
 
+/**
+ * Prints 'R'ELEASE build logs, which show in both RELEASE and DEBUG builds.
+ */
+#define BT_LOGR(args...)                                             \
+  __android_log_print(ANDROID_LOG_INFO, "GeckoBluetooth", args)      \
+
+/**
+ * Prints DEBUG build warnings, which show in DEBUG build only.
+ */
 #define BT_WARNING(args...)                                          \
-  __android_log_print(ANDROID_LOG_WARN, "GeckoBluetooth", args)
+  NS_WARNING(nsPrintfCString(args).get())                            \
 
 #else
-#define BT_LOG(args, ...)                                            \
+#define BT_LOGD(args, ...)                                           \
   do {                                                               \
     if (gBluetoothDebugFlag) {                                       \
       printf(args, ##__VA_ARGS__);                                   \
     }                                                                \
   } while(0)
 
+#define BT_LOGR(args, ...) printf(args, ##__VA_ARGS__)
 #define BT_WARNING(args, ...) printf(args, ##__VA_ARGS__)
 #endif
 
 #define BEGIN_BLUETOOTH_NAMESPACE \
   namespace mozilla { namespace dom { namespace bluetooth {
 #define END_BLUETOOTH_NAMESPACE \
   } /* namespace bluetooth */ } /* namespace dom */ } /* namespace mozilla */
 #define USING_BLUETOOTH_NAMESPACE \
--- a/dom/bluetooth/BluetoothDevice.cpp
+++ b/dom/bluetooth/BluetoothDevice.cpp
@@ -125,41 +125,41 @@ BluetoothDevice::SetPropertyByValue(cons
     nsresult rv;
     nsIScriptContext* sc = GetContextForEventHandlers(&rv);
     NS_ENSURE_SUCCESS_VOID(rv);
 
     AutoPushJSContext cx(sc->GetNativeContext());
 
     JS::Rooted<JSObject*> uuids(cx);
     if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, uuids.address()))) {
-      NS_WARNING("Cannot set JS UUIDs object!");
+      BT_WARNING("Cannot set JS UUIDs object!");
       return;
     }
     mJsUuids = uuids;
     Root();
   } else if (name.EqualsLiteral("Services")) {
     mServices = value.get_ArrayOfnsString();
     nsresult rv;
     nsIScriptContext* sc = GetContextForEventHandlers(&rv);
     NS_ENSURE_SUCCESS_VOID(rv);
 
     AutoPushJSContext cx(sc->GetNativeContext());
 
     JS::Rooted<JSObject*> services(cx);
     if (NS_FAILED(nsTArrayToJSArray(cx, mServices, services.address()))) {
-      NS_WARNING("Cannot set JS Services object!");
+      BT_WARNING("Cannot set JS Services object!");
       return;
     }
     mJsServices = services;
     Root();
   } else {
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling device property: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(name));
-    NS_WARNING(warningMsg.get());
+    BT_WARNING(warningMsg.get());
   }
 }
 
 // static
 already_AddRefed<BluetoothDevice>
 BluetoothDevice::Create(nsPIDOMWindow* aWindow,
                         const nsAString& aAdapterPath,
                         const BluetoothValue& aValue)
@@ -170,56 +170,56 @@ BluetoothDevice::Create(nsPIDOMWindow* a
   nsRefPtr<BluetoothDevice> device =
     new BluetoothDevice(aWindow, aAdapterPath, aValue);
   return device.forget();
 }
 
 void
 BluetoothDevice::Notify(const BluetoothSignal& aData)
 {
-  BT_LOG("[D] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
+  BT_LOGD("[D] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
 
   BluetoothValue v = aData.value();
   if (aData.name().EqualsLiteral("PropertyChanged")) {
     NS_ASSERTION(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue,
                  "PropertyChanged: Invalid value type");
     const InfallibleTArray<BluetoothNamedValue>& arr =
       v.get_ArrayOfBluetoothNamedValue();
 
     NS_ASSERTION(arr.Length() == 1,
                  "Got more than one property in a change message!");
     SetPropertyByValue(arr[0]);
   } else {
 #ifdef DEBUG
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling device signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
-    NS_WARNING(warningMsg.get());
+    BT_WARNING(warningMsg.get());
 #endif
   }
 }
 
 JS::Value
 BluetoothDevice::GetUuids(JSContext* aCx, ErrorResult& aRv)
 {
   if (!mJsUuids) {
-    NS_WARNING("UUIDs not yet set!\n");
+    BT_WARNING("UUIDs not yet set!");
     aRv.Throw(NS_ERROR_FAILURE);
     return JS::NullValue();
   }
 
   JS::ExposeObjectToActiveJS(mJsUuids);
   return JS::ObjectValue(*mJsUuids);
 }
 
 JS::Value
 BluetoothDevice::GetServices(JSContext* aCx, ErrorResult& aRv)
 {
   if (!mJsServices) {
-    NS_WARNING("Services not yet set!\n");
+    BT_WARNING("Services not yet set!");
     aRv.Throw(NS_ERROR_FAILURE);
     return JS::Value(JSVAL_NULL);
   }
 
   JS::ExposeObjectToActiveJS(mJsServices);
   return JS::ObjectValue(*mJsServices);
 }
 
--- a/dom/bluetooth/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/BluetoothHfpManager.cpp
@@ -166,30 +166,30 @@ public:
   Handle(const nsAString& aName, const JS::Value& aResult)
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     JSContext *cx = nsContentUtils::GetCurrentJSContext();
     NS_ENSURE_TRUE(cx, NS_OK);
 
     if (!aResult.isNumber()) {
-      NS_WARNING("'" AUDIO_VOLUME_BT_SCO_ID "' is not a number!");
+      BT_WARNING("'" AUDIO_VOLUME_BT_SCO_ID "' is not a number!");
       return NS_OK;
     }
 
     BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
     hfp->mCurrentVgs = aResult.toNumber();
 
     return NS_OK;
   }
 
   NS_IMETHOD
   HandleError(const nsAString& aName)
   {
-    NS_WARNING("Unable to get value for '" AUDIO_VOLUME_BT_SCO_ID "'");
+    BT_WARNING("Unable to get value for '" AUDIO_VOLUME_BT_SCO_ID "'");
     return NS_OK;
   }
 };
 
 NS_IMPL_ISUPPORTS1(BluetoothHfpManager::GetVolumeTask,
                    nsISettingsServiceCallback);
 
 NS_IMETHODIMP
@@ -250,17 +250,17 @@ public:
     MOZ_ASSERT(NS_IsMainThread());
 
     // Stop sending RING indicator
     if (sStopSendingRingFlag) {
       return;
     }
 
     if (!sBluetoothHfpManager) {
-      NS_WARNING("BluetoothHfpManager no longer exists, cannot send ring!");
+      BT_WARNING("BluetoothHfpManager no longer exists, cannot send ring!");
       return;
     }
 
     nsAutoCString ringMsg("RING");
     sBluetoothHfpManager->SendLine(ringMsg.get());
 
     if (!mNumber.IsEmpty()) {
       nsAutoCString clipMsg("+CLIP: \"");
@@ -370,17 +370,17 @@ BluetoothHfpManager::Init()
     BT_WARNING("Failed to add observers!");
     return false;
   }
 
   hal::RegisterBatteryObserver(this);
 
   mListener = new BluetoothRilListener();
   if (!mListener->StartListening()) {
-    NS_WARNING("Failed to start listening RIL");
+    BT_WARNING("Failed to start listening RIL");
     return false;
   }
 
   nsCOMPtr<nsISettingsService> settings =
     do_GetService("@mozilla.org/settingsService;1");
   NS_ENSURE_TRUE(settings, false);
 
   nsCOMPtr<nsISettingsServiceLock> settingsLock;
@@ -400,17 +400,17 @@ BluetoothHfpManager::Init()
   mScoSocketStatus = mScoSocket->GetConnectionStatus();
   ListenSco();
   return true;
 }
 
 BluetoothHfpManager::~BluetoothHfpManager()
 {
   if (!mListener->StopListening()) {
-    NS_WARNING("Failed to stop listening RIL");
+    BT_WARNING("Failed to stop listening RIL");
   }
   mListener = nullptr;
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   NS_ENSURE_TRUE_VOID(obs);
 
   if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) ||
       NS_FAILED(obs->RemoveObserver(this, MOZSETTINGS_CHANGED_ID))) {
@@ -449,17 +449,17 @@ BluetoothHfpManager::NotifyConnectionSta
 
   // Notify Gecko observers
   nsCOMPtr<nsIObserverService> obs =
     do_GetService("@mozilla.org/observer-service;1");
   NS_ENSURE_TRUE_VOID(obs);
 
   if (NS_FAILED(obs->NotifyObservers(this, NS_ConvertUTF16toUTF8(aType).get(),
                                      mDeviceAddress.get()))) {
-    NS_WARNING("Failed to notify observsers!");
+    BT_WARNING("Failed to notify observsers!");
   }
 
   // Dispatch an event of status change
   bool status;
   nsAutoString eventName;
   if (aType.EqualsLiteral(BLUETOOTH_HFP_STATUS_CHANGED_ID)) {
     status = IsConnected();
     eventName.AssignLiteral(HFP_STATUS_CHANGED_ID);
@@ -482,17 +482,17 @@ BluetoothHfpManager::NotifyDialer(const 
   InfallibleTArray<BluetoothNamedValue> parameters;
   type.AssignLiteral("bluetooth-dialer-command");
 
   name.AssignLiteral("command");
   v = nsString(aCommand);
   parameters.AppendElement(BluetoothNamedValue(name, v));
 
   if (!BroadcastSystemMessage(type, parameters)) {
-    NS_WARNING("Failed to broadcast system message to dialer");
+    BT_WARNING("Failed to broadcast system message to dialer");
   }
 }
 
 void
 BluetoothHfpManager::HandleVolumeChanged(const nsAString& aData)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -561,17 +561,17 @@ BluetoothHfpManager::HandleVoiceConnecti
     service = true;
   }
   UpdateCIND(CINDType::SERVICE, service);
 
   uint8_t signal;
   JS::Value value;
   voiceInfo->GetRelSignalStrength(&value);
   if (!value.isNumber()) {
-    NS_WARNING("Failed to get relSignalStrength in BluetoothHfpManager");
+    BT_WARNING("Failed to get relSignalStrength in BluetoothHfpManager");
     return;
   }
   signal = ceil(value.toNumber() / 20.0);
   UpdateCIND(CINDType::SIGNAL, signal);
 
   /**
    * Possible return values for mode are:
    * - null (unknown): set mNetworkSelectionMode to 0 (auto)
@@ -595,17 +595,17 @@ BluetoothHfpManager::HandleVoiceConnecti
   // or numeric; long alphanumeric format can be upto 16 characters long and
   // short format up to 8 characters (refer GSM MoU SE.13 [9])..."
   // However, we found that the operator name may sometimes be longer than 16
   // characters. After discussion, we decided to fix this here but not in RIL
   // or modem.
   //
   // Please see Bug 871366 for more information.
   if (mOperatorName.Length() > 16) {
-    NS_WARNING("The operator name was longer than 16 characters. We cut it.");
+    BT_WARNING("The operator name was longer than 16 characters. We cut it.");
     mOperatorName.Left(mOperatorName, 16);
   }
 }
 
 void
 BluetoothHfpManager::HandleIccInfoChanged()
 {
   nsCOMPtr<nsIIccProvider> icc =
@@ -665,45 +665,45 @@ BluetoothHfpManager::ReceiveSocketData(B
   } else if (msg.Find("AT+CMER=") != -1) {
     /**
      * SLC establishment is done when AT+CMER has been received.
      * Do nothing but respond with "OK".
      */
     ParseAtCommand(msg, 8, atCommandValues);
 
     if (atCommandValues.Length() < 4) {
-      NS_WARNING("Could't get the value of command [AT+CMER=]");
+      BT_WARNING("Could't get the value of command [AT+CMER=]");
       goto respond_with_ok;
     }
 
     if (!atCommandValues[0].EqualsLiteral("3") ||
         !atCommandValues[1].EqualsLiteral("0") ||
         !atCommandValues[2].EqualsLiteral("0")) {
-      NS_WARNING("Wrong value of CMER");
+      BT_WARNING("Wrong value of CMER");
       goto respond_with_ok;
     }
 
     mCMER = atCommandValues[3].EqualsLiteral("1");
   } else if (msg.Find("AT+CMEE=") != -1) {
     ParseAtCommand(msg, 8, atCommandValues);
 
     if (atCommandValues.IsEmpty()) {
-      NS_WARNING("Could't get the value of command [AT+CMEE=]");
+      BT_WARNING("Could't get the value of command [AT+CMEE=]");
       goto respond_with_ok;
     }
 
     // AT+CMEE = 0: +CME ERROR shall not be used
     // AT+CMEE = 1: use numeric <err>
     // AT+CMEE = 2: use verbose <err>
     mCMEE = !atCommandValues[0].EqualsLiteral("0");
   } else if (msg.Find("AT+COPS=") != -1) {
     ParseAtCommand(msg, 8, atCommandValues);
 
     if (atCommandValues.Length() != 2) {
-      NS_WARNING("Could't get the value of command [AT+COPS=]");
+      BT_WARNING("Could't get the value of command [AT+COPS=]");
       goto respond_with_ok;
     }
 
     // Handsfree only support AT+COPS=3,0
     if (!atCommandValues[0].EqualsLiteral("3") ||
         !atCommandValues[1].EqualsLiteral("0")) {
       if (mCMEE) {
         SendCommand("+CME ERROR: ", BluetoothCmeError::OPERATION_NOT_SUPPORTED);
@@ -718,49 +718,49 @@ BluetoothHfpManager::ReceiveSocketData(B
     message.AppendLiteral(",0,\"");
     message.Append(NS_ConvertUTF16toUTF8(mOperatorName));
     message.AppendLiteral("\"");
     SendLine(message.get());
   } else if (msg.Find("AT+VTS=") != -1) {
     ParseAtCommand(msg, 7, atCommandValues);
 
     if (atCommandValues.Length() != 1) {
-      NS_WARNING("Couldn't get the value of command [AT+VTS=]");
+      BT_WARNING("Couldn't get the value of command [AT+VTS=]");
       goto respond_with_ok;
     }
 
     if (IsValidDtmf(atCommandValues[0].get()[0])) {
       nsAutoCString message("VTS=");
       message += atCommandValues[0].get()[0];
       NotifyDialer(NS_ConvertUTF8toUTF16(message));
     }
   } else if (msg.Find("AT+VGM=") != -1) {
     ParseAtCommand(msg, 7, atCommandValues);
 
     if (atCommandValues.IsEmpty()) {
-      NS_WARNING("Couldn't get the value of command [AT+VGM]");
+      BT_WARNING("Couldn't get the value of command [AT+VGM]");
       goto respond_with_ok;
     }
 
     nsresult rv;
     int vgm = atCommandValues[0].ToInteger(&rv);
     if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to extract microphone volume from bluetooth headset!");
+      BT_WARNING("Failed to extract microphone volume from bluetooth headset!");
       goto respond_with_ok;
     }
 
     NS_ASSERTION(vgm >= 0 && vgm <= 15, "Received invalid VGM value");
     mCurrentVgm = vgm;
   } else if (msg.Find("AT+CHLD=?") != -1) {
     SendLine("+CHLD: (0,1,2)");
   } else if (msg.Find("AT+CHLD=") != -1) {
     ParseAtCommand(msg, 8, atCommandValues);
 
     if (atCommandValues.IsEmpty()) {
-      NS_WARNING("Could't get the value of command [AT+CHLD=]");
+      BT_WARNING("Could't get the value of command [AT+CHLD=]");
       goto respond_with_ok;
     }
 
     /**
      * The following three cases are supported:
      * AT+CHLD=0 - Releases all held calls or sets User Determined User Busy
      *             (UDUB) for a waiting call
      * AT+CHLD=1 - Releases active calls and accepts the other (held or
@@ -771,53 +771,53 @@ BluetoothHfpManager::ReceiveSocketData(B
      * The following cases are NOT supported yet:
      * AT+CHLD=1<idx>, AT+CHLD=2<idx>, AT+CHLD=3, AT+CHLD=4
      * Please see 4.33.2 in Bluetooth hands-free profile 1.6 for more
      * information.
      */
     char chld = atCommandValues[0][0];
     bool valid = true;
     if (atCommandValues[0].Length() > 1) {
-      NS_WARNING("No index should be included in command [AT+CHLD]");
+      BT_WARNING("No index should be included in command [AT+CHLD]");
       valid = false;
     } else if (chld == '3' || chld == '4') {
-      NS_WARNING("The value of command [AT+CHLD] is not supported");
+      BT_WARNING("The value of command [AT+CHLD] is not supported");
       valid = false;
     } else if (chld == '0') {
       // We need to rename these dialer commands for better readability
       // and expandability.
       // See bug 884190 for more information.
       NotifyDialer(NS_LITERAL_STRING("CHLD=0"));
     } else if (chld == '1') {
       NotifyDialer(NS_LITERAL_STRING("CHLD=1"));
     } else if (chld == '2') {
       NotifyDialer(NS_LITERAL_STRING("CHLD=2"));
     } else {
-      NS_WARNING("Wrong value of command [AT+CHLD]");
+      BT_WARNING("Wrong value of command [AT+CHLD]");
       valid = false;
     }
 
     if (!valid) {
       SendLine("ERROR");
       return;
     }
   } else if (msg.Find("AT+VGS=") != -1) {
     // Adjust volume by headset
     mReceiveVgsFlag = true;
     ParseAtCommand(msg, 7, atCommandValues);
 
     if (atCommandValues.IsEmpty()) {
-      NS_WARNING("Could't get the value of command [AT+VGS=]");
+      BT_WARNING("Could't get the value of command [AT+VGS=]");
       goto respond_with_ok;
     }
 
     nsresult rv;
     int newVgs = atCommandValues[0].ToInteger(&rv);
     if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to extract volume value from bluetooth headset!");
+      BT_WARNING("Failed to extract volume value from bluetooth headset!");
       goto respond_with_ok;
     }
 
     if (newVgs == mCurrentVgs) {
       goto respond_with_ok;
     }
 
     NS_ASSERTION(newVgs >= 0 && newVgs <= 15, "Received invalid VGS value");
@@ -850,36 +850,36 @@ BluetoothHfpManager::ReceiveSocketData(B
   } else if (msg.Find("AT+CHUP") != -1) {
     NotifyDialer(NS_LITERAL_STRING("CHUP"));
   } else if (msg.Find("AT+CLCC") != -1) {
     SendCommand("+CLCC: ");
   } else if (msg.Find("ATD") != -1) {
     nsAutoCString message(msg), newMsg;
     int end = message.FindChar(';');
     if (end < 0) {
-      NS_WARNING("Could't get the value of command [ATD]");
+      BT_WARNING("Could't get the value of command [ATD]");
       goto respond_with_ok;
     }
 
     newMsg += nsDependentCSubstring(message, 0, end);
     NotifyDialer(NS_ConvertUTF8toUTF16(newMsg));
   } else if (msg.Find("AT+CLIP=") != -1) {
     ParseAtCommand(msg, 8, atCommandValues);
 
     if (atCommandValues.IsEmpty()) {
-      NS_WARNING("Could't get the value of command [AT+CLIP=]");
+      BT_WARNING("Could't get the value of command [AT+CLIP=]");
       goto respond_with_ok;
     }
 
     mCLIP = atCommandValues[0].EqualsLiteral("1");
   } else if (msg.Find("AT+CCWA=") != -1) {
     ParseAtCommand(msg, 8, atCommandValues);
 
     if (atCommandValues.IsEmpty()) {
-      NS_WARNING("Could't get the value of command [AT+CCWA=]");
+      BT_WARNING("Could't get the value of command [AT+CCWA=]");
       goto respond_with_ok;
     }
 
     mCCWA = atCommandValues[0].EqualsLiteral("1");
   } else if (msg.Find("AT+CKPD") != -1) {
     if (!sStopSendingRingFlag) {
       // Bluetooth HSP spec 4.2.2
       // There is an incoming call, notify Dialer to pick up the phone call
@@ -902,17 +902,17 @@ BluetoothHfpManager::ReceiveSocketData(B
           DisconnectSco();
         }
       } else {
         // Three conditions have to be matched to come in here:
         // (1) Not sending RING indicator
         // (2) A SCO link exists
         // (3) This is the very first AT+CKPD=200 of this session
         // It is the case of Figure 4.3, Bluetooth HSP spec. Do nothing.
-        NS_WARNING("AT+CKPD=200: Do nothing");
+        BT_WARNING("AT+CKPD=200: Do nothing");
       }
     }
 
     mFirstCKPD = false;
   } else if (msg.Find("AT+CNUM") != -1) {
     if (!mMsisdn.IsEmpty()) {
       nsAutoCString message("+CNUM: ,\"");
       message.Append(NS_ConvertUTF16toUTF8(mMsisdn).get());
@@ -951,17 +951,17 @@ BluetoothHfpManager::ReceiveSocketData(B
         // Ignore requests to activate/deactivate mandatory indicators
       }
     }
   } else {
     nsCString warningMsg;
     warningMsg.Append(NS_LITERAL_CSTRING("Unsupported AT command: "));
     warningMsg.Append(msg);
     warningMsg.Append(NS_LITERAL_CSTRING(", reply with ERROR"));
-    NS_WARNING(warningMsg.get());
+    BT_WARNING(warningMsg.get());
 
     SendLine("ERROR");
     return;
   }
 
 respond_with_ok:
   // We always respond to remote device with "OK" in general cases.
   SendLine("OK");
@@ -1021,44 +1021,44 @@ BluetoothHfpManager::Connect(const nsASt
 }
 
 bool
 BluetoothHfpManager::Listen()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (sInShutdown) {
-    NS_WARNING("Listen called while in shutdown!");
+    BT_WARNING("Listen called while in shutdown!");
     return false;
   }
 
   if (mSocket) {
-    NS_WARNING("mSocket exists. Failed to listen.");
+    BT_WARNING("mSocket exists. Failed to listen.");
     return false;
   }
 
   if (!mHandsfreeSocket) {
     mHandsfreeSocket =
       new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
 
     if (!mHandsfreeSocket->Listen(
           BluetoothReservedChannels::CHANNEL_HANDSFREE_AG)) {
-      NS_WARNING("[HFP] Can't listen on RFCOMM socket!");
+      BT_WARNING("[HFP] Can't listen on RFCOMM socket!");
       mHandsfreeSocket = nullptr;
       return false;
     }
   }
 
   if (!mHeadsetSocket) {
     mHeadsetSocket =
       new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
 
     if (!mHeadsetSocket->Listen(
           BluetoothReservedChannels::CHANNEL_HEADSET_AG)) {
-      NS_WARNING("[HSP] Can't listen on RFCOMM socket!");
+      BT_WARNING("[HSP] Can't listen on RFCOMM socket!");
       mHandsfreeSocket->Disconnect();
       mHandsfreeSocket = nullptr;
       mHeadsetSocket = nullptr;
       return false;
     }
   }
 
   return true;
@@ -1096,31 +1096,31 @@ BluetoothHfpManager::SendLine(const char
 
   return mSocket->SendSocketData(msg);
 }
 
 bool
 BluetoothHfpManager::SendCommand(const char* aCommand, uint32_t aValue)
 {
   if (!IsConnected()) {
-    NS_WARNING("Trying to SendCommand() without a SLC");
+    BT_WARNING("Trying to SendCommand() without a SLC");
     return false;
   }
 
   nsAutoCString message;
   message += aCommand;
 
   if (!strcmp(aCommand, "+CIEV: ")) {
     if (!mCMER || !sCINDItems[aValue].activated) {
       // Indicator status update is disabled
       return true;
     }
 
     if ((aValue < 1) || (aValue > ArrayLength(sCINDItems) - 1)) {
-      NS_WARNING("unexpected CINDType for CIEV command");
+      BT_WARNING("unexpected CINDType for CIEV command");
       return false;
     }
 
     message.AppendInt(aValue);
     message.AppendLiteral(",");
     message.AppendInt(sCINDItems[aValue].value);
   } else if (!strcmp(aCommand, "+CIND: ")) {
     if (!aValue) {
@@ -1178,17 +1178,17 @@ BluetoothHfpManager::SendCommand(const c
         case nsITelephonyProvider::CALL_STATE_INCOMING:
           if (!FindFirstCall(nsITelephonyProvider::CALL_STATE_CONNECTED)) {
             message.AppendInt(4);
           } else {
             message.AppendInt(5);
           }
           break;
         default:
-          NS_WARNING("Not handling call status for CLCC");
+          BT_WARNING("Not handling call status for CLCC");
           break;
       }
       message.AppendLiteral(",0,0,\"");
       message.Append(NS_ConvertUTF16toUTF8(call.mNumber));
       message.AppendLiteral("\",");
       message.AppendInt(call.mType);
 
       rv &= SendLine(message.get());
@@ -1338,17 +1338,17 @@ BluetoothHfpManager::HandleCallStateChan
           ConnectSco();
         case nsITelephonyProvider::CALL_STATE_DIALING:
         case nsITelephonyProvider::CALL_STATE_ALERTING:
           // Outgoing call
           UpdateCIND(CINDType::CALL, CallState::IN_PROGRESS, aSend);
           UpdateCIND(CINDType::CALLSETUP, CallSetupState::NO_CALLSETUP, aSend);
           break;
         default:
-          NS_WARNING("Not handling state changed");
+          BT_WARNING("Not handling state changed");
       }
 
       // = Handle callheld separately =
       // Besides checking if there is still held calls, another thing we
       // need to consider is the state change when receiving AT+CHLD=2.
       // Assume that there is one active call(c1) and one call on hold(c2).
       // We got AT+CHLD=2, which swaps active/held position. The first
       // action would be c2 -> ACTIVE, then c1 -> HELD. When we get the
@@ -1377,17 +1377,17 @@ BluetoothHfpManager::HandleCallStateChan
         case nsITelephonyProvider::CALL_STATE_CONNECTED:
           // No call is ongoing
           if (sCINDItems[CINDType::CALLHELD].value ==
               CallHeldState::NO_CALLHELD) {
             UpdateCIND(CINDType::CALL, CallState::NO_CALL, aSend);
           }
           break;
         default:
-          NS_WARNING("Not handling state changed");
+          BT_WARNING("Not handling state changed");
       }
 
       // Handle held calls separately
       if (!FindFirstCall(nsITelephonyProvider::CALL_STATE_HELD)) {
         UpdateCIND(CINDType::CALLHELD, CallHeldState::NO_CALLHELD, aSend);
       } else if (!FindFirstCall(nsITelephonyProvider::CALL_STATE_CONNECTED)) {
         UpdateCIND(CINDType::CALLHELD, CallHeldState::ONHOLD_NOACTIVE, aSend);
       } else {
@@ -1407,17 +1407,17 @@ BluetoothHfpManager::HandleCallStateChan
                                                   new CloseScoTask(),
                                                   sBusyToneInterval);
         }
 
         ResetCallArray();
       }
       break;
     default:
-      NS_WARNING("Not handling state changed");
+      BT_WARNING("Not handling state changed");
       break;
   }
 }
 
 void
 BluetoothHfpManager::OnSocketConnectSuccess(BluetoothSocket* aSocket)
 {
   MOZ_ASSERT(aSocket);
@@ -1616,30 +1616,30 @@ BluetoothHfpManager::GetAddress(nsAStrin
 }
 
 bool
 BluetoothHfpManager::ConnectSco(BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (sInShutdown) {
-    NS_WARNING("ConnecteSco called while in shutdown!");
+    BT_WARNING("ConnecteSco called while in shutdown!");
     return false;
   }
 
   if (!IsConnected()) {
-    NS_WARNING("BluetoothHfpManager is not connected");
+    BT_WARNING("BluetoothHfpManager is not connected");
     return false;
   }
 
   SocketConnectionStatus status = mScoSocket->GetConnectionStatus();
   if (status == SocketConnectionStatus::SOCKET_CONNECTED ||
       status == SocketConnectionStatus::SOCKET_CONNECTING ||
       (mScoRunnable && (mScoRunnable != aRunnable))) {
-    NS_WARNING("SCO connection exists or is being established");
+    BT_WARNING("SCO connection exists or is being established");
     return false;
   }
 
   mScoSocket->Disconnect();
 
   mScoRunnable = aRunnable;
 
   BluetoothService* bs = BluetoothService::Get();
@@ -1649,50 +1649,50 @@ BluetoothHfpManager::ConnectSco(Bluetoot
   mScoSocketStatus = mSocket->GetConnectionStatus();
   return NS_SUCCEEDED(rv);
 }
 
 bool
 BluetoothHfpManager::DisconnectSco()
 {
   if (!IsConnected()) {
-    NS_WARNING("BluetoothHfpManager is not connected");
+    BT_WARNING("BluetoothHfpManager is not connected");
     return false;
   }
 
   SocketConnectionStatus status = mScoSocket->GetConnectionStatus();
   if (status != SOCKET_CONNECTED && status != SOCKET_CONNECTING) {
-    NS_WARNING("No SCO exists");
+    BT_WARNING("No SCO exists");
     return false;
   }
 
   mScoSocket->Disconnect();
   return true;
 }
 
 bool
 BluetoothHfpManager::ListenSco()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (sInShutdown) {
-    NS_WARNING("ListenSco called while in shutdown!");
+    BT_WARNING("ListenSco called while in shutdown!");
     return false;
   }
 
   if (mScoSocket->GetConnectionStatus() ==
       SocketConnectionStatus::SOCKET_LISTENING) {
-    NS_WARNING("SCO socket has been already listening");
+    BT_WARNING("SCO socket has been already listening");
     return false;
   }
 
   mScoSocket->Disconnect();
 
   if (!mScoSocket->Listen(-1)) {
-    NS_WARNING("Can't listen on SCO socket!");
+    BT_WARNING("Can't listen on SCO socket!");
     return false;
   }
 
   mScoSocketStatus = mScoSocket->GetConnectionStatus();
   return true;
 }
 
 bool
--- a/dom/bluetooth/BluetoothHfpManager.h
+++ b/dom/bluetooth/BluetoothHfpManager.h
@@ -76,16 +76,21 @@ public:
   virtual void OnUpdateSdpRecords(const nsAString& aDeviceAddress) MOZ_OVERRIDE;
   virtual void GetAddress(nsAString& aDeviceAddress) MOZ_OVERRIDE;
   virtual void Connect(const nsAString& aDeviceAddress,
                        BluetoothProfileController* aController) MOZ_OVERRIDE;
   virtual void Disconnect(BluetoothProfileController* aController) MOZ_OVERRIDE;
   virtual void OnConnect(const nsAString& aErrorStr) MOZ_OVERRIDE;
   virtual void OnDisconnect(const nsAString& AErrorStr) MOZ_OVERRIDE;
 
+  virtual void GetName(nsACString& aName)
+  {
+    aName.AssignLiteral("HFP/HSP");
+  }
+
   bool Listen();
   bool ConnectSco(BluetoothReplyRunnable* aRunnable = nullptr);
   bool DisconnectSco();
   bool ListenSco();
 
   /**
    * @param aSend A boolean indicates whether we need to notify headset or not
    */
--- a/dom/bluetooth/BluetoothHidManager.cpp
+++ b/dom/bluetooth/BluetoothHidManager.cpp
@@ -231,17 +231,17 @@ BluetoothHidManager::NotifyStatusChanged
   parameters.AppendElement(
     BluetoothNamedValue(NS_LITERAL_STRING("connected"), v));
 
   v = mDeviceAddress;
   parameters.AppendElement(
     BluetoothNamedValue(NS_LITERAL_STRING("address"), v));
 
   if (!BroadcastSystemMessage(type, parameters)) {
-    NS_WARNING("Failed to broadcast system message to settings");
+    BT_WARNING("Failed to broadcast system message to settings");
     return;
   }
 }
 
 void
 BluetoothHidManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
                                          const nsAString& aServiceUuid,
                                          int aChannel)
--- a/dom/bluetooth/BluetoothHidManager.h
+++ b/dom/bluetooth/BluetoothHidManager.h
@@ -32,16 +32,22 @@ public:
   virtual bool IsConnected() MOZ_OVERRIDE;
   virtual void Connect(const nsAString& aDeviceAddress,
                        BluetoothProfileController* aController) MOZ_OVERRIDE;
   virtual void Disconnect(BluetoothProfileController* aController)
                           MOZ_OVERRIDE;
   virtual void OnConnect(const nsAString& aErrorStr) MOZ_OVERRIDE;
   virtual void OnDisconnect(const nsAString& aErrorStr) MOZ_OVERRIDE;
 
+  virtual void GetName(nsACString& aName)
+  {
+    aName.AssignLiteral("HID");
+  }
+
+  // HID-specific functions
   void HandleInputPropertyChanged(const BluetoothSignal& aSignal);
 
 private:
   BluetoothHidManager();
   bool Init();
   void Cleanup();
   void HandleShutdown();
 
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -43,40 +43,40 @@ public:
 
   bool
   ParseSuccessfulReply(JS::Value* aValue)
   {
     *aValue = JSVAL_VOID;
 
     const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
     if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
-      NS_WARNING("Not a BluetoothNamedValue array!");
+      BT_WARNING("Not a BluetoothNamedValue array!");
       SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
       return false;
     }
 
     const InfallibleTArray<BluetoothNamedValue>& values =
       v.get_ArrayOfBluetoothNamedValue();
     nsRefPtr<BluetoothAdapter> adapter =
       BluetoothAdapter::Create(mManagerPtr->GetOwner(), values);
 
     nsresult rv;
     nsIScriptContext* sc = mManagerPtr->GetContextForEventHandlers(&rv);
     if (!sc) {
-      NS_WARNING("Cannot create script context!");
+      BT_WARNING("Cannot create script context!");
       SetError(NS_LITERAL_STRING("BluetoothScriptContextError"));
       return false;
     }
 
     AutoPushJSContext cx(sc->GetNativeContext());
 
     JS::Rooted<JSObject*> global(cx, sc->GetWindowProxy());
     rv = nsContentUtils::WrapNative(cx, global, adapter, aValue);
     if (NS_FAILED(rv)) {
-      NS_WARNING("Cannot create native object!");
+      BT_WARNING("Cannot create native object!");
       SetError(NS_LITERAL_STRING("BluetoothNativeObjectError"));
       return false;
     }
 
     return true;
   }
 
   void
@@ -115,17 +115,17 @@ BluetoothManager::~BluetoothManager()
 void
 BluetoothManager::SetPropertyByValue(const BluetoothNamedValue& aValue)
 {
 #ifdef DEBUG
     const nsString& name = aValue.name();
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling manager property: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(name));
-    NS_WARNING(warningMsg.get());
+    BT_WARNING(warningMsg.get());
 #endif
 }
 
 bool
 BluetoothManager::GetEnabled(ErrorResult& aRv)
 {
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
@@ -192,30 +192,30 @@ BluetoothManager::CheckPermission(nsPIDO
   NS_ENSURE_SUCCESS(rv, false);
 
   return permission == nsIPermissionManager::ALLOW_ACTION;
 }
 
 void
 BluetoothManager::Notify(const BluetoothSignal& aData)
 {
-  BT_LOG("[M] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
+  BT_LOGD("[M] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
 
   if (aData.name().EqualsLiteral("AdapterAdded")) {
     DispatchTrustedEvent(NS_LITERAL_STRING("adapteradded"));
   } else if (aData.name().EqualsLiteral("Enabled")) {
     DispatchTrustedEvent(NS_LITERAL_STRING("enabled"));
   } else if (aData.name().EqualsLiteral("Disabled")) {
     DispatchTrustedEvent(NS_LITERAL_STRING("disabled"));
   } else {
 #ifdef DEBUG
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling manager signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
-    NS_WARNING(warningMsg.get());
+    BT_WARNING(warningMsg.get());
 #endif
   }
 }
 
 bool
 BluetoothManager::IsConnected(uint16_t aProfileId, ErrorResult& aRv)
 {
   BluetoothService* bs = BluetoothService::Get();
--- a/dom/bluetooth/BluetoothOppManager.cpp
+++ b/dom/bluetooth/BluetoothOppManager.cpp
@@ -108,27 +108,27 @@ public:
 
     uint32_t numRead;
     nsAutoArrayPtr<char> buf(new char[mAvailablePacketSize]);
 
     // function inputstream->Read() only works on non-main thread
     nsresult rv = mInputStream->Read(buf, mAvailablePacketSize, &numRead);
     if (NS_FAILED(rv)) {
       // Needs error handling here
-      NS_WARNING("Failed to read from input stream");
+      BT_WARNING("Failed to read from input stream");
       return NS_ERROR_FAILURE;
     }
 
     if (numRead > 0) {
       sBluetoothOppManager->CheckPutFinal(numRead);
 
       nsRefPtr<SendSocketDataTask> task =
         new SendSocketDataTask((uint8_t*)buf.forget(), numRead);
       if (NS_FAILED(NS_DispatchToMainThread(task))) {
-        NS_WARNING("Failed to dispatch to main thread!");
+        BT_WARNING("Failed to dispatch to main thread!");
         return NS_ERROR_FAILURE;
       }
     }
 
     return NS_OK;
   };
 
 private:
@@ -303,37 +303,37 @@ BluetoothOppManager::HandleShutdown()
 }
 
 bool
 BluetoothOppManager::Listen()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mSocket) {
-    NS_WARNING("mSocket exists. Failed to listen.");
+    BT_WARNING("mSocket exists. Failed to listen.");
     return false;
   }
 
   if (!mRfcommSocket) {
     mRfcommSocket =
       new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true);
 
     if (!mRfcommSocket->Listen(BluetoothReservedChannels::CHANNEL_OPUSH)) {
-      NS_WARNING("[OPP] Can't listen on RFCOMM socket!");
+      BT_WARNING("[OPP] Can't listen on RFCOMM socket!");
       mRfcommSocket = nullptr;
       return false;
     }
   }
 
   if (!mL2capSocket) {
     mL2capSocket =
       new BluetoothSocket(this, BluetoothSocketType::EL2CAP, true, true);
 
     if (!mL2capSocket->Listen(BluetoothReservedChannels::CHANNEL_OPUSH_L2CAP)) {
-      NS_WARNING("[OPP] Can't listen on L2CAP socket!");
+      BT_WARNING("[OPP] Can't listen on L2CAP socket!");
       mRfcommSocket->Disconnect();
       mRfcommSocket = nullptr;
       mL2capSocket = nullptr;
       return false;
     }
   }
 
   return true;
@@ -445,17 +445,17 @@ BluetoothOppManager::AfterOppConnected()
   mWaitingForConfirmationFlag = true;
   AfterFirstPut();
   // Get a mount lock to prevent the sdcard from being shared with
   // the PC while we're doing a OPP file transfer. After OPP transaction
   // were done, the mount lock will be freed.
   if (!AcquireSdcardMountLock()) {
     // If we fail to get a mount lock, abort this transaction
     // Directly sending disconnect-request is better than abort-request
-    NS_WARNING("BluetoothOPPManager couldn't get a mount lock!");
+    BT_WARNING("BluetoothOPPManager couldn't get a mount lock!");
     Disconnect(nullptr);
   }
 }
 
 void
 BluetoothOppManager::AfterOppDisconnected()
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -575,44 +575,44 @@ BluetoothOppManager::ExtractPacketHeader
 
 bool
 BluetoothOppManager::ExtractBlobHeaders()
 {
   RetrieveSentFileName();
 
   nsresult rv = mBlob->GetType(mContentType);
   if (NS_FAILED(rv)) {
-    NS_WARNING("Can't get content type");
+    BT_WARNING("Can't get content type");
     SendDisconnectRequest();
     return false;
   }
 
   uint64_t fileLength;
   rv = mBlob->GetSize(&fileLength);
   if (NS_FAILED(rv)) {
-    NS_WARNING("Can't get file size");
+    BT_WARNING("Can't get file size");
     SendDisconnectRequest();
     return false;
   }
 
   // Currently we keep the size of files which were sent/received via
   // Bluetooth not exceed UINT32_MAX because the Length header in OBEX
   // is only 4-byte long. Although it is possible to transfer a file
   // larger than UINT32_MAX, it needs to parse another OBEX Header
   // and I would like to leave it as a feature.
   if (fileLength > (uint64_t)UINT32_MAX) {
-    NS_WARNING("The file size is too large for now");
+    BT_WARNING("The file size is too large for now");
     SendDisconnectRequest();
     return false;
   }
 
   mFileLength = fileLength;
   rv = NS_NewThread(getter_AddRefs(mReadFileThread));
   if (NS_FAILED(rv)) {
-    NS_WARNING("Can't create thread");
+    BT_WARNING("Can't create thread");
     SendDisconnectRequest();
     return false;
   }
 
   return true;
 }
 
 void
@@ -824,20 +824,20 @@ BluetoothOppManager::ServerDataHandler(U
       mSuccessFlag = true;
       FileTransferComplete();
       NotifyAboutFileChange();
     }
   } else if (opCode == ObexRequestCode::Get ||
              opCode == ObexRequestCode::GetFinal ||
              opCode == ObexRequestCode::SetPath) {
     ReplyError(ObexResponseCode::BadRequest);
-    NS_WARNING("Unsupported ObexRequestCode");
+    BT_WARNING("Unsupported ObexRequestCode");
   } else {
     ReplyError(ObexResponseCode::NotImplemented);
-    NS_WARNING("Unrecognized ObexRequestCode");
+    BT_WARNING("Unrecognized ObexRequestCode");
   }
 }
 
 void
 BluetoothOppManager::ClearQueue()
 {
   mCurrentBlobIndex = -1;
   mBlob = nullptr;
@@ -873,17 +873,17 @@ BluetoothOppManager::ClientDataHandler(U
         mLastCommand == ObexRequestCode::Abort ||
         mLastCommand == ObexRequestCode::PutFinal) {
       SendDisconnectRequest();
     }
     nsAutoCString str;
     str += "[OPP] 0x";
     str.AppendInt(mLastCommand, 16);
     str += " failed";
-    NS_WARNING(str.get());
+    BT_WARNING(str.get());
     FileTransferComplete();
     return;
   }
 
   if (mLastCommand == ObexRequestCode::PutFinal) {
     mSuccessFlag = true;
     FileTransferComplete();
 
@@ -937,31 +937,31 @@ BluetoothOppManager::ClientDataHandler(U
       UpdateProgress();
       mUpdateProgressCounter = mSentFileLength / kUpdateProgressBase + 1;
     }
 
     nsresult rv;
     if (!mInputStream) {
       rv = mBlob->GetInternalStream(getter_AddRefs(mInputStream));
       if (NS_FAILED(rv)) {
-        NS_WARNING("Can't get internal stream of blob");
+        BT_WARNING("Can't get internal stream of blob");
         SendDisconnectRequest();
         return;
       }
     }
 
     nsRefPtr<ReadFileTask> task = new ReadFileTask(mInputStream,
                                                    mRemoteMaxPacketLength);
     rv = mReadFileThread->Dispatch(task, NS_DISPATCH_NORMAL);
     if (NS_FAILED(rv)) {
-      NS_WARNING("Cannot dispatch read file task!");
+      BT_WARNING("Cannot dispatch read file task!");
       SendDisconnectRequest();
     }
   } else {
-    NS_WARNING("Unhandled ObexRequestCode");
+    BT_WARNING("Unhandled ObexRequestCode");
   }
 }
 
 // Virtual function of class SocketConsumer
 void
 BluetoothOppManager::ReceiveSocketData(BluetoothSocket* aSocket,
                                        nsAutoPtr<UnixSocketRawData>& aMessage)
 {
@@ -1024,17 +1024,17 @@ BluetoothOppManager::SendPutHeaderReques
 void
 BluetoothOppManager::SendPutRequest(uint8_t* aFileBody,
                                     int aFileBodyLength)
 {
   int packetLeftSpace = mRemoteMaxPacketLength - kPutRequestHeaderSize;
 
   if (!mConnected) return;
   if (aFileBodyLength > packetLeftSpace) {
-    NS_WARNING("Not allowed such a small MaxPacketLength value");
+    BT_WARNING("Not allowed such a small MaxPacketLength value");
     return;
   }
 
   // Section 3.3.3 "Put", IrOBEX 1.2
   // [opcode:1][length:2][Headers:var]
   uint8_t* req = new uint8_t[mRemoteMaxPacketLength];
 
   int index = 3;
@@ -1229,17 +1229,17 @@ BluetoothOppManager::FileTransferComplet
   v = mSentFileLength;
   parameters.AppendElement(BluetoothNamedValue(name, v));
 
   name.AssignLiteral("contentType");
   v = mContentType;
   parameters.AppendElement(BluetoothNamedValue(name, v));
 
   if (!BroadcastSystemMessage(type, parameters)) {
-    NS_WARNING("Failed to broadcast [bluetooth-opp-transfer-complete]");
+    BT_WARNING("Failed to broadcast [bluetooth-opp-transfer-complete]");
     return;
   }
 
   mSendTransferCompleteFlag = true;
 }
 
 void
 BluetoothOppManager::StartFileTransfer()
@@ -1265,17 +1265,17 @@ BluetoothOppManager::StartFileTransfer()
   v = mFileLength;
   parameters.AppendElement(BluetoothNamedValue(name, v));
 
   name.AssignLiteral("contentType");
   v = mContentType;
   parameters.AppendElement(BluetoothNamedValue(name, v));
 
   if (!BroadcastSystemMessage(type, parameters)) {
-    NS_WARNING("Failed to broadcast [bluetooth-opp-transfer-start]");
+    BT_WARNING("Failed to broadcast [bluetooth-opp-transfer-start]");
     return;
   }
 }
 
 void
 BluetoothOppManager::UpdateProgress()
 {
   nsString type, name;
@@ -1295,17 +1295,17 @@ BluetoothOppManager::UpdateProgress()
   v = mSentFileLength;
   parameters.AppendElement(BluetoothNamedValue(name, v));
 
   name.AssignLiteral("fileLength");
   v = mFileLength;
   parameters.AppendElement(BluetoothNamedValue(name, v));
 
   if (!BroadcastSystemMessage(type, parameters)) {
-    NS_WARNING("Failed to broadcast [bluetooth-opp-update-progress]");
+    BT_WARNING("Failed to broadcast [bluetooth-opp-update-progress]");
     return;
   }
 }
 
 void
 BluetoothOppManager::ReceivingFileConfirmation()
 {
   nsString type, name;
@@ -1325,17 +1325,17 @@ BluetoothOppManager::ReceivingFileConfir
   v = mFileLength;
   parameters.AppendElement(BluetoothNamedValue(name, v));
 
   name.AssignLiteral("contentType");
   v = mContentType;
   parameters.AppendElement(BluetoothNamedValue(name, v));
 
   if (!BroadcastSystemMessage(type, parameters)) {
-    NS_WARNING("Failed to send [bluetooth-opp-receiving-file-confirmation]");
+    BT_WARNING("Failed to send [bluetooth-opp-receiving-file-confirmation]");
     return;
   }
 }
 
 void
 BluetoothOppManager::NotifyAboutFileChange()
 {
   NS_NAMED_LITERAL_STRING(data, "modified");
--- a/dom/bluetooth/BluetoothOppManager.h
+++ b/dom/bluetooth/BluetoothOppManager.h
@@ -73,16 +73,21 @@ public:
   // The following functions are inherited from BluetoothProfileManagerBase
   virtual void OnGetServiceChannel(const nsAString& aDeviceAddress,
                                    const nsAString& aServiceUuid,
                                    int aChannel) MOZ_OVERRIDE;
   virtual void OnUpdateSdpRecords(const nsAString& aDeviceAddress) MOZ_OVERRIDE;
   virtual void GetAddress(nsAString& aDeviceAddress) MOZ_OVERRIDE;
   virtual bool IsConnected() MOZ_OVERRIDE;
 
+  virtual void GetName(nsACString& aName)
+  {
+    aName.AssignLiteral("OPP");
+  }
+
   /*
    * If an application wants to send a file, first, it needs to
    * call Connect() to create a valid RFCOMM connection. After
    * that, call SendFile()/StopSendingFile() to control file-sharing
    * process. During the file transfering process, the application
    * will receive several system messages which contain the processed
    * percentage of file. At the end, the application will get another
    * system message indicating that the process is complete, then it can
--- a/dom/bluetooth/BluetoothProfileController.cpp
+++ b/dom/bluetooth/BluetoothProfileController.cpp
@@ -12,16 +12,24 @@
 #include "BluetoothHidManager.h"
 #include "BluetoothOppManager.h"
 
 #include "BluetoothUtils.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 
 USING_BLUETOOTH_NAMESPACE
 
+#define BT_LOGR_PROFILE(mgr, args...)                 \
+  do {                                                \
+    nsCString name;                                   \
+    mgr->GetName(name);                               \
+    BT_LOGR("%s: [%s] %s", __FUNCTION__, name.get(),  \
+      nsPrintfCString(args).get());                   \
+  } while(0)
+
 BluetoothProfileController::BluetoothProfileController(
                                    const nsAString& aDeviceAddress,
                                    BluetoothReplyRunnable* aRunnable,
                                    BluetoothProfileControllerCallback aCallback)
   : mCallback(aCallback)
   , mDeviceAddress(aDeviceAddress)
   , mRunnable(aRunnable)
   , mSuccess(false)
@@ -115,17 +123,16 @@ BluetoothProfileController::Connect(uint
 
   mCod = aCod;
 
   /**
    * Connect to HFP/HSP first. Then, connect A2DP if Rendering bit is set.
    * It's almost impossible to send file to a remote device which is an Audio
    * device or a Rendering device, so we won't connect OPP in that case.
    */
-  BluetoothProfileManagerBase* profile;
   if (hasAudio) {
     AddProfile(BluetoothHfpManager::Get());
   }
   if (hasRendering) {
     AddProfile(BluetoothA2dpManager::Get());
   }
   if (hasObjectTransfer && !hasAudio && !hasRendering) {
     AddProfile(BluetoothOppManager::Get());
@@ -139,16 +146,17 @@ BluetoothProfileController::Connect(uint
 
 void
 BluetoothProfileController::ConnectNext()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (++mProfilesIndex < mProfiles.Length()) {
     MOZ_ASSERT(!mDeviceAddress.IsEmpty());
+    BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "");
 
     mProfiles[mProfilesIndex]->Connect(mDeviceAddress, this);
     return;
   }
 
   MOZ_ASSERT(mRunnable && mCallback);
 
   // The action has been completed, so the dom request is replied and then
@@ -161,16 +169,18 @@ BluetoothProfileController::ConnectNext(
   }
   mCallback();
 }
 
 void
 BluetoothProfileController::OnConnect(const nsAString& aErrorStr)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "<%s>",
+    NS_ConvertUTF16toUTF8(aErrorStr).get());
 
   if (!aErrorStr.IsEmpty()) {
     BT_WARNING(NS_ConvertUTF16toUTF8(aErrorStr).get());
   } else {
     mSuccess = true;
   }
 
   ConnectNext();
@@ -198,16 +208,18 @@ BluetoothProfileController::Disconnect(B
 }
 
 void
 BluetoothProfileController::DisconnectNext()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (++mProfilesIndex < mProfiles.Length()) {
+    BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "");
+
     mProfiles[mProfilesIndex]->Disconnect(this);
     return;
   }
 
   MOZ_ASSERT(mRunnable && mCallback);
 
   // The action has been completed, so the dom request is replied and then
   // the callback is invoked
@@ -219,18 +231,19 @@ BluetoothProfileController::DisconnectNe
   }
   mCallback();
 }
 
 void
 BluetoothProfileController::OnDisconnect(const nsAString& aErrorStr)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "<%s>",
+    NS_ConvertUTF16toUTF8(aErrorStr).get());
 
   if (!aErrorStr.IsEmpty()) {
     BT_WARNING(NS_ConvertUTF16toUTF8(aErrorStr).get());
   } else {
     mSuccess = true;
   }
 
   DisconnectNext();
 }
-
--- a/dom/bluetooth/BluetoothProfileManagerBase.h
+++ b/dom/bluetooth/BluetoothProfileManagerBase.h
@@ -58,13 +58,18 @@ public:
   virtual void Disconnect(BluetoothProfileController* aController) = 0;
 
   /**
    * If it establishes/releases a connection successfully, the error string
    * will be empty. Otherwise, the error string shows the failure reason.
    */
   virtual void OnConnect(const nsAString& aErrorStr) = 0;
   virtual void OnDisconnect(const nsAString& aErrorStr) = 0;
+
+  /**
+   * Returns string of profile name
+   */
+  virtual void GetName(nsACString& aName) = 0;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif  //#ifndef mozilla_dom_bluetooth_bluetoothprofilemanagerbase_h__
--- a/dom/bluetooth/BluetoothPropertyContainer.cpp
+++ b/dom/bluetooth/BluetoothPropertyContainer.cpp
@@ -36,17 +36,17 @@ BluetoothPropertyContainer::SetProperty(
                                         ErrorResult& aRv)
 {
   nsRefPtr<mozilla::dom::DOMRequest> request = new DOMRequest(aOwner);
   nsRefPtr<BluetoothReplyRunnable> task =
     new BluetoothVoidReplyRunnable(request);
 
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
-    NS_WARNING("Bluetooth service not available!");
+    BT_WARNING("Bluetooth service not available!");
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsresult rv = bs->SetProperty(mObjectType, aProperty, task);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
--- a/dom/bluetooth/BluetoothReplyRunnable.cpp
+++ b/dom/bluetooth/BluetoothReplyRunnable.cpp
@@ -68,17 +68,17 @@ BluetoothReplyRunnable::Run()
     if (!ParseSuccessfulReply(&v)) {
       rv = FireErrorString();
     } else {
       rv = FireReply(v);
     }
   }
 
   if (NS_FAILED(rv)) {
-    NS_WARNING("Could not fire DOMRequest!");
+    BT_WARNING("Could not fire DOMRequest!");
   }
 
   ReleaseMembers();
   MOZ_ASSERT(!mDOMRequest,
              "mDOMRequest still alive! Deriving class should call "
              "BluetoothReplyRunnable::ReleaseMembers()!");
 
   return rv;
--- a/dom/bluetooth/BluetoothRilListener.cpp
+++ b/dom/bluetooth/BluetoothRilListener.cpp
@@ -187,20 +187,20 @@ TelephonyListener::NotifyError(int32_t a
     // In order to not miss any related call state transition.
     // It's possible that 3G network signal lost for unknown reason.
     // If a call is released abnormally, NotifyError() will be called,
     // instead of CallStateChanged(). We need to reset the call array state
     // via setting CALL_STATE_DISCONNECTED
     hfp->HandleCallStateChanged(aCallIndex,
                                 nsITelephonyProvider::CALL_STATE_DISCONNECTED,
                                 aError, EmptyString(), false, true);
-    NS_WARNING("Reset the call state due to call transition ends abnormally");
+    BT_WARNING("Reset the call state due to call transition ends abnormally");
   }
 
-  NS_WARNING(NS_ConvertUTF16toUTF8(aError).get());
+  BT_WARNING(NS_ConvertUTF16toUTF8(aError).get());
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TelephonyListener::ConferenceCallStateChanged(uint16_t aCallState)
 {
   return NS_OK;
 }
--- a/dom/bluetooth/BluetoothService.cpp
+++ b/dom/bluetooth/BluetoothService.cpp
@@ -181,48 +181,48 @@ public:
      * When two values are the same, we don't switch on/off bluetooth
      * but we still do ToggleBtAck task. One special case happens at startup
      * stage. At startup, the initialization of BluetoothService still has to
      * be done even if mEnabled is equal to the status of Bluetooth firmware.
      *
      * Please see bug 892392 for more information.
      */
     if (!mIsStartup && mEnabled == gBluetoothService->IsEnabledInternal()) {
-      NS_WARNING("Bluetooth has already been enabled/disabled before.");
+      BT_WARNING("Bluetooth has already been enabled/disabled before.");
     } else {
       // Switch on/off bluetooth
       if (mEnabled) {
         if (NS_FAILED(gBluetoothService->StartInternal())) {
-          NS_WARNING("Bluetooth service failed to start!");
+          BT_WARNING("Bluetooth service failed to start!");
           mEnabled = !mEnabled;
         }
       } else {
         if (NS_FAILED(gBluetoothService->StopInternal())) {
-          NS_WARNING("Bluetooth service failed to stop!");
+          BT_WARNING("Bluetooth service failed to stop!");
           mEnabled = !mEnabled;
         }
       }
     }
 
     // This is requested in Bug 836516. With settings this property, WLAN
     // firmware could be aware of Bluetooth has been turned on/off, so that the
     // mecahnism of handling coexistence of WIFI and Bluetooth could be started.
     //
     // In the future, we may have our own way instead of setting a system
     // property to let firmware developers be able to sense that Bluetooth has
     // been toggled.
 #if defined(MOZ_WIDGET_GONK)
     if (property_set(PROP_BLUETOOTH_ENABLED, mEnabled ? "true" : "false") != 0) {
-      NS_WARNING("Failed to set bluetooth enabled property");
+      BT_WARNING("Failed to set bluetooth enabled property");
     }
 #endif
 
     nsCOMPtr<nsIRunnable> ackTask = new BluetoothService::ToggleBtAck(mEnabled);
     if (NS_FAILED(NS_DispatchToMainThread(ackTask))) {
-      NS_WARNING("Failed to dispatch to main thread!");
+      BT_WARNING("Failed to dispatch to main thread!");
     }
 
     return NS_OK;
   }
 
 private:
   bool mEnabled;
   bool mIsStartup;
@@ -233,32 +233,32 @@ class BluetoothService::StartupTask : pu
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD Handle(const nsAString& aName, const JS::Value& aResult)
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     if (!aResult.isBoolean()) {
-      NS_WARNING("Setting for '" BLUETOOTH_ENABLED_SETTING "' is not a boolean!");
+      BT_WARNING("Setting for '" BLUETOOTH_ENABLED_SETTING "' is not a boolean!");
       return NS_OK;
     }
 
     // It is theoretically possible to shut down before the first settings check
     // has completed (though extremely unlikely).
     if (gBluetoothService) {
       return gBluetoothService->HandleStartupSettingsCheck(aResult.toBoolean());
     }
 
     return NS_OK;
   }
 
   NS_IMETHOD HandleError(const nsAString& aName)
   {
-    NS_WARNING("Unable to get value for '" BLUETOOTH_ENABLED_SETTING "'");
+    BT_WARNING("Unable to get value for '" BLUETOOTH_ENABLED_SETTING "'");
     return NS_OK;
   }
 };
 
 NS_IMPL_ISUPPORTS1(BluetoothService::StartupTask, nsISettingsServiceCallback);
 
 NS_IMPL_ISUPPORTS1(BluetoothService, nsIObserver)
 
@@ -302,66 +302,66 @@ BluetoothService::Create()
   }
 #endif
 
 #if defined(MOZ_BLUETOOTH_GONK)
   return new BluetoothGonkService();
 #elif defined(MOZ_BLUETOOTH_DBUS)
   return new BluetoothDBusService();
 #endif
-  NS_WARNING("No platform support for bluetooth!");
+  BT_WARNING("No platform support for bluetooth!");
   return nullptr;
 }
 
 bool
 BluetoothService::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   NS_ENSURE_TRUE(obs, false);
 
   if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
                                  false))) {
-    NS_WARNING("Failed to add shutdown observer!");
+    BT_WARNING("Failed to add shutdown observer!");
     return false;
   }
 
   // Only the main process should observe bluetooth settings changes.
   if (IsMainProcess() &&
       NS_FAILED(obs->AddObserver(this, MOZSETTINGS_CHANGED_ID, false))) {
-    NS_WARNING("Failed to add settings change observer!");
+    BT_WARNING("Failed to add settings change observer!");
     return false;
   }
 
   return true;
 }
 
 void
 BluetoothService::Cleanup()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (obs &&
       (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) ||
        NS_FAILED(obs->RemoveObserver(this, MOZSETTINGS_CHANGED_ID)))) {
-    NS_WARNING("Can't unregister observers!");
+    BT_WARNING("Can't unregister observers!");
   }
 }
 
 void
 BluetoothService::RegisterBluetoothSignalHandler(
                                               const nsAString& aNodeName,
                                               BluetoothSignalObserver* aHandler)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aHandler);
 
-  BT_LOG("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aNodeName).get());
+  BT_LOGD("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aNodeName).get());
 
   BluetoothSignalObserverList* ol;
   if (!mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
     ol = new BluetoothSignalObserverList();
     mBluetoothSignalObserverTable.Put(aNodeName, ol);
   }
 
   ol->AddObserver(aHandler);
@@ -370,31 +370,31 @@ BluetoothService::RegisterBluetoothSigna
 void
 BluetoothService::UnregisterBluetoothSignalHandler(
                                               const nsAString& aNodeName,
                                               BluetoothSignalObserver* aHandler)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aHandler);
 
-  BT_LOG("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aNodeName).get());
+  BT_LOGD("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aNodeName).get());
 
   BluetoothSignalObserverList* ol;
   if (mBluetoothSignalObserverTable.Get(aNodeName, &ol)) {
     ol->RemoveObserver(aHandler);
     // We shouldn't have duplicate instances in the ObserverList, but there's
     // no appropriate way to do duplication check while registering, so
     // assertions are added here.
     MOZ_ASSERT(!ol->RemoveObserver(aHandler));
     if (ol->Length() == 0) {
       mBluetoothSignalObserverTable.Remove(aNodeName);
     }
   }
   else {
-    NS_WARNING("Node was never registered!");
+    BT_WARNING("Node was never registered!");
   }
 }
 
 PLDHashOperator
 RemoveAllSignalHandlers(const nsAString& aKey,
                         nsAutoPtr<BluetoothSignalObserverList>& aData,
                         void* aUserArg)
 {
@@ -429,17 +429,17 @@ BluetoothService::DistributeSignal(const
     return;
   }
 
   BluetoothSignalObserverList* ol;
   if (!mBluetoothSignalObserverTable.Get(aSignal.path(), &ol)) {
 #if DEBUG
     nsAutoCString msg("No observer registered for path ");
     msg.Append(NS_ConvertUTF16toUTF8(aSignal.path()));
-    NS_WARNING(msg.get());
+    BT_WARNING(msg.get());
 #endif
     return;
   }
   MOZ_ASSERT(ol->Length());
   ol->Broadcast(aSignal);
 }
 
 nsresult
@@ -524,17 +524,17 @@ BluetoothService::SetEnabled(bool aEnabl
       RemoveObserversExceptBluetoothManager, nullptr);
   }
 
   /**
    * mEnabled: real status of bluetooth
    * aEnabled: expected status of bluetooth
    */
   if (mEnabled == aEnabled) {
-    NS_WARNING("Bluetooth has already been enabled/disabled before\
+    BT_WARNING("Bluetooth has already been enabled/disabled before\
                 or the toggling is failed.");
   }
 
   mEnabled = aEnabled;
 
   gToggleInProgress = false;
 }
 
@@ -730,17 +730,17 @@ BluetoothService::Get()
 
   // If we already exist, exit early
   if (gBluetoothService) {
     return gBluetoothService;
   }
 
   // If we're in shutdown, don't create a new instance
   if (gInShutdown) {
-    NS_WARNING("BluetoothService can't be created during shutdown");
+    BT_WARNING("BluetoothService can't be created during shutdown");
     return nullptr;
   }
 
   // Create new instance, register, return
   nsRefPtr<BluetoothService> service = BluetoothService::Create();
   NS_ENSURE_TRUE(service, nullptr);
 
   if (!service->Init()) {
@@ -779,21 +779,21 @@ BluetoothService::Notify(const Bluetooth
 {
   nsString type = NS_LITERAL_STRING("bluetooth-pairing-request");
 
   AutoSafeJSContext cx;
   JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, nullptr, nullptr, nullptr));
   NS_ENSURE_TRUE_VOID(obj);
 
   if (!SetJsObject(cx, aData.value(), obj)) {
-    NS_WARNING("Failed to set properties of system message!");
+    BT_WARNING("Failed to set properties of system message!");
     return;
   }
 
-  BT_LOG("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
+  BT_LOGD("[S] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get());
 
   if (aData.name().EqualsLiteral("RequestConfirmation")) {
     MOZ_ASSERT(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 4,
       "RequestConfirmation: Wrong length of parameters");
   } else if (aData.name().EqualsLiteral("RequestPinCode")) {
     MOZ_ASSERT(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 3,
       "RequestPinCode: Wrong length of parameters");
   } else if (aData.name().EqualsLiteral("RequestPasskey")) {
@@ -806,17 +806,17 @@ BluetoothService::Notify(const Bluetooth
   } else if (aData.name().EqualsLiteral(PAIRED_STATUS_CHANGED_ID)) {
     MOZ_ASSERT(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 1,
       "pairedstatuschanged: Wrong length of parameters");
     type.AssignLiteral("bluetooth-pairedstatuschanged");
   } else {
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling service signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
-    NS_WARNING(warningMsg.get());
+    BT_WARNING(warningMsg.get());
     return;
   }
 
   nsCOMPtr<nsISystemMessagesInternal> systemMessenger =
     do_GetService("@mozilla.org/system-message-internal;1");
   NS_ENSURE_TRUE_VOID(systemMessenger);
 
   systemMessenger->BroadcastMessage(type,
--- a/dom/bluetooth/BluetoothSocket.cpp
+++ b/dom/bluetooth/BluetoothSocket.cpp
@@ -32,17 +32,17 @@ BluetoothSocket::Connect(const nsACStrin
   MOZ_ASSERT(!aDeviceAddress.IsEmpty());
 
   nsAutoPtr<BluetoothUnixSocketConnector> c(
     new BluetoothUnixSocketConnector(mType, aChannel, mAuth, mEncrypt));
 
   if (!ConnectSocket(c.forget(), aDeviceAddress.BeginReading())) {
     nsAutoString addr;
     GetAddress(addr);
-    BT_LOG("%s failed. Current connected device address: %s",
+    BT_LOGD("%s failed. Current connected device address: %s",
            __FUNCTION__, NS_ConvertUTF16toUTF8(addr).get());
     return false;
   }
 
   return true;
 }
 
 bool
@@ -51,17 +51,17 @@ BluetoothSocket::Listen(int aChannel)
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoPtr<BluetoothUnixSocketConnector> c(
     new BluetoothUnixSocketConnector(mType, aChannel, mAuth, mEncrypt));
 
   if (!ListenSocket(c.forget())) {
     nsAutoString addr;
     GetAddress(addr);
-    BT_LOG("%s failed. Current connected device address: %s",
+    BT_LOGD("%s failed. Current connected device address: %s",
            __FUNCTION__, NS_ConvertUTF16toUTF8(addr).get());
     return false;
   }
 
   return true;
 }
 
 void
--- a/dom/bluetooth/BluetoothUnixSocketConnector.cpp
+++ b/dom/bluetooth/BluetoothUnixSocketConnector.cpp
@@ -94,32 +94,32 @@ BluetoothUnixSocketConnector::SetUp(int 
     break;
   default:
     MOZ_CRASH("Unknown socket type!");
   }
 
   if (lm) {
     if (mType == BluetoothSocketType::RFCOMM) {
       if (setsockopt(aFd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
-        NS_WARNING("setsockopt(RFCOMM_LM) failed, throwing");
+        BT_WARNING("setsockopt(RFCOMM_LM) failed, throwing");
         return false;
       }
     } else if (mType == BluetoothSocketType::L2CAP ||
                mType == BluetoothSocketType::EL2CAP) {
       if (setsockopt(aFd, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm))) {
-        NS_WARNING("setsockopt(L2CAP_LM) failed, throwing");
+        BT_WARNING("setsockopt(L2CAP_LM) failed, throwing");
         return false;
       }
     }
   }
 
   if (mType == BluetoothSocketType::RFCOMM) {
     sndbuf = RFCOMM_SO_SNDBUF;
     if (setsockopt(aFd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
-      NS_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
+      BT_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
       return false;
     }
   }
 
   /* Setting L2CAP socket options */
   if (mType == BluetoothSocketType::L2CAP ||
       mType == BluetoothSocketType::EL2CAP) {
     struct l2cap_options opts;
@@ -141,23 +141,23 @@ BluetoothUnixSocketConnector::SetUp(int 
 
       err = setsockopt(aFd, SOL_L2CAP, L2CAP_OPTIONS, &opts, optlen);
     }
 
     /* Set larger SNDBUF & RCVBUF for EL2CAP connections */
     if (mType == BluetoothSocketType::EL2CAP) {
       sndbuf = L2CAP_SO_SNDBUF;
       if (setsockopt(aFd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
-        NS_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
+        BT_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
         return false;
       }
 
       rcvbuf = L2CAP_SO_RCVBUF;
       if (setsockopt(aFd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf))) {
-        NS_WARNING("setsockopt(SO_RCVBUF) failed, throwing");
+        BT_WARNING("setsockopt(SO_RCVBUF) failed, throwing");
         return false;
       }
     }
   }
 
   return true;
 }
 
@@ -180,22 +180,22 @@ BluetoothUnixSocketConnector::Create()
   case BluetoothSocketType::EL2CAP:
     fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_L2CAP);
     break;
   default:
     MOZ_CRASH();
   }
 
   if (fd < 0) {
-    NS_WARNING("Could not open bluetooth socket!");
+    BT_WARNING("Could not open bluetooth socket!");
     return -1;
   }
 
   if (!SetUp(fd)) {
-    NS_WARNING("Could not set up socket!");
+    BT_WARNING("Could not set up socket!");
     return -1;
   }
 
   return fd;
 }
 
 bool
 BluetoothUnixSocketConnector::CreateAddr(bool aIsServer,
@@ -203,17 +203,17 @@ BluetoothUnixSocketConnector::CreateAddr
                                          sockaddr_any& aAddr,
                                          const char* aAddress)
 {
   // Set to BDADDR_ANY, if it's not a server, we'll reset.
   bdaddr_t bd_address_obj = {{0, 0, 0, 0, 0, 0}};
 
   if (!aIsServer && aAddress && strlen(aAddress) > 0) {
     if (get_bdaddr(aAddress, &bd_address_obj)) {
-      NS_WARNING("Can't get bluetooth address!");
+      BT_WARNING("Can't get bluetooth address!");
       return false;
     }
   }
 
   // Initialize
   memset(&aAddr, 0, sizeof(aAddr));
 
   switch (mType) {
@@ -234,17 +234,17 @@ BluetoothUnixSocketConnector::CreateAddr
     break;
   case BluetoothSocketType::SCO:
     struct sockaddr_sco addr_sco;
     aAddrSize = sizeof(addr_sco);
     aAddr.sco.sco_family = AF_BLUETOOTH;
     memcpy(&aAddr.sco.sco_bdaddr, &bd_address_obj, sizeof(bd_address_obj));
     break;
   default:
-    NS_WARNING("Socket type unknown!");
+    BT_WARNING("Socket type unknown!");
     return false;
   }
   return true;
 }
 
 void
 BluetoothUnixSocketConnector::GetSocketAddr(const sockaddr_any& aAddr,
                                             nsAString& aAddrStr)
--- a/dom/bluetooth/BluetoothUtils.cpp
+++ b/dom/bluetooth/BluetoothUtils.cpp
@@ -24,17 +24,17 @@ BEGIN_BLUETOOTH_NAMESPACE
 bool
 SetJsObject(JSContext* aContext,
             const BluetoothValue& aValue,
             JS::Handle<JSObject*> aObj)
 {
   MOZ_ASSERT(aContext && aObj);
 
   if (aValue.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
-    NS_WARNING("SetJsObject: Invalid parameter type");
+    BT_WARNING("SetJsObject: Invalid parameter type");
     return false;
   }
 
   const nsTArray<BluetoothNamedValue>& arr =
     aValue.get_ArrayOfBluetoothNamedValue();
 
   for (uint32_t i = 0; i < arr.Length(); i++) {
     JS::Rooted<JS::Value> val(aContext);
@@ -51,24 +51,24 @@ SetJsObject(JSContext* aContext,
       }
       case BluetoothValue::Tuint32_t:
         val = INT_TO_JSVAL(v.get_uint32_t());
         break;
       case BluetoothValue::Tbool:
         val = BOOLEAN_TO_JSVAL(v.get_bool());
         break;
       default:
-        NS_WARNING("SetJsObject: Parameter is not handled");
+        BT_WARNING("SetJsObject: Parameter is not handled");
         break;
     }
 
     if (!JS_SetProperty(aContext, aObj,
                         NS_ConvertUTF16toUTF8(arr[i].name()).get(),
                         val)) {
-      NS_WARNING("Failed to set property");
+      BT_WARNING("Failed to set property");
       return false;
     }
   }
 
   return true;
 }
 
 nsString
@@ -107,22 +107,22 @@ BroadcastSystemMessage(const nsAString& 
                        const InfallibleTArray<BluetoothNamedValue>& aData)
 {
   mozilla::AutoSafeJSContext cx;
   NS_ASSERTION(!::JS_IsExceptionPending(cx),
       "Shouldn't get here when an exception is pending!");
 
   JS::RootedObject obj(cx, JS_NewObject(cx, NULL, NULL, NULL));
   if (!obj) {
-    NS_WARNING("Failed to new JSObject for system message!");
+    BT_WARNING("Failed to new JSObject for system message!");
     return false;
   }
 
   if (!SetJsObject(cx, aData, obj)) {
-    NS_WARNING("Failed to set properties of system message!");
+    BT_WARNING("Failed to set properties of system message!");
     return false;
   }
 
   nsCOMPtr<nsISystemMessagesInternal> systemMessenger =
     do_GetService("@mozilla.org/system-message-internal;1");
   NS_ENSURE_TRUE(systemMessenger, false);
 
   systemMessenger->BroadcastMessage(aType,
@@ -144,17 +144,17 @@ DispatchBluetoothReply(BluetoothReplyRun
     reply = new BluetoothReply(BluetoothReplyError(err));
   } else {
     MOZ_ASSERT(aValue.type() != BluetoothValue::T__None);
     reply = new BluetoothReply(BluetoothReplySuccess(aValue));
   }
 
   aRunnable->SetReply(reply);
   if (NS_FAILED(NS_DispatchToMainThread(aRunnable))) {
-    NS_WARNING("Failed to dispatch to main thread!");
+    BT_WARNING("Failed to dispatch to main thread!");
   }
 }
 
 void
 ParseAtCommand(const nsACString& aAtCommand, const int aStart,
                nsTArray<nsCString>& aRetValues)
 {
   int length = aAtCommand.Length();
--- a/dom/bluetooth/gonk/BluetoothGonkService.cpp
+++ b/dom/bluetooth/gonk/BluetoothGonkService.cpp
@@ -94,28 +94,29 @@ StartStopGonkBluetooth(bool aShouldEnabl
     return NS_OK;
   }
   if (aShouldEnable) {
     result = (sBluedroidFunctions.bt_enable() == 0) ? true : false;
     if (sBluedroidFunctions.bt_is_enabled() < 0) {
       // if isEnabled < 0, this means we brought up the firmware, but something
       // went wrong with bluetoothd. Post a warning message, but try to proceed
       // with firmware unloading if that was requested, so we can retry later.
-      NS_WARNING("Bluetooth firmware up, but cannot connect to HCI socket! Check bluetoothd and try stopping/starting bluetooth again.");
+      BT_WARNING("Bluetooth firmware up, but cannot connect to HCI socket! "
+        "Check bluetoothd and try stopping/starting bluetooth again.");
       // Just disable now, return an error.
       if (sBluedroidFunctions.bt_disable() != 0) {
-        NS_WARNING("Problem shutting down bluetooth after error in bringup!");
+        BT_WARNING("Problem shutting down bluetooth after error in bringup!");
       }
       return NS_ERROR_FAILURE;
     }
   } else {
     result = (sBluedroidFunctions.bt_disable() == 0) ? true : false;
   }
   if (!result) {
-    NS_WARNING("Could not set gonk bluetooth firmware!");
+    BT_WARNING("Could not set gonk bluetooth firmware!");
     return NS_ERROR_FAILURE;
   }
   
   return NS_OK;
 }
 
 nsresult
 BluetoothGonkService::StartInternal()
--- a/dom/bluetooth/ipc/BluetoothParent.cpp
+++ b/dom/bluetooth/ipc/BluetoothParent.cpp
@@ -43,17 +43,17 @@ public:
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(mReply);
 
     if (mRequest) {
       // Must do this first because Send__delete__ will delete mRequest.
       mRequest->RequestComplete();
 
       if (!mRequest->Send__delete__(mRequest, *mReply)) {
-        NS_WARNING("Failed to send response to child process!");
+        BT_WARNING("Failed to send response to child process!");
         return NS_ERROR_FAILURE;
       }
     }
 
     ReleaseMembers();
     return NS_OK;
   }
 
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -30,17 +30,16 @@
 
 #include <cstdio>
 #include <dbus/dbus.h>
 
 #include "nsAutoPtr.h"
 #include "nsThreadUtils.h"
 #include "nsDebug.h"
 #include "nsDataHashtable.h"
-#include "nsPrintfCString.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/Hal.h"
 #include "mozilla/ipc/UnixSocket.h"
 #include "mozilla/ipc/DBusThread.h"
 #include "mozilla/ipc/DBusUtils.h"
 #include "mozilla/ipc/RawDBusConnection.h"
 #include "mozilla/Mutex.h"
@@ -165,17 +164,16 @@ static const char* sBluetoothDBusSignals
   "type='signal',interface='org.bluez.HealthDevice'",
   "type='signal',interface='org.bluez.AudioSink'",
   "type='signal',interface='org.bluez.Control'"
 };
 
 /**
  * DBus Connection held for the BluetoothCommandThread to use. Should never be
  * used by any other thread.
- *
  */
 static nsRefPtr<RawDBusConnection> gThreadConnection;
 static nsDataHashtable<nsStringHashKey, DBusMessage* >* sPairingReqTable;
 static nsTArray<uint32_t> sAuthorizedServiceClass;
 static nsString sAdapterPath;
 static Atomic<int32_t> sIsPairing(0);
 static int sConnectedDeviceCount = 0;
 static StaticAutoPtr<Monitor> sStopBluetoothMonitor;
@@ -201,17 +199,17 @@ GetConnectedDevicesFilter(const Bluetoot
   return true;
 }
 
 static bool
 GetPairedDevicesFilter(const BluetoothValue& aValue)
 {
   // Check property 'Paired' and only paired device will be returned
   if (aValue.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
-    NS_WARNING("Not a BluetoothNamedValue array!");
+    BT_WARNING("Not a BluetoothNamedValue array!");
     return false;
   }
 
   const InfallibleTArray<BluetoothNamedValue>& deviceProperties =
     aValue.get_ArrayOfBluetoothNamedValue();
   uint32_t length = deviceProperties.Length();
   for (uint32_t p = 0; p < length; ++p) {
     if (deviceProperties[p].name().EqualsLiteral("Paired")) {
@@ -364,40 +362,16 @@ IsDBusMessageError(DBusMessage* aMsg, DB
       aErrorStr = NS_ConvertUTF8toUTF16(error_msg);
       return true;
     }
   }
   return false;
 }
 
 static void
-UnpackIntMessage(DBusMessage* aMsg, DBusError* aErr,
-                 BluetoothValue& aValue, nsAString& aErrorStr)
-{
-  MOZ_ASSERT(aMsg);
-
-  DBusError err;
-  dbus_error_init(&err);
-  if (!IsDBusMessageError(aMsg, aErr, aErrorStr)) {
-    MOZ_ASSERT(dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN,
-               "Got dbus callback that's not a METHOD_RETURN!");
-    int i;
-    if (!dbus_message_get_args(aMsg, &err, DBUS_TYPE_INT32,
-                               &i, DBUS_TYPE_INVALID)) {
-      if (dbus_error_is_set(&err)) {
-        aErrorStr = NS_ConvertUTF8toUTF16(err.message);
-        LOG_AND_FREE_DBUS_ERROR(&err);
-      }
-    } else {
-      aValue = (uint32_t)i;
-    }
-  }
-}
-
-static void
 UnpackObjectPathMessage(DBusMessage* aMsg, DBusError* aErr,
                         BluetoothValue& aValue, nsAString& aErrorStr)
 {
   DBusError err;
   dbus_error_init(&err);
   if (!IsDBusMessageError(aMsg, aErr, aErrorStr)) {
     MOZ_ASSERT(dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN,
                "Got dbus callback that's not a METHOD_RETURN!");
@@ -417,23 +391,23 @@ UnpackObjectPathMessage(DBusMessage* aMs
 
 class PrepareProfileManagersRunnable : public nsRunnable
 {
 public:
   nsresult Run()
   {
     BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
     if (!hfp || !hfp->Listen()) {
-      NS_WARNING("Failed to start listening for BluetoothHfpManager!");
+      BT_WARNING("Failed to start listening for BluetoothHfpManager!");
       return NS_ERROR_FAILURE;
     }
 
     BluetoothOppManager* opp = BluetoothOppManager::Get();
     if (!opp || !opp->Listen()) {
-      NS_WARNING("Failed to start listening for BluetoothOppManager!");
+      BT_WARNING("Failed to start listening for BluetoothOppManager!");
       return NS_ERROR_FAILURE;
     }
 
     BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
     NS_ENSURE_TRUE(a2dp, NS_ERROR_FAILURE);
     a2dp->ResetA2dp();
     a2dp->ResetAvrcp();
 
@@ -646,19 +620,19 @@ GetProperty(DBusMessageIter aIter, Prope
    */
   bool convert = false;
   if (propertyName.EqualsLiteral("Connected") &&
       receivedType == DBUS_TYPE_ARRAY) {
     convert = true;
   }
 
   if ((receivedType != expectedType) && !convert) {
-    NS_WARNING(nsPrintfCString("Iterator not type we expect! Property name: %s,
-      Property Type Expected: %d, Property Type Received: %d",
-      NS_ConvertUTF16toUTF8(propertyName).get(), expectedType, receivedType).get());
+    BT_WARNING("Iterator not type we expect! Property name: %s,"
+      "Property Type Expected: %d, Property Type Received: %d",
+      NS_ConvertUTF16toUTF8(propertyName).get(), expectedType, receivedType);
     return false;
   }
 
   BluetoothValue propertyValue;
   switch (receivedType) {
     case DBUS_TYPE_STRING:
     case DBUS_TYPE_OBJECT_PATH:
       const char* c;
@@ -737,17 +711,17 @@ ParseProperties(DBusMessageIter* aIter,
   do {
     MOZ_ASSERT(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY,
                "Trying to parse a property from sth. that's not an dict!");
     dbus_message_iter_recurse(&dict, &dict_entry);
 
     if (!GetProperty(dict_entry, aPropertyTypes, aPropertyTypeLen, &prop_index,
                      props)) {
       aErrorStr.AssignLiteral("Can't Create Property!");
-      NS_WARNING("Can't create property!");
+      BT_WARNING("Can't create property!");
       return;
     }
   } while (dbus_message_iter_next(&dict));
 
   aValue = props;
 }
 
 static bool
@@ -797,23 +771,23 @@ ParsePropertyChange(DBusMessage* aMsg, B
 {
   DBusMessageIter iter;
   DBusError err;
   int prop_index = -1;
   InfallibleTArray<BluetoothNamedValue> props;
 
   dbus_error_init(&err);
   if (!dbus_message_iter_init(aMsg, &iter)) {
-    NS_WARNING("Can't create iterator!");
+    BT_WARNING("Can't create iterator!");
     return;
   }
 
   if (!GetProperty(iter, aPropertyTypes, aPropertyTypeLen,
                    &prop_index, props)) {
-    NS_WARNING("Can't get property!");
+    BT_WARNING("Can't get property!");
     aErrorStr.AssignLiteral("Can't get property!");
     return;
   }
   aValue = props;
 }
 
 class AppendDeviceNameReplyHandler: public DBusReplyHandler
 {
@@ -934,17 +908,17 @@ AgentEventFilter(DBusConnection *conn, D
     BT_WARNING("%s: agent handler not interested (not a method call).\n",
                __FUNCTION__);
     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   }
 
   DBusError err;
   dbus_error_init(&err);
 
-  BT_LOG("%s: %s, %s", __FUNCTION__,
+  BT_LOGD("%s: %s, %s", __FUNCTION__,
                        dbus_message_get_path(msg),
                        dbus_message_get_member(msg));
 
   nsString signalPath = NS_ConvertUTF8toUTF16(dbus_message_get_path(msg));
   nsString signalName = NS_ConvertUTF8toUTF16(dbus_message_get_member(msg));
   nsString errorStr;
   BluetoothValue v;
   InfallibleTArray<BluetoothNamedValue> parameters;
@@ -986,17 +960,17 @@ AgentEventFilter(DBusConnection *conn, D
     NS_ConvertUTF8toUTF16 uuidStr(uuid);
     BluetoothServiceClass serviceClass =
       BluetoothUuidHelper::GetBluetoothServiceClass(uuidStr);
     if (serviceClass == BluetoothServiceClass::UNKNOWN) {
       errorStr.AssignLiteral("Failed to get service class");
       goto handle_error;
     }
 
-    DBusMessage* reply;
+    DBusMessage* reply = nullptr;
     int i;
     int length = sAuthorizedServiceClass.Length();
     for (i = 0; i < length; i++) {
       if (serviceClass == sAuthorizedServiceClass[i]) {
         reply = dbus_message_new_method_return(msg);
         break;
       }
     }
@@ -1194,17 +1168,17 @@ public:
 
     // TODO/qdot: This needs to be held for the life of the bluetooth connection
     // so we could clean it up. For right now though, we can throw it away.
     nsTArray<uint32_t> handles;
 
     ExtractHandles(aReply, handles);
 
     if(!RegisterAgent(&sAgentVTable)) {
-      NS_WARNING("Failed to register agent");
+      BT_WARNING("Failed to register agent");
     }
   }
 
 private:
   void ExtractHandles(DBusMessage *aMessage, nsTArray<uint32_t>& aOutHandles)
   {
     DBusError error;
     int length;
@@ -1375,17 +1349,17 @@ EventFilter(DBusConnection* aConn, DBusM
 
   DBusError err;
   dbus_error_init(&err);
 
   nsAutoString signalPath;
   nsAutoString signalName;
   nsAutoString signalInterface;
 
-  BT_LOG("%s: %s, %s, %s", __FUNCTION__,
+  BT_LOGD("%s: %s, %s, %s", __FUNCTION__,
                           dbus_message_get_interface(aMsg),
                           dbus_message_get_path(aMsg),
                           dbus_message_get_member(aMsg));
 
   signalInterface = NS_ConvertUTF8toUTF16(dbus_message_get_interface(aMsg));
   signalPath = NS_ConvertUTF8toUTF16(dbus_message_get_path(aMsg));
   signalName = NS_ConvertUTF8toUTF16(dbus_message_get_member(aMsg));
   nsString errorStr;
@@ -1401,17 +1375,17 @@ EventFilter(DBusConnection* aConn, DBusM
   } else if (signalInterface.EqualsLiteral(DBUS_DEVICE_IFACE)){
     signalPath = GetAddressFromObjectPath(signalPath);
   }
 
   if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceFound")) {
     DBusMessageIter iter;
 
     if (!dbus_message_iter_init(aMsg, &iter)) {
-      NS_WARNING("Can't create iterator!");
+      BT_WARNING("Can't create iterator!");
       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
 
     const char* addr;
     dbus_message_iter_get_basic(&iter, &addr);
 
     if (!dbus_message_iter_next(&iter)) {
       errorStr.AssignLiteral("Unexpected message struct in msg DeviceFound");
@@ -1578,17 +1552,17 @@ EventFilter(DBusConnection* aConn, DBusM
                         sInputProperties,
                         ArrayLength(sInputProperties));
   } else {
     errorStr = NS_ConvertUTF8toUTF16(dbus_message_get_member(aMsg));
     errorStr.AppendLiteral(" Signal not handled!");
   }
 
   if (!errorStr.IsEmpty()) {
-    NS_WARNING(NS_ConvertUTF16toUTF8(errorStr).get());
+    BT_WARNING(NS_ConvertUTF16toUTF8(errorStr).get());
     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   }
 
   BluetoothSignal signal(signalName, signalPath, v);
   nsRefPtr<nsRunnable> task;
   if (signalInterface.EqualsLiteral(DBUS_SINK_IFACE)) {
     task = new SinkPropertyChangedHandler(signal);
   } else if (signalInterface.EqualsLiteral(DBUS_CTL_IFACE)) {
@@ -1628,47 +1602,47 @@ GetDefaultAdapterPath(BluetoothValue& aV
 
   return aError.IsEmpty();
 }
 
 bool
 BluetoothDBusService::IsReady()
 {
   if (!IsEnabled() || !mConnection || !gThreadConnection || IsToggling()) {
-    NS_WARNING("Bluetooth service is not ready yet!");
+    BT_WARNING("Bluetooth service is not ready yet!");
     return false;
   }
   return true;
 }
 
 nsresult
 BluetoothDBusService::StartInternal()
 {
   // This could block. It should never be run on the main thread.
   MOZ_ASSERT(!NS_IsMainThread());
 
   if (!StartDBus()) {
-    NS_WARNING("Cannot start DBus thread!");
+    BT_WARNING("Cannot start DBus thread!");
     return NS_ERROR_FAILURE;
   }
 
   if (mConnection) {
     return NS_OK;
   }
 
   if (NS_FAILED(EstablishDBusConnection())) {
-    NS_WARNING("Cannot start Main Thread DBus connection!");
+    BT_WARNING("Cannot start Main Thread DBus connection!");
     StopDBus();
     return NS_ERROR_FAILURE;
   }
 
   gThreadConnection = new RawDBusConnection();
 
   if (NS_FAILED(gThreadConnection->EstablishDBusConnection())) {
-    NS_WARNING("Cannot start Sync Thread DBus connection!");
+    BT_WARNING("Cannot start Sync Thread DBus connection!");
     StopDBus();
     return NS_ERROR_FAILURE;
   }
 
   DBusError err;
   dbus_error_init(&err);
 
   // Set which messages will be processed by this dbus connection.
@@ -1682,34 +1656,34 @@ BluetoothDBusService::StartInternal()
     if (dbus_error_is_set(&err)) {
       LOG_AND_FREE_DBUS_ERROR(&err);
     }
   }
 
   // Add a filter for all incoming messages_base
   if (!dbus_connection_add_filter(mConnection, EventFilter,
                                   NULL, NULL)) {
-    NS_WARNING("Cannot create DBus Event Filter for DBus Thread!");
+    BT_WARNING("Cannot create DBus Event Filter for DBus Thread!");
     return NS_ERROR_FAILURE;
   }
 
   if (!sPairingReqTable) {
     sPairingReqTable = new nsDataHashtable<nsStringHashKey, DBusMessage* >;
   }
 
   BluetoothValue v;
   nsAutoString replyError;
   if (!GetDefaultAdapterPath(v, replyError)) {
     // Adapter path is not ready yet
     // Let's do PrepareAdapterRunnable when we receive signal 'AdapterAdded'
   } else {
     // Adapter path has been ready. let's do PrepareAdapterRunnable now
     nsRefPtr<PrepareAdapterRunnable> b = new PrepareAdapterRunnable(v.get_nsString());
     if (NS_FAILED(NS_DispatchToMainThread(b))) {
-      NS_WARNING("Failed to dispatch to main thread!");
+      BT_WARNING("Failed to dispatch to main thread!");
     }
   }
 
   return NS_OK;
 }
 
 PLDHashOperator
 UnrefDBusMessages(const nsAString& key, DBusMessage* value, void* arg)
@@ -2271,25 +2245,25 @@ BluetoothDBusService::SetProperty(Blueto
   /* Compose the command */
   DBusMessage* msg = dbus_message_new_method_call(
                                       "org.bluez",
                                       NS_ConvertUTF16toUTF8(sAdapterPath).get(),
                                       interface,
                                       "SetProperty");
 
   if (!msg) {
-    NS_WARNING("Could not allocate D-Bus message object!");
+    BT_WARNING("Could not allocate D-Bus message object!");
     return NS_ERROR_FAILURE;
   }
 
   nsCString intermediatePropName(NS_ConvertUTF16toUTF8(aValue.name()));
   const char* propName = intermediatePropName.get();
   if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &propName,
                                 DBUS_TYPE_INVALID)) {
-    NS_WARNING("Couldn't append arguments to dbus message!");
+    BT_WARNING("Couldn't append arguments to dbus message!");
     return NS_ERROR_FAILURE;
   }
 
   int type;
   int tmp_int;
   void* val;
   nsCString str;
   if (aValue.value().type() == BluetoothValue::Tuint32_t) {
@@ -2301,42 +2275,42 @@ BluetoothDBusService::SetProperty(Blueto
     const char* tempStr = str.get();
     val = &tempStr;
     type = DBUS_TYPE_STRING;
   } else if (aValue.value().type() == BluetoothValue::Tbool) {
     tmp_int = aValue.value().get_bool() ? 1 : 0;
     val = &(tmp_int);
     type = DBUS_TYPE_BOOLEAN;
   } else {
-    NS_WARNING("Property type not handled!");
+    BT_WARNING("Property type not handled!");
     dbus_message_unref(msg);
     return NS_ERROR_FAILURE;
   }
 
   DBusMessageIter value_iter, iter;
   dbus_message_iter_init_append(msg, &iter);
   char var_type[2] = {(char)type, '\0'};
   if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
                                         var_type, &value_iter) ||
       !dbus_message_iter_append_basic(&value_iter, type, val) ||
       !dbus_message_iter_close_container(&iter, &value_iter)) {
-    NS_WARNING("Could not append argument to method call!");
+    BT_WARNING("Could not append argument to method call!");
     dbus_message_unref(msg);
     return NS_ERROR_FAILURE;
   }
 
   nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
 
   // msg is unref'd as part of dbus_func_send_async
   if (!dbus_func_send_async(mConnection,
                             msg,
                             1000,
                             GetVoidCallback,
                             (void*)aRunnable)) {
-    NS_WARNING("Could not start async function!");
+    BT_WARNING("Could not start async function!");
     return NS_ERROR_FAILURE;
   }
   runnable.forget();
   return NS_OK;
 }
 
 bool
 BluetoothDBusService::GetDevicePath(const nsAString& aAdapterPath,
@@ -2408,17 +2382,17 @@ BluetoothDBusService::CreatePairedDevice
                                   NS_ConvertUTF16toUTF8(sAdapterPath).get(),
                                   DBUS_ADAPTER_IFACE,
                                   "CreatePairedDevice",
                                   DBUS_TYPE_STRING, &deviceAddress,
                                   DBUS_TYPE_OBJECT_PATH, &deviceAgentPath,
                                   DBUS_TYPE_STRING, &capabilities,
                                   DBUS_TYPE_INVALID);
   if (!ret) {
-    NS_WARNING("Could not start async function!");
+    BT_WARNING("Could not start async function!");
     return NS_ERROR_FAILURE;
   }
 
   runnable.forget();
   return NS_OK;
 }
 
 static void
@@ -2672,17 +2646,17 @@ BluetoothDBusService::Disconnect(const n
 bool
 BluetoothDBusService::IsConnected(const uint16_t aServiceUuid)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   BluetoothProfileManagerBase* profile =
     BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid);
   if (!profile) {
-    NS_WARNING(ERR_UNKNOWN_PROFILE);
+    BT_WARNING(ERR_UNKNOWN_PROFILE);
     return false;
   }
 
   NS_ENSURE_TRUE(profile, false);
   return profile->IsConnected();
 }
 
 class OnUpdateSdpRecordsRunnable : public nsRunnable
--- a/dom/bluetooth/linux/BluetoothDBusService.h
+++ b/dom/bluetooth/linux/BluetoothDBusService.h
@@ -1,16 +1,16 @@
 /* -*- 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_bluetooth_bluetoothdbuseventservice_h__
-#define mozilla_dom_bluetooth_bluetoothdbuseventservice_h__
+#ifndef mozilla_dom_bluetooth_bluetoothdbusservice_h__
+#define mozilla_dom_bluetooth_bluetoothdbusservice_h__
 
 #include "mozilla/Attributes.h"
 #include "BluetoothCommon.h"
 #include "mozilla/ipc/RawDBusConnection.h"
 #include "BluetoothService.h"
 
 class DBusMessage;
 
--- a/dom/interfaces/events/moz.build
+++ b/dom/interfaces/events/moz.build
@@ -10,17 +10,16 @@ XPIDL_SOURCES += [
     'nsIDOMClipboardEvent.idl',
     'nsIDOMCloseEvent.idl',
     'nsIDOMCommandEvent.idl',
     'nsIDOMCompositionEvent.idl',
     'nsIDOMCustomEvent.idl',
     'nsIDOMDOMTransactionEvent.idl',
     'nsIDOMDataContainerEvent.idl',
     'nsIDOMDataTransfer.idl',
-    'nsIDOMDeviceLightEvent.idl',
     'nsIDOMDeviceMotionEvent.idl',
     'nsIDOMDeviceOrientationEvent.idl',
     'nsIDOMDragEvent.idl',
     'nsIDOMElementReplaceEvent.idl',
     'nsIDOMEvent.idl',
     'nsIDOMEventListener.idl',
     'nsIDOMEventTarget.idl',
     'nsIDOMFocusEvent.idl',
@@ -43,16 +42,15 @@ XPIDL_SOURCES += [
     'nsIDOMSimpleGestureEvent.idl',
     'nsIDOMSmartCardEvent.idl',
     'nsIDOMStyleRuleChangeEvent.idl',
     'nsIDOMStyleSheetApplicableStateChangeEvent.idl',
     'nsIDOMStyleSheetChangeEvent.idl',
     'nsIDOMTouchEvent.idl',
     'nsIDOMTransitionEvent.idl',
     'nsIDOMUIEvent.idl',
-    'nsIDOMUserProximityEvent.idl',
     'nsIDOMWheelEvent.idl',
 ]
 
 XPIDL_MODULE = 'dom_events'
 
 MODULE = 'dom'
 
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMDeviceLightEvent.idl
+++ /dev/null
@@ -1,21 +0,0 @@
-/* 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 "nsIDOMEvent.idl"
-
-[scriptable, builtinclass, uuid(0e4d1751-fdcd-4ee6-b82d-d3f5d992370d)]
-interface nsIDOMDeviceLightEvent : nsIDOMEvent
-{
-  [noscript] void initDeviceLightEvent(in DOMString eventTypeArg,
-                                       in boolean canBubbleArg,
-                                       in boolean cancelableArg,
-                                       in double value);
-
-  readonly attribute double value;
-};
-
-dictionary DeviceLightEventInit : EventInit
-{
-   double value = Infinity;
-};
--- a/dom/interfaces/events/nsIDOMEvent.idl
+++ b/dom/interfaces/events/nsIDOMEvent.idl
@@ -21,19 +21,18 @@ class nsEvent;
 class nsDOMEvent;
 class nsCommandEvent;
 class nsPresContext;
 class nsInvalidateRequestList;
 namespace IPC {
 class Message;
 }
 namespace mozilla {
-namespace widget {
 class WheelEvent;
-} // namespace widget
+
 namespace dom {
 class EventTarget;
 } // namespace dom
 } // namespace mozilla
 %}
 
 /**
  * The nsIDOMEvent interface is the primary datatype for all events in
@@ -256,17 +255,17 @@ nsresult
 NS_NewDOMMouseScrollEvent(nsIDOMEvent** aInstancePtrResult,
                           mozilla::dom::EventTarget* aOwner,
                           nsPresContext* aPresContext,
                           class nsInputEvent* aEvent);
 nsresult
 NS_NewDOMWheelEvent(nsIDOMEvent** aInstancePtrResult,
                     mozilla::dom::EventTarget* aOwner,
                     nsPresContext* aPresContext,
-                    mozilla::widget::WheelEvent* aEvent);
+                    mozilla::WheelEvent* aEvent);
 nsresult
 NS_NewDOMDragEvent(nsIDOMEvent** aInstancePtrResult,
                    mozilla::dom::EventTarget* aOwner,
                    nsPresContext* aPresContext,
                    class nsDragEvent* aEvent);
 nsresult
 NS_NewDOMClipboardEvent(nsIDOMEvent** aInstancePtrResult,
                         mozilla::dom::EventTarget* aOwner,
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMUserProximityEvent.idl
+++ /dev/null
@@ -1,21 +0,0 @@
-/* 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 "nsIDOMEvent.idl"
-
-[scriptable, builtinclass, uuid(5f1a4c25-e65d-4b50-a883-7498ab88c677)]
-interface nsIDOMUserProximityEvent : nsIDOMEvent
-{
-  [noscript] void initUserProximityEvent(in DOMString eventTypeArg,
-                                         in boolean canBubbleArg,
-                                         in boolean cancelableArg,
-                                         in boolean near);
-
-  readonly attribute boolean near;
-};
-
-dictionary UserProximityEventInit : EventInit
-{
-   boolean near;
-};
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -863,17 +863,18 @@ ContentChild::DeallocPNeckoChild(PNeckoC
 }
 
 PExternalHelperAppChild*
 ContentChild::AllocPExternalHelperAppChild(const OptionalURIParams& uri,
                                            const nsCString& aMimeContentType,
                                            const nsCString& aContentDisposition,
                                            const bool& aForceSave,
                                            const int64_t& aContentLength,
-                                           const OptionalURIParams& aReferrer)
+                                           const OptionalURIParams& aReferrer,
+                                           PBrowserChild* aBrowser)
 {
     ExternalHelperAppChild *child = new ExternalHelperAppChild();
     child->AddRef();
     return child;
 }
 
 bool
 ContentChild::DeallocPExternalHelperAppChild(PExternalHelperAppChild* aService)
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -141,17 +141,18 @@ public:
     virtual bool DeallocPNeckoChild(PNeckoChild*);
 
     virtual PExternalHelperAppChild *AllocPExternalHelperAppChild(
             const OptionalURIParams& uri,
             const nsCString& aMimeContentType,
             const nsCString& aContentDisposition,
             const bool& aForceSave,
             const int64_t& aContentLength,
-            const OptionalURIParams& aReferrer);
+            const OptionalURIParams& aReferrer,
+            PBrowserChild* aBrowser);
     virtual bool DeallocPExternalHelperAppChild(PExternalHelperAppChild *aService);
 
     virtual PSmsChild* AllocPSmsChild();
     virtual bool DeallocPSmsChild(PSmsChild*);
 
     virtual PTelephonyChild* AllocPTelephonyChild();
     virtual bool DeallocPTelephonyChild(PTelephonyChild*);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2230,21 +2230,22 @@ ContentParent::DeallocPNeckoParent(PNeck
 }
 
 PExternalHelperAppParent*
 ContentParent::AllocPExternalHelperAppParent(const OptionalURIParams& uri,
                                              const nsCString& aMimeContentType,
                                              const nsCString& aContentDisposition,
                                              const bool& aForceSave,
                                              const int64_t& aContentLength,
-                                             const OptionalURIParams& aReferrer)
+                                             const OptionalURIParams& aReferrer,
+                                             PBrowserParent* aBrowser)
 {
     ExternalHelperAppParent *parent = new ExternalHelperAppParent(uri, aContentLength);
     parent->AddRef();
-    parent->Init(this, aMimeContentType, aContentDisposition, aForceSave, aReferrer);
+    parent->Init(this, aMimeContentType, aContentDisposition, aForceSave, aReferrer, aBrowser);
     return parent;
 }
 
 bool
 ContentParent::DeallocPExternalHelperAppParent(PExternalHelperAppParent* aService)
 {
     ExternalHelperAppParent *parent = static_cast<ExternalHelperAppParent *>(aService);
     parent->Release();
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -311,17 +311,18 @@ private:
     virtual bool DeallocPNeckoParent(PNeckoParent* necko);
 
     virtual PExternalHelperAppParent* AllocPExternalHelperAppParent(
             const OptionalURIParams& aUri,
             const nsCString& aMimeContentType,
             const nsCString& aContentDisposition,
             const bool& aForceSave,
             const int64_t& aContentLength,
-            const OptionalURIParams& aReferrer);
+            const OptionalURIParams& aReferrer,
+            PBrowserParent* aBrowser);
     virtual bool DeallocPExternalHelperAppParent(PExternalHelperAppParent* aService);
 
     virtual PSmsParent* AllocPSmsParent();
     virtual bool DeallocPSmsParent(PSmsParent*);
 
     virtual PTelephonyParent* AllocPTelephonyParent();
     virtual bool DeallocPTelephonyParent(PTelephonyParent*);
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -39,17 +39,17 @@ using nscolor;
 using nsCompositionEvent;
 using nsIMEUpdatePreference;
 using nsIntPoint;
 using nsIntRect;
 using nsIntSize;
 using nsKeyEvent;
 using nsMouseEvent;
 using nsMouseScrollEvent;
-using mozilla::widget::WheelEvent;
+using mozilla::WheelEvent;
 using nsQueryContentEvent;
 using nsRect;
 using nsSelectionEvent;
 using nsTextEvent;
 using nsTouchEvent;
 using RemoteDOMEvent;
 using mozilla::dom::ScreenOrientation;
 using mozilla::layers::TextureFactoryIdentifier;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -392,17 +392,18 @@ parent:
                           nsString name,
                           nsString bidi,
                           nsString lang);
 
     CloseAlert(nsString name);
 
     PExternalHelperApp(OptionalURIParams uri, nsCString aMimeContentType,
                        nsCString aContentDisposition, bool aForceSave,
-                       int64_t aContentLength, OptionalURIParams aReferrer);
+                       int64_t aContentLength, OptionalURIParams aReferrer,
+                       nullable PBrowser aBrowser);
 
     AddGeolocationListener(Principal principal, bool highAccuracy);
     RemoveGeolocationListener();
     SetGeolocationHigherAccuracy(bool enable);
 
     ConsoleMessage(nsString message);
     ScriptError(nsString message, nsString sourceName, nsString sourceLine,
                 uint32_t lineNumber, uint32_t colNumber, uint32_t flags,
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -219,17 +219,17 @@ public:
                                 const float&    aX,
                                 const float&    aY,
                                 const int32_t&  aButton,
                                 const int32_t&  aClickCount,
                                 const int32_t&  aModifiers,
                                 const bool&     aIgnoreRootScrollFrame);
     virtual bool RecvRealMouseEvent(const nsMouseEvent& event);
     virtual bool RecvRealKeyEvent(const nsKeyEvent& event);
-    virtual bool RecvMouseWheelEvent(const mozilla::widget::WheelEvent& event);
+    virtual bool RecvMouseWheelEvent(const mozilla::WheelEvent& event);
     virtual bool RecvRealTouchEvent(const nsTouchEvent& event);
     virtual bool RecvRealTouchMoveEvent(const nsTouchEvent& event);
     virtual bool RecvKeyEvent(const nsString& aType,
                               const int32_t&  aKeyCode,
                               const int32_t&  aCharCode,
                               const int32_t&  aModifiers,
                               const bool&     aPreventDefault);
     virtual bool RecvCompositionEvent(const nsCompositionEvent& event);
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -192,17 +192,17 @@ public:
 
     void SendMouseEvent(const nsAString& aType, float aX, float aY,
                         int32_t aButton, int32_t aClickCount,
                         int32_t aModifiers, bool aIgnoreRootScrollFrame);
     void SendKeyEvent(const nsAString& aType, int32_t aKeyCode,
                       int32_t aCharCode, int32_t aModifiers,
                       bool aPreventDefault);
     bool SendRealMouseEvent(nsMouseEvent& event);
-    bool SendMouseWheelEvent(mozilla::widget::WheelEvent& event);
+    bool SendMouseWheelEvent(mozilla::WheelEvent& event);
     bool SendRealKeyEvent(nsKeyEvent& event);
     bool SendRealTouchEvent(nsTouchEvent& event);
 
     virtual PDocumentRendererParent*
     AllocPDocumentRendererParent(const nsRect& documentRect, const gfxMatrix& transform,
                                  const nsString& bgcolor,
                                  const uint32_t& renderFlags, const bool& flushLayout,
                                  const nsIntSize& renderSize);
new file mode 100644
--- /dev/null
+++ b/dom/media/GetUserMediaRequest.cpp
@@ -0,0 +1,64 @@
+/* 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 "base/basictypes.h"
+#include "GetUserMediaRequest.h"
+#include "mozilla/dom/MediaStreamTrackBinding.h"
+#include "mozilla/dom/GetUserMediaRequestBinding.h"
+#include "nsIScriptGlobalObject.h"
+#include "nsPIDOMWindow.h"
+#include "nsCxPusher.h"
+
+namespace mozilla {
+namespace dom {
+
+GetUserMediaRequest::GetUserMediaRequest(
+    nsPIDOMWindow* aInnerWindow,
+    const nsAString& aCallID,
+    const MediaStreamConstraintsInternal& aConstraints)
+  : mInnerWindow(aInnerWindow)
+  , mWindowID(aInnerWindow->GetOuterWindow()->WindowID())
+  , mCallID(aCallID)
+  , mConstraints(aConstraints)
+{
+  SetIsDOMBinding();
+}
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(GetUserMediaRequest, mInnerWindow)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(GetUserMediaRequest)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(GetUserMediaRequest)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GetUserMediaRequest)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+JSObject*
+GetUserMediaRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return GetUserMediaRequestBinding::Wrap(aCx, aScope, this);
+}
+
+nsISupports* GetUserMediaRequest::GetParentObject()
+{
+  return mInnerWindow;
+}
+
+void GetUserMediaRequest::GetCallID(nsString& retval)
+{
+  retval = mCallID;
+}
+
+uint64_t GetUserMediaRequest::WindowID()
+{
+  return mWindowID;
+}
+
+void
+GetUserMediaRequest::GetConstraints(MediaStreamConstraintsInternal &result)
+{
+  result = mConstraints;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/GetUserMediaRequest.h
@@ -0,0 +1,48 @@
+/* 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 GetUserMediaRequest_h__
+#define GetUserMediaRequest_h__
+
+#include "mozilla/ErrorResult.h"
+#include "nsISupportsImpl.h"
+#include "nsAutoPtr.h"
+#include "nsWrapperCache.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/MediaStreamTrackBinding.h"
+#include "nsPIDOMWindow.h"
+
+namespace mozilla {
+namespace dom {
+class MediaStreamConstraintsInternal;
+
+class GetUserMediaRequest : public nsISupports, public nsWrapperCache
+{
+public:
+  GetUserMediaRequest(nsPIDOMWindow* aInnerWindow, const nsAString& aCallID,
+                      const MediaStreamConstraintsInternal& aConstraints);
+  virtual ~GetUserMediaRequest() {};
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(GetUserMediaRequest)
+
+  virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> scope)
+    MOZ_OVERRIDE;
+  nsISupports* GetParentObject();
+
+  uint64_t WindowID();
+  void GetCallID(nsString& retval);
+  void GetConstraints(MediaStreamConstraintsInternal &result);
+
+private:
+  nsCOMPtr<nsPIDOMWindow> mInnerWindow;
+  uint64_t mWindowID;
+  const nsString mCallID;
+  MediaStreamConstraintsInternal mConstraints;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // GetUserMediaRequest_h__
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1,29 +1,32 @@
 /* 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 "MediaManager.h"
 
 #include "MediaStreamGraph.h"
+#include "GetUserMediaRequest.h"
 #ifdef MOZ_WIDGET_GONK
 #include "nsIAudioManager.h"
 #endif
 #include "nsIDOMFile.h"
 #include "nsIEventTarget.h"
 #include "nsIUUIDGenerator.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIPopupWindowManager.h"
 #include "nsISupportsArray.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/MediaStreamTrackBinding.h"
+#include "mozilla/dom/GetUserMediaRequestBinding.h"
 
 // For PR_snprintf
 #include "prprf.h"
 
 #include "nsJSUtils.h"
 #include "nsDOMFile.h"
 #include "nsGlobalWindow.h"
 
@@ -56,16 +59,86 @@ GetMediaManagerLog()
     sLog = PR_NewLogModule("MediaManager");
   return sLog;
 }
 #define LOG(msg) PR_LOG(GetMediaManagerLog(), PR_LOG_DEBUG, msg)
 #else
 #define LOG(msg)
 #endif
 
+using dom::MediaStreamConstraints;         // Outside API (contains JSObject)
+using dom::MediaStreamConstraintsInternal; // Storable supported constraints
+using dom::MediaTrackConstraintsInternal;  // Video or audio constraints
+using dom::MediaTrackConstraintSet;        // Mandatory or optional constraints
+using dom::MediaTrackConstraints;          // Raw mMandatory (as JSObject)
+using dom::GetUserMediaRequest;
+using dom::Sequence;
+
+// Used to compare raw MediaTrackConstraintSet against normalized dictionary
+// version to detect member differences, e.g. unsupported constraints.
+
+static nsresult CompareDictionaries(JSContext* aCx, JSObject *aA,
+                                    const MediaTrackConstraintSet &aB,
+                                    nsString *aDifference)
+{
+  JS::Rooted<JSObject*> a(aCx, aA);
+  JSAutoCompartment ac(aCx, aA);
+  JS::Rooted<JS::Value> bval(aCx);
+  aB.ToObject(aCx, JS::NullPtr(), &bval);
+  JS::Rooted<JSObject*> b(aCx, &bval.toObject());
+
+  // Iterate over each property in A, and check if it is in B
+
+  JS::AutoIdArray props(aCx, JS_Enumerate(aCx, a));
+
+  for (size_t i = 0; i < props.length(); i++) {
+    JS::Rooted<JS::Value> bprop(aCx);
+    if (!JS_GetPropertyById(aCx, b, props[i], &bprop)) {
+      LOG(("Error parsing dictionary!\n"));
+      return NS_ERROR_UNEXPECTED;
+    }
+    if (bprop.isUndefined()) {
+      // Unknown property found in A. Bail with name
+      JS::Rooted<JS::Value> nameval(aCx);
+      bool success = JS_IdToValue(aCx, props[i], nameval.address());
+      NS_ENSURE_TRUE(success, NS_ERROR_UNEXPECTED);
+
+      JS::Rooted<JSString*> namestr(aCx, JS_ValueToString(aCx, nameval));
+      NS_ENSURE_TRUE(namestr, NS_ERROR_UNEXPECTED);
+      aDifference->Assign(JS_GetStringCharsZ(aCx, namestr));
+      return NS_OK;
+    }
+  }
+  aDifference->Truncate();
+  return NS_OK;
+}
+
+// Look for and return any unknown mandatory constraint. Done by comparing
+// a raw MediaTrackConstraints against a normalized copy, both passed in.
+
+static nsresult ValidateTrackConstraints(
+    JSContext *aCx, JSObject *aRaw,
+    const MediaTrackConstraintsInternal &aNormalized,
+    nsString *aOutUnknownConstraint)
+{
+  // First find raw mMandatory member (use MediaTrackConstraints as helper)
+  dom::RootedDictionary<MediaTrackConstraints> track(aCx);
+  JS::Rooted<JS::Value> rawval(aCx, JS::ObjectValue(*aRaw));
+  bool success = track.Init(aCx, rawval);
+  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
+
+  if (track.mMandatory.WasPassed()) {
+    nsresult rv = CompareDictionaries(aCx, track.mMandatory.Value(),
+                                      aNormalized.mMandatory,
+                                      aOutUnknownConstraint);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+  return NS_OK;
+}
+
 /**
  * Send an error back to content. The error is the form a string.
  * Do this only on the main thread. The success callback is also passed here
  * so it can be released correctly.
  */
 class ErrorCallbackRunnable : public nsRunnable
 {
 public:
@@ -232,16 +305,38 @@ protected:
   nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener;
 };
 
 /**
  * nsIMediaDevice implementation.
  */
 NS_IMPL_ISUPPORTS1(MediaDevice, nsIMediaDevice)
 
+MediaDevice::MediaDevice(MediaEngineVideoSource* aSource)
+  : mHasFacingMode(false)
+  , mSource(aSource) {
+  mType.Assign(NS_LITERAL_STRING("video"));
+  mSource->GetName(mName);
+  mSource->GetUUID(mID);
+
+  // Kludge to test user-facing cameras on OSX.
+  if (mName.Find(NS_LITERAL_STRING("Face")) != -1) {
+    mHasFacingMode = true;
+    mFacingMode = dom::VideoFacingModeEnum::User;
+  }
+}
+
+MediaDevice::MediaDevice(MediaEngineAudioSource* aSource)
+  : mHasFacingMode(false)
+  , mSource(aSource) {
+  mType.Assign(NS_LITERAL_STRING("audio"));
+  mSource->GetName(mName);
+  mSource->GetUUID(mID);
+}
+
 NS_IMETHODIMP
 MediaDevice::GetName(nsAString& aName)
 {
   aName.Assign(mName);
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -253,16 +348,28 @@ MediaDevice::GetType(nsAString& aType)
 
 NS_IMETHODIMP
 MediaDevice::GetId(nsAString& aID)
 {
   aID.Assign(mID);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+MediaDevice::GetFacingMode(nsAString& aFacingMode)
+{
+  if (mHasFacingMode) {
+    aFacingMode.Assign(NS_ConvertUTF8toUTF16(
+        dom::VideoFacingModeEnumValues::strings[uint32_t(mFacingMode)].value));
+  } else {
+    aFacingMode.Truncate(0);
+  }
+  return NS_OK;
+}
+
 MediaEngineSource*
 MediaDevice::GetSource()
 {
   return mSource;
 }
 
 /**
  * A subclass that we only use to stash internal pointers to MediaStreamGraph objects
@@ -504,88 +611,162 @@ private:
   nsRefPtr<MediaEngineSource> mAudioSource;
   nsRefPtr<MediaEngineSource> mVideoSource;
   uint64_t mWindowID;
   nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener;
   nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
 };
 
 /**
+ * Helper functions that implement the constraints algorithm from
+ * http://dev.w3.org/2011/webrtc/editor/getusermedia.html#methods-5
+ */
+
+static bool SatisfyConstraint(const MediaEngineVideoSource *,
+                              const MediaTrackConstraintSet &aConstraints,
+                              nsIMediaDevice &aCandidate)
+{
+  if (aConstraints.mFacingMode.WasPassed()) {
+    nsString s;
+    aCandidate.GetFacingMode(s);
+    if (!s.EqualsASCII(dom::VideoFacingModeEnumValues::strings[
+        uint32_t(aConstraints.mFacingMode.Value())].value)) {
+      return false;
+    }
+  }
+  // TODO: Add more video-specific constraints
+  return true;
+}
+
+static bool SatisfyConstraint(const MediaEngineAudioSource *,
+                              const MediaTrackConstraintSet &aConstraints,
+                              nsIMediaDevice &aCandidate)
+{
+  // TODO: Add audio-specific constraints
+  return true;
+}
+
+typedef nsTArray<nsCOMPtr<nsIMediaDevice> > SourceSet;
+
+// Source getter that constrains list returned
+
+template<class SourceType>
+static SourceSet *
+  GetSources(MediaEngine *engine,
+             const MediaTrackConstraintsInternal &aConstraints,
+             void (MediaEngine::* aEnumerate)(nsTArray<nsRefPtr<SourceType> >*))
+{
+  const SourceType * const type = nullptr;
+
+  // First collect sources
+  SourceSet candidateSet;
+  {
+    nsTArray<nsRefPtr<SourceType> > sources;
+    (engine->*aEnumerate)(&sources);
+
+    /**
+      * We're allowing multiple tabs to access the same camera for parity
+      * with Chrome.  See bug 811757 for some of the issues surrounding
+      * this decision.  To disallow, we'd filter by IsAvailable() as we used
+      * to.
+      */
+
+    for (uint32_t len = sources.Length(), i = 0; i < len; i++) {
+      candidateSet.AppendElement(new MediaDevice(sources[i]));
+    }
+  }
+
+  // Then apply mandatory constraints
+
+  // Note: Iterator must be signed as it can dip below zero
+  for (int i = 0; i < int(candidateSet.Length()); i++) {
+    // Overloading instead of template specialization keeps things local
+    if (!SatisfyConstraint(type, aConstraints.mMandatory, *candidateSet[i])) {
+      candidateSet.RemoveElementAt(i--);
+    }
+  }
+
+  // Then apply optional constraints.
+  //
+  // These are only effective when there are multiple sources to pick from.
+  // Spec as-of-this-writing says to run algorithm on "all possible tracks
+  // of media type T that the browser COULD RETURN" (emphasis added).
+  //
+  // We think users ultimately control which devices we could return, so after
+  // determining the webpage's preferred list, we add the remaining choices
+  // to the tail, reasoning that they would all have passed individually,
+  // i.e. if the user had any one of them as their sole device (enabled).
+  //
+  // This avoids users having to unplug/disable devices should a webpage pick
+  // the wrong one (UX-fail). Webpage-preferred devices will be listed first.
+
+  SourceSet tailSet;
+
+  if (aConstraints.mOptional.WasPassed()) {
+    const Sequence<MediaTrackConstraintSet> &array = aConstraints.mOptional.Value();
+    for (int i = 0; i < int(array.Length()); i++) {
+      SourceSet rejects;
+      // Note: Iterator must be signed as it can dip below zero
+      for (int j = 0; j < int(candidateSet.Length()); j++) {
+        if (!SatisfyConstraint(type, array[i], *candidateSet[j])) {
+          rejects.AppendElement(candidateSet[j]);
+          candidateSet.RemoveElementAt(j--);
+        }
+      }
+      (candidateSet.Length()? tailSet : candidateSet).MoveElementsFrom(rejects);
+    }
+  }
+
+  SourceSet *result = new SourceSet;
+  result->MoveElementsFrom(candidateSet);
+  result->MoveElementsFrom(tailSet);
+  return result;
+}
+
+/**
  * Runs on a seperate thread and is responsible for enumerating devices.
  * Depending on whether a picture or stream was asked for, either
  * ProcessGetUserMedia or ProcessGetUserMediaSnapshot is called, and the results
  * are sent back to the DOM.
  *
  * Do not run this on the main thread. The success and error callbacks *MUST*
  * be dispatched on the main thread!
  */
 class GetUserMediaRunnable : public nsRunnable
 {
 public:
-  /**
-   * The caller can choose to provide a MediaDevice as the last argument,
-   * if one is not provided, a default device is automatically chosen.
-   */
-  GetUserMediaRunnable(bool aAudio, bool aVideo, bool aPicture,
-    already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
-    already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
-    uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
-    MediaEnginePrefs &aPrefs,
-    MediaDevice* aAudioDevice, MediaDevice* aVideoDevice)
-    : mAudio(aAudio)
-    , mVideo(aVideo)
-    , mPicture(aPicture)
-    , mSuccess(aSuccess)
-    , mError(aError)
-    , mWindowID(aWindowID)
-    , mListener(aListener)
-    , mPrefs(aPrefs)
-    , mDeviceChosen(true)
-    , mBackendChosen(false)
-    , mManager(MediaManager::GetInstance())
-  {
-    if (mAudio) {
-      mAudioDevice = aAudioDevice;
-    }
-    if (mVideo) {
-      mVideoDevice = aVideoDevice;
-    }
-  }
-
-  GetUserMediaRunnable(bool aAudio, bool aVideo, bool aPicture,
+  GetUserMediaRunnable(
+    const MediaStreamConstraintsInternal& aConstraints,
     already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
     already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
     uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
     MediaEnginePrefs &aPrefs)
-    : mAudio(aAudio)
-    , mVideo(aVideo)
-    , mPicture(aPicture)
+    : mConstraints(aConstraints)
     , mSuccess(aSuccess)
     , mError(aError)
     , mWindowID(aWindowID)
     , mListener(aListener)
     , mPrefs(aPrefs)
     , mDeviceChosen(false)
     , mBackendChosen(false)
     , mManager(MediaManager::GetInstance())
   {}
 
   /**
    * The caller can also choose to provide their own backend instead of
    * using the one provided by MediaManager::GetBackend.
    */
-  GetUserMediaRunnable(bool aAudio, bool aVideo,
+  GetUserMediaRunnable(
+    const MediaStreamConstraintsInternal& aConstraints,
     already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
     already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
     uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
     MediaEnginePrefs &aPrefs,
     MediaEngine* aBackend)
-    : mAudio(aAudio)
-    , mVideo(aVideo)
-    , mPicture(false)
+    : mConstraints(aConstraints)
     , mSuccess(aSuccess)
     , mError(aError)
     , mWindowID(aWindowID)
     , mListener(aListener)
     , mPrefs(aPrefs)
     , mDeviceChosen(false)
     , mBackendChosen(true)
     , mBackend(aBackend)
@@ -612,31 +793,33 @@ public:
     if (!mDeviceChosen) {
       nsresult rv = SelectDevice();
       if (rv != NS_OK) {
         return rv;
       }
     }
 
     // It is an error if audio or video are requested along with picture.
-    if (mPicture && (mAudio || mVideo)) {
+    if (mConstraints.mPicture && (mConstraints.mAudio || mConstraints.mVideo)) {
       NS_DispatchToMainThread(new ErrorCallbackRunnable(
         mSuccess, mError, NS_LITERAL_STRING("NOT_SUPPORTED_ERR"), mWindowID
       ));
       return NS_OK;
     }
 
-    if (mPicture) {
+    if (mConstraints.mPicture) {
       ProcessGetUserMediaSnapshot(mVideoDevice->GetSource(), 0);
       return NS_OK;
     }
 
     // There's a bug in the permission code that can leave us with mAudio but no audio device
-    ProcessGetUserMedia((mAudio && mAudioDevice) ? mAudioDevice->GetSource() : nullptr,
-                        (mVideo && mVideoDevice) ? mVideoDevice->GetSource() : nullptr);
+    ProcessGetUserMedia(((mConstraints.mAudio && mAudioDevice) ?
+                         mAudioDevice->GetSource() : nullptr),
+                        ((mConstraints.mVideo && mVideoDevice) ?
+                         mVideoDevice->GetSource() : nullptr));
     return NS_OK;
   }
 
   nsresult
   Denied(const nsAString& aErrorMsg)
   {
       // We add a disabled listener to the StreamListeners array until accepted
       // If this was the only active MediaStream, remove the window from the list.
@@ -677,79 +860,41 @@ public:
     mVideoDevice = aVideoDevice;
     mDeviceChosen = true;
     return NS_OK;
   }
 
   nsresult
   SelectDevice()
   {
-    bool found = false;
-    uint32_t count;
-    if (mPicture || mVideo) {
-      nsTArray<nsRefPtr<MediaEngineVideoSource> > videoSources;
-      mBackend->EnumerateVideoDevices(&videoSources);
+    if (mConstraints.mPicture || mConstraints.mVideo) {
+      ScopedDeletePtr<SourceSet> sources (GetSources(mBackend,
+          mConstraints.mVideom, &MediaEngine::EnumerateVideoDevices));
 
-      count = videoSources.Length();
-      if (count <= 0) {
+      if (!sources->Length()) {
         NS_DispatchToMainThread(new ErrorCallbackRunnable(
-          mSuccess, mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID
-        ));
+          mSuccess, mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID));
         return NS_ERROR_FAILURE;
       }
-
-      /**
-       * We're allowing multiple tabs to access the same camera for parity
-       * with Chrome.  See bug 811757 for some of the issues surrounding
-       * this decision.  To disallow, we'd filter by IsAvailable() as we used
-       * to.
-       */
       // Pick the first available device.
-      for (uint32_t i = 0; i < count; i++) {
-        nsRefPtr<MediaEngineVideoSource> vSource = videoSources[i];
-        found = true;
-        mVideoDevice = new MediaDevice(videoSources[i]);
-        break;
-      }
-
-      if (!found) {
-        NS_DispatchToMainThread(new ErrorCallbackRunnable(
-          mSuccess, mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
-        ));
-        return NS_ERROR_FAILURE;
-      }
+      mVideoDevice = do_QueryObject((*sources)[0]);
       LOG(("Selected video device"));
     }
 
-    found = false;
-    if (mAudio) {
-      nsTArray<nsRefPtr<MediaEngineAudioSource> > audioSources;
-      mBackend->EnumerateAudioDevices(&audioSources);
+    if (mConstraints.mAudio) {
+      ScopedDeletePtr<SourceSet> sources (GetSources(mBackend,
+          mConstraints.mAudiom, &MediaEngine::EnumerateAudioDevices));
 
-      count = audioSources.Length();
-      if (count <= 0) {
+      if (!sources->Length()) {
         NS_DispatchToMainThread(new ErrorCallbackRunnable(
-          mSuccess, mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID
-        ));
+          mSuccess, mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID));
         return NS_ERROR_FAILURE;
       }
-
-      for (uint32_t i = 0; i < count; i++) {
-        nsRefPtr<MediaEngineAudioSource> aSource = audioSources[i];
-        found = true;
-        mAudioDevice = new MediaDevice(audioSources[i]);
-        break;
-      }
-
-      if (!found) {
-        NS_DispatchToMainThread(new ErrorCallbackRunnable(
-          mSuccess, mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID
-        ));
-        return NS_ERROR_FAILURE;
-      }
+      // Pick the first available device.
+      mAudioDevice = do_QueryObject((*sources)[0]);
       LOG(("Selected audio device"));
     }
 
     return NS_OK;
   }
 
   /**
    * Allocates a video or audio device and returns a MediaStream via
@@ -813,19 +958,17 @@ public:
 
     NS_DispatchToMainThread(new SuccessCallbackRunnable(
       mSuccess, mError, file, mWindowID
     ));
     return;
   }
 
 private:
-  bool mAudio;
-  bool mVideo;
-  bool mPicture;
+  MediaStreamConstraintsInternal mConstraints;
 
   already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
   already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
   uint64_t mWindowID;
   nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener;
   nsRefPtr<MediaDevice> mAudioDevice;
   nsRefPtr<MediaDevice> mVideoDevice;
   MediaEnginePrefs mPrefs;
@@ -842,65 +985,46 @@ private:
  * GetUserMediaDevices function. Enumerates a list of audio & video devices,
  * wraps them up in nsIMediaDevice objects and returns it to the success
  * callback.
  */
 class GetUserMediaDevicesRunnable : public nsRunnable
 {
 public:
   GetUserMediaDevicesRunnable(
+    const MediaStreamConstraintsInternal& aConstraints,
     already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> aSuccess,
     already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
     uint64_t aWindowId)
-    : mSuccess(aSuccess)
+    : mConstraints(aConstraints)
+    , mSuccess(aSuccess)
     , mError(aError)
     , mManager(MediaManager::GetInstance())
-    , mWindowId(aWindowId)
-  {}
+    , mWindowId(aWindowId) {}
 
   NS_IMETHOD
   Run()
   {
     NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
-
-    uint32_t audioCount, videoCount, i;
-
-    nsTArray<nsRefPtr<MediaEngineVideoSource> > videoSources;
-    mManager->GetBackend(mWindowId)->EnumerateVideoDevices(&videoSources);
-    videoCount = videoSources.Length();
-
-    nsTArray<nsRefPtr<MediaEngineAudioSource> > audioSources;
-    mManager->GetBackend(mWindowId)->EnumerateAudioDevices(&audioSources);
-    audioCount = audioSources.Length();
-
-    nsTArray<nsCOMPtr<nsIMediaDevice> > *devices =
-      new nsTArray<nsCOMPtr<nsIMediaDevice> >;
+    MediaEngine *backend = mManager->GetBackend(mWindowId);
 
-    /**
-     * We're allowing multiple tabs to access the same camera for parity
-     * with Chrome.  See bug 811757 for some of the issues surrounding
-     * this decision.  To disallow, we'd filter by IsAvailable() as we used
-     * to.
-     */
-    for (i = 0; i < videoCount; i++) {
-      MediaEngineVideoSource *vSource = videoSources[i];
-      devices->AppendElement(new MediaDevice(vSource));
+    ScopedDeletePtr<SourceSet> final (GetSources(backend, mConstraints.mVideom,
+                                          &MediaEngine::EnumerateVideoDevices));
+    {
+      ScopedDeletePtr<SourceSet> s (GetSources(backend, mConstraints.mAudiom,
+                                        &MediaEngine::EnumerateAudioDevices));
+      final->MoveElementsFrom(*s);
     }
-    for (i = 0; i < audioCount; i++) {
-      MediaEngineAudioSource *aSource = audioSources[i];
-      devices->AppendElement(new MediaDevice(aSource));
-    }
-
-    NS_DispatchToMainThread(new DeviceSuccessCallbackRunnable(
-      mSuccess, mError, devices // give ownership of the nsTArray to the runnable
-    ));
+    NS_DispatchToMainThread(new DeviceSuccessCallbackRunnable(mSuccess, mError,
+                                                              final.forget()));
     return NS_OK;
   }
 
 private:
+  MediaStreamConstraintsInternal mConstraints;
   already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
   already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
   nsRefPtr<MediaManager> mManager;
   uint64_t mWindowId;
 };
 
 MediaManager::MediaManager()
   : mMediaThread(nullptr)
@@ -968,85 +1092,87 @@ MediaManager::GetInstance()
 }
 
 /**
  * The entry point for this file. A call from Navigator::mozGetUserMedia
  * will end up here. MediaManager is a singleton that is responsible
  * for handling all incoming getUserMedia calls from every window.
  */
 nsresult
-MediaManager::GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow,
-  nsIMediaStreamOptions* aParams,
+MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
+  nsPIDOMWindow* aWindow, const MediaStreamConstraints& aRawConstraints,
   nsIDOMGetUserMediaSuccessCallback* aOnSuccess,
   nsIDOMGetUserMediaErrorCallback* aOnError)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
-  NS_ENSURE_TRUE(aParams, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aOnError, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER);
 
   nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess(aOnSuccess);
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError(aOnError);
 
-  /* Get options */
-  nsresult rv;
-  bool fake, audio, video, picture;
-
-  rv = aParams->GetFake(&fake);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aParams->GetPicture(&picture);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aParams->GetAudio(&audio);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aParams->GetVideo(&video);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIMediaDevice> audiodevice;
-  rv = aParams->GetAudioDevice(getter_AddRefs(audiodevice));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIMediaDevice> videodevice;
-  rv = aParams->GetVideoDevice(getter_AddRefs(videodevice));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // If a device was provided, make sure it support the type of stream requested.
-  if (audiodevice) {
-    nsString type;
-    audiodevice->GetType(type);
-    if (audio && !type.EqualsLiteral("audio")) {
-      return NS_ERROR_FAILURE;
-    }
-  }
-  if (videodevice) {
-    nsString type;
-    videodevice->GetType(type);
-    if ((picture || video) && !type.EqualsLiteral("video")) {
-        return NS_ERROR_FAILURE;
-    }
+  Maybe<JSAutoCompartment> ac;
+  if (aRawConstraints.mAudio.IsObject() || aRawConstraints.mVideo.IsObject()) {
+    ac.construct(aCx, (aRawConstraints.mVideo.IsObject()?
+                       aRawConstraints.mVideo.GetAsObject() :
+                       aRawConstraints.mAudio.GetAsObject()));
   }
 
-  // We only support "front" or "back". TBD: Send to GetUserMediaRunnable.
-  nsString cameraType;
-  rv = aParams->GetCamera(cameraType);
-  NS_ENSURE_SUCCESS(rv, rv);
+  // aRawConstraints has JSObjects in it, so process it by copying it into
+  // MediaStreamConstraintsInternal which does not.
+
+  dom::RootedDictionary<MediaStreamConstraintsInternal> c(aCx);
+
+  // TODO: Simplify this part once Bug 767924 is fixed.
+  // Since we cannot yet use unions on non-objects, we process the raw object
+  // into discrete members for internal use until Bug 767924 is fixed
+
+  nsresult rv;
+  nsString unknownConstraintFound;
+
+  if (aRawConstraints.mAudio.IsObject()) {
+    JS::Rooted<JS::Value> temp(aCx,
+        JS::ObjectValue(*aRawConstraints.mAudio.GetAsObject()));
+    bool success = c.mAudiom.Init(aCx, temp);
+    NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
+
+    rv = ValidateTrackConstraints(aCx, aRawConstraints.mAudio.GetAsObject(),
+                                  c.mAudiom, &unknownConstraintFound);
+    NS_ENSURE_SUCCESS(rv, rv);
+    c.mAudio = true;
+  } else {
+    c.mAudio = aRawConstraints.mAudio.GetAsBoolean();
+  }
+  if (aRawConstraints.mVideo.IsObject()) {
+    JS::Rooted<JS::Value> temp(aCx,
+        JS::ObjectValue(*aRawConstraints.mVideo.GetAsObject()));
+    bool success = c.mVideom.Init(aCx, temp);
+    NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
+
+    rv = ValidateTrackConstraints(aCx, aRawConstraints.mVideo.GetAsObject(),
+                                  c.mVideom, &unknownConstraintFound);
+    NS_ENSURE_SUCCESS(rv, rv);
+    c.mVideo = true;
+  } else {
+    c.mVideo = aRawConstraints.mVideo.GetAsBoolean();
+  }
+  c.mPicture = aRawConstraints.mPicture;
+  c.mFake = aRawConstraints.mFake;
 
   /**
    * If we were asked to get a picture, before getting a snapshot, we check if
    * the calling page is allowed to open a popup. We do this because
    * {picture:true} will open a new "window" to let the user preview or select
    * an image, on Android. The desktop UI for {picture:true} is TBD, at which
    * may point we can decide whether to extend this test there as well.
    */
 #if !defined(MOZ_WEBRTC)
-  if (picture && !aPrivileged) {
+  if (c.mPicture && !aPrivileged) {
     if (aWindow->GetPopupControlState() > openControlled) {
       nsCOMPtr<nsIPopupWindowManager> pm =
         do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
       if (!pm) {
         return NS_OK;
       }
       uint32_t permission;
       nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
@@ -1074,16 +1200,32 @@ MediaManager::GetUserMedia(bool aPrivile
   nsRefPtr<GetUserMediaRunnable> gUMRunnable;
   // This is safe since we're on main-thread, and the windowlist can only
   // be invalidated from the main-thread (see OnNavigation)
   StreamListeners* listeners = GetActiveWindows()->Get(windowID);
   if (!listeners) {
     listeners = new StreamListeners;
     GetActiveWindows()->Put(windowID, listeners);
   }
+
+  if (!unknownConstraintFound.IsEmpty()) {
+    // An unsupported mandatory constraint was found.
+    // Things are set up enough here that we can fire Error callback.
+
+    LOG(("Unsupported mandatory constraint: %s\n",
+          NS_ConvertUTF16toUTF8(unknownConstraintFound).get()));
+
+    nsString errormsg(NS_LITERAL_STRING("NOT_SUPPORTED_ERR: "));
+    errormsg.Append(unknownConstraintFound);
+    NS_DispatchToMainThread(new ErrorCallbackRunnable(onSuccess.forget(),
+                                                      onError.forget(),
+                                                      errormsg, windowID));
+    return NS_OK;
+  }
+
   // Ensure there's a thread for gum to proxy to off main thread
   nsIThread *mediaThread = MediaManager::GetThread();
 
   // Create a disabled listener to act as a placeholder
   GetUserMediaCallbackMediaStreamListener* listener =
     new GetUserMediaCallbackMediaStreamListener(mediaThread, windowID);
 
   // No need for locking because we always do this in the main thread.
@@ -1091,62 +1233,46 @@ MediaManager::GetUserMedia(bool aPrivile
 
   // Developer preference for turning off permission check.
   if (Preferences::GetBool("media.navigator.permission.disabled", false)) {
     aPrivileged = true;
   }
 
   /**
    * Pass runnables along to GetUserMediaRunnable so it can add the
-   * MediaStreamListener to the runnable list. The last argument can
-   * optionally be a MediaDevice object, which should provided if one was
-   * selected by the user via the UI, or was provided by privileged code
-   * via the device: attribute via nsIMediaStreamOptions.
-   *
-   * If a fake stream was requested, we force the use of the default backend.
+   * MediaStreamListener to the runnable list.
    */
-  // XXX take options from constraints instead of prefs
-  if (fake) {
+  if (c.mFake) {
     // Fake stream from default backend.
-    gUMRunnable = new GetUserMediaRunnable(
-      audio, video, onSuccess.forget(), onError.forget(), windowID, listener, mPrefs,
-      new MediaEngineDefault()
-                                           );
-  } else if (audiodevice || videodevice) {
-    // Stream from provided device.
-    gUMRunnable = new GetUserMediaRunnable(
-      audio, video, picture, onSuccess.forget(), onError.forget(), windowID, listener, mPrefs,
-      static_cast<MediaDevice*>(audiodevice.get()),
-      static_cast<MediaDevice*>(videodevice.get())
-                                           );
+    gUMRunnable = new GetUserMediaRunnable(c, onSuccess.forget(),
+      onError.forget(), windowID, listener, mPrefs, new MediaEngineDefault());
   } else {
     // Stream from default device from WebRTC backend.
-    gUMRunnable = new GetUserMediaRunnable(
-      audio, video, picture, onSuccess.forget(), onError.forget(), windowID, listener, mPrefs
-                                           );
+    gUMRunnable = new GetUserMediaRunnable(c, onSuccess.forget(),
+      onError.forget(), windowID, listener, mPrefs);
   }
 
 #ifdef MOZ_B2G_CAMERA
   if (mCameraManager == nullptr) {
     aPrivileged = nsDOMCameraManager::CheckPermission(aWindow);
     if (aPrivileged) {
       mCameraManager = nsDOMCameraManager::CreateInstance(aWindow);
     }
   }
 #endif
 
 #if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
-  if (picture) {
+  if (c.mPicture) {
     // ShowFilePickerForMimeType() must run on the Main Thread! (on Android)
     NS_DispatchToMainThread(gUMRunnable);
     return NS_OK;
   }
 #endif
   // XXX No full support for picture in Desktop yet (needs proper UI)
-  if (aPrivileged || fake) {
+  if (aPrivileged || c.mFake) {
     mMediaThread->Dispatch(gUMRunnable, NS_DISPATCH_NORMAL);
   } else {
     // Ask for user permission, and dispatch runnable (or not) when a response
     // is received via an observer notification. Each call is paired with its
     // runnable by a GUID.
     nsresult rv;
     nsCOMPtr<nsIUUIDGenerator> uuidgen =
       do_GetService("@mozilla.org/uuid-generator;1", &rv);
@@ -1159,52 +1285,41 @@ MediaManager::GetUserMedia(bool aPrivile
 
     char buffer[NSID_LENGTH];
     id.ToProvidedString(buffer);
     NS_ConvertUTF8toUTF16 callID(buffer);
 
     // Store the current callback.
     mActiveCallbacks.Put(callID, gUMRunnable);
 
-    // Construct JSON structure with both the windowID and the callID.
-    nsAutoString data;
-    data.Append(NS_LITERAL_STRING("{\"windowID\":"));
-
-    // Convert window ID to string.
-    char windowBuffer[32];
-    PR_snprintf(windowBuffer, sizeof(windowBuffer), "%llu",
-                aWindow->GetOuterWindow()->WindowID());
-    data.Append(NS_ConvertUTF8toUTF16(windowBuffer));
-
-    data.Append(NS_LITERAL_STRING(", \"callID\":\""));
-    data.Append(callID);
-    data.Append(NS_LITERAL_STRING("\"}"));
-
     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-    obs->NotifyObservers(aParams, "getUserMedia:request", data.get());
+    nsRefPtr<GetUserMediaRequest> req = new GetUserMediaRequest(aWindow,
+                                                                callID, c);
+    obs->NotifyObservers(req, "getUserMedia:request", nullptr);
   }
 
   return NS_OK;
 }
 
 nsresult
 MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow,
+  const MediaStreamConstraintsInternal& aConstraints,
   nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
   nsIDOMGetUserMediaErrorCallback* aOnError)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   NS_ENSURE_TRUE(aOnError, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER);
 
   nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess(aOnSuccess);
   nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError(aOnError);
 
   nsCOMPtr<nsIRunnable> gUMDRunnable = new GetUserMediaDevicesRunnable(
-    onSuccess.forget(), onError.forget(), aWindow->WindowID()
+    aConstraints, onSuccess.forget(), onError.forget(), aWindow->WindowID()
   );
 
   nsCOMPtr<nsIThread> deviceThread;
   nsresult rv = NS_NewThread(getter_AddRefs(deviceThread));
   NS_ENSURE_SUCCESS(rv, rv);
 
 
   deviceThread->Dispatch(gUMDRunnable, NS_DISPATCH_NORMAL);
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -15,28 +15,34 @@
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 
 #include "nsPIDOMWindow.h"
 #include "nsIDOMNavigatorUserMedia.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/StaticPtr.h"
+#include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "prlog.h"
 #include "DOMMediaStream.h"
 
 #ifdef MOZ_WEBRTC
 #include "mtransport/runnable_utils.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include "DOMCameraManager.h"
 #endif
 
 namespace mozilla {
+namespace dom {
+class MediaStreamConstraints;
+class NavigatorUserMediaSuccessCallback;
+class NavigatorUserMediaErrorCallback;
+}
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetMediaManagerLog();
 #define MM_LOG(msg) PR_LOG(GetMediaManagerLog(), PR_LOG_DEBUG, msg)
 #else
 #define MM_LOG(msg)
 #endif
 
@@ -345,35 +351,27 @@ typedef nsTArray<nsRefPtr<GetUserMediaCa
 typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable;
 
 class MediaDevice : public nsIMediaDevice
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIMEDIADEVICE
 
-  MediaDevice(MediaEngineVideoSource* aSource) {
-    mSource = aSource;
-    mType.Assign(NS_LITERAL_STRING("video"));
-    mSource->GetName(mName);
-    mSource->GetUUID(mID);
-  }
-  MediaDevice(MediaEngineAudioSource* aSource) {
-    mSource = aSource;
-    mType.Assign(NS_LITERAL_STRING("audio"));
-    mSource->GetName(mName);
-    mSource->GetUUID(mID);
-  }
+  MediaDevice(MediaEngineVideoSource* aSource);
+  MediaDevice(MediaEngineAudioSource* aSource);
   virtual ~MediaDevice() {}
 
   MediaEngineSource* GetSource();
 private:
   nsString mName;
   nsString mType;
   nsString mID;
+  bool mHasFacingMode;
+  dom::VideoFacingModeEnum mFacingMode;
   nsRefPtr<MediaEngineSource> mSource;
 };
 
 class MediaManager MOZ_FINAL : public nsIMediaManagerService,
                                public nsIObserver
 {
 public:
   static already_AddRefed<MediaManager> GetInstance();
@@ -402,21 +400,24 @@ public:
   }
   bool IsWindowStillActive(uint64_t aWindowId) {
     return !!GetWindowListeners(aWindowId);
   }
   // Note: also calls aListener->Remove(), even if inactive
   void RemoveFromWindowList(uint64_t aWindowID,
     GetUserMediaCallbackMediaStreamListener *aListener);
 
-  nsresult GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow,
-    nsIMediaStreamOptions* aParams,
+  nsresult GetUserMedia(JSContext* aCx, bool aPrivileged,
+    nsPIDOMWindow* aWindow,
+    const dom::MediaStreamConstraints& aRawConstraints,
     nsIDOMGetUserMediaSuccessCallback* onSuccess,
     nsIDOMGetUserMediaErrorCallback* onError);
+
   nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow,
+    const dom::MediaStreamConstraintsInternal& aConstraints,
     nsIGetUserMediaDevicesSuccessCallback* onSuccess,
     nsIDOMGetUserMediaErrorCallback* onError);
   void OnNavigation(uint64_t aWindowID);
 
   MediaEnginePrefs mPrefs;
 
 private:
   WindowTable *GetActiveWindows() {
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -14,21 +14,26 @@ XPIDL_SOURCES += [
     'nsIDOMNavigatorUserMedia.idl',
     'nsIMediaManager.idl',
 ]
 
 XPIDL_MODULE = 'dom_media'
 
 MODULE = 'dom'
 
+EXPORTS.mozilla.dom += [
+    'GetUserMediaRequest.h',
+]
+
 EXPORTS.mozilla += [
     'MediaManager.h',
 ]
 
 CPP_SOURCES += [
+    'GetUserMediaRequest.cpp',
     'MediaManager.cpp',
 ]
 
 EXTRA_COMPONENTS += [
     'PeerConnection.js',
     'PeerConnection.manifest',
 ]
 
--- a/dom/media/nsIDOMNavigatorUserMedia.idl
+++ b/dom/media/nsIDOMNavigatorUserMedia.idl
@@ -1,22 +1,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIVariant.idl"
 #include "nsIDOMMediaStream.idl"
 
-[scriptable, builtinclass, uuid(6de854f9-acf8-4383-b464-4803631ef309)]
+[scriptable, builtinclass, uuid(4af2bdb7-1547-4d10-8886-02a78c3c0b83)]
 interface nsIMediaDevice : nsISupports
 {
   readonly attribute DOMString type;
   readonly attribute DOMString name;
   readonly attribute DOMString id;
+  readonly attribute DOMString facingMode;
 };
 
 [scriptable, function, uuid(24544878-d35e-4962-8c5f-fb84e97bdfee)]
 interface nsIGetUserMediaDevicesSuccessCallback : nsISupports
 {
   void onSuccess(in nsIVariant devices);
 };
 
@@ -30,20 +31,8 @@ interface nsIDOMGetUserMediaSuccessCallb
   void onSuccess(in nsISupports value);
 };
 
 [scriptable, function, uuid(2614bbcf-85cc-43e5-8740-964f52bdc7ca)]
 interface nsIDOMGetUserMediaErrorCallback : nsISupports
 {
   void onError(in DOMString error);
 };
-
-[scriptable, uuid(f34a3616-395a-43cd-b275-bf81750ac8b9)]
-interface nsIMediaStreamOptions : nsISupports
-{
-  readonly attribute boolean fake;
-  readonly attribute boolean audio;
-  readonly attribute boolean video;
-  readonly attribute boolean picture;
-  readonly attribute DOMString camera;
-  readonly attribute nsIMediaDevice audioDevice;
-  readonly attribute nsIMediaDevice videoDevice;
-};
--- a/dom/media/tests/mochitest/test_getUserMedia_exceptions.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_exceptions.html
@@ -34,17 +34,17 @@ var exceptionTests = [
   { params: [{video: true, fake: true}, unexpectedCall],
     error: "Not enough arguments to Navigator.mozGetUserMedia.",
     message: "two arguments specified" },
 
   // Each test here verifies that providing an incorret object
   // type to any mozGetUserMedia parameter should throw
   // the correct exception specified
   { params: [1, unexpectedCall, unexpectedCall],
-    error: "Argument 1 of Navigator.mozGetUserMedia is not an object.",
+    error: "Argument 1 of Navigator.mozGetUserMedia can't be converted to a dictionary.",
     message: "wrong object type as first parameter" },
   { params: [{video: true, fake: true}, 1, unexpectedCall],
     error: "Argument 2 of Navigator.mozGetUserMedia is not an object.",
     message: "wrong object type as second parameter" },
   { params: [{video: true, fake: true}, unexpectedCall, 1],
     error: "Argument 3 of Navigator.mozGetUserMedia is not an object.",
     message: "wrong object type as third parameter" }
 ];
--- a/dom/mobilemessage/tests/test_mms_pdu_helper.js
+++ b/dom/mobilemessage/tests/test_mms_pdu_helper.js
@@ -807,22 +807,22 @@ add_test(function test_PduHelper_parseHe
   function parse(input, expect, exception) {
     let data = {array: input, offset: 0};
     do_check_throws(wsp_test_func.bind(null, MMS.PduHelper.parseHeaders, data, expect),
                     exception);
   }
 
   // Parse ends with Content-Type
   let expect = {};
-  expect["x-mms-mms-version"] = MMS_VERSION;
+  expect["x-mms-mms-version"] = MMS_VERSION_1_3;
   expect["content-type"] = {
     media: "application/vnd.wap.multipart.related",
     params: null,
   };
-  parse([0x80 | 0x0D, 0x80 | MMS_VERSION,   // X-Mms-Mms-Version: 1.3
+  parse([0x80 | 0x0D, 0x80 | MMS_VERSION_1_3,   // X-Mms-Mms-Version: 1.3
          0x80 | 0x04, 0x80 | 0x33,          // Content-Type: application/vnd.wap.multipart.related
          0x80 | 0x0C, MMS_PDU_TYPE_SEND_REQ // X-Mms-Message-Type: M-Send.req
         ], expect);
 
   // Parse header fields with multiple entries
   expect = {
     to: [
       { address: "+123", type: "PLMN" },
@@ -899,24 +899,24 @@ add_test(function test_PduHelper_encodeH
       data.array.pop();
     }
 
     return data.array;
   }
 
   let headers = {};
   headers["x-mms-message-type"] = MMS_PDU_TYPE_SEND_REQ;
-  headers["x-mms-mms-version"] = MMS_VERSION;
+  headers["x-mms-mms-version"] = MMS_VERSION_1_3;
   headers["x-mms-transaction-id"] = "asdf";
   headers["to"] = { address: "+123", type: "PLMN" };
   headers["content-type"] = {
     media: "application/vnd.wap.multipart.related",
   };
   wsp_encode_test_ex(func, headers,
                      Array.concat([0x80 | 0x0C, MMS_PDU_TYPE_SEND_REQ])
                           .concat([0x80 | 0x18]).concat(strToCharCodeArray(headers["x-mms-transaction-id"]))
-                          .concat([0x80 | 0x0D, 0x80 | MMS_VERSION])
+                          .concat([0x80 | 0x0D, 0x80 | MMS_VERSION_1_3])
                           .concat([0x80 | 0x17]).concat(strToCharCodeArray("+123/TYPE=PLMN"))
                           .concat([0x80 | 0x04, 0x80 | 0x33]));
 
   run_next_test();
 });
 
--- a/dom/src/events/nsJSEventListener.cpp
+++ b/dom/src/events/nsJSEventListener.cpp
@@ -268,16 +268,16 @@ nsJSEventListener::HandleEvent(nsIDOMEve
 nsresult
 NS_NewJSEventListener(nsIScriptContext* aContext, JSObject* aScopeObject,
                       nsISupports*aTarget, nsIAtom* aEventType,
                       const nsEventHandler& aHandler,
                       nsIJSEventListener** aReturn)
 {
   MOZ_ASSERT(aContext || aHandler.HasEventHandler(),
              "Must have a handler if we don't have an nsIScriptContext");
-  NS_ENSURE_ARG(aEventType);
+  NS_ENSURE_ARG(aEventType || !NS_IsMainThread());
   nsJSEventListener* it =
     new nsJSEventListener(aContext, aScopeObject, aTarget, aEventType,
                           aHandler);
   NS_ADDREF(*aReturn = it);
 
   return NS_OK;
 }
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -340,17 +340,17 @@ XPCOMUtils.defineLazyGetter(this, "gMess
 
     receiveMessage: function receiveMessage(msg) {
       if (DEBUG) debug("Received '" + msg.name + "' message from content process");
       if (msg.name == "child-process-shutdown") {
         // By the time we receive child-process-shutdown, the child process has
         // already forgotten its permissions so we need to unregister the target
         // for every permission.
         this._unregisterMessageTarget(null, msg.target);
-        return;
+        return null;
       }
 
       if (RIL_IPC_MOBILECONNECTION_MSG_NAMES.indexOf(msg.name) != -1) {
         if (!msg.target.assertPermission("mobileconnection")) {
           if (DEBUG) {
             debug("MobileConnection message " + msg.name +
                   " from a content process with no 'mobileconnection' privileges.");
           }
@@ -383,26 +383,26 @@ XPCOMUtils.defineLazyGetter(this, "gMess
       } else {
         if (DEBUG) debug("Ignoring unknown message type: " + msg.name);
         return null;
       }
 
       switch (msg.name) {
         case "RIL:RegisterMobileConnectionMsg":
           this._registerMessageTarget("mobileconnection", msg.target);
-          return;
+          return null;
         case "RIL:RegisterIccMsg":
           this._registerMessageTarget("icc", msg.target);
-          return;
+          return null;
         case "RIL:RegisterVoicemailMsg":
           this._registerMessageTarget("voicemail", msg.target);
-          return;
+          return null;
         case "RIL:RegisterCellBroadcastMsg":
           this._registerMessageTarget("cellbroadcast", msg.target);
-          return;
+          return null;
       }
 
       let clientId = msg.json.clientId || 0;
       let radioInterface = this.ril.getRadioInterface(clientId);
       if (!radioInterface) {
         if (DEBUG) debug("No such radio interface: " + clientId);
         return null;
       }
@@ -909,16 +909,17 @@ RadioInterface.prototype = {
         break;
       case "RIL:SetVoicePrivacyMode":
         this.workerMessenger.sendWithIPCMessage(msg, "setVoicePrivacyMode");
         break;
       case "RIL:GetVoicePrivacyMode":
         this.workerMessenger.sendWithIPCMessage(msg, "queryVoicePrivacyMode");
         break;
     }
+    return null;
   },
 
   handleUnsolicitedWorkerMessage: function handleUnsolicitedWorkerMessage(message) {
     switch (message.rilMessageType) {
       case "callRing":
         gTelephonyProvider.notifyCallRing();
         break;
       case "callStateChange":
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -48,23 +48,16 @@ let GLOBAL = this;
 
 if (!this.debug) {
   // Debugging stub that goes nowhere.
   this.debug = function debug(message) {
     dump("RIL Worker[" + CLIENT_ID + "]: " + message + "\n");
   };
 }
 
-const INT32_MAX   = 2147483647;
-const UINT8_SIZE  = 1;
-const UINT16_SIZE = 2;
-const UINT32_SIZE = 4;
-
-const PDU_HEX_OCTET_SIZE = 4;
-
 const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"];
 
 // Timeout value for emergency callback mode.
 const EMERGENCY_CB_MODE_TIMEOUT_MS = 300000;  // 5 mins = 300000 ms.
 
 const ICC_MAX_LINEAR_FIXED_RECORDS = 0xfe;
 
 // MMI match groups
@@ -145,33 +138,33 @@ let Buf = {
     } else if (response_type == RESPONSE_TYPE_UNSOLICITED) {
       request_type = this.readUint32();
       if (DEBUG) debug("Unsolicited response for request type " + request_type);
     } else {
       if (DEBUG) debug("Unknown response type: " + response_type);
       return;
     }
 
-    RIL.handleParcel(request_type, this.mReadAvailable, options);
+    RIL.handleParcel(request_type, this.readAvailable, options);
   },
 
   /**
    * Start a new outgoing parcel.
    *
    * @param type
    *        Integer specifying the request type.
    * @param options [optional]
    *        Object containing information about the request, e.g. the
    *        original main thread message object that led to the RIL request.
    */
   newParcel: function newParcel(type, options) {
     if (DEBUG) debug("New outgoing parcel of type " + type);
 
     // We're going to leave room for the parcel size at the beginning.
-    this.mOutgoingIndex = this.PARCEL_SIZE_SIZE;
+    this.outgoingIndex = this.PARCEL_SIZE_SIZE;
     this.writeUint32(type);
     this.writeUint32(this.mToken);
 
     if (!options) {
       options = {};
     }
     options.rilRequestType = type;
     options.rilRequestError = null;
@@ -3971,17 +3964,17 @@ let RIL = {
     let options = {
       pid: message.pid,
       dcs: message.dcs,
       encoding: message.encoding,
     };
     Buf.newParcel(REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, options);
 
     Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable()
-                           - 2 * UINT32_SIZE)); // Skip response_type & request_type.
+                           - 2 * Buf.UINT32_SIZE)); // Skip response_type & request_type.
     let messageStringLength = Buf.readUint32(); // In semi-octets
     let smscLength = GsmPDUHelper.readHexOctet(); // In octets, inclusive of TOA
     let tpduLength = (messageStringLength / 2) - (smscLength + 1); // In octets
 
     // Device identities: 4 bytes
     // Address: 0 or (2 + smscLength)
     // SMS TPDU: (2 or 3) + tpduLength
     let berLen = 4 +
@@ -4004,27 +3997,27 @@ let RIL = {
     GsmPDUHelper.writeHexOctet(0x02);
     GsmPDUHelper.writeHexOctet(STK_DEVICE_ID_NETWORK);
     GsmPDUHelper.writeHexOctet(STK_DEVICE_ID_SIM);
 
     // Address-TLV
     if (smscLength) {
       GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_ADDRESS);
       GsmPDUHelper.writeHexOctet(smscLength);
-      Buf.copyIncomingToOutgoing(PDU_HEX_OCTET_SIZE * smscLength);
+      Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * smscLength);
     }
 
     // SMS TPDU-TLV
     GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_SMS_TPDU |
                                COMPREHENSIONTLV_FLAG_CR);
     if (tpduLength > 127) {
       GsmPDUHelper.writeHexOctet(0x81);
     }
     GsmPDUHelper.writeHexOctet(tpduLength);
-    Buf.copyIncomingToOutgoing(PDU_HEX_OCTET_SIZE * tpduLength);
+    Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * tpduLength);
 
     // Write 2 string delimitors for the total string length must be even.
     Buf.writeStringDelimiter(0);
 
     Buf.sendParcel();
   },
 
   /**
@@ -4063,78 +4056,79 @@ let RIL = {
     GsmPDUHelper.writeHexOctet(options.dcs);
     // 6. TP-UDL
     if (options.encoding == PDU_DCS_MSG_CODING_7BITS_ALPHABET) {
       GsmPDUHelper.writeHexOctet(Math.floor(responsePduLen * 8 / 7));
     } else {
       GsmPDUHelper.writeHexOctet(responsePduLen);
     }
     // TP-UD
-    Buf.copyIncomingToOutgoing(PDU_HEX_OCTET_SIZE * responsePduLen);
+    Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * responsePduLen);
     // Write 2 string delimitors for the total string length must be even.
     Buf.writeStringDelimiter(0);
 
     Buf.sendParcel();
   },
 
   /**
    * @param message A decoded SMS-DELIVER message.
    */
   writeSmsToSIM: function writeSmsToSIM(message) {
     Buf.newParcel(REQUEST_WRITE_SMS_TO_SIM);
 
     // Write EFsms Status
     Buf.writeUint32(EFSMS_STATUS_FREE);
 
     Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable()
-                           - 2 * UINT32_SIZE)); // Skip response_type & request_type.
+                           - 2 * Buf.UINT32_SIZE)); // Skip response_type & request_type.
     let messageStringLength = Buf.readUint32(); // In semi-octets
     let smscLength = GsmPDUHelper.readHexOctet(); // In octets, inclusive of TOA
     let pduLength = (messageStringLength / 2) - (smscLength + 1); // In octets
 
     // 1. Write PDU first.
     if (smscLength > 0) {
-      Buf.seekIncoming(smscLength * PDU_HEX_OCTET_SIZE);
+      Buf.seekIncoming(smscLength * Buf.PDU_HEX_OCTET_SIZE);
     }
     // Write EFsms PDU string length
     Buf.writeUint32(2 * pduLength); // In semi-octets
     if (pduLength) {
-      Buf.copyIncomingToOutgoing(PDU_HEX_OCTET_SIZE * pduLength);
+      Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * pduLength);
     }
     // Write 2 string delimitors for the total string length must be even.
     Buf.writeStringDelimiter(0);
 
     // 2. Write SMSC
     // Write EFsms SMSC string length
     Buf.writeUint32(2 * (smscLength + 1)); // Plus smscLength itself, in semi-octets
     // Write smscLength
     GsmPDUHelper.writeHexOctet(smscLength);
     // Write TOA & SMSC Address
     if (smscLength) {
       Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable()
-                             - 2 * UINT32_SIZE // Skip response_type, request_type.
-                             - 2 * PDU_HEX_OCTET_SIZE)); // Skip messageStringLength & smscLength.
-      Buf.copyIncomingToOutgoing(PDU_HEX_OCTET_SIZE * smscLength);
+                             - 2 * Buf.UINT32_SIZE // Skip response_type, request_type.
+                             - 2 * Buf.PDU_HEX_OCTET_SIZE)); // Skip messageStringLength & smscLength.
+      Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * smscLength);
     }
     // Write 2 string delimitors for the total string length must be even.
     Buf.writeStringDelimiter(0);
 
     Buf.sendParcel();
   },
 
   /**
    * Helper for processing multipart SMS.
    *
    * @param message
    *        Received sms message.
    *
    * @return A failure cause defined in 3GPP 23.040 clause 9.2.3.22.
    */
   _processSmsMultipart: function _processSmsMultipart(message) {
-    if (message.header && (message.header.segmentMaxSeq > 1)) {
+    if (message.header && message.header.segmentMaxSeq &&
+        (message.header.segmentMaxSeq > 1)) {
       message = this._processReceivedSmsSegment(message);
     } else {
       if (message.encoding == PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
         message.fullData = message.data;
         delete message.data;
       } else {
         message.fullBody = message.body;
         delete message.body;
@@ -6578,17 +6572,17 @@ let GsmPDUHelper = {
         }
       } else if (octet == PDU_NL_EXTENDED_ESCAPE) {
         escapeFound = true;
       } else {
         ret += langTable[octet];
       }
     }
 
-    Buf.seekIncoming((numOctets - i) * PDU_HEX_OCTET_SIZE);
+    Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE);
     return ret;
   },
 
   /**
    * Write GSM 8-bit unpacked octets.
    *
    * @param numOctets   Number of total octets to be writen, including trailing
    *                    0xff.
@@ -6690,17 +6684,17 @@ let GsmPDUHelper = {
           if (code == 0xffff) {
             i += 2;
             break;
           }
           str += String.fromCharCode(code);
         }
 
         // Skip trailing 0xff
-        Buf.seekIncoming((numOctets - i) * PDU_HEX_OCTET_SIZE);
+        Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE);
         break;
       case 0x81: // Fall through
       case 0x82:
         /**
          * +------+-----+--------+-----+-----+-----+--------+------+
          * | 0x81 | len | offset | Ch1 | Ch2 | ... | Ch_len | 0xff |
          * +------+-----+--------+-----+-----+-----+--------+------+
          *
@@ -6744,24 +6738,24 @@ let GsmPDUHelper = {
               count++;
               if (this.readHexOctet() & 0x80) {
                 gotUCS2 = 1;
                 break;
               }
             }
             // Unread.
             // +1 for the GSM alphabet indexed at i,
-            Buf.seekIncoming(-1 * (count + 1) * PDU_HEX_OCTET_SIZE);
+            Buf.seekIncoming(-1 * (count + 1) * Buf.PDU_HEX_OCTET_SIZE);
             str += this.read8BitUnpackedToString(count + 1 - gotUCS2);
             i += count - gotUCS2;
           }
         }
 
         // Skipping trailing 0xff
-        Buf.seekIncoming((numOctets - len - headerLen) * PDU_HEX_OCTET_SIZE);
+        Buf.seekIncoming((numOctets - len - headerLen) * Buf.PDU_HEX_OCTET_SIZE);
         break;
     }
     return str;
   },
 
   /**
    * Read 1 + UDHL octets and construct user data header.
    *
@@ -7021,17 +7015,17 @@ let GsmPDUHelper = {
     let length = Buf.readUint32();
 
     let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES;
     let alphaId = this.readAlphaIdentifier(alphaLen);
 
     let number = this.readNumberWithLength();
 
     // Skip 2 unused octets, CCP and EXT1.
-    Buf.seekIncoming(2 * PDU_HEX_OCTET_SIZE);
+    Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE);
     Buf.readStringDelimiter(length);
 
     let contact = null;
     if (alphaId || number) {
       contact = {alphaId: alphaId,
                  number: number};
     }
     return contact;
@@ -7083,17 +7077,17 @@ let GsmPDUHelper = {
     let temp;
     // Read the 1st octet to determine the encoding.
     if ((temp = GsmPDUHelper.readHexOctet()) == 0x80 ||
          temp == 0x81 ||
          temp == 0x82) {
       numOctets--;
       return this.readICCUCS2String(temp, numOctets);
     } else {
-      Buf.seekIncoming(-1 * PDU_HEX_OCTET_SIZE);
+      Buf.seekIncoming(-1 * Buf.PDU_HEX_OCTET_SIZE);
       return this.read8BitUnpackedToString(numOctets);
     }
   },
 
   /**
    * Write Alpha Identifier.
    *
    * @param numOctets
@@ -7187,19 +7181,19 @@ let GsmPDUHelper = {
     let number;
     let numLen = this.readHexOctet();
     if (numLen != 0xff) {
       if (numLen > ADN_MAX_BCD_NUMBER_BYTES) {
         throw new Error("invalid length of BCD number/SSC contents - " + numLen);
       }
 
       number = this.readDiallingNumber(numLen);
-      Buf.seekIncoming((ADN_MAX_BCD_NUMBER_BYTES - numLen) * PDU_HEX_OCTET_SIZE);
+      Buf.seekIncoming((ADN_MAX_BCD_NUMBER_BYTES - numLen) * Buf.PDU_HEX_OCTET_SIZE);
     } else {
-      Buf.seekIncoming(ADN_MAX_BCD_NUMBER_BYTES * PDU_HEX_OCTET_SIZE);
+      Buf.seekIncoming(ADN_MAX_BCD_NUMBER_BYTES * Buf.PDU_HEX_OCTET_SIZE);
     }
 
     return number;
   },
 
   writeNumberWithLength: function writeNumberWithLength(number) {
     if (number) {
       let numStart = number[0] == "+" ? 1 : 0;
@@ -9855,17 +9849,17 @@ StkCommandParamsFactory[STK_CMD_TIMER_MA
 
 let StkProactiveCmdHelper = {
   retrieve: function retrieve(tag, length) {
     let method = StkProactiveCmdHelper[tag];
     if (typeof method != "function") {
       if (DEBUG) {
         debug("Unknown comprehension tag " + tag.toString(16));
       }
-      Buf.seekIncoming(length * PDU_HEX_OCTET_SIZE);
+      Buf.seekIncoming(length * Buf.PDU_HEX_OCTET_SIZE);
       return null;
     }
     return method.call(this, length);
   },
 
   /**
    * Command Details.
    *
@@ -10821,17 +10815,17 @@ let ICCIOHelper = {
    * Process a ICC_COMMAND_GET_RESPONSE type command for REQUEST_SIM_IO.
    */
   processICCIOGetResponse: function processICCIOGetResponse(options) {
     let strLen = Buf.readUint32();
 
     // The format is from TS 51.011, clause 9.2.1
 
     // Skip RFU, data[0] data[1]
-    Buf.seekIncoming(2 * PDU_HEX_OCTET_SIZE);
+    Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE);
 
     // File size, data[2], data[3]
     options.fileSize = (GsmPDUHelper.readHexOctet() << 8) |
                         GsmPDUHelper.readHexOctet();
 
     // 2 bytes File id. data[4], data[5]
     let fileId = (GsmPDUHelper.readHexOctet() << 8) |
                   GsmPDUHelper.readHexOctet();
@@ -10846,31 +10840,31 @@ let ICCIOHelper = {
       throw new Error("Unexpected file type " + fileType);
     }
 
     // Skip 1 byte RFU, data[7],
     //      3 bytes Access conditions, data[8] data[9] data[10],
     //      1 byte File status, data[11],
     //      1 byte Length of the following data, data[12].
     Buf.seekIncoming(((RESPONSE_DATA_STRUCTURE - RESPONSE_DATA_FILE_TYPE - 1) *
-        PDU_HEX_OCTET_SIZE));
+        Buf.PDU_HEX_OCTET_SIZE));
 
     // Read Structure of EF, data[13]
     let efType = GsmPDUHelper.readHexOctet();
     if (efType != options.type) {
       throw new Error("Expected EF type " + options.type + " but read " + efType);
     }
 
     // Length of a record, data[14].
     // Only available for LINEAR_FIXED and CYCLIC.
     if (efType == EF_TYPE_LINEAR_FIXED || efType == EF_TYPE_CYCLIC) {
       options.recordSize = GsmPDUHelper.readHexOctet();
       options.totalRecords = options.fileSize / options.recordSize;
     } else {
-      Buf.seekIncoming(1 * PDU_HEX_OCTET_SIZE);
+      Buf.seekIncoming(1 * Buf.PDU_HEX_OCTET_SIZE);
     }
 
     Buf.readStringDelimiter(strLen);
 
     if (options.callback) {
       options.callback(options);
     }
   },
@@ -11253,17 +11247,17 @@ let ICCRecordHelper = {
       let strLen = Buf.readUint32();
       let octetLen = strLen / 2, readLen = 0;
 
       let pbrTlvs = [];
       while (readLen < octetLen) {
         let tag = GsmPDUHelper.readHexOctet();
         if (tag == 0xff) {
           readLen++;
-          Buf.seekIncoming((octetLen - readLen) * PDU_HEX_OCTET_SIZE);
+          Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
           break;
         }
 
         let tlvLen = GsmPDUHelper.readHexOctet();
         let tlvs = ICCUtilsHelper.decodeSimTlvs(tlvLen);
         pbrTlvs.push({tag: tag,
                       length: tlvLen,
                       value: tlvs});
@@ -11397,17 +11391,17 @@ let ICCRecordHelper = {
       // Note: The fields marked as C above are mandatort if the file
       //       is not type 1 (as specified in EF_PBR)
       if (fileType == ICC_USIM_TYPE1_TAG) {
         email = GsmPDUHelper.read8BitUnpackedToString(octetLen);
       } else {
         email = GsmPDUHelper.read8BitUnpackedToString(octetLen - 2);
 
         // Consumes the remaining buffer
-        Buf.seekIncoming(2 * PDU_HEX_OCTET_SIZE); // For ADN SFI and Record Identifier
+        Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); // For ADN SFI and Record Identifier
       }
 
       Buf.readStringDelimiter(strLen);
 
       if (onsuccess) {
         onsuccess(email);
       }
     }
@@ -11475,27 +11469,27 @@ let ICCRecordHelper = {
    */
   readANR: function readANR(fileId, fileType, recordNumber, onsuccess, onerror) {
     function callback(options) {
       let strLen = Buf.readUint32();
       let number = null;
       this._anrRecordSize = options.recordSize;
 
       // Skip EF_AAS Record ID.
-      Buf.seekIncoming(1 * PDU_HEX_OCTET_SIZE);
+      Buf.seekIncoming(1 * Buf.PDU_HEX_OCTET_SIZE);
 
       number = GsmPDUHelper.readNumberWithLength();
 
       // Skip 2 unused octets, CCP and EXT1.
-      Buf.seekIncoming(2 * PDU_HEX_OCTET_SIZE);
+      Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE);
 
       // For Type 2 there are two extra octets.
       if (fileType == ICC_USIM_TYPE2_TAG) {
         // Skip 2 unused octets, ADN SFI and Record Identifier.
-        Buf.seekIncoming(2 * PDU_HEX_OCTET_SIZE);
+        Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE);
       }
 
       Buf.readStringDelimiter(strLen);
 
       if (onsuccess) {
         onsuccess(number);
       }
     }
@@ -11582,17 +11576,17 @@ let ICCRecordHelper = {
           // We don't care about its content if its tag is not SPDI nor
           // PLMN_LIST.
           endLoop = true;
           break;
         }
       }
 
       // Consume unread octets.
-      Buf.seekIncoming((octetLen - readLen) * PDU_HEX_OCTET_SIZE);
+      Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
       Buf.readStringDelimiter(strLen);
 
       if (DEBUG) debug("SPDI: " + JSON.stringify(RIL.iccInfoPrivate.SPDI));
       if (ICCUtilsHelper.updateDisplayCondition()) {
         ICCUtilsHelper.handleICCInfoChange();
       }
     }
 
@@ -11758,17 +11752,17 @@ let ICCRecordHelper = {
           (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet();
         // PLMN Network Name Record Identifier
         oplElement.pnnRecordId = GsmPDUHelper.readHexOctet();
         if (DEBUG) {
           debug("OPL: [" + (opl.length + 1) + "]: " + JSON.stringify(oplElement));
         }
         opl.push(oplElement);
       } else {
-        Buf.seekIncoming(5 * PDU_HEX_OCTET_SIZE);
+        Buf.seekIncoming(5 * Buf.PDU_HEX_OCTET_SIZE);
       }
       Buf.readStringDelimiter(strLen);
 
       if (options.p1 < options.totalRecords) {
         ICCIOHelper.loadNextRecord(options);
       } else {
         RIL.iccInfoPrivate.OPL = opl;
       }
@@ -11792,34 +11786,34 @@ let ICCRecordHelper = {
       let readLen = 0;
 
       while (readLen < octetLen) {
         let tlvTag = GsmPDUHelper.readHexOctet();
 
         if (tlvTag == 0xFF) {
           // Unused byte
           readLen++;
-          Buf.seekIncoming((octetLen - readLen) * PDU_HEX_OCTET_SIZE);
+          Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
           break;
         }
 
         // Needs this check to avoid initializing twice.
         pnnElement = pnnElement || {};
 
         let tlvLen = GsmPDUHelper.readHexOctet();
 
         switch (tlvTag) {
           case PNN_IEI_FULL_NETWORK_NAME:
             pnnElement.fullName = GsmPDUHelper.readNetworkName(tlvLen);
             break;
           case PNN_IEI_SHORT_NETWORK_NAME:
             pnnElement.shortName = GsmPDUHelper.readNetworkName(tlvLen);
             break;
           default:
-            Buf.seekIncoming(tlvLen * PDU_HEX_OCTET_SIZE);
+            Buf.seekIncoming(tlvLen * Buf.PDU_HEX_OCTET_SIZE);
             break;
         }
 
         readLen += (tlvLen + 2); // +2 for tlvTag and tlvLen
       }
       Buf.readStringDelimiter(strLen);
 
       if (pnnElement) {
@@ -11867,17 +11861,17 @@ let ICCRecordHelper = {
 
       if (readLen == octetLen) {
         // Find free record.
         if (onsuccess) {
           onsuccess(options.p1);
         }
         return;
       } else {
-        Buf.seekIncoming((octetLen - readLen) * PDU_HEX_OCTET_SIZE);
+        Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
       }
 
       Buf.readStringDelimiter(strLen);
 
       if (options.p1 < options.totalRecords) {
         ICCIOHelper.loadNextRecord(options);
       } else {
         // No free record found.
@@ -12920,17 +12914,17 @@ let RuimRecordHelper = {
     function callback(options) {
       let strLen = Buf.readUint32();
       let tempOctet = GsmPDUHelper.readHexOctet();
       cdmaHomeSystemId.push(((GsmPDUHelper.readHexOctet() & 0x7f) << 8) | tempOctet);
       tempOctet = GsmPDUHelper.readHexOctet();
       cdmaHomeNetworkId.push(((GsmPDUHelper.readHexOctet() & 0xff) << 8) | tempOctet);
 
       // Consuming the last octet: band class.
-      Buf.seekIncoming(PDU_HEX_OCTET_SIZE);
+      Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE);
 
       Buf.readStringDelimiter(strLen);
       if (options.p1 < options.totalRecords) {
         ICCIOHelper.loadNextRecord(options);
       } else {
         if (DEBUG) {
           debug("CDMAHome system id: " + JSON.stringify(cdmaHomeSystemId));
           debug("CDMAHome network id: " + JSON.stringify(cdmaHomeNetworkId));
@@ -12977,17 +12971,17 @@ let RuimRecordHelper = {
 
   readSPN: function readSPN() {
     function callback() {
       let strLen = Buf.readUint32();
       let octetLen = strLen / 2;
       let displayCondition = GsmPDUHelper.readHexOctet();
       let codingScheme = GsmPDUHelper.readHexOctet();
       // Skip one octet: language indicator.
-      Buf.seekIncoming(PDU_HEX_OCTET_SIZE);
+      Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE);
       let readLen = 3;
 
       // SPN String ends up with 0xff.
       let userDataBuffer = [];
 
       while (readLen < octetLen) {
         let octet = GsmPDUHelper.readHexOctet();
         readLen++;
@@ -13013,17 +13007,17 @@ let RuimRecordHelper = {
       }
 
       RIL.iccInfo.spn = CdmaPDUHelper.decodeCdmaPDUMsg(codingScheme, null, msgLen);
       if (DEBUG) {
         debug("CDMA SPN: " + RIL.iccInfo.spn +
               ", Display condition: " + displayCondition);
       }
       RIL.iccInfoPrivate.spnDisplayCondition = displayCondition;
-      Buf.seekIncoming((octetLen - readLen) * PDU_HEX_OCTET_SIZE);
+      Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE);
       Buf.readStringDelimiter(strLen);
     }
 
     ICCIOHelper.loadTransparentEF({fileId: ICC_EF_CSIM_SPN,
                                    callback: callback.bind(this)});
   }
 };
 
--- a/dom/system/gonk/tests/header_helpers.js
+++ b/dom/system/gonk/tests/header_helpers.js
@@ -20,17 +20,20 @@ let subscriptLoader = Cc["@mozilla.org/m
  *
  * @note that this does not start an actual worker thread. The worker
  * is executed on the main thread, within a separate namespace object.
  */
 function newWorker(custom_ns) {
   let worker_ns = {
     importScripts: function fakeImportScripts() {
       Array.slice(arguments).forEach(function (script) {
-        subscriptLoader.loadSubScript("resource://gre/modules/" + script, this);
+        if (!script.startsWith("resource:")) {
+          script = "resource://gre/modules/" + script;
+        }
+        subscriptLoader.loadSubScript(script, this);
       }, this);
     },
 
     postRILMessage: function fakePostRILMessage(message) {
     },
 
     postMessage: function fakepostMessage(message) {
     },
@@ -49,16 +52,32 @@ function newWorker(custom_ns) {
   // systemlibs.js utilizes ctypes for loading native libraries.
   Cu.import("resource://gre/modules/ctypes.jsm", worker_ns);
 
   // Copy the custom definitions over.
   for (let key in custom_ns) {
     worker_ns[key] = custom_ns[key];
   }
 
+  // fake require() for toolkit/components/workerloader/require.js
+  let require = (function() {
+    return function require(script) {
+      worker_ns.module = {};
+      worker_ns.importScripts(script);
+      return worker_ns;
+    }
+  })();
+
+  Object.freeze(require);
+  Object.defineProperty(worker_ns, "require", {
+    value: require,
+    enumerable: true,
+    configurable: false
+  });
+
   // Load the RIL worker itself.
   worker_ns.importScripts("ril_worker.js");
 
   return worker_ns;
 }
 
 /**
  * Create a parcel suitable for postRILMessage().
@@ -118,25 +137,26 @@ function newIncomingParcel(fakeParcelSiz
   }
 
   return bytes;
 }
 
 /**
  *
  */
-function newRadioInterfaceLayer() {
-  let ril_ns = {
-    ChromeWorker: function ChromeWorker() {
-      // Stub function
-    },
+let ril_ns;
+function newRadioInterface() {
+  if (!ril_ns) {
+    ril_ns = {};
+    subscriptLoader.loadSubScript("resource://gre/components/RadioInterfaceLayer.js", ril_ns);
+  }
+
+  return {
+    __proto__: ril_ns.RadioInterface.prototype,
   };
-
-  subscriptLoader.loadSubScript("resource://gre/components/RadioInterfaceLayer.js", ril_ns);
-  return new ril_ns.RadioInterfaceLayer();
 }
 
 /**
  * Test whether specified function throws exception with expected
  * result.
  *
  * @param func
  *        Function to be tested.
--- a/dom/system/gonk/tests/test_ril_worker_buf.js
+++ b/dom/system/gonk/tests/test_ril_worker_buf.js
@@ -27,17 +27,18 @@ function add_test_incoming_parcel(parcel
     if (!parcel) {
       parcel = newIncomingParcel(-1,
                                  worker.RESPONSE_TYPE_UNSOLICITED,
                                  worker.REQUEST_VOICE_REGISTRATION_STATE,
                                  [0, 0, 0, 0]);
     }
 
     // supports only requests less or equal than UINT8_MAX(255).
-    let request = parcel[worker.PARCEL_SIZE_SIZE + worker.UINT32_SIZE];
+    let buf = worker.Buf;
+    let request = parcel[buf.PARCEL_SIZE_SIZE + buf.UINT32_SIZE];
     worker.RIL[request] = function ril_request_handler() {
       handler(worker);
       worker.postMessage();
     };
 
     worker.onRILMessage(parcel);
 
     // end of incoming parcel's trip, let's do next test.
@@ -106,40 +107,40 @@ add_test(function test_incoming_parcel_b
   }
 
   // Do nothing in handleParcel().
   let request = worker.REQUEST_VOICE_REGISTRATION_STATE;
   worker.RIL[request] = null;
 
   // Prepare two parcels, whose sizes are both smaller than the incoming buffer
   // size but larger when combined, to trigger the bug.
-  let pA_dataLength = buf.INCOMING_BUFFER_LENGTH / 2;
+  let pA_dataLength = buf.incomingBufferLength / 2;
   let pA = newIncomingParcel(-1,
                              worker.RESPONSE_TYPE_UNSOLICITED,
                              request,
                              calloc(pA_dataLength, 1));
-  let pA_parcelSize = pA.length - worker.PARCEL_SIZE_SIZE;
+  let pA_parcelSize = pA.length - buf.PARCEL_SIZE_SIZE;
 
-  let pB_dataLength = buf.INCOMING_BUFFER_LENGTH * 3 / 4;
+  let pB_dataLength = buf.incomingBufferLength * 3 / 4;
   let pB = newIncomingParcel(-1,
                              worker.RESPONSE_TYPE_UNSOLICITED,
                              request,
                              calloc(pB_dataLength, 1));
-  let pB_parcelSize = pB.length - worker.PARCEL_SIZE_SIZE;
+  let pB_parcelSize = pB.length - buf.PARCEL_SIZE_SIZE;
 
   // First, send an incomplete pA and verifies related data pointer:
   let p1 = pA.subarray(0, pA.length - 1);
   worker.onRILMessage(p1);
   // The parcel should not have been processed.
   do_check_eq(buf.readAvailable, 0);
   // buf.currentParcelSize should have been set because incoming data has more
   // than 4 octets.
   do_check_eq(buf.currentParcelSize, pA_parcelSize);
   // buf.readIncoming should contains remaining unconsumed octets count.
-  do_check_eq(buf.readIncoming, p1.length - worker.PARCEL_SIZE_SIZE);
+  do_check_eq(buf.readIncoming, p1.length - buf.PARCEL_SIZE_SIZE);
   // buf.incomingWriteIndex should be ready to accept the last octet.
   do_check_eq(buf.incomingWriteIndex, p1.length);
 
   // Second, send the last octet of pA and whole pB. The Buf should now expand
   // to cover both pA & pB.
   let p2 = new Uint8Array(1 + pB.length);
   p2.set(pA.subarray(pA.length - 1), 0);
   p2.set(pB, 1);
--- a/dom/system/gonk/tests/test_ril_worker_sms.js
+++ b/dom/system/gonk/tests/test_ril_worker_sms.js
@@ -1,537 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
 
 const ESCAPE = "\uffff";
 const RESCTL = "\ufffe";
-const LF = "\n";
-const CR = "\r";
-const SP = " ";
-const FF = "\u000c";
 
 function run_test() {
   run_next_test();
 }
 
 /**
- * Verify validity of the national language tables
- */
-add_test(function test_nl_locking_shift_tables_validity() {
-  for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) {
-    do_print("Verifying PDU_NL_LOCKING_SHIFT_TABLES[" + lst + "]");
-
-    let table = PDU_NL_LOCKING_SHIFT_TABLES[lst];
-
-    // Make sure table length is 128, or it will break table lookup algorithm.
-    do_check_eq(table.length, 128);
-
-    // Make sure special values are preserved.
-    do_check_eq(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE);
-    do_check_eq(table[PDU_NL_LINE_FEED], LF);
-    do_check_eq(table[PDU_NL_CARRIAGE_RETURN], CR);
-    do_check_eq(table[PDU_NL_SPACE], SP);
-  }
-
-  run_next_test();
-});
-
-add_test(function test_nl_single_shift_tables_validity() {
-  for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) {
-    do_print("Verifying PDU_NL_SINGLE_SHIFT_TABLES[" + sst + "]");
-
-    let table = PDU_NL_SINGLE_SHIFT_TABLES[sst];
-
-    // Make sure table length is 128, or it will break table lookup algorithm.
-    do_check_eq(table.length, 128);
-
-    // Make sure special values are preserved.
-    do_check_eq(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE);
-    do_check_eq(table[PDU_NL_PAGE_BREAK], FF);
-    do_check_eq(table[PDU_NL_RESERVED_CONTROL], RESCTL);
-  }
-
-  run_next_test();
-});
-
-add_test(function test_gsm_sms_strict_7bit_charmap_validity() {
-  let defaultTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
-  let defaultShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
-  for (let from in GSM_SMS_STRICT_7BIT_CHARMAP) {
-    let to = GSM_SMS_STRICT_7BIT_CHARMAP[from];
-    do_print("Verifying GSM_SMS_STRICT_7BIT_CHARMAP[\"\\u0x"
-             + from.charCodeAt(0).toString(16) + "\"] => \"\\u"
-             + to.charCodeAt(0).toString(16) + "\"");
-
-    // Make sure "from" is not in default table
-    do_check_eq(defaultTable.indexOf(from), -1);
-    do_check_eq(defaultShiftTable.indexOf(from), -1);
-    // Make sure "to" is in default table
-    if ((defaultTable.indexOf(to) < 0)
-        && (defaultShiftTable.indexOf(to) < 0)) {
-      do_check_eq(false, true);
-    }
-  }
-
-  run_next_test();
-});
-
-/**
- * Verify GsmPDUHelper#readDataCodingScheme.
- */
-add_test(function test_GsmPDUHelper_readDataCodingScheme() {
-  let worker = newWorker({
-    postRILMessage: function fakePostRILMessage(data) {
-      // Do nothing
-    },
-    postMessage: function fakePostMessage(message) {
-      // Do nothing
-    }
-  });
-
-  let helper = worker.GsmPDUHelper;
-  function test_dcs(dcs, encoding, messageClass, mwi) {
-    helper.readHexOctet = function () {
-      return dcs;
-    }
-
-    let msg = {};
-    helper.readDataCodingScheme(msg);
-
-    do_check_eq(msg.dcs, dcs);
-    do_check_eq(msg.encoding, encoding);
-    do_check_eq(msg.messageClass, messageClass);
-    do_check_eq(msg.mwi == null, mwi == null);
-    if (mwi != null) {
-      do_check_eq(msg.mwi.active, mwi.active);
-      do_check_eq(msg.mwi.discard, mwi.discard);
-      do_check_eq(msg.mwi.msgCount, mwi.msgCount);
-    }
-  }
-
-  // Group 00xx
-  //   Bit 3 and 2 indicate the character set being used.
-  test_dcs(0x00, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
-  test_dcs(0x04, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
-  test_dcs(0x08, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
-  test_dcs(0x0C, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
-  //   Bit 4, if set to 0, indicates that bits 1 to 0 are reserved and have no
-  //   message class meaning.
-  test_dcs(0x01, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
-  test_dcs(0x02, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
-  test_dcs(0x03, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
-  //   Bit 4, if set to 1, indicates that bits 1 to 0 have a message class meaning.
-  test_dcs(0x10, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
-  test_dcs(0x11, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]);
-  test_dcs(0x12, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]);
-  test_dcs(0x13, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]);
-
-  // Group 01xx
-  test_dcs(0x50, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
-
-  // Group 1000..1011: reserved
-  test_dcs(0x8F, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
-  test_dcs(0x9F, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
-  test_dcs(0xAF, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
-  test_dcs(0xBF, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
-
-  // Group 1100: Message Waiting Indication Group: Discard Message
-  //   Bit 3 indicates Indication Sense:
-  test_dcs(0xC0, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
-           {active: false, discard: true, msgCount: 0});
-  test_dcs(0xC8, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
-           {active: true, discard: true, msgCount: -1});
-  //   Bit 2 is reserved, and set to 0:
-  test_dcs(0xCC, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
-           {active: true, discard: true, msgCount: -1});
-
-  // Group 1101: Message Waiting Indication Group: Store Message
-  //   Bit 3 indicates Indication Sense:
-  test_dcs(0xD0, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
-           {active: false, discard: false, msgCount: 0});
-  test_dcs(0xD8, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
-           {active: true, discard: false, msgCount: -1});
-  //   Bit 2 is reserved, and set to 0:
-  test_dcs(0xDC, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
-           {active: true, discard: false, msgCount: -1});
-
-  // Group 1110: Message Waiting Indication Group: Store Message, UCS2
-  //   Bit 3 indicates Indication Sense:
-  test_dcs(0xE0, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
-           {active: false, discard: false, msgCount: 0});
-  test_dcs(0xE8, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
-           {active: true, discard: false, msgCount: -1});
-  //   Bit 2 is reserved, and set to 0:
-  test_dcs(0xEC, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
-           {active: true, discard: false, msgCount: -1});
-
-  // Group 1111
-  test_dcs(0xF0, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
-  test_dcs(0xF1, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]);
-  test_dcs(0xF2, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]);
-  test_dcs(0xF3, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]);
-  test_dcs(0xF4, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
-  test_dcs(0xF5, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]);
-  test_dcs(0xF6, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]);
-  test_dcs(0xF7, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]);
-  //   Bit 3 is reserved and should be set to 0, but if it doesn't we should
-  //   ignore it.
-  test_dcs(0xF8, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
-           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
-
-  run_next_test();
-});
-
-/**
- * Verify RadioInterfaceLayer#_countGsm7BitSeptets() and
- * GsmPDUHelper#writeStringAsSeptets() algorithm match each other.
- */
-add_test(function test_RadioInterfaceLayer__countGsm7BitSeptets() {
-  let ril = newRadioInterfaceLayer();
-
-  let worker = newWorker({
-    postRILMessage: function fakePostRILMessage(data) {
-      // Do nothing
-    },
-    postMessage: function fakePostMessage(message) {
-      // Do nothing
-    }
-  });
-
-  let helper = worker.GsmPDUHelper;
-  helper.resetOctetWritten = function () {
-    helper.octetsWritten = 0;
-  };
-  helper.writeHexOctet = function () {
-    helper.octetsWritten++;
-  };
-
-  function do_check_calc(str, expectedCalcLen, lst, sst, strict7BitEncoding, strToWrite) {
-    do_check_eq(expectedCalcLen,
-                ril._countGsm7BitSeptets(str,
-                                         PDU_NL_LOCKING_SHIFT_TABLES[lst],
-                                         PDU_NL_SINGLE_SHIFT_TABLES[sst],
-                                         strict7BitEncoding));
-
-    helper.resetOctetWritten();
-    strToWrite = strToWrite || str;
-    helper.writeStringAsSeptets(strToWrite, 0, lst, sst);
-    do_check_eq(Math.ceil(expectedCalcLen * 7 / 8), helper.octetsWritten);
-  }
-
-  // Test calculation encoded message length using both locking/single shift tables.
-  for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) {
-    let langTable = PDU_NL_LOCKING_SHIFT_TABLES[lst];
-
-    let str = langTable.substring(0, PDU_NL_EXTENDED_ESCAPE)
-              + langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1);
-
-    for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) {
-      let langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[sst];
-
-      // <escape>, <resctrl> should be ignored.
-      do_check_calc(ESCAPE + RESCTL, 0, lst, sst);
-
-      // Characters defined in locking shift table should be encoded directly.
-      do_check_calc(str, str.length, lst, sst);
-
-      let [str1, str2] = ["", ""];
-      for (let i = 0; i < langShiftTable.length; i++) {
-        if ((i == PDU_NL_EXTENDED_ESCAPE) || (i == PDU_NL_RESERVED_CONTROL)) {
-          continue;
-        }
-
-        let c = langShiftTable[i];
-        if (langTable.indexOf(c) >= 0) {
-          str1 += c;
-        } else {
-          str2 += c;
-        }
-      }
-
-      // Characters found in both locking/single shift tables should be
-      // directly encoded.
-      do_check_calc(str1, str1.length, lst, sst);
-
-      // Characters found only in single shift tables should be encoded as
-      // <escape><code>, therefore doubles its original length.
-      do_check_calc(str2, str2.length * 2, lst, sst);
-    }
-  }
-
-  // Bug 790192: support strict GSM SMS 7-Bit encoding
-  let str = "", strToWrite = "", gsmLen = 0;
-  for (let c in GSM_SMS_STRICT_7BIT_CHARMAP) {
-    str += c;
-    strToWrite += GSM_SMS_STRICT_7BIT_CHARMAP[c];
-    if (PDU_NL_LOCKING_SHIFT_TABLES.indexOf(GSM_SMS_STRICT_7BIT_CHARMAP[c])) {
-      gsmLen += 1;
-    } else {
-      gsmLen += 2;
-    }
-  }
-  do_check_calc(str, gsmLen,
-                PDU_NL_IDENTIFIER_DEFAULT, PDU_NL_IDENTIFIER_DEFAULT,
-                true, strToWrite);
-
-  run_next_test();
-});
-
-/**
- * Verify RadioInterfaceLayer#calculateUserDataLength handles national language
- * selection correctly.
- */
-add_test(function test_RadioInterfaceLayer__calculateUserDataLength() {
-  let ril = newRadioInterfaceLayer();
-
-  function test_calc(str, expected, enabledGsmTableTuples, strict7BitEncoding) {
-    ril.enabledGsmTableTuples = enabledGsmTableTuples;
-    let options = ril._calculateUserDataLength(str, strict7BitEncoding);
-
-    do_check_eq(expected[0], options.dcs);
-    do_check_eq(expected[1], options.encodedFullBodyLength);
-    do_check_eq(expected[2], options.userDataHeaderLength);
-    do_check_eq(expected[3], options.langIndex);
-    do_check_eq(expected[4], options.langShiftIndex);
-  }
-
-  // Test UCS fallback
-  // - No any default enabled nl tables
-  test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0,], []);
-  // - Character not defined in enabled nl tables
-  test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0,], [[2, 2]]);
-
-  // With GSM default nl tables
-  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 0, 0, 0], [[0, 0]]);
-  // - SP is defined in both locking/single shift tables, should be directly
-  //   encoded.
-  test_calc(SP, [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 0, 0, 0], [[0, 0]]);
-  // - '^' is only defined in single shift table, should be encoded as
-  //   <escape>^.
-  test_calc("^", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 0, 0, 0], [[0, 0]]);
-
-  // Test userDataHeaderLength calculation
-  // - Header contains both IEIs
-  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 6, 1, 1], [[1, 1]]);
-  // - Header contains only locking shift table IEI
-  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[1, 0]]);
-  // - Header contains only single shift table IEI
-  test_calc("^", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 3, 0, 1], [[0, 1]]);
-
-  // Test minimum cost nl tables selection
-  // - 'A' is defined in locking shift table
-  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[1, 0], [2, 0]]);
-  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[2, 0], [1, 0]]);
-  // - 'A' is defined in single shift table
-  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 6, 2, 4], [[2, 0], [2, 4]]);
-  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 6, 2, 4], [[2, 4], [2, 0]]);
-  // - 'A' is defined in locking shift table of one tuple and in single shift
-  //   table of another.
-  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[1, 0], [2, 4]]);
-  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 3, 1, 0], [[2, 4], [1, 0]]);
-
-  // Test Bug 733981
-  // - Case 1, headerLen is in octets, not septets. "\\" is defined in default
-  //   single shift table and Portuguese locking shift table. The original code
-  //   will add headerLen 7(octets), which should be 8(septets), to calculated
-  //   cost and gets 14, which should be 15 in total for the first run. As for
-  //   the second run, it will be undoubtedly 14 in total. With correct fix,
-  //   the best choice should be the second one.
-  test_calc("\\\\\\\\\\\\\\",
-            [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 14, 0, 0, 0], [[3, 1], [0, 0]]);
-  // - Case 2, possible early return non-best choice. The original code will
-  //   get total cost 6 in the first run and returns immediately. With correct
-  //   fix, the best choice should be the second one.
-  test_calc(ESCAPE + ESCAPE + ESCAPE + ESCAPE + ESCAPE + "\\",
-            [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 2, 0, 0, 0], [[3, 0], [0, 0]]);
-
-  // Test Bug 790192: support strict GSM SMS 7-Bit encoding
-  let str = "", gsmLen = 0, udhl = 0;
-  for (let c in GSM_SMS_STRICT_7BIT_CHARMAP) {
-    str += c;
-    if (PDU_NL_LOCKING_SHIFT_TABLES.indexOf(GSM_SMS_STRICT_7BIT_CHARMAP[c])) {
-      gsmLen += 1;
-    } else {
-      gsmLen += 2;
-    }
-  }
-  if (str.length > PDU_MAX_USER_DATA_UCS2) {
-    udhl = 5;
-  }
-  test_calc(str, [PDU_DCS_MSG_CODING_7BITS_ALPHABET, gsmLen, 0, 0, 0], [[0, 0]], true);
-  test_calc(str, [PDU_DCS_MSG_CODING_16BITS_ALPHABET, str.length * 2, udhl], [[0, 0]]);
-
-  run_next_test();
-});
-
-function generateStringOfLength(str, length) {
-  while (str.length < length) {
-    if (str.length < (length / 2)) {
-      str = str + str;
-    } else {
-      str = str + str.substr(0, length - str.length);
-    }
-  }
-
-  return str;
-}
-
-/**
- * Verify RadioInterfaceLayer#_calculateUserDataLength7Bit multipart handling.
- */
-add_test(function test_RadioInterfaceLayer__calculateUserDataLength7Bit_multipart() {
-  let ril = newRadioInterfaceLayer();
-
-  function test_calc(str, expected) {
-    let options = ril._calculateUserDataLength7Bit(str);
-
-    do_check_eq(expected[0], options.encodedFullBodyLength);
-    do_check_eq(expected[1], options.userDataHeaderLength);
-    do_check_eq(expected[2], options.segmentMaxSeq);
-  }
-
-  test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT),
-            [PDU_MAX_USER_DATA_7BIT, 0, 1]);
-  test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT + 1),
-            [PDU_MAX_USER_DATA_7BIT + 1, 5, 2]);
-
-  run_next_test();
-});
-
-/**
- * Verify RadioInterfaceLayer#_fragmentText().
- */
-add_test(function test_RadioInterfaceLayer__fragmentText7Bit() {
-  let ril = newRadioInterfaceLayer();
-
-  function test_calc(str, strict7BitEncoding, expectedSegments) {
-    expectedSegments = expectedSegments || 1;
-    let options = ril._fragmentText(str, null, strict7BitEncoding);
-    do_check_eq(expectedSegments, options.segments.length);
-  }
-
-  // 7-Bit
-
-  // Boundary checks
-  test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT), false);
-  test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT), true);
-  test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT + 1), false, 2);
-  test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT + 1), true, 2);
-
-  // Escaped character
-  test_calc(generateStringOfLength("{", PDU_MAX_USER_DATA_7BIT / 2), false);
-  test_calc(generateStringOfLength("{", PDU_MAX_USER_DATA_7BIT / 2 + 1), false, 2);
-  // Escaped character cannot be separated
-  test_calc(generateStringOfLength("{", (PDU_MAX_USER_DATA_7BIT - 7) * 2 / 2), false, 3);
-
-  // Test headerLen, 7 = Math.ceil(6 * 8 / 7), 6 = headerLen + 1
-  test_calc(generateStringOfLength("A", PDU_MAX_USER_DATA_7BIT - 7));
-  test_calc(generateStringOfLength("A", (PDU_MAX_USER_DATA_7BIT - 7) * 2), false, 2);
-  test_calc(generateStringOfLength("A", (PDU_MAX_USER_DATA_7BIT - 7) * 3), false, 3);
-
-  // UCS-2
-
-  // Boundary checks
-  test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2));
-  test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2), true);
-  test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2 + 1), false, 2);
-  // Bug 816082: when strict GSM SMS 7-Bit encoding is enabled, replace unicode
-  // chars with '*'.
-  test_calc(generateStringOfLength("\ua2db", PDU_MAX_USER_DATA_UCS2 + 1), true, 1);
-
-  // UCS2 character cannot be separated
-  ril.segmentRef16Bit = true;
-  test_calc(generateStringOfLength("\ua2db", (PDU_MAX_USER_DATA_UCS2 * 2 - 7) * 2 / 2), false, 3);
-  ril.segmentRef16Bit = false;
-
-  // Test Bug 790192: support strict GSM SMS 7-Bit encoding
-  for (let c in GSM_SMS_STRICT_7BIT_CHARMAP) {
-    test_calc(generateStringOfLength(c, PDU_MAX_USER_DATA_7BIT), false, 3);
-    test_calc(generateStringOfLength(c, PDU_MAX_USER_DATA_7BIT), true);
-    test_calc(generateStringOfLength(c, PDU_MAX_USER_DATA_UCS2), false);
-  }
-
-  run_next_test();
-});
-
-/**
- * Verify GsmPDUHelper#writeStringAsSeptets() padding bits handling.
- */
-add_test(function test_GsmPDUHelper_writeStringAsSeptets() {
-  let worker = newWorker({
-    postRILMessage: function fakePostRILMessage(data) {
-      // Do nothing
-    },
-    postMessage: function fakePostMessage(message) {
-      // Do nothing
-    }
-  });
-
-  let helper = worker.GsmPDUHelper;
-  helper.resetOctetWritten = function () {
-    helper.octetsWritten = 0;
-  };
-  helper.writeHexOctet = function () {
-    helper.octetsWritten++;
-  };
-
-  let base = "AAAAAAAA"; // Base string of 8 characters long
-  for (let len = 0; len < 8; len++) {
-    let str = base.substring(0, len);
-
-    for (let paddingBits = 0; paddingBits < 8; paddingBits++) {
-      do_print("Verifying GsmPDUHelper.writeStringAsSeptets("
-               + str + ", " + paddingBits + ", <default>, <default>)");
-      helper.resetOctetWritten();
-      helper.writeStringAsSeptets(str, paddingBits, PDU_NL_IDENTIFIER_DEFAULT,
-                                  PDU_NL_IDENTIFIER_DEFAULT);
-      do_check_eq(Math.ceil(((len * 7) + paddingBits) / 8),
-                  helper.octetsWritten);
-    }
-  }
-
-  run_next_test();
-});
-
-/**
  * Verify receiving SMS-DELIVERY messages
  */
 
 function hexToNibble(nibble) {
   nibble &= 0x0f;
   if (nibble < 10) {
     nibble += 48; // ASCII '0'
   } else {
@@ -643,33 +127,38 @@ function newWriteHexOctetAsUint8Worker()
 
 function add_test_receiving_sms(expected, pdu) {
   add_test(function test_receiving_sms() {
     let worker = newWorker({
       postRILMessage: function fakePostRILMessage(data) {
         // Do nothing
       },
       postMessage: function fakePostMessage(message) {
-        do_print("body: " + message.body);
-        do_check_eq(expected, message.body)
+        do_print("fullBody: " + message.fullBody);
+        do_check_eq(expected, message.fullBody)
       }
     });
 
     do_print("expect: " + expected);
     do_print("pdu: " + pdu);
     worker.onRILMessage(newSmsParcel(pdu));
 
     run_next_test();
   });
 }
 
+let test_receiving_7bit_alphabets__ril;
+let test_receiving_7bit_alphabets__worker;
 function test_receiving_7bit_alphabets(lst, sst) {
-  let ril = newRadioInterfaceLayer();
-
-  let worker = newWriteHexOctetAsUint8Worker();
+  if (!test_receiving_7bit_alphabets__ril) {
+    test_receiving_7bit_alphabets__ril = newRadioInterface();
+    test_receiving_7bit_alphabets__worker = newWriteHexOctetAsUint8Worker();
+  }
+  let ril = test_receiving_7bit_alphabets__ril;
+  let worker = test_receiving_7bit_alphabets__worker;
   let helper = worker.GsmPDUHelper;
   let buf = worker.Buf;
 
   function get7bitRawBytes(expected) {
     buf.outgoingIndex = 0;
     helper.writeStringAsSeptets(expected, 0, lst, sst);
 
     let subArray = buf.outgoingBytes.subarray(0, buf.outgoingIndex);
@@ -688,17 +177,17 @@ function test_receiving_7bit_alphabets(l
     let pdu = compose7bitPdu(lst, sst, rawBytes, septets);
     add_test_receiving_sms(expected, pdu);
 
     i += len;
   }
 }
 
 function test_receiving_ucs2_alphabets(text) {
-  let worker = newWriteHexOctetAsUint8Worker();
+  let worker = test_receiving_7bit_alphabets__worker;
   let buf = worker.Buf;
 
   function getUCS2RawBytes(expected) {
     buf.outgoingIndex = 0;
     worker.GsmPDUHelper.writeUCS2String(expected);
 
     let subArray = buf.outgoingBytes.subarray(0, buf.outgoingIndex);
     return Array.slice(subArray);
@@ -767,55 +256,8 @@ add_test(function test_sendSMS_UCS2_with
         encodedBodyLength: 12,
       }, {
         body: "World!",
         encodedBodyLength: 12,
       }
     ],
   });
 });
-
-/**
- * Verify GsmPDUHelper#readAddress
- */
-add_test(function test_GsmPDUHelper_readAddress() {
-  let worker = newWorker({
-    postRILMessage: function fakePostRILMessage(data) {
-      // Do nothing
-    },
-    postMessage: function fakePostMessage(message) {
-      // Do nothing
-    }
-
-  });
-
-  let helper = worker.GsmPDUHelper;
-  function test_address(addrHex, addrString) {
-    let uint16Array = [];
-    let ix = 0;
-    for (let i = 0; i < addrHex.length; ++i) {
-      uint16Array[i] = addrHex[i].charCodeAt();
-    }
-
-    worker.Buf.readUint16 = function (){
-      if(ix >= uint16Array.length) {
-        do_throw("out of range in uint16Array");
-      }
-      return uint16Array[ix++];
-    }
-    let length = helper.readHexOctet();
-    let parsedAddr = helper.readAddress(length);
-    do_check_eq(parsedAddr, addrString);
-  }
-
-  // For AlphaNumeric
-  test_address("04D01100", "_@");
-  test_address("04D01000", "\u0394@");
-
-  // Direct prepand
-  test_address("0B914151245584F6", "+14154255486");
-  test_address("0E914151245584B633", "+14154255486#33");
-
-  // PDU_TOA_NATIONAL
-  test_address("0BA14151245584F6", "14154255486");
-
-  run_next_test();
-});
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_sms_gsmpduhelper.js
@@ -0,0 +1,233 @@
+/* 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 GsmPDUHelper#readDataCodingScheme.
+ */
+add_test(function test_GsmPDUHelper_readDataCodingScheme() {
+  let worker = newWorker({
+    postRILMessage: function fakePostRILMessage(data) {
+      // Do nothing
+    },
+    postMessage: function fakePostMessage(message) {
+      // Do nothing
+    }
+  });
+
+  let helper = worker.GsmPDUHelper;
+  function test_dcs(dcs, encoding, messageClass, mwi) {
+    helper.readHexOctet = function () {
+      return dcs;
+    }
+
+    let msg = {};
+    helper.readDataCodingScheme(msg);
+
+    do_check_eq(msg.dcs, dcs);
+    do_check_eq(msg.encoding, encoding);
+    do_check_eq(msg.messageClass, messageClass);
+    do_check_eq(msg.mwi == null, mwi == null);
+    if (mwi != null) {
+      do_check_eq(msg.mwi.active, mwi.active);
+      do_check_eq(msg.mwi.discard, mwi.discard);
+      do_check_eq(msg.mwi.msgCount, mwi.msgCount);
+    }
+  }
+
+  // Group 00xx
+  //   Bit 3 and 2 indicate the character set being used.
+  test_dcs(0x00, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
+  test_dcs(0x04, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
+  test_dcs(0x08, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
+  test_dcs(0x0C, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
+  //   Bit 4, if set to 0, indicates that bits 1 to 0 are reserved and have no
+  //   message class meaning.
+  test_dcs(0x01, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
+  test_dcs(0x02, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
+  test_dcs(0x03, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
+  //   Bit 4, if set to 1, indicates that bits 1 to 0 have a message class meaning.
+  test_dcs(0x10, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
+  test_dcs(0x11, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]);
+  test_dcs(0x12, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]);
+  test_dcs(0x13, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]);
+
+  // Group 01xx
+  test_dcs(0x50, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
+
+  // Group 1000..1011: reserved
+  test_dcs(0x8F, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
+  test_dcs(0x9F, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
+  test_dcs(0xAF, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
+  test_dcs(0xBF, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]);
+
+  // Group 1100: Message Waiting Indication Group: Discard Message
+  //   Bit 3 indicates Indication Sense:
+  test_dcs(0xC0, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
+           {active: false, discard: true, msgCount: 0});
+  test_dcs(0xC8, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
+           {active: true, discard: true, msgCount: -1});
+  //   Bit 2 is reserved, and set to 0:
+  test_dcs(0xCC, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
+           {active: true, discard: true, msgCount: -1});
+
+  // Group 1101: Message Waiting Indication Group: Store Message
+  //   Bit 3 indicates Indication Sense:
+  test_dcs(0xD0, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
+           {active: false, discard: false, msgCount: 0});
+  test_dcs(0xD8, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
+           {active: true, discard: false, msgCount: -1});
+  //   Bit 2 is reserved, and set to 0:
+  test_dcs(0xDC, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
+           {active: true, discard: false, msgCount: -1});
+
+  // Group 1110: Message Waiting Indication Group: Store Message, UCS2
+  //   Bit 3 indicates Indication Sense:
+  test_dcs(0xE0, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
+           {active: false, discard: false, msgCount: 0});
+  test_dcs(0xE8, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
+           {active: true, discard: false, msgCount: -1});
+  //   Bit 2 is reserved, and set to 0:
+  test_dcs(0xEC, PDU_DCS_MSG_CODING_16BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
+           {active: true, discard: false, msgCount: -1});
+
+  // Group 1111
+  test_dcs(0xF0, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
+  test_dcs(0xF1, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]);
+  test_dcs(0xF2, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]);
+  test_dcs(0xF3, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]);
+  test_dcs(0xF4, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
+  test_dcs(0xF5, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]);
+  test_dcs(0xF6, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]);
+  test_dcs(0xF7, PDU_DCS_MSG_CODING_8BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]);
+  //   Bit 3 is reserved and should be set to 0, but if it doesn't we should
+  //   ignore it.
+  test_dcs(0xF8, PDU_DCS_MSG_CODING_7BITS_ALPHABET,
+           GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]);
+
+  run_next_test();
+});
+
+/**
+ * Verify GsmPDUHelper#writeStringAsSeptets() padding bits handling.
+ */
+add_test(function test_GsmPDUHelper_writeStringAsSeptets() {
+  let worker = newWorker({
+    postRILMessage: function fakePostRILMessage(data) {
+      // Do nothing
+    },
+    postMessage: function fakePostMessage(message) {
+      // Do nothing
+    }
+  });
+
+  let helper = worker.GsmPDUHelper;
+  helper.resetOctetWritten = function () {
+    helper.octetsWritten = 0;
+  };
+  helper.writeHexOctet = function () {
+    helper.octetsWritten++;
+  };
+
+  let base = "AAAAAAAA"; // Base string of 8 characters long
+  for (let len = 0; len < 8; len++) {
+    let str = base.substring(0, len);
+
+    for (let paddingBits = 0; paddingBits < 8; paddingBits++) {
+      do_print("Verifying GsmPDUHelper.writeStringAsSeptets("
+               + str + ", " + paddingBits + ", <default>, <default>)");
+      helper.resetOctetWritten();
+      helper.writeStringAsSeptets(str, paddingBits, PDU_NL_IDENTIFIER_DEFAULT,
+                                  PDU_NL_IDENTIFIER_DEFAULT);
+      do_check_eq(Math.ceil(((len * 7) + paddingBits) / 8),
+                  helper.octetsWritten);
+    }
+  }
+
+  run_next_test();
+});
+
+/**
+ * Verify GsmPDUHelper#readAddress
+ */
+add_test(function test_GsmPDUHelper_readAddress() {
+  let worker = newWorker({
+    postRILMessage: function fakePostRILMessage(data) {
+      // Do nothing
+    },
+    postMessage: function fakePostMessage(message) {
+      // Do nothing
+    }
+
+  });
+
+  let helper = worker.GsmPDUHelper;
+  function test_address(addrHex, addrString) {
+    let uint16Array = [];
+    let ix = 0;
+    for (let i = 0; i < addrHex.length; ++i) {
+      uint16Array[i] = addrHex[i].charCodeAt();
+    }
+
+    worker.Buf.readUint16 = function (){
+      if(ix >= uint16Array.length) {
+        do_throw("out of range in uint16Array");
+      }
+      return uint16Array[ix++];
+    }
+    let length = helper.readHexOctet();
+    let parsedAddr = helper.readAddress(length);
+    do_check_eq(parsedAddr, addrString);
+  }
+
+  // For AlphaNumeric
+  test_address("04D01100", "_@");
+  test_address("04D01000", "\u0394@");
+
+  // Direct prepand
+  test_address("0B914151245584F6", "+14154255486");
+  test_address("0E914151245584B633", "+14154255486#33");
+
+  // PDU_TOA_NATIONAL
+  test_address("0BA14151245584F6", "14154255486");
+
+  run_next_test();
+});
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_sms_nl_tables.js
@@ -0,0 +1,77 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+const ESCAPE = "\uffff";
+const RESCTL = "\ufffe";
+const LF = "\n";
+const CR = "\r";
+const SP = " ";
+const FF = "\u000c";
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Verify validity of the national language tables
+ */
+add_test(function test_nl_locking_shift_tables_validity() {
+  for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) {
+    do_print("Verifying PDU_NL_LOCKING_SHIFT_TABLES[" + lst + "]");
+
+    let table = PDU_NL_LOCKING_SHIFT_TABLES[lst];
+
+    // Make sure table length is 128, or it will break table lookup algorithm.
+    do_check_eq(table.length, 128);
+
+    // Make sure special values are preserved.
+    do_check_eq(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE);
+    do_check_eq(table[PDU_NL_LINE_FEED], LF);
+    do_check_eq(table[PDU_NL_CARRIAGE_RETURN], CR);
+    do_check_eq(table[PDU_NL_SPACE], SP);
+  }
+
+  run_next_test();
+});
+
+add_test(function test_nl_single_shift_tables_validity() {
+  for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) {
+    do_print("Verifying PDU_NL_SINGLE_SHIFT_TABLES[" + sst + "]");
+
+    let table = PDU_NL_SINGLE_SHIFT_TABLES[sst];
+
+    // Make sure table length is 128, or it will break table lookup algorithm.
+    do_check_eq(table.length, 128);
+
+    // Make sure special values are preserved.
+    do_check_eq(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE);
+    do_check_eq(table[PDU_NL_PAGE_BREAK], FF);
+    do_check_eq(table[PDU_NL_RESERVED_CONTROL], RESCTL);
+  }
+
+  run_next_test();
+});
+
+add_test(function test_gsm_sms_strict_7bit_charmap_validity() {
+  let defaultTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+  let defaultShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+  for (let from in GSM_SMS_STRICT_7BIT_CHARMAP) {
+    let to = GSM_SMS_STRICT_7BIT_CHARMAP[from];
+    do_print("Verifying GSM_SMS_STRICT_7BIT_CHARMAP[\"\\u0x"
+             + from.charCodeAt(0).toString(16) + "\"] => \"\\u"
+             + to.charCodeAt(0).toString(16) + "\"");
+
+    // Make sure "from" is not in default table
+    do_check_eq(defaultTable.indexOf(from), -1);
+    do_check_eq(defaultShiftTable.indexOf(from), -1);
+    // Make sure "to" is in default table
+    if ((defaultTable.indexOf(to) < 0)
+        && (defaultShiftTable.indexOf(to) < 0)) {
+      do_check_eq(false, true);
+    }
+  }
+
+  run_next_test();
+});
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_sms_segment_info.js
@@ -0,0 +1,284 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+const ESCAPE = "\uffff";
+const RESCTL = "\ufffe";
+const SP = " ";
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Verify RadioInterface#_countGsm7BitSeptets() and
+ * GsmPDUHelper#writeStringAsSeptets() algorithm match each other.
+ */
+add_test(function test_RadioInterface__countGsm7BitSeptets() {
+  let ril = newRadioInterface();
+
+  let worker = newWorker({
+    postRILMessage: function fakePostRILMessage(data) {
+      // Do nothing
+    },
+    postMessage: function fakePostMessage(message) {
+      // Do nothing
+    }
+  });
+
+  let helper = worker.GsmPDUHelper;
+  helper.resetOctetWritten = function () {
+    helper.octetsWritten = 0;
+  };
+  helper.writeHexOctet = function () {
+    helper.octetsWritten++;
+  };
+
+  function do_check_calc(str, expectedCalcLen, lst, sst, strict7BitEncoding, strToWrite) {
+    do_check_eq(expectedCalcLen,
+                ril._countGsm7BitSeptets(str,
+                                         PDU_NL_LOCKING_SHIFT_TABLES[lst],
+                                         PDU_NL_SINGLE_SHIFT_TABLES[sst],
+                                         strict7BitEncoding));
+
+    helper.resetOctetWritten();
+    strToWrite = strToWrite || str;
+    helper.writeStringAsSeptets(strToWrite, 0, lst, sst);
+    do_check_eq(Math.ceil(expectedCalcLen * 7 / 8), helper.octetsWritten);
+  }
+
+  // Test calculation encoded message length using both locking/single shift tables.
+  for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) {
+    let langTable = PDU_NL_LOCKING_SHIFT_TABLES[lst];
+
+    let str = langTable.substring(0, PDU_NL_EXTENDED_ESCAPE)
+              + langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1);
+
+    for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) {
+      let langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[sst];
+
+      // <escape>, <resctrl> should be ignored.
+      do_check_calc(ESCAPE + RESCTL, 0, lst, sst);
+
+      // Characters defined in locking shift table should be encoded directly.
+      do_check_calc(str, str.length, lst, sst);
+
+      let [str1, str2] = ["", ""];
+      for (let i = 0; i < langShiftTable.length; i++) {
+        if ((i == PDU_NL_EXTENDED_ESCAPE) || (i == PDU_NL_RESERVED_CONTROL)) {
+          continue;
+        }
+
+        let c = langShiftTable[i];
+        if (langTable.indexOf(c) >= 0) {
+          str1 += c;
+        } else {
+          str2 += c;
+        }
+      }
+
+      // Characters found in both locking/single shift tables should be
+      // directly encoded.
+      do_check_calc(str1, str1.length, lst, sst);
+
+      // Characters found only in single shift tables should be encoded as
+      // <escape><code>, therefore doubles its original length.
+      do_check_calc(str2, str2.length * 2, lst, sst);
+    }
+  }
+
+  // Bug 790192: support strict GSM SMS 7-Bit encoding
+  let str = "", strToWrite = "", gsmLen = 0;
+  for (let c in GSM_SMS_STRICT_7BIT_CHARMAP) {
+    str += c;
+    strToWrite += GSM_SMS_STRICT_7BIT_CHARMAP[c];
+    if (PDU_NL_LOCKING_SHIFT_TABLES.indexOf(GSM_SMS_STRICT_7BIT_CHARMAP[c])) {
+      gsmLen += 1;
+    } else {
+      gsmLen += 2;
+    }
+  }
+  do_check_calc(str, gsmLen,
+                PDU_NL_IDENTIFIER_DEFAULT, PDU_NL_IDENTIFIER_DEFAULT,
+                true, strToWrite);
+
+  run_next_test();
+});
+
+/**
+ * Verify RadioInterface#calculateUserDataLength handles national language
+ * selection correctly.
+ */
+add_test(function test_RadioInterface__calculateUserDataLength() {
+  let ril = newRadioInterface();
+
+  function test_calc(str, expected, enabledGsmTableTuples, strict7BitEncoding) {
+    ril.enabledGsmTableTuples = enabledGsmTableTuples;
+    let options = ril._calculateUserDataLength(str, strict7BitEncoding);
+
+    do_check_eq(expected[0], options.dcs);
+    do_check_eq(expected[1], options.encodedFullBodyLength);
+    do_check_eq(expected[2], options.userDataHeaderLength);
+    do_check_eq(expected[3], options.langIndex);
+    do_check_eq(expected[4], options.langShiftIndex);
+  }
+
+  // Test UCS fallback
+  // - No any default enabled nl tables
+  test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0,], []);
+  // - Character not defined in enabled nl tables
+  test_calc("A", [PDU_DCS_MSG_CODING_16BITS_ALPHABET, 2, 0,], [[2, 2]]);
+
+  // With GSM default nl tables
+  test_calc("A", [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 0, 0, 0], [[0, 0]]);
+  // - SP is defined in both locking/single shift tables, should be directly
+  //   encoded.
+  test_calc(SP, [PDU_DCS_MSG_CODING_7BITS_ALPHABET, 1, 0, 0, 0], [[0, 0]]);
+  // - '^' is only defined in single shift table, should be encoded as
+  //   <escape>^.
+  test_c