Merge m-c to b2g-i
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 14 Apr 2014 15:56:31 +0200
changeset 196839 0e7892f55d6ff873d86105e1d4bcd6aa9861805f
parent 196838 f3e37dbf95374aecf3811cec82d19c7e61194a25 (current diff)
parent 196835 265d82091bce0ab6aa4ac23a3850fe8c05310f42 (diff)
child 196840 62695c859513e5530940c2323e997b9ca640f113
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to b2g-i
accessible/tests/mochitest/events/test_name.xul
browser/components/customizableui/test/browser_989609_bootstrapped_custom_toolbar.js
content/mathml/content/crashtests/462929-1.html
content/mathml/content/crashtests/770710-1.html
content/mathml/content/crashtests/crashtests.list
content/mathml/content/src/moz.build
content/mathml/content/src/nsMathMLElement.cpp
content/mathml/content/src/nsMathMLElement.h
content/mathml/content/src/nsMathMLElementFactory.cpp
content/xml/content/crashtest/420429.xul
content/xml/content/crashtest/453278-frame.xml
content/xml/content/crashtest/453278.html
content/xml/content/crashtest/803586.xhtml
content/xml/content/crashtest/crashtests.list
content/xml/content/src/CDATASection.cpp
content/xml/content/src/CDATASection.h
content/xml/content/src/ProcessingInstruction.cpp
content/xml/content/src/ProcessingInstruction.h
content/xml/content/src/XMLStylesheetProcessingInstruction.cpp
content/xml/content/src/XMLStylesheetProcessingInstruction.h
content/xml/content/src/htmlmathml-f.ent
content/xml/content/src/moz.build
content/xml/content/src/nsXMLElement.cpp
content/xml/content/src/nsXMLElement.h
content/xml/document/crashtests/136896-1.xml
content/xml/document/crashtests/185285-1.xml
content/xml/document/crashtests/382636-1.xml
content/xml/document/crashtests/382636-2.svg
content/xml/document/crashtests/382636-3.xhtml
content/xml/document/crashtests/382636-4.xul
content/xml/document/crashtests/431703-1.xhtml
content/xml/document/crashtests/crashtests.list
content/xml/document/crashtests/tree.gif
content/xml/document/moz.build
content/xml/document/public/moz.build
content/xml/document/public/nsIXMLContentSink.h
content/xml/document/resources/XMLMonoPrint.css
content/xml/document/resources/XMLPrettyPrint.css
content/xml/document/resources/XMLPrettyPrint.xml
content/xml/document/resources/XMLPrettyPrint.xsl
content/xml/document/resources/jar.mn
content/xml/document/resources/moz.build
content/xml/document/src/XMLDocument.cpp
content/xml/document/src/XMLDocument.h
content/xml/document/src/moz.build
content/xml/document/src/nsXMLContentSink.cpp
content/xml/document/src/nsXMLContentSink.h
content/xml/document/src/nsXMLFragmentContentSink.cpp
content/xml/document/src/nsXMLPrettyPrinter.cpp
content/xml/document/src/nsXMLPrettyPrinter.h
content/xml/document/test/file_bug293347.xml
content/xml/document/test/file_bug293347xslt.xml
content/xml/document/test/mochitest.ini
content/xml/document/test/moz.build
content/xml/document/test/test_bug232004.xhtml
content/xml/document/test/test_bug293347.html
content/xml/document/test/test_bug343870.xhtml
content/xml/document/test/test_bug355213.xhtml
content/xml/document/test/test_bug392338.html
content/xml/document/test/test_bug399502.xhtml
content/xml/document/test/test_bug445330.html
content/xml/document/test/test_bug691215.html
content/xml/document/test/test_viewport.xhtml
content/xml/moz.build
content/xml/tests/books/bethlehem.gif
content/xml/tests/books/bill.gif
content/xml/tests/books/books.js
content/xml/tests/books/books.xml
content/xml/tests/books/charing.gif
content/xml/tests/books/classic.css
content/xml/tests/books/common.css
content/xml/tests/books/kerouac.gif
content/xml/tests/books/list.css
content/xml/tests/books/road.gif
content/xml/tests/books/welville.gif
content/xml/tests/docbook.css
content/xml/tests/docbooktest.xml
content/xml/tests/flamer.gif
content/xml/tests/load/display.css
content/xml/tests/load/display.xml
content/xml/tests/load/load.html
content/xml/tests/load/loadauth.html
content/xml/tests/load/loaddisplay.html
content/xml/tests/load/test.xml
content/xml/tests/script.xml
content/xml/tests/simple.xml
content/xml/tests/toc/book.css
content/xml/tests/toc/irslogo.gif
content/xml/tests/toc/minus.gif
content/xml/tests/toc/plus.gif
content/xml/tests/toc/rights.xml
content/xml/tests/toc/toc.css
content/xml/tests/toc/toc.js
content/xml/tests/xlink/auto.xml
content/xml/tests/xlink/link.css
content/xml/tests/xlink/manual.xml
content/xml/tests/xmlbase/xmlbase.css
content/xml/tests/xmlbase/xmlbase.xml
dom/interfaces/apps/nsIDOMMozApplicationEvent.idl
dom/interfaces/html/nsIDOMHTMLByteRanges.idl
dom/interfaces/storage/nsIDOMToString.idl
python/virtualenv/docs/_theme/nature/static/nature.css_t
python/virtualenv/docs/_theme/nature/static/pygments.css
python/virtualenv/docs/_theme/nature/theme.conf
python/virtualenv/virtualenv_support/pip-1.4.1.tar.gz
python/virtualenv/virtualenv_support/setuptools-0.9.8.tar.gz
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -965,40 +965,72 @@ DocAccessible::AttributeChangedImpl(Acce
   if (aNameSpaceID == kNameSpaceID_None) {
     // Check for hyphenated aria-foo property?
     if (StringBeginsWith(nsDependentAtomString(aAttribute),
                          NS_LITERAL_STRING("aria-"))) {
       ARIAAttributeChanged(aAccessible, aAttribute);
     }
   }
 
-  if (aAttribute == nsGkAtoms::alt ||
-      aAttribute == nsGkAtoms::title ||
-      aAttribute == nsGkAtoms::aria_label ||
-      aAttribute == nsGkAtoms::aria_labelledby) {
+  // Fire name change and description change events. XXX: it's not complete and
+  // dupes the code logic of accessible name and description calculation, we do
+  // that for performance reasons.
+  if (aAttribute == nsGkAtoms::aria_label) {
+    FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, aAccessible);
+    return;
+  }
+
+  if (aAttribute == nsGkAtoms::aria_describedby) {
+    FireDelayedEvent(nsIAccessibleEvent::EVENT_DESCRIPTION_CHANGE, aAccessible);
+    return;
+  }
+
+  nsIContent* elm = aAccessible->GetContent();
+  if (aAttribute == nsGkAtoms::aria_labelledby &&
+      !elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_label)) {
     FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, aAccessible);
     return;
   }
 
+  if (aAttribute == nsGkAtoms::alt &&
+      !elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_label) &&
+      !elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_labelledby)) {
+    FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, aAccessible);
+    return;
+  }
+
+  if (aAttribute == nsGkAtoms::title) {
+    if (!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_label) &&
+        !elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_labelledby) &&
+        !elm->HasAttr(kNameSpaceID_None, nsGkAtoms::alt)) {
+      FireDelayedEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, aAccessible);
+      return;
+    }
+
+    if (!elm->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_describedby))
+      FireDelayedEvent(nsIAccessibleEvent::EVENT_DESCRIPTION_CHANGE, aAccessible);
+
+    return;
+  }
+
   if (aAttribute == nsGkAtoms::aria_busy) {
-    bool isOn = aAccessible->GetContent()->
-      AttrValueIs(aNameSpaceID, aAttribute, nsGkAtoms::_true, eCaseMatters);
+    bool isOn = elm->AttrValueIs(aNameSpaceID, aAttribute, nsGkAtoms::_true,
+                                 eCaseMatters);
     nsRefPtr<AccEvent> event =
       new AccStateChangeEvent(aAccessible, states::BUSY, isOn);
     FireDelayedEvent(event);
     return;
   }
 
   // ARIA or XUL selection
   if ((aAccessible->GetContent()->IsXUL() && aAttribute == nsGkAtoms::selected) ||
       aAttribute == nsGkAtoms::aria_selected) {
     Accessible* widget =
       nsAccUtils::GetSelectableContainer(aAccessible, aAccessible->State());
     if (widget) {
-      nsIContent* elm = aAccessible->GetContent();
       AccSelChangeEvent::SelChangeType selChangeType =
         elm->AttrValueIs(aNameSpaceID, aAttribute, nsGkAtoms::_true, eCaseMatters) ?
           AccSelChangeEvent::eSelectionAdd : AccSelChangeEvent::eSelectionRemove;
 
       nsRefPtr<AccEvent> event =
         new AccSelChangeEvent(widget, aAccessible, selChangeType);
       FireDelayedEvent(event);
     }
--- a/accessible/tests/mochitest/events.js
+++ b/accessible/tests/mochitest/events.js
@@ -1,12 +1,13 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Constants
 
 const EVENT_ALERT = nsIAccessibleEvent.EVENT_ALERT;
+const EVENT_DESCRIPTION_CHANGE = nsIAccessibleEvent.EVENT_DESCRIPTION_CHANGE;
 const EVENT_DOCUMENT_LOAD_COMPLETE = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
 const EVENT_DOCUMENT_RELOAD = nsIAccessibleEvent.EVENT_DOCUMENT_RELOAD;
 const EVENT_DOCUMENT_LOAD_STOPPED = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_STOPPED;
 const EVENT_HIDE = nsIAccessibleEvent.EVENT_HIDE;
 const EVENT_FOCUS = nsIAccessibleEvent.EVENT_FOCUS;
 const EVENT_NAME_CHANGE = nsIAccessibleEvent.EVENT_NAME_CHANGE;
 const EVENT_MENU_START = nsIAccessibleEvent.EVENT_MENU_START;
 const EVENT_MENU_END = nsIAccessibleEvent.EVENT_MENU_END;
--- a/accessible/tests/mochitest/events/a11y.ini
+++ b/accessible/tests/mochitest/events/a11y.ini
@@ -8,16 +8,17 @@ support-files =
 [test_aria_menu.html]
 [test_aria_objattr.html]
 [test_aria_statechange.html]
 [test_attrs.html]
 [test_caretmove.html]
 [test_caretmove.xul]
 [test_coalescence.html]
 [test_contextmenu.html]
+[test_descrchange.html]
 [test_docload.html]
 [test_docload.xul]
 [test_docload_aria.html]
 [test_dragndrop.html]
 [test_flush.html]
 [test_focus_aria_activedescendant.html]
 [test_focus_autocomplete.xul]
 # Disabled on Linux and Windows due to frequent failures - bug 695019, bug 890795
@@ -36,17 +37,18 @@ skip-if = os == 'win' || os == 'linux'
 [test_focus_selects.html]
 [test_focus_tabbox.xul]
 [test_focus_tree.xul]
 [test_fromUserInput.html]
 [test_label.xul]
 [test_menu.xul]
 [test_mutation.html]
 [test_mutation.xhtml]
-[test_name.xul]
+[test_namechange.xul]
+[test_namechange.html]
 [test_scroll.xul]
 [test_selection.html]
 [test_selection.xul]
 [test_selection_aria.html]
 [test_statechange.html]
 [test_text.html]
 [test_text_alg.html]
 [test_textattrchange.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/events/test_descrchange.html
@@ -0,0 +1,85 @@
+<html>
+
+<head>
+  <title>Accessible description change event testing</title>
+
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../states.js"></script>
+
+  <script type="application/javascript">
+    ////////////////////////////////////////////////////////////////////////////
+    // Invokers
+
+    function setAttr(aID, aAttr, aValue, aChecker)
+    {
+      this.eventSeq = [ aChecker ];
+      this.invoke = function setAttr_invoke()
+      {
+        getNode(aID).setAttribute(aAttr, aValue);
+      }
+
+      this.getID = function setAttr_getID()
+      {
+        return "set attr '" + aAttr + "', value '" + aValue + "'";
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Do tests
+
+    //gA11yEventDumpToConsole = true; // debuggin
+
+    var gQueue = null;
+    function doTests()
+    {
+      gQueue = new eventQueue();
+
+      gQueue.push(new setAttr("tst1", "aria-describedby", "display",
+                              new invokerChecker(EVENT_DESCRIPTION_CHANGE, "tst1")));
+      gQueue.push(new setAttr("tst1", "title", "title",
+                              new unexpectedInvokerChecker(EVENT_DESCRIPTION_CHANGE, "tst1")));
+
+      gQueue.push(new setAttr("tst2", "title", "title",
+                              new invokerChecker(EVENT_NAME_CHANGE, "tst2")));
+
+      gQueue.invoke(); // Will call SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTests);
+  </script>
+</head>
+
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=991969"
+     title="Event not fired when description changes">
+    Bug 991969
+  </a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <button id="tst1">btn1</button>
+  <button id="tst2">btn2</button>
+
+  <div id="eventdump"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/events/test_namechange.html
@@ -0,0 +1,103 @@
+<html>
+
+<head>
+  <title>Accessible name change event testing</title>
+
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../states.js"></script>
+
+  <script type="application/javascript">
+    ////////////////////////////////////////////////////////////////////////////
+    // Invokers
+
+    function setAttr(aID, aAttr, aValue, aChecker)
+    {
+      this.eventSeq = [ aChecker ];
+      this.invoke = function setAttr_invoke()
+      {
+        getNode(aID).setAttribute(aAttr, aValue);
+      }
+
+      this.getID = function setAttr_getID()
+      {
+        return "set attr '" + aAttr + "', value '" + aValue + "'";
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Do tests
+
+    //gA11yEventDumpToConsole = true; // debuggin
+
+    var gQueue = null;
+    function doTests()
+    {
+      gQueue = new eventQueue();
+
+      gQueue.push(new setAttr("tst1", "aria-label", "hi",
+                              new invokerChecker(EVENT_NAME_CHANGE, "tst1")));
+      gQueue.push(new setAttr("tst1", "aria-labelledby", "display",
+                              new unexpectedInvokerChecker(EVENT_NAME_CHANGE, "tst1")));
+      gQueue.push(new setAttr("tst1", "alt", "alt",
+                              new unexpectedInvokerChecker(EVENT_NAME_CHANGE, "tst1")));
+      gQueue.push(new setAttr("tst1", "title", "title",
+                              new unexpectedInvokerChecker(EVENT_NAME_CHANGE, "tst1")));
+
+      gQueue.push(new setAttr("tst2", "aria-labelledby", "display",
+                              new invokerChecker(EVENT_NAME_CHANGE, "tst2")));
+      gQueue.push(new setAttr("tst2", "alt", "alt",
+                              new unexpectedInvokerChecker(EVENT_NAME_CHANGE, "tst2")));
+      gQueue.push(new setAttr("tst2", "title", "title",
+                              new unexpectedInvokerChecker(EVENT_NAME_CHANGE, "tst2")));
+
+      gQueue.push(new setAttr("tst3", "alt", "alt",
+                              new invokerChecker(EVENT_NAME_CHANGE, "tst3")));
+      gQueue.push(new setAttr("tst3", "title", "title",
+                              new unexpectedInvokerChecker(EVENT_NAME_CHANGE, "tst3")));
+
+      gQueue.push(new setAttr("tst4", "title", "title",
+                              new invokerChecker(EVENT_NAME_CHANGE, "tst4")));
+
+      gQueue.invoke(); // Will call SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTests);
+  </script>
+</head>
+
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=991969"
+     title="Event not fired when description changes">
+    Bug 991969
+  </a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <img id="tst1">
+  <img id="tst2">
+  <img id="tst3">
+  <img id="tst4">
+
+  <div id="eventdump"></div>
+</body>
+</html>
rename from accessible/tests/mochitest/events/test_name.xul
rename to accessible/tests/mochitest/events/test_namechange.xul
--- a/browser/components/customizableui/src/CustomizableUI.jsm
+++ b/browser/components/customizableui/src/CustomizableUI.jsm
@@ -333,17 +333,17 @@ let CustomizableUIInternal = {
     // Sanity check default placements array:
     if (!Array.isArray(props.get("defaultPlacements"))) {
       throw new Error("Should provide an array of default placements");
     }
 
     if (!areaIsKnown) {
       gAreas.set(aName, props);
 
-      if (props.get("legacy")) {
+      if (props.get("legacy") && !gPlacements.has(aName)) {
         // Guarantee this area exists in gFuturePlacements, to avoid checking it in
         // various places elsewhere.
         gFuturePlacements.set(aName, new Set());
       } else {
         this.restoreStateForArea(aName);
       }
 
       // If we have pending build area nodes, register all of them
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -94,15 +94,15 @@ skip-if = os == "linux"
 [browser_980155_add_overflow_toolbar.js]
 [browser_981418-widget-onbeforecreated-handler.js]
 
 [browser_984455_bookmarks_items_reparenting.js]
 skip-if = os == "linux"
 
 [browser_985815_propagate_setToolbarVisibility.js]
 [browser_981305_separator_insertion.js]
-[browser_989609_bootstrapped_custom_toolbar.js]
 [browser_987177_destroyWidget_xul.js]
 [browser_987177_xul_wrapper_updating.js]
 [browser_987492_window_api.js]
 [browser_992747_toggle_noncustomizable_toolbar.js]
 [browser_993322_widget_notoolbar.js]
+[browser_bootstrapped_custom_toolbar.js]
 [browser_panel_toggle.js]
rename from browser/components/customizableui/test/browser_989609_bootstrapped_custom_toolbar.js
rename to browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js
--- a/browser/components/customizableui/test/browser_989609_bootstrapped_custom_toolbar.js
+++ b/browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js
@@ -2,74 +2,78 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const kTestBarID = "testBar";
 const kWidgetID = "characterencoding-button";
 
-function createTestBar() {
+function createTestBar(aLegacy) {
   let testBar = document.createElement("toolbar");
   testBar.id = kTestBarID;
   testBar.setAttribute("customizable", "true");
-  CustomizableUI.registerArea(kTestBarID,
-    { type: CustomizableUI.TYPE_TOOLBAR, legacy: false }
-  );
+  CustomizableUI.registerArea(kTestBarID, {
+    type: CustomizableUI.TYPE_TOOLBAR,
+    legacy: aLegacy,
+  });
   gNavToolbox.appendChild(testBar);
   return testBar;
 }
 
 /**
  * Helper function that does the following:
  *
  * 1) Creates a custom toolbar and registers it
- *    with CustomizableUI.
+ *    with CustomizableUI. Sets the legacy attribute
+ *    of the object passed to registerArea to aLegacy.
  * 2) Adds the widget with ID aWidgetID to that new
  *    toolbar.
  * 3) Enters customize mode and makes sure that the
  *    widget is still in the right toolbar.
  * 4) Exits customize mode, then removes and deregisters
  *    the custom toolbar.
  * 5) Checks that the widget has no placement.
  * 6) Re-adds and re-registers a custom toolbar with the same
- *    ID as the first one.
+ *    ID and options as the first one.
  * 7) Enters customize mode and checks that the widget is
  *    properly back in the toolbar.
  * 8) Exits customize mode, removes and de-registers the
  *    toolbar, and resets the toolbars to default.
  */
-function checkRestoredPresence(aWidgetID) {
+function checkRestoredPresence(aWidgetID, aLegacy) {
   return Task.spawn(function* () {
-    let testBar = createTestBar();
+    let testBar = createTestBar(aLegacy);
     CustomizableUI.addWidgetToArea(aWidgetID, kTestBarID);
     let placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
     is(placement.area, kTestBarID,
        "Expected " + aWidgetID + " to be in the test toolbar");
 
     CustomizableUI.unregisterArea(testBar.id);
     testBar.remove();
 
     let placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
     is(placement, null, "Expected " + aWidgetID + " to be in the palette");
 
-    testBar = createTestBar();
+    testBar = createTestBar(aLegacy);
 
     yield startCustomizing();
     let placement = CustomizableUI.getPlacementOfWidget(aWidgetID);
     is(placement.area, kTestBarID,
        "Expected " + aWidgetID + " to be in the test toolbar");
     yield endCustomizing();
 
     CustomizableUI.unregisterArea(testBar.id);
     testBar.remove();
 
     yield resetCustomization();
   });
 }
 
 add_task(function* () {
-  yield checkRestoredPresence("downloads-button")
+  yield checkRestoredPresence("downloads-button", false);
+  yield checkRestoredPresence("downloads-button", true);
 });
 
 add_task(function* () {
-  yield checkRestoredPresence("characterencoding-button")
-});
\ No newline at end of file
+  yield checkRestoredPresence("characterencoding-button", false);
+  yield checkRestoredPresence("characterencoding-button", true);
+});
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -139,16 +139,28 @@
   #toolbar-menubar:not(:-moz-lwtheme),
   #TabsToolbar:not(:-moz-lwtheme) {
     background-color: transparent !important;
     color: black;
     border-left-style: none !important;
     border-right-style: none !important;
   }
 
+  /* Use a different color only on Windows 8 and higher for inactive windows.
+   * On aero, the menubar fog disappears for inactive windows, and renders gray
+   * illegible.
+   */
+  @media not all and (-moz-os-version: windows-vista) {
+    @media not all and (-moz-os-version: windows-win7) {
+      #toolbar-menubar:not(:-moz-lwtheme):-moz-window-inactive {
+        color: ThreeDShadow;
+      }
+    }
+  }
+
   #main-window[darkwindowframe="true"] #toolbar-menubar:not(:-moz-lwtheme):not(:-moz-window-inactive),
   #main-window[darkwindowframe="true"] #TabsToolbar:not(:-moz-lwtheme):not(:-moz-window-inactive) {
     color: white;
   }
 
   #main-window[darkwindowframe="true"] :-moz-any(#toolbar-menubar, #TabsToolbar) :-moz-any(@primaryToolbarButtons@):not(:-moz-lwtheme):not(:-moz-window-inactive),
   #main-window[darkwindowframe="true"] :-moz-any(#toolbar-menubar, #TabsToolbar) #bookmarks-menu-button:not(:-moz-lwtheme) > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:not(:-moz-window-inactive) {
     list-style-image: url(chrome://browser/skin/Toolbar-inverted.png);
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -104,21 +104,33 @@
     -moz-binding: url("chrome://global/content/bindings/general.xml#windowdragbox");
     visibility: visible;
   }
 %ifdef WINDOWS_AERO
 }
 %endif
 
 /* Make the menu inherit the toolbar's color. On non-compositor (Aero Basic, XP modern, classic)
- * this is defined above. Otherwise (Aero Glass, Windows 8 inactive windows), this is hardcoded
- * to black in browser-aero.css. */
-#main-menubar > menu:not(:-moz-lwtheme) {
-  color: inherit;
-}
+ * this is defined above, but only for tabsintitlebar. Otherwise (Aero Glass, Windows 8),
+ * this is hardcoded to black in browser-aero.css, even without tabsintitlebar. */
+%ifdef WINDOWS_AERO
+@media not all and (-moz-windows-compositor) {
+%endif
+  #main-window[tabsintitlebar] #main-menubar > menu:not(:-moz-lwtheme) {
+    color: inherit;
+  }
+%ifdef WINDOWS_AERO
+}
+
+@media (-moz-windows-compositor) {
+  #main-menubar > menu:not(:-moz-lwtheme) {
+    color: inherit;
+  }
+}
+%endif
 
 /**
  * In the classic themes, the titlebar has a horizontal gradient, which is
  * problematic for reading the text of background tabs when they're in the
  * titlebar. We side-step this issue by layering our own background underneath
  * the tabs. Unfortunately, this requires a bunch of positioning in order to get
  * text and icons to not appear fuzzy.
  */
@@ -586,17 +598,16 @@ toolbar .toolbarbutton-1 > .toolbarbutto
   background: none;
 }
 
 #nav-bar .toolbarbutton-1:not([type=menu-button]),
 #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button,
 #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   padding: 8px 2px;
   -moz-box-pack: center;
-  -moz-box-align: stretch;
 }
 
 #nav-bar #PanelUI-menu-button {
   -moz-padding-start: 7px;
   -moz-padding-end: 5px;
 }
 
 #nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#social-provider-button):not(#PanelUI-menu-button) {
@@ -1046,16 +1057,26 @@ toolbarbutton[sdk-button="true"][cui-are
 #menu_tabview[groups="2"] {
   -moz-image-region: rect(1px, 53px, 17px, 37px);
 }
 
 #menu_tabview[groups="3"] {
   -moz-image-region: rect(1px, 71px, 17px, 55px);
 }
 
+/* zoom control text (reset) button special case: */
+
+#nav-bar #zoom-reset-button > .toolbarbutton-text {
+  /* To make this line up with the icons, it needs the same height (18px) +
+   * padding (2 * 2px) + border (2 * 1px), but as a minimum because otherwise
+   * increase in text sizes would break things...
+   */
+  min-height: 24px;
+}
+
 /* ::::: fullscreen window controls ::::: */
 
 #window-controls {
   -moz-margin-start: 4px;
 }
 
 #minimize-button,
 #restore-button,
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -107,32 +107,33 @@ class EventTarget;
 class FrameRequestCallback;
 class HTMLBodyElement;
 struct LifecycleCallbackArgs;
 class Link;
 class GlobalObject;
 class NodeFilter;
 class NodeIterator;
 class ProcessingInstruction;
+class StyleSheetList;
 class Touch;
 class TouchList;
 class TreeWalker;
 class UndoManager;
 class XPathEvaluator;
 template<typename> class OwningNonNull;
 template<typename> class Sequence;
 
 template<typename, typename> class CallbackObjectHolder;
 typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
 } // namespace dom
 } // namespace mozilla
 
 #define NS_IDOCUMENT_IID \
-{ 0xa7679e4a, 0xa5ec, 0x45bf, \
-  { 0x8f, 0xe4, 0xad, 0x4a, 0xb8, 0xc7, 0x7f, 0xc7 } }
+{ 0x906d05e7, 0x39af, 0x4ff0, \
+  { 0xbc, 0xcd, 0x30, 0x0c, 0x7f, 0xeb, 0x86, 0x21 } }
 
 // Flag for AddStyleSheet().
 #define NS_STYLESHEET_FROM_CATALOG                (1 << 0)
 
 // Enum for requesting a particular type of document when creating a doc
 enum DocumentFlavor {
   DocumentFlavorLegacyGuess, // compat with old code until made HTML5-compliant
   DocumentFlavorHTML, // HTMLDocument with HTMLness bit set to true
@@ -1330,16 +1331,23 @@ public:
   /**
    * @param aFireSync whether to fire onload synchronously.  If false,
    * onload will fire asynchronously after all onload blocks have been
    * removed.  It will NOT fire from inside UnblockOnload.  If true,
    * onload may fire from inside UnblockOnload.
    */
   virtual void UnblockOnload(bool aFireSync) = 0;
 
+  void BlockDOMContentLoaded()
+  {
+    ++mBlockDOMContentLoaded;
+  }
+
+  virtual void UnblockDOMContentLoaded() = 0;
+
   /**
    * Notification that the page has been shown, for documents which are loaded
    * into a DOM window.  This corresponds to the completion of document load,
    * or to the page's presentation being restored into an existing DOM window.
    * This notification fires applicable DOM events to the content window.  See
    * nsIDOMPageTransitionEvent.idl for a description of the |aPersisted|
    * parameter. If aDispatchStartTarget is null, the pageshow event is
    * dispatched on the ScriptGlobalObject for this document, otherwise it's
@@ -2164,17 +2172,17 @@ public:
   {
     return mVisibilityState;
   }
   mozilla::dom::VisibilityState MozVisibilityState()
   {
     WarnOnceAbout(ePrefixedVisibilityAPI);
     return VisibilityState();
   }
-  virtual nsIDOMStyleSheetList* StyleSheets() = 0;
+  virtual mozilla::dom::StyleSheetList* StyleSheets() = 0;
   void GetSelectedStyleSheetSet(nsAString& aSheetSet);
   virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) = 0;
   virtual void GetLastStyleSheetSet(nsString& aSheetSet) = 0;
   void GetPreferredStyleSheetSet(nsAString& aSheetSet);
   virtual mozilla::dom::DOMStringList* StyleSheetSets() = 0;
   virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) = 0;
   Element* ElementFromPoint(float aX, float aY);
 
@@ -2548,16 +2556,19 @@ protected:
   nsCOMPtr<nsIStructuredCloneContainer> mStateObjectContainer;
   nsCOMPtr<nsIVariant> mStateObjectCached;
 
   uint8_t mDefaultElementType;
 
   uint32_t mInSyncOperationCount;
 
   nsRefPtr<mozilla::dom::XPathEvaluator> mXPathEvaluator;
+
+  uint32_t mBlockDOMContentLoaded;
+  bool mDidFireDOMContentLoaded:1;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
 
 /**
  * mozAutoSubtreeModified batches DOM mutations so that a DOMSubtreeModified
  * event is dispatched, if necessary, when the outermost mozAutoSubtreeModified
  * object is deleted.
--- a/content/base/src/ShadowRoot.cpp
+++ b/content/base/src/ShadowRoot.cpp
@@ -479,17 +479,17 @@ ShadowRoot::SetApplyAuthorStyles(bool aA
   nsIPresShell* shell = OwnerDoc()->GetShell();
   if (shell) {
     OwnerDoc()->BeginUpdate(UPDATE_STYLE);
     shell->RestyleShadowRoot(this);
     OwnerDoc()->EndUpdate(UPDATE_STYLE);
   }
 }
 
-nsIDOMStyleSheetList*
+StyleSheetList*
 ShadowRoot::StyleSheets()
 {
   if (!mStyleSheetList) {
     mStyleSheetList = new ShadowRootStyleSheetList(this);
   }
 
   return mStyleSheetList;
 }
@@ -650,60 +650,56 @@ ShadowRoot::ContentRemoved(nsIDocument* 
 
   // Watch for node that is removed from the pool because
   // it may need to be removed from an insertion point.
   if (IsPooledNode(aChild, aContainer, mPoolHost)) {
     RemoveDistributedNode(aChild);
   }
 }
 
-NS_IMPL_CYCLE_COLLECTION_1(ShadowRootStyleSheetList, mShadowRoot)
+NS_IMPL_CYCLE_COLLECTION_INHERITED_1(ShadowRootStyleSheetList, StyleSheetList,
+                                     mShadowRoot)
 
-NS_INTERFACE_TABLE_HEAD(ShadowRootStyleSheetList)
-  NS_INTERFACE_TABLE1(ShadowRootStyleSheetList, nsIDOMStyleSheetList)
-  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(ShadowRootStyleSheetList)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StyleSheetList)
-NS_INTERFACE_MAP_END
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList)
+NS_INTERFACE_MAP_END_INHERITING(StyleSheetList)
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(ShadowRootStyleSheetList)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(ShadowRootStyleSheetList)
+NS_IMPL_ADDREF_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
+NS_IMPL_RELEASE_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
 
 ShadowRootStyleSheetList::ShadowRootStyleSheetList(ShadowRoot* aShadowRoot)
   : mShadowRoot(aShadowRoot)
 {
   MOZ_COUNT_CTOR(ShadowRootStyleSheetList);
 }
 
 ShadowRootStyleSheetList::~ShadowRootStyleSheetList()
 {
   MOZ_COUNT_DTOR(ShadowRootStyleSheetList);
 }
 
-NS_IMETHODIMP
-ShadowRootStyleSheetList::Item(uint32_t aIndex, nsIDOMStyleSheet** aReturn)
+nsCSSStyleSheet*
+ShadowRootStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
+{
+  nsTArray<nsRefPtr<nsCSSStyleSheet>>* sheets =
+    mShadowRoot->mProtoBinding->GetStyleSheets();
+
+  if (!sheets) {
+    aFound = false;
+    return nullptr;
+  }
+
+  aFound = aIndex < sheets->Length();
+  return sheets->SafeElementAt(aIndex);
+}
+
+uint32_t
+ShadowRootStyleSheetList::Length()
 {
   nsTArray<nsRefPtr<nsCSSStyleSheet> >* sheets =
     mShadowRoot->mProtoBinding->GetStyleSheets();
 
-  if (sheets) {
-    NS_IF_ADDREF(*aReturn = sheets->SafeElementAt(aIndex));
-  } else {
-    *aReturn = nullptr;
+  if (!sheets) {
+    return 0;
   }
 
-  return NS_OK;
+  return sheets->Length();
 }
 
-NS_IMETHODIMP
-ShadowRootStyleSheetList::GetLength(uint32_t* aLength)
-{
-  nsTArray<nsRefPtr<nsCSSStyleSheet> >* sheets =
-    mShadowRoot->mProtoBinding->GetStyleSheets();
-
-  if (sheets) {
-    *aLength = sheets->Length();
-  } else {
-    *aLength = 0;
-  }
-
-  return NS_OK;
-}
-
--- a/content/base/src/ShadowRoot.h
+++ b/content/base/src/ShadowRoot.h
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_shadowroot_h__
 #define mozilla_dom_shadowroot_h__
 
 #include "mozilla/dom/DocumentFragment.h"
+#include "mozilla/dom/StyleSheetList.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsTHashtable.h"
 #include "nsDocument.h"
 
 class nsIAtom;
 class nsIContent;
 class nsIDocument;
@@ -47,17 +48,17 @@ public:
   virtual ~ShadowRoot();
 
   void AddToIdTable(Element* aElement, nsIAtom* aId);
   void RemoveFromIdTable(Element* aElement, nsIAtom* aId);
   void InsertSheet(nsCSSStyleSheet* aSheet, nsIContent* aLinkingContent);
   void RemoveSheet(nsCSSStyleSheet* aSheet);
   bool ApplyAuthorStyles();
   void SetApplyAuthorStyles(bool aApplyAuthorStyles);
-  nsIDOMStyleSheetList* StyleSheets();
+  StyleSheetList* StyleSheets();
   HTMLShadowElement* GetShadowElement() { return mShadowElement; }
 
   /**
    * Sets the current shadow insertion point where the older
    * ShadowRoot will be projected.
    */
   void SetShadowElement(HTMLShadowElement* aShadowElement);
 
@@ -164,27 +165,32 @@ protected:
 
   // A boolean that indicates that an insertion point was added or removed
   // from this ShadowRoot and that the nodes need to be redistributed into
   // the insertion points. After this flag is set, nodes will be distributed
   // on the next mutation event.
   bool mInsertionPointChanged;
 };
 
-class ShadowRootStyleSheetList : public nsIDOMStyleSheetList
+class ShadowRootStyleSheetList : public StyleSheetList
 {
 public:
   ShadowRootStyleSheetList(ShadowRoot* aShadowRoot);
   virtual ~ShadowRootStyleSheetList();
 
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS(ShadowRootStyleSheetList)
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
 
-  // nsIDOMStyleSheetList
-  NS_DECL_NSIDOMSTYLESHEETLIST
+  virtual nsINode* GetParentObject() const MOZ_OVERRIDE
+  {
+    return mShadowRoot;
+  }
+
+  virtual uint32_t Length() MOZ_OVERRIDE;
+  virtual nsCSSStyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) MOZ_OVERRIDE;
 
 protected:
   nsRefPtr<ShadowRoot> mShadowRoot;
 };
 
 } // namespace dom
 } // namespace mozilla
 
new file mode 100644
--- /dev/null
+++ b/content/base/src/StyleSheetList.cpp
@@ -0,0 +1,46 @@
+/* -*- 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/StyleSheetList.h"
+
+#include "mozilla/dom/StyleSheetListBinding.h"
+#include "nsCSSStyleSheet.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(StyleSheetList)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheetList)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheetList)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheetList)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(StyleSheetList)
+
+/* virtual */ JSObject*
+StyleSheetList::WrapObject(JSContext* aCx)
+{
+  return StyleSheetListBinding::Wrap(aCx, this);
+}
+
+NS_IMETHODIMP
+StyleSheetList::GetLength(uint32_t* aLength)
+{
+  *aLength = Length();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+StyleSheetList::SlowItem(uint32_t aIndex, nsIDOMStyleSheet** aItem)
+{
+  NS_IF_ADDREF(*aItem = Item(aIndex));
+  return NS_OK;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/base/src/StyleSheetList.h
@@ -0,0 +1,48 @@
+/* -*- 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/. */
+
+#ifndef mozilla_dom_StyleSheetList_h
+#define mozilla_dom_StyleSheetList_h
+
+#include "nsIDOMStyleSheetList.h"
+#include "nsWrapperCache.h"
+
+class nsCSSStyleSheet;
+class nsINode;
+
+namespace mozilla {
+namespace dom {
+
+class StyleSheetList : public nsIDOMStyleSheetList
+                     , public nsWrapperCache
+{
+public:
+  StyleSheetList()
+  {
+    SetIsDOMBinding();
+  }
+  virtual ~StyleSheetList() {}
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheetList)
+  NS_DECL_NSIDOMSTYLESHEETLIST
+
+  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE MOZ_FINAL;
+
+  virtual nsINode* GetParentObject() const = 0;
+
+  virtual uint32_t Length() = 0;
+  virtual nsCSSStyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) = 0;
+  nsCSSStyleSheet* Item(uint32_t aIndex)
+  {
+    bool dummy = false;
+    return IndexedGetter(aIndex, dummy);
+  }
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_StyleSheetList_h
--- a/content/base/src/moz.build
+++ b/content/base/src/moz.build
@@ -67,16 +67,17 @@ EXPORTS.mozilla.dom += [
     'DOMPoint.h',
     'DOMQuad.h',
     'DOMRect.h',
     'DOMStringList.h',
     'EventSource.h',
     'Link.h',
     'NodeIterator.h',
     'ShadowRoot.h',
+    'StyleSheetList.h',
     'Text.h',
     'TreeWalker.h',
 ]
 
 UNIFIED_SOURCES += [
     'Attr.cpp',
     'ChildIterator.cpp',
     'Comment.cpp',
@@ -156,16 +157,17 @@ UNIFIED_SOURCES += [
     'nsTraversal.cpp',
     'nsTreeSanitizer.cpp',
     'nsViewportInfo.cpp',
     'nsXHTMLContentSerializer.cpp',
     'nsXMLContentSerializer.cpp',
     'nsXMLHttpRequest.cpp',
     'nsXMLNameSpaceMap.cpp',
     'ShadowRoot.cpp',
+    'StyleSheetList.cpp',
     'Text.cpp',
     'ThirdPartyUtil.cpp',
     'TreeWalker.cpp',
     'WebSocket.cpp',
 ]
 
 # These files cannot be built in unified mode because they use FORCE_PR_LOG
 SOURCES += [
--- a/content/base/src/nsAttrValue.h
+++ b/content/base/src/nsAttrValue.h
@@ -7,17 +7,17 @@
  * A struct that represents the value (type and actual data) of an
  * attribute.
  */
 
 #ifndef nsAttrValue_h___
 #define nsAttrValue_h___
 
 #include "nscore.h"
-#include "nsString.h"
+#include "nsStringGlue.h"
 #include "nsStringBuffer.h"
 #include "nsColor.h"
 #include "nsCaseTreatment.h"
 #include "nsMargin.h"
 #include "nsCOMPtr.h"
 #include "SVGAttrValueWrapper.h"
 #include "nsTArrayForwardDeclare.h"
 #include "nsIAtom.h"
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -718,86 +718,58 @@ nsDOMStyleSheetList::nsDOMStyleSheetList
 
 nsDOMStyleSheetList::~nsDOMStyleSheetList()
 {
   if (mDocument) {
     mDocument->RemoveObserver(this);
   }
 }
 
-DOMCI_DATA(StyleSheetList, nsDOMStyleSheetList)
-
-// XXX couldn't we use the GetIIDs method from CSSStyleSheetList here?
-// QueryInterface implementation for nsDOMStyleSheetList
-NS_INTERFACE_TABLE_HEAD(nsDOMStyleSheetList)
-  NS_INTERFACE_TABLE3(nsDOMStyleSheetList,
-                      nsIDOMStyleSheetList,
-                      nsIDocumentObserver,
-                      nsIMutationObserver)
-  NS_INTERFACE_TABLE_TO_MAP_SEGUE
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StyleSheetList)
-NS_INTERFACE_MAP_END
-
-
-NS_IMPL_ADDREF(nsDOMStyleSheetList)
-NS_IMPL_RELEASE(nsDOMStyleSheetList)
-
-
-NS_IMETHODIMP
-nsDOMStyleSheetList::GetLength(uint32_t* aLength)
-{
-  if (mDocument) {
-    // XXX Find the number and then cache it. We'll use the
-    // observer notification to figure out if new ones have
-    // been added or removed.
-    if (-1 == mLength) {
-      mLength = mDocument->GetNumberOfStyleSheets();
+NS_IMPL_ISUPPORTS_INHERITED2(nsDOMStyleSheetList, StyleSheetList,
+                             nsIDocumentObserver,
+                             nsIMutationObserver)
+
+uint32_t
+nsDOMStyleSheetList::Length()
+{
+  if (!mDocument) {
+    return 0;
+  }
+
+  // XXX Find the number and then cache it. We'll use the
+  // observer notification to figure out if new ones have
+  // been added or removed.
+  if (-1 == mLength) {
+    mLength = mDocument->GetNumberOfStyleSheets();
 
 #ifdef DEBUG
-      int32_t i;
-      for (i = 0; i < mLength; i++) {
-        nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(i);
-        nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(sheet));
-        NS_ASSERTION(domss, "All \"normal\" sheets implement nsIDOMStyleSheet");
-      }
+    int32_t i;
+    for (i = 0; i < mLength; i++) {
+      nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(i);
+      nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(sheet));
+      NS_ASSERTION(domss, "All \"normal\" sheets implement nsIDOMStyleSheet");
+    }
 #endif
-    }
-    *aLength = mLength;
-  }
-  else {
-    *aLength = 0;
-  }
-
-  return NS_OK;
-}
-
-nsIStyleSheet*
-nsDOMStyleSheetList::GetItemAt(uint32_t aIndex)
+  }
+  return mLength;
+}
+
+nsCSSStyleSheet*
+nsDOMStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
 {
   if (!mDocument || aIndex >= (uint32_t)mDocument->GetNumberOfStyleSheets()) {
+    aFound = false;
     return nullptr;
   }
 
+  aFound = true;
   nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(aIndex);
   NS_ASSERTION(sheet, "Must have a sheet");
 
-  return sheet;
-}
-
-NS_IMETHODIMP
-nsDOMStyleSheetList::Item(uint32_t aIndex, nsIDOMStyleSheet** aReturn)
-{
-  nsIStyleSheet *sheet = GetItemAt(aIndex);
-  if (!sheet) {
-      *aReturn = nullptr;
-
-      return NS_OK;
-  }
-
-  return CallQueryInterface(sheet, aReturn);
+  return static_cast<nsCSSStyleSheet*>(sheet);
 }
 
 void
 nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode *aNode)
 {
   mDocument = nullptr;
 }
 
@@ -1550,17 +1522,18 @@ nsIDocument::nsIDocument()
     mRemovedFromDocShell(false),
     // mAllowDNSPrefetch starts true, so that we can always reliably && it
     // with various values that might disable it.  Since we never prefetch
     // unless we get a window, and in that case the docshell value will get
     // &&-ed in, this is safe.
     mAllowDNSPrefetch(true),
     mIsBeingUsedAsImage(false),
     mHasLinksToUpdate(false),
-    mPartID(0)
+    mPartID(0),
+    mDidFireDOMContentLoaded(true)
 {
   SetInDocument();
 }
 
 // NOTE! nsDocument::operator new() zeroes out all members, so don't
 // bother initializing members to 0.
 
 nsDocument::nsDocument(const char* aContentType)
@@ -4702,16 +4675,18 @@ nsDocument::EndUpdate(nsUpdateType aUpda
 }
 
 void
 nsDocument::BeginLoad()
 {
   // Block onload here to prevent having to deal with blocking and
   // unblocking it while we know the document is loading.
   BlockOnload();
+  mDidFireDOMContentLoaded = false;
+  BlockDOMContentLoaded();
 
   if (mScriptLoader) {
     mScriptLoader->BeginDeferringScripts();
   }
 
   NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad, (this));
 }
 
@@ -4943,16 +4918,29 @@ nsDocument::EndLoad()
   // do that to get a StartLayout() to happen.
   if (mParser) {
     mWeakSink = do_GetWeakReference(mParser->GetContentSink());
     mParser = nullptr;
   }
 
   NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad, (this));
 
+  UnblockDOMContentLoaded();
+}
+
+void
+nsDocument::UnblockDOMContentLoaded()
+{
+  MOZ_ASSERT(mBlockDOMContentLoaded);
+  if (--mBlockDOMContentLoaded != 0 || mDidFireDOMContentLoaded) {
+    return;
+  }
+  mDidFireDOMContentLoaded = true;
+
+  MOZ_ASSERT(mReadyState == READYSTATE_INTERACTIVE);
   if (!mSynchronousDOMContentLoaded) {
     nsRefPtr<nsIRunnable> ev =
       NS_NewRunnableMethod(this, &nsDocument::DispatchContentLoadedEvents);
     NS_DispatchToCurrentThread(ev);
   } else {
     DispatchContentLoadedEvents();
   }
 }
@@ -6087,17 +6075,17 @@ nsDocument::Load(const nsAString& aUrl, 
 
 NS_IMETHODIMP
 nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets)
 {
   NS_ADDREF(*aStyleSheets = StyleSheets());
   return NS_OK;
 }
 
-nsIDOMStyleSheetList*
+StyleSheetList*
 nsDocument::StyleSheets()
 {
   if (!mDOMStyleSheets) {
     mDOMStyleSheets = new nsDOMStyleSheetList(this);
   }
   return mDOMStyleSheets;
 }
 
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -18,17 +18,16 @@
 #include "nsCRT.h"
 #include "nsWeakReference.h"
 #include "nsWeakPtr.h"
 #include "nsVoidArray.h"
 #include "nsTArray.h"
 #include "nsIDOMXMLDocument.h"
 #include "nsIDOMDocumentXBL.h"
 #include "nsStubDocumentObserver.h"
-#include "nsIDOMStyleSheetList.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIContent.h"
 #include "nsIPrincipal.h"
 #include "nsIParser.h"
 #include "nsBindingManager.h"
 #include "nsINodeInfo.h"
 #include "nsInterfaceHashtable.h"
 #include "nsJSThingHashtable.h"
@@ -60,30 +59,30 @@
 #include "nsIProgressEventSink.h"
 #include "nsISecurityEventSink.h"
 #include "nsIChannelEventSink.h"
 #include "imgIRequest.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/DOMImplementation.h"
+#include "mozilla/dom/StyleSheetList.h"
 #include "nsIDOMTouchEvent.h"
 #include "nsDataHashtable.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Attributes.h"
 #include "nsIDOMXPathEvaluator.h"
 #include "jsfriendapi.h"
 
 #define XML_DECLARATION_BITS_DECLARATION_EXISTS   (1 << 0)
 #define XML_DECLARATION_BITS_ENCODING_EXISTS      (1 << 1)
 #define XML_DECLARATION_BITS_STANDALONE_EXISTS    (1 << 2)
 #define XML_DECLARATION_BITS_STANDALONE_YES       (1 << 3)
 
 
-class nsDOMStyleSheetList;
 class nsDOMStyleSheetSetList;
 class nsIOutputStream;
 class nsDocument;
 class nsIDTD;
 class nsIRadioVisitor;
 class nsIFormControl;
 struct nsRadioGroupStruct;
 class nsOnloadBlocker;
@@ -431,35 +430,39 @@ public:
     delete mNext;
   }
 
   nsCOMPtr<nsIAtom> mField;
   nsString          mData;
   nsDocHeaderData*  mNext;
 };
 
-class nsDOMStyleSheetList : public nsIDOMStyleSheetList,
+class nsDOMStyleSheetList : public mozilla::dom::StyleSheetList,
                             public nsStubDocumentObserver
 {
 public:
   nsDOMStyleSheetList(nsIDocument *aDocument);
   virtual ~nsDOMStyleSheetList();
 
-  NS_DECL_ISUPPORTS
-
-  NS_DECL_NSIDOMSTYLESHEETLIST
+  NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDocumentObserver
   NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETADDED
   NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETREMOVED
 
   // nsIMutationObserver
   NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
 
-  nsIStyleSheet* GetItemAt(uint32_t aIndex);
+  virtual nsINode* GetParentObject() const MOZ_OVERRIDE
+  {
+    return mDocument;
+  }
+
+  virtual uint32_t Length() MOZ_OVERRIDE;
+  virtual nsCSSStyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) MOZ_OVERRIDE;
 
 protected:
   int32_t       mLength;
   nsIDocument*  mDocument;
 };
 
 class nsOnloadBlocker MOZ_FINAL : public nsIRequest
 {
@@ -1220,32 +1223,34 @@ public:
 
   // WebIDL bits
   virtual mozilla::dom::DOMImplementation*
     GetImplementation(mozilla::ErrorResult& rv) MOZ_OVERRIDE;
   virtual JSObject*
     RegisterElement(JSContext* aCx, const nsAString& aName,
                     const mozilla::dom::ElementRegistrationOptions& aOptions,
                     mozilla::ErrorResult& rv) MOZ_OVERRIDE;
-  virtual nsIDOMStyleSheetList* StyleSheets() MOZ_OVERRIDE;
+  virtual mozilla::dom::StyleSheetList* StyleSheets() MOZ_OVERRIDE;
   virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) MOZ_OVERRIDE;
   virtual void GetLastStyleSheetSet(nsString& aSheetSet) MOZ_OVERRIDE;
   virtual mozilla::dom::DOMStringList* StyleSheetSets() MOZ_OVERRIDE;
   virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) MOZ_OVERRIDE;
   using nsIDocument::CreateElement;
   using nsIDocument::CreateElementNS;
   virtual already_AddRefed<Element> CreateElement(const nsAString& aTagName,
                                                   const nsAString& aTypeExtension,
                                                   mozilla::ErrorResult& rv) MOZ_OVERRIDE;
   virtual already_AddRefed<Element> CreateElementNS(const nsAString& aNamespaceURI,
                                                     const nsAString& aQualifiedName,
                                                     const nsAString& aTypeExtension,
                                                     mozilla::ErrorResult& rv) MOZ_OVERRIDE;
   virtual void UseRegistryFromDocument(nsIDocument* aDocument) MOZ_OVERRIDE;
 
+  virtual void UnblockDOMContentLoaded() MOZ_OVERRIDE;
+
 protected:
   friend class nsNodeUtils;
   friend class nsDocumentOnStack;
 
   void IncreaseStackRefCnt()
   {
     ++mStackRefCnt;
   }
@@ -1425,17 +1430,17 @@ public:
                                     mozilla::ErrorResult& rv);
 
   static bool IsRegisterElementEnabled(JSContext* aCx, JSObject* aObject);
 
   // The "registry" from the web components spec.
   nsRefPtr<mozilla::dom::Registry> mRegistry;
 
   nsRefPtr<mozilla::EventListenerManager> mListenerManager;
-  nsCOMPtr<nsIDOMStyleSheetList> mDOMStyleSheets;
+  nsRefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
   nsRefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
   nsRefPtr<nsScriptLoader> mScriptLoader;
   nsDocHeaderData* mHeaderData;
   /* mIdentifierMap works as follows for IDs:
    * 1) Attribute changes affect the table immediately (removing and adding
    *    entries as needed).
    * 2) Removals from the DOM affect the table immediately
    * 3) Additions to the DOM always update existing entries for names, and add
--- a/content/base/src/nsHostObjectProtocolHandler.cpp
+++ b/content/base/src/nsHostObjectProtocolHandler.cpp
@@ -89,23 +89,24 @@ class BlobURLsReporter MOZ_FINAL : publi
     nsAutoCString origin;
     nsCOMPtr<nsIURI> principalURI;
     if (NS_SUCCEEDED(aInfo->mPrincipal->GetURI(getter_AddRefs(principalURI)))
         && principalURI) {
       principalURI->GetPrePath(origin);
     }
 
     for (uint32_t i = 0; i < maxFrames && frame; ++i) {
-      nsCString fileName;
+      nsString fileNameUTF16;
       int32_t lineNumber = 0;
 
-      frame->GetFilename(fileName);
+      frame->GetFilename(fileNameUTF16);
       frame->GetLineNumber(&lineNumber);
 
-      if (!fileName.IsEmpty()) {
+      if (!fileNameUTF16.IsEmpty()) {
+        NS_ConvertUTF16toUTF8 fileName(fileNameUTF16);
         stack += "js(";
         if (!origin.IsEmpty()) {
           // Make the file name root-relative for conciseness if possible.
           const char* originData;
           uint32_t originLen;
 
           originLen = origin.GetData(&originData);
           // If fileName starts with origin + "/", cut up to that "/".
--- a/content/base/src/nsImageLoadingContent.h
+++ b/content/base/src/nsImageLoadingContent.h
@@ -229,31 +229,16 @@ private:
   /**
    * UpdateImageState recomputes the current state of this image loading
    * content and updates what ImageState() returns accordingly.  It will also
    * fire a ContentStatesChanged() notification as needed if aNotify is true.
    */
   void UpdateImageState(bool aNotify);
 
   /**
-   * CancelImageRequests can be called when we want to cancel the
-   * image requests, generally due to our src changing and us wanting
-   * to start a new load.  The "current" request will be canceled only
-   * if it has not progressed far enough to know the image size yet
-   * unless aEvenIfSizeAvailable is true.
-   *
-   * @param aReason the reason the requests are being canceled
-   * @param aEvenIfSizeAvailable cancels the current load even if its size is
-   *                             available
-   * @param aNewImageStatus the nsIContentPolicy status of the new image load
-   */
-  void CancelImageRequests(nsresult aReason, bool aEvenIfSizeAvailable,
-                           int16_t aNewImageStatus);
-
-  /**
    * Method to fire an event once we know what's going on with the image load.
    *
    * @param aEventType "load" or "error" depending on how things went
    */
   nsresult FireEvent(const nsAString& aEventType);
 
 protected:
   /**
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -119,17 +119,18 @@ NS_IMPL_ISUPPORTS0(nsScriptLoadRequest)
 //
 //////////////////////////////////////////////////////////////
 
 nsScriptLoader::nsScriptLoader(nsIDocument *aDocument)
   : mDocument(aDocument),
     mBlockerCount(0),
     mEnabled(true),
     mDeferEnabled(false),
-    mDocumentParsingDone(false)
+    mDocumentParsingDone(false),
+    mBlockingDOMContentLoaded(false)
 {
   // enable logging for CSP
 #ifdef PR_LOGGING
   if (!gCspPRLog)
     gCspPRLog = PR_NewLogModule("CSP");
 #endif
 }
 
@@ -651,17 +652,17 @@ nsScriptLoader::ProcessScriptElement(nsI
       // If we come here, the script is a parser-created script and it has
       // the defer attribute but not the async attribute. Since a
       // a parser-inserted script is being run, we came here by the parser
       // running the script, which means the parser is still alive and the
       // parse is ongoing.
       NS_ASSERTION(mDocument->GetCurrentContentSink() ||
                    aElement->GetParserCreated() == FROM_PARSER_XSLT,
           "Non-XSLT Defer script on a document without an active parser; bug 592366.");
-      mDeferRequests.AppendElement(request);
+      AddDeferRequest(request);
       return false;
     }
 
     if (aElement->GetParserCreated() == FROM_PARSER_XSLT) {
       // Need to maintain order for XSLT-inserted scripts
       NS_ASSERTION(!mParserBlockingRequest,
           "Parser-blocking scripts and XSLT scripts in the same doc!");
       mXSLTRequests.AppendElement(request);
@@ -1166,16 +1167,19 @@ nsScriptLoader::ProcessPendingRequests()
     mPendingChildLoaders.RemoveElementAt(0);
     child->RemoveExecuteBlocker();
   }
 
   if (mDocumentParsingDone && mDocument &&
       !mParserBlockingRequest && mAsyncRequests.IsEmpty() &&
       mNonAsyncExternalScriptInsertedRequests.IsEmpty() &&
       mXSLTRequests.IsEmpty() && mDeferRequests.IsEmpty()) {
+    if (MaybeRemovedDeferRequests()) {
+      return ProcessPendingRequests();
+    }
     // No more pending scripts; time to unblock onload.
     // OK to unblock onload synchronously here, since callers must be
     // prepared for the world changing anyway.
     mDocumentParsingDone = false;
     mDocument->UnblockOnload(true);
   }
 }
 
@@ -1483,8 +1487,32 @@ nsScriptLoader::PreloadURI(nsIURI *aURI,
   if (NS_FAILED(rv)) {
     return;
   }
 
   PreloadInfo *pi = mPreloads.AppendElement();
   pi->mRequest = request;
   pi->mCharset = aCharset;
 }
+
+void
+nsScriptLoader::AddDeferRequest(nsScriptLoadRequest* aRequest)
+{
+  mDeferRequests.AppendElement(aRequest);
+  if (mDeferEnabled && mDeferRequests.Length() == 1 && mDocument &&
+      !mBlockingDOMContentLoaded) {
+    MOZ_ASSERT(mDocument->GetReadyStateEnum() == nsIDocument::READYSTATE_LOADING);
+    mBlockingDOMContentLoaded = true;
+    mDocument->BlockDOMContentLoaded();
+  }
+}
+
+bool
+nsScriptLoader::MaybeRemovedDeferRequests()
+{
+  if (mDeferRequests.Length() == 0 && mDocument &&
+      mBlockingDOMContentLoaded) {
+    mBlockingDOMContentLoaded = false;
+    mDocument->UnblockDOMContentLoaded();
+    return true;
+  }
+  return false;
+}
--- a/content/base/src/nsScriptLoader.h
+++ b/content/base/src/nsScriptLoader.h
@@ -286,16 +286,19 @@ private:
                                     JS::CompileOptions *aOptions);
 
   nsresult PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
                                 nsIStreamLoader* aLoader,
                                 nsresult aStatus,
                                 uint32_t aStringLen,
                                 const uint8_t* aString);
 
+  void AddDeferRequest(nsScriptLoadRequest* aRequest);
+  bool MaybeRemovedDeferRequests();
+
   nsIDocument* mDocument;                   // [WEAK]
   nsCOMArray<nsIScriptLoaderObserver> mObservers;
   nsTArray<nsRefPtr<nsScriptLoadRequest> > mNonAsyncExternalScriptInsertedRequests;
   nsTArray<nsRefPtr<nsScriptLoadRequest> > mAsyncRequests;
   nsTArray<nsRefPtr<nsScriptLoadRequest> > mDeferRequests;
   nsTArray<nsRefPtr<nsScriptLoadRequest> > mXSLTRequests;
   nsRefPtr<nsScriptLoadRequest> mParserBlockingRequest;
 
@@ -320,16 +323,17 @@ private:
   nsCOMPtr<nsIScriptElement> mCurrentScript;
   nsCOMPtr<nsIScriptElement> mCurrentParserInsertedScript;
   // XXXbz do we want to cycle-collect these or something?  Not sure.
   nsTArray< nsRefPtr<nsScriptLoader> > mPendingChildLoaders;
   uint32_t mBlockerCount;
   bool mEnabled;
   bool mDeferEnabled;
   bool mDocumentParsingDone;
+  bool mBlockingDOMContentLoaded;
 };
 
 class nsAutoScriptLoaderDisabler
 {
 public:
   nsAutoScriptLoaderDisabler(nsIDocument* aDoc)
   {
     mLoader = aDoc->ScriptLoader();
--- a/content/html/content/public/HTMLMediaElement.h
+++ b/content/html/content/public/HTMLMediaElement.h
@@ -491,17 +491,21 @@ public:
   {
     return mAudioCaptured;
   }
 
   JSObject* MozGetMetadata(JSContext* aCx, ErrorResult& aRv);
 
   double MozFragmentEnd();
 
-  AudioChannel MozAudioChannelType() const;
+  AudioChannel MozAudioChannelType() const
+  {
+    return mAudioChannel;
+  }
+
   void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
 
   TextTrackList* TextTracks();
 
   already_AddRefed<TextTrack> AddTextTrack(TextTrackKind aKind,
                                            const nsAString& aLabel,
                                            const nsAString& aLanguage);
 
@@ -1117,18 +1121,18 @@ protected:
   CORSMode mCORSMode;
 
   // True if the media has an audio track
   bool mHasAudio;
 
   // True if the media's channel's download has been suspended.
   bool mDownloadSuspendedByCache;
 
-  // Audio Channel Type.
-  AudioChannelType mAudioChannelType;
+  // Audio Channel.
+  AudioChannel mAudioChannel;
 
   // The audio channel has been faded.
   bool mAudioChannelFaded;
 
   // Is this media element playing?
   bool mPlayingThroughTheAudioChannel;
 
   // An agent used to join audio channel service.
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -3914,17 +3914,17 @@ HTMLInputElement::PostHandleEvent(EventC
       // control and as a result aVisitor.mEventStatus will already have been
       // set to nsEventStatus_eConsumeNoDefault. However, we know that
       // whenever the up/down arrow keys cause the value of the number
       // control to change the string in the text control will change, and
       // the cursor will be moved to the end of the text control, overwriting
       // the editor's handling of up/down keypress events. For that reason we
       // just ignore aVisitor.mEventStatus here and go ahead and handle the
       // event to increase/decrease the value of the number control.
-      if (!aVisitor.mEvent->mFlags.mDefaultPreventedByContent) {
+      if (!aVisitor.mEvent->mFlags.mDefaultPreventedByContent && IsMutable()) {
         StepNumberControlForUserEvent(keyEvent->keyCode == NS_VK_UP ? 1 : -1);
         aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
       }
     } else if (nsEventStatus_eIgnore == aVisitor.mEventStatus) {
       switch (aVisitor.mEvent->message) {
 
         case NS_FOCUS_CONTENT:
         {
@@ -4140,17 +4140,18 @@ HTMLInputElement::PostHandleEvent(EventC
             if (mouseEvent->button == WidgetMouseEvent::eLeftButton &&
                 !(mouseEvent->IsShift() || mouseEvent->IsControl() ||
                   mouseEvent->IsAlt() || mouseEvent->IsMeta() ||
                   mouseEvent->IsAltGraph() || mouseEvent->IsFn() ||
                   mouseEvent->IsOS())) {
               nsNumberControlFrame* numberControlFrame =
                 do_QueryFrame(GetPrimaryFrame());
               if (numberControlFrame) {
-                if (aVisitor.mEvent->message == NS_MOUSE_BUTTON_DOWN) {
+                if (aVisitor.mEvent->message == NS_MOUSE_BUTTON_DOWN && 
+                    IsMutable()) {
                   switch (numberControlFrame->GetSpinButtonForPointerEvent(
                             aVisitor.mEvent->AsMouseEvent())) {
                   case nsNumberControlFrame::eSpinButtonUp:
                     StepNumberControlForUserEvent(1);
                     mNumberControlSpinnerSpinsUp = true;
                     StartNumberControlSpinnerSpin();
                     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
                     break;
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -1999,29 +1999,30 @@ HTMLMediaElement::HTMLMediaElement(alrea
     mHasPlayedOrSeeked(false),
     mHasSelfReference(false),
     mShuttingDown(false),
     mSuspendedForPreloadNone(false),
     mMediaSecurityVerified(false),
     mCORSMode(CORS_NONE),
     mHasAudio(false),
     mDownloadSuspendedByCache(false),
-    mAudioChannelType(AUDIO_CHANNEL_NORMAL),
     mAudioChannelFaded(false),
     mPlayingThroughTheAudioChannel(false)
 {
 #ifdef PR_LOGGING
   if (!gMediaElementLog) {
     gMediaElementLog = PR_NewLogModule("nsMediaElement");
   }
   if (!gMediaElementEventsLog) {
     gMediaElementEventsLog = PR_NewLogModule("nsMediaElementEvents");
   }
 #endif
 
+  mAudioChannel = AudioChannelService::GetDefaultAudioChannel();
+
   mPaused.SetOuter(this);
 
   RegisterFreezableElement();
   NotifyOwnerDocumentActivityChanged();
 }
 
 HTMLMediaElement::~HTMLMediaElement()
 {
@@ -2277,53 +2278,44 @@ bool HTMLMediaElement::ParseAttribute(in
   static const nsAttrValue::EnumTable kPreloadTable[] = {
     { "",         HTMLMediaElement::PRELOAD_ATTR_EMPTY },
     { "none",     HTMLMediaElement::PRELOAD_ATTR_NONE },
     { "metadata", HTMLMediaElement::PRELOAD_ATTR_METADATA },
     { "auto",     HTMLMediaElement::PRELOAD_ATTR_AUTO },
     { 0 }
   };
 
-  // Mappings from 'mozaudiochannel' attribute strings to an enumeration.
-  static const nsAttrValue::EnumTable kMozAudioChannelAttributeTable[] = {
-    { "normal",             AUDIO_CHANNEL_NORMAL },
-    { "content",            AUDIO_CHANNEL_CONTENT },
-    { "notification",       AUDIO_CHANNEL_NOTIFICATION },
-    { "alarm",              AUDIO_CHANNEL_ALARM },
-    { "telephony",          AUDIO_CHANNEL_TELEPHONY },
-    { "ringer",             AUDIO_CHANNEL_RINGER },
-    { "publicnotification", AUDIO_CHANNEL_PUBLICNOTIFICATION },
-    { 0 }
-  };
-
   if (aNamespaceID == kNameSpaceID_None) {
     if (ParseImageAttribute(aAttribute, aValue, aResult)) {
       return true;
     }
     if (aAttribute == nsGkAtoms::crossorigin) {
       ParseCORSValue(aValue, aResult);
       return true;
     }
     if (aAttribute == nsGkAtoms::preload) {
       return aResult.ParseEnumValue(aValue, kPreloadTable, false);
     }
 
     if (aAttribute == nsGkAtoms::mozaudiochannel) {
-      bool parsed = aResult.ParseEnumValue(aValue, kMozAudioChannelAttributeTable, false,
-                                           &kMozAudioChannelAttributeTable[0]);
+      const nsAttrValue::EnumTable* table =
+        AudioChannelService::GetAudioChannelTable();
+      MOZ_ASSERT(table);
+
+      bool parsed = aResult.ParseEnumValue(aValue, table, false, &table[0]);
       if (!parsed) {
         return false;
       }
 
-      AudioChannelType audioChannelType = static_cast<AudioChannelType>(aResult.GetEnumValue());
-
-      if (audioChannelType != mAudioChannelType &&
+      AudioChannel audioChannel = static_cast<AudioChannel>(aResult.GetEnumValue());
+
+      if (audioChannel != mAudioChannel &&
           !mDecoder &&
           CheckAudioChannelPermissions(aValue)) {
-        mAudioChannelType = audioChannelType;
+        mAudioChannel = audioChannel;
       }
 
       return true;
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
@@ -2599,17 +2591,17 @@ nsresult HTMLMediaElement::FinishDecoder
   mPendingEvents.Clear();
   // Set mDecoder now so if methods like GetCurrentSrc get called between
   // here and Load(), they work.
   mDecoder = aDecoder;
 
   // Tell the decoder about its MediaResource now so things like principals are
   // available immediately.
   mDecoder->SetResource(aStream);
-  mDecoder->SetAudioChannelType(mAudioChannelType);
+  aDecoder->SetAudioChannel(mAudioChannel);
   mDecoder->SetAudioCaptured(mAudioCaptured);
   mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
   mDecoder->SetPreservesPitch(mPreservesPitch);
   mDecoder->SetPlaybackRate(mPlaybackRate);
 
   if (mPreloadAction == HTMLMediaElement::PRELOAD_METADATA) {
     mDecoder->SetMinimizePrerollUntilPlaybackStarts();
   }
@@ -3841,22 +3833,24 @@ void HTMLMediaElement::UpdateAudioChanne
     if (!mAudioChannelAgent) {
       nsresult rv;
       mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1", &rv);
       if (!mAudioChannelAgent) {
         return;
       }
       nsCOMPtr<nsIDOMHTMLVideoElement> video = do_QueryObject(this);
       // Use a weak ref so the audio channel agent can't leak |this|.
-      if (AUDIO_CHANNEL_NORMAL == mAudioChannelType && video) {
+      if (AudioChannel::Normal == mAudioChannel && video) {
         mAudioChannelAgent->InitWithVideo(OwnerDoc()->GetWindow(),
-                                          mAudioChannelType, this, true);
+                                          static_cast<int32_t>(mAudioChannel),
+                                          this, true);
       } else {
         mAudioChannelAgent->InitWithWeakCallback(OwnerDoc()->GetWindow(),
-                                                 mAudioChannelType, this);
+                                                 static_cast<int32_t>(mAudioChannel),
+                                                 this);
       }
       mAudioChannelAgent->SetVisibilityState(!OwnerDoc()->Hidden());
     }
 
     if (mPlayingThroughTheAudioChannel) {
       int32_t canPlay;
       mAudioChannelAgent->StartPlaying(&canPlay);
       CanPlayChanged(canPlay);
@@ -3922,47 +3916,21 @@ HTMLMediaElement::PopulatePendingTextTra
   }
 }
 
 TextTrackManager*
 HTMLMediaElement::GetOrCreateTextTrackManager()
 {
   if (!mTextTrackManager) {
     mTextTrackManager = new TextTrackManager(this);
+    mTextTrackManager->AddListeners();
   }
   return mTextTrackManager;
 }
 
-AudioChannel
-HTMLMediaElement::MozAudioChannelType() const
-{
-  switch (mAudioChannelType) {
-    case AUDIO_CHANNEL_CONTENT:
-      return AudioChannel::Content;
-
-    case AUDIO_CHANNEL_NOTIFICATION:
-      return AudioChannel::Notification;
-
-    case AUDIO_CHANNEL_ALARM:
-      return AudioChannel::Alarm;
-
-    case AUDIO_CHANNEL_TELEPHONY:
-      return AudioChannel::Telephony;
-
-    case AUDIO_CHANNEL_RINGER:
-      return AudioChannel::Ringer;
-
-    case AUDIO_CHANNEL_PUBLICNOTIFICATION:
-      return AudioChannel::Publicnotification;
-
-    default:
-      return AudioChannelService::GetDefaultAudioChannel();
-  }
-}
-
 void
 HTMLMediaElement::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv)
 {
   nsString channel;
   channel.AssignASCII(AudioChannelValues::strings[uint32_t(aValue)].value,
                       AudioChannelValues::strings[uint32_t(aValue)].length);
   SetHTMLAttr(nsGkAtoms::mozaudiochannel, channel, aRv);
 }
--- a/content/html/content/src/TextTrackManager.cpp
+++ b/content/html/content/src/TextTrackManager.cpp
@@ -3,18 +3,20 @@
 
 /* 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/TextTrackManager.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/HTMLTrackElement.h"
+#include "mozilla/dom/HTMLVideoElement.h"
 #include "mozilla/dom/TextTrack.h"
 #include "mozilla/dom/TextTrackCue.h"
+#include "mozilla/dom/Event.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "nsComponentManagerUtils.h"
 #include "nsVideoFrame.h"
 #include "nsIFrame.h"
 #include "nsTArrayHelpers.h"
 #include "nsIWebVTTParserWrapper.h"
 
 namespace mozilla {
@@ -70,27 +72,30 @@ CompareTextTracks::LessThan(TextTrack* a
       // No rules for Media Resource Specific tracks yet.
       break;
   }
   return true;
 }
 
 NS_IMPL_CYCLE_COLLECTION_4(TextTrackManager, mMediaElement, mTextTracks,
                            mPendingTextTracks, mNewCues)
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(TextTrackManager, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(TextTrackManager, Release)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextTrackManager)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(TextTrackManager)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(TextTrackManager)
 
 StaticRefPtr<nsIWebVTTParserWrapper> TextTrackManager::sParserWrapper;
 
 TextTrackManager::TextTrackManager(HTMLMediaElement *aMediaElement)
   : mMediaElement(aMediaElement)
   , performedTrackSelection(false)
 {
-  MOZ_COUNT_CTOR(TextTrackManager);
-
   bool hasHadScriptObject = true;
   nsIScriptGlobalObject* scriptObject =
     mMediaElement->OwnerDoc()->GetScriptHandlingObject(hasHadScriptObject);
 
   NS_ENSURE_TRUE_VOID(scriptObject || !hasHadScriptObject);
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(scriptObject);
   mNewCues = new TextTrackCueList(window);
@@ -100,21 +105,16 @@ TextTrackManager::TextTrackManager(HTMLM
   if (!sParserWrapper) {
     nsCOMPtr<nsIWebVTTParserWrapper> parserWrapper =
       do_CreateInstance(NS_WEBVTTPARSERWRAPPER_CONTRACTID);
     sParserWrapper = parserWrapper;
     ClearOnShutdown(&sParserWrapper);
   }
 }
 
-TextTrackManager::~TextTrackManager()
-{
-  MOZ_COUNT_DTOR(TextTrackManager);
-}
-
 TextTrackList*
 TextTrackManager::TextTracks() const
 {
   return mTextTracks;
 }
 
 already_AddRefed<TextTrack>
 TextTrackManager::AddTextTrack(TextTrackKind aKind, const nsAString& aLabel,
@@ -251,16 +251,25 @@ TextTrackManager::PopulatePendingList()
         ttrack->ReadyState() == TextTrackReadyState::Loading) {
       mPendingTextTracks->AddTextTrack(ttrack,
                                        CompareTextTracks(mMediaElement));
     }
   }
 }
 
 void
+TextTrackManager::AddListeners()
+{
+  if (mMediaElement) {
+    mMediaElement->AddEventListener(NS_LITERAL_STRING("resizevideocontrols"),
+                                    this, false, false);
+  }
+}
+
+void
 TextTrackManager::HonorUserPreferencesForTrackSelection()
 {
   if (performedTrackSelection || !mTextTracks) {
     return;
   }
 
   TextTrackKind ttKinds[] = { TextTrackKind::Captions,
                               TextTrackKind::Subtitles };
@@ -347,10 +356,27 @@ TextTrackManager::GetTextTracksOfKind(Te
   for (uint32_t i = 0; i < mTextTracks->Length(); i++) {
     TextTrack* textTrack = (*mTextTracks)[i];
     if (textTrack->Kind() == aTextTrackKind) {
       aTextTracks.AppendElement(textTrack);
     }
   }
 }
 
+NS_IMETHODIMP
+TextTrackManager::HandleEvent(nsIDOMEvent* aEvent)
+{
+  if (!mTextTracks) {
+    return NS_OK;
+  }
+
+  nsAutoString type;
+  aEvent->GetType(type);
+  if (type.EqualsLiteral("resizevideocontrols")) {
+    for (uint32_t i = 0; i< mTextTracks->Length(); i++) {
+      ((*mTextTracks)[i])->SetCuesDirty();
+    }
+  }
+  return NS_OK;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/content/html/content/src/TextTrackManager.h
+++ b/content/html/content/src/TextTrackManager.h
@@ -28,24 +28,25 @@ public:
   int32_t TrackChildPosition(TextTrack* aTrack) const;
   bool Equals(TextTrack* aOne, TextTrack* aTwo) const;
   bool LessThan(TextTrack* aOne, TextTrack* aTwo) const;
 };
 
 class TextTrack;
 class TextTrackCue;
 
-class TextTrackManager
+class TextTrackManager MOZ_FINAL : public nsIDOMEventListener
 {
 public:
-  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(TextTrackManager)
-  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(TextTrackManager);
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(TextTrackManager)
+
+  NS_DECL_NSIDOMEVENTLISTENER
 
   TextTrackManager(HTMLMediaElement *aMediaElement);
-  ~TextTrackManager();
 
   TextTrackList* TextTracks() const;
   already_AddRefed<TextTrack> AddTextTrack(TextTrackKind aKind,
                                            const nsAString& aLabel,
                                            const nsAString& aLanguage,
                                            TextTrackMode aMode,
                                            TextTrackReadyState aReadyState,
                                            TextTrackSource aTextTrackSource);
@@ -83,16 +84,18 @@ public:
   /**
    * Converts the TextTrackCue's cuetext into a tree of DOM objects and attaches
    * it to a div on it's owning TrackElement's MediaElement's caption overlay.
    */
   void UpdateCueDisplay();
 
   void PopulatePendingList();
 
+  void AddListeners();
+
   // The HTMLMediaElement that this TextTrackManager manages the TextTracks of.
   nsRefPtr<HTMLMediaElement> mMediaElement;
 private:
   // List of the TextTrackManager's owning HTMLMediaElement's TextTracks.
   nsRefPtr<TextTrackList> mTextTracks;
   // List of text track objects awaiting loading.
   nsRefPtr<TextTrackList> mPendingTextTracks;
   // List of newly introduced Text Track cues.
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsHTMLDocument.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/HTMLAllCollection.h"
 #include "nsCOMPtr.h"
+#include "nsGlobalWindow.h"
 #include "nsXPIDLString.h"
 #include "nsPrintfCString.h"
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsIHTMLContentSink.h"
 #include "nsIXMLContentSink.h"
 #include "nsHTMLParts.h"
 #include "nsHTMLStyleSheet.h"
@@ -2149,38 +2150,34 @@ nsHTMLDocument::Embeds()
   }
   return mEmbeds;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetSelection(nsISelection** aReturn)
 {
   ErrorResult rv;
-  *aReturn = GetSelection(rv).take();
+  NS_IF_ADDREF(*aReturn = GetSelection(rv));
   return rv.ErrorCode();
 }
 
-already_AddRefed<Selection>
-nsHTMLDocument::GetSelection(ErrorResult& rv)
+Selection*
+nsHTMLDocument::GetSelection(ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(GetScopeObject());
-  nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(window);
-  if (!pwin) {
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(GetScopeObject());
+  if (!window) {
     return nullptr;
   }
-  NS_ASSERTION(pwin->IsInnerWindow(), "Should have inner window here!");
-  if (!pwin->GetOuterWindow() ||
-      pwin->GetOuterWindow()->GetCurrentInnerWindow() != pwin) {
+
+  NS_ASSERTION(window->IsInnerWindow(), "Should have inner window here!");
+  if (!window->IsCurrentInnerWindow()) {
     return nullptr;
   }
 
-  nsCOMPtr<nsISelection> sel;
-  rv = window->GetSelection(getter_AddRefs(sel));
-  nsRefPtr<Selection> selection = static_cast<Selection*>(sel.get());
-  return selection.forget();
+  return static_cast<nsGlobalWindow*>(window.get())->GetSelection(aRv);
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::CaptureEvents()
 {
   WarnOnceAbout(nsIDocument::eUseOfCaptureEvents);
   return NS_OK;
 }
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -228,17 +228,17 @@ public:
   // The XPCOM Get/SetALinkColor work OK for us, since they never throw.
   // The XPCOM Get/SetBgColor work OK for us, since they never throw.
   nsIHTMLCollection* Anchors();
   nsIHTMLCollection* Applets();
   void Clear() const
   {
     // Deprecated
   }
-  already_AddRefed<mozilla::Selection> GetSelection(mozilla::ErrorResult& rv);
+  mozilla::Selection* GetSelection(mozilla::ErrorResult& aRv);
   // The XPCOM CaptureEvents works fine for us.
   // The XPCOM ReleaseEvents works fine for us.
   // We're picking up GetLocation from Document
   already_AddRefed<nsIDOMLocation> GetLocation() const {
     return nsIDocument::GetLocation();
   }
 
   virtual nsHTMLDocument* AsHTMLDocument() MOZ_OVERRIDE { return this; }
--- a/content/media/AudioSampleFormat.h
+++ b/content/media/AudioSampleFormat.h
@@ -19,16 +19,18 @@ namespace mozilla {
  * produce that format only; queued AudioData always uses that format.
  */
 enum AudioSampleFormat
 {
   // Native-endian signed 16-bit audio samples
   AUDIO_FORMAT_S16,
   // Signed 32-bit float samples
   AUDIO_FORMAT_FLOAT32,
+  // Silence: format will be chosen later
+  AUDIO_FORMAT_SILENCE,
   // The format used for output by AudioStream.
 #ifdef MOZ_SAMPLE_TYPE_S16
   AUDIO_OUTPUT_FORMAT = AUDIO_FORMAT_S16
 #else
   AUDIO_OUTPUT_FORMAT = AUDIO_FORMAT_FLOAT32
 #endif
 };
 
--- a/content/media/AudioSegment.cpp
+++ b/content/media/AudioSegment.cpp
@@ -47,16 +47,19 @@ InterleaveAndConvertBuffer(const void** 
     break;
   case AUDIO_FORMAT_S16:
     InterleaveAndConvertBuffer(reinterpret_cast<const int16_t**>(aSourceChannels),
                                aLength,
                                aVolume,
                                aChannels,
                                aOutput);
     break;
+   case AUDIO_FORMAT_SILENCE:
+    // nothing to do here.
+    break;
   }
 }
 
 void
 AudioSegment::ApplyVolume(float aVolume)
 {
   for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
     ci->mVolume *= aVolume;
@@ -116,17 +119,28 @@ void AudioSegment::ResampleChunks(SpeexR
   uint32_t inRate, outRate;
 
   if (mChunks.IsEmpty()) {
     return;
   }
 
   speex_resampler_get_rate(aResampler, &inRate, &outRate);
 
-  switch (mChunks[0].mBufferFormat) {
+  AudioSampleFormat format = AUDIO_FORMAT_SILENCE;
+  for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
+    if (ci->mBufferFormat != AUDIO_FORMAT_SILENCE) {
+      format = ci->mBufferFormat;
+    }
+  }
+
+  switch (format) {
+    // If the format is silence at this point, all the chunks are silent. The
+    // actual function we use does not matter, it's just a matter of changing
+    // the chunks duration.
+    case AUDIO_FORMAT_SILENCE:
     case AUDIO_FORMAT_FLOAT32:
       Resample<float>(aResampler, inRate, outRate);
     break;
     case AUDIO_FORMAT_S16:
       Resample<int16_t>(aResampler, inRate, outRate);
     break;
     default:
       MOZ_ASSERT(false);
--- a/content/media/AudioSegment.h
+++ b/content/media/AudioSegment.h
@@ -105,16 +105,17 @@ struct AudioChunk {
   }
   bool IsNull() const { return mBuffer == nullptr; }
   void SetNull(TrackTicks aDuration)
   {
     mBuffer = nullptr;
     mChannelData.Clear();
     mDuration = aDuration;
     mVolume = 1.0f;
+    mBufferFormat = AUDIO_FORMAT_SILENCE;
   }
   int ChannelCount() const { return mChannelData.Length(); }
 
   TrackTicks mDuration; // in frames within the buffer
   nsRefPtr<ThreadSharedObject> mBuffer; // the buffer object whose lifetime is managed; null means data is all zeroes
   nsTArray<const void*> mChannelData; // one pointer per channel; empty if and only if mBuffer is null
   float mVolume; // volume multiplier to apply (1.0f if mBuffer is nonnull)
   SampleFormat mBufferFormat; // format of frames in mBuffer (only meaningful if mBuffer is nonnull)
@@ -139,16 +140,21 @@ public:
   void Resample(SpeexResamplerState* aResampler, uint32_t aInRate, uint32_t aOutRate)
   {
     mDuration = 0;
 
     for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
       nsAutoTArray<nsTArray<T>, GUESS_AUDIO_CHANNELS> output;
       nsAutoTArray<const T*, GUESS_AUDIO_CHANNELS> bufferPtrs;
       AudioChunk& c = *ci;
+      // If this chunk is null, don't bother resampling, just alter its duration
+      if (c.IsNull()) {
+        c.mDuration *= aOutRate / aInRate;
+        mDuration += c.mDuration;
+      }
       uint32_t channels = c.mChannelData.Length();
       output.SetLength(channels);
       bufferPtrs.SetLength(channels);
       uint32_t inFrames = c.mDuration,
       outFrames = c.mDuration * aOutRate / aInRate;
       for (uint32_t i = 0; i < channels; i++) {
         const T* in = static_cast<const T*>(c.mChannelData[i]);
         T* out = output[i].AppendElements(outFrames);
--- a/content/media/AudioStream.cpp
+++ b/content/media/AudioStream.cpp
@@ -105,35 +105,35 @@ bool AudioStream::sCubebLatencyPrefSet;
 
 /*static*/ bool AudioStream::CubebLatencyPrefSet()
 {
   StaticMutexAutoLock lock(sMutex);
   return sCubebLatencyPrefSet;
 }
 
 #if defined(__ANDROID__) && defined(MOZ_B2G)
-static cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannelType aType)
+static cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannel aChannel)
 {
-  switch(aType) {
-    case dom::AUDIO_CHANNEL_NORMAL:
+  switch(aChannel) {
+    case dom::AudioChannel::Normal:
       return CUBEB_STREAM_TYPE_SYSTEM;
-    case dom::AUDIO_CHANNEL_CONTENT:
+    case dom::AudioChannel::Content:
       return CUBEB_STREAM_TYPE_MUSIC;
-    case dom::AUDIO_CHANNEL_NOTIFICATION:
+    case dom::AudioChannel::Notification:
       return CUBEB_STREAM_TYPE_NOTIFICATION;
-    case dom::AUDIO_CHANNEL_ALARM:
+    case dom::AudioChannel::Alarm:
       return CUBEB_STREAM_TYPE_ALARM;
-    case dom::AUDIO_CHANNEL_TELEPHONY:
+    case dom::AudioChannel::Telephony:
       return CUBEB_STREAM_TYPE_VOICE_CALL;
-    case dom::AUDIO_CHANNEL_RINGER:
+    case dom::AudioChannel::Ringer:
       return CUBEB_STREAM_TYPE_RING;
     // Currently Android openSLES library doesn't support FORCE_AUDIBLE yet.
-    case dom::AUDIO_CHANNEL_PUBLICNOTIFICATION:
+    case dom::AudioChannel::Publicnotification:
     default:
-      NS_ERROR("The value of AudioChannelType is invalid");
+      NS_ERROR("The value of AudioChannel is invalid");
       return CUBEB_STREAM_TYPE_MAX;
   }
 }
 #endif
 
 AudioStream::AudioStream()
   : mMonitor("AudioStream")
   , mInRate(0)
@@ -344,17 +344,17 @@ WriteDumpFile(FILE* aDumpFile, AudioStre
     SetUint16LE(output + i*2, int16_t(input[i]*32767.0f));
   }
   fwrite(output, 2, samples, aDumpFile);
   fflush(aDumpFile);
 }
 
 nsresult
 AudioStream::Init(int32_t aNumChannels, int32_t aRate,
-                  const dom::AudioChannelType aAudioChannelType,
+                  const dom::AudioChannel aAudioChannel,
                   LatencyRequest aLatencyRequest)
 {
   cubeb* cubebContext = GetCubebContext();
 
   if (!cubebContext || aNumChannels < 0 || aRate < 0) {
     return NS_ERROR_FAILURE;
   }
 
@@ -367,17 +367,17 @@ AudioStream::Init(int32_t aNumChannels, 
 
   mDumpFile = OpenDumpFile(this);
 
   cubeb_stream_params params;
   params.rate = aRate;
   params.channels = mOutChannels;
 #if defined(__ANDROID__)
 #if defined(MOZ_B2G)
-  params.stream_type = ConvertChannelToCubebType(aAudioChannelType);
+  params.stream_type = ConvertChannelToCubebType(aAudioChannel);
 #else
   params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
 #endif
 
   if (params.stream_type == CUBEB_STREAM_TYPE_MAX) {
     return NS_ERROR_INVALID_ARG;
   }
 #endif
--- a/content/media/AudioStream.h
+++ b/content/media/AudioStream.h
@@ -2,21 +2,21 @@
 /* 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/. */
 #if !defined(AudioStream_h_)
 #define AudioStream_h_
 
 #include "AudioSampleFormat.h"
-#include "AudioChannelCommon.h"
 #include "nsAutoPtr.h"
 #include "nsAutoRef.h"
 #include "nsCOMPtr.h"
 #include "Latency.h"
+#include "mozilla/dom/AudioChannelBinding.h"
 #include "mozilla/StaticMutex.h"
 
 #include "cubeb/cubeb.h"
 
 template <>
 class nsAutoRefTraits<cubeb_stream> : public nsPointerRefTraits<cubeb_stream>
 {
 public:
@@ -193,17 +193,17 @@ public:
     HighLatency,
     LowLatency
   };
 
   // Initialize the audio stream. aNumChannels is the number of audio
   // channels (1 for mono, 2 for stereo, etc) and aRate is the sample rate
   // (22050Hz, 44100Hz, etc).
   nsresult Init(int32_t aNumChannels, int32_t aRate,
-                const dom::AudioChannelType aAudioStreamType,
+                const dom::AudioChannel aAudioStreamChannel,
                 LatencyRequest aLatencyRequest);
 
   // Closes the stream. All future use of the stream is an error.
   void Shutdown();
 
   // Write audio data to the audio hardware.  aBuf is an array of AudioDataValues
   // AudioDataValue of length aFrames*mChannels.  If aFrames is larger
   // than the result of Available(), the write will block until sufficient
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -18,16 +18,17 @@
 #include "nsError.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPtr.h"
 #include "nsIMemoryReporter.h"
 #include "nsComponentManagerUtils.h"
 #include "nsITimer.h"
 #include <algorithm>
 #include "MediaShutdownManager.h"
+#include "AudioChannelService.h"
 
 #ifdef MOZ_WMF
 #include "WMFDecoder.h"
 #endif
 
 using namespace mozilla::layers;
 using namespace mozilla::dom;
 
@@ -422,27 +423,28 @@ MediaDecoder::MediaDecoder() :
   mNextState(PLAY_STATE_PAUSED),
   mCalledResourceLoaded(false),
   mIgnoreProgressData(false),
   mInfiniteStream(false),
   mOwner(nullptr),
   mPinnedForSeek(false),
   mShuttingDown(false),
   mPausedForPlaybackRateNull(false),
-  mAudioChannelType(AUDIO_CHANNEL_NORMAL),
   mMinimizePreroll(false)
 {
   MOZ_COUNT_CTOR(MediaDecoder);
   MOZ_ASSERT(NS_IsMainThread());
   MediaMemoryTracker::AddMediaDecoder(this);
 #ifdef PR_LOGGING
   if (!gMediaDecoderLog) {
     gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
   }
 #endif
+
+  mAudioChannel = AudioChannelService::GetDefaultAudioChannel();
 }
 
 bool MediaDecoder::Init(MediaDecoderOwner* aOwner)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mOwner = aOwner;
   mVideoFrameContainer = aOwner->GetVideoFrameContainer();
   MediaShutdownManager::Instance().Register(this);
--- a/content/media/MediaDecoder.h
+++ b/content/media/MediaDecoder.h
@@ -178,21 +178,21 @@ destroying the MediaDecoder object.
 #if !defined(MediaDecoder_h_)
 #define MediaDecoder_h_
 
 #include "nsISupports.h"
 #include "nsCOMPtr.h"
 #include "nsIObserver.h"
 #include "nsAutoPtr.h"
 #include "MediaResource.h"
+#include "mozilla/dom/AudioChannelBinding.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/TimeStamp.h"
 #include "MediaStreamGraph.h"
-#include "AudioChannelCommon.h"
 #include "AbstractMediaDecoder.h"
 #include "necko-config.h"
 
 class nsIStreamListener;
 class nsIPrincipal;
 class nsITimer;
 
 namespace mozilla {
@@ -734,18 +734,18 @@ public:
   bool CanPlayThrough();
 
   // Make the decoder state machine update the playback position. Called by
   // the reader on the decoder thread (Assertions for this checked by
   // mDecoderStateMachine). This must be called with the decode monitor
   // held.
   void UpdatePlaybackPosition(int64_t aTime) MOZ_FINAL MOZ_OVERRIDE;
 
-  void SetAudioChannelType(dom::AudioChannelType aType) { mAudioChannelType = aType; }
-  dom::AudioChannelType GetAudioChannelType() { return mAudioChannelType; }
+  void SetAudioChannel(dom::AudioChannel aChannel) { mAudioChannel = aChannel; }
+  dom::AudioChannel GetAudioChannel() { return mAudioChannel; }
 
   // Send a new set of metadata to the state machine, to be dispatched to the
   // main thread to be presented when the |currentTime| of the media is greater
   // or equal to aPublishTime.
   void QueueMetadata(int64_t aPublishTime,
                      int aChannels,
                      int aRate,
                      bool aHasAudio,
@@ -1200,17 +1200,17 @@ protected:
   // Read/Write from the main thread only.
   bool mShuttingDown;
 
   // True if the playback is paused because the playback rate member is 0.0.
   bool mPausedForPlaybackRateNull;
 
   // Be assigned from media element during the initialization and pass to
   // AudioStream Class.
-  dom::AudioChannelType mAudioChannelType;
+  dom::AudioChannel mAudioChannel;
 
   // True if the decoder has been directed to minimize its preroll before
   // playback starts. After the first time playback starts, we don't attempt
   // to minimize preroll, as we assume the user is likely to keep playing,
   // or play the media again.
   bool mMinimizePreroll;
 };
 
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -758,38 +758,38 @@ void MediaDecoderStateMachine::AudioLoop
   int64_t audioStartTime = -1;
   uint32_t channels, rate;
   double volume = -1;
   bool setVolume;
   double playbackRate = -1;
   bool setPlaybackRate;
   bool preservesPitch;
   bool setPreservesPitch;
-  AudioChannelType audioChannelType;
+  AudioChannel audioChannel;
 
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     mAudioCompleted = false;
     audioStartTime = mAudioStartTime;
     NS_ASSERTION(audioStartTime != -1, "Should have audio start time by now");
     channels = mInfo.mAudio.mChannels;
     rate = mInfo.mAudio.mRate;
 
-    audioChannelType = mDecoder->GetAudioChannelType();
+    audioChannel = mDecoder->GetAudioChannel();
     volume = mVolume;
     preservesPitch = mPreservesPitch;
     playbackRate = mPlaybackRate;
   }
 
   {
     // AudioStream initialization can block for extended periods in unusual
     // circumstances, so we take care to drop the decoder monitor while
     // initializing.
     nsAutoPtr<AudioStream> audioStream(new AudioStream());
-    audioStream->Init(channels, rate, audioChannelType, AudioStream::HighLatency);
+    audioStream->Init(channels, rate, audioChannel, AudioStream::HighLatency);
     audioStream->SetVolume(volume);
     if (audioStream->SetPreservesPitch(preservesPitch) != NS_OK) {
       NS_WARNING("Setting the pitch preservation failed at AudioLoop start.");
     }
     if (playbackRate != 1.0) {
       NS_ASSERTION(playbackRate != 0,
                    "Don't set the playbackRate to 0 on an AudioStream.");
       if (audioStream->SetPlaybackRate(playbackRate) != NS_OK) {
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -1,29 +1,30 @@
 /* -*- 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 "MediaStreamGraphImpl.h"
 #include "mozilla/LinkedList.h"
+#include "mozilla/MathAlgorithms.h"
 #include "mozilla/unused.h"
 
 #include "AudioSegment.h"
 #include "VideoSegment.h"
 #include "nsContentUtils.h"
 #include "nsIAppShell.h"
 #include "nsIObserver.h"
 #include "nsServiceManagerUtils.h"
 #include "nsWidgetsCID.h"
 #include "prlog.h"
 #include "mozilla/Attributes.h"
 #include "TrackUnionStream.h"
 #include "ImageContainer.h"
-#include "AudioChannelCommon.h"
+#include "AudioChannelService.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "AudioNodeExternalInputStream.h"
 #include <algorithm>
 #include "DOMMediaStream.h"
 #include "GeckoProfiler.h"
 #include "mozilla/unused.h"
 #include "speex/speex_resampler.h"
@@ -836,17 +837,19 @@ MediaStreamGraphImpl::CreateOrDestroyAud
         MediaStream::AudioOutputStream* audioOutputStream =
           aStream->mAudioOutputStreams.AppendElement();
         audioOutputStream->mAudioPlaybackStartTime = aAudioOutputStartTime;
         audioOutputStream->mBlockedAudioTime = 0;
         audioOutputStream->mLastTickWritten = 0;
         audioOutputStream->mStream = new AudioStream();
         // XXX for now, allocate stereo output. But we need to fix this to
         // match the system's ideal channel configuration.
-        audioOutputStream->mStream->Init(2, IdealAudioRate(), AUDIO_CHANNEL_NORMAL, AudioStream::LowLatency);
+        audioOutputStream->mStream->Init(2, IdealAudioRate(),
+                                         AudioChannel::Normal,
+                                         AudioStream::LowLatency);
         audioOutputStream->mTrackID = tracks->GetID();
 
         LogLatency(AsyncLatencyLogger::AudioStreamCreate,
                    reinterpret_cast<uint64_t>(aStream),
                    reinterpret_cast<int64_t>(audioOutputStream->mStream.get()));
       }
     }
   }
@@ -896,17 +899,17 @@ MediaStreamGraphImpl::PlayAudio(MediaStr
     // sample, or play a sample twice.
     TrackTicks offset = track->TimeToTicksRoundDown(GraphTimeToStreamTime(aStream, aFrom));
     if (!audioOutput.mLastTickWritten) {
         audioOutput.mLastTickWritten = offset;
     }
     if (audioOutput.mLastTickWritten != offset) {
       // If there is a global underrun of the MSG, this property won't hold, and
       // we reset the sample count tracking.
-      if (std::abs(audioOutput.mLastTickWritten - offset) != 1) {
+      if (mozilla::Abs(audioOutput.mLastTickWritten - offset) != 1) {
         audioOutput.mLastTickWritten = offset;
       } else {
         offset = audioOutput.mLastTickWritten;
       }
     }
 
     // We don't update aStream->mBufferStartTime here to account for
     // time spent blocked. Instead, we'll update it in UpdateCurrentTime after the
--- a/content/media/TextTrack.cpp
+++ b/content/media/TextTrack.cpp
@@ -120,16 +120,24 @@ TextTrack::AddCue(TextTrackCue& aCue)
 void
 TextTrack::RemoveCue(TextTrackCue& aCue, ErrorResult& aRv)
 {
   mCueList->RemoveCue(aCue, aRv);
   SetDirty();
 }
 
 void
+TextTrack::SetCuesDirty()
+{
+  for (uint32_t i = 0; i < mCueList->Length(); i++) {
+    ((*mCueList)[i])->Reset();
+  }
+}
+
+void
 TextTrack::UpdateActiveCueList()
 {
   if (!mTextTrackList) {
     return;
   }
 
   HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
   if (!mediaElement) {
--- a/content/media/TextTrack.h
+++ b/content/media/TextTrack.h
@@ -100,16 +100,17 @@ public:
 
   TextTrackReadyState ReadyState() const;
   void SetReadyState(TextTrackReadyState aState);
   void SetReadyState(uint32_t aReadyState);
 
   void AddCue(TextTrackCue& aCue);
   void RemoveCue(TextTrackCue& aCue, ErrorResult& aRv);
   void SetDirty() { mDirty = true; }
+  void SetCuesDirty();
 
   TextTrackList* GetTextTrackList();
   void SetTextTrackList(TextTrackList* aTextTrackList);
 
   IMPL_EVENT_HANDLER(cuechange)
 
   HTMLTrackElement* GetTrackElement();
   void SetTrackElement(HTMLTrackElement* aTrackElement);
--- a/content/media/TextTrackCue.h
+++ b/content/media/TextTrackCue.h
@@ -290,16 +290,21 @@ public:
   }
 
   void SetDisplayState(HTMLDivElement* aDisplayState)
   {
     mDisplayState = aDisplayState;
     mReset = false;
   }
 
+  void Reset()
+  {
+    mReset = true;
+  }
+
   bool HasBeenReset()
   {
     return mReset;
   }
 
   // Helper functions for implementation.
   bool
   operator==(const TextTrackCue& rhs) const
--- a/content/media/encoder/VorbisTrackEncoder.cpp
+++ b/content/media/encoder/VorbisTrackEncoder.cpp
@@ -75,17 +75,17 @@ VorbisTrackEncoder::Init(int aChannels, 
 
   mon.NotifyAll();
 
   return ret == 0 ? NS_OK : NS_ERROR_FAILURE;
 }
 
 void VorbisTrackEncoder::WriteLacing(nsTArray<uint8_t> *aOutput, int32_t aLacing)
 {
-  while (aLacing > 255) {
+  while (aLacing >= 255) {
     aLacing -= 255;
     aOutput->AppendElement(255);
   }
   aOutput->AppendElement((uint8_t)aLacing);
 }
 
 already_AddRefed<TrackMetadataBase>
 VorbisTrackEncoder::GetMetadata()
--- a/content/media/omx/MediaOmxDecoder.cpp
+++ b/content/media/omx/MediaOmxDecoder.cpp
@@ -40,17 +40,17 @@ MediaOmxDecoder::MediaOmxDecoder() :
 MediaDecoder* MediaOmxDecoder::Clone()
 {
   return new MediaOmxDecoder();
 }
 
 MediaDecoderStateMachine* MediaOmxDecoder::CreateStateMachine()
 {
   mReader = new MediaOmxReader(this);
-  mReader->SetAudioChannelType(GetAudioChannelType());
+  mReader->SetAudioChannel(GetAudioChannel());
   return new MediaDecoderStateMachine(this, mReader);
 }
 
 void MediaOmxDecoder::SetCanOffloadAudio(bool aCanOffloadAudio)
 {
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mCanOffloadAudio = aCanOffloadAudio;
 }
--- a/content/media/omx/MediaOmxReader.cpp
+++ b/content/media/omx/MediaOmxReader.cpp
@@ -8,16 +8,17 @@
 
 #include "MediaDecoderStateMachine.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "MediaResource.h"
 #include "VideoUtils.h"
 #include "MediaOmxDecoder.h"
 #include "AbstractMediaDecoder.h"
+#include "AudioChannelService.h"
 #include "OmxDecoder.h"
 #include "MPAPI.h"
 #include "gfx2DGlue.h"
 
 #ifdef MOZ_AUDIO_OFFLOAD
 #include <stagefright/Utils.h>
 #include <cutils/properties.h>
 #include <stagefright/MetaData.h>
@@ -40,24 +41,25 @@ extern PRLogModuleInfo* gMediaDecoderLog
 #endif
 
 MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder) :
   MediaDecoderReader(aDecoder),
   mHasVideo(false),
   mHasAudio(false),
   mVideoSeekTimeUs(-1),
   mAudioSeekTimeUs(-1),
-  mSkipCount(0),
-  mAudioChannelType(dom::AUDIO_CHANNEL_DEFAULT)
+  mSkipCount(0)
 {
 #ifdef PR_LOGGING
   if (!gMediaDecoderLog) {
     gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
   }
 #endif
+
+  mAudioChannel = dom::AudioChannelService::GetDefaultAudioChannel();
 }
 
 MediaOmxReader::~MediaOmxReader()
 {
   ReleaseMediaResources();
   ReleaseDecoder();
   mOmxDecoder.clear();
 }
@@ -432,21 +434,21 @@ void MediaOmxReader::CheckAudioOffload()
 
   // Supporting audio offload only when there is no video, no streaming
   bool hasNoVideo = !mOmxDecoder->HasVideo();
   bool isNotStreaming
       = mDecoder->GetResource()->IsDataCachedToEndOfResource(0);
 
   // Not much benefit in trying to offload other channel types. Most of them
   // aren't supported and also duration would be less than a minute
-  bool isTypeMusic = mAudioChannelType == dom::AUDIO_CHANNEL_CONTENT;
+  bool isTypeMusic = mAudioChannel == dom::AudioChannel::Content;
 
   DECODER_LOG(PR_LOG_DEBUG, ("%s meta %p, no video %d, no streaming %d,"
       " channel type %d", __FUNCTION__, meta.get(), hasNoVideo,
-      isNotStreaming, mAudioChannelType));
+      isNotStreaming, mAudioChannel));
 
   if ((meta.get()) && hasNoVideo && isNotStreaming && isTypeMusic &&
       canOffloadStream(meta, false, false, AUDIO_STREAM_MUSIC)) {
     DECODER_LOG(PR_LOG_DEBUG, ("Can offload this audio stream"));
     mDecoder->SetCanOffloadAudio(true);
   }
 }
 #endif
--- a/content/media/omx/MediaOmxReader.h
+++ b/content/media/omx/MediaOmxReader.h
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 #if !defined(MediaOmxReader_h_)
 #define MediaOmxReader_h_
 
 #include "MediaResource.h"
 #include "MediaDecoderReader.h"
 #include "nsRect.h"
-#include "AudioChannelCommon.h"
+#include "mozilla/dom/AudioChannelBinding.h"
 #include <ui/GraphicBuffer.h>
 #include <stagefright/MediaSource.h>
 
 namespace android {
 class OmxDecoder;
 class MediaExtractor;
 }
 
@@ -31,17 +31,17 @@ class MediaOmxReader : public MediaDecod
   nsCString mType;
   bool mHasVideo;
   bool mHasAudio;
   nsIntRect mPicture;
   nsIntSize mInitialFrame;
   int64_t mVideoSeekTimeUs;
   int64_t mAudioSeekTimeUs;
   int32_t mSkipCount;
-  dom::AudioChannelType mAudioChannelType;
+  dom::AudioChannel mAudioChannel;
   android::sp<android::MediaSource> mAudioOffloadTrack;
 
 protected:
   android::sp<android::OmxDecoder> mOmxDecoder;
   android::sp<android::MediaExtractor> mExtractor;
 
   // Called by ReadMetadata() during MediaDecoderStateMachine::DecodeMetadata()
   // on decode thread. It create and initialize the OMX decoder including
@@ -80,18 +80,18 @@ public:
 
   virtual nsresult ReadMetadata(MediaInfo* aInfo,
                                 MetadataTags** aTags);
   virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
 
   virtual void SetIdle() MOZ_OVERRIDE;
   virtual void SetActive() MOZ_OVERRIDE;
 
-  void SetAudioChannelType(dom::AudioChannelType aAudioChannelType) {
-    mAudioChannelType = aAudioChannelType;
+  void SetAudioChannel(dom::AudioChannel aAudioChannel) {
+    mAudioChannel = aAudioChannel;
   }
 
   android::sp<android::MediaSource> GetAudioOffloadTrack() {
     return mAudioOffloadTrack;
   }
 
 #ifdef MOZ_AUDIO_OFFLOAD
   // Check whether it is possible to offload current audio track. This access
--- a/content/media/webaudio/AudioDestinationNode.cpp
+++ b/content/media/webaudio/AudioDestinationNode.cpp
@@ -472,50 +472,20 @@ AudioDestinationNode::CheckAudioChannelP
 
 void
 AudioDestinationNode::CreateAudioChannelAgent()
 {
   if (mAudioChannelAgent) {
     mAudioChannelAgent->StopPlaying();
   }
 
-  AudioChannelType type = AUDIO_CHANNEL_NORMAL;
-  switch(mAudioChannel) {
-    case AudioChannel::Normal:
-      type = AUDIO_CHANNEL_NORMAL;
-      break;
-
-    case AudioChannel::Content:
-      type = AUDIO_CHANNEL_CONTENT;
-      break;
-
-    case AudioChannel::Notification:
-      type = AUDIO_CHANNEL_NOTIFICATION;
-      break;
-
-    case AudioChannel::Alarm:
-      type = AUDIO_CHANNEL_ALARM;
-      break;
-
-    case AudioChannel::Telephony:
-      type = AUDIO_CHANNEL_TELEPHONY;
-      break;
-
-    case AudioChannel::Ringer:
-      type = AUDIO_CHANNEL_RINGER;
-      break;
-
-    case AudioChannel::Publicnotification:
-      type = AUDIO_CHANNEL_PUBLICNOTIFICATION;
-      break;
-
-  }
-
   mAudioChannelAgent = new AudioChannelAgent();
-  mAudioChannelAgent->InitWithWeakCallback(GetOwner(), type, this);
+  mAudioChannelAgent->InitWithWeakCallback(GetOwner(),
+                                           static_cast<int32_t>(mAudioChannel),
+                                           this);
 
   nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
   if (docshell) {
     bool isActive = false;
     docshell->GetIsActive(&isActive);
     mAudioChannelAgent->SetVisibilityState(isActive);
   }
 
--- a/content/media/webrtc/LoadManager.cpp
+++ b/content/media/webrtc/LoadManager.cpp
@@ -29,18 +29,17 @@ PRLogModuleInfo *gLoadManagerLog = nullp
 #endif
 
 namespace mozilla {
 
 LoadManager::LoadManager(int aLoadMeasurementInterval,
                          int aAveragingMeasurements,
                          float aHighLoadThreshold,
                          float aLowLoadThreshold)
-  : mLastSystemLoad(0),
-    mLoadSum(0.0f),
+  : mLoadSum(0.0f),
     mLoadSumMeasurements(0),
     mOveruseActive(false),
     mLoadMeasurementInterval(aLoadMeasurementInterval),
     mAveragingMeasurements(aAveragingMeasurements),
     mHighLoadThreshold(aHighLoadThreshold),
     mLowLoadThreshold(aLowLoadThreshold),
     mCurrentState(webrtc::kLoadNormal)
 {
--- a/content/media/webrtc/LoadManager.h
+++ b/content/media/webrtc/LoadManager.h
@@ -37,17 +37,16 @@ public:
     // CPULoadStateCallbackInvoker interface
     virtual void AddObserver(webrtc::CPULoadStateObserver * aObserver) MOZ_OVERRIDE;
     virtual void RemoveObserver(webrtc::CPULoadStateObserver * aObserver) MOZ_OVERRIDE;
 
 private:
     void LoadHasChanged();
 
     nsRefPtr<LoadMonitor> mLoadMonitor;
-    float mLastSystemLoad;
     float mLoadSum;
     int   mLoadSumMeasurements;
     // Set when overuse was signaled to us, and hasn't been un-signaled yet.
     bool  mOveruseActive;
     // Load measurement settings
     int mLoadMeasurementInterval;
     int mAveragingMeasurements;
     float mHighLoadThreshold;
--- a/content/media/webrtc/LoadMonitor.h
+++ b/content/media/webrtc/LoadMonitor.h
@@ -48,17 +48,16 @@ private:
     void SetSystemLoad(float load);
     void FireCallbacks();
 
     int                  mLoadUpdateInterval;
     mozilla::Mutex       mLock;
     mozilla::CondVar     mCondVar;
     bool                 mShutdownPending;
     nsCOMPtr<nsIThread>  mLoadInfoThread;
-    uint64_t             mTicksPerInterval;
     float                mSystemLoad;
     float                mProcessLoad;
     LoadNotificationCallback* mLoadNotificationCallback;
 };
 
 } //namespace
 
 #endif /* _LOADMONITOR_H_ */
--- a/content/svg/content/src/DOMSVGLength.cpp
+++ b/content/svg/content/src/DOMSVGLength.cpp
@@ -4,53 +4,65 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DOMSVGLength.h"
 #include "DOMSVGLengthList.h"
 #include "DOMSVGAnimatedLengthList.h"
 #include "SVGLength.h"
 #include "SVGAnimatedLengthList.h"
 #include "nsSVGElement.h"
+#include "nsSVGLength2.h"
 #include "nsIDOMSVGLength.h"
 #include "nsError.h"
 #include "nsMathUtils.h"
+#include "mozilla/dom/SVGLengthBinding.h"
+#include "nsSVGAttrTearoffTable.h"
 
 // See the architecture comment in DOMSVGAnimatedLengthList.h.
 
 namespace mozilla {
 
+static nsSVGAttrTearoffTable<nsSVGLength2, DOMSVGLength>
+  sBaseSVGLengthTearOffTable,
+  sAnimSVGLengthTearOffTable;
+
 // We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
 // clear our list's weak ref to us to be safe. (The other option would be to
 // not unlink and rely on the breaking of the other edges in the cycle, as
 // NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGLength)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGLength)
   // We may not belong to a list, so we must null check tmp->mList.
   if (tmp->mList) {
     tmp->mList->mItems[tmp->mListIndex] = nullptr;
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK(mList)
+NS_IMPL_CYCLE_COLLECTION_UNLINK(mSVGElement)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGLength)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSVGElement)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGLength)
+NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGLength)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGLength)
 
-}
-DOMCI_DATA(SVGLength, mozilla::DOMSVGLength)
-namespace mozilla {
-
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGLength)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(mozilla::DOMSVGLength) // pseudo-interface
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLength)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLength)
 NS_INTERFACE_MAP_END
 
 //----------------------------------------------------------------------
 // Helper class: AutoChangeLengthNotifier
 // Stack-based helper class to pair calls to WillChangeLengthList and
 // DidChangeLengthList.
 class MOZ_STACK_CLASS AutoChangeLengthNotifier
 {
@@ -86,238 +98,417 @@ DOMSVGLength::DOMSVGLength(DOMSVGLengthL
                            uint32_t aListIndex,
                            bool aIsAnimValItem)
   : mList(aList)
   , mListIndex(aListIndex)
   , mAttrEnum(aAttrEnum)
   , mIsAnimValItem(aIsAnimValItem)
   , mUnit(nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER)
   , mValue(0.0f)
+  , mVal(nullptr)
 {
   // These shifts are in sync with the members in the header.
   NS_ABORT_IF_FALSE(aList &&
                     aAttrEnum < (1 << 4) &&
                     aListIndex <= MaxListIndex(), "bad arg");
 
   NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGNumber!");
+
+  SetIsDOMBinding();
 }
 
 DOMSVGLength::DOMSVGLength()
   : mList(nullptr)
   , mListIndex(0)
   , mAttrEnum(0)
   , mIsAnimValItem(false)
   , mUnit(nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER)
   , mValue(0.0f)
+  , mVal(nullptr)
 {
+  SetIsDOMBinding();
+}
+
+DOMSVGLength::DOMSVGLength(nsSVGLength2* aVal, nsSVGElement* aSVGElement,
+                           bool aAnimVal)
+  : mList(nullptr)
+  , mListIndex(0)
+  , mAttrEnum(0)
+  , mIsAnimValItem(aAnimVal)
+  , mUnit(nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER)
+  , mValue(0.0f)
+  , mVal(aVal)
+  , mSVGElement(aSVGElement)
+{
+  SetIsDOMBinding();
+}
+
+DOMSVGLength::~DOMSVGLength()
+{
+  // Our mList's weak ref to us must be nulled out when we die. If GC has
+  // unlinked us using the cycle collector code, then that has already
+  // happened, and mList is null.
+  if (mList) {
+    mList->mItems[mListIndex] = nullptr;
+  }
+
+  if (mVal) {
+    auto& table = mIsAnimValItem ? sAnimSVGLengthTearOffTable : sBaseSVGLengthTearOffTable;
+    table.RemoveTearoff(mVal);
+  }
+}
+
+already_AddRefed<DOMSVGLength>
+DOMSVGLength::GetTearOff(nsSVGLength2* aVal, nsSVGElement* aSVGElement,
+                         bool aAnimVal)
+{
+  auto& table = aAnimVal ? sAnimSVGLengthTearOffTable : sBaseSVGLengthTearOffTable;
+  nsRefPtr<DOMSVGLength> domLength = table.GetTearoff(aVal);
+  if (!domLength) {
+    domLength = new DOMSVGLength(aVal, aSVGElement, aAnimVal);
+    table.AddTearoff(aVal, domLength);
+  }
+
+  return domLength.forget();
+}
+
+uint16_t
+DOMSVGLength::UnitType()
+{
+  if (mVal) {
+    if (mIsAnimValItem) {
+      mSVGElement->FlushAnimations();
+    }
+    return mVal->mSpecifiedUnitType;
+  }
+
+  if (mIsAnimValItem && HasOwner()) {
+    Element()->FlushAnimations(); // May make HasOwner() == false
+  }
+  return HasOwner() ? InternalItem().GetUnit() : mUnit;
 }
 
 NS_IMETHODIMP
 DOMSVGLength::GetUnitType(uint16_t* aUnit)
 {
+  *aUnit = UnitType();
+  return NS_OK;
+}
+
+float
+DOMSVGLength::GetValue(ErrorResult& aRv)
+{
+  if (mVal) {
+    if (mIsAnimValItem) {
+      mSVGElement->FlushAnimations();
+      return mVal->GetAnimValue(mSVGElement);
+    }
+    return mVal->GetBaseValue(mSVGElement);
+  }
+
   if (mIsAnimValItem && HasOwner()) {
     Element()->FlushAnimations(); // May make HasOwner() == false
   }
-  *aUnit = HasOwner() ? InternalItem().GetUnit() : mUnit;
-  return NS_OK;
+  if (HasOwner()) {
+    float value = InternalItem().GetValueInUserUnits(Element(), Axis());
+    if (!NS_finite(value)) {
+      aRv.Throw(NS_ERROR_FAILURE);
+    }
+    return value;
+  } else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
+             mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX) {
+    return mValue;
+  }
+  // else [SVGWG issue] Can't convert this length's value to user units
+  // ReportToConsole
+  aRv.Throw(NS_ERROR_FAILURE);
+  return 0.0f;
 }
 
 NS_IMETHODIMP
 DOMSVGLength::GetValue(float* aValue)
 {
-  if (mIsAnimValItem && HasOwner()) {
-    Element()->FlushAnimations(); // May make HasOwner() == false
-  }
-  if (HasOwner()) {
-    *aValue = InternalItem().GetValueInUserUnits(Element(), Axis());
-    if (NS_finite(*aValue)) {
-      return NS_OK;
-    }
-  } else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
-             mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX) {
-    *aValue = mValue;
-    return NS_OK;
-  }
-  // else [SVGWG issue] Can't convert this length's value to user units
-  // ReportToConsole
-  return NS_ERROR_FAILURE;
+  ErrorResult rv;
+  *aValue = GetValue(rv);
+  return rv.ErrorCode();
 }
 
-NS_IMETHODIMP
-DOMSVGLength::SetValue(float aUserUnitValue)
+void
+DOMSVGLength::SetValue(float aUserUnitValue, ErrorResult& aRv)
 {
   if (mIsAnimValItem) {
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+    aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
   }
 
-  if (!NS_finite(aUserUnitValue)) {
-    return NS_ERROR_ILLEGAL_VALUE;
+  if (mVal) {
+    mVal->SetBaseValue(aUserUnitValue, mSVGElement, true);
+    return;
   }
 
   // Although the value passed in is in user units, this method does not turn
   // this length into a user unit length. Instead it converts the user unit
   // value to this length's current unit and sets that, leaving this length's
   // unit as it is.
 
   if (HasOwner()) {
     if (InternalItem().GetValueInUserUnits(Element(), Axis()) ==
         aUserUnitValue) {
-      return NS_OK;
+      return;
     }
     float uuPerUnit = InternalItem().GetUserUnitsPerUnit(Element(), Axis());
     if (uuPerUnit > 0) {
       float newValue = aUserUnitValue / uuPerUnit;
       if (NS_finite(newValue)) {
         AutoChangeLengthNotifier notifier(this);
         InternalItem().SetValueAndUnit(newValue, InternalItem().GetUnit());
-        return NS_OK;
+        return;
       }
     }
   } else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
              mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX) {
     mValue = aUserUnitValue;
-    return NS_OK;
+    return;
   }
   // else [SVGWG issue] Can't convert user unit value to this length's unit
   // ReportToConsole
-  return NS_ERROR_FAILURE;
+  aRv.Throw(NS_ERROR_FAILURE);
+}
+
+NS_IMETHODIMP
+DOMSVGLength::SetValue(float aUserUnitValue)
+{
+  if (!NS_finite(aUserUnitValue)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  ErrorResult rv;
+  SetValue(aUserUnitValue, rv);
+  return rv.ErrorCode();
+}
+
+float
+DOMSVGLength::ValueInSpecifiedUnits()
+{
+  if (mVal) {
+    if (mIsAnimValItem) {
+      mSVGElement->FlushAnimations();
+      return mVal->mAnimVal;
+    }
+    return mVal->mBaseVal;
+  }
+
+  if (mIsAnimValItem && HasOwner()) {
+    Element()->FlushAnimations(); // May make HasOwner() == false
+  }
+  return HasOwner() ? InternalItem().GetValueInCurrentUnits() : mValue;
 }
 
 NS_IMETHODIMP
 DOMSVGLength::GetValueInSpecifiedUnits(float* aValue)
 {
-  if (mIsAnimValItem && HasOwner()) {
-    Element()->FlushAnimations(); // May make HasOwner() == false
+  *aValue = ValueInSpecifiedUnits();
+  return NS_OK;
+}
+
+void
+DOMSVGLength::SetValueInSpecifiedUnits(float aValue, ErrorResult& aRv)
+{
+  if (mIsAnimValItem) {
+    aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
   }
-  *aValue = HasOwner() ? InternalItem().GetValueInCurrentUnits() : mValue;
-  return NS_OK;
+
+  if (mVal) {
+    mVal->SetBaseValueInSpecifiedUnits(aValue, mSVGElement, true);
+    return;
+  }
+
+  if (HasOwner()) {
+    if (InternalItem().GetValueInCurrentUnits() == aValue) {
+      return;
+    }
+    AutoChangeLengthNotifier notifier(this);
+    InternalItem().SetValueInCurrentUnits(aValue);
+    return;
+  }
+  mValue = aValue;
 }
 
 NS_IMETHODIMP
 DOMSVGLength::SetValueInSpecifiedUnits(float aValue)
 {
-  if (mIsAnimValItem) {
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
-  }
-
   if (!NS_finite(aValue)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
+  ErrorResult rv;
+  SetValueInSpecifiedUnits(aValue, rv);
+  return rv.ErrorCode();
+}
+
+void
+DOMSVGLength::SetValueAsString(const nsAString& aValue, ErrorResult& aRv)
+{
+  if (mIsAnimValItem) {
+    aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
+  }
+
+  if (mVal) {
+    mVal->SetBaseValueString(aValue, mSVGElement, true);
+    return;
+  }
+
+  SVGLength value;
+  if (!value.SetValueFromString(aValue)) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
+  }
   if (HasOwner()) {
-    if (InternalItem().GetValueInCurrentUnits() == aValue) {
-      return NS_OK;
+    if (InternalItem() == value) {
+      return;
     }
     AutoChangeLengthNotifier notifier(this);
-    InternalItem().SetValueInCurrentUnits(aValue);
-    return NS_OK;
+    InternalItem() = value;
+    return;
   }
-  mValue = aValue;
-  return NS_OK;
+  mValue = value.GetValueInCurrentUnits();
+  mUnit = value.GetUnit();
 }
 
 NS_IMETHODIMP
 DOMSVGLength::SetValueAsString(const nsAString& aValue)
 {
-  if (mIsAnimValItem) {
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
-  }
-
-  SVGLength value;
-  if (!value.SetValueFromString(aValue)) {
-    return NS_ERROR_DOM_SYNTAX_ERR;
-  }
-  if (HasOwner()) {
-    if (InternalItem() == value) {
-      return NS_OK;
-    }
-    AutoChangeLengthNotifier notifier(this);
-    InternalItem() = value;
-    return NS_OK;
-  }
-  mValue = value.GetValueInCurrentUnits();
-  mUnit = value.GetUnit();
-  return NS_OK;
+  ErrorResult rv;
+  SetValueAsString(aValue, rv);
+  return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 DOMSVGLength::GetValueAsString(nsAString& aValue)
 {
+  if (mVal) {
+    if (mIsAnimValItem) {
+      mSVGElement->FlushAnimations();
+      mVal->GetAnimValueString(aValue);
+    } else {
+      mVal->GetBaseValueString(aValue);
+    }
+    return NS_OK;
+  }
+
   if (mIsAnimValItem && HasOwner()) {
     Element()->FlushAnimations(); // May make HasOwner() == false
   }
   if (HasOwner()) {
     InternalItem().GetValueAsString(aValue);
     return NS_OK;
   }
   SVGLength(mValue, mUnit).GetValueAsString(aValue);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-DOMSVGLength::NewValueSpecifiedUnits(uint16_t aUnit, float aValue)
+void
+DOMSVGLength::NewValueSpecifiedUnits(uint16_t aUnit, float aValue,
+                                     ErrorResult& aRv)
 {
   if (mIsAnimValItem) {
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+    aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
   }
 
-  if (!NS_finite(aValue)) {
-    return NS_ERROR_ILLEGAL_VALUE;
+  if (mVal) {
+    mVal->NewValueSpecifiedUnits(aUnit, aValue, mSVGElement);
+    return;
   }
 
   if (!SVGLength::IsValidUnitType(aUnit)) {
-    return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return;
   }
   if (HasOwner()) {
     if (InternalItem().GetUnit() == aUnit &&
         InternalItem().GetValueInCurrentUnits() == aValue) {
-      return NS_OK;
+      return;
     }
     AutoChangeLengthNotifier notifier(this);
     InternalItem().SetValueAndUnit(aValue, uint8_t(aUnit));
-    return NS_OK;
+    return;
   }
   mUnit = uint8_t(aUnit);
   mValue = aValue;
-  return NS_OK;
 }
 
 NS_IMETHODIMP
-DOMSVGLength::ConvertToSpecifiedUnits(uint16_t aUnit)
+DOMSVGLength::NewValueSpecifiedUnits(uint16_t aUnit, float aValue)
+{
+  if (!NS_finite(aValue)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  ErrorResult rv;
+  NewValueSpecifiedUnits(aUnit, aValue, rv);
+  return rv.ErrorCode();
+}
+
+void
+DOMSVGLength::ConvertToSpecifiedUnits(uint16_t aUnit, ErrorResult& aRv)
 {
   if (mIsAnimValItem) {
-    return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+    aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
+    return;
+  }
+
+  if (mVal) {
+    mVal->ConvertToSpecifiedUnits(aUnit, mSVGElement);
+    return;
   }
 
   if (!SVGLength::IsValidUnitType(aUnit)) {
-    return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return;
   }
   if (HasOwner()) {
     if (InternalItem().GetUnit() == aUnit) {
-      return NS_OK;
+      return;
     }
     float val = InternalItem().GetValueInSpecifiedUnit(
                                  aUnit, Element(), Axis());
     if (NS_finite(val)) {
       AutoChangeLengthNotifier notifier(this);
       InternalItem().SetValueAndUnit(val, aUnit);
-      return NS_OK;
+      return;
     }
   } else {
     SVGLength len(mValue, mUnit);
     float val = len.GetValueInSpecifiedUnit(aUnit, nullptr, 0);
     if (NS_finite(val)) {
       mValue = val;
       mUnit = aUnit;
-      return NS_OK;
+      return;
     }
   }
   // else [SVGWG issue] Can't convert unit
   // ReportToConsole
-  return NS_ERROR_FAILURE;
+  aRv.Throw(NS_ERROR_FAILURE);
+}
+
+NS_IMETHODIMP
+DOMSVGLength::ConvertToSpecifiedUnits(uint16_t aUnit)
+{
+  ErrorResult rv;
+  ConvertToSpecifiedUnits(aUnit, rv);
+  return rv.ErrorCode();
+}
+
+JSObject*
+DOMSVGLength::WrapObject(JSContext* aCx)
+{
+  return dom::SVGLengthBinding::Wrap(aCx, this);
 }
 
 void
 DOMSVGLength::InsertingIntoList(DOMSVGLengthList *aList,
                                 uint8_t aAttrEnum,
                                 uint32_t aListIndex,
                                 bool aIsAnimValItem)
 {
--- a/content/svg/content/src/DOMSVGLength.h
+++ b/content/svg/content/src/DOMSVGLength.h
@@ -9,31 +9,34 @@
 #include "DOMSVGLengthList.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDebug.h"
 #include "nsIDOMSVGLength.h"
 #include "nsTArray.h"
 #include "SVGLength.h"
 #include "mozilla/Attributes.h"
+#include "nsWrapperCache.h"
 
 class nsSVGElement;
 
 // We make DOMSVGLength a pseudo-interface to allow us to QI to it in order to
 // check that the objects that scripts pass to DOMSVGLengthList methods are our
 // *native* length objects.
 //
 // {A8468350-7F7B-4976-9A7E-3765A1DADF9A}
 #define MOZILLA_DOMSVGLENGTH_IID \
   { 0xA8468350, 0x7F7B, 0x4976, { 0x9A, 0x7E, 0x37, 0x65, 0xA1, 0xDA, 0xDF, 0x9A } }
 
 #define MOZ_SVG_LIST_INDEX_BIT_COUNT 22 // supports > 4 million list items
 
 namespace mozilla {
 
+class ErrorResult;
+
 /**
  * Class DOMSVGLength
  *
  * This class creates the DOM objects that wrap internal SVGLength objects that
  * are in an SVGLengthList. It is also used to create the objects returned by
  * SVGSVGElement.createSVGLength().
  *
  * For the DOM wrapper classes for non-list SVGLength, see nsSVGLength2.h.
@@ -61,48 +64,51 @@ namespace mozilla {
  * type can find their corresponding internal SVGLength.
  *
  * To use these classes for <length> attributes as well as <list-of-length>
  * attributes, we would need to take a bit from mListIndex and use that to
  * indicate whether the object belongs to a list or non-list attribute, then
  * if-else as appropriate. The bug for doing that work is:
  * https://bugzilla.mozilla.org/show_bug.cgi?id=571734
  */
-class DOMSVGLength MOZ_FINAL : public nsIDOMSVGLength
+class DOMSVGLength MOZ_FINAL : public nsIDOMSVGLength,
+                               public nsWrapperCache
 {
   friend class AutoChangeLengthNotifier;
 
+  /**
+   * Ctor for creating the object returned by nsSVGLength2::ToDOMBaseVal/ToDOMAnimVal
+   */
+  DOMSVGLength(nsSVGLength2* aVal, nsSVGElement* aSVGElement, bool aAnimVal);
+
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOMSVGLENGTH_IID)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGLength)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGLength)
   NS_DECL_NSIDOMSVGLENGTH
 
   /**
    * Generic ctor for DOMSVGLength objects that are created for an attribute.
    */
   DOMSVGLength(DOMSVGLengthList *aList,
                uint8_t aAttrEnum,
                uint32_t aListIndex,
                bool aIsAnimValItem);
 
   /**
    * Ctor for creating the objects returned by SVGSVGElement.createSVGLength(),
    * which do not initially belong to an attribute.
    */
   DOMSVGLength();
 
-  ~DOMSVGLength() {
-    // Our mList's weak ref to us must be nulled out when we die. If GC has
-    // unlinked us using the cycle collector code, then that has already
-    // happened, and mList is null.
-    if (mList) {
-      mList->mItems[mListIndex] = nullptr;
-    }
-  }
+  ~DOMSVGLength();
+
+  static already_AddRefed<DOMSVGLength> GetTearOff(nsSVGLength2* aVal,
+                                                   nsSVGElement* aSVGElement,
+                                                   bool aAnimVal);
 
   /**
    * Create an unowned copy of an owned length. The caller is responsible for
    * the first AddRef().
    */
   DOMSVGLength* Copy() {
     NS_ASSERTION(mList, "unexpected caller");
     DOMSVGLength *copy = new DOMSVGLength();
@@ -151,19 +157,38 @@ public:
    * removed from its current DOM list so that it can first make a copy of its
    * internal counterpart's values. (If it didn't do this, then it would
    * "lose" its value on being removed.)
    */
   void RemovingFromList();
 
   SVGLength ToSVGLength();
 
+  // WebIDL
+  uint16_t UnitType();
+  float GetValue(ErrorResult& aRv);
+  void SetValue(float aValue, ErrorResult& aRv);
+  float ValueInSpecifiedUnits();
+  void SetValueInSpecifiedUnits(float aValue, ErrorResult& aRv);
+  // The XPCOM GetValueAsString is good
+  void SetValueAsString(const nsAString& aValue, ErrorResult& aRv);
+  void NewValueSpecifiedUnits(uint16_t aUnit, float aValue,
+                              ErrorResult& aRv);
+  void ConvertToSpecifiedUnits(uint16_t aUnit, ErrorResult& aRv);
+
+  nsISupports* GetParentObject() const {
+    auto svgElement = mList ? Element() : mSVGElement.get();
+    return static_cast<nsIDOMSVGElement*> (svgElement);
+  }
+
+  JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
 private:
 
-  nsSVGElement* Element() {
+  nsSVGElement* Element() const {
     return mList->Element();
   }
 
   uint8_t AttrEnum() const {
     return mAttrEnum;
   }
 
   /**
@@ -196,16 +221,20 @@ private:
 
   uint32_t mListIndex:MOZ_SVG_LIST_INDEX_BIT_COUNT;
   uint32_t mAttrEnum:4; // supports up to 16 attributes
   uint32_t mIsAnimValItem:1;
 
   // The following members are only used when we're not in a list:
   uint32_t mUnit:5; // can handle 31 units (the 10 SVG 1.1 units + rem, vw, vh, wm, calc + future additions)
   float mValue;
+
+  // The following members are only used when we have an nsSVGLength2
+  nsSVGLength2* mVal; // kept alive because it belongs to mSVGElement
+  nsRefPtr<nsSVGElement> mSVGElement;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(DOMSVGLength, MOZILLA_DOMSVGLENGTH_IID)
 
 } // namespace mozilla
 
 #undef MOZ_SVG_LIST_INDEX_BIT_COUNT
 
--- a/content/svg/content/src/DOMSVGLengthList.cpp
+++ b/content/svg/content/src/DOMSVGLengthList.cpp
@@ -167,89 +167,89 @@ DOMSVGLengthList::Clear(ErrorResult& aEr
     // their values. This also notifies the animVal list:
     mAList->InternalBaseValListWillChangeTo(SVGLengthList());
 
     mItems.Clear();
     InternalList().Clear();
   }
 }
 
-already_AddRefed<nsIDOMSVGLength>
-DOMSVGLengthList::Initialize(nsIDOMSVGLength *newItem,
+already_AddRefed<DOMSVGLength>
+DOMSVGLengthList::Initialize(DOMSVGLength& newItem,
                              ErrorResult& error)
 {
   if (IsAnimValList()) {
     error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     return nullptr;
   }
 
   // If newItem is already in a list we should insert a clone of newItem, and
   // for consistency, this should happen even if *this* is the list that
   // newItem is currently in. Note that in the case of newItem being in this
   // list, the Clear() call before the InsertItemBefore() call would remove it
   // from this list, and so the InsertItemBefore() call would not insert a
   // clone of newItem, it would actually insert newItem. To prevent that from
   // happening we have to do the clone here, if necessary.
 
-  nsCOMPtr<DOMSVGLength> domItem = do_QueryInterface(newItem);
+  nsRefPtr<DOMSVGLength> domItem = &newItem;
   if (!domItem) {
     error.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
     return nullptr;
   }
   if (domItem->HasOwner()) {
-    newItem = domItem->Copy();
+    domItem = domItem->Copy();
   }
 
   ErrorResult rv;
   Clear(rv);
   MOZ_ASSERT(!rv.Failed());
-  return InsertItemBefore(newItem, 0, error);
+  return InsertItemBefore(*domItem, 0, error);
 }
 
-already_AddRefed<nsIDOMSVGLength>
+already_AddRefed<DOMSVGLength>
 DOMSVGLengthList::GetItem(uint32_t index, ErrorResult& error)
 {
   bool found;
-  nsRefPtr<nsIDOMSVGLength> item = IndexedGetter(index, found, error);
+  nsRefPtr<DOMSVGLength> item = IndexedGetter(index, found, error);
   if (!found) {
     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
   }
   return item.forget();
 }
 
-already_AddRefed<nsIDOMSVGLength>
+already_AddRefed<DOMSVGLength>
 DOMSVGLengthList::IndexedGetter(uint32_t index, bool& found, ErrorResult& error)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
   }
   found = index < LengthNoFlush();
   if (found) {
     return GetItemAt(index);
   }
   return nullptr;
 }
 
-already_AddRefed<nsIDOMSVGLength>
-DOMSVGLengthList::InsertItemBefore(nsIDOMSVGLength *newItem,
+already_AddRefed<DOMSVGLength>
+DOMSVGLengthList::InsertItemBefore(DOMSVGLength& newItem,
                                    uint32_t index,
                                    ErrorResult& error)
 {
   if (IsAnimValList()) {
     error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     return nullptr;
   }
 
   index = std::min(index, LengthNoFlush());
   if (index >= DOMSVGLength::MaxListIndex()) {
     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return nullptr;
   }
 
-  nsCOMPtr<DOMSVGLength> domItem = do_QueryInterface(newItem);
+  nsRefPtr<DOMSVGLength> domItem = &newItem;
   if (!domItem) {
     error.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
     return nullptr;
   }
   if (domItem->HasOwner()) {
     domItem = domItem->Copy(); // must do this before changing anything!
   }
 
@@ -272,27 +272,27 @@ DOMSVGLengthList::InsertItemBefore(nsIDO
   // data from InternalList() itself!:
   domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
 
   UpdateListIndicesFromIndex(mItems, index + 1);
 
   return domItem.forget();
 }
 
-already_AddRefed<nsIDOMSVGLength>
-DOMSVGLengthList::ReplaceItem(nsIDOMSVGLength *newItem,
+already_AddRefed<DOMSVGLength>
+DOMSVGLengthList::ReplaceItem(DOMSVGLength& newItem,
                               uint32_t index,
                               ErrorResult& error)
 {
   if (IsAnimValList()) {
     error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     return nullptr;
   }
 
-  nsCOMPtr<DOMSVGLength> domItem = do_QueryInterface(newItem);
+  nsRefPtr<DOMSVGLength> domItem = &newItem;
   if (!domItem) {
     error.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
     return nullptr;
   }
   if (index >= LengthNoFlush()) {
     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return nullptr;
   }
@@ -312,17 +312,17 @@ DOMSVGLengthList::ReplaceItem(nsIDOMSVGL
 
   // This MUST come after the ToSVGPoint() call, otherwise that call
   // would end up reading bad data from InternalList()!
   domItem->InsertingIntoList(this, AttrEnum(), index, IsAnimValList());
 
   return domItem.forget();
 }
 
-already_AddRefed<nsIDOMSVGLength>
+already_AddRefed<DOMSVGLength>
 DOMSVGLengthList::RemoveItem(uint32_t index,
                              ErrorResult& error)
 {
   if (IsAnimValList()) {
     error.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
     return nullptr;
   }
 
@@ -333,39 +333,39 @@ DOMSVGLengthList::RemoveItem(uint32_t in
 
   AutoChangeLengthListNotifier notifier(this);
   // Now that we know we're removing, keep animVal list in sync as necessary.
   // Do this *before* touching InternalList() so the removed item can get its
   // internal value.
   MaybeRemoveItemFromAnimValListAt(index);
 
   // We have to return the removed item, so get it, creating it if necessary:
-  nsCOMPtr<nsIDOMSVGLength> result = GetItemAt(index);
+  nsCOMPtr<DOMSVGLength> result = GetItemAt(index);
 
   // Notify the DOM item of removal *before* modifying the lists so that the
   // DOM item can copy its *old* value:
   mItems[index]->RemovingFromList();
 
   InternalList().RemoveItem(index);
   mItems.RemoveElementAt(index);
 
   UpdateListIndicesFromIndex(mItems, index);
 
   return result.forget();
 }
 
-already_AddRefed<nsIDOMSVGLength>
+already_AddRefed<DOMSVGLength>
 DOMSVGLengthList::GetItemAt(uint32_t aIndex)
 {
   MOZ_ASSERT(aIndex < mItems.Length());
 
   if (!mItems[aIndex]) {
     mItems[aIndex] = new DOMSVGLength(this, AttrEnum(), aIndex, IsAnimValList());
   }
-  nsRefPtr<nsIDOMSVGLength> result = mItems[aIndex];
+  nsRefPtr<DOMSVGLength> result = mItems[aIndex];
   return result.forget();
 }
 
 void
 DOMSVGLengthList::MaybeInsertNullInAnimValListAt(uint32_t aIndex)
 {
   NS_ABORT_IF_FALSE(!IsAnimValList(), "call from baseVal to animVal");
 
--- a/content/svg/content/src/DOMSVGLengthList.h
+++ b/content/svg/content/src/DOMSVGLengthList.h
@@ -10,17 +10,16 @@
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDebug.h"
 #include "nsTArray.h"
 #include "SVGLengthList.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 
-class nsIDOMSVGLength;
 class nsSVGElement;
 
 namespace mozilla {
 
 class DOMSVGLength;
 
 /**
  * Class DOMSVGLengthList
@@ -104,32 +103,32 @@ public:
   uint32_t NumberOfItems() const
   {
     if (IsAnimValList()) {
       Element()->FlushAnimations();
     }
     return LengthNoFlush();
   }
   void Clear(ErrorResult& aError);
-  already_AddRefed<nsIDOMSVGLength> Initialize(nsIDOMSVGLength *newItem,
+  already_AddRefed<DOMSVGLength> Initialize(DOMSVGLength& newItem,
+                                            ErrorResult& error);
+  already_AddRefed<DOMSVGLength> GetItem(uint32_t index,
+                                         ErrorResult& error);
+  already_AddRefed<DOMSVGLength> IndexedGetter(uint32_t index, bool& found,
                                                ErrorResult& error);
-  already_AddRefed<nsIDOMSVGLength> GetItem(uint32_t index,
-                                            ErrorResult& error);
-  already_AddRefed<nsIDOMSVGLength> IndexedGetter(uint32_t index, bool& found,
+  already_AddRefed<DOMSVGLength> InsertItemBefore(DOMSVGLength& newItem,
+                                                  uint32_t index,
                                                   ErrorResult& error);
-  already_AddRefed<nsIDOMSVGLength> InsertItemBefore(nsIDOMSVGLength *newItem,
-                                                     uint32_t index,
-                                                     ErrorResult& error);
-  already_AddRefed<nsIDOMSVGLength> ReplaceItem(nsIDOMSVGLength *newItem,
-                                                uint32_t index,
-                                                ErrorResult& error);
-  already_AddRefed<nsIDOMSVGLength> RemoveItem(uint32_t index,
-                                               ErrorResult& error);
-  already_AddRefed<nsIDOMSVGLength> AppendItem(nsIDOMSVGLength *newItem,
-                                               ErrorResult& error)
+  already_AddRefed<DOMSVGLength> ReplaceItem(DOMSVGLength& newItem,
+                                             uint32_t index,
+                                             ErrorResult& error);
+  already_AddRefed<DOMSVGLength> RemoveItem(uint32_t index,
+                                            ErrorResult& error);
+  already_AddRefed<DOMSVGLength> AppendItem(DOMSVGLength& newItem,
+                                            ErrorResult& error)
   {
     return InsertItemBefore(newItem, LengthNoFlush(), error);
   }
   uint32_t Length() const
   {
     return NumberOfItems();
   }
 
@@ -159,18 +158,18 @@ private:
    *
    * To simplify the code we just have this one method for obtaining both
    * baseVal and animVal internal lists. This means that animVal lists don't
    * get const protection, but our setter methods guard against changing
    * animVal lists.
    */
   SVGLengthList& InternalList() const;
 
-  /// Returns the nsIDOMSVGLength at aIndex, creating it if necessary.
-  already_AddRefed<nsIDOMSVGLength> GetItemAt(uint32_t aIndex);
+  /// Returns the DOMSVGLength at aIndex, creating it if necessary.
+  already_AddRefed<DOMSVGLength> GetItemAt(uint32_t aIndex);
 
   void MaybeInsertNullInAnimValListAt(uint32_t aIndex);
   void MaybeRemoveItemFromAnimValListAt(uint32_t aIndex);
 
   // Weak refs to our DOMSVGLength items. The items are friends and take care
   // of clearing our pointer to them when they die.
   FallibleTArray<DOMSVGLength*> mItems;
 
--- a/content/svg/content/src/SVGAnimatedLength.cpp
+++ b/content/svg/content/src/SVGAnimatedLength.cpp
@@ -1,41 +1,42 @@
 /* -*- 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/SVGAnimatedLength.h"
 #include "mozilla/dom/SVGAnimatedLengthBinding.h"
 #include "nsSVGLength2.h"
+#include "DOMSVGLength.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(SVGAnimatedLength, mSVGElement)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(SVGAnimatedLength, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(SVGAnimatedLength, Release)
 
 JSObject*
 SVGAnimatedLength::WrapObject(JSContext* aCx)
 {
   return SVGAnimatedLengthBinding::Wrap(aCx, this);
 }
 
-already_AddRefed<nsIDOMSVGLength>
+already_AddRefed<DOMSVGLength>
 SVGAnimatedLength::BaseVal()
 {
-  nsRefPtr<nsIDOMSVGLength> angle;
+  nsRefPtr<DOMSVGLength> angle;
   mVal->ToDOMBaseVal(getter_AddRefs(angle), mSVGElement);
   return angle.forget();
 }
 
-already_AddRefed<nsIDOMSVGLength>
+already_AddRefed<DOMSVGLength>
 SVGAnimatedLength::AnimVal()
 {
-  nsRefPtr<nsIDOMSVGLength> angle;
+  nsRefPtr<DOMSVGLength> angle;
   mVal->ToDOMAnimVal(getter_AddRefs(angle), mSVGElement);
   return angle.forget();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGAnimatedLength.h
+++ b/content/svg/content/src/SVGAnimatedLength.h
@@ -5,19 +5,21 @@
 
 #ifndef mozilla_dom_SVGAnimatedLength_h
 #define mozilla_dom_SVGAnimatedLength_h
 
 #include "mozilla/Attributes.h"
 #include "nsSVGElement.h"
 
 class nsSVGLength2;
-class nsIDOMSVGLength;
 
 namespace mozilla {
+
+class DOMSVGLength;
+
 namespace dom {
 
 class SVGAnimatedLength MOZ_FINAL : public nsWrapperCache
 {
 public:
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(SVGAnimatedLength)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(SVGAnimatedLength)
 
@@ -25,18 +27,18 @@ public:
     : mVal(aVal), mSVGElement(aSVGElement)
   { SetIsDOMBinding(); }
 
   ~SVGAnimatedLength();
 
   // WebIDL
   nsSVGElement* GetParentObject() { return mSVGElement; }
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
-  already_AddRefed<nsIDOMSVGLength> BaseVal();
-  already_AddRefed<nsIDOMSVGLength> AnimVal();
+  already_AddRefed<DOMSVGLength> BaseVal();
+  already_AddRefed<DOMSVGLength> AnimVal();
 
 protected:
   nsSVGLength2* mVal; // kept alive because it belongs to content
   nsRefPtr<nsSVGElement> mSVGElement;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGAttrValueWrapper.h
+++ b/content/svg/content/src/SVGAttrValueWrapper.h
@@ -7,17 +7,17 @@
 #ifndef MOZILLA_SVGATTRVALUEWRAPPER_H__
 #define MOZILLA_SVGATTRVALUEWRAPPER_H__
 
 /**
  * Utility wrapper for handling SVG types used inside nsAttrValue so that these
  * types don't need to be exported outside the SVG module.
  */
 
-#include "nsString.h"
+#include "nsStringGlue.h"
 
 class nsSVGAngle;
 class nsSVGIntegerPair;
 class nsSVGLength2;
 class nsSVGNumberPair;
 class nsSVGViewBox;
 
 namespace mozilla {
--- a/content/svg/content/src/SVGEllipseElement.cpp
+++ b/content/svg/content/src/SVGEllipseElement.cpp
@@ -93,18 +93,18 @@ SVGEllipseElement::GetLengthInfo()
 // nsSVGPathGeometryElement methods
 
 void
 SVGEllipseElement::ConstructPath(gfxContext *aCtx)
 {
   if (!aCtx->IsCairo()) {
     RefPtr<Path> path = BuildPath();
     if (path) {
-      gfxPath gfxpath(path);
-      aCtx->SetPath(&gfxpath);
+      nsRefPtr<gfxPath> gfxpath = new gfxPath(path);
+      aCtx->SetPath(gfxpath);
     }
     return;
   }
 
   float x, y, rx, ry;
 
   GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
 
--- a/content/svg/content/src/SVGSVGElement.cpp
+++ b/content/svg/content/src/SVGSVGElement.cpp
@@ -382,20 +382,20 @@ SVGSVGElement::DeselectAll()
 
 already_AddRefed<nsIDOMSVGNumber>
 SVGSVGElement::CreateSVGNumber()
 {
   nsCOMPtr<nsIDOMSVGNumber> number = new DOMSVGNumber();
   return number.forget();
 }
 
-already_AddRefed<nsIDOMSVGLength>
+already_AddRefed<DOMSVGLength>
 SVGSVGElement::CreateSVGLength()
 {
-  nsCOMPtr<nsIDOMSVGLength> length = new DOMSVGLength();
+  nsCOMPtr<DOMSVGLength> length = new DOMSVGLength();
   return length.forget();
 }
 
 already_AddRefed<SVGAngle>
 SVGSVGElement::CreateSVGAngle()
 {
   nsSVGAngle* angle = new nsSVGAngle();
   angle->Init();
--- a/content/svg/content/src/SVGSVGElement.h
+++ b/content/svg/content/src/SVGSVGElement.h
@@ -25,16 +25,17 @@ class nsIDOMSVGNumber;
 class nsSMILTimeContainer;
 class nsSVGOuterSVGFrame;
 class nsSVGInnerSVGFrame;
 class nsSVGImageFrame;
 
 namespace mozilla {
 class AutoSVGRenderingState;
 class DOMSVGAnimatedPreserveAspectRatio;
+class DOMSVGLength;
 class EventChainPreVisitor;
 class SVGFragmentIdentifier;
 
 namespace dom {
 class SVGAngle;
 class SVGAnimatedRect;
 class SVGMatrix;
 class SVGTransform;
@@ -234,17 +235,17 @@ public:
   void ForceRedraw(ErrorResult& rv);
   void PauseAnimations();
   void UnpauseAnimations();
   bool AnimationsPaused();
   float GetCurrentTime();
   void SetCurrentTime(float seconds);
   void DeselectAll();
   already_AddRefed<nsIDOMSVGNumber> CreateSVGNumber();
-  already_AddRefed<nsIDOMSVGLength> CreateSVGLength();
+  already_AddRefed<DOMSVGLength> CreateSVGLength();
   already_AddRefed<SVGAngle> CreateSVGAngle();
   already_AddRefed<nsISVGPoint> CreateSVGPoint();
   already_AddRefed<SVGMatrix> CreateSVGMatrix();
   already_AddRefed<SVGIRect> CreateSVGRect();
   already_AddRefed<SVGTransform> CreateSVGTransform();
   already_AddRefed<SVGTransform> CreateSVGTransformFromMatrix(SVGMatrix& matrix);
   using nsINode::GetElementById; // This does what we want
   already_AddRefed<SVGAnimatedRect> ViewBox();
--- a/content/svg/content/src/nsSVGLength2.cpp
+++ b/content/svg/content/src/nsSVGLength2.cpp
@@ -10,42 +10,21 @@
 #include "mozilla/dom/SVGSVGElement.h"
 #include "nsContentUtils.h" // NS_ENSURE_FINITE
 #include "nsIFrame.h"
 #include "nsSMILFloatType.h"
 #include "nsSMILValue.h"
 #include "nsSVGAttrTearoffTable.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsTextFormatter.h"
+#include "DOMSVGLength.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGLength2::DOMBaseVal, mSVGElement)
-
-NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGLength2::DOMAnimVal, mSVGElement)
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGLength2::DOMBaseVal)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGLength2::DOMBaseVal)
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGLength2::DOMAnimVal)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGLength2::DOMAnimVal)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGLength2::DOMBaseVal)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLength)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLength)
-NS_INTERFACE_MAP_END
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGLength2::DOMAnimVal)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLength)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLength)
-NS_INTERFACE_MAP_END
-
 static nsIAtom** const unitMap[] =
 {
   nullptr, /* SVG_LENGTHTYPE_UNKNOWN */
   nullptr, /* SVG_LENGTHTYPE_NUMBER */
   &nsGkAtoms::percentage,
   &nsGkAtoms::em,
   &nsGkAtoms::ex,
   &nsGkAtoms::px,
@@ -53,20 +32,16 @@ static nsIAtom** const unitMap[] =
   &nsGkAtoms::mm,
   &nsGkAtoms::in,
   &nsGkAtoms::pt,
   &nsGkAtoms::pc
 };
 
 static nsSVGAttrTearoffTable<nsSVGLength2, SVGAnimatedLength>
   sSVGAnimatedLengthTearoffTable;
-static nsSVGAttrTearoffTable<nsSVGLength2, nsSVGLength2::DOMBaseVal>
-  sBaseSVGLengthTearoffTable;
-static nsSVGAttrTearoffTable<nsSVGLength2, nsSVGLength2::DOMAnimVal>
-  sAnimSVGLengthTearoffTable;
 
 /* Helper functions */
 
 static bool
 IsValidUnitType(uint16_t unit)
 {
   if (unit > nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN &&
       unit <= nsIDOMSVGLength::SVG_LENGTHTYPE_PC)
@@ -340,53 +315,35 @@ nsSVGLength2::NewValueSpecifiedUnits(uin
   else {
     aSVGElement->AnimationNeedsResample();
   }
   aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
   return NS_OK;
 }
 
 nsresult
-nsSVGLength2::ToDOMBaseVal(nsIDOMSVGLength **aResult, nsSVGElement *aSVGElement)
+nsSVGLength2::ToDOMBaseVal(DOMSVGLength **aResult, nsSVGElement *aSVGElement)
 {
-  nsRefPtr<DOMBaseVal> domBaseVal =
-    sBaseSVGLengthTearoffTable.GetTearoff(this);
-  if (!domBaseVal) {
-    domBaseVal = new DOMBaseVal(this, aSVGElement);
-    sBaseSVGLengthTearoffTable.AddTearoff(this, domBaseVal);
-  }
+  nsRefPtr<DOMSVGLength> domBaseVal =
+    DOMSVGLength::GetTearOff(this, aSVGElement, false);
 
   domBaseVal.forget(aResult);
   return NS_OK;
 }
 
-nsSVGLength2::DOMBaseVal::~DOMBaseVal()
+nsresult
+nsSVGLength2::ToDOMAnimVal(DOMSVGLength **aResult, nsSVGElement *aSVGElement)
 {
-  sBaseSVGLengthTearoffTable.RemoveTearoff(mVal);
-}
-
-nsresult
-nsSVGLength2::ToDOMAnimVal(nsIDOMSVGLength **aResult, nsSVGElement *aSVGElement)
-{
-  nsRefPtr<DOMAnimVal> domAnimVal =
-    sAnimSVGLengthTearoffTable.GetTearoff(this);
-  if (!domAnimVal) {
-    domAnimVal = new DOMAnimVal(this, aSVGElement);
-    sAnimSVGLengthTearoffTable.AddTearoff(this, domAnimVal);
-  }
+  nsRefPtr<DOMSVGLength> domAnimVal =
+    DOMSVGLength::GetTearOff(this, aSVGElement, true);
 
   domAnimVal.forget(aResult);
   return NS_OK;
 }
 
-nsSVGLength2::DOMAnimVal::~DOMAnimVal()
-{
-  sAnimSVGLengthTearoffTable.RemoveTearoff(mVal);
-}
-
 /* Implementation */
 
 nsresult
 nsSVGLength2::SetBaseValueString(const nsAString &aValueAsString,
                                  nsSVGElement *aSVGElement,
                                  bool aDoSetAttr)
 {
   float value;
--- a/content/svg/content/src/nsSVGLength2.h
+++ b/content/svg/content/src/nsSVGLength2.h
@@ -16,26 +16,28 @@
 #include "nsMathUtils.h"
 #include "nsSVGElement.h"
 #include "SVGContentUtils.h"
 
 class nsIFrame;
 class nsSMILValue;
 
 namespace mozilla {
+class DOMSVGLength;
 namespace dom {
 class SVGAnimatedLength;
 class SVGAnimationElement;
 class SVGSVGElement;
 }
 }
 
 class nsSVGLength2
 {
   friend class mozilla::dom::SVGAnimatedLength;
+  friend class mozilla::DOMSVGLength;
 public:
   void Init(uint8_t aCtxType = SVGContentUtils::XY,
             uint8_t aAttrEnum = 0xff,
             float aValue = 0,
             uint8_t aUnitType = nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER) {
     mAnimVal = mBaseVal = aValue;
     mSpecifiedUnitType = aUnitType;
     mAttrEnum = aAttrEnum;
@@ -126,128 +128,20 @@ private:
   void SetBaseValue(float aValue, nsSVGElement *aSVGElement, bool aDoSetAttr);
   void SetBaseValueInSpecifiedUnits(float aValue, nsSVGElement *aSVGElement,
                                     bool aDoSetAttr);
   void SetAnimValue(float aValue, nsSVGElement *aSVGElement);
   void SetAnimValueInSpecifiedUnits(float aValue, nsSVGElement *aSVGElement);
   nsresult NewValueSpecifiedUnits(uint16_t aUnitType, float aValue,
                                   nsSVGElement *aSVGElement);
   nsresult ConvertToSpecifiedUnits(uint16_t aUnitType, nsSVGElement *aSVGElement);
-  nsresult ToDOMBaseVal(nsIDOMSVGLength **aResult, nsSVGElement* aSVGElement);
-  nsresult ToDOMAnimVal(nsIDOMSVGLength **aResult, nsSVGElement* aSVGElement);
+  nsresult ToDOMBaseVal(mozilla::DOMSVGLength **aResult, nsSVGElement* aSVGElement);
+  nsresult ToDOMAnimVal(mozilla::DOMSVGLength **aResult, nsSVGElement* aSVGElement);
 
 public:
-  struct DOMBaseVal : public nsIDOMSVGLength
-  {
-    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-    NS_DECL_CYCLE_COLLECTION_CLASS(DOMBaseVal)
-
-    DOMBaseVal(nsSVGLength2* aVal, nsSVGElement *aSVGElement)
-      : mVal(aVal), mSVGElement(aSVGElement) {}
-    virtual ~DOMBaseVal();
-    
-    nsSVGLength2* mVal; // kept alive because it belongs to mSVGElement
-    nsRefPtr<nsSVGElement> mSVGElement;
-    
-    NS_IMETHOD GetUnitType(uint16_t* aResult) MOZ_OVERRIDE
-      { *aResult = mVal->mSpecifiedUnitType; return NS_OK; }
-
-    NS_IMETHOD GetValue(float* aResult) MOZ_OVERRIDE
-      { *aResult = mVal->GetBaseValue(mSVGElement); return NS_OK; }
-    NS_IMETHOD SetValue(float aValue) MOZ_OVERRIDE
-      {
-        if (!NS_finite(aValue)) {
-          return NS_ERROR_ILLEGAL_VALUE;
-        }
-        mVal->SetBaseValue(aValue, mSVGElement, true);
-        return NS_OK;
-      }
-
-    NS_IMETHOD GetValueInSpecifiedUnits(float* aResult) MOZ_OVERRIDE
-      { *aResult = mVal->mBaseVal; return NS_OK; }
-    NS_IMETHOD SetValueInSpecifiedUnits(float aValue) MOZ_OVERRIDE
-      {
-        if (!NS_finite(aValue)) {
-          return NS_ERROR_ILLEGAL_VALUE;
-        }
-        mVal->SetBaseValueInSpecifiedUnits(aValue, mSVGElement, true);
-        return NS_OK;
-      }
-
-    NS_IMETHOD SetValueAsString(const nsAString& aValue) MOZ_OVERRIDE
-      { return mVal->SetBaseValueString(aValue, mSVGElement, true); }
-    NS_IMETHOD GetValueAsString(nsAString& aValue) MOZ_OVERRIDE
-      { mVal->GetBaseValueString(aValue); return NS_OK; }
-
-    NS_IMETHOD NewValueSpecifiedUnits(uint16_t unitType,
-                                      float valueInSpecifiedUnits) MOZ_OVERRIDE
-      {
-        return mVal->NewValueSpecifiedUnits(unitType, valueInSpecifiedUnits,
-                                            mSVGElement); }
-
-    NS_IMETHOD ConvertToSpecifiedUnits(uint16_t unitType) MOZ_OVERRIDE
-      { return mVal->ConvertToSpecifiedUnits(unitType, mSVGElement); }
-  };
-
-  struct DOMAnimVal : public nsIDOMSVGLength
-  {
-    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-    NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimVal)
-
-    DOMAnimVal(nsSVGLength2* aVal, nsSVGElement *aSVGElement)
-      : mVal(aVal), mSVGElement(aSVGElement) {}
-    virtual ~DOMAnimVal();
-    
-    nsSVGLength2* mVal; // kept alive because it belongs to mSVGElement
-    nsRefPtr<nsSVGElement> mSVGElement;
-    
-    // Script may have modified animation parameters or timeline -- DOM getters
-    // need to flush any resample requests to reflect these modifications.
-    NS_IMETHOD GetUnitType(uint16_t* aResult) MOZ_OVERRIDE
-    {
-      mSVGElement->FlushAnimations();
-      *aResult = mVal->mSpecifiedUnitType;
-      return NS_OK;
-    }
-
-    NS_IMETHOD GetValue(float* aResult) MOZ_OVERRIDE
-    {
-      mSVGElement->FlushAnimations();
-      *aResult = mVal->GetAnimValue(mSVGElement);
-      return NS_OK;
-    }
-    NS_IMETHOD SetValue(float aValue) MOZ_OVERRIDE
-      { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
-
-    NS_IMETHOD GetValueInSpecifiedUnits(float* aResult) MOZ_OVERRIDE
-    {
-      mSVGElement->FlushAnimations();
-      *aResult = mVal->mAnimVal;
-      return NS_OK;
-    }
-    NS_IMETHOD SetValueInSpecifiedUnits(float aValue) MOZ_OVERRIDE
-      { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
-
-    NS_IMETHOD SetValueAsString(const nsAString& aValue) MOZ_OVERRIDE
-      { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
-    NS_IMETHOD GetValueAsString(nsAString& aValue) MOZ_OVERRIDE
-    {
-      mSVGElement->FlushAnimations();
-      mVal->GetAnimValueString(aValue);
-      return NS_OK;
-    }
-
-    NS_IMETHOD NewValueSpecifiedUnits(uint16_t unitType,
-                                      float valueInSpecifiedUnits) MOZ_OVERRIDE
-      { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
-
-    NS_IMETHOD ConvertToSpecifiedUnits(uint16_t unitType) MOZ_OVERRIDE
-      { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
-  };
-
   struct SMILLength : public nsISMILAttr
   {
   public:
     SMILLength(nsSVGLength2* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
 
     // These will stay alive because a nsISMILAttr only lives as long
     // as the Compositing step, and DOM elements don't get a chance to
new file mode 100644
--- /dev/null
+++ b/content/xml/document/crashtests/994740-1.xhtml
@@ -0,0 +1,15 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script>
+<![CDATA[
+
+function boom()
+{
+    document.createElement("head").innerHTML = "<";
+}
+
+]]>
+</script></head>
+
+<body onload="boom();"></body>
+</html>
--- a/content/xml/document/crashtests/crashtests.list
+++ b/content/xml/document/crashtests/crashtests.list
@@ -1,7 +1,8 @@
 load 136896-1.xml
 load 185285-1.xml
 load 382636-1.xml
 load 382636-2.svg
 load 382636-3.xhtml
 load 382636-4.xul # Throws (bug 455856)
 load 431703-1.xhtml
+load 994740-1.xhtml
--- a/content/xml/document/src/nsXMLFragmentContentSink.cpp
+++ b/content/xml/document/src/nsXMLFragmentContentSink.cpp
@@ -357,16 +357,18 @@ nsXMLFragmentContentSink::FinishFragment
   *aFragment = nullptr;
   mTargetDocument = nullptr;
   mNodeInfoManager = nullptr;
   mScriptLoader = nullptr;
   mCSSLoader = nullptr;
   mContentStack.Clear();
   mDocumentURI = nullptr;
   mDocShell = nullptr;
+  mDocElement = nullptr;
+  mCurrentHead = nullptr;
   if (mParseError) {
     //XXX PARSE_ERR from DOM3 Load and Save would be more appropriate
     mRoot = nullptr;
     mParseError = false;
     return NS_ERROR_DOM_SYNTAX_ERR;
   } else if (mRoot) {
     nsresult rv = CallQueryInterface(mRoot, aFragment);
     mRoot = nullptr;
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -2331,16 +2331,86 @@ onInstallSuccessAck: function onInstallS
     // For packaged apps, keep the update manifest distinct from the app manifest.
     let manifestName = aIsPackage ? "update.webapp" : "manifest.webapp";
 
     let dir = this._getAppDir(aId).path;
     let manFile = OS.Path.join(dir, manifestName);
     this._writeFile(manFile, JSON.stringify(aJsonManifest));
   },
 
+  // Add an app that is already installed to the registry.
+  addInstalledApp: Task.async(function*(aApp, aManifest, aUpdateManifest) {
+    if (this.getAppLocalIdByManifestURL(aApp.manifestURL) !=
+        Ci.nsIScriptSecurityManager.NO_APP_ID) {
+      return;
+    }
+
+    let app = AppsUtils.cloneAppObject(aApp);
+
+    if (!AppsUtils.checkManifest(aManifest, app) ||
+        (aUpdateManifest && !AppsUtils.checkManifest(aUpdateManifest, app))) {
+      return;
+    }
+
+    app.name = aManifest.name;
+
+    app.csp = aManifest.csp || "";
+
+    app.appStatus = AppsUtils.getAppManifestStatus(aManifest);
+
+    app.removable = true;
+
+    // Reuse the app ID if the scheme is "app".
+    let uri = Services.io.newURI(app.origin, null, null);
+    if (uri.scheme == "app") {
+      app.id = uri.host;
+    } else {
+      app.id = this.makeAppId();
+    }
+
+    app.localId = this._nextLocalId();
+
+    app.basePath = OS.Path.dirname(this.appsFile);
+
+    app.progress = 0.0;
+    app.installState = "installed";
+    app.downloadAvailable = false;
+    app.downloading = false;
+    app.readyToApplyDownload = false;
+
+    if (aUpdateManifest && aUpdateManifest.size) {
+      app.downloadSize = aUpdateManifest.size;
+    }
+
+    app.manifestHash = AppsUtils.computeHash(JSON.stringify(aUpdateManifest ||
+                                                            aManifest));
+
+    let zipFile = WebappOSUtils.getPackagePath(app);
+    app.packageHash = yield this._computeFileHash(zipFile);
+
+    app.role = aManifest.role || "";
+
+    app.redirects = this.sanitizeRedirects(aManifest.redirects);
+
+    this.webapps[app.id] = app;
+
+    // Store the manifest in the manifest cache, so we don't need to re-read it
+    this._manifestCache[app.id] = app.manifest;
+
+    // Store the manifest and the updateManifest.
+    this._writeManifestFile(app.id, false, aManifest);
+    if (aUpdateManifest) {
+      this._writeManifestFile(app.id, true, aUpdateManifest);
+    }
+
+    this._saveApps().then(() => {
+      this.broadcastMessage("Webapps:AddApp", { id: app.id, app: app });
+    });
+  }),
+
   confirmInstall: function(aData, aProfileDir, aInstallSuccessCallback) {
     debug("confirmInstall");
 
     let origin = Services.io.newURI(aData.app.origin, null, null);
     let id = this._appIdForManifestURL(aData.app.manifestURL);
     let manifestURL = origin.resolve(aData.app.manifestURL);
     let localId = this.getAppLocalIdByManifestURL(manifestURL);
 
--- a/dom/audiochannel/AudioChannelAgent.cpp
+++ b/dom/audiochannel/AudioChannelAgent.cpp
@@ -79,32 +79,32 @@ nsresult
 AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType,
                                 nsIAudioChannelAgentCallback *aCallback,
                                 bool aUseWeakRef, bool aWithVideo)
 {
   // We need the window only for IPC.
   MOZ_ASSERT(aWindow || XRE_GetProcessType() == GeckoProcessType_Default);
 
   // We syncd the enum of channel type between nsIAudioChannelAgent.idl and
-  // AudioChannelCommon.h the same.
-  static_assert(static_cast<AudioChannelType>(AUDIO_AGENT_CHANNEL_NORMAL) ==
-                AUDIO_CHANNEL_NORMAL &&
-                static_cast<AudioChannelType>(AUDIO_AGENT_CHANNEL_CONTENT) ==
-                AUDIO_CHANNEL_CONTENT &&
-                static_cast<AudioChannelType>(AUDIO_AGENT_CHANNEL_NOTIFICATION) ==
-                AUDIO_CHANNEL_NOTIFICATION &&
-                static_cast<AudioChannelType>(AUDIO_AGENT_CHANNEL_ALARM) ==
-                AUDIO_CHANNEL_ALARM &&
-                static_cast<AudioChannelType>(AUDIO_AGENT_CHANNEL_TELEPHONY) ==
-                AUDIO_CHANNEL_TELEPHONY &&
-                static_cast<AudioChannelType>(AUDIO_AGENT_CHANNEL_RINGER) ==
-                AUDIO_CHANNEL_RINGER &&
-                static_cast<AudioChannelType>(AUDIO_AGENT_CHANNEL_PUBLICNOTIFICATION) ==
-                AUDIO_CHANNEL_PUBLICNOTIFICATION,
-                "Enum of channel on nsIAudioChannelAgent.idl should be the same with AudioChannelCommon.h");
+  // AudioChannelBinding.h the same.
+  MOZ_ASSERT(static_cast<AudioChannel>(AUDIO_AGENT_CHANNEL_NORMAL) ==
+             AudioChannel::Normal &&
+             static_cast<AudioChannel>(AUDIO_AGENT_CHANNEL_CONTENT) ==
+             AudioChannel::Content &&
+             static_cast<AudioChannel>(AUDIO_AGENT_CHANNEL_NOTIFICATION) ==
+             AudioChannel::Notification &&
+             static_cast<AudioChannel>(AUDIO_AGENT_CHANNEL_ALARM) ==
+             AudioChannel::Alarm &&
+             static_cast<AudioChannel>(AUDIO_AGENT_CHANNEL_TELEPHONY) ==
+             AudioChannel::Telephony &&
+             static_cast<AudioChannel>(AUDIO_AGENT_CHANNEL_RINGER) ==
+             AudioChannel::Ringer &&
+             static_cast<AudioChannel>(AUDIO_AGENT_CHANNEL_PUBLICNOTIFICATION) ==
+             AudioChannel::Publicnotification,
+             "Enum of channel on nsIAudioChannelAgent.idl should be the same with AudioChannelBinding.h");
 
   if (mAudioChannelType != AUDIO_AGENT_CHANNEL_ERROR ||
       aChannelType > AUDIO_AGENT_CHANNEL_PUBLICNOTIFICATION ||
       aChannelType < AUDIO_AGENT_CHANNEL_NORMAL) {
     return NS_ERROR_FAILURE;
   }
 
   mWindow = aWindow;
@@ -126,17 +126,17 @@ NS_IMETHODIMP AudioChannelAgent::StartPl
 {
   AudioChannelService *service = AudioChannelService::GetAudioChannelService();
   if (mAudioChannelType == AUDIO_AGENT_CHANNEL_ERROR ||
       service == nullptr || mIsRegToService) {
     return NS_ERROR_FAILURE;
   }
 
   service->RegisterAudioChannelAgent(this,
-    static_cast<AudioChannelType>(mAudioChannelType), mWithVideo);
+    static_cast<AudioChannel>(mAudioChannelType), mWithVideo);
   *_retval = service->GetState(this, !mVisible);
   mIsRegToService = true;
   return NS_OK;
 }
 
 /* void stopPlaying (); */
 NS_IMETHODIMP AudioChannelAgent::StopPlaying(void)
 {
--- a/dom/audiochannel/AudioChannelCommon.h
+++ b/dom/audiochannel/AudioChannelCommon.h
@@ -5,30 +5,16 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_audiochannelcommon_h__
 #define mozilla_dom_audiochannelcommon_h__
 
 namespace mozilla {
 namespace dom {
 
-// The audio channel. Read the nsIHTMLMediaElement.idl for a description
-// about this attribute.
-enum AudioChannelType {
-  AUDIO_CHANNEL_DEFAULT = -1,
-  AUDIO_CHANNEL_NORMAL = 0,
-  AUDIO_CHANNEL_CONTENT,
-  AUDIO_CHANNEL_NOTIFICATION,
-  AUDIO_CHANNEL_ALARM,
-  AUDIO_CHANNEL_TELEPHONY,
-  AUDIO_CHANNEL_RINGER,
-  AUDIO_CHANNEL_PUBLICNOTIFICATION,
-  AUDIO_CHANNEL_LAST
-};
-
 enum AudioChannelState {
   AUDIO_CHANNEL_STATE_NORMAL = 0,
   AUDIO_CHANNEL_STATE_MUTED,
   AUDIO_CHANNEL_STATE_FADED,
   AUDIO_CHANNEL_STATE_LAST
 };
 
 } // namespace dom
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -32,16 +32,28 @@
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::hal;
 
 StaticRefPtr<AudioChannelService> gAudioChannelService;
 
+// Mappings from 'mozaudiochannel' attribute strings to an enumeration.
+static const nsAttrValue::EnumTable kMozAudioChannelAttributeTable[] = {
+  { "normal",             (int16_t)AudioChannel::Normal },
+  { "content",            (int16_t)AudioChannel::Content },
+  { "notification",       (int16_t)AudioChannel::Notification },
+  { "alarm",              (int16_t)AudioChannel::Alarm },
+  { "telephony",          (int16_t)AudioChannel::Telephony },
+  { "ringer",             (int16_t)AudioChannel::Ringer },
+  { "publicnotification", (int16_t)AudioChannel::Publicnotification },
+  { nullptr }
+};
+
 // static
 AudioChannelService*
 AudioChannelService::GetAudioChannelService()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
     return AudioChannelServiceChild::GetAudioChannelService();
@@ -70,18 +82,18 @@ AudioChannelService::Shutdown()
   if (gAudioChannelService) {
     gAudioChannelService = nullptr;
   }
 }
 
 NS_IMPL_ISUPPORTS2(AudioChannelService, nsIObserver, nsITimerCallback)
 
 AudioChannelService::AudioChannelService()
-: mCurrentHigherChannel(AUDIO_CHANNEL_LAST)
-, mCurrentVisibleHigherChannel(AUDIO_CHANNEL_LAST)
+: mCurrentHigherChannel(INT32_MAX)
+, mCurrentVisibleHigherChannel(INT32_MAX)
 , mPlayableHiddenContentChildID(CONTENT_PROCESS_ID_UNKNOWN)
 , mDisabled(false)
 , mDefChannelChildID(CONTENT_PROCESS_ID_UNKNOWN)
 {
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->AddObserver(this, "ipc:content-shutdown", false);
@@ -95,62 +107,62 @@ AudioChannelService::AudioChannelService
 }
 
 AudioChannelService::~AudioChannelService()
 {
 }
 
 void
 AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
-                                               AudioChannelType aType,
+                                               AudioChannel aChannel,
                                                bool aWithVideo)
 {
   if (mDisabled) {
     return;
   }
 
-  MOZ_ASSERT(aType != AUDIO_CHANNEL_DEFAULT);
-
-  AudioChannelAgentData* data = new AudioChannelAgentData(aType,
+  AudioChannelAgentData* data = new AudioChannelAgentData(aChannel,
                                 true /* aElementHidden */,
                                 AUDIO_CHANNEL_STATE_MUTED /* aState */,
                                 aWithVideo);
   mAgents.Put(aAgent, data);
-  RegisterType(aType, CONTENT_PROCESS_ID_MAIN, aWithVideo);
+  RegisterType(aChannel, CONTENT_PROCESS_ID_MAIN, aWithVideo);
 
   // If this is the first agent for this window, we must notify the observers.
   uint32_t count = CountWindow(aAgent->Window());
   if (count == 1) {
     nsCOMPtr<nsIObserverService> observerService =
       services::GetObserverService();
     if (observerService) {
       observerService->NotifyObservers(ToSupports(aAgent->Window()),
                                        "media-playback",
                                        NS_LITERAL_STRING("active").get());
     }
   }
 }
 
 void
-AudioChannelService::RegisterType(AudioChannelType aType, uint64_t aChildID, bool aWithVideo)
+AudioChannelService::RegisterType(AudioChannel aChannel, uint64_t aChildID,
+                                  bool aWithVideo)
 {
   if (mDisabled) {
     return;
   }
 
-  AudioChannelInternalType type = GetInternalType(aType, true);
+  AudioChannelInternalType type = GetInternalType(aChannel, true);
   mChannelCounters[type].AppendElement(aChildID);
 
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     // Since there is another telephony registered, we can unregister old one
     // immediately.
-    if (mDeferTelChannelTimer && aType == AUDIO_CHANNEL_TELEPHONY) {
+    if (mDeferTelChannelTimer && aChannel == AudioChannel::Telephony) {
       mDeferTelChannelTimer->Cancel();
       mDeferTelChannelTimer = nullptr;
-      UnregisterTypeInternal(aType, mTimerElementHidden, mTimerChildID, false);
+      UnregisterTypeInternal(aChannel, mTimerElementHidden, mTimerChildID,
+                             false);
     }
 
     if (aWithVideo) {
       mWithVideoChildIDs.AppendElement(aChildID);
     }
 
     // No hidden content channel can be playable if there is a content channel
     // in foreground (bug 855208), nor if there is a normal channel with video
@@ -181,17 +193,17 @@ AudioChannelService::UnregisterAudioChan
   if (mDisabled) {
     return;
   }
 
   nsAutoPtr<AudioChannelAgentData> data;
   mAgents.RemoveAndForget(aAgent, data);
 
   if (data) {
-    UnregisterType(data->mType, data->mElementHidden,
+    UnregisterType(data->mChannel, data->mElementHidden,
                    CONTENT_PROCESS_ID_MAIN, data->mWithVideo);
   }
 #ifdef MOZ_WIDGET_GONK
   bool active = AnyAudioChannelIsActive();
   for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
     mSpeakerManager[i]->SetAudioChannelActive(active);
   }
 #endif
@@ -205,84 +217,84 @@ AudioChannelService::UnregisterAudioChan
       observerService->NotifyObservers(ToSupports(aAgent->Window()),
                                        "media-playback",
                                        NS_LITERAL_STRING("inactive").get());
     }
   }
 }
 
 void
-AudioChannelService::UnregisterType(AudioChannelType aType,
+AudioChannelService::UnregisterType(AudioChannel aChannel,
                                     bool aElementHidden,
                                     uint64_t aChildID,
                                     bool aWithVideo)
 {
   if (mDisabled) {
     return;
   }
 
   // There are two reasons to defer the decrease of telephony channel.
   // 1. User can have time to remove device from his ear before music resuming.
   // 2. Give BT SCO to be disconnected before starting to connect A2DP.
   if (XRE_GetProcessType() == GeckoProcessType_Default &&
-      aType == AUDIO_CHANNEL_TELEPHONY &&
+      aChannel == AudioChannel::Telephony &&
       (mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY_HIDDEN].Length() +
        mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY].Length()) == 1) {
     mTimerElementHidden = aElementHidden;
     mTimerChildID = aChildID;
     mDeferTelChannelTimer = do_CreateInstance("@mozilla.org/timer;1");
     mDeferTelChannelTimer->InitWithCallback(this, 1500, nsITimer::TYPE_ONE_SHOT);
     return;
   }
 
-  UnregisterTypeInternal(aType, aElementHidden, aChildID, aWithVideo);
+  UnregisterTypeInternal(aChannel, aElementHidden, aChildID, aWithVideo);
 }
 
 void
-AudioChannelService::UnregisterTypeInternal(AudioChannelType aType,
+AudioChannelService::UnregisterTypeInternal(AudioChannel aChannel,
                                             bool aElementHidden,
                                             uint64_t aChildID,
                                             bool aWithVideo)
 {
   // The array may contain multiple occurrence of this appId but
   // this should remove only the first one.
-  AudioChannelInternalType type = GetInternalType(aType, aElementHidden);
+  AudioChannelInternalType type = GetInternalType(aChannel, aElementHidden);
   MOZ_ASSERT(mChannelCounters[type].Contains(aChildID));
   mChannelCounters[type].RemoveElement(aChildID);
 
   // In order to avoid race conditions, it's safer to notify any existing
   // agent any time a new one is registered.
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     // No hidden content channel is playable if the original playable hidden
     // process does not need to play audio from background anymore.
-    if (aType == AUDIO_CHANNEL_CONTENT &&
+    if (aChannel == AudioChannel::Content &&
         mPlayableHiddenContentChildID == aChildID &&
         !mChannelCounters[AUDIO_CHANNEL_INT_CONTENT_HIDDEN].Contains(aChildID)) {
       mPlayableHiddenContentChildID = CONTENT_PROCESS_ID_UNKNOWN;
     }
 
     if (aWithVideo) {
       MOZ_ASSERT(mWithVideoChildIDs.Contains(aChildID));
       mWithVideoChildIDs.RemoveElement(aChildID);
     }
 
     SendAudioChannelChangedNotification(aChildID);
     Notify();
   }
 }
 
 void
-AudioChannelService::UpdateChannelType(AudioChannelType aType,
+AudioChannelService::UpdateChannelType(AudioChannel aChannel,
                                        uint64_t aChildID,
                                        bool aElementHidden,
                                        bool aElementWasHidden)
 {
   // Calculate the new and old internal type and update the hashtable if needed.
-  AudioChannelInternalType newType = GetInternalType(aType, aElementHidden);
-  AudioChannelInternalType oldType = GetInternalType(aType, aElementWasHidden);
+  AudioChannelInternalType newType = GetInternalType(aChannel, aElementHidden);
+  AudioChannelInternalType oldType = GetInternalType(aChannel, aElementWasHidden);
 
   if (newType != oldType) {
     mChannelCounters[newType].AppendElement(aChildID);
     MOZ_ASSERT(mChannelCounters[oldType].Contains(aChildID));
     mChannelCounters[oldType].RemoveElement(aChildID);
   }
 
   // No hidden content channel can be playable if there is a content channel
@@ -310,34 +322,36 @@ AudioChannelService::GetState(AudioChann
   if (!mAgents.Get(aAgent, &data)) {
     return AUDIO_CHANNEL_STATE_MUTED;
   }
 
   bool oldElementHidden = data->mElementHidden;
   // Update visibility.
   data->mElementHidden = aElementHidden;
 
-  data->mState = GetStateInternal(data->mType, CONTENT_PROCESS_ID_MAIN,
+  data->mState = GetStateInternal(data->mChannel, CONTENT_PROCESS_ID_MAIN,
                                 aElementHidden, oldElementHidden);
   return data->mState;
 }
 
 AudioChannelState
-AudioChannelService::GetStateInternal(AudioChannelType aType, uint64_t aChildID,
-                                      bool aElementHidden, bool aElementWasHidden)
+AudioChannelService::GetStateInternal(AudioChannel aChannel, uint64_t aChildID,
+                                      bool aElementHidden,
+                                      bool aElementWasHidden)
 {
-  UpdateChannelType(aType, aChildID, aElementHidden, aElementWasHidden);
+  UpdateChannelType(aChannel, aChildID, aElementHidden, aElementWasHidden);
 
   // Calculating the new and old type and update the hashtable if needed.
-  AudioChannelInternalType newType = GetInternalType(aType, aElementHidden);
-  AudioChannelInternalType oldType = GetInternalType(aType, aElementWasHidden);
+  AudioChannelInternalType newType = GetInternalType(aChannel, aElementHidden);
+  AudioChannelInternalType oldType = GetInternalType(aChannel,
+                                                     aElementWasHidden);
 
   if (newType != oldType &&
-      (aType == AUDIO_CHANNEL_CONTENT ||
-       (aType == AUDIO_CHANNEL_NORMAL &&
+      (aChannel == AudioChannel::Content ||
+       (aChannel == AudioChannel::Normal &&
         mWithVideoChildIDs.Contains(aChildID)))) {
     Notify();
   }
 
   SendAudioChannelChangedNotification(aChildID);
 
   // Let play any visible audio channel.
   if (!aElementHidden) {
@@ -422,40 +436,48 @@ bool
 AudioChannelService::ProcessContentOrNormalChannelIsActive(uint64_t aChildID)
 {
   return mChannelCounters[AUDIO_CHANNEL_INT_CONTENT].Contains(aChildID) ||
          mChannelCounters[AUDIO_CHANNEL_INT_CONTENT_HIDDEN].Contains(aChildID) ||
          mChannelCounters[AUDIO_CHANNEL_INT_NORMAL].Contains(aChildID);
 }
 
 void
-AudioChannelService::SetDefaultVolumeControlChannel(AudioChannelType aType,
+AudioChannelService::SetDefaultVolumeControlChannel(int32_t aChannel,
                                                     bool aHidden)
 {
-  SetDefaultVolumeControlChannelInternal(aType, aHidden, CONTENT_PROCESS_ID_MAIN);
+  SetDefaultVolumeControlChannelInternal(aChannel, aHidden,
+                                         CONTENT_PROCESS_ID_MAIN);
 }
 
 void
-AudioChannelService::SetDefaultVolumeControlChannelInternal(
-  AudioChannelType aType, bool aHidden, uint64_t aChildID)
+AudioChannelService::SetDefaultVolumeControlChannelInternal(int32_t aChannel,
+                                                            bool aHidden,
+                                                            uint64_t aChildID)
 {
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
     return;
   }
 
   // If this child is in the background and mDefChannelChildID is set to
   // others then it means other child in the foreground already set it's
   // own default channel already.
   if (!aHidden && mDefChannelChildID != aChildID) {
     return;
   }
 
   mDefChannelChildID = aChildID;
   nsString channelName;
-  channelName.AssignASCII(ChannelName(aType));
+
+  if (aChannel == -1) {
+    channelName.AssignASCII("unknown");
+  } else {
+    GetAudioChannelString(static_cast<AudioChannel>(aChannel), channelName);
+  }
+
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     obs->NotifyObservers(nullptr, "default-volume-channel-changed",
                          channelName.get());
   }
 }
 
 void
@@ -470,87 +492,94 @@ AudioChannelService::SendAudioChannelCha
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     obs->NotifyObservers(static_cast<nsIWritablePropertyBag*>(props),
                          "audio-channel-process-changed", nullptr);
   }
 
   // Calculating the most important active channel.
-  AudioChannelType higher = AUDIO_CHANNEL_DEFAULT;
+  int32_t higher = -1;
 
   // Top-Down in the hierarchy for visible elements
   if (!mChannelCounters[AUDIO_CHANNEL_INT_PUBLICNOTIFICATION].IsEmpty()) {
-    higher = AUDIO_CHANNEL_PUBLICNOTIFICATION;
+    higher = static_cast<int32_t>(AudioChannel::Publicnotification);
   }
 
   else if (!mChannelCounters[AUDIO_CHANNEL_INT_RINGER].IsEmpty()) {
-    higher = AUDIO_CHANNEL_RINGER;
+    higher = static_cast<int32_t>(AudioChannel::Ringer);
   }
 
   else if (!mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY].IsEmpty()) {
-    higher = AUDIO_CHANNEL_TELEPHONY;
+    higher = static_cast<int32_t>(AudioChannel::Telephony);
   }
 
   else if (!mChannelCounters[AUDIO_CHANNEL_INT_ALARM].IsEmpty()) {
-    higher = AUDIO_CHANNEL_ALARM;
+    higher = static_cast<int32_t>(AudioChannel::Alarm);
   }
 
   else if (!mChannelCounters[AUDIO_CHANNEL_INT_NOTIFICATION].IsEmpty()) {
-    higher = AUDIO_CHANNEL_NOTIFICATION;
+    higher = static_cast<int32_t>(AudioChannel::Notification);
   }
 
   else if (!mChannelCounters[AUDIO_CHANNEL_INT_CONTENT].IsEmpty()) {
-    higher = AUDIO_CHANNEL_CONTENT;
+    higher = static_cast<int32_t>(AudioChannel::Content);
   }
 
   else if (!mChannelCounters[AUDIO_CHANNEL_INT_NORMAL].IsEmpty()) {
-    higher = AUDIO_CHANNEL_NORMAL;
+    higher = static_cast<int32_t>(AudioChannel::Normal);
   }
 
-  AudioChannelType visibleHigher = higher;
+  int32_t visibleHigher = higher;
 
   // Top-Down in the hierarchy for non-visible elements
   // And we can ignore normal channel because it can't play in the background.
-  for (int i = AUDIO_CHANNEL_LAST - 1;
-       i > higher && i > AUDIO_CHANNEL_NORMAL; i--) {
-    if (i == AUDIO_CHANNEL_CONTENT &&
+  int32_t index;
+  for (index = 0; kMozAudioChannelAttributeTable[index].tag; ++index);
+
+  for (--index;
+       kMozAudioChannelAttributeTable[index].value > higher &&
+       kMozAudioChannelAttributeTable[index].value > (int16_t)AudioChannel::Normal;
+       --index) {
+    if (kMozAudioChannelAttributeTable[index].value == (int16_t)AudioChannel::Content &&
       mPlayableHiddenContentChildID != CONTENT_PROCESS_ID_UNKNOWN) {
-      higher = static_cast<AudioChannelType>(i);
+      higher = kMozAudioChannelAttributeTable[index].value;
     }
 
     // Each channel type will be split to fg and bg for recording the state,
     // so here need to do a translation.
-    if (!mChannelCounters[i * 2 + 1].IsEmpty()) {
-      higher = static_cast<AudioChannelType>(i);
+    if (!mChannelCounters[index * 2 + 1].IsEmpty()) {
+      higher = kMozAudioChannelAttributeTable[index].value;
       break;
     }
   }
 
   if (higher != mCurrentHigherChannel) {
     mCurrentHigherChannel = higher;
 
     nsString channelName;
-    if (mCurrentHigherChannel != AUDIO_CHANNEL_DEFAULT) {
-      channelName.AssignASCII(ChannelName(mCurrentHigherChannel));
+    if (mCurrentHigherChannel != -1) {
+      GetAudioChannelString(static_cast<AudioChannel>(mCurrentHigherChannel),
+                            channelName);
     } else {
       channelName.AssignLiteral("none");
     }
 
     if (obs) {
       obs->NotifyObservers(nullptr, "audio-channel-changed", channelName.get());
     }
   }
 
   if (visibleHigher != mCurrentVisibleHigherChannel) {
     mCurrentVisibleHigherChannel = visibleHigher;
 
     nsString channelName;
-    if (mCurrentVisibleHigherChannel != AUDIO_CHANNEL_DEFAULT) {
-      channelName.AssignASCII(ChannelName(mCurrentVisibleHigherChannel));
+    if (mCurrentVisibleHigherChannel != -1) {
+      GetAudioChannelString(static_cast<AudioChannel>(mCurrentVisibleHigherChannel),
+                            channelName);
     } else {
       channelName.AssignLiteral("none");
     }
 
     if (obs) {
       obs->NotifyObservers(nullptr, "visible-audio-channel-changed", channelName.get());
     }
   }
@@ -579,17 +608,18 @@ AudioChannelService::Notify()
   for (uint32_t i = 0; i < children.Length(); i++) {
     unused << children[i]->SendAudioChannelNotify();
   }
 }
 
 NS_IMETHODIMP
 AudioChannelService::Notify(nsITimer* aTimer)
 {
-  UnregisterTypeInternal(AUDIO_CHANNEL_TELEPHONY, mTimerElementHidden, mTimerChildID, false);
+  UnregisterTypeInternal(AudioChannel::Telephony, mTimerElementHidden,
+                         mTimerChildID, false);
   mDeferTelChannelTimer = nullptr;
   return NS_OK;
 }
 
 bool
 AudioChannelService::AnyAudioChannelIsActive()
 {
   for (int i = AUDIO_CHANNEL_INT_LAST - 1;
@@ -615,44 +645,16 @@ AudioChannelService::ChannelsActiveWithH
     if (!mChannelCounters[i].IsEmpty()) {
       return true;
     }
   }
 
   return false;
 }
 
-const char*
-AudioChannelService::ChannelName(AudioChannelType aType)
-{
-  static struct {
-    int32_t type;
-    const char* value;
-  } ChannelNameTable[] = {
-    { AUDIO_CHANNEL_NORMAL,             "normal" },
-    { AUDIO_CHANNEL_CONTENT,            "content" },
-    { AUDIO_CHANNEL_NOTIFICATION,       "notification" },
-    { AUDIO_CHANNEL_ALARM,              "alarm" },
-    { AUDIO_CHANNEL_TELEPHONY,          "telephony" },
-    { AUDIO_CHANNEL_RINGER,             "ringer" },
-    { AUDIO_CHANNEL_PUBLICNOTIFICATION, "publicnotification" },
-    { -1,                               "unknown" }
-  };
-
-  for (int i = AUDIO_CHANNEL_NORMAL; ; ++i) {
-    if (ChannelNameTable[i].type == aType ||
-        ChannelNameTable[i].type == -1) {
-      return ChannelNameTable[i].value;
-    }
-  }
-
-  NS_NOTREACHED("Execution should not reach here!");
-  return nullptr;
-}
-
 NS_IMETHODIMP
 AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
 {
   if (!strcmp(aTopic, "xpcom-shutdown")) {
     mDisabled = true;
   }
 
   if (!strcmp(aTopic, "ipc:content-shutdown")) {
@@ -688,18 +690,17 @@ AudioChannelService::Observe(nsISupports
 
       // We don't have to remove the agents from the mAgents hashtable because if
       // that table contains only agents running on the same process.
 
       SendAudioChannelChangedNotification(childID);
       Notify();
 
       if (mDefChannelChildID == childID) {
-        SetDefaultVolumeControlChannelInternal(AUDIO_CHANNEL_DEFAULT,
-                                               false, childID);
+        SetDefaultVolumeControlChannelInternal(-1, false, childID);
         mDefChannelChildID = CONTENT_PROCESS_ID_UNKNOWN;
       }
     } else {
       NS_WARNING("ipc:content-shutdown message without childID property");
     }
   }
 #ifdef MOZ_WIDGET_GONK
   // To process the volume control on each audio channel according to
@@ -734,83 +735,82 @@ AudioChannelService::Observe(nsISupports
       return NS_OK;
     }
 
     nsCOMPtr<nsIAudioManager> audioManager = do_GetService(NS_AUDIOMANAGER_CONTRACTID);
     NS_ENSURE_TRUE(audioManager, NS_OK);
 
     int32_t index = value.toInt32();
     if (keyStr.EqualsLiteral("audio.volume.content")) {
-      audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_CONTENT, index);
+      audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Content, index);
     } else if (keyStr.EqualsLiteral("audio.volume.notification")) {
-      audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_NOTIFICATION, index);
+      audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Notification, index);
     } else if (keyStr.EqualsLiteral("audio.volume.alarm")) {
-      audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_ALARM, index);
+      audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Alarm, index);
     } else if (keyStr.EqualsLiteral("audio.volume.telephony")) {
-      audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_TELEPHONY, index);
+      audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Telephony, index);
     } else if (!keyStr.EqualsLiteral("audio.volume.bt_sco")) {
       // bt_sco is not a valid audio channel so we manipulate it in
       // AudioManager.cpp. And the others should not be used.
       // We didn't use MOZ_ASSUME_UNREACHABLE here because any web content who
       // has permission of mozSettings can set any names then it can be easy to
       // crash the B2G.
       NS_WARNING("unexpected audio channel for volume control");
     }
   }
 #endif
 
   return NS_OK;
 }
 
 AudioChannelService::AudioChannelInternalType
-AudioChannelService::GetInternalType(AudioChannelType aType,
+AudioChannelService::GetInternalType(AudioChannel aChannel,
                                      bool aElementHidden)
 {
-  switch (aType) {
-    case AUDIO_CHANNEL_NORMAL:
+  switch (aChannel) {
+    case AudioChannel::Normal:
       return aElementHidden
                ? AUDIO_CHANNEL_INT_NORMAL_HIDDEN
                : AUDIO_CHANNEL_INT_NORMAL;
 
-    case AUDIO_CHANNEL_CONTENT:
+    case AudioChannel::Content:
       return aElementHidden
                ? AUDIO_CHANNEL_INT_CONTENT_HIDDEN
                : AUDIO_CHANNEL_INT_CONTENT;
 
-    case AUDIO_CHANNEL_NOTIFICATION:
+    case AudioChannel::Notification:
       return aElementHidden
                ? AUDIO_CHANNEL_INT_NOTIFICATION_HIDDEN
                : AUDIO_CHANNEL_INT_NOTIFICATION;
 
-    case AUDIO_CHANNEL_ALARM:
+    case AudioChannel::Alarm:
       return aElementHidden
                ? AUDIO_CHANNEL_INT_ALARM_HIDDEN
                : AUDIO_CHANNEL_INT_ALARM;
 
-    case AUDIO_CHANNEL_TELEPHONY:
+    case AudioChannel::Telephony:
       return aElementHidden
                ? AUDIO_CHANNEL_INT_TELEPHONY_HIDDEN
                : AUDIO_CHANNEL_INT_TELEPHONY;
 
-    case AUDIO_CHANNEL_RINGER:
+    case AudioChannel::Ringer:
       return aElementHidden
                ? AUDIO_CHANNEL_INT_RINGER_HIDDEN
                : AUDIO_CHANNEL_INT_RINGER;
 
-    case AUDIO_CHANNEL_PUBLICNOTIFICATION:
+    case AudioChannel::Publicnotification:
       return aElementHidden
                ? AUDIO_CHANNEL_INT_PUBLICNOTIFICATION_HIDDEN
                : AUDIO_CHANNEL_INT_PUBLICNOTIFICATION;
 
-    case AUDIO_CHANNEL_LAST:
     default:
       break;
   }
 
-  MOZ_CRASH("unexpected audio channel type");
+  MOZ_CRASH("unexpected audio channel");
 }
 
 struct RefreshAgentsVolumeData
 {
   RefreshAgentsVolumeData(nsPIDOMWindow* aWindow)
     : mWindow(aWindow)
   {}
 
@@ -878,56 +878,73 @@ AudioChannelService::CountWindowEnumerat
 uint32_t
 AudioChannelService::CountWindow(nsIDOMWindow* aWindow)
 {
   CountWindowData data(aWindow);
   mAgents.EnumerateRead(CountWindowEnumerator, &data);
   return data.mCount;
 }
 
-// Mappings from 'mozaudiochannel' attribute strings to an enumeration.
-static const struct AudioChannelTable
+/* static */ const nsAttrValue::EnumTable*
+AudioChannelService::GetAudioChannelTable()
+{
+  return kMozAudioChannelAttributeTable;
+}
+
+/* static */ AudioChannel
+AudioChannelService::GetAudioChannel(const nsAString& aChannel)
 {
-  const char* string;
-  AudioChannel value;
-} kMozAudioChannelAttributeTable[] = {
-  { "normal",             AudioChannel::Normal },
-  { "content",            AudioChannel::Content },
-  { "notification",       AudioChannel::Notification },
-  { "alarm",              AudioChannel::Alarm },
-  { "telephony",          AudioChannel::Telephony },
-  { "ringer",             AudioChannel::Ringer },
-  { "publicnotification", AudioChannel::Publicnotification },
-  { nullptr }
-};
+  for (uint32_t i = 0; kMozAudioChannelAttributeTable[i].tag; ++i) {
+    if (aChannel.EqualsASCII(kMozAudioChannelAttributeTable[i].tag)) {
+      return static_cast<AudioChannel>(kMozAudioChannelAttributeTable[i].value);
+    }
+  }
+
+  return AudioChannel::Normal;
+}
 
 /* static */ AudioChannel
 AudioChannelService::GetDefaultAudioChannel()
 {
   nsString audioChannel = Preferences::GetString("media.defaultAudioChannel");
   if (audioChannel.IsEmpty()) {
     return AudioChannel::Normal;
   }
 
-  for (uint32_t i = 0; kMozAudioChannelAttributeTable[i].string; ++i) {
-    if (audioChannel.EqualsASCII(kMozAudioChannelAttributeTable[i].string)) {
-      return kMozAudioChannelAttributeTable[i].value;
+  for (uint32_t i = 0; kMozAudioChannelAttributeTable[i].tag; ++i) {
+    if (audioChannel.EqualsASCII(kMozAudioChannelAttributeTable[i].tag)) {
+      return static_cast<AudioChannel>(kMozAudioChannelAttributeTable[i].value);
     }
   }
 
   return AudioChannel::Normal;
 }
 
 /* static */ void
-AudioChannelService::GetDefaultAudioChannelString(nsString& aString)
+AudioChannelService::GetAudioChannelString(AudioChannel aChannel,
+                                           nsAString& aString)
+{
+  aString.AssignASCII("normal");
+
+  for (uint32_t i = 0; kMozAudioChannelAttributeTable[i].tag; ++i) {
+    if (aChannel ==
+        static_cast<AudioChannel>(kMozAudioChannelAttributeTable[i].value)) {
+      aString.AssignASCII(kMozAudioChannelAttributeTable[i].tag);
+      break;
+    }
+  }
+}
+
+/* static */ void
+AudioChannelService::GetDefaultAudioChannelString(nsAString& aString)
 {
   aString.AssignASCII("normal");
 
   nsString audioChannel = Preferences::GetString("media.defaultAudioChannel");
   if (!audioChannel.IsEmpty()) {
-    for (uint32_t i = 0; kMozAudioChannelAttributeTable[i].string; ++i) {
-      if (audioChannel.EqualsASCII(kMozAudioChannelAttributeTable[i].string)) {
+    for (uint32_t i = 0; kMozAudioChannelAttributeTable[i].tag; ++i) {
+      if (audioChannel.EqualsASCII(kMozAudioChannelAttributeTable[i].tag)) {
         aString = audioChannel;
         break;
       }
     }
   }
 }
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -9,16 +9,17 @@
 
 #include "nsAutoPtr.h"
 #include "nsIObserver.h"
 #include "nsTArray.h"
 #include "nsITimer.h"
 
 #include "AudioChannelCommon.h"
 #include "AudioChannelAgent.h"
+#include "nsAttrValue.h"
 #include "nsClassHashtable.h"
 #include "mozilla/dom/AudioChannelBinding.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 #ifdef MOZ_WIDGET_GONK
@@ -43,20 +44,20 @@ public:
 
   /**
    * Shutdown the singleton.
    */
   static void Shutdown();
 
   /**
    * Any audio channel agent that starts playing should register itself to
-   * this service, sharing the AudioChannelType.
+   * this service, sharing the AudioChannel.
    */
   virtual void RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
-                                         AudioChannelType aType,
+                                         AudioChannel aChannel,
                                          bool aWithVideo);
 
   /**
    * Any audio channel agent that stops playing should unregister itself to
    * this service.
    */
   virtual void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
 
@@ -76,19 +77,21 @@ public:
   /**
    * Return true if a normal or content channel is active for the given
    * process ID.
    */
   virtual bool ProcessContentOrNormalChannelIsActive(uint64_t aChildID);
 
   /***
    * AudioChannelManager calls this function to notify the default channel used
-   * to adjust volume when there is no any active channel.
+   * to adjust volume when there is no any active channel. if aChannel is -1,
+   * the default audio channel will be used. Otherwise aChannel is casted to
+   * AudioChannel enum.
    */
-  virtual void SetDefaultVolumeControlChannel(AudioChannelType aType,
+  virtual void SetDefaultVolumeControlChannel(int32_t aChannel,
                                               bool aHidden);
 
   bool AnyAudioChannelIsActive();
 
   void RefreshAgentsVolume(nsPIDOMWindow* aWindow);
 
 #ifdef MOZ_WIDGET_GONK
   void RegisterSpeakerManager(SpeakerManagerService* aSpeakerManager)
@@ -99,45 +102,48 @@ public:
   }
 
   void UnregisterSpeakerManager(SpeakerManagerService* aSpeakerManager)
   {
     mSpeakerManager.RemoveElement(aSpeakerManager);
   }
 #endif
 
+  static const nsAttrValue::EnumTable* GetAudioChannelTable();
+  static AudioChannel GetAudioChannel(const nsAString& aString);
   static AudioChannel GetDefaultAudioChannel();
-  static void GetDefaultAudioChannelString(nsString& aString);
+  static void GetAudioChannelString(AudioChannel aChannel, nsAString& aString);
+  static void GetDefaultAudioChannelString(nsAString& aString);
 
 protected:
   void Notify();
 
   /**
    * Send the audio-channel-changed notification for the given process ID if
    * needed.
    */
   void SendAudioChannelChangedNotification(uint64_t aChildID);
 
   /* Register/Unregister IPC types: */
-  void RegisterType(AudioChannelType aType, uint64_t aChildID, bool aWithVideo);
-  void UnregisterType(AudioChannelType aType, bool aElementHidden,
+  void RegisterType(AudioChannel aChannel, uint64_t aChildID, bool aWithVideo);
+  void UnregisterType(AudioChannel aChannel, bool aElementHidden,
                       uint64_t aChildID, bool aWithVideo);
-  void UnregisterTypeInternal(AudioChannelType aType, bool aElementHidden,
+  void UnregisterTypeInternal(AudioChannel aChannel, bool aElementHidden,
                               uint64_t aChildID, bool aWithVideo);
 
-  AudioChannelState GetStateInternal(AudioChannelType aType, uint64_t aChildID,
+  AudioChannelState GetStateInternal(AudioChannel aChannel, uint64_t aChildID,
                                      bool aElementHidden,
                                      bool aElementWasHidden);
 
   /* Update the internal type value following the visibility changes */
-  void UpdateChannelType(AudioChannelType aType, uint64_t aChildID,
+  void UpdateChannelType(AudioChannel aChannel, uint64_t aChildID,
                          bool aElementHidden, bool aElementWasHidden);
 
   /* Send the default-volume-channel-changed notification */
-  void SetDefaultVolumeControlChannelInternal(AudioChannelType aType,
+  void SetDefaultVolumeControlChannelInternal(int32_t aChannel,
                                               bool aHidden, uint64_t aChildID);
 
   AudioChannelService();
   virtual ~AudioChannelService();
 
   enum AudioChannelInternalType {
     AUDIO_CHANNEL_INT_NORMAL = 0,
     AUDIO_CHANNEL_INT_NORMAL_HIDDEN,
@@ -156,34 +162,32 @@ protected:
     AUDIO_CHANNEL_INT_LAST
   };
 
   bool ChannelsActiveWithHigherPriorityThan(AudioChannelInternalType aType);
 
   bool CheckVolumeFadedCondition(AudioChannelInternalType aType,
                                  bool aElementHidden);
 
-  const char* ChannelName(AudioChannelType aType);
-
-  AudioChannelInternalType GetInternalType(AudioChannelType aType,
+  AudioChannelInternalType GetInternalType(AudioChannel aChannel,
                                            bool aElementHidden);
 
   class AudioChannelAgentData {
   public:
-    AudioChannelAgentData(AudioChannelType aType,
+    AudioChannelAgentData(AudioChannel aChannel,
                           bool aElementHidden,
                           AudioChannelState aState,
                           bool aWithVideo)
-    : mType(aType)
+    : mChannel(aChannel)
     , mElementHidden(aElementHidden)
     , mState(aState)
     , mWithVideo(aWithVideo)
     {}
 
-    AudioChannelType mType;
+    AudioChannel mChannel;
     bool mElementHidden;
     AudioChannelState mState;
     const bool mWithVideo;
   };
 
   static PLDHashOperator
   NotifyEnumerator(AudioChannelAgent* aAgent,
                    AudioChannelAgentData* aData, void *aUnused);
@@ -202,18 +206,18 @@ protected:
   uint32_t CountWindow(nsIDOMWindow* aWindow);
 
   nsClassHashtable< nsPtrHashKey<AudioChannelAgent>, AudioChannelAgentData > mAgents;
 #ifdef MOZ_WIDGET_GONK
   nsTArray<SpeakerManagerService*>  mSpeakerManager;
 #endif
   nsTArray<uint64_t> mChannelCounters[AUDIO_CHANNEL_INT_LAST];
 
-  AudioChannelType mCurrentHigherChannel;
-  AudioChannelType mCurrentVisibleHigherChannel;
+  int32_t mCurrentHigherChannel;
+  int32_t mCurrentVisibleHigherChannel;
 
   nsTArray<uint64_t> mWithVideoChildIDs;
 
   // mPlayableHiddenContentChildID stores the ChildID of the process which can
   // play content channel(s) in the background.
   // A background process contained content channel(s) will become playable:
   //   1. When this background process registers its content channel(s) in
   //   AudioChannelService and there is no foreground process with registered
--- a/dom/audiochannel/AudioChannelServiceChild.cpp
+++ b/dom/audiochannel/AudioChannelServiceChild.cpp
@@ -67,39 +67,39 @@ AudioChannelServiceChild::GetState(Audio
   AudioChannelAgentData* data;
   if (!mAgents.Get(aAgent, &data)) {
     return AUDIO_CHANNEL_STATE_MUTED;
   }
 
   AudioChannelState state = AUDIO_CHANNEL_STATE_MUTED;
   bool oldElementHidden = data->mElementHidden;
 
-  UpdateChannelType(data->mType, CONTENT_PROCESS_ID_MAIN, aElementHidden, oldElementHidden);
+  UpdateChannelType(data->mChannel, CONTENT_PROCESS_ID_MAIN, aElementHidden,
+                    oldElementHidden);
 
   // Update visibility.
   data->mElementHidden = aElementHidden;
 
   ContentChild* cc = ContentChild::GetSingleton();
-  cc->SendAudioChannelGetState(data->mType, aElementHidden, oldElementHidden, &state);
+  cc->SendAudioChannelGetState(data->mChannel, aElementHidden, oldElementHidden,
+                               &state);
   data->mState = state;
   cc->SendAudioChannelChangedNotification();
 
   return state;
 }
 
 void
 AudioChannelServiceChild::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
-                                                    AudioChannelType aType,
+                                                    AudioChannel aChannel,
                                                     bool aWithVideo)
 {
-  MOZ_ASSERT(aType != AUDIO_CHANNEL_DEFAULT);
+  AudioChannelService::RegisterAudioChannelAgent(aAgent, aChannel, aWithVideo);
 
-  AudioChannelService::RegisterAudioChannelAgent(aAgent, aType, aWithVideo);
-
-  ContentChild::GetSingleton()->SendAudioChannelRegisterType(aType, aWithVideo);
+  ContentChild::GetSingleton()->SendAudioChannelRegisterType(aChannel, aWithVideo);
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     obs->NotifyObservers(nullptr, "audio-channel-agent-changed", nullptr);
   }
 }
 
 void
@@ -112,31 +112,31 @@ AudioChannelServiceChild::UnregisterAudi
 
   // We need to keep a copy because unregister will remove the
   // AudioChannelAgentData object from the hashtable.
   AudioChannelAgentData data(*pData);
 
   AudioChannelService::UnregisterAudioChannelAgent(aAgent);
 
   ContentChild::GetSingleton()->SendAudioChannelUnregisterType(
-      data.mType, data.mElementHidden, data.mWithVideo);
+      data.mChannel, data.mElementHidden, data.mWithVideo);
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     obs->NotifyObservers(nullptr, "audio-channel-agent-changed", nullptr);
   }
 #ifdef MOZ_WIDGET_GONK
   bool active = AnyAudioChannelIsActive();
   for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
     mSpeakerManager[i]->SetAudioChannelActive(active);
   }
 #endif
 }
 
 void
-AudioChannelServiceChild::SetDefaultVolumeControlChannel(
-  AudioChannelType aType, bool aHidden)
+AudioChannelServiceChild::SetDefaultVolumeControlChannel(int32_t aChannel,
+                                                         bool aHidden)
 {
   ContentChild *cc = ContentChild::GetSingleton();
   if (cc) {
-    cc->SendAudioChannelChangeDefVolChannel(aType, aHidden);
+    cc->SendAudioChannelChangeDefVolChannel(aChannel, aHidden);
   }
 }
--- a/dom/audiochannel/AudioChannelServiceChild.h
+++ b/dom/audiochannel/AudioChannelServiceChild.h
@@ -26,28 +26,29 @@ public:
    *
    * @return NS_OK on proper assignment, NS_ERROR_FAILURE otherwise.
    */
   static AudioChannelService* GetAudioChannelService();
 
   static void Shutdown();
 
   virtual void RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
-                                         AudioChannelType aType,
+                                         AudioChannel aChannel,
                                          bool aWithVideo);
   virtual void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
 
   /**
    * Return the state to indicate this agent should keep playing/
    * fading volume/muted.
    */
   virtual AudioChannelState GetState(AudioChannelAgent* aAgent,
                                      bool aElementHidden);
 
-  virtual void SetDefaultVolumeControlChannel(AudioChannelType aType, bool aHidden);
+  virtual void SetDefaultVolumeControlChannel(int32_t aChannel,
+                                              bool aHidden);
 
 protected:
   AudioChannelServiceChild();
   virtual ~AudioChannelServiceChild();
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/audiochannel/tests/TestAudioChannelService.cpp
+++ b/dom/audiochannel/tests/TestAudioChannelService.cpp
@@ -26,18 +26,18 @@
 using namespace mozilla::dom;
 
 class Agent : public nsIAudioChannelAgentCallback,
               public nsSupportsWeakReference
 {
 public:
   NS_DECL_ISUPPORTS
 
-  Agent(AudioChannelType aType)
-  : mType(aType)
+  Agent(AudioChannel aChannel)
+  : mChannel(aChannel)
   , mWaitCallback(false)
   , mRegistered(false)
   , mCanPlay(AUDIO_CHANNEL_STATE_MUTED)
   {
     mAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1");
   }
 
   virtual ~Agent()
@@ -46,20 +46,22 @@ public:
       StopPlaying();
     }
   }
 
   nsresult Init(bool video=false)
   {
     nsresult rv = NS_OK;
     if (video) {
-      rv = mAgent->InitWithVideo(nullptr, mType, this, true);
+      rv = mAgent->InitWithVideo(nullptr, static_cast<int32_t>(mChannel),
+                                 this, true);
     }
     else {
-      rv = mAgent->InitWithWeakCallback(nullptr, mType, this);
+      rv = mAgent->InitWithWeakCallback(nullptr, static_cast<int32_t>(mChannel),
+                                        this);
     }
     NS_ENSURE_SUCCESS(rv, rv);
 
     return mAgent->SetVisibilityState(false);
   }
 
   nsresult StartPlaying(AudioChannelState *_ret)
   {
@@ -122,29 +124,29 @@ public:
         TEST_ENSURE_BASE(false, "GetCanPlay timeout");
       }
     }
     *_ret = mCanPlay;
     return NS_OK;
   }
 
   nsCOMPtr<nsIAudioChannelAgent> mAgent;
-  AudioChannelType mType;
+  AudioChannel mChannel;
   bool mWaitCallback;
   bool mRegistered;
   AudioChannelState mCanPlay;
 };
 
 NS_IMPL_ISUPPORTS2(Agent, nsIAudioChannelAgentCallback,
                    nsISupportsWeakReference)
 
 nsresult
 TestDoubleStartPlaying()
 {
-  nsRefPtr<Agent> agent = new Agent(AUDIO_CHANNEL_NORMAL);
+  nsRefPtr<Agent> agent = new Agent(AudioChannel::Normal);
 
   nsresult rv = agent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   AudioChannelState playable;
   rv = agent->mAgent->StartPlaying((int32_t *)&playable);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -153,17 +155,17 @@ TestDoubleStartPlaying()
     "Test0: StartPlaying calling twice must return error");
 
   return NS_OK;
 }
 
 nsresult
 TestOneNormalChannel()
 {
-  nsRefPtr<Agent> agent = new Agent(AUDIO_CHANNEL_NORMAL);
+  nsRefPtr<Agent> agent = new Agent(AudioChannel::Normal);
   nsresult rv = agent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   AudioChannelState playable;
   rv = agent->StartPlaying(&playable);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
     "Test1: A normal channel unvisible agent must be muted");
@@ -177,21 +179,21 @@ TestOneNormalChannel()
     "Test1: A normal channel visible agent must be playable");
 
   return rv;
 }
 
 nsresult
 TestTwoNormalChannels()
 {
-  nsRefPtr<Agent> agent1 = new Agent(AUDIO_CHANNEL_NORMAL);
+  nsRefPtr<Agent> agent1 = new Agent(AudioChannel::Normal);
   nsresult rv = agent1->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<Agent> agent2 = new Agent(AUDIO_CHANNEL_NORMAL);
+  nsRefPtr<Agent> agent2 = new Agent(AudioChannel::Normal);
   rv = agent2->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   AudioChannelState playable;
   rv = agent1->StartPlaying(&playable);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
     "Test2: A normal channel unvisible agent1 must be muted");
@@ -218,21 +220,21 @@ TestTwoNormalChannels()
     "Test2: A normal channel visible agent2 must be playable");
 
   return rv;
 }
 
 nsresult
 TestContentChannels()
 {
-  nsRefPtr<Agent> agent1 = new Agent(AUDIO_CHANNEL_CONTENT);
+  nsRefPtr<Agent> agent1 = new Agent(AudioChannel::Content);
   nsresult rv = agent1->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<Agent> agent2 = new Agent(AUDIO_CHANNEL_CONTENT);
+  nsRefPtr<Agent> agent2 = new Agent(AudioChannel::Content);
   rv = agent2->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // All content channels in the foreground can be allowed to play
   rv = agent1->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = agent2->SetVisibilityState(true);
@@ -303,25 +305,25 @@ TestContentChannels()
     "from background state");
 
   return rv;
 }
 
 nsresult
 TestFadedState()
 {
-  nsRefPtr<Agent> normalAgent = new Agent(AUDIO_CHANNEL_NORMAL);
+  nsRefPtr<Agent> normalAgent = new Agent(AudioChannel::Normal);
   nsresult rv = normalAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<Agent> contentAgent = new Agent(AUDIO_CHANNEL_CONTENT);
+  nsRefPtr<Agent> contentAgent = new Agent(AudioChannel::Content);
   rv = contentAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<Agent> notificationAgent = new Agent(AUDIO_CHANNEL_NOTIFICATION);
+  nsRefPtr<Agent> notificationAgent = new Agent(AudioChannel::Notification);
   rv = notificationAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = normalAgent->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = contentAgent->SetVisibilityState(true);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -382,42 +384,42 @@ TestFadedState()
   NS_ENSURE_SUCCESS(rv, rv);
 
   return rv;
 }
 
 nsresult
 TestPriorities()
 {
-  nsRefPtr<Agent> normalAgent = new Agent(AUDIO_CHANNEL_NORMAL);
+  nsRefPtr<Agent> normalAgent = new Agent(AudioChannel::Normal);
   nsresult rv = normalAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<Agent> contentAgent = new Agent(AUDIO_CHANNEL_CONTENT);
+  nsRefPtr<Agent> contentAgent = new Agent(AudioChannel::Content);
   rv = contentAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<Agent> notificationAgent = new Agent(AUDIO_CHANNEL_NOTIFICATION);
+  nsRefPtr<Agent> notificationAgent = new Agent(AudioChannel::Notification);
   rv = notificationAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<Agent> alarmAgent = new Agent(AUDIO_CHANNEL_ALARM);
+  nsRefPtr<Agent> alarmAgent = new Agent(AudioChannel::Alarm);
   rv = alarmAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<Agent> telephonyAgent = new Agent(AUDIO_CHANNEL_TELEPHONY);
+  nsRefPtr<Agent> telephonyAgent = new Agent(AudioChannel::Telephony);
   rv = telephonyAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<Agent> ringerAgent = new Agent(AUDIO_CHANNEL_RINGER);
+  nsRefPtr<Agent> ringerAgent = new Agent(AudioChannel::Ringer);
   rv = ringerAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsRefPtr<Agent> pNotificationAgent =
-    new Agent(AUDIO_CHANNEL_PUBLICNOTIFICATION);
+    new Agent(AudioChannel::Publicnotification);
   rv = pNotificationAgent->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   AudioChannelState playable;
 
   rv = normalAgent->StartPlaying(&playable);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
@@ -539,21 +541,21 @@ TestPriorities()
     "Test5: A pNotification channel visible agent must be playable");
 
   return rv;
 }
 
 nsresult
 TestOneVideoNormalChannel()
 {
-  nsRefPtr<Agent> agent1 = new Agent(AUDIO_CHANNEL_NORMAL);
+  nsRefPtr<Agent> agent1 = new Agent(AudioChannel::Normal);
   nsresult rv = agent1->Init(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsRefPtr<Agent> agent2 = new Agent(AUDIO_CHANNEL_CONTENT);
+  nsRefPtr<Agent> agent2 = new Agent(AudioChannel::Content);
   rv = agent2->Init(false);
   NS_ENSURE_SUCCESS(rv, rv);
 
   AudioChannelState playable;
   rv = agent1->StartPlaying(&playable);
   NS_ENSURE_SUCCESS(rv, rv);
   TEST_ENSURE_BASE(playable == AUDIO_CHANNEL_STATE_MUTED,
     "Test6: A video normal channel invisible agent1 must be muted");
@@ -644,21 +646,21 @@ int main(int argc, char** argv)
   if (NS_FAILED(TestContentChannels())) {
     return 1;
   }
 
   if (NS_FAILED(TestFadedState())) {
     return 1;
   }
 
-  // Channel type with AUDIO_CHANNEL_TELEPHONY cannot be unregistered until the
+  // Channel type with AudioChannel::Telephony cannot be unregistered until the
   // main thread has chances to process 1500 millisecond timer. In order to
   // skip ambiguous return value of ChannelsActiveWithHigherPriorityThan(), new
   // test cases are added before any test case that registers the channel type
-  // with AUDIO_CHANNEL_TELEPHONY channel.
+  // with AudioChannel::Telephony channel.
   if (NS_FAILED(TestOneVideoNormalChannel())) {
     return 1;
   }
 
   if (NS_FAILED(TestPriorities())) {
     return 1;
   }
 
--- a/dom/audiochannel/tests/moz.build
+++ b/dom/audiochannel/tests/moz.build
@@ -3,10 +3,13 @@
 # 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/.
 
 CPP_UNIT_TESTS += [
     'TestAudioChannelService.cpp',
 ]
 
+if CONFIG['OS_ARCH'] == 'WINNT':
+    DEFINES['NOMINMAX'] = True
+
 FAIL_ON_WARNINGS = True
 
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -809,42 +809,37 @@ Console::Method(JSContext* aCx, MethodNa
       Throw(aCx, rv);
       return;
     }
 
     if (language == nsIProgrammingLanguage::JAVASCRIPT ||
         language == nsIProgrammingLanguage::JAVASCRIPT2) {
       ConsoleStackEntry& data = *callData->mStack.AppendElement();
 
-      nsCString string;
-      rv = stack->GetFilename(string);
+      rv = stack->GetFilename(data.mFilename);
       if (NS_FAILED(rv)) {
         Throw(aCx, rv);
         return;
       }
 
-      CopyUTF8toUTF16(string, data.mFilename);
-
       int32_t lineNumber;
       rv = stack->GetLineNumber(&lineNumber);
       if (NS_FAILED(rv)) {
         Throw(aCx, rv);
         return;
       }
 
       data.mLineNumber = lineNumber;
 
-      rv = stack->GetName(string);
+      rv = stack->GetName(data.mFunctionName);
       if (NS_FAILED(rv)) {
         Throw(aCx, rv);
         return;
       }
 
-      CopyUTF8toUTF16(string, data.mFunctionName);
-
       data.mLanguage = language;
     }
 
     nsCOMPtr<nsIStackFrame> caller;
     rv = stack->GetCaller(getter_AddRefs(caller));
     if (NS_FAILED(rv)) {
       Throw(aCx, rv);
       return;
--- a/dom/base/DOMException.cpp
+++ b/dom/base/DOMException.cpp
@@ -315,19 +315,19 @@ Exception::GetName(nsACString& aName)
     if (name) {
       aName.Assign(name);
     }
   }
 
   return NS_OK;
 }
 
-/* readonly attribute AUTF8String filename; */
+/* readonly attribute AString filename; */
 NS_IMETHODIMP
-Exception::GetFilename(nsACString& aFilename)
+Exception::GetFilename(nsAString& aFilename)
 {
   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
 
   if (mLocation) {
     return mLocation->GetFilename(aFilename);
   }
 
   aFilename.Assign(mFilename);
@@ -504,28 +504,16 @@ Exception::GetName(nsString& retval)
 #ifdef DEBUG
   DebugOnly<nsresult> rv =
 #endif
   GetName(str);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   CopyUTF8toUTF16(str, retval);
 }
 
-void
-Exception::GetFilename(nsString& retval)
-{
-  nsCString str;
-#ifdef DEBUG
-  DebugOnly<nsresult> rv =
-#endif
-  GetFilename(str);
-  MOZ_ASSERT(NS_SUCCEEDED(rv));
-  CopyUTF8toUTF16(str, retval);
-}
-
 uint32_t
 Exception::LineNumber() const
 {
   if (mLocation) {
     int32_t lineno;
     if (NS_SUCCEEDED(mLocation->GetLineNumber(&lineno))) {
       return lineno;
     }
@@ -617,25 +605,27 @@ DOMException::ToString(nsACString& aRetu
   static const char defaultLocation[] = "<unknown>";
   static const char defaultName[] = "<unknown>";
   static const char format[] =
     "[Exception... \"%s\"  code: \"%d\" nsresult: \"0x%x (%s)\"  location: \"%s\"]";
 
   nsAutoCString location;
 
   if (mInner) {
-    nsCString filename;
+    nsString filename;
     mInner->GetFilename(filename);
 
     if (!filename.IsEmpty()) {
       uint32_t line_nr = 0;
 
       mInner->GetLineNumber(&line_nr);
 
-      char *temp = PR_smprintf("%s Line: %d", filename.get(), line_nr);
+      char *temp = PR_smprintf("%s Line: %d",
+                               NS_ConvertUTF16toUTF8(filename).get(),
+                               line_nr);
       if (temp) {
         location.Assign(temp);
         PR_smprintf_free(temp);
       }
     }
   }
 
   if (location.IsEmpty()) {
--- a/dom/base/DOMException.h
+++ b/dom/base/DOMException.h
@@ -64,17 +64,17 @@ public:
   nsISupports* GetParentObject() const { return nullptr; }
 
   void GetMessageMoz(nsString& retval);
 
   uint32_t Result() const;
 
   void GetName(nsString& retval);
 
-  void GetFilename(nsString& retval);
+  // The XPCOM GetFilename does the right thing.
 
   uint32_t LineNumber() const;
 
   uint32_t ColumnNumber() const;
 
   already_AddRefed<nsIStackFrame> GetLocation() const;
 
   already_AddRefed<nsISupports> GetInner() const;
@@ -95,17 +95,17 @@ public:
 protected:
   virtual ~Exception();
 
   nsCString       mMessage;
   nsresult        mResult;
   nsCString       mName;
   nsCOMPtr<nsIStackFrame> mLocation;
   nsCOMPtr<nsISupports> mData;
-  nsCString       mFilename;
+  nsString        mFilename;
   int             mLineNumber;
   nsCOMPtr<nsIException> mInner;
   bool            mInitialized;
 
   bool mHoldingJSVal;
   JS::Heap<JS::Value> mThrownJSVal;
 
 private:
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -16,17 +16,17 @@ load 375399-1.html
 load 404869-1.xul
 load 417852-1.html
 load 462947.html
 load 439206-1.html
 load 473284.xul
 load 499006-1.html
 load 499006-2.html
 load 502617.html
-asserts(1-2) load 504224.html # bug 564098
+load 504224.html
 load 603531.html
 load 601247.html
 load 609560-1.xhtml
 load 612018-1.html
 load 637116.html
 load 666869.html
 load 675621-1.html
 load 677194.html
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -80,17 +80,16 @@
 #include "nsIDOMXULCheckboxElement.h"
 #include "nsIDOMXULPopupElement.h"
 
 // Event related includes
 #include "nsIDOMEventTarget.h"
 
 // CSS related includes
 #include "nsCSSRules.h"
-#include "nsIDOMStyleSheetList.h"
 #include "nsIDOMCSSRule.h"
 #include "nsICSSRuleList.h"
 #include "nsAutoPtr.h"
 #include "nsMemory.h"
 
 // Tranformiix
 #include "nsIXSLTProcessor.h"
 #include "nsIXSLTProcessorPrivate.h"
@@ -117,17 +116,16 @@
 #include "nsIXULTemplateBuilder.h"
 #include "nsITreeColumns.h"
 #endif
 #include "nsIDOMXPathExpression.h"
 #include "nsIDOMNSXPathExpression.h"
 #include "nsIDOMXPathNSResolver.h"
 #include "nsIDOMXPathResult.h"
 
-#include "nsIDOMSVGLength.h"
 #include "nsIDOMSVGNumber.h"
 
 // Storage includes
 #include "nsIDOMStorage.h"
 #include "nsPIDOMStorage.h"
 
 // Drag and drop
 #include "nsIDOMFile.h"
@@ -314,18 +312,16 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(CSSImportRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CSSMediaRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CSSNameSpaceRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CSSRuleList, nsCSSRuleListSH,
                            ARRAY_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(StyleSheetList, nsStyleSheetListSH,
-                           ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CSSStyleSheet, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   // XUL classes
 #ifdef MOZ_XUL
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCommandDispatcher, nsDOMGenericSH,
                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
@@ -360,18 +356,16 @@ static nsDOMClassInfoData sClassInfoData
 
   NS_DEFINE_CLASSINFO_DATA(CSSMozDocumentRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(CSSSupportsRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   // other SVG classes
-  NS_DEFINE_CLASSINFO_DATA(SVGLength, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(SVGNumber, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(WindowUtils, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(XSLTProcessor, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -943,20 +937,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(CSSNameSpaceRule, nsIDOMCSSRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSRule)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CSSRuleList, nsIDOMCSSRuleList)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSRuleList)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(StyleSheetList, nsIDOMStyleSheetList)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMStyleSheetList)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(CSSStyleSheet, nsIDOMCSSStyleSheet)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSStyleSheet)
   DOM_CLASSINFO_MAP_END
 
 #ifdef MOZ_XUL
   DOM_CLASSINFO_MAP_BEGIN(XULCommandDispatcher, nsIDOMXULCommandDispatcher)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCommandDispatcher)
   DOM_CLASSINFO_MAP_END
@@ -1013,20 +1003,16 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN(CSSSupportsRule, nsIDOMCSSSupportsRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSSupportsRule)
   DOM_CLASSINFO_MAP_END
 
   // The SVG document
 
   // other SVG classes
-  DOM_CLASSINFO_MAP_BEGIN(SVGLength, nsIDOMSVGLength)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGLength)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(SVGNumber, nsIDOMSVGNumber)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGNumber)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(XSLTProcessor, nsIXSLTProcessor)
     DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessor)
     DOM_CLASSINFO_MAP_ENTRY(nsIXSLTProcessorPrivate)
   DOM_CLASSINFO_MAP_END
@@ -3675,29 +3661,16 @@ nsArraySH::GetProperty(nsIXPConnectWrapp
       rv = NS_SUCCESS_I_DID_SOMETHING;
     }
   }
 
   return rv;
 }
 
 
-// StyleSheetList helper
-
-nsISupports*
-nsStyleSheetListSH::GetItemAt(nsISupports *aNative, uint32_t aIndex,
-                              nsWrapperCache **aCache, nsresult *rv)
-{
-  nsIDOMStyleSheetList* list = static_cast<nsIDOMStyleSheetList*>(aNative);
-  nsCOMPtr<nsIDOMStyleSheet> sheet;
-  list->Item(aIndex, getter_AddRefs(sheet));
-  return sheet;
-}
-
-
 // CSSRuleList scriptable helper
 
 nsISupports*
 nsCSSRuleListSH::GetItemAt(nsISupports *aNative, uint32_t aIndex,
                            nsWrapperCache **aCache, nsresult *aResult)
 {
   nsICSSRuleList* list = static_cast<nsICSSRuleList*>(aNative);
 #ifdef DEBUG
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -363,40 +363,16 @@ public:
                          JSObject *obj, jsid id, JS::Value *vp, bool *_retval) MOZ_OVERRIDE;
 
 private:
   // Not implemented, nothing should create an instance of this class.
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData);
 };
 
 
-// StyleSheetList helper
-
-class nsStyleSheetListSH : public nsArraySH
-{
-protected:
-  nsStyleSheetListSH(nsDOMClassInfoData* aData) : nsArraySH(aData)
-  {
-  }
-
-  virtual ~nsStyleSheetListSH()
-  {
-  }
-
-  virtual nsISupports* GetItemAt(nsISupports *aNative, uint32_t aIndex,
-                                 nsWrapperCache **aCache, nsresult *aResult) MOZ_OVERRIDE;
-
-public:
-  static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
-  {
-    return new nsStyleSheetListSH(aData);
-  }
-};
-
-
 // CSSRuleList helper
 
 class nsCSSRuleListSH : public nsArraySH
 {
 protected:
   nsCSSRuleListSH(nsDOMClassInfoData* aData) : nsArraySH(aData)
   {
   }
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -11,17 +11,16 @@ DOMCI_CLASS(DOMConstructor)
 
 // CSS classes
 DOMCI_CLASS(CSSStyleRule)
 DOMCI_CLASS(CSSCharsetRule)
 DOMCI_CLASS(CSSImportRule)
 DOMCI_CLASS(CSSMediaRule)
 DOMCI_CLASS(CSSNameSpaceRule)
 DOMCI_CLASS(CSSRuleList)
-DOMCI_CLASS(StyleSheetList)
 DOMCI_CLASS(CSSStyleSheet)
 
 // XUL classes
 #ifdef MOZ_XUL
 DOMCI_CLASS(XULCommandDispatcher)
 #endif
 DOMCI_CLASS(XULControllers)
 DOMCI_CLASS(BoxObject)
@@ -41,17 +40,16 @@ DOMCI_CLASS(XULTreeBuilder)
 #ifdef MOZ_XUL
 DOMCI_CLASS(TreeColumn)
 #endif
 
 DOMCI_CLASS(CSSMozDocumentRule)
 DOMCI_CLASS(CSSSupportsRule)
 
 // other SVG classes
-DOMCI_CLASS(SVGLength)
 DOMCI_CLASS(SVGNumber)
 
 // WindowUtils
 DOMCI_CLASS(WindowUtils)
 
 // XSLTProcessor
 DOMCI_CLASS(XSLTProcessor)
 
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -429,44 +429,25 @@ nsDOMWindowUtils::SetDisplayPortMarginsF
   if (!content) {
     return NS_ERROR_INVALID_ARG;
   }
 
   if (content->GetCurrentDoc() != presShell->GetDocument()) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  DisplayPortMarginsPropertyData* currentData =
-    static_cast<DisplayPortMarginsPropertyData*>(content->GetProperty(nsGkAtoms::DisplayPortMargins));
-  if (currentData && currentData->mPriority > aPriority) {
-    return NS_OK;
-  }
-
   // Note order change of arguments between our function signature and
   // LayerMargin constructor.
   LayerMargin displayportMargins(aTopMargin,
                                  aRightMargin,
                                  aBottomMargin,
                                  aLeftMargin);
 
-  content->SetProperty(nsGkAtoms::DisplayPortMargins,
-                       new DisplayPortMarginsPropertyData(displayportMargins, aAlignmentX, aAlignmentY, aPriority),
-                       nsINode::DeleteProperty<DisplayPortMarginsPropertyData>);
-
-  nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
-  if (rootScrollFrame && content == rootScrollFrame->GetContent()) {
-    // We are setting a root displayport for a document.
-    // The pres shell needs a special flag set.
-    presShell->SetIgnoreViewportScrolling(true);
-  }
-
-  nsIFrame* rootFrame = presShell->FrameManager()->GetRootFrame();
-  if (rootFrame) {
-    rootFrame->SchedulePaint();
-  }
+  nsLayoutUtils::SetDisplayPortMargins(content, presShell, displayportMargins,
+                                       aAlignmentX, aAlignmentY, aPriority);
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SetDisplayPortBaseForElement(int32_t aX,
                                                int32_t aY,
@@ -492,18 +473,17 @@ nsDOMWindowUtils::SetDisplayPortBaseForE
   if (!content) {
     return NS_ERROR_INVALID_ARG;
   }
 
   if (content->GetCurrentDoc() != presShell->GetDocument()) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  content->SetProperty(nsGkAtoms::DisplayPortBase, new nsRect(aX, aY, aWidth, aHeight),
-                       nsINode::DeleteProperty<nsRect>);
+  nsLayoutUtils::SetDisplayPortBase(content, nsRect(aX, aY, aWidth, aHeight));
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SetCriticalDisplayPortForElement(float aXPx, float aYPx,
                                                    float aWidthPx, float aHeightPx,
                                                    nsIDOMElement* aElement)
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -106,31 +106,35 @@ public:
     mImpl.construct(aValue1, aValue2);
   }
 
   bool WasPassed() const
   {
     return !mImpl.empty();
   }
 
-  void Construct()
+  // Return InternalType here so we can work with it usefully.
+  InternalType& Construct()
   {
     mImpl.construct();
+    return mImpl.ref();
   }
 
   template <class T1>
-  void Construct(const T1 &t1)
+  InternalType& Construct(const T1 &t1)
   {
     mImpl.construct(t1);
+    return mImpl.ref();
   }
 
   template <class T1, class T2>
-  void Construct(const T1 &t1, const T2 &t2)
+  InternalType& Construct(const T1 &t1, const T2 &t2)
   {
     mImpl.construct(t1, t2);
+    return mImpl.ref();
   }
 
   void Reset()
   {
     if (WasPassed()) {
       mImpl.destroy();
     }
   }
@@ -223,28 +227,28 @@ public:
     Optional_base<JSObject*, JSObject*>()
   {}
 
   explicit Optional(JSObject* aValue) :
     Optional_base<JSObject*, JSObject*>(aValue)
   {}
 
   // Don't allow us to have an uninitialized JSObject*
-  void Construct()
+  JSObject*& Construct()
   {
     // The Android compiler sucks and thinks we're trying to construct
     // a JSObject* from an int if we don't cast here.  :(
-    Optional_base<JSObject*, JSObject*>::Construct(
+    return Optional_base<JSObject*, JSObject*>::Construct(
       static_cast<JSObject*>(nullptr));
   }
 
   template <class T1>
-  void Construct(const T1& t1)
+  JSObject*& Construct(const T1& t1)
   {
-    Optional_base<JSObject*, JSObject*>::Construct(t1);
+    return Optional_base<JSObject*, JSObject*>::Construct(t1);
   }
 };
 
 // A specialization of Optional for JS::Value to make sure no one ever uses it.
 template<>
 class Optional<JS::Value>
 {
 private:
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1050,16 +1050,21 @@ DOMInterfaces = {
     'concrete': False,
     'resultNotAddRefed': ['nearestViewportElement', 'farthestViewportElement']
 },
 
 'SVGGradientElement': {
     'concrete': False,
 },
 
+'SVGLength': {
+    'nativeType': 'mozilla::DOMSVGLength',
+    'headerFile': 'DOMSVGLength.h'
+},
+
 'SVGLengthList': {
     'nativeType': 'mozilla::DOMSVGLengthList',
     'headerFile': 'DOMSVGLengthList.h'
 },
 
 'SVGLinearGradientElement': {
     'headerFile': 'mozilla/dom/SVGGradientElement.h',
 },
@@ -1910,18 +1915,16 @@ addExternalIface('nsIDocShell', nativeTy
 addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True)
 addExternalIface('nsIVariant', nativeType='nsIVariant', notflattened=True)
 addExternalIface('OutputStream', nativeType='nsIOutputStream',
                  notflattened=True)
 addExternalIface('Principal', nativeType='nsIPrincipal',
                  headerFile='nsIPrincipal.h', notflattened=True)
 addExternalIface('StackFrame', nativeType='nsIStackFrame',
                  headerFile='nsIException.h', notflattened=True)
-addExternalIface('StyleSheetList')
-addExternalIface('SVGLength')
 addExternalIface('SVGNumber')
 addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h',
                  notflattened=True)
 addExternalIface('UserDataHandler')
 addExternalIface('XPathResult', nativeType='nsISupports')
 addExternalIface('XPathExpression')
 addExternalIface('XPathNSResolver')
 addExternalIface('XULCommandDispatcher')
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -297,18 +297,18 @@ private:
   }
 
   int32_t GetLineno();
 
   nsRefPtr<StackDescriptionOwner> mStackDescription;
   nsCOMPtr<nsIStackFrame> mCaller;
 
   // Cached values
-  nsCString mFilename;
-  nsCString mFunname;
+  nsString mFilename;
+  nsString mFunname;
   int32_t mLineno;
   uint32_t mLanguage;
 
   size_t mIndex;
 
   bool mFilenameInitialized;
   bool mFunnameInitialized;
   bool mLinenoInitialized;
@@ -369,44 +369,46 @@ NS_IMETHODIMP JSStackFrame::GetLanguageN
     aLanguageName.AssignASCII(js);
   } else {
     aLanguageName.AssignASCII(cpp);
   }
 
   return NS_OK;
 }
 
-/* readonly attribute string filename; */
-NS_IMETHODIMP JSStackFrame::GetFilename(nsACString& aFilename)
+/* readonly attribute AString filename; */
+NS_IMETHODIMP JSStackFrame::GetFilename(nsAString& aFilename)
 {
   if (!mFilenameInitialized) {
     JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex);
     if (const char *filename = desc.filename()) {
-      mFilename.Assign(filename);
+      CopyUTF8toUTF16(filename, mFilename);
     }
     mFilenameInitialized = true;
   }
 
   // The filename must be set to null if empty.
   if (mFilename.IsEmpty()) {
     aFilename.SetIsVoid(true);
   } else {
     aFilename.Assign(mFilename);
   }
 
   return NS_OK;
 }
 
-/* readonly attribute string name; */
-NS_IMETHODIMP JSStackFrame::GetName(nsACString& aFunction)
+/* readonly attribute AString name; */
+NS_IMETHODIMP JSStackFrame::GetName(nsAString& aFunction)
 {
   if (!mFunnameInitialized) {
     JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex);
     if (JSFlatString *name = desc.funDisplayName()) {
-      CopyUTF16toUTF8(JS_GetFlatStringChars(name), mFunname);
+      mFunname.Assign(JS_GetFlatStringChars(name),
+                      // XXXbz Can't JS_GetStringLength on JSFlatString!
+                      JS_GetStringLength(JS_FORGET_STRING_FLATNESS(name)));
     }
     mFunnameInitialized = true;
   }
 
   // The function name must be set to null if empty.
   if (mFunname.IsEmpty()) {
     aFunction.SetIsVoid(true);
   } else {
@@ -455,34 +457,36 @@ NS_IMETHODIMP JSStackFrame::GetCaller(ns
 
 /* AUTF8String toString (); */
 NS_IMETHODIMP JSStackFrame::ToString(nsACString& _retval)
 {
   _retval.Truncate();
 
   const char* frametype = IsJSFrame() ? "JS" : "native";
 
-  nsCString filename;
+  nsString filename;
   nsresult rv = GetFilename(filename);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (filename.IsEmpty()) {
-    filename.AssignASCII("<unknown filename>");
+    filename.AssignLiteral("<unknown filename>");
   }
 
-  nsCString funname;
+  nsString funname;
   rv = GetName(funname);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (funname.IsEmpty()) {
-    funname.AssignASCII("<TOP_LEVEL>");
+    funname.AssignLiteral("<TOP_LEVEL>");
   }
   static const char format[] = "%s frame :: %s :: %s :: line %d";
-  _retval.AppendPrintf(format, frametype, filename.get(),
-                       funname.get(), GetLineno());
+  _retval.AppendPrintf(format, frametype,
+                       NS_ConvertUTF16toUTF8(filename).get(),
+                       NS_ConvertUTF16toUTF8(funname).get(),
+                       GetLineno());
   return NS_OK;
 }
 
 /* static */ already_AddRefed<nsIStackFrame>
 JSStackFrame::CreateStack(JSContext* aCx, int32_t aMaxDepth)
 {
   static const unsigned MAX_FRAMES = 100;
   if (aMaxDepth < 0) {
@@ -506,18 +510,18 @@ JSStackFrame::CreateStackFrameLocation(u
                                        const char* aFunctionName,
                                        int32_t aLineNumber,
                                        nsIStackFrame* aCaller)
 {
   nsRefPtr<JSStackFrame> self = new JSStackFrame(nullptr, 0);
 
   self->mLanguage = aLanguage;
   self->mLineno = aLineNumber;
-  self->mFilename = aFilename;
-  self->mFunname = aFunctionName;
+  CopyUTF8toUTF16(aFilename, self->mFilename);
+  CopyUTF8toUTF16(aFunctionName, self->mFunname);
 
   self->mCaller = aCaller;
 
   return self.forget();
 }
 
 already_AddRefed<nsIStackFrame>
 CreateStack(JSContext* aCx, int32_t aMaxDepth)
--- a/dom/bindings/ToJSValue.h
+++ b/dom/bindings/ToJSValue.h
@@ -188,16 +188,26 @@ template <typename T>
 bool
 ToJSValue(JSContext* aCx,
           const nsRefPtr<T>& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   return ToJSValue(aCx, *aArgument.get(), aValue);
 }
 
+// Accept WebIDL dictionaries
+template <class T>
+typename EnableIf<IsBaseOf<DictionaryBase, T>::value, bool>::Type
+ToJSValue(JSContext* aCx,
+          const T& aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  return aArgument.ToObject(aCx, aValue);
+}
+
 // Accept arrays of other things we accept
 template <typename T>
 bool
 ToJSValue(JSContext* aCx,
           T* aArguments,
           size_t aLength,
           JS::MutableHandle<JS::Value> aValue)
 {
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -722,17 +722,17 @@ nsDOMCameraControl::StartRecording(const
 
   NotifyRecordingStatusChange(NS_LITERAL_STRING("starting"));
 
 #ifdef MOZ_B2G
   if (!mAudioChannelAgent) {
     mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1");
     if (mAudioChannelAgent) {
       // Camera app will stop recording when it falls to the background, so no callback is necessary.
-      mAudioChannelAgent->Init(mWindow, AUDIO_CHANNEL_CONTENT, nullptr);
+      mAudioChannelAgent->Init(mWindow, (int32_t)AudioChannel::Content, nullptr);
       // Video recording doesn't output any sound, so it's not necessary to check canPlay.
       int32_t canPlay;
       mAudioChannelAgent->StartPlaying(&canPlay);
     }
   }
 #endif
 
   nsCOMPtr<nsIDOMDOMRequest> request;
--- a/dom/interfaces/html/moz.build
+++ b/dom/interfaces/html/moz.build
@@ -8,17 +8,16 @@ XPIDL_SOURCES += [
     'nsIDOMHTMLAnchorElement.idl',
     'nsIDOMHTMLAppletElement.idl',
     'nsIDOMHTMLAreaElement.idl',
     'nsIDOMHTMLAudioElement.idl',
     'nsIDOMHTMLBaseElement.idl',
     'nsIDOMHTMLBodyElement.idl',
     'nsIDOMHTMLBRElement.idl',
     'nsIDOMHTMLButtonElement.idl',
-    'nsIDOMHTMLByteRanges.idl',
     'nsIDOMHTMLCanvasElement.idl',
     'nsIDOMHTMLCollection.idl',
     'nsIDOMHTMLDirectoryElement.idl',
     'nsIDOMHTMLDivElement.idl',
     'nsIDOMHTMLDocument.idl',
     'nsIDOMHTMLElement.idl',
     'nsIDOMHTMLEmbedElement.idl',
     'nsIDOMHTMLFieldSetElement.idl',
deleted file mode 100644
--- a/dom/interfaces/html/nsIDOMHTMLByteRanges.idl
+++ /dev/null
@@ -1,27 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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 "domstubs.idl"
-
-[scriptable, uuid(992c540c-4d81-42df-80a6-f71ede2b59d8)]
-interface nsIDOMHTMLByteRanges : nsISupports
-{
-  /* The number of ranges represented by the object */
-  readonly attribute unsigned long length;
-
-  /* The start(index) method must return the position of the first
-     byte of the indexth range represented by the object. */
-  unsigned long start(in unsigned long index);
-
-  /* The end(index) method must return the position of the byte
-     immediately after the last byte of the indexth range represented
-     by the object. (The byte position returned by this method is not
-     in the range itself. If the first byte of the range is the byte
-     at position 0, and the entire stream of bytes is in the range,
-     then the value of the position of the byte returned by this
-     method for that range will be the same as the number of bytes in
-     the stream.) */
-  unsigned long end(in unsigned long index);
-};
--- a/dom/interfaces/storage/moz.build
+++ b/dom/interfaces/storage/moz.build
@@ -3,17 +3,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIDOMStorage.idl',
     'nsIDOMStorageEvent.idl',
     'nsIDOMStorageManager.idl',
-    'nsIDOMToString.idl',
 ]
 
 XPIDL_MODULE = 'dom_storage'
 
 EXPORTS += [
     'nsPIDOMStorage.h',
 ]
 
deleted file mode 100644
--- a/dom/interfaces/storage/nsIDOMToString.idl
+++ /dev/null
@@ -1,23 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "domstubs.idl"
-
-/**
- * The sole purpose of this interface is to make it easy for XPCOM
- * object's to hook into JS' toString() when interacting with
- * XPConnect. If you implement this interface and advertize it in the
- * object's classinfo, you'll get automatic mapping from JS'
- * toString() to the toString() method in this interface.
- *
- * XXXjst: This doesn't really belong in dom/public/idl/storage, but
- * it gets to live here until I find a more suitable place.
- */
-
-[scriptable, uuid(2a72e20f-e337-4822-8994-2e35b5550d03)]
-interface nsIDOMToString : nsISupports
-{
-  DOMString toString();
-};
--- a/dom/interfaces/stylesheets/nsIDOMStyleSheetList.idl
+++ b/dom/interfaces/stylesheets/nsIDOMStyleSheetList.idl
@@ -8,14 +8,15 @@
 /**
  * The nsIDOMStyleSheetList interface is a datatype for a style sheet
  * list in the Document Object Model.
  *
  * For more information on this interface please see
  * http://www.w3.org/TR/DOM-Level-2-Style
  */
 
-[scriptable, uuid(a6cf9081-15b3-11d2-932e-00805f8add32)]
+[scriptable, uuid(0e424250-ac2a-4fe2-bccd-a45824af090e)]
 interface nsIDOMStyleSheetList : nsISupports
 {
   readonly attribute unsigned long    length;
+  [binaryname(SlowItem)]
   nsIDOMStyleSheet         item(in unsigned long index);
 };
--- a/dom/ipc/AppProcessChecker.cpp
+++ b/dom/ipc/AppProcessChecker.cpp
@@ -9,16 +9,17 @@
 #include "nsIPermissionManager.h"
 #ifdef MOZ_CHILD_PERMISSIONS
 #include "ContentParent.h"
 #include "mozIApplication.h"
 #include "mozilla/hal_sandbox/PHalParent.h"
 #include "nsIAppsService.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
+#include "nsPrintfCString.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "TabParent.h"
 
 #include <algorithm>
 
 using namespace mozilla::dom;
@@ -110,17 +111,21 @@ AssertAppProcess(PContentParent* aActor,
   const InfallibleTArray<PBrowserParent*>& browsers =
     aActor->ManagedPBrowserParent();
   for (uint32_t i = 0; i < browsers.Length(); ++i) {
     if (AssertAppProcess(browsers[i], aType, aCapability)) {
       return true;
     }
   }
 
-  printf_stderr("Security problem: Content process does not have `%s'.  It will be killed.\n", aCapability);
+  NS_ERROR(
+    nsPrintfCString(
+      "Security problem: Content process does not have `%s'.  It will be killed.\n",
+      aCapability).get());
+
   static_cast<ContentParent*>(aActor)->KillHard();
 
   return false;
 }
 
 bool
 AssertAppStatus(PContentParent* aActor,
                 unsigned short aStatus)
@@ -128,17 +133,21 @@ AssertAppStatus(PContentParent* aActor,
   const InfallibleTArray<PBrowserParent*>& browsers =
     aActor->ManagedPBrowserParent();
   for (uint32_t i = 0; i < browsers.Length(); ++i) {
     if (AssertAppStatus(browsers[i], aStatus)) {
       return true;
     }
   }
 
-  printf_stderr("Security problem: Content process does not have `%d' status.  It will be killed.\n", aStatus);
+  NS_ERROR(
+    nsPrintfCString(
+      "Security problem: Content process does not have `%d' status.  It will be killed.",
+      aStatus).get());
+
   static_cast<ContentParent*>(aActor)->KillHard();
 
   return false;
 }
 
 bool
 AssertAppProcess(PHalParent* aActor,
                  AssertAppProcessType aType,
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1894,75 +1894,75 @@ ContentParent::RecvFirstIdle()
     // which we use as a good time to prelaunch another process. If we
     // prelaunch any sooner than this, then we'll be competing with the
     // child process and slowing it down.
     PreallocatedProcessManager::AllocateAfterDelay();
     return true;
 }
 
 bool
-ContentParent::RecvAudioChannelGetState(const AudioChannelType& aType,
+ContentParent::RecvAudioChannelGetState(const AudioChannel& aChannel,
                                         const bool& aElementHidden,
                                         const bool& aElementWasHidden,
                                         AudioChannelState* aState)
 {
     nsRefPtr<AudioChannelService> service =
         AudioChannelService::GetAudioChannelService();
     *aState = AUDIO_CHANNEL_STATE_NORMAL;
     if (service) {
-        *aState = service->GetStateInternal(aType, mChildID,
+        *aState = service->GetStateInternal(aChannel, mChildID,
                                             aElementHidden, aElementWasHidden);
     }
     return true;
 }
 
 bool
-ContentParent::RecvAudioChannelRegisterType(const AudioChannelType& aType,
+ContentParent::RecvAudioChannelRegisterType(const AudioChannel& aChannel,
                                             const bool& aWithVideo)
 {
     nsRefPtr<AudioChannelService> service =
         AudioChannelService::GetAudioChannelService();
     if (service) {
-        service->RegisterType(aType, mChildID, aWithVideo);
+        service->RegisterType(aChannel, mChildID, aWithVideo);
     }
     return true;
 }
 
 bool
-ContentParent::RecvAudioChannelUnregisterType(const AudioChannelType& aType,
+ContentParent::RecvAudioChannelUnregisterType(const AudioChannel& aChannel,
                                               const bool& aElementHidden,
                                               const bool& aWithVideo)
 {
     nsRefPtr<AudioChannelService> service =
         AudioChannelService::GetAudioChannelService();
     if (service) {
-        service->UnregisterType(aType, aElementHidden, mChildID, aWithVideo);
+        service->UnregisterType(aChannel, aElementHidden, mChildID, aWithVideo);
     }
     return true;
 }
 
 bool
 ContentParent::RecvAudioChannelChangedNotification()
 {
     nsRefPtr<AudioChannelService> service =
         AudioChannelService::GetAudioChannelService();
     if (service) {
        service->SendAudioChannelChangedNotification(ChildID());
     }
     return true;
 }
 
 bool
-ContentParent::RecvAudioChannelChangeDefVolChannel(
-  const AudioChannelType& aType, const bool& aHidden)
+ContentParent::RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
+                                                   const bool& aHidden)
 {
     nsRefPtr<AudioChannelService> service =
         AudioChannelService::GetAudioChannelService();
     if (service) {
-       service->SetDefaultVolumeControlChannelInternal(aType,
+       service->SetDefaultVolumeControlChannelInternal(aChannel,
                                                        aHidden, mChildID);
     }
     return true;
 }
 
 bool
 ContentParent::RecvBroadcastVolume(const nsString& aVolumeName)
 {
@@ -1979,18 +1979,21 @@ ContentParent::RecvBroadcastVolume(const
 #endif
 }
 
 bool
 ContentParent::RecvNuwaReady()
 {
 #ifdef MOZ_NUWA_PROCESS
     if (!IsNuwaProcess()) {
-        printf_stderr("Terminating child process %d for unauthorized IPC message: "
-                      "NuwaReady", Pid());
+        NS_ERROR(
+            nsPrintfCString(
+                "Terminating child process %d for unauthorized IPC message: NuwaReady",
+                Pid()).get());
+
         KillHard();
         return false;
     }
     PreallocatedProcessManager::OnNuwaReady();
     return true;
 #else
     NS_ERROR("ContentParent::RecvNuwaReady() not implemented!");
     return false;
@@ -1998,18 +2001,21 @@ ContentParent::RecvNuwaReady()
 }
 
 bool
 ContentParent::RecvAddNewProcess(const uint32_t& aPid,
                                  const InfallibleTArray<ProtocolFdMapping>& aFds)
 {
 #ifdef MOZ_NUWA_PROCESS
     if (!IsNuwaProcess()) {
-        printf_stderr("Terminating child process %d for unauthorized IPC message: "
-                      "AddNewProcess(%d)", Pid(), aPid);
+        NS_ERROR(
+            nsPrintfCString(
+                "Terminating child process %d for unauthorized IPC message: "
+                "AddNewProcess(%d)", Pid(), aPid).get());
+
         KillHard();
         return false;
     }
     nsRefPtr<ContentParent> content;
     content = new ContentParent(this,
                                 MAGIC_PREALLOCATED_APP_MANIFEST_URL,
                                 aPid,
                                 aFds);
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -485,30 +485,30 @@ private:
                                  const uint32_t& aColNumber,
                                  const uint32_t& aFlags,
                                  const nsCString& aCategory) MOZ_OVERRIDE;
 
     virtual bool RecvPrivateDocShellsExist(const bool& aExist) MOZ_OVERRIDE;
 
     virtual bool RecvFirstIdle() MOZ_OVERRIDE;
 
-    virtual bool RecvAudioChannelGetState(const AudioChannelType& aType,
+    virtual bool RecvAudioChannelGetState(const AudioChannel& aChannel,
                                           const bool& aElementHidden,
                                           const bool& aElementWasHidden,
                                           AudioChannelState* aValue) MOZ_OVERRIDE;
 
-    virtual bool RecvAudioChannelRegisterType(const AudioChannelType& aType,
+    virtual bool RecvAudioChannelRegisterType(const AudioChannel& aChannel,
                                               const bool& aWithVideo) MOZ_OVERRIDE;
-    virtual bool RecvAudioChannelUnregisterType(const AudioChannelType& aType,
+    virtual bool RecvAudioChannelUnregisterType(const AudioChannel& aChannel,
                                                 const bool& aElementHidden,
                                                 const bool& aWithVideo) MOZ_OVERRIDE;
 
     virtual bool RecvAudioChannelChangedNotification() MOZ_OVERRIDE;
 
-    virtual bool RecvAudioChannelChangeDefVolChannel(const AudioChannelType& aType,
+    virtual bool RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
                                                      const bool& aHidden) MOZ_OVERRIDE;
 
     virtual bool RecvBroadcastVolume(const nsString& aVolumeName) MOZ_OVERRIDE;
 
     virtual bool RecvSpeakerManagerGetSpeakerStatus(bool* aValue) MOZ_OVERRIDE;
 
     virtual bool RecvSpeakerManagerForceSpeaker(const bool& aEnable) MOZ_OVERRIDE;
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -41,17 +41,17 @@ using struct ResourceMapping from "mozil
 using struct OverrideMapping from "mozilla/chrome/RegistryMessageUtils.h";
 using base::ChildPrivileges from "base/process_util.h";
 using struct IPC::Permission from "mozilla/net/NeckoMessageUtils.h";
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 using mozilla::dom::asmjscache::OpenMode from "mozilla/dom/asmjscache/AsmJSCache.h";
 using mozilla::dom::asmjscache::WriteParams from "mozilla/dom/asmjscache/AsmJSCache.h";
-using mozilla::dom::AudioChannelType from "AudioChannelCommon.h";
+using mozilla::dom::AudioChannel from "mozilla/dom/AudioChannelBinding.h";
 using mozilla::dom::AudioChannelState from "AudioChannelCommon.h";
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
 using gfxIntSize from "nsSize.h";
 
 namespace mozilla {
 namespace dom {
 
@@ -510,28 +510,27 @@ parent:
 
     // Notify the parent of the presence or absence of private docshells
     PrivateDocShellsExist(bool aExist);
 
     // Tell the parent that the child has gone idle for the first time
     async FirstIdle();
 
     // Get Muted from the main AudioChannelService.
-    sync AudioChannelGetState(AudioChannelType aType, bool aElementHidden,
+    sync AudioChannelGetState(AudioChannel aChannel, bool aElementHidden,
                               bool aElementWasHidden)
         returns (AudioChannelState value);
 
-    sync AudioChannelRegisterType(AudioChannelType aType, bool aWithVideo);
-    sync AudioChannelUnregisterType(AudioChannelType aType,
+    sync AudioChannelRegisterType(AudioChannel aChannel, bool aWithVideo);
+    sync AudioChannelUnregisterType(AudioChannel aChannel,
                                     bool aElementHidden,
                                     bool aWithVideo);
 
     async AudioChannelChangedNotification();
-    async AudioChannelChangeDefVolChannel(AudioChannelType aType,
-                                          bool aHidden);
+    async AudioChannelChangeDefVolChannel(int32_t aChannel, bool aHidden);
 
     async FilePathUpdateNotify(nsString aType,
                                nsString aStorageName,
                                nsString aFilepath,
                                nsCString aReason);
     // get nsIVolumeService to broadcast volume information
     async BroadcastVolume(nsString volumeName);
 
--- a/dom/ipc/TabMessageUtils.h
+++ b/dom/ipc/TabMessageUtils.h
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TABMESSAGE_UTILS_H
 #define TABMESSAGE_UTILS_H
 
 #include "AudioChannelCommon.h"
 #include "ipc/IPCMessageUtils.h"
+#include "mozilla/dom/AudioChannelBinding.h"
 #include "nsIDOMEvent.h"
 #include "nsCOMPtr.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 namespace mozilla {
@@ -53,26 +54,48 @@ struct ParamTraits<mozilla::dom::RemoteD
     return mozilla::dom::ReadRemoteEvent(aMsg, aIter, aResult);
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
   }
 };
 
-template <>
-struct ParamTraits<mozilla::dom::AudioChannelType>
-  : public EnumSerializer<mozilla::dom::AudioChannelType,
-                          mozilla::dom::AUDIO_CHANNEL_DEFAULT,
-                          mozilla::dom::AUDIO_CHANNEL_LAST>
-{ };
+template<>
+struct ParamTraits<mozilla::dom::AudioChannel>
+{
+  typedef mozilla::dom::AudioChannel paramType;
+
+  static bool IsLegalValue(const paramType &aValue) {
+    return aValue <= mozilla::dom::AudioChannel::Publicnotification;
+  }
+
+  static void Write(Message* aMsg, const paramType& aValue) {
+    MOZ_ASSERT(IsLegalValue(aValue));
+    WriteParam(aMsg, (uint32_t)aValue);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult) {
+    uint32_t value;
+    if(!ReadParam(aMsg, aIter, &value) ||
+       !IsLegalValue(paramType(value))) {
+      return false;
+    }
+    *aResult = paramType(value);
+    return true;
+  }
+
+  static void Log(const paramType& aParam, std::wstring* aLog)
+  {
+  }
+};
 
 template <>
 struct ParamTraits<mozilla::dom::AudioChannelState>
   : public EnumSerializer<mozilla::dom::AudioChannelState,
-                           mozilla::dom::AUDIO_CHANNEL_STATE_NORMAL,
-                           mozilla::dom::AUDIO_CHANNEL_STATE_LAST>
+                          mozilla::dom::AUDIO_CHANNEL_STATE_NORMAL,
+                          mozilla::dom::AUDIO_CHANNEL_STATE_LAST>
 { };
 
 }
 
 
 #endif
--- a/dom/mobilemessage/src/MmsMessage.cpp
+++ b/dom/mobilemessage/src/MmsMessage.cpp
@@ -9,16 +9,17 @@
 #include "jsfriendapi.h" // For js_DateGetMsecSinceEpoch
 #include "nsJSUtils.h"
 #include "nsContentUtils.h"
 #include "nsIDOMFile.h"
 #include "nsTArrayHelpers.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/mobilemessage/Constants.h" // For MessageType
 #include "mozilla/dom/mobilemessage/SmsTypes.h"
+#include "mozilla/dom/ToJSValue.h"
 #include "nsDOMFile.h"
 #include "nsCxPusher.h"
 
 using namespace mozilla::dom::mobilemessage;
 
 DOMCI_DATA(MozMmsMessage, mozilla::dom::MmsMessage)
 
 namespace mozilla {
@@ -462,86 +463,20 @@ MmsMessage::GetDeliveryInfo(JSContext* a
   // to return a more correct value. Ex, if .delivery = 'received', we should
   // also make .deliveryInfo = null, since the .deliveryInfo is useless.
   uint32_t length = mDeliveryInfo.Length();
   if (length == 0) {
     aDeliveryInfo.setNull();
     return NS_OK;
   }
 
-  JS::Rooted<JSObject*> deliveryInfo(
-    aCx, JS_NewArrayObject(aCx, length));
-  NS_ENSURE_TRUE(deliveryInfo, NS_ERROR_OUT_OF_MEMORY);
-
-  for (uint32_t i = 0; i < length; ++i) {
-    const MmsDeliveryInfo &info = mDeliveryInfo[i];
-
-    JS::Rooted<JSObject*> infoJsObj(
-      aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr()));
-    NS_ENSURE_TRUE(infoJsObj, NS_ERROR_OUT_OF_MEMORY);
-
-    JS::Rooted<JS::Value> tmpJsVal(aCx);
-    JSString* tmpJsStr;
-
-    // Get |info.mReceiver|.
-    tmpJsStr = JS_NewUCStringCopyN(aCx,
-                                   info.mReceiver.get(),
-                                   info.mReceiver.Length());
-    NS_ENSURE_TRUE(tmpJsStr, NS_ERROR_OUT_OF_MEMORY);
-
-    tmpJsVal.setString(tmpJsStr);
-    if (!JS_DefineProperty(aCx, infoJsObj, "receiver", tmpJsVal,
-                           nullptr, nullptr, JSPROP_ENUMERATE)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    // Get |info.mDeliveryStatus|.
-    tmpJsStr = JS_NewUCStringCopyN(aCx,
-                                   info.mDeliveryStatus.get(),
-                                   info.mDeliveryStatus.Length());
-    NS_ENSURE_TRUE(tmpJsStr, NS_ERROR_OUT_OF_MEMORY);
-
-    tmpJsVal.setString(tmpJsStr);
-    if (!JS_DefineProperty(aCx, infoJsObj, "deliveryStatus", tmpJsVal,
-                           nullptr, nullptr, JSPROP_ENUMERATE)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    // Get |info.mDeliveryTimestamp|.
-    tmpJsVal.setNumber(static_cast<double>(info.mDeliveryTimestamp));
-    if (!JS_DefineProperty(aCx, infoJsObj, "deliveryTimestamp", tmpJsVal,
-                           nullptr, nullptr, JSPROP_ENUMERATE)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    // Get |info.mReadStatus|.
-    tmpJsStr = JS_NewUCStringCopyN(aCx,
-                                   info.mReadStatus.get(),
-                                   info.mReadStatus.Length());
-    NS_ENSURE_TRUE(tmpJsStr, NS_ERROR_OUT_OF_MEMORY);
-
-    tmpJsVal.setString(tmpJsStr);
-    if (!JS_DefineProperty(aCx, infoJsObj, "readStatus", tmpJsVal,
-                           nullptr, nullptr, JSPROP_ENUMERATE)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    // Get |info.mReadTimestamp|.
-    tmpJsVal.setNumber(static_cast<double>(info.mReadTimestamp));
-    if (!JS_DefineProperty(aCx, infoJsObj, "readTimestamp", tmpJsVal,
-                           nullptr, nullptr, JSPROP_ENUMERATE)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    if (!JS_SetElement(aCx, deliveryInfo, i, infoJsObj)) {
-      return NS_ERROR_FAILURE;
-    }
+  if (!ToJSValue(aCx, mDeliveryInfo, aDeliveryInfo)) {
+    return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  aDeliveryInfo.setObject(*deliveryInfo);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MmsMessage::GetSender(nsAString& aSender)
 {
   aSender = mSender;
   return NS_OK;
--- a/dom/permission/tests/test_wifi-manage.html
+++ b/dom/permission/tests/test_wifi-manage.html
@@ -25,17 +25,17 @@ function verifier(success, failure) {
   }
 }
 
 var gData = [
   {
     perm: ["wifi-manage"],
     needParentPerm: true,
     obj: "mozWifiManager",
-    idl: "nsIDOMWifiManager",
+    webidl: "MozWifiManager",
     verifier: verifier.toSource(),
   },
 ]
 </script>
 </pre>
 </body>
 </html>
 
--- a/dom/system/gonk/AudioChannelManager.cpp
+++ b/dom/system/gonk/AudioChannelManager.cpp
@@ -20,17 +20,17 @@ namespace system {
 
 NS_IMPL_QUERY_INTERFACE_INHERITED1(AudioChannelManager, DOMEventTargetHelper,
                                    nsIDOMEventListener)
 NS_IMPL_ADDREF_INHERITED(AudioChannelManager, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(AudioChannelManager, DOMEventTargetHelper)
 
 AudioChannelManager::AudioChannelManager()
   : mState(SWITCH_STATE_UNKNOWN)
-  , mVolumeChannel(AUDIO_CHANNEL_DEFAULT)
+  , mVolumeChannel(-1)
 {
   RegisterSwitchObserver(SWITCH_HEADPHONES, this);
   mState = GetCurrentSwitchState(SWITCH_HEADPHONES);
   SetIsDOMBinding();
 }
 
 AudioChannelManager::~AudioChannelManager()
 {
@@ -75,69 +75,51 @@ AudioChannelManager::Notify(const Switch
 
 bool
 AudioChannelManager::SetVolumeControlChannel(const nsAString& aChannel)
 {
   if (aChannel.EqualsASCII("publicnotification")) {
     return false;
   }
 
-  AudioChannelType oldVolumeChannel = mVolumeChannel;
+  AudioChannel newChannel = AudioChannelService::GetAudioChannel(aChannel);
+
   // Only normal channel doesn't need permission.
-  if (aChannel.EqualsASCII("normal")) {
-    mVolumeChannel = AUDIO_CHANNEL_NORMAL;
-  } else {
+  if (newChannel != AudioChannel::Normal) {
     nsCOMPtr<nsIPermissionManager> permissionManager =
       do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
     if (!permissionManager) {
       return false;
     }
     uint32_t perm = nsIPermissionManager::UNKNOWN_ACTION;
     permissionManager->TestPermissionFromWindow(GetOwner(),
       nsCString(NS_LITERAL_CSTRING("audio-channel-") +
       NS_ConvertUTF16toUTF8(aChannel)).get(), &perm);
     if (perm != nsIPermissionManager::ALLOW_ACTION) {
       return false;
     }
-
-    if (aChannel.EqualsASCII("content")) {
-      mVolumeChannel = AUDIO_CHANNEL_CONTENT;
-    } else if (aChannel.EqualsASCII("notification")) {
-      mVolumeChannel = AUDIO_CHANNEL_NOTIFICATION;
-    } else if (aChannel.EqualsASCII("alarm")) {
-      mVolumeChannel = AUDIO_CHANNEL_ALARM;
-    } else if (aChannel.EqualsASCII("telephony")) {
-      mVolumeChannel = AUDIO_CHANNEL_TELEPHONY;
-    } else if (aChannel.EqualsASCII("ringer")) {
-      mVolumeChannel = AUDIO_CHANNEL_RINGER;
-    }
   }
 
-  if (oldVolumeChannel == mVolumeChannel) {
+  if (mVolumeChannel == (int32_t)newChannel) {
     return true;
   }
+
+  mVolumeChannel = (int32_t)newChannel;
+
   NotifyVolumeControlChannelChanged();
   return true;
 }
 
 bool
 AudioChannelManager::GetVolumeControlChannel(nsAString & aChannel)
 {
-  if (mVolumeChannel == AUDIO_CHANNEL_NORMAL) {
-    aChannel.AssignASCII("normal");
-  } else if (mVolumeChannel == AUDIO_CHANNEL_CONTENT) {
-    aChannel.AssignASCII("content");
-  } else if (mVolumeChannel == AUDIO_CHANNEL_NOTIFICATION) {
-    aChannel.AssignASCII("notification");
-  } else if (mVolumeChannel == AUDIO_CHANNEL_ALARM) {
-    aChannel.AssignASCII("alarm");
-  } else if (mVolumeChannel == AUDIO_CHANNEL_TELEPHONY) {
-    aChannel.AssignASCII("telephony");
-  } else if (mVolumeChannel == AUDIO_CHANNEL_RINGER) {
-    aChannel.AssignASCII("ringer");
+  if (mVolumeChannel >= 0) {
+    AudioChannelService::GetAudioChannelString(
+                                      static_cast<AudioChannel>(mVolumeChannel),
+                                      aChannel);
   } else {
     aChannel.AssignASCII("");
   }
 
   return true;
 }
 
 void
@@ -148,17 +130,17 @@ AudioChannelManager::NotifyVolumeControl
 
   bool isActive = false;
   docshell->GetIsActive(&isActive);
 
   AudioChannelService* service = AudioChannelService::GetAudioChannelService();
   if (isActive) {
     service->SetDefaultVolumeControlChannel(mVolumeChannel, isActive);
   } else {
-    service->SetDefaultVolumeControlChannel(AUDIO_CHANNEL_DEFAULT, isActive);
+    service->SetDefaultVolumeControlChannel(-1, isActive);
   }
 }
 
 NS_IMETHODIMP
 AudioChannelManager::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsAutoString type;
   aEvent->GetType(type);
--- a/dom/system/gonk/AudioChannelManager.h
+++ b/dom/system/gonk/AudioChannelManager.h
@@ -61,16 +61,16 @@ public:
   bool GetVolumeControlChannel(nsAString& aChannel);
 
   IMPL_EVENT_HANDLER(headphoneschange)
 
 private:
   void NotifyVolumeControlChannelChanged();
 
   hal::SwitchState mState;
-  AudioChannelType mVolumeChannel;
+  int32_t mVolumeChannel;
 };
 
 } // namespace system
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_system_AudioChannelManager_h
--- a/dom/system/gonk/AudioManager.cpp
+++ b/dom/system/gonk/AudioManager.cpp
@@ -124,24 +124,27 @@ public:
   NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult)
   {
     nsCOMPtr<nsIAudioManager> audioManager =
       do_GetService(NS_AUDIOMANAGER_CONTRACTID);
     NS_ENSURE_TRUE(JSVAL_IS_INT(aResult), NS_OK);
 
     int32_t volIndex = JSVAL_TO_INT(aResult);
     if (aName.EqualsLiteral("audio.volume.content")) {
-      audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_CONTENT, volIndex);
+      audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Content,
+                                          volIndex);
     } else if (aName.EqualsLiteral("audio.volume.notification")) {
-      audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_NOTIFICATION,
+      audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Notification,
                                           volIndex);
     } else if (aName.EqualsLiteral("audio.volume.alarm")) {
-      audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_ALARM, volIndex);
+      audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Alarm,
+                                          volIndex);
     } else if (aName.EqualsLiteral("audio.volume.telephony")) {
-      audioManager->SetAudioChannelVolume(AUDIO_CHANNEL_TELEPHONY, volIndex);
+      audioManager->SetAudioChannelVolume((int32_t)AudioChannel::Telephony,
+                                          volIndex);
     } else if (aName.EqualsLiteral("audio.volume.bt_sco")) {
       static_cast<AudioManager *>(audioManager.get())->SetStreamVolumeIndex(
         AUDIO_STREAM_BLUETOOTH_SCO, volIndex);
     } else {
       MOZ_ASSUME_UNREACHABLE("unexpected audio channel for initializing "
                              "volume control");
     }
 
@@ -526,19 +529,19 @@ AudioManager::SetPhoneState(int32_t aSta
     mPhoneAudioAgent = nullptr;
   }
 
   if (aState == PHONE_STATE_IN_CALL || aState == PHONE_STATE_RINGTONE) {
     mPhoneAudioAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1");
     MOZ_ASSERT(mPhoneAudioAgent);
     if (aState == PHONE_STATE_IN_CALL) {
       // Telephony doesn't be paused by any other channels.
-      mPhoneAudioAgent->Init(nullptr, AUDIO_CHANNEL_TELEPHONY, nullptr);
+      mPhoneAudioAgent->Init(nullptr, (int32_t)AudioChannel::Telephony, nullptr);
     } else {
-      mPhoneAudioAgent->Init(nullptr, AUDIO_CHANNEL_RINGER, nullptr);
+      mPhoneAudioAgent->Init(nullptr, (int32_t)AudioChannel::Ringer, nullptr);
     }
 
     // Telephony can always play.
     int32_t canPlay;
     mPhoneAudioAgent->StartPlaying(&canPlay);
   }
 
   return NS_OK;
@@ -603,97 +606,97 @@ AudioManager::SetFmRadioAudioEnabled(boo
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 }
 
 NS_IMETHODIMP
 AudioManager::SetAudioChannelVolume(int32_t aChannel, int32_t aIndex) {
   nsresult status;
 
-  switch (aChannel) {
-    case AUDIO_CHANNEL_CONTENT:
+  switch (static_cast<AudioChannel>(aChannel)) {
+    case AudioChannel::Content:
       // sync FMRadio's volume with content channel.
       if (IsDeviceOn(AUDIO_DEVICE_OUT_FM)) {
         status = SetStreamVolumeIndex(AUDIO_STREAM_FM, aIndex);
         NS_ENSURE_SUCCESS(status, status);
       }
       status = SetStreamVolumeIndex(AUDIO_STREAM_MUSIC, aIndex);
       NS_ENSURE_SUCCESS(status, status);
       status = SetStreamVolumeIndex(AUDIO_STREAM_SYSTEM, aIndex);
       break;
-    case AUDIO_CHANNEL_NOTIFICATION:
+    case AudioChannel::Notification:
       status = SetStreamVolumeIndex(AUDIO_STREAM_NOTIFICATION, aIndex);
       NS_ENSURE_SUCCESS(status, status);
       status = SetStreamVolumeIndex(AUDIO_STREAM_RING, aIndex);
       break;
-    case AUDIO_CHANNEL_ALARM:
+    case AudioChannel::Alarm:
       status = SetStreamVolumeIndex(AUDIO_STREAM_ALARM, aIndex);
       break;
-    case AUDIO_CHANNEL_TELEPHONY:
+    case AudioChannel::Telephony:
       status = SetStreamVolumeIndex(AUDIO_STREAM_VOICE_CALL, aIndex);
       break;
     default:
       return NS_ERROR_INVALID_ARG;
   }
 
   return status;
 }
 
 NS_IMETHODIMP
 AudioManager::GetAudioChannelVolume(int32_t aChannel, int32_t* aIndex) {
   if (!aIndex) {
     return NS_ERROR_NULL_POINTER;
   }
 
-  switch (aChannel) {
-    case AUDIO_CHANNEL_CONTENT:
+  switch (static_cast<AudioChannel>(aChannel)) {
+    case AudioChannel::Content:
       MOZ_ASSERT(mCurrentStreamVolumeTbl[AUDIO_STREAM_MUSIC] ==
                  mCurrentStreamVolumeTbl[AUDIO_STREAM_SYSTEM]);
       *aIndex = mCurrentStreamVolumeTbl[AUDIO_STREAM_MUSIC];
       break;
-    case AUDIO_CHANNEL_NOTIFICATION:
+    case AudioChannel::Notification:
       MOZ_ASSERT(mCurrentStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
                  mCurrentStreamVolumeTbl[AUDIO_STREAM_RING]);
       *aIndex = mCurrentStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION];
       break;
-    case AUDIO_CHANNEL_ALARM:
+    case AudioChannel::Alarm:
       *aIndex = mCurrentStreamVolumeTbl[AUDIO_STREAM_ALARM];
       break;
-    case AUDIO_CHANNEL_TELEPHONY:
+    case AudioChannel::Telephony:
       *aIndex = mCurrentStreamVolumeTbl[AUDIO_STREAM_VOICE_CALL];
       break;
     default:
       return NS_ERROR_INVALID_ARG;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 AudioManager::GetMaxAudioChannelVolume(int32_t aChannel, int32_t* aMaxIndex) {
   if (!aMaxIndex) {
     return NS_ERROR_NULL_POINTER;
   }
 
   int32_t stream;
-  switch (aChannel) {
-    case AUDIO_CHANNEL_CONTENT:
+  switch (static_cast<AudioChannel>(aChannel)) {
+    case AudioChannel::Content:
       MOZ_ASSERT(sMaxStreamVolumeTbl[AUDIO_STREAM_MUSIC] ==
                  sMaxStreamVolumeTbl[AUDIO_STREAM_SYSTEM]);
       stream = AUDIO_STREAM_MUSIC;
       break;
-    case AUDIO_CHANNEL_NOTIFICATION:
+    case AudioChannel::Notification:
       MOZ_ASSERT(sMaxStreamVolumeTbl[AUDIO_STREAM_NOTIFICATION] ==
                  sMaxStreamVolumeTbl[AUDIO_STREAM_RING]);
       stream = AUDIO_STREAM_NOTIFICATION;
       break;
-    case AUDIO_CHANNEL_ALARM:
+    case AudioChannel::Alarm:
       stream = AUDIO_STREAM_ALARM;
       break;
-    case AUDIO_CHANNEL_TELEPHONY:
+    case AudioChannel::Telephony:
       stream = AUDIO_STREAM_VOICE_CALL;
       break;
     default:
       return NS_ERROR_INVALID_ARG;
   }
 
   *aMaxIndex = sMaxStreamVolumeTbl[stream];
    return NS_OK;
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -687,16 +687,20 @@ var interfaceNamesInGlobalScope =
     {name: "MozVoicemail", b2g: true, pref: "dom.voicemail.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozVoicemailEvent", b2g: true, pref: "dom.voicemail.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWakeLock", b2g: true, pref: "dom.wakelock.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWifiConnectionInfoEvent", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "MozWifiManager", b2g: true, permission: "wifi-manage"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "MozWifiNetwork", b2g: true, permission: "wifi-manage"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWifiStatusChangeEvent", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWifiP2pGroupOwner", b2g: true, permission: "wifi-manage"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWifiP2pManager", b2g: true, permission: "wifi-manage"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozWifiP2pStatusChangeEvent", b2g: true, permission: "wifi-manage"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -10,17 +10,16 @@
  * http://dvcs.w3.org/hg/pointerlock/raw-file/default/index.html#extensions-to-the-document-interface
  * http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#sec-document-interface
  * http://dev.w3.org/csswg/cssom/#extensions-to-the-document-interface
  * http://dev.w3.org/csswg/cssom-view/#extensions-to-the-document-interface
  *
  * http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/core/nsIDOMDocument.idl
  */
 
-interface StyleSheetList;
 interface WindowProxy;
 interface nsISupports;
 interface URI;
 interface nsIDocShell;
 
 enum VisibilityState { "hidden", "visible" };
 
 /* http://dom.spec.whatwg.org/#interface-document */
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MozWifiManager.webidl
@@ -0,0 +1,257 @@
+/* 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/. */
+
+enum WifiWPSMethod {
+  "pbc",
+  "pin",
+  "cancel"
+};
+
+enum ConnectionStatus {
+  "connecting",
+  "associated",
+  "connected",
+  "disconnected",
+  "wps-timeout",
+  "wps-failed",
+  "wps-overlapped",
+  "connectingfailed"
+};
+
+dictionary WifiWPSInfo {
+  WifiWPSMethod method;
+  DOMString? pin;
+  DOMString? bssid;
+};
+
+dictionary NetworkProperties {
+  DOMString ssid;
+  sequence<DOMString>? security;
+  sequence<DOMString>? capabilities;
+  boolean known;
+  boolean connected;
+  boolean hidden;
+  DOMString bssid;
+  DOMString signalStrength;
+  long relSignalStrength;
+  DOMString psk;
+  DOMString keyManagement;
+  DOMString identity;
+  DOMString password;
+  DOMString phase1;
+  DOMString phase2;
+  DOMString eap;
+  DOMString pin;
+  boolean dontConnect;
+};
+
+[Constructor(optional NetworkProperties properties),
+ JSImplementation="@mozilla.org/mozwifinetwork;1",
+ Func="Navigator::HasWifiManagerSupport"]
+interface MozWifiNetwork {
+  readonly attribute DOMString ssid;
+  [Constant, Cached] readonly attribute sequence<DOMString>? security;
+  [Constant, Cached] readonly attribute sequence<DOMString>? capabilities;
+  readonly attribute boolean known;
+  readonly attribute boolean connected;
+  readonly attribute boolean hidden;
+
+           attribute DOMString? bssid;
+           attribute DOMString? signalStrength;
+           attribute long? relSignalStrength;
+           attribute DOMString? psk;
+           attribute DOMString? keyManagement;
+           attribute DOMString? identity;
+           attribute DOMString? password;
+           attribute DOMString? phase1;
+           attribute DOMString? phase2;
+           attribute DOMString? eap;
+           attribute DOMString? pin;
+           attribute boolean? dontConnect;
+};
+
+[JSImplementation="@mozilla.org/mozwificonnection;1",
+ ChromeOnly]
+interface MozWifiConnection {
+  readonly attribute ConnectionStatus status;
+  readonly attribute MozWifiNetwork? network;
+};
+
+[JSImplementation="@mozilla.org/mozwificonnectioninfo;1",
+ ChromeOnly]
+interface MozWifiConnectionInfo {
+  readonly attribute short signalStrength;
+  readonly attribute short relSignalStrength;
+  readonly attribute long linkSpeed;
+  readonly attribute DOMString? ipAddress;
+};
+
+dictionary IPConfiguration {
+  boolean enabled;
+  DOMString ipaddr;
+  DOMString proxy;
+  short maskLength;
+  DOMString gateway;
+  DOMString dns1;
+  DOMString dns2;
+};
+
+[JSImplementation="@mozilla.org/wifimanager;1",
+ NavigatorProperty="mozWifiManager",
+ Func="Navigator::HasWifiManagerSupport"]
+interface MozWifiManager : EventTarget {
+  /**
+   * Returns the list of currently available networks.
+   * onsuccess: We have obtained the current list of networks. request.value
+   *            is an object whose property names are SSIDs and values are
+   *            network objects.
+   * onerror: We were unable to obtain a list of property names.
+   */
+  DOMRequest getNetworks();
+
+  /**
+   * Returns the list of networks known to the system that will be
+   * automatically connected to if they're in range.
+   * onsuccess: request.value is an object whose property names are
+   *            SSIDs and values are network objects.
+   * onerror: We were unable to obtain a list of known networks.
+   */
+  DOMRequest getKnownNetworks();
+
+  /**
+   * Takes one of the networks returned from getNetworks and tries to
+   * connect to it.
+   * @param network A network object with information about the network,
+   *                such as the SSID, key management desired, etc.
+   * onsuccess: We have started attempting to associate with the network.
+   *            request.value is true.
+   * onerror: We were unable to select the network. This most likely means a
+   *          configuration error.
+   */
+  DOMRequest associate(MozWifiNetwork network);
+
+  /**
+   * Given a network, removes it from the list of networks that we'll
+   * automatically connect to. In order to re-connect to the network, it is
+   * necessary to call associate on it.
+   * @param network A network object with the SSID of the network to remove.
+   * onsuccess: We have removed this network. If we were previously
+   *            connected to it, we have started reconnecting to the next
+   *            network in the list.
+   * onerror: We were unable to remove the network.
+   */
+  DOMRequest forget(MozWifiNetwork network);
+
+  /**
+   * Wi-Fi Protected Setup functionality.
+   * @param detail WPS detail which has 'method' and 'pin' field.
+   *               The possible method field values are:
+   *                 - pbc: The Push Button Configuration.
+   *                 - pin: The PIN configuration.
+   *                 - cancel: Request to cancel WPS in progress.
+   *               If method field is 'pin', 'pin' field can exist and has
+   *               a PIN number.
+   *               If method field is 'pin', 'bssid' field can exist and has
+   *               a opposite BSSID.
+   * onsuccess: We have successfully started/canceled wps.
+   * onerror: We have failed to start/cancel wps.
+   */
+  DOMRequest wps(optional WifiWPSInfo detail);
+
+  /**
+   * Turn on/off wifi power saving mode.
+   * @param enabled true or false.
+   * onsuccess: We have successfully turn on/off wifi power saving mode.
+   * onerror: We have failed to turn on/off wifi power saving mode.
+   */
+  DOMRequest setPowerSavingMode(boolean enabled);
+
+  /**
+   * Given a network, configure using static IP instead of running DHCP
+   * @param network A network object with the SSID of the network to set static ip.
+   * @param info info should have following field:
+   *        - enabled True to enable static IP, false to use DHCP
+   *        - ipaddr configured static IP address
+   *        - proxy configured proxy server address
+   *        - maskLength configured mask length
+   *        - gateway configured gateway address
+   *        - dns1 configured first DNS server address
+   *        - dns2 configured seconf DNS server address
+   * onsuccess: We have successfully configure the static ip mode.
+   * onerror: We have failed to configure the static ip mode.
+   */
+  DOMRequest setStaticIpMode(MozWifiNetwork network, optional IPConfiguration info);
+
+  /**
+   * Given a network, configure http proxy when using wifi.
+   * @param network A network object with the SSID of the network to set http proxy.
+   * @param info info should have following field:
+   *        - httpProxyHost ip address of http proxy.
+   *        - httpProxyPort port of http proxy, set 0 to use default port 8080.
+   *        set info to null to clear http proxy.
+   * onsuccess: We have successfully configure http proxy.
+   * onerror: We have failed to configure http proxy.
+   */
+  DOMRequest setHttpProxy(MozWifiNetwork network, any info);
+
+  /**
+   * Returns whether or not wifi is currently enabled.
+   */
+  readonly attribute boolean enabled;
+
+  /**
+   * Returns the MAC address of the wifi adapter.
+   */
+  readonly attribute DOMString macAddress;
+
+  /**
+   * An non-null object containing the following information:
+   *  - status ("disconnected", "connecting", "associated", "connected")
+   *  - network
+   *
+   *  Note that the object returned is read only. Any changes required must
+   *  be done by calling other APIs.
+   */
+  readonly attribute MozWifiConnection connection;
+
+  /**
+   * A connectionInformation object with the same information found in an
+   * nsIDOMMozWifiConnectionInfoEvent (but without the network).
+   * If we are not currently connected to a network, this will be null.
+   */
+  readonly attribute MozWifiConnectionInfo? connectionInformation;
+
+  /**
+   * State notification listeners. These all take an
+   * nsIDOMMozWifiStatusChangeEvent with the new status and a network (which
+   * may be null).
+   *
+   * The possible statuses are:
+   *   - connecting: Fires when we start the process of connecting to a
+   *                 network.
+   *   - associated: Fires when we have connected to an access point but do
+   *                 not yet have an IP address.
+   *   - connected: Fires once we are fully connected to an access point and
+   *                can access the internet.
+   *   - disconnected: Fires when we either fail to connect to an access
+   *                   point (transition: associated -> disconnected) or
+   *                   when we were connected to a network but have
+   *                   disconnected for any reason (transition: connected ->
+   *                   disconnected).
+   */
+  attribute EventHandler onstatuschange;
+
+  /**
+   * An event listener that is called with information about the signal
+   * strength and link speed every 5 seconds.
+   */
+  attribute EventHandler onconnectionInfoUpdate;
+
+  /**
+   * These two events fire when the wifi system is brought online or taken
+   * offline.
+   */
+  attribute EventHandler onenabled;
+  attribute EventHandler ondisabled;
+};
--- a/dom/webidl/SVGAnimatedLength.webidl
+++ b/dom/webidl/SVGAnimatedLength.webidl
@@ -5,17 +5,15 @@
  *
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-interface SVGLength;
-
 interface SVGAnimatedLength {
   [Constant]
   readonly attribute SVGLength baseVal;
   [Constant]
   readonly attribute SVGLength animVal;
 };
 
new file mode 100644
--- /dev/null
+++ b/dom/webidl/SVGLength.webidl
@@ -0,0 +1,40 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://www.w3.org/TR/SVG2/
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+interface SVGLength {
+
+  // Length Unit Types
+  const unsigned short SVG_LENGTHTYPE_UNKNOWN = 0;
+  const unsigned short SVG_LENGTHTYPE_NUMBER = 1;
+  const unsigned short SVG_LENGTHTYPE_PERCENTAGE = 2;
+  const unsigned short SVG_LENGTHTYPE_EMS = 3;
+  const unsigned short SVG_LENGTHTYPE_EXS = 4;
+  const unsigned short SVG_LENGTHTYPE_PX = 5;
+  const unsigned short SVG_LENGTHTYPE_CM = 6;
+  const unsigned short SVG_LENGTHTYPE_MM = 7;
+  const unsigned short SVG_LENGTHTYPE_IN = 8;
+  const unsigned short SVG_LENGTHTYPE_PT = 9;
+  const unsigned short SVG_LENGTHTYPE_PC = 10;
+
+  readonly attribute unsigned short unitType;
+  [Throws]
+           attribute float value;
+  [SetterThrows]
+           attribute float valueInSpecifiedUnits;
+  [SetterThrows]
+           attribute DOMString valueAsString;
+
+  [Throws]
+  void newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits);
+  [Throws]
+  void convertToSpecifiedUnits(unsigned short unitType);
+};
--- a/dom/webidl/SVGLengthList.webidl
+++ b/dom/webidl/SVGLengthList.webidl
@@ -5,18 +5,16 @@
  *
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG11/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-interface SVGLength;
-
 interface SVGLengthList {
   readonly attribute unsigned long numberOfItems;
   [Throws]
   void clear();
   [Throws]
   SVGLength initialize(SVGLength newItem);
   [Throws]
   getter SVGLength getItem(unsigned long index);
new file mode 100644
--- /dev/null
+++ b/dom/webidl/StyleSheetList.webidl
@@ -0,0 +1,8 @@
+/* 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/. */
+
+interface StyleSheetList {
+  readonly attribute unsigned long length;
+  getter StyleSheet? item(unsigned long index);
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -298,16 +298,17 @@ WEBIDL_FILES = [
     'ShadowRoot.webidl',
     'SharedWorker.webidl',
     'SharedWorkerGlobalScope.webidl',
     'SimpleGestureEvent.webidl',
     'SourceBuffer.webidl',
     'SourceBufferList.webidl',
     'StorageType.webidl',
     'StyleSheet.webidl',
+    'StyleSheetList.webidl',
     'SVGAElement.webidl',
     'SVGAltGlyphElement.webidl',
     'SVGAngle.webidl',
     'SVGAnimatedAngle.webidl',
     'SVGAnimatedBoolean.webidl',
     'SVGAnimatedEnumeration.webidl',
     'SVGAnimatedInteger.webidl',
     'SVGAnimatedLength.webidl',
@@ -360,16 +361,17 @@ WEBIDL_FILES = [
     'SVGFilterElement.webidl',
     'SVGFilterPrimitiveStandardAttributes.webidl',
     'SVGFitToViewBox.webidl',
     'SVGForeignObjectElement.webidl',
     'SVGGElement.webidl',
     'SVGGradientElement.webidl',
     'SVGGraphicsElement.webidl',
     'SVGImageElement.webidl',
+    'SVGLength.webidl',
     'SVGLengthList.webidl',
     'SVGLinearGradientElement.webidl',
     'SVGLineElement.webidl',
     'SVGMarkerElement.webidl',
     'SVGMaskElement.webidl',
     'SVGMatrix.webidl',
     'SVGMetadataElement.webidl',
     'SVGMPathElement.webidl',
@@ -553,16 +555,17 @@ if CONFIG['MOZ_NFC']:
          'MozNFCPeer.webidl',
          'MozNFCTag.webidl',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     WEBIDL_FILES += [
         'MozSpeakerManager.webidl',
         'MozWifiConnectionInfoEvent.webidl',
+        'MozWifiManager.webidl',
         'MozWifiP2pManager.webidl',
         'MozWifiP2pStatusChangeEvent.webidl',
         'MozWifiStatusChangeEvent.webidl',
     ]
 
 if CONFIG['MOZ_WEBSPEECH']:
     WEBIDL_FILES += [
         'SpeechRecognitionError.webidl',
--- a/dom/wifi/DOMWifiManager.js
+++ b/dom/wifi/DOMWifiManager.js
@@ -10,77 +10,81 @@ const {classes: Cc, interfaces: Ci, util
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 
 const DEBUG = false; // set to false to suppress debug messages
 
 const DOMWIFIMANAGER_CONTRACTID = "@mozilla.org/wifimanager;1";
-const DOMWIFIMANAGER_CID        = Components.ID("{2cf775a7-1837-410c-9e26-323c42e076da}");
+const DOMWIFIMANAGER_CID        = Components.ID("{c9b5f09e-25d2-40ca-aef4-c4d13d93c706}");
 
-function DOMWifiManager() {
-}
-
-function exposeCurrentNetwork(currentNetwork) {
-  currentNetwork.__exposedProps__ = exposeCurrentNetwork.currentNetworkApi;
+function MozWifiNetwork() {
 }
 
-exposeCurrentNetwork.currentNetworkApi = {
-  ssid: "r",
-  security: "r",
-  capabilities: "r",
-  known: "r"
+MozWifiNetwork.prototype = {
+
+  init: function(aWindow) {
+    this._window = aWindow;
+  },
+
+  __init: function(obj) {
+    for (let key in obj) {
+      this[key] = obj[key];
+    }
+  },
+
+  classID: Components.ID("{c01fd751-43c0-460a-8b64-abf652ec7220}"),
+  contractID: "@mozilla.org/mozwifinetwork;1",
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
+                                         Ci.nsIDOMGlobalPropertyInitializer])
 };
 
-// For smaller, read-only APIs, we expose any property that doesn't begin with
-// an underscore.
-function exposeReadOnly(obj) {
-  var exposedProps = {};
-  for (let i in obj) {
-    if (i[0] === "_")
-      continue;
-    exposedProps[i] = "r";
-  }
+function MozWifiConnection(obj) {
+  this.status = obj.status;
+  this.network = obj.network;
+}
+
+MozWifiConnection.prototype = {
+  classID: Components.ID("{23579da4-201b-4319-bd42-9b7f337343ac}"),
+  contractID: "@mozilla.org/mozwificonnection;1",
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports])
+};
 
-  obj.__exposedProps__ = exposedProps;
-  return obj;
+function MozWifiConnectionInfo(obj) {
+  this.signalStrength = obj.signalStrength;
+  this.relSignalStrength = obj.relSignalStrength;
+  this.linkSpeed = obj.linkSpeed;
+  this.ipAddress = obj.ipAddress;
+}
+
+MozWifiConnectionInfo.prototype = {
+  classID: Components.ID("{83670352-6ed4-4c35-8de9-402296a1959c}"),
+  contractID: "@mozilla.org/mozwificonnectioninfo;1",
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports])
+}
+
+function DOMWifiManager() {
+  this.defineEventHandlerGetterSetter("onstatuschange");
+  this.defineEventHandlerGetterSetter("onconnectionInfoUpdate");
+  this.defineEventHandlerGetterSetter("onenabled");
+  this.defineEventHandlerGetterSetter("ondisabled");
 }
 
 DOMWifiManager.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
-
-  classID:   DOMWIFIMANAGER_CID,
-  classInfo: XPCOMUtils.generateCI({classID: DOMWIFIMANAGER_CID,
-                                    contractID: DOMWIFIMANAGER_CONTRACTID,
-                                    classDescription: "DOMWifiManager",
-                                    interfaces: [Ci.nsIDOMWifiManager],
-                                    flags: Ci.nsIClassInfo.DOM_OBJECT}),
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMWifiManager,
-                                         Ci.nsIDOMGlobalPropertyInitializer,
+  classDescription: "DOMWifiManager",
+  classID: DOMWIFIMANAGER_CID,
+  contractID: DOMWIFIMANAGER_CONTRACTID,
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
                                          Ci.nsISupportsWeakReference,
                                          Ci.nsIObserver]),
 
   // nsIDOMGlobalPropertyInitializer implementation
   init: function(aWindow) {
-    let principal = aWindow.document.nodePrincipal;
-    let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
-
-    let perm = principal == secMan.getSystemPrincipal()
-                 ? Ci.nsIPermissionManager.ALLOW_ACTION
-                 : Services.perms.testExactPermissionFromPrincipal(principal, "wifi-manage");
-
-    // Only pages with perm set can use the wifi manager.
-    this._hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
-
-    if (!this._hasPrivileges) {
-      return null;
-    }
-
     // Maintain this state for synchronous APIs.
     this._currentNetwork = null;
     this._connectionStatus = "disconnected";
     this._enabled = false;
     this._lastConnectionInfo = null;
 
     const messages = ["WifiManager:getNetworks:Return:OK", "WifiManager:getNetworks:Return:NO",
                       "WifiManager:getKnownNetworks:Return:OK", "WifiManager:getKnownNetworks:Return:NO",
@@ -96,37 +100,64 @@ DOMWifiManager.prototype = {
                       "WifiManager:onwpstimeout", "WifiManager:onwpsfail",
                       "WifiManager:onwpsoverlap", "WifiManager:connectionInfoUpdate",
                       "WifiManager:onconnectingfailed"];
     this.initDOMRequestHelper(aWindow, messages);
     this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
 
     var state = this._mm.sendSyncMessage("WifiManager:getState")[0];
     if (state) {
-      this._currentNetwork = state.network;
-      if (this._currentNetwork)
-        exposeCurrentNetwork(this._currentNetwork);
-      this._lastConnectionInfo = state.connectionInfo;
+      this._currentNetwork = this._convertWifiNetwork(state.network);
+      this._lastConnectionInfo = this._convertConnectionInfo(state.connectionInfo);
       this._enabled = state.enabled;
       this._connectionStatus = state.status;
       this._macAddress = state.macAddress;
     } else {
       this._currentNetwork = null;
       this._lastConnectionInfo = null;
       this._enabled = false;
       this._connectionStatus = "disconnected";
       this._macAddress = "";
     }
   },
 
-  uninit: function() {
-    this._onStatusChange = null;
-    this._onConnectionInfoUpdate = null;
-    this._onEnabled = null;
-    this._onDisabled = null;
+  _convertWifiNetworkToJSON: function(aNetwork) {
+    let json = {};
+
+    for (let key in aNetwork) {
+      // In WifiWorker.js there are lots of check using "key in network".
+      // So if the value of any property of WifiNetwork is undefined, do not clone it.
+      if (aNetwork[key] != undefined) {
+        json[key] = aNetwork[key];
+      }
+    }
+    return json;
+  },
+
+  _convertWifiNetwork: function(aNetwork) {
+    let network = aNetwork ? new this._window.MozWifiNetwork(aNetwork) : null;
+    return network;
+  },
+
+  _convertWifiNetworks: function(aNetworks) {
+    let networks = [];
+    for (let i in aNetworks) {
+      networks.push(this._convertWifiNetwork(aNetworks[i]));
+    }
+    return networks;
+  },
+
+  _convertConnection: function(aConn) {
+    let conn = aConn ? new MozWifiConnection(aConn) : null;
+    return conn;
+  },
+
+  _convertConnectionInfo: function(aInfo) {
+    let info = aInfo ? new MozWifiConnectionInfo(aInfo) : null;
+    return info;
   },
 
   _sendMessageForRequest: function(name, data, request) {
     let id = this.getRequestId(request);
     this._mm.sendAsyncMessage(name, { data: data, rid: id, mid: this._id });
   },
 
   receiveMessage: function(aMessage) {
@@ -139,25 +170,25 @@ DOMWifiManager.prototype = {
       request = this.takeRequest(msg.rid);
       if (!request) {
         return;
       }
     }
 
     switch (aMessage.name) {
       case "WifiManager:getNetworks:Return:OK":
-        Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
+        Services.DOMRequest.fireSuccess(request, this._convertWifiNetworks(msg.data));
         break;
 
       case "WifiManager:getNetworks:Return:NO":
         Services.DOMRequest.fireError(request, "Unable to scan for networks");
         break;
 
       case "WifiManager:getKnownNetworks:Return:OK":
-        Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
+        Services.DOMRequest.fireSuccess(request, this._convertWifiNetworks(msg.data));
         break;
 
       case "WifiManager:getKnownNetworks:Return:NO":
         Services.DOMRequest.fireError(request, "Unable to get known networks");
         break;
 
       case "WifiManager:associate:Return:OK":
         Services.DOMRequest.fireSuccess(request, true);
@@ -171,41 +202,41 @@ DOMWifiManager.prototype = {
         Services.DOMRequest.fireSuccess(request, true);
         break;
 
       case "WifiManager:forget:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:wps:Return:OK":
-        Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
+        Services.DOMRequest.fireSuccess(request, msg.data);
         break;
 
       case "WifiManager:wps:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:setPowerSavingMode:Return:OK":
-        Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
+        Services.DOMRequest.fireSuccess(request, msg.data);
         break;
 
       case "WifiManager:setPowerSavingMode:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:setHttpProxy:Return:OK":
-        Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
+        Services.DOMRequest.fireSuccess(request, msg.data);
         break;
 
       case "WifiManager:setHttpProxy:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:setStaticIpMode:Return:OK":
-        Services.DOMRequest.fireSuccess(request, exposeReadOnly(msg.data));
+        Services.DOMRequest.fireSuccess(request, msg.data);
         break;
 
       case "WifiManager:setStaticIpMode:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:wifiDown":
         this._enabled = false;
@@ -215,32 +246,29 @@ DOMWifiManager.prototype = {
 
       case "WifiManager:wifiUp":
         this._enabled = true;
         this._macAddress = msg.macAddress;
         this._fireEnabledOrDisabled(true);
         break;
 
       case "WifiManager:onconnecting":
-        this._currentNetwork = msg.network;
-        exposeCurrentNetwork(this._currentNetwork);
+        this._currentNetwork = this._convertWifiNetwork(msg.network);
         this._connectionStatus = "connecting";
         this._fireStatusChangeEvent();
         break;
 
       case "WifiManager:onassociate":
-        this._currentNetwork = msg.network;
-        exposeCurrentNetwork(this._currentNetwork);
+        this._currentNetwork = this._convertWifiNetwork(msg.network);
         this._connectionStatus = "associated";
         this._fireStatusChangeEvent();
         break;
 
       case "WifiManager:onconnect":
-        this._currentNetwork = msg.network;
-        exposeCurrentNetwork(this._currentNetwork);
+        this._currentNetwork = this._convertWifiNetwork(msg.network);
         this._connectionStatus = "connected";
         this._fireStatusChangeEvent();
         break;
 
       case "WifiManager:ondisconnect":
         this._currentNetwork = null;
         this._connectionStatus = "disconnected";
         this._lastConnectionInfo = null;
@@ -264,179 +292,138 @@ DOMWifiManager.prototype = {
       case "WifiManager:onwpsoverlap":
         this._currentNetwork = null;
         this._connectionStatus = "wps-overlapped";
         this._lastConnectionInfo = null;
         this._fireStatusChangeEvent();
         break;
 
       case "WifiManager:connectionInfoUpdate":
-        this._lastConnectionInfo = msg;
+        this._lastConnectionInfo = this._convertConnectionInfo(msg);
         this._fireConnectionInfoUpdate(msg);
         break;
       case "WifiManager:onconnectingfailed":
         this._currentNetwork = null;
         this._connectionStatus = "connectingfailed";
         this._lastConnectionInfo = null;
         this._fireStatusChangeEvent();
         break;
     }
   },
 
   _fireStatusChangeEvent: function StatusChangeEvent() {
-    if (this._onStatusChange) {
-      debug("StatusChangeEvent");
-      var event = new this._window.MozWifiStatusChangeEvent("statusChangeEvent",
-                                                            { network: this._currentNetwork,
-                                                              status: this._connectionStatus
-                                                            });
-      this._onStatusChange.handleEvent(event);
-    }
+    var event = new this._window.MozWifiStatusChangeEvent("statuschange",
+                                                          { network: this._currentNetwork,
+                                                            status: this._connectionStatus
+                                                          });
+    this.__DOM_IMPL__.dispatchEvent(event);
   },
 
-  _fireConnectionInfoUpdate: function connectionInfoUpdate(info) {
-    if (this._onConnectionInfoUpdate) {
-      debug("ConnectionInfoEvent");
-      var evt = new this._window.MozWifiConnectionInfoEvent("connectionInfoEvent",
-                                                            { network: this._currentNetwork,
-                                                              signalStrength: info.signalStrength,
-                                                              relSignalStrength: info.relSignalStrength,
-                                                              linkSpeed: info.linkSpeed,
-                                                              ipAddress: info.ipAddress,
-                                                            });
-      this._onConnectionInfoUpdate.handleEvent(evt);
-    }
+  _fireConnectionInfoUpdate: function onConnectionInfoUpdate(info) {
+    var evt = new this._window.MozWifiConnectionInfoEvent("connectioninfoupdate",
+                                                          { network: this._currentNetwork,
+                                                            signalStrength: info.signalStrength,
+                                                            relSignalStrength: info.relSignalStrength,
+                                                            linkSpeed: info.linkSpeed,
+                                                            ipAddress: info.ipAddress,
+                                                          });
+    this.__DOM_IMPL__.dispatchEvent(evt);
   },
 
   _fireEnabledOrDisabled: function enabledDisabled(enabled) {
-    var handler = enabled ? this._onEnabled : this._onDisabled;
-    if (handler) {
-      var evt = new this._window.Event("WifiEnabled");
-      handler.handleEvent(evt);
-    }
+    var evt = new this._window.Event(enabled ? "enabled" : "disabled");
+    this.__DOM_IMPL__.dispatchEvent(evt);
   },
 
-  // nsIDOMWifiManager
-  getNetworks: function nsIDOMWifiManager_getNetworks() {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  getNetworks: function getNetworks() {
     var request = this.createRequest();
     this._sendMessageForRequest("WifiManager:getNetworks", null, request);
     return request;
   },
 
-  getKnownNetworks: function nsIDOMWifiManager_getKnownNetworks() {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  getKnownNetworks: function getKnownNetworks() {
     var request = this.createRequest();
     this._sendMessageForRequest("WifiManager:getKnownNetworks", null, request);
     return request;
   },
 
-  associate: function nsIDOMWifiManager_associate(network) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  associate: function associate(network) {
     var request = this.createRequest();
-    this._sendMessageForRequest("WifiManager:associate", network, request);
+    this._sendMessageForRequest("WifiManager:associate",
+                                this._convertWifiNetworkToJSON(network), request);
     return request;
   },
 
-  forget: function nsIDOMWifiManager_forget(network) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  forget: function forget(network) {
     var request = this.createRequest();
-    this._sendMessageForRequest("WifiManager:forget", network, request);
+    this._sendMessageForRequest("WifiManager:forget",
+                                this._convertWifiNetworkToJSON(network), request);
     return request;
   },
 
-  wps: function nsIDOMWifiManager_wps(detail) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  wps: function wps(detail) {
     var request = this.createRequest();
     this._sendMessageForRequest("WifiManager:wps", detail, request);
     return request;
   },
 
-  setPowerSavingMode: function nsIDOMWifiManager_setPowerSavingMode(enabled) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  setPowerSavingMode: function setPowerSavingMode(enabled) {
     var request = this.createRequest();
     this._sendMessageForRequest("WifiManager:setPowerSavingMode", enabled, request);
     return request;
   },
 
-  setHttpProxy: function nsIDOMWifiManager_setHttpProxy(network, info) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  setHttpProxy: function setHttpProxy(network, info) {
     var request = this.createRequest();
-    this._sendMessageForRequest("WifiManager:setHttpProxy", {network:network, info:info}, request);
+    this._sendMessageForRequest("WifiManager:setHttpProxy",
+                                { network: this._convertWifiNetworkToJSON(network), info:info}, request);
     return request;
   },
 
-  setStaticIpMode: function nsIDOMWifiManager_setStaticIpMode(network, info) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
+  setStaticIpMode: function setStaticIpMode(network, info) {
     var request = this.createRequest();
-    this._sendMessageForRequest("WifiManager:setStaticIpMode", {network: network,info: info}, request);
+    this._sendMessageForRequest("WifiManager:setStaticIpMode",
+                                { network: this._convertWifiNetworkToJSON(network), info: info}, request);
     return request;
   },
 
   get enabled() {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
     return this._enabled;
   },
 
   get macAddress() {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
     return this._macAddress;
   },
 
   get connection() {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    return exposeReadOnly({ status: this._connectionStatus,
-                            network: this._currentNetwork });
+    let _connection = this._convertConnection({ status: this._connectionStatus,
+                                                network: this._currentNetwork,
+                                              });
+    return _connection;
   },
 
   get connectionInformation() {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    return this._lastConnectionInfo
-           ? exposeReadOnly(this._lastConnectionInfo)
-           : null;
-  },
-
-  set onstatuschange(callback) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    this._onStatusChange = callback;
+    return this._lastConnectionInfo;
   },
 
-  set connectionInfoUpdate(callback) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    this._onConnectionInfoUpdate = callback;
+  defineEventHandlerGetterSetter: function(name) {
+    Object.defineProperty(this, name, {
+      get: function() {
+        return this.__DOM_IMPL__.getEventHandler(name);
+      },
+      set: function(handler) {
+        this.__DOM_IMPL__.setEventHandler(name, handler);
+      }
+    });
   },
-
-  set onenabled(callback) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    this._onEnabled = callback;
-  },
-
-  set ondisabled(callback) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    this._onDisabled = callback;
-  }
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DOMWifiManager]);
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
+  DOMWifiManager, MozWifiNetwork, MozWifiConnection, MozWifiConnectionInfo
+]);
 
 let debug;
 if (DEBUG) {
   debug = function (s) {
     dump("-*- DOMWifiManager component: " + s + "\n");
   };
 } else {
   debug = function (s) {};
--- a/dom/wifi/DOMWifiManager.manifest
+++ b/dom/wifi/DOMWifiManager.manifest
@@ -1,4 +1,12 @@
 # DOMWifiManager.js
-component {2cf775a7-1837-410c-9e26-323c42e076da} DOMWifiManager.js
-contract @mozilla.org/wifimanager;1 {2cf775a7-1837-410c-9e26-323c42e076da}
-category JavaScript-navigator-property mozWifiManager @mozilla.org/wifimanager;1
+component {c9b5f09e-25d2-40ca-aef4-c4d13d93c706} DOMWifiManager.js
+contract @mozilla.org/wifimanager;1 {c9b5f09e-25d2-40ca-aef4-c4d13d93c706}
+
+component {c01fd751-43c0-460a-8b64-abf652ec7220} DOMWifiManager.js
+contract @mozilla.org/mozwifinetwork;1 {c01fd751-43c0-460a-8b64-abf652ec7220}
+
+component {23579da4-201b-4319-bd42-9b7f337343ac} DOMWifiManager.js
+contract @mozilla.org/mozwificonnection;1 {23579da4-201b-4319-bd42-9b7f337343ac}
+
+component {83670352-6ed4-4c35-8de9-402296a1959c} DOMWifiManager.js
+contract @mozilla.org/mozwificonnectioninfo;1 {83670352-6ed4-4c35-8de9-402296a1959c}
--- a/dom/wifi/nsIWifi.idl
+++ b/dom/wifi/nsIWifi.idl
@@ -53,168 +53,8 @@ interface nsIWifi : nsISupports
      * Returns the list of currently available networks as well as the list of
      * currently configured networks.
      *
      * On success a callback is notified with the list of networks.
      * On failure after 3 scan retry attempts a callback is notified of failure.
      */
     void getWifiScanResults(in nsIWifiScanResultsReady callback);
 };
-
-[scriptable, uuid(e5a72295-1c5f-4848-9cbb-f1d3785c16c1)]
-interface nsIDOMWifiManager : nsISupports
-{
-    /**
-     * Returns the list of currently available networks.
-     * onsuccess: We have obtained the current list of networks. request.value
-     *            is an object whose property names are SSIDs and values are
-     *            network objects.
-     * onerror: We were unable to obtain a list of property names.
-     */
-    nsIDOMDOMRequest getNetworks();
-
-    /**
-     * Returns the list of networks known to the system that will be
-     * automatically connected to if they're in range.
-     * onsuccess: request.value is an object whose property names are
-     *            SSIDs and values are network objects.
-     * onerror: We were unable to obtain a list of known networks.
-     */
-    nsIDOMDOMRequest getKnownNetworks();
-
-    /**
-     * Takes one of the networks returned from getNetworks and tries to
-     * connect to it.
-     * @param network A network object with information about the network,
-     *                such as the SSID, key management desired, etc.
-     * onsuccess: We have started attempting to associate with the network.
-     *            request.value is true.
-     * onerror: We were unable to select the network. This most likely means a
-     *          configuration error.
-     */
-    nsIDOMDOMRequest associate(in jsval network);
-
-    /**
-     * Given a network, removes it from the list of networks that we'll
-     * automatically connect to. In order to re-connect to the network, it is
-     * necessary to call associate on it.
-     * @param network A network object with the SSID of the network to remove.
-     * onsuccess: We have removed this network. If we were previously
-     *            connected to it, we have started reconnecting to the next
-     *            network in the list.
-     * onerror: We were unable to remove the network.
-     */
-    nsIDOMDOMRequest forget(in jsval network);
-
-    /**
-     * Wi-Fi Protected Setup functionality.
-     * @param detail WPS detail which has 'method' and 'pin' field.
-     *               The possible method field values are:
-     *                 - pbc: The Push Button Configuration.
-     *                 - pin: The PIN configuration.
-     *                 - cancel: Request to cancel WPS in progress.
-     *               If method field is 'pin', 'pin' field can exist and has
-     *               a PIN number.
-     *               If method field is 'pin', 'bssid' field can exist and has
-     *               a opposite BSSID.
-     * onsuccess: We have successfully started/canceled wps.
-     * onerror: We have failed to start/cancel wps.
-     */
-    nsIDOMDOMRequest wps(in jsval detail);
-
-    /**
-     * Turn on/off wifi power saving mode.
-     * @param enabled true or false.
-     * onsuccess: We have successfully turn on/off wifi power saving mode.
-     * onerror: We have failed to turn on/off wifi power saving mode.
-     */
-    nsIDOMDOMRequest setPowerSavingMode(in boolean enabled);
-
-    /**
-     * Given a network, configure using static IP instead of running DHCP
-     * @param network A network object with the SSID of the network to set static ip.
-     * @param info info should have following field:
-     *        - enabled True to enable static IP, false to use DHCP
-     *        - ipaddr configured static IP address
-     *        - proxy configured proxy server address
-     *        - maskLength configured mask length
-     *        - gateway configured gateway address
-     *        - dns1 configured first DNS server address
-     *        - dns2 configured seconf DNS server address
-     * onsuccess: We have successfully configure the static ip mode.
-     * onerror: We have failed to configure the static ip mode.
-     */
-    nsIDOMDOMRequest setStaticIpMode(in jsval network,
-                                     in jsval info);
-
-    /**
-     * Given a network, configure http proxy when using wifi.
-     * @param network A network object with the SSID of the network to set http proxy.
-     * @param info info should have following field:
-     *        - httpProxyHost ip address of http proxy.
-     *        - httpProxyPort port of http proxy, set 0 to use default port 8080.
-     *        set info to null to clear http proxy.
-     * onsuccess: We have successfully configure http proxy.
-     * onerror: We have failed to configure http proxy.
-     */
-    nsIDOMDOMRequest setHttpProxy(in jsval network,
-                                  in jsval info);
-
-    /**
-     * Returns whether or not wifi is currently enabled.
-     */
-    readonly attribute boolean enabled;
-
-    /**
-     * Returns the MAC address of the wifi adapter.
-     */
-    readonly attribute DOMString macAddress;
-
-    /**
-     * An non-null object containing the following information:
-     *  - status ("disconnected", "connecting", "associated", "connected")
-     *  - network
-     *
-     *  Note that the object returned is read only. Any changes required must
-     *  be done by calling other APIs.
-     */
-    readonly attribute jsval connection;
-
-    /**
-     * A connectionInformation object with the same information found in an
-     * nsIDOMMozWifiConnectionInfoEvent (but without the network).
-     * If we are not currently connected to a network, this will be null.
-     */
-    readonly attribute jsval connectionInformation;
-
-    /**
-     * State notification listeners. These all take an
-     * nsIDOMMozWifiStatusChangeEvent with the new status and a network (which
-     * may be null).
-     *
-     * The possible statuses are:
-     *   - connecting: Fires when we start the process of connecting to a
-     *                 network.
-     *   - associated: Fires when we have connected to an access point but do
-     *                 not yet have an IP address.
-     *   - connected: Fires once we are fully connected to an access point and
-     *                can access the internet.
-     *   - disconnected: Fires when we either fail to connect to an access
-     *                   point (transition: associated -> disconnected) or
-     *                   when we were connected to a network but have
-     *                   disconnected for any reason (transition: connected ->
-     *                   disconnected).
-     */
-    attribute nsIDOMEventListener onstatuschange;
-
-    /**
-     * An event listener that is called with information about the signal
-     * strength and link speed every 5 seconds.
-     */
-    attribute nsIDOMEventListener connectionInfoUpdate;
-
-    /**
-     * These two events fire when the wifi system is brought online or taken
-     * offline.
-     */
-    attribute nsIDOMEventListener onenabled;
-    attribute nsIDOMEventListener ondisabled;
-};
new file mode 100644
--- /dev/null
+++ b/dom/xml/crashtests/994740-1.xhtml
@@ -0,0 +1,15 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script>
+<![CDATA[
+
+function boom()
+{
+    document.createElement("head").innerHTML = "<";
+}
+
+]]>
+</script></head>
+
+<body onload="boom();"></body>
+</html>
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -728,16 +728,17 @@ Layer::ComputeEffectiveTransformForMaskL
     mMaskLayer->mEffectiveTransform = mMaskLayer->GetTransform() * mMaskLayer->mEffectiveTransform;
   }
 }
 
 ContainerLayer::ContainerLayer(LayerManager* aManager, void* aImplData)
   : Layer(aManager, aImplData),
     mFirstChild(nullptr),
     mLastChild(nullptr),
+    mScrollHandoffParentId(FrameMetrics::NULL_SCROLL_ID),
     mPreXScale(1.0f),
     mPreYScale(1.0f),
     mInheritedXScale(1.0f),
     mInheritedYScale(1.0f),
     mUseIntermediateSurface(false),
     mSupportsComponentAlphaChildren(false),
     mMayHaveReadbackChild(false)
 {
@@ -888,17 +889,18 @@ ContainerLayer::RepositionChild(Layer* a
   aChild->SetPrevSibling(aAfter);
   aChild->SetNextSibling(afterNext);
   return true;
 }
 
 void
 ContainerLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
 {
-  aAttrs = ContainerLayerAttributes(GetFrameMetrics(), mPreXScale, mPreYScale,
+  aAttrs = ContainerLayerAttributes(GetFrameMetrics(), mScrollHandoffParentId,
+                                    mPreXScale, mPreYScale,
                                     mInheritedXScale, mInheritedYScale);
 }
 
 bool
 ContainerLayer::HasMultipleChildren()
 {
   uint32_t count = 0;
   for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
@@ -1376,16 +1378,19 @@ ThebesLayer::PrintInfo(nsACString& aTo, 
 
 nsACString&
 ContainerLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
 {
   Layer::PrintInfo(aTo, aPrefix);
   if (!mFrameMetrics.IsDefault()) {
     AppendToString(aTo, mFrameMetrics, " [metrics=", "]");
   }
+  if (mScrollHandoffParentId != FrameMetrics::NULL_SCROLL_ID) {
+    aTo.AppendPrintf(" [scrollParent=%llu]", mScrollHandoffParentId);
+  }
   if (UseIntermediateSurface()) {
     aTo += " [usesTmpSurf]";
   }
   if (1.0 != mPreXScale || 1.0 != mPreYScale) {
     aTo.AppendPrintf(" [preScale=%g, %g]", mPreXScale, mPreYScale);
   }
   return aTo;
 }
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1622,16 +1622,32 @@ public:
   }
 
   // These functions allow attaching an AsyncPanZoomController to this layer,
   // and can be used anytime.
   // A container layer has an APZC only-if GetFrameMetrics().IsScrollable()
   void SetAsyncPanZoomController(AsyncPanZoomController *controller);
   AsyncPanZoomController* GetAsyncPanZoomController() const;
 
+  /**
+   * CONSTRUCTION PHASE ONLY
+   * Set the ViewID of the ContainerLayer to which overscroll should be handed
+   * off. A value of NULL_SCROLL_ID means that the default handoff-parent-finding
+   * behaviour should be used (i.e. walk up the layer tree to find the next
+   * scrollable ancestor layer).
+   */
+  void SetScrollHandoffParentId(FrameMetrics::ViewID aScrollParentId)
+  {
+    if (mScrollHandoffParentId != aScrollParentId) {
+      MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ScrollHandoffParentId", this));
+      mScrollHandoffParentId = aScrollParentId;
+      Mutated();
+    }
+  }
+
   void SetPreScale(float aXScale, float aYScale)
   {
     if (mPreXScale == aXScale && mPreYScale == aYScale) {
       return;
     }
 
     MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PreScale", this));
     mPreXScale = aXScale;
@@ -1658,16 +1674,17 @@ public:
   // These getters can be used anytime.
 
   virtual ContainerLayer* AsContainerLayer() { return this; }
   virtual const ContainerLayer* AsContainerLayer() const { return this; }
 
   virtual Layer* GetFirstChild() const { return mFirstChild; }
   virtual Layer* GetLastChild() const { return mLastChild; }
   const FrameMetrics& GetFrameMetrics() const { return mFrameMetrics; }
+  FrameMetrics::ViewID GetScrollHandoffParentId() const { return mScrollHandoffParentId; }
   float GetPreXScale() const { return mPreXScale; }
   float GetPreYScale() const { return mPreYScale; }
   float GetInheritedXScale() const { return mInheritedXScale; }
   float GetInheritedYScale() const { return mInheritedYScale; }
 
   MOZ_LAYER_DECL_NAME("ContainerLayer", TYPE_CONTAINER)
 
   /**
@@ -1729,16 +1746,17 @@ protected:
   void ComputeEffectiveTransformsForChildren(const gfx::Matrix4x4& aTransformToSurface);
 
   virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
 
   Layer* mFirstChild;
   Layer* mLastChild;
   FrameMetrics mFrameMetrics;
   nsRefPtr<AsyncPanZoomController> mAPZC;
+  FrameMetrics::ViewID mScrollHandoffParentId;
   float mPreXScale;
   float mPreYScale;
   // The resolution scale inherited from the parent layer. This will already
   // be part of mTransform.
   float mInheritedXScale;
   float mInheritedYScale;
   bool mUseIntermediateSurface;
   bool mSupportsComponentAlphaChildren;
--- a/gfx/layers/basic/TextureClientX11.cpp
+++ b/gfx/layers/basic/TextureClientX11.cpp
@@ -71,44 +71,16 @@ TextureClientX11::ToSurfaceDescriptor(Su
 TextureClientData*
 TextureClientX11::DropTextureData()
 {
   MOZ_ASSERT(!(mFlags & TEXTURE_DEALLOCATE_CLIENT));
   return nullptr;
 }
 
 bool
-TextureClientX11::UpdateSurface(gfxASurface* aSurface)
-{
-  MOZ_ASSERT(IsValid());
-
-  RefPtr<DrawTarget> dt = GetAsDrawTarget();
-  if (!dt) {
-    return false;
-  }
-
-  RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
-  dt->CopySurface(source, IntRect(IntPoint(), GetSize()), IntPoint());
-
-  return true;
-}
-
-already_AddRefed<gfxASurface>
-TextureClientX11::GetAsSurface()
-{
-  MOZ_ASSERT(IsValid());
-  if (!mSurface) {
-    return nullptr;
-  }
-
-  nsRefPtr<gfxASurface> temp = mSurface.get();
-  return temp.forget();
-}
-
-bool
 TextureClientX11::AllocateForSurface(IntSize aSize, TextureAllocationFlags aTextureFlags)
 {
   MOZ_ASSERT(IsValid());
   //MOZ_ASSERT(mFormat != gfx::FORMAT_YUV, "This TextureClient cannot use YCbCr data");
 
   gfxContentType contentType = ContentForFormat(mFormat);
   nsRefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(aSize, contentType);
   if (!surface || surface->GetType() != gfxSurfaceType::Xlib) {
--- a/gfx/layers/basic/TextureClientX11.h
+++ b/gfx/layers/basic/TextureClientX11.h
@@ -46,20 +46,16 @@ class TextureClientX11
   virtual bool AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags flags) MOZ_OVERRIDE;
 
   virtual bool CanExposeDrawTarget() const MOZ_OVERRIDE { return true; }
 
   virtual TemporaryRef<gfx::DrawTarget> GetAsDrawTarget() MOZ_OVERRIDE;
 
   virtual gfx::SurfaceFormat GetFormat() const { return mFormat; }
 
-  virtual bool UpdateSurface(gfxASurface* aSurface) MOZ_OVERRIDE;
-
-  virtual already_AddRefed<gfxASurface> GetAsSurface() MOZ_OVERRIDE;
-
   virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
 
  private:
   gfx::SurfaceFormat mFormat;
   gfx::IntSize mSize;
   RefPtr<gfxXlibSurface> mSurface;
   bool mLocked;
 };
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -666,61 +666,16 @@ BufferTextureClient::~BufferTextureClien
 
 ISurfaceAllocator*
 BufferTextureClient::GetAllocator() const
 {
   return mAllocator;
 }
 
 bool
-BufferTextureClient::UpdateSurface(gfxASurface* aSurface)
-{
-  MOZ_ASSERT(mLocked);
-  MOZ_ASSERT(aSurface);
-  MOZ_ASSERT(!IsImmutable());
-  MOZ_ASSERT(IsValid());
-
-  ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
-  if (!serializer.IsValid()) {
-    return false;
-  }
-
-  RefPtr<DrawTarget> dt = GetAsDrawTarget();
-  RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
-
-  dt->CopySurface(source, IntRect(IntPoint(), serializer.GetSize()), IntPoint());
-  // XXX - if the Moz2D backend is D2D, we would be much better off memcpying
-  // the content of the surface directly because with D2D, GetAsDrawTarget is
-  // very expensive.
-
-  if (TextureRequiresLocking(mFlags) && !ImplementsLocking()) {
-    // We don't have support for proper locking yet, so we'll
-    // have to be immutable instead.
-    MarkImmutable();
-  }
-  return true;
-}
-
-already_AddRefed<gfxASurface>
-BufferTextureClient::GetAsSurface()
-{
-  MOZ_ASSERT(mLocked);
-  MOZ_ASSERT(IsValid());
-
-  ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
-  if (!serializer.IsValid()) {
-    return nullptr;
-  }
-
-  RefPtr<gfxImageSurface> surf = serializer.GetAsThebesSurface();
-  nsRefPtr<gfxASurface> result = surf.get();
-  return result.forget();
-}
-
-bool
 BufferTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
 {
   MOZ_ASSERT(IsValid());
   MOZ_ASSERT(mFormat != gfx::SurfaceFormat::YUV, "This textureClient cannot use YCbCr data");
   MOZ_ASSERT(aSize.width * aSize.height);
 
   int bufSize
     = ImageDataSerializer::ComputeMinBufferSize(aSize, mFormat);
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -61,18 +61,16 @@ enum TextureAllocationFlags {
 };
 
 /**
  * Interface for TextureClients that can be updated using a gfxASurface.
  */
 class TextureClientSurface
 {
 public:
-  virtual bool UpdateSurface(gfxASurface* aSurface) = 0;
-  virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
   /**
    * Allocates for a given surface size, taking into account the pixel format
    * which is part of the state of the TextureClient.
    *
    * Does not clear the surface by default, clearing the surface can be done
    * by passing the CLEAR_BUFFER flag.
    */
   virtual bool AllocateForSurface(gfx::IntSize aSize,
@@ -436,20 +434,16 @@ public:
   virtual bool CanExposeDrawTarget() const MOZ_OVERRIDE { return true; }
 
   virtual TemporaryRef<gfx::DrawTarget> GetAsDrawTarget() MOZ_OVERRIDE;
 
   // TextureClientSurface
 
   virtual TextureClientSurface* AsTextureClientSurface() MOZ_OVERRIDE { return this; }
 
-  virtual bool UpdateSurface(gfxASurface* aSurface) MOZ_OVERRIDE;
-
-  virtual already_AddRefed<gfxASurface> GetAsSurface() MOZ_OVERRIDE;
-
   virtual bool AllocateForSurface(gfx::IntSize aSize,
                                   TextureAllocationFlags aFlags = ALLOC_DEFAULT) MOZ_OVERRIDE;
 
   // TextureClientYCbCr
 
   virtual TextureClientYCbCr* AsTextureClientYCbCr() MOZ_OVERRIDE { return this; }
 
   virtual bool UpdateYCbCr(const PlanarYCbCrData& aData) MOZ_OVERRIDE;
--- a/gfx/layers/composite/APZCTreeManager.cpp
+++ b/gfx/layers/composite/APZCTreeManager.cpp
@@ -210,16 +210,17 @@ APZCTreeManager::UpdatePanZoomController
           aApzcsToDestroy->RemoveElement(apzc);
           apzc->SetPrevSibling(nullptr);
           apzc->SetLastChild(nullptr);
         }
         APZC_LOG("Using APZC %p for layer %p with identifiers %lld %lld\n", apzc, aLayer, aLayersId, container->GetFrameMetrics().GetScrollId());
 
         apzc->NotifyLayersUpdated(metrics,
                                   aIsFirstPaint && (aLayersId == aFirstPaintLayersId));
+        apzc->SetScrollHandoffParentId(container->GetScrollHandoffParentId());
 
         // Use the composition bounds as the hit test region.
         // Optionally, the GeckoContentController can provide a touch-sensitive
         // region that constrains all frames associated with the controller.
         // In this case we intersect the composition bounds with that region.
         ParentLayerRect visible(metrics.mCompositionBounds);
         CSSRect touchSensitiveRegion;
         if (state->mController->GetTouchSensitiveRegion(&touchSensitiveRegion)) {
@@ -863,37 +864,94 @@ APZCTreeManager::BuildOverscrollHandoffC
   // order in which scroll will be handed off to them.
 
   // Grab tree lock to protect mOverscrollHandoffChain from concurrent
   // access between the input and compositor threads.
   MonitorAutoLock lock(mTreeLock);
 
   mOverscrollHandoffChain.clear();
 
-  // Start with the child -> parent chain.
-  for (AsyncPanZoomController* apzc = aInitialTarget; apzc; apzc = apzc->GetParent()) {
+  // Build the chain. If there is a scroll parent link, we use that. This is
+  // needed to deal with scroll info layers, because they participate in handoff
+  // but do not follow the expected layer tree structure. If there are no
+  // scroll parent links we just walk up the tree to find the scroll parent.
+  AsyncPanZoomController* apzc = aInitialTarget;
+  while (apzc != nullptr) {
     if (!mOverscrollHandoffChain.append(apzc)) {
       NS_WARNING("Vector::append failed");
       mOverscrollHandoffChain.clear();
       return;
     }
+    if (apzc->GetScrollHandoffParentId() == FrameMetrics::NULL_SCROLL_ID) {
+      if (!apzc->IsRootForLayersId()) {
+        // This probably indicates a bug or missed case in layout code
+        NS_WARNING("Found a non-root APZ with no handoff parent");
+      }
+      apzc = apzc->GetParent();
+      continue;
+    }
+
+    // Find the AsyncPanZoomController instance with a matching layersId and
+    // the scroll id that matches apzc->GetScrollHandoffParentId(). To do this
+    // search the subtree with the same layersId for the apzc with the specified
+    // scroll id.
+    AsyncPanZoomController* scrollParent = nullptr;
+    AsyncPanZoomController* parent = apzc;
+    while (!parent->IsRootForLayersId()) {
+      parent = parent->GetParent();
+      // While walking up to find the root of the subtree, if we encounter the
+      // handoff parent, we don't actually need to do the search so we can
+      // just abort here.
+      if (parent->GetGuid().mScrollId == apzc->GetScrollHandoffParentId()) {
+        scrollParent = parent;
+        break;
+      }
+    }
+    if (!scrollParent) {
+      scrollParent = FindTargetAPZC(parent, apzc->GetScrollHandoffParentId());
+    }
+    apzc = scrollParent;
   }
 
   // Now adjust the chain to account for scroll grabbing. Sorting is a bit
   // of an overkill here, but scroll grabbing will likely be generalized
   // to scroll priorities, so we might as well do it this way.
   // The sorting being stable ensures that the relative order between
   // non-scrollgrabbing APZCs remains child -> parent.
   // (The relative order between scrollgrabbing APZCs will also remain
   // child -> parent, though that's just an artefact of the implementation
   // and users of 'scrollgrab' should not rely on this.)
   std::stable_sort(mOverscrollHandoffChain.begin(), mOverscrollHandoffChain.end(),
                    CompareByScrollPriority());
 }
 
+/* Find the apzc in the subtree rooted at aApzc that has the same layers id as
+   aApzc, and that has the given scroll id. Generally this function should be called
+   with aApzc being the root of its layers id subtree. */
+AsyncPanZoomController*
+APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, FrameMetrics::ViewID aScrollId)
+{
+  mTreeLock.AssertCurrentThreadOwns();
+
+  if (aApzc->GetGuid().mScrollId == aScrollId) {
+    return aApzc;
+  }
+  for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
+    if (child->GetGuid().mLayersId != aApzc->GetGuid().mLayersId) {
+      continue;
+    }
+    AsyncPanZoomController* match = FindTargetAPZC(child, aScrollId);
+    if (match) {
+      return match;
+    }
+  }
+
+  return nullptr;
+}
+
 void
 APZCTreeManager::ClearOverscrollHandoffChain()
 {
   MonitorAutoLock lock(mTreeLock);
   mOverscrollHandoffChain.clear();
 }
 
 AsyncPanZoomController*
--- a/gfx/layers/composite/APZCTreeManager.h
+++ b/gfx/layers/composite/APZCTreeManager.h
@@ -293,16 +293,17 @@ public:
      used by other production code.
   */
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint);
   void GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut,
                           gfx3DMatrix& aTransformToGeckoOut);
 private:
   /* Helpers */
+  AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, FrameMetrics::ViewID aScrollId);
   AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
   AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint);
   already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
   already_AddRefed<AsyncPanZoomController> RootAPZCForLayersId(AsyncPanZoomController* aApzc);
   already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent);
   nsEventStatus ProcessTouchEvent(WidgetTouchEvent& touchEvent, ScrollableLayerGuid* aOutTargetGuid);
   nsEventStatus ProcessEvent(WidgetInputEvent& inputEvent, ScrollableLayerGuid* aOutTargetGuid);
   void UpdateZoomConstraintsRecursively(AsyncPanZoomController* aApzc,
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -556,17 +556,17 @@ AsyncCompositionManager::ApplyAsyncConte
     oldTransform.Scale(resolution.scale, resolution.scale, 1);
 
     AlignFixedAndStickyLayers(aLayer, aLayer, oldTransform, fixedLayerMargins);
 
     appliedTransform = true;
   }
 
   if (container->GetScrollbarDirection() != Layer::NONE) {
-    ApplyAsyncTransformToScrollbar(container);
+    ApplyAsyncTransformToScrollbar(aCurrentFrame, container);
   }
   return appliedTransform;
 }
 
 static bool
 LayerHasNonContainerDescendants(ContainerLayer* aContainer)
 {
   for (Layer* child = aContainer->GetFirstChild();
@@ -575,78 +575,140 @@ LayerHasNonContainerDescendants(Containe
     if (!container || LayerHasNonContainerDescendants(container)) {
       return true;
     }
   }
 
   return false;
 }
 
-void
-AsyncCompositionManager::ApplyAsyncTransformToScrollbar(ContainerLayer* aLayer)
+static bool
+LayerIsContainerForScrollbarTarget(Layer* aTarget, ContainerLayer* aScrollbar)
+{
+  if (!aTarget->AsContainerLayer()) {
+    return false;
+  }
+  AsyncPanZoomController* apzc = aTarget->AsContainerLayer()->GetAsyncPanZoomController();
+  if (!apzc) {
+    return false;
+  }
+  const FrameMetrics& metrics = aTarget->AsContainerLayer()->GetFrameMetrics();
+  if (metrics.GetScrollId() != aScrollbar->GetScrollbarTargetContainerId()) {
+    return false;
+  }
+  return true;
+}
+
+static void
+ApplyAsyncTransformToScrollbarForContent(TimeStamp aCurrentFrame, ContainerLayer* aScrollbar,
+                                         Layer* aContent, bool aScrollbarIsChild)
 {
-  // If this layer corresponds to a scrollbar, then search backwards through the
-  // siblings until we find the container layer with the right ViewID; this is
-  // the content that this scrollbar is for. Pick up the transient async transform
-  // from that layer and use it to update the scrollbar position.
+  ContainerLayer* content = aContent->AsContainerLayer();
+  if (!LayerHasNonContainerDescendants(content)) {
+    return;
+  }
+
+  const FrameMetrics& metrics = content->GetFrameMetrics();
+  AsyncPanZoomController* apzc = content->GetAsyncPanZoomController();
+
+  if (aScrollbarIsChild) {
+    // Because we try to apply the scrollbar transform before we apply the async transform on
+    // the actual content, we need to ensure that the APZC has updated any pending animations
+    // to the current frame timestamp before we extract the transforms from it. The code in this
+    // block accomplishes that and throws away the temp variables.
+    // TODO: it might be cleaner to do a pass through the layer tree to advance all the APZC
+    // transforms before updating the layer shadow transforms. That will allow removal of this code.
+    ViewTransform treeTransform;
+    ScreenPoint scrollOffset;
+    apzc->SampleContentTransformForFrame(aCurrentFrame, &treeTransform, scrollOffset);
+  }
+
+  gfx3DMatrix asyncTransform = gfx3DMatrix(apzc->GetCurrentAsyncTransform());
+  gfx3DMatrix nontransientTransform = apzc->GetNontransientAsyncTransform();
+  gfx3DMatrix transientTransform = asyncTransform * nontransientTransform.Inverse();
+
+  // |transientTransform| represents the amount by which we have scrolled and
+  // zoomed since the last paint. Because the scrollbar was sized and positioned based
+  // on the painted content, we need to adjust it based on transientTransform so that
+  // it reflects what the user is actually seeing now.
+  // - The scroll thumb needs to be scaled in the direction of scrolling by the inverse
+  //   of the transientTransform scale (representing the zoom). This is because zooming
+  //   in decreases the fraction of the whole scrollable rect that is in view.
+  // - It needs to be translated in opposite direction of the transientTransform
+  //   translation (representing the scroll). This is because scrolling down, which
+  //   translates the layer content up, should result in moving the scroll thumb down.
+  //   The amount of the translation to the scroll thumb should be such that the ratio
+  //   of the translation to the size of the scroll port is the same as the ratio
+  //   of the scroll amount to the size of the scrollable rect.
+  Matrix4x4 scrollbarTransform;
+  if (aScrollbar->GetScrollbarDirection() == Layer::VERTICAL) {
+    float scale = metrics.CalculateCompositedSizeInCssPixels().height / metrics.mScrollableRect.height;
+    scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f, 1.f / transientTransform.GetYScale(), 1.f);
+    scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(0, -transientTransform._42 * scale, 0);
+  }
+  if (aScrollbar->GetScrollbarDirection() == Layer::HORIZONTAL) {
+    float scale = metrics.CalculateCompositedSizeInCssPixels().width / metrics.mScrollableRect.width;
+    scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f / transientTransform.GetXScale(), 1.f, 1.f);
+    scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(-transientTransform._41 * scale, 0, 0);
+  }
+
+  Matrix4x4 transform = scrollbarTransform * aScrollbar->GetTransform();
+
+  if (aScrollbarIsChild) {
+    // If the scrollbar layer is a child of the content it is a scrollbar for, then we
+    // need to do an extra untransform to cancel out the transient async transform on
+    // the content. This is needed because otherwise that transient async transform is
+    // part of the effective transform of this scrollbar, and the scrollbar will jitter
+    // as the content scrolls.
+    Matrix4x4 targetUntransform;
+    ToMatrix4x4(transientTransform.Inverse(), targetUntransform);
+    transform = transform * targetUntransform;
+  }
+
+  // GetTransform already takes the pre- and post-scale into account.  Since we
+  // will apply the pre- and post-scale again when computing the effective
+  // transform, we must apply the inverses here.
+  transform.Scale(1.0f/aScrollbar->GetPreXScale(),
+                  1.0f/aScrollbar->GetPreYScale(),
+                  1);
+  transform = transform * Matrix4x4().Scale(1.0f/aScrollbar->GetPostXScale(),
+                                            1.0f/aScrollbar->GetPostYScale(),
+                                            1);
+  aScrollbar->AsLayerComposite()->SetShadowTransform(transform);
+}
+
+void
+AsyncCompositionManager::ApplyAsyncTransformToScrollbar(TimeStamp aCurrentFrame, ContainerLayer* aLayer)
+{
+  // If this layer corresponds to a scrollbar, then there should be a layer that
+  // is a previous sibling or a parent that has a matching ViewID on its FrameMetrics.
+  // That is the content that this scrollbar is for. We pick up the transient
+  // async transform from that layer and use it to update the scrollbar position.
   // Note that it is possible that the content layer is no longer there; in
   // this case we don't need to do anything because there can't be an async
   // transform on the content.
   // We only apply the transform if the scroll-target layer has non-container
   // children (i.e. when it has some possibly-visible content). This is to
   // avoid moving scroll-bars in the situation that only a scroll information
   // layer has been built for a scroll frame, as this would result in a
   // disparity between scrollbars and visible content.
   for (Layer* scrollTarget = aLayer->GetPrevSibling();
        scrollTarget;
        scrollTarget = scrollTarget->GetPrevSibling()) {
-    if (!scrollTarget->AsContainerLayer()) {
-      continue;
-    }
-    AsyncPanZoomController* apzc = scrollTarget->AsContainerLayer()->GetAsyncPanZoomController();
-    if (!apzc) {
-      continue;
-    }
-    const FrameMetrics& metrics = scrollTarget->AsContainerLayer()->GetFrameMetrics();
-    if (metrics.GetScrollId() != aLayer->GetScrollbarTargetContainerId()) {
-      continue;
-    }
-    if (!LayerHasNonContainerDescendants(scrollTarget->AsContainerLayer())) {
+    if (LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) {
+      // Found a sibling that matches our criteria
+      ApplyAsyncTransformToScrollbarForContent(aCurrentFrame, aLayer, scrollTarget, false);
       return;
     }
-
-    gfx3DMatrix asyncTransform = gfx3DMatrix(apzc->GetCurrentAsyncTransform());
-    gfx3DMatrix nontransientTransform = apzc->GetNontransientAsyncTransform();
-    gfx3DMatrix transientTransform = asyncTransform * nontransientTransform.Inverse();
+  }
 
-    Matrix4x4 scrollbarTransform;
-    if (aLayer->GetScrollbarDirection() == Layer::VERTICAL) {
-      float scale = metrics.CalculateCompositedSizeInCssPixels().height / metrics.mScrollableRect.height;
-      scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f, 1.f / transientTransform.GetYScale(), 1.f);
-      scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(0, -transientTransform._42 * scale, 0);
-    }
-    if (aLayer->GetScrollbarDirection() == Layer::HORIZONTAL) {
-      float scale = metrics.CalculateCompositedSizeInCssPixels().width / metrics.mScrollableRect.width;
-      scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f / transientTransform.GetXScale(), 1.f, 1.f);
-      scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(-transientTransform._41 * scale, 0, 0);
-    }
-
-    Matrix4x4 transform = scrollbarTransform * aLayer->GetTransform();
-    // GetTransform already takes the pre- and post-scale into account.  Since we
-    // will apply the pre- and post-scale again when computing the effective
-    // transform, we must apply the inverses here.
-    transform.Scale(1.0f/aLayer->GetPreXScale(),
-                    1.0f/aLayer->GetPreYScale(),
-                    1);
-    transform = transform * Matrix4x4().Scale(1.0f/aLayer->GetPostXScale(),
-                                              1.0f/aLayer->GetPostYScale(),
-                                              1);
-    aLayer->AsLayerComposite()->SetShadowTransform(transform);
-
-    return;
+  // If we didn't find a sibling, look for a parent
+  Layer* scrollTarget = aLayer->GetParent();
+  if (scrollTarget && LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) {
+    ApplyAsyncTransformToScrollbarForContent(aCurrentFrame, aLayer, scrollTarget, true);
   }
 }
 
 void
 AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
 {
   LayerComposite* layerComposite = aLayer->AsLayerComposite();
   ContainerLayer* container = aLayer->AsContainerLayer();
--- a/gfx/layers/composite/AsyncCompositionManager.h
+++ b/gfx/layers/composite/AsyncCompositionManager.h
@@ -119,20 +119,20 @@ public:
 private:
   void TransformScrollableLayer(Layer* aLayer);
   // Return true if an AsyncPanZoomController content transform was
   // applied for |aLayer|.  *aWantNextFrame is set to true if the
   // controller wants another animation frame.
   bool ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame, Layer* aLayer,
                                         bool* aWantNextFrame);
   /**
-   * Update the shadow trasnform for aLayer assuming that is a scrollbar,
+   * Update the shadow transform for aLayer assuming that is a scrollbar,
    * so that it stays in sync with the content that is being scrolled by APZ.
    */
-  void ApplyAsyncTransformToScrollbar(ContainerLayer* aLayer);
+  void ApplyAsyncTransformToScrollbar(TimeStamp aCurrentFrame, ContainerLayer* aLayer);
 
   void SetFirstPaintViewport(const LayerIntPoint& aOffset,
                              const CSSToLayerScale& aZoom,
                              const CSSRect& aCssPageRect);
   void SetPageRect(const CSSRect& aCssPageRect);
   void SyncViewportInfo(const LayerIntRect& aDisplayPort,
                         const CSSToLayerScale& aDisplayResolution,
                         bool aLayersUpdated,
--- a/gfx/layers/composite/TiledContentHost.h
+++ b/gfx/layers/composite/TiledContentHost.h
@@ -207,27 +207,16 @@ public:
   const nsIntRegion& GetValidLowPrecisionRegion() const
   {
     return mLowPrecisionTiledBuffer.GetValidRegion();
   }
 
   void UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
                            const SurfaceDescriptorTiles& aTiledDescriptor);
 
-  // Renders a single given tile.
-  void RenderTile(const TileHost& aTile,
-                  EffectChain& aEffectChain,
-                  float aOpacity,
-                  const gfx::Matrix4x4& aTransform,
-                  const gfx::Filter& aFilter,
-                  const gfx::Rect& aClipRect,
-                  const nsIntRegion& aScreenRegion,
-                  const nsIntPoint& aTextureOffset,
-                  const nsIntSize& aTextureBounds);
-
   void Composite(EffectChain& aEffectChain,
                  float aOpacity,
                  const gfx::Matrix4x4& aTransform,
                  const gfx::Filter& aFilter,
                  const gfx::Rect& aClipRect,
                  const nsIntRegion* aVisibleRegion = nullptr,
                  TiledLayerProperties* aLayerProperties = nullptr);
 
@@ -255,24 +244,36 @@ public:
   virtual void SetReleaseFence(const android::sp<android::Fence>& aReleaseFence)
   {
     mTiledBuffer.SetReleaseFence(aReleaseFence);
     mLowPrecisionTiledBuffer.SetReleaseFence(aReleaseFence);
   }
 #endif
 
 private:
+
   void RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
                          EffectChain& aEffectChain,
                          float aOpacity,
                          const gfx::Filter& aFilter,
                          const gfx::Rect& aClipRect,
                          nsIntRegion aMaskRegion,
                          gfx::Matrix4x4 aTransform);
 
+  // Renders a single given tile.
+  void RenderTile(const TileHost& aTile,
+                  EffectChain& aEffectChain,
+                  float aOpacity,
+                  const gfx::Matrix4x4& aTransform,
+                  const gfx::Filter& aFilter,
+                  const gfx::Rect& aClipRect,
+                  const nsIntRegion& aScreenRegion,
+                  const nsIntPoint& aTextureOffset,
+                  const nsIntSize& aTextureBounds);
+
   void EnsureTileStore() {}
 
   TiledLayerBufferComposite    mTiledBuffer;
   TiledLayerBufferComposite    mLowPrecisionTiledBuffer;
   TiledLayerBufferComposite    mOldTiledBuffer;
   TiledLayerBufferComposite    mOldLowPrecisionTiledBuffer;
   bool                         mPendingUpload;
   bool                         mPendingLowPrecisionUpload;
--- a/gfx/layers/d3d9/ImageLayerD3D9.h
+++ b/gfx/layers/d3d9/ImageLayerD3D9.h
@@ -31,22 +31,16 @@ public:
   virtual void RenderLayer();
 
   virtual already_AddRefed<IDirect3DTexture9> GetAsTexture(gfx::IntSize* aSize);
 
 private:
   IDirect3DTexture9* GetTexture(Image *aImage, bool& aHasAlpha);
 };
 
-class ImageD3D9
-{
-public:
-  virtual already_AddRefed<gfxASurface> GetAsSurface() = 0;
-};
-
 
 struct TextureD3D9BackendData : public ImageBackendData
 {
   nsRefPtr<IDirect3DTexture9> mTexture;
 };
 
 struct PlanarYCbCrD3D9BackendData : public ImageBackendData
 {
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -419,16 +419,17 @@ AsyncPanZoomController::AsyncPanZoomCont
      mLastAsyncScrollOffset(0, 0),
      mCurrentAsyncScrollOffset(0, 0),
      mAsyncScrollTimeoutTask(nullptr),
      mHandlingTouchQueue(false),
      mAllowedTouchBehaviorSet(false),
      mPreventDefault(false),
      mPreventDefaultSet(false),
      mTreeManager(aTreeManager),
+     mScrollParentId(FrameMetrics::NULL_SCROLL_ID),
      mAPZCId(sAsyncPanZoomControllerCount++),
      mSharedFrameMetricsBuffer(nullptr),
      mSharedLock(nullptr)
 {
   MOZ_COUNT_CTOR(AsyncPanZoomController);
 
   if (aGestures == USE_GESTURE_DETECTOR) {
     mGestureEventListener = new GestureEventListener(this);
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -290,32 +290,16 @@ public:
   /**
    * Cancels any currently running animation. Note that all this does is set the
    * state of the AsyncPanZoomController back to NOTHING, but it is the
    * animation's responsibility to check this before advancing.
    */
   void CancelAnimation();
 
   /**
-   * Attempt to scroll in response to a touch-move from |aStartPoint| to
-   * |aEndPoint|, which are in our (transformed) screen coordinates.
-   * Due to overscroll handling, there may not actually have been a touch-move
-   * at these points, but this function will scroll as if there had been.
-   * If this attempt causes overscroll (i.e. the layer cannot be scrolled
-   * by the entire amount requested), the overscroll is passed back to the
-   * tree manager via APZCTreeManager::DispatchScroll().
-   * |aOverscrollHandoffChainIndex| is used by the tree manager to keep track
-   * of which APZC to hand off the overscroll to; this function increments it
-   * and passes it on to APZCTreeManager::DispatchScroll() in the event of
-   * overscroll.
-   */
-  void AttemptScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint,
-                     uint32_t aOverscrollHandoffChainIndex = 0);
-
-  /**
    * Take over a fling with the given velocity from another APZC. Used for
    * during overscroll handoff for a fling.
    */
   void TakeOverFling(ScreenPoint aVelocity);
 
   /**
    * Returns allowed touch behavior for the given point on the scrollable layer.
    * Internally performs a kind of hit testing based on the regions constructed
@@ -330,31 +314,21 @@ public:
   /**
    * Sets allowed touch behavior for current touch session.
    * This method is invoked by the APZCTreeManager which in its turn invoked by
    * the widget after performing touch-action values retrieving.
    */
   void SetAllowedTouchBehavior(const nsTArray<TouchBehaviorFlags>& aBehaviors);
 
   /**
-   * A helper function for calling APZCTreeManager::DispatchScroll().
-   * Guards against the case where the APZC is being concurrently destroyed
-   * (and thus mTreeManager is being nulled out).
-   */
-  void CallDispatchScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint,
-                          uint32_t aOverscrollHandoffChainIndex);
-
-  /**
    * Returns whether this APZC is for an element marked with the 'scrollgrab'
    * attribute.
    */
   bool HasScrollgrab() const { return mFrameMetrics.mHasScrollgrab; }
 
-  void FlushRepaintForOverscrollHandoff();
-
   /**
    * Set an extra offset for testing async scrolling.
    */
   void SetTestAsyncScrollOffset(const CSSPoint& aPoint)
   {
     mTestAsyncScrollOffset = aPoint;
   }
 
@@ -764,17 +738,18 @@ private:
   CSSPoint mTestAsyncScrollOffset;
 
   RefPtr<AsyncPanZoomAnimation> mAnimation;
 
   friend class Axis;
   friend class FlingAnimation;
 
 
-  /* The functions and members in this section are used to build a tree
+  /* ===================================================================
+   * The functions and members in this section are used to build a tree
    * structure out of APZC instances. This tree can only be walked or
    * manipulated while holding the lock in the associated APZCTreeManager
    * instance.
    */
 public:
   void SetLastChild(AsyncPanZoomController* child) {
     mLastChild = child;
     if (child) {
@@ -812,17 +787,62 @@ private:
   // pointer out in Destroy() will prevent accessing deleted memory.
   Atomic<APZCTreeManager*> mTreeManager;
 
   nsRefPtr<AsyncPanZoomController> mLastChild;
   nsRefPtr<AsyncPanZoomController> mPrevSibling;
   nsRefPtr<AsyncPanZoomController> mParent;
 
 
-  /* The functions and members in this section are used to maintain the
+  /* ===================================================================
+   * The functions and members in this section are used in building the
+   * scroll handoff chain, so that we can have seamless scrolling continue
+   * across APZC instances.
+   */
+public:
+  void SetScrollHandoffParentId(FrameMetrics::ViewID aScrollParentId) {
+    mScrollParentId = aScrollParentId;
+  }
+
+  FrameMetrics::ViewID GetScrollHandoffParentId() const {
+    return mScrollParentId;
+  }
+
+  /**
+   * Attempt to scroll in response to a touch-move from |aStartPoint| to
+   * |aEndPoint|, which are in our (transformed) screen coordinates.
+   * Due to overscroll handling, there may not actually have been a touch-move
+   * at these points, but this function will scroll as if there had been.
+   * If this attempt causes overscroll (i.e. the layer cannot be scrolled
+   * by the entire amount requested), the overscroll is passed back to the
+   * tree manager via APZCTreeManager::DispatchScroll().
+   * |aOverscrollHandoffChainIndex| is used by the tree manager to keep track
+   * of which APZC to hand off the overscroll to; this function increments it
+   * and passes it on to APZCTreeManager::DispatchScroll() in the event of
+   * overscroll.
+   */
+  void AttemptScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint,
+                     uint32_t aOverscrollHandoffChainIndex = 0);
+
+  void FlushRepaintForOverscrollHandoff();
+
+private:
+  FrameMetrics::ViewID mScrollParentId;
+
+  /**
+   * A helper function for calling APZCTreeManager::DispatchScroll().
+   * Guards against the case where the APZC is being concurrently destroyed
+   * (and thus mTreeManager is being nulled out).
+   */
+  void CallDispatchScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint,
+                          uint32_t aOverscrollHandoffChainIndex);
+
+
+  /* ===================================================================
+   * The functions and members in this section are used to maintain the
    * area that this APZC instance is responsible for. This is used when