Merge m-c to b2g-inbound. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 02 Jul 2015 15:59:46 -0400
changeset 270147 56e62aba9d13beea18e587157d34b028f18f632d
parent 270146 d38f200f97959f0f1f89048a88aebde0765e012c (current diff)
parent 270134 2f25351c5b058aa1ce52ab8eafe89efce07fff51 (diff)
child 270148 64a947d09ed7e8296c6371fd8861ddc5f429db31
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-esr52@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone42.0a1
Merge m-c to b2g-inbound. a=merge
mobile/android/base/overlays/service/sharemethods/ParcelableClientRecord.java
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -20,34 +20,35 @@
 #include "TableCellAccessible.h"
 
 #include "mozilla/Services.h"
 #include "nsRect.h"
 #include "nsCocoaUtils.h"
 #include "nsCoord.h"
 #include "nsObjCExceptions.h"
 #include "nsWhitespaceTokenizer.h"
+#include <prdtoa.h>
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 #define NSAccessibilityMathRootRadicandAttribute @"AXMathRootRadicand"
 #define NSAccessibilityMathRootIndexAttribute @"AXMathRootIndex"
 #define NSAccessibilityMathFractionNumeratorAttribute @"AXMathFractionNumerator"
 #define NSAccessibilityMathFractionDenominatorAttribute @"AXMathFractionDenominator"
 #define NSAccessibilityMathBaseAttribute @"AXMathBase"
 #define NSAccessibilityMathSubscriptAttribute @"AXMathSubscript"
 #define NSAccessibilityMathSuperscriptAttribute @"AXMathSuperscript"
 #define NSAccessibilityMathUnderAttribute @"AXMathUnder"
 #define NSAccessibilityMathOverAttribute @"AXMathOver"
+#define NSAccessibilityMathLineThicknessAttribute @"AXMathLineThickness"
 // XXX WebKit also defines the following attributes.
-// See bugs 1176970, 1176973 and 1176983.
+// See bugs 1176970 and 1176983.
 // - NSAccessibilityMathFencedOpenAttribute @"AXMathFencedOpen"
 // - NSAccessibilityMathFencedCloseAttribute @"AXMathFencedClose"
-// - NSAccessibilityMathLineThicknessAttribute @"AXMathLineThickness"
 // - NSAccessibilityMathPrescriptsAttribute @"AXMathPrescripts"
 // - NSAccessibilityMathPostscriptsAttribute @"AXMathPostscripts"
 
 // returns the passed in object if it is not ignored. if it's ignored, will return
 // the first unignored ancestor.
 static inline id
 GetClosestInterestingAccessible(id anObject)
 {
@@ -167,18 +168,17 @@ ConvertToNSArray(nsTArray<Accessible*>& 
       [additional addObject:NSAccessibilityMathRootRadicandAttribute];
       break;
     case roles::MATHML_SQUARE_ROOT:
       [additional addObject:NSAccessibilityMathRootRadicandAttribute];
       break;
     case roles::MATHML_FRACTION:
       [additional addObject:NSAccessibilityMathFractionNumeratorAttribute];
       [additional addObject:NSAccessibilityMathFractionDenominatorAttribute];
-      // XXX bug 1176973
-      // WebKit also defines NSAccessibilityMathLineThicknessAttribute
+      [additional addObject:NSAccessibilityMathLineThicknessAttribute];
       break;
     case roles::MATHML_SUB:
     case roles::MATHML_SUP:
     case roles::MATHML_SUB_SUP:
       [additional addObject:NSAccessibilityMathBaseAttribute];
       [additional addObject:NSAccessibilityMathSubscriptAttribute];
       [additional addObject:NSAccessibilityMathSuperscriptAttribute];
       break;
@@ -417,18 +417,34 @@ ConvertToNSArray(nsTArray<Accessible*>& 
     if ([attribute isEqualToString:NSAccessibilityMathRootRadicandAttribute])
       return [self childAt:0];
     break;
   case roles::MATHML_FRACTION:
     if ([attribute isEqualToString:NSAccessibilityMathFractionNumeratorAttribute])
       return [self childAt:0];
     if ([attribute isEqualToString:NSAccessibilityMathFractionDenominatorAttribute])
       return [self childAt:1];
-    // XXX bug 1176973
-    // WebKit also defines NSAccessibilityMathLineThicknessAttribute
+    if ([attribute isEqualToString:NSAccessibilityMathLineThicknessAttribute]) {
+      // WebKit sets line thickness to some logical value parsed in the
+      // renderer object of the <mfrac> element. It's not clear whether the
+      // exact value is relevant to assistive technologies. From a semantic
+      // point of view, the only important point is to distinguish between
+      // <mfrac> elements that have a fraction bar and those that do not.
+      // Per the MathML 3 spec, the latter happens iff the linethickness
+      // attribute is of the form [zero-float][optional-unit]. In that case we
+      // set line thickness to zero and in the other cases we set it to one.
+      nsCOMPtr<nsIPersistentProperties> attributes = accWrap->Attributes();
+      nsAutoString thickness;
+      nsAccUtils::GetAccAttr(attributes, nsGkAtoms::linethickness_, thickness);
+      double value = 1.0;
+      if (!thickness.IsEmpty())
+        value = PR_strtod(NS_LossyConvertUTF16toASCII(thickness).get(),
+                          nullptr);
+      return [NSNumber numberWithInteger:(value ? 1 : 0)];
+    }
     break;
   case roles::MATHML_SUB:
     if ([attribute isEqualToString:NSAccessibilityMathBaseAttribute])
       return [self childAt:0];
     if ([attribute isEqualToString:NSAccessibilityMathSubscriptAttribute])
       return [self childAt:1];
 #ifdef DEBUG
     if ([attribute isEqualToString:NSAccessibilityMathSuperscriptAttribute])
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -121,22 +121,24 @@ var FullScreen = {
         // request was initiated from an in-process browser, we need
         // to get its corresponding browser here.
         let browser;
         if (event.target == gBrowser) {
           browser = event.originalTarget;
         } else {
           let topWin = event.target.ownerDocument.defaultView.top;
           browser = gBrowser.getBrowserForContentWindow(topWin);
-          if (!browser) {
-            document.mozCancelFullScreen();
-            break;
+        }
+        if (!browser || !this.enterDomFullscreen(browser)) {
+          if (document.mozFullScreen) {
+            // MozDOMFullscreen:Entered is dispatched synchronously in
+            // fullscreen change, hence we have to avoid calling this
+            // method synchronously here.
+            setTimeout(() => document.mozCancelFullScreen(), 0);
           }
-        }
-        if (!this.enterDomFullscreen(browser)) {
           break;
         }
         // If it is a remote browser, send a message to ask the content
         // to enter fullscreen state. We don't need to do so if it is an
         // in-process browser, since all related document should have
         // entered fullscreen state at this point.
         if (this._isRemoteBrowser(browser)) {
           browser.messageManager.sendAsyncMessage("DOMFullscreen:Entered");
@@ -171,25 +173,23 @@ var FullScreen = {
     if (!document.mozFullScreen)
       return false;
 
     // If we've received a fullscreen notification, we have to ensure that the
     // element that's requesting fullscreen belongs to the browser that's currently
     // active. If not, we exit fullscreen since the "full-screen document" isn't
     // actually visible now.
     if (gBrowser.selectedBrowser != aBrowser) {
-      document.mozCancelFullScreen();
       return false;
     }
 
     let focusManager = Services.focus;
     if (focusManager.activeWindow != window) {
       // The top-level window has lost focus since the request to enter
       // full-screen was made. Cancel full-screen.
-      document.mozCancelFullScreen();
       return false;
     }
 
     document.documentElement.setAttribute("inDOMFullscreen", true);
 
     if (gFindBarInitialized)
       gFindBar.close();
 
--- a/browser/devtools/animationinspector/test/head.js
+++ b/browser/devtools/animationinspector/test/head.js
@@ -7,16 +7,17 @@
 const Cu = Components.utils;
 const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 const {require} = devtools;
 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 const TargetFactory = devtools.TargetFactory;
 const {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
 const {ViewHelpers} = Cu.import("resource:///modules/devtools/ViewHelpers.jsm", {});
+const DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 
 // All tests are asynchronous
 waitForExplicitFinish();
 
 const TEST_URL_ROOT = "http://example.com/browser/browser/devtools/animationinspector/test/";
 const ROOT_TEST_DIR = getRootDirectory(gTestPath);
 const FRAME_SCRIPT_URL = ROOT_TEST_DIR + "doc_frame_script.js";
 const COMMON_FRAME_SCRIPT_URL = "chrome://browser/content/devtools/frame-script-utils.js";
@@ -35,19 +36,19 @@ registerCleanupFunction(function*() {
 Services.prefs.setBoolPref(NEW_UI_PREF, false);
 
 // Uncomment this pref to dump all devtools emitted events to the console.
 // Services.prefs.setBoolPref("devtools.dump.emit", true);
 
 // Uncomment this pref to dump all devtools protocol traffic
 // Services.prefs.setBoolPref("devtools.debugger.log", true);
 
-// Set the testing flag on gDevTools and reset it when the test ends
-gDevTools.testing = true;
-registerCleanupFunction(() => gDevTools.testing = false);
+// Set the testing flag on DevToolsUtils and reset it when the test ends
+DevToolsUtils.testing = true;
+registerCleanupFunction(() => DevToolsUtils.testing = false);
 
 // Clean-up all prefs that might have been changed during a test run
 // (safer here because if the test fails, then the pref is never reverted)
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.dump.emit");
   Services.prefs.clearUserPref("devtools.debugger.log");
   Services.prefs.clearUserPref(NEW_UI_PREF);
 });
@@ -157,19 +158,20 @@ function assertAnimationsDisplayed(panel
  *
  * @param {InspectorPanel} inspector
  * @return {Promise}
  */
 let waitForAnimationInspectorReady = Task.async(function*(inspector) {
   let win = inspector.sidebar.getWindowForTab("animationinspector");
   let updated = inspector.once("inspector-updated");
 
-  // In e10s, if we wait for underlying toolbox actors to load (by setting
-  // gDevTools.testing to true), we miss the "animationinspector-ready" event on
-  // the sidebar, so check to see if the iframe is already loaded.
+  // In e10s, if we wait for underlying toolbox actors to
+  // load (by setting DevToolsUtils.testing to true), we miss the
+  // "animationinspector-ready" event on the sidebar, so check to see if the
+  // iframe is already loaded.
   let tabReady = win.document.readyState === "complete" ?
                  promise.resolve() :
                  inspector.sidebar.once("animationinspector-ready");
 
   return promise.all([updated, tabReady]);
 });
 
 /**
--- a/browser/devtools/app-manager/test/head.js
+++ b/browser/devtools/app-manager/test/head.js
@@ -6,27 +6,28 @@ const {utils: Cu, classes: Cc, interface
 
 const {Promise: promise} =
   Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js", {});
 const {devtools} =
   Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 const {require} = devtools;
 
 const {AppProjects} = require("devtools/app-manager/app-projects");
+const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
 
 const APP_MANAGER_URL = "about:app-manager";
 const TEST_BASE =
   "chrome://mochitests/content/browser/browser/devtools/app-manager/test/";
 const HOSTED_APP_MANIFEST = TEST_BASE + "hosted_app.manifest";
 
 const PACKAGED_APP_DIR_PATH = getTestFilePath(".");
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
 });
 
 function addTab(url, targetWindow = window) {
   info("Adding tab: " + url);
 
   let deferred = promise.defer();
   let targetBrowser = targetWindow.gBrowser;
 
--- a/browser/devtools/canvasdebugger/canvasdebugger.js
+++ b/browser/devtools/canvasdebugger/canvasdebugger.js
@@ -5,45 +5,42 @@
 
 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 Cu.import("resource://gre/modules/devtools/Console.jsm");
-Cu.import("resource:///modules/devtools/gDevTools.jsm");
 
 const devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
 const { require } = devtools;
 const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
 const EventEmitter = require("devtools/toolkit/event-emitter");
 const { CallWatcherFront } = require("devtools/server/actors/call-watcher");
 const { CanvasFront } = require("devtools/server/actors/canvas");
+const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
 
 const Telemetry = require("devtools/shared/telemetry");
 const telemetry = new Telemetry();
 
-const CANVAS_ACTOR_RECORDING_ATTEMPT = gDevTools.testing ? 500 : 5000;
+const CANVAS_ACTOR_RECORDING_ATTEMPT = DevToolsUtils.testing ? 500 : 5000;
 
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
   "resource://gre/modules/Task.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
   "resource://gre/modules/PluralForm.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
   "resource://gre/modules/FileUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
   "resource://gre/modules/NetUtil.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "DevToolsUtils",
-  "resource://gre/modules/devtools/DevToolsUtils.jsm");
-
 XPCOMUtils.defineLazyGetter(this, "NetworkHelper", function() {
   return require("devtools/toolkit/webconsole/network-helper");
 });
 
 // The panel's window global is an EventEmitter firing the following events:
 const EVENTS = {
   // When the UI is reset from tab navigation.
   UI_RESET: "CanvasDebugger:UIReset",
--- a/browser/devtools/canvasdebugger/test/head.js
+++ b/browser/devtools/canvasdebugger/test/head.js
@@ -16,16 +16,17 @@ let { Task } = Cu.import("resource://gre
 let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
 let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
 let { CallWatcherFront } = devtools.require("devtools/server/actors/call-watcher");
 let { CanvasFront } = devtools.require("devtools/server/actors/canvas");
 let { setTimeout } = devtools.require("sdk/timers");
+let DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 let TiltGL = devtools.require("devtools/tilt/tilt-gl");
 let TargetFactory = devtools.TargetFactory;
 let Toolbox = devtools.Toolbox;
 let mm = null
 
 const FRAME_SCRIPT_UTILS_URL = "chrome://browser/content/devtools/frame-script-utils.js";
 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/canvasdebugger/test/";
 const SET_TIMEOUT_URL = EXAMPLE_URL + "doc_settimeout.html";
@@ -39,20 +40,21 @@ const WEBGL_ENUM_URL = EXAMPLE_URL + "do
 const WEBGL_BINDINGS_URL = EXAMPLE_URL + "doc_webgl-bindings.html";
 const RAF_BEGIN_URL = EXAMPLE_URL + "doc_raf-begin.html";
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 let gToolEnabled = Services.prefs.getBoolPref("devtools.canvasdebugger.enabled");
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 
 registerCleanupFunction(() => {
   info("finish() was called, cleaning up...");
+  DevToolsUtils.testing = false;
   Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
   Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", gToolEnabled);
 
   // Some of yhese tests use a lot of memory due to GL contexts, so force a GC
   // to help fragmentation.
   info("Forcing GC after canvas debugger test.");
   Cu.forceGC();
 });
--- a/browser/devtools/commandline/test/head.js
+++ b/browser/devtools/commandline/test/head.js
@@ -1,26 +1,28 @@
 /* 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/. */
 
 const TEST_BASE_HTTP = "http://example.com/browser/browser/devtools/commandline/test/";
 const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/commandline/test/";
 
-var require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
-var console = require("resource://gre/modules/devtools/Console.jsm").console;
+let { require } =
+  Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
+let console = require("resource://gre/modules/devtools/Console.jsm").console;
+let DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
 
 // Import the GCLI test helper
 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 Services.scriptloader.loadSubScript(testDir + "/helpers.js", this);
 Services.scriptloader.loadSubScript(testDir + "/mockCommands.js", this);
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
 });
 
 function whenDelayedStartupFinished(aWindow, aCallback) {
   Services.obs.addObserver(function observer(aSubject, aTopic) {
     if (aWindow == aSubject) {
       Services.obs.removeObserver(observer, aTopic);
       executeSoon(aCallback);
     }
--- a/browser/devtools/debugger/test/head.js
+++ b/browser/devtools/debugger/test/head.js
@@ -26,19 +26,19 @@ let { AddonManager } = Cu.import("resour
 let EventEmitter = require("devtools/toolkit/event-emitter");
 const { promiseInvoke } = require("devtools/async-utils");
 let TargetFactory = devtools.TargetFactory;
 let Toolbox = devtools.Toolbox;
 
 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/debugger/test/";
 const FRAME_SCRIPT_URL = getRootDirectory(gTestPath) + "code_frame-script.js";
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
 });
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 registerCleanupFunction(function* () {
   info("finish() was called, cleaning up...");
   Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
--- a/browser/devtools/fontinspector/test/head.js
+++ b/browser/devtools/fontinspector/test/head.js
@@ -7,25 +7,26 @@
 const Cu = Components.utils;
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 
 const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let TargetFactory = devtools.TargetFactory;
+const DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 
 const BASE_URI = "http://mochi.test:8888/browser/browser/devtools/fontinspector/test/"
 
 // All test are asynchronous
 waitForExplicitFinish();
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
 });
 
 registerCleanupFunction(function*() {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   yield gDevTools.closeToolbox(target);
 
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -45,56 +45,24 @@ this.DevTools = function DevTools() {
   this._themes = new Map();    // Map<themeId, theme>
   this._toolboxes = new Map(); // Map<target, toolbox>
   this._telemetry = new Telemetry();
 
   // destroy() is an observer's handler so we need to preserve context.
   this.destroy = this.destroy.bind(this);
   this._teardown = this._teardown.bind(this);
 
-  this._testing = false;
-
   EventEmitter.decorate(this);
 
   Services.obs.addObserver(this._teardown, "devtools-unloaded", false);
   Services.obs.addObserver(this.destroy, "quit-application", false);
 };
 
 DevTools.prototype = {
   /**
-   * When the testing flag is set we take appropriate action to prevent race
-   * conditions in our testing environment. This means setting
-   * dom.send_after_paint_to_content to false to prevent infinite MozAfterPaint
-   * loops and not autohiding the highlighter.
-   */
-  get testing() {
-    return this._testing;
-  },
-
-  set testing(state) {
-    let oldState = this._testing;
-    this._testing = state;
-
-    if (state !== oldState) {
-      if (state) {
-        this._savedSendAfterPaintToContentPref =
-          Services.prefs.getBoolPref("dom.send_after_paint_to_content");
-
-        // dom.send_after_paint_to_content is set to true (non-default) in
-        // testing/profiles/prefs_general.js so lets set it to the same as it is
-        // in a default browser profile for the duration of the test.
-        Services.prefs.setBoolPref("dom.send_after_paint_to_content", false);
-      } else {
-        Services.prefs.setBoolPref("dom.send_after_paint_to_content",
-                                   this._savedSendAfterPaintToContentPref);
-      }
-    }
-  },
-
-  /**
    * Register a new developer tool.
    *
    * A definition is a light object that holds different information about a
    * developer tool. This object is not supposed to have any operational code.
    * See it as a "manifest".
    * The only actual code lives in the build() function, which will be used to
    * start an instance of this tool.
    *
--- a/browser/devtools/framework/test/browser_ignore_toolbox_network_requests.js
+++ b/browser/devtools/framework/test/browser_ignore_toolbox_network_requests.js
@@ -4,27 +4,27 @@
 
 // Test that network requests originating from the toolbox don't get recorded in
 // the network panel.
 
 add_task(function*() {
   // TODO: This test tries to verify the normal behavior of the netmonitor and
   // therefore needs to avoid the explicit check for tests. Bug 1167188 will
   // allow us to remove this workaround.
-  let isTesting = gDevTools.testing;
-  gDevTools.testing = false;
+  let isTesting = DevToolsUtils.testing;
+  DevToolsUtils.testing = false;
 
   let tab = yield addTab(URL_ROOT + "doc_viewsource.html");
   let target = TargetFactory.forTab(tab);
   let toolbox = yield gDevTools.showToolbox(target, "styleeditor");
   let panel = toolbox.getPanel("styleeditor");
 
   is(panel.UI.editors.length, 1, "correct number of editors opened");
 
   let monitor = yield toolbox.selectTool("netmonitor");
   let { RequestsMenu } = monitor.panelWin.NetMonitorView;
   is(RequestsMenu.itemCount, 0, "No network requests appear in the network panel");
 
   yield gDevTools.closeToolbox(target);
   tab = target = toolbox = panel = null;
   gBrowser.removeCurrentTab();
-  gDevTools.testing = isTesting;
+  DevToolsUtils.testing = isTesting;
 });
--- a/browser/devtools/framework/test/shared-head.js
+++ b/browser/devtools/framework/test/shared-head.js
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // This shared-head.js file is used for multiple directories in devtools.
 const {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 const {ScratchpadManager} = Cu.import("resource:///modules/devtools/scratchpad-manager.jsm", {});
 const {TargetFactory} = devtools;
+const DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 
 const TEST_DIR = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 const CHROME_URL_ROOT = TEST_DIR + "/";
 const URL_ROOT = CHROME_URL_ROOT.replace("chrome://mochitests/content/", "http://example.com/");
 
 // All test are asynchronous
 waitForExplicitFinish();
 
@@ -24,19 +25,19 @@ function getFrameScript() {
   let frameURL = "chrome://browser/content/devtools/frame-script-utils.js";
   mm.loadFrameScript(frameURL, false);
   SimpleTest.registerCleanupFunction(() => {
     mm = null;
   });
   return mm;
 }
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
   Services.prefs.clearUserPref("devtools.dump.emit");
   Services.prefs.clearUserPref("devtools.toolbox.host");
   Services.prefs.clearUserPref("devtools.toolbox.previousHost");
 });
 
 registerCleanupFunction(function cleanup() {
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
--- a/browser/devtools/framework/toolbox-highlighter-utils.js
+++ b/browser/devtools/framework/toolbox-highlighter-utils.js
@@ -2,17 +2,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/. */
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 const {Promise: promise} = require("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource:///modules/devtools/gDevTools.jsm");
+const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
 
 /**
  * Client-side highlighter shared module.
  * To be used by toolbox panels that need to highlight DOM elements.
  *
  * Highlighting and selecting elements is common enough that it needs to be at
  * toolbox level, accessible by any panel that needs it.
  * That's why the toolbox is the one that initializes the inspector and
@@ -239,25 +239,25 @@ exports.getHighlighterUtils = function(t
   let gripToNodeFront = exported.gripToNodeFront = requireInspector(
   function*(grip) {
     return yield toolbox.walker.getNodeActorFromObjectActor(grip.actor);
   });
 
   /**
    * Hide the highlighter.
    * @param {Boolean} forceHide Only really matters in test mode (when
-   * gDevTools.testing is true). In test mode, hovering over several nodes in
-   * the markup view doesn't hide/show the highlighter to ease testing. The
+   * DevToolsUtils.testing is true). In test mode, hovering over several nodes
+   * in the markup view doesn't hide/show the highlighter to ease testing. The
    * highlighter stays visible at all times, except when the mouse leaves the
    * markup view, which is when this param is passed to true
    * @return a promise that resolves when the highlighter is hidden
    */
   let unhighlight = exported.unhighlight = Task.async(
   function*(forceHide=false) {
-    forceHide = forceHide || !gDevTools.testing;
+    forceHide = forceHide || !DevToolsUtils.testing;
 
     // Note that if isRemoteHighlightable is true, there's no need to hide the
     // highlighter as the walker uses setTimeout to hide it after some time
     if (forceHide && toolbox.highlighter && isRemoteHighlightable()) {
       yield toolbox.highlighter.hideBoxModel();
     }
 
     toolbox.emit("node-unhighlight");
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.js
@@ -413,17 +413,17 @@ Toolbox.prototype = {
       // used to intercept console.profile calls before the performance tools are open.
       let profilerReady = this.initPerformance();
 
       // However, while testing, we must wait for the performance connection to
       // finish, as most tests shut down without waiting for a toolbox
       // destruction event, resulting in the shared profiler connection being
       // opened and closed outside of the test that originally opened the
       // toolbox.
-      if (gDevTools.testing) {
+      if (DevToolsUtils.testing) {
         yield profilerReady;
       }
 
       this.emit("ready");
     }.bind(this)).then(null, console.error.bind(console));
   },
 
   _pingTelemetry: function() {
@@ -1724,17 +1724,17 @@ Toolbox.prototype = {
           {showAllAnonymousContent: Services.prefs.getBoolPref("devtools.inspector.showAllAnonymousContent")}
         );
         this._selection = new Selection(this._walker);
 
         if (this.highlighterUtils.isRemoteHighlightable()) {
           this.walker.on("highlighter-ready", this._highlighterReady);
           this.walker.on("highlighter-hide", this._highlighterHidden);
 
-          let autohide = !gDevTools.testing;
+          let autohide = !DevToolsUtils.testing;
           this._highlighter = yield this._inspector.getHighlighter(autohide);
         }
       }.bind(this));
     }
     return this._initInspector;
   },
 
   /**
@@ -1909,17 +1909,17 @@ Toolbox.prototype = {
 
       // Free _host after the call to destroyed in order to let a chance
       // to destroyed listeners to still query toolbox attributes
       this._host = null;
       this._toolPanels.clear();
 
       // Force GC to prevent long GC pauses when running tests and to free up
       // memory in general when the toolbox is closed.
-      if (gDevTools.testing) {
+      if (DevToolsUtils.testing) {
         win.QueryInterface(Ci.nsIInterfaceRequestor)
            .getInterface(Ci.nsIDOMWindowUtils)
            .garbageCollect();
       }
     }).then(null, console.error);
 
     let leakCheckObserver = ({wrappedJSObject: barrier}) => {
       // Make the leak detector wait until this toolbox is properly destroyed.
--- a/browser/devtools/inspector/test/head.js
+++ b/browser/devtools/inspector/test/head.js
@@ -21,24 +21,25 @@ const ROOT_TEST_DIR = getRootDirectory(g
 const FRAME_SCRIPT_URL = ROOT_TEST_DIR + "doc_frame_script.js";
 const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 
 // All test are asynchronous
 waitForExplicitFinish();
 
 let {TargetFactory, require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
 let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
+let DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
 
 // Import the GCLI test helper
 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
 });
 
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.dump.emit");
   Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
 });
 
 registerCleanupFunction(function*() {
--- a/browser/devtools/layoutview/test/head.js
+++ b/browser/devtools/layoutview/test/head.js
@@ -5,30 +5,31 @@
 "use strict";
 
 const Cu = Components.utils;
 let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let TargetFactory = devtools.TargetFactory;
 let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 let {console} = Components.utils.import("resource://gre/modules/devtools/Console.jsm", {});
+let DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 
 // All test are asynchronous
 waitForExplicitFinish();
 
 const TEST_URL_ROOT = "http://example.com/browser/browser/devtools/layoutview/test/";
 
 // Uncomment this pref to dump all devtools emitted events to the console.
 // Services.prefs.setBoolPref("devtools.dump.emit", true);
 
 // Services.prefs.setBoolPref("devtools.debugger.log", true);
 
-// Set the testing flag on gDevTools and reset it when the test ends
-gDevTools.testing = true;
-registerCleanupFunction(() => gDevTools.testing = false);
+// Set the testing flag on DevToolsUtils and reset it when the test ends
+DevToolsUtils.testing = true;
+registerCleanupFunction(() => DevToolsUtils.testing = false);
 
 // Clean-up all prefs that might have been changed during a test run
 // (safer here because if the test fails, then the pref is never reverted)
 Services.prefs.setIntPref("devtools.toolbox.footer.height", 350);
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.dump.emit");
   Services.prefs.clearUserPref("devtools.debugger.log");
   Services.prefs.clearUserPref("devtools.toolbox.footer.height");
--- a/browser/devtools/markupview/test/head.js
+++ b/browser/devtools/markupview/test/head.js
@@ -6,31 +6,31 @@ const Cu = Components.utils;
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let TargetFactory = devtools.TargetFactory;
 let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
 let promise = devtools.require("resource://gre/modules/Promise.jsm").Promise;
 let {getInplaceEditorForSpan: inplaceEditor} = devtools.require("devtools/shared/inplace-editor");
 let clipboard = devtools.require("sdk/clipboard");
 let {setTimeout, clearTimeout} = devtools.require("sdk/timers");
 let {promiseInvoke} = devtools.require("devtools/async-utils");
-
+let DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 
 // All test are asynchronous
 waitForExplicitFinish();
 
 // If a test times out we want to see the complete log and not just the last few
 // lines.
 SimpleTest.requestCompleteLog();
 
 // Uncomment this pref to dump all devtools emitted events to the console.
 // Services.prefs.setBoolPref("devtools.dump.emit", true);
 
-// Set the testing flag on gDevTools and reset it when the test ends
-gDevTools.testing = true;
-registerCleanupFunction(() => gDevTools.testing = false);
+// Set the testing flag on DevToolsUtils and reset it when the test ends
+DevToolsUtils.testing = true;
+registerCleanupFunction(() => DevToolsUtils.testing = false);
 
 // Clear preferences that may be set during the course of tests.
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.inspector.htmlPanelOpen");
   Services.prefs.clearUserPref("devtools.inspector.sidebarOpen");
   Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
   Services.prefs.clearUserPref("devtools.dump.emit");
   Services.prefs.clearUserPref("devtools.markup.pagesize");
--- a/browser/devtools/netmonitor/netmonitor-controller.js
+++ b/browser/devtools/netmonitor/netmonitor-controller.js
@@ -118,35 +118,33 @@ Cu.import("resource:///modules/devtools/
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
 const EventEmitter = require("devtools/toolkit/event-emitter");
 const Editor = require("devtools/sourceeditor/editor");
 const {Tooltip} = require("devtools/shared/widgets/Tooltip");
 const {ToolSidebar} = require("devtools/framework/sidebar");
+const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Chart",
   "resource:///modules/devtools/Chart.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Curl",
   "resource:///modules/devtools/Curl.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "CurlUtils",
   "resource:///modules/devtools/Curl.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
   "resource://gre/modules/Task.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
   "resource://gre/modules/PluralForm.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "DevToolsUtils",
-  "resource://gre/modules/devtools/DevToolsUtils.jsm");
-
 XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
   "@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
 
 XPCOMUtils.defineLazyServiceGetter(this, "DOMParser",
   "@mozilla.org/xmlextras/domparser;1", "nsIDOMParser");
 
 Object.defineProperty(this, "NetworkHelper", {
   get: function() {
@@ -795,17 +793,17 @@ function whenDataAvailable(aDataStore, a
 };
 
 const WDA_DEFAULT_VERIFY_INTERVAL = 50; // ms
 
 // Use longer timeout during testing as the tests need this process to succeed
 // and two seconds is quite short on slow debug builds. The timeout here should
 // be at least equal to the general mochitest timeout of 45 seconds so that this
 // never gets hit during testing.
-const WDA_DEFAULT_GIVE_UP_TIMEOUT = gDevTools.testing ? 45000 : 2000; // ms
+const WDA_DEFAULT_GIVE_UP_TIMEOUT = DevToolsUtils.testing ? 45000 : 2000; // ms
 
 /**
  * Helper method for debugging.
  * @param string
  */
 function dumpn(str) {
   if (wantLogging) {
     dump("NET-FRONTEND: " + str + "\n");
--- a/browser/devtools/netmonitor/netmonitor-view.js
+++ b/browser/devtools/netmonitor/netmonitor-view.js
@@ -2,19 +2,16 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 
-XPCOMUtils.defineLazyModuleGetter(this, "DevToolsUtils",
-  "resource://gre/modules/devtools/DevToolsUtils.jsm");
-
 XPCOMUtils.defineLazyGetter(this, "HarExporter", function() {
   return devtools.require("devtools/netmonitor/har/har-exporter.js").HarExporter;
 });
 
 XPCOMUtils.defineLazyGetter(this, "NetworkHelper", function() {
   return devtools.require("devtools/toolkit/webconsole/network-helper");
 });
 
--- a/browser/devtools/netmonitor/test/head.js
+++ b/browser/devtools/netmonitor/test/head.js
@@ -6,16 +6,17 @@ const { classes: Cc, interfaces: Ci, uti
 
 let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
 let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
 let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let { CurlUtils } = Cu.import("resource:///modules/devtools/Curl.jsm", {});
 let NetworkHelper = devtools.require("devtools/toolkit/webconsole/network-helper");
+let DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 let TargetFactory = devtools.TargetFactory;
 let Toolbox = devtools.Toolbox;
 
 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/netmonitor/test/";
 
 const API_CALLS_URL = EXAMPLE_URL + "html_api-calls-test-page.html";
 const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
 const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
@@ -49,19 +50,19 @@ const SORTING_SJS = EXAMPLE_URL + "sjs_s
 const HTTPS_REDIRECT_SJS = EXAMPLE_URL + "sjs_https-redirect-test-server.sjs";
 const CORS_SJS_PATH = "/browser/browser/devtools/netmonitor/test/sjs_cors-test-server.sjs";
 
 const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
 const TEST_IMAGE_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
 
 const FRAME_SCRIPT_UTILS_URL = "chrome://browser/content/devtools/frame-script-utils.js"
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
 });
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 const gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
 // To enable logging for try runs, just set the pref to true.
 Services.prefs.setBoolPref("devtools.debugger.log", false);
--- a/browser/devtools/performance/modules/logic/front.js
+++ b/browser/devtools/performance/modules/logic/front.js
@@ -436,17 +436,17 @@ PerformanceFront.prototype = {
     this.emit(eventName, ...args);
   },
 
   /**
    * Helper method to interface with the underlying actors directly.
    * Used only in tests.
    */
   _request: function (actorName, method, ...args) {
-    if (!gDevTools.testing) {
+    if (!DevToolsUtils.testing) {
       throw new Error("PerformanceFront._request may only be used in tests.");
     }
     let actor = this[`_${actorName}`];
     return actor[method].apply(actor, args);
   },
 
   toString: () => "[object PerformanceFront]"
 };
--- a/browser/devtools/performance/performance-controller.js
+++ b/browser/devtools/performance/performance-controller.js
@@ -527,17 +527,17 @@ let PerformanceController = {
    *
    * @return {object}
    */
   getMultiprocessStatus: function () {
     // If testing, set both supported and enabled to true so we
     // have realtime rendering tests in non-e10s. This function is
     // overridden wholesale in tests when we want to test multiprocess support
     // specifically.
-    if (gDevTools.testing) {
+    if (DevToolsUtils.testing) {
       return { supported: true, enabled: true };
     }
     let supported = system.constants.E10S_TESTING_ONLY;
     // This is only checked on tool startup -- requires a restart if
     // e10s subsequently enabled.
     let enabled = this._e10s;
     return { supported, enabled };
   },
--- a/browser/devtools/performance/test/head.js
+++ b/browser/devtools/performance/test/head.js
@@ -40,17 +40,17 @@ const INVERT_PREF = "devtools.performanc
 const INVERT_FLAME_PREF = "devtools.performance.ui.invert-flame-graph";
 const FLATTEN_PREF = "devtools.performance.ui.flatten-tree-recursion";
 const JIT_PREF = "devtools.performance.ui.enable-jit-optimizations";
 const EXPERIMENTAL_PREF = "devtools.performance.ui.experimental";
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 
 let DEFAULT_PREFS = [
   "devtools.debugger.log",
   "devtools.performance.ui.invert-call-tree",
   "devtools.performance.ui.flatten-tree-recursion",
   "devtools.performance.ui.show-platform-data",
   "devtools.performance.ui.show-idle-blocks",
   "devtools.performance.ui.enable-memory",
@@ -79,17 +79,17 @@ Services.prefs.setBoolPref("devtools.deb
  * the tool. Must be called after initializing (once we have a tab).
  */
 function loadFrameScripts () {
   mm = gBrowser.selectedBrowser.messageManager;
   mm.loadFrameScript(FRAME_SCRIPT_UTILS_URL, false);
 }
 
 registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
   info("finish() was called, cleaning up...");
 
   // Rollback any pref changes
   Object.keys(DEFAULT_PREFS).forEach(pref => {
     Preferences.set(pref, DEFAULT_PREFS[pref]);
   });
 
   Cu.forceGC();
--- a/browser/devtools/projecteditor/test/head.js
+++ b/browser/devtools/projecteditor/test/head.js
@@ -5,31 +5,32 @@
 const Cu = Components.utils;
 const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 const TargetFactory = devtools.TargetFactory;
 const {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
 const promise = devtools.require("sdk/core/promise");
 const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
 const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {});
 const ProjectEditor = devtools.require("projecteditor/projecteditor");
+const DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 
 const TEST_URL_ROOT = "http://mochi.test:8888/browser/browser/devtools/projecteditor/test/";
 const SAMPLE_WEBAPP_URL = TEST_URL_ROOT + "/helper_homepage.html";
 let TEMP_PATH;
 let TEMP_FOLDER_NAME = "ProjectEditor" + (new Date().getTime());
 
 // All test are asynchronous
 waitForExplicitFinish();
 
 // Uncomment this pref to dump all devtools emitted events to the console.
 // Services.prefs.setBoolPref("devtools.dump.emit", true);
 
-// Set the testing flag on gDevTools and reset it when the test ends
-gDevTools.testing = true;
-registerCleanupFunction(() => gDevTools.testing = false);
+// Set the testing flag on DevToolsUtils and reset it when the test ends
+DevToolsUtils.testing = true;
+registerCleanupFunction(() => DevToolsUtils.testing = false);
 
 // Clear preferences that may be set during the course of tests.
 registerCleanupFunction(() => {
   // Services.prefs.clearUserPref("devtools.dump.emit");
   TEMP_PATH = null;
   TEMP_FOLDER_NAME = null;
 });
 
@@ -327,9 +328,8 @@ function onPopupShow(menu) {
 function onPopupHidden(menu) {
   let defer = promise.defer();
   menu.addEventListener("popuphidden", function onpopuphidden() {
     menu.removeEventListener("popuphidden", onpopuphidden);
     defer.resolve();
   });
   return defer.promise;
 }
-
--- a/browser/devtools/responsivedesign/test/head.js
+++ b/browser/devtools/responsivedesign/test/head.js
@@ -2,24 +2,25 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 
 let {devtools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 let TargetFactory = devtools.TargetFactory;
+let DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 
 // Import the GCLI test helper
 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
 });
 
 /**
  * Open the toolbox, with the inspector tool visible.
  * @return a promise that resolves when the inspector is ready
  */
 let openInspector = Task.async(function*() {
   info("Opening the inspector");
--- a/browser/devtools/scratchpad/test/head.js
+++ b/browser/devtools/scratchpad/test/head.js
@@ -9,19 +9,19 @@ const {FileUtils} = Cu.import("resource:
 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 const {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
 const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
 const {DevToolsUtils} = Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm", {});
 const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
 
 let gScratchpadWindow; // Reference to the Scratchpad chrome window object
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
 });
 
 /**
  * Open a Scratchpad window.
  *
  * @param function aReadyCallback
  *        Optional. The function you want invoked when the Scratchpad instance
  *        is ready.
--- a/browser/devtools/shadereditor/test/head.js
+++ b/browser/devtools/shadereditor/test/head.js
@@ -13,16 +13,17 @@ Services.prefs.setBoolPref("devtools.deb
 let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
 let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
 let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
 
 let { WebGLFront } = devtools.require("devtools/server/actors/webgl");
+let DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 let TiltGL = devtools.require("devtools/tilt/tilt-gl");
 let TargetFactory = devtools.TargetFactory;
 let Toolbox = devtools.Toolbox;
 let mm = null;
 
 const FRAME_SCRIPT_UTILS_URL = "chrome://browser/content/devtools/frame-script-utils.js"
 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/shadereditor/test/";
 const SIMPLE_CANVAS_URL = EXAMPLE_URL + "doc_simple-canvas.html";
@@ -31,20 +32,21 @@ const MULTIPLE_CONTEXTS_URL = EXAMPLE_UR
 const OVERLAPPING_GEOMETRY_CANVAS_URL = EXAMPLE_URL + "doc_overlapping-geometry.html";
 const BLENDED_GEOMETRY_CANVAS_URL = EXAMPLE_URL + "doc_blended-geometry.html";
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 let gToolEnabled = Services.prefs.getBoolPref("devtools.shadereditor.enabled");
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 
 registerCleanupFunction(() => {
   info("finish() was called, cleaning up...");
+  DevToolsUtils.testing = false;
   Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
   Services.prefs.setBoolPref("devtools.shadereditor.enabled", gToolEnabled);
 
   // These tests use a lot of memory due to GL contexts, so force a GC to help
   // fragmentation.
   info("Forcing GC after shadereditor test.");
   Cu.forceGC();
 });
--- a/browser/devtools/shared/test/head.js
+++ b/browser/devtools/shared/test/head.js
@@ -4,20 +4,21 @@
 
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let {TargetFactory, require} = devtools;
 let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
 let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 const {DOMHelpers} = Cu.import("resource:///modules/devtools/DOMHelpers.jsm", {});
 const {Hosts} = require("devtools/framework/toolbox-hosts");
 const {defer} = require("sdk/core/promise");
+const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
 });
 
 const TEST_URI_ROOT = "http://example.com/browser/browser/devtools/shared/test/";
 const OPTIONS_VIEW_URL = TEST_URI_ROOT + "doc_options-view.xul";
 
 /**
  * Open a new tab at a URL and call a callback on load
  */
--- a/browser/devtools/sourceeditor/test/head.js
+++ b/browser/devtools/sourceeditor/test/head.js
@@ -3,20 +3,21 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 const { require } = devtools;
 const Editor  = require("devtools/sourceeditor/editor");
 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
+const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
 });
 
 /**
  * Open a new tab at a URL and call a callback on load
  */
 function addTab(aURL, aCallback) {
   waitForExplicitFinish();
 
--- a/browser/devtools/storage/test/head.js
+++ b/browser/devtools/storage/test/head.js
@@ -16,28 +16,29 @@ const TargetFactory = devtools.TargetFac
 const SPLIT_CONSOLE_PREF = "devtools.toolbox.splitconsoleEnabled";
 const STORAGE_PREF = "devtools.storage.enabled";
 const PATH = "browser/browser/devtools/storage/test/";
 const MAIN_DOMAIN = "http://test1.example.org/" + PATH;
 const ALT_DOMAIN = "http://sectest1.example.org/" + PATH;
 const ALT_DOMAIN_SECURED = "https://sectest1.example.org:443/" + PATH;
 
 let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
+let DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
 
 waitForExplicitFinish();
 
 let gToolbox, gPanelWindow, gWindow, gUI;
 
 Services.prefs.setBoolPref(STORAGE_PREF, true);
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 registerCleanupFunction(() => {
   gToolbox = gPanelWindow = gWindow = gUI = null;
   Services.prefs.clearUserPref(STORAGE_PREF);
   Services.prefs.clearUserPref(SPLIT_CONSOLE_PREF);
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
   }
 });
 
 /**
  * Add a new test tab in the browser and load the given url.
  *
--- a/browser/devtools/styleeditor/test/browser_styleeditor_fetch-from-cache.js
+++ b/browser/devtools/styleeditor/test/browser_styleeditor_fetch-from-cache.js
@@ -4,19 +4,16 @@
 "use strict";
 
 // A test to ensure Style Editor doesn't bybass cache when loading style sheet
 // contents (bug 978688).
 
 const TEST_URL = TEST_BASE_HTTP + "doc_uncached.html";
 
 add_task(function*() {
-  let isTesting = gDevTools.testing;
-  gDevTools.testing = true;
-
   info("Opening netmonitor");
   let tab = yield addTab("about:blank");
   let target = TargetFactory.forTab(tab);
   let toolbox = yield gDevTools.showToolbox(target, "netmonitor");
   let netmonitor = toolbox.getPanel("netmonitor");
   netmonitor._view.RequestsMenu.lazyUpdate = false;
 
   info("Navigating to test page");
@@ -24,22 +21,20 @@ add_task(function*() {
 
   info("Opening Style Editor");
   let styleeditor = yield toolbox.selectTool("styleeditor");
 
   info("Waiting for the source to be loaded.");
   yield styleeditor.UI.editors[0].getSourceEditor();
 
   info("Checking Netmonitor contents.");
-  let requestsForCss = 0;
   let attachments = [];
   for (let item of netmonitor._view.RequestsMenu) {
     if (item.attachment.url.endsWith("doc_uncached.css")) {
       attachments.push(item.attachment);
     }
   }
 
   is(attachments.length, 2,
      "Got two requests for doc_uncached.css after Style Editor was loaded.");
   ok(attachments[1].fromCache,
      "Second request was loaded from browser cache");
-  gDevTools.testing = isTesting;
 });
--- a/browser/devtools/styleeditor/test/head.js
+++ b/browser/devtools/styleeditor/test/head.js
@@ -6,26 +6,25 @@ const TEST_BASE = "chrome://mochitests/c
 const TEST_BASE_HTTP = "http://example.com/browser/browser/devtools/styleeditor/test/";
 const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/styleeditor/test/";
 const TEST_HOST = 'mochi.test:8888';
 
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let TargetFactory = devtools.TargetFactory;
 let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
 let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
-
-
+let DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 
 // Import the GCLI test helper
 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
 });
 
 /**
  * Add a new test tab in the browser and load the given url.
  * @param {String} url The url to be loaded in the new tab
  * @param {Window} win The window to add the tab to (default: current window).
  * @return a promise that resolves to the tab object when the url is loaded
  */
--- a/browser/devtools/styleinspector/test/head.js
+++ b/browser/devtools/styleinspector/test/head.js
@@ -6,16 +6,17 @@
 
 const Cu = Components.utils;
 let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let TargetFactory = devtools.TargetFactory;
 let {CssHtmlTree} = devtools.require("devtools/styleinspector/computed-view");
 let {CssRuleView, _ElementStyle} = devtools.require("devtools/styleinspector/rule-view");
 let {CssLogic, CssSelector} = devtools.require("devtools/styleinspector/css-logic");
+let DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 let {editableField, getInplaceEditorForSpan: inplaceEditor} = devtools.require("devtools/shared/inplace-editor");
 let {console} = Components.utils.import("resource://gre/modules/devtools/Console.jsm", {});
 
 // All tests are asynchronous
 waitForExplicitFinish();
 
 const TEST_URL_ROOT = "http://example.com/browser/browser/devtools/styleinspector/test/";
@@ -32,18 +33,18 @@ registerCleanupFunction(function*() {
     gBrowser.removeCurrentTab();
   }
 });
 
 // Uncomment this pref to dump all devtools emitted events to the console.
 // Services.prefs.setBoolPref("devtools.dump.emit", true);
 
 // Set the testing flag on gDevTools and reset it when the test ends
-gDevTools.testing = true;
-registerCleanupFunction(() => gDevTools.testing = false);
+DevToolsUtils.testing = true;
+registerCleanupFunction(() => DevToolsUtils.testing = false);
 
 // Clean-up all prefs that might have been changed during a test run
 // (safer here because if the test fails, then the pref is never reverted)
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
   Services.prefs.clearUserPref("devtools.dump.emit");
   Services.prefs.clearUserPref("devtools.defaultColorUnit");
 });
--- a/browser/devtools/tilt/test/head.js
+++ b/browser/devtools/tilt/test/head.js
@@ -3,16 +3,17 @@
 "use strict";
 
 let {devtools} = Components.utils.import("resource://gre/modules/devtools/Loader.jsm", {});
 let TiltManager = devtools.require("devtools/tilt/tilt").TiltManager;
 let TiltGL = devtools.require("devtools/tilt/tilt-gl");
 let {EPSILON, TiltMath, vec3, mat3, mat4, quat4} = devtools.require("devtools/tilt/tilt-math");
 let TiltUtils = devtools.require("devtools/tilt/tilt-utils");
 let {TiltVisualizer} = devtools.require("devtools/tilt/tilt-visualizer");
+let DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 
 let tempScope = {};
 Components.utils.import("resource://gre/modules/devtools/LayoutHelpers.jsm", tempScope);
 let LayoutHelpers = tempScope.LayoutHelpers;
 
 const DEFAULT_HTML = "data:text/html," +
   "<DOCTYPE html>" +
   "<html>" +
@@ -50,19 +51,19 @@ const DESTROYED = Tilt.NOTIFICATIONS.DES
 const SHOWN = Tilt.NOTIFICATIONS.SHOWN;
 const HIDDEN = Tilt.NOTIFICATIONS.HIDDEN;
 const HIGHLIGHTING = Tilt.NOTIFICATIONS.HIGHLIGHTING;
 const UNHIGHLIGHTING = Tilt.NOTIFICATIONS.UNHIGHLIGHTING;
 const NODE_REMOVED = Tilt.NOTIFICATIONS.NODE_REMOVED;
 
 const TILT_ENABLED = Services.prefs.getBoolPref("devtools.tilt.enabled");
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 SimpleTest.registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
 });
 
 function isTiltEnabled() {
   info("Apparently, Tilt is" + (TILT_ENABLED ? "" : " not") + " enabled.");
   return TILT_ENABLED;
 }
 
 function isWebGLSupported() {
--- a/browser/devtools/webaudioeditor/includes.js
+++ b/browser/devtools/webaudioeditor/includes.js
@@ -18,16 +18,17 @@ let { EventTarget } = require("sdk/event
 
 const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
 const { Class } = require("sdk/core/heritage");
 const EventEmitter = require("devtools/toolkit/event-emitter");
 const STRINGS_URI = "chrome://browser/locale/devtools/webaudioeditor.properties"
 const L10N = new ViewHelpers.L10N(STRINGS_URI);
 const Telemetry = require("devtools/shared/telemetry");
 const telemetry = new Telemetry();
+const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
 
 devtools.lazyRequireGetter(this, "LineGraphWidget",
   "devtools/shared/widgets/LineGraphWidget");
 
 // `AUDIO_NODE_DEFINITION` defined in the controller's initialization,
 // which describes all the properties of an AudioNode
 let AUDIO_NODE_DEFINITION;
 
--- a/browser/devtools/webaudioeditor/test/head.js
+++ b/browser/devtools/webaudioeditor/test/head.js
@@ -14,16 +14,17 @@ Services.prefs.setBoolPref("devtools.deb
 let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
 let { Promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
 let { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
 
 let { WebAudioFront } = devtools.require("devtools/server/actors/webaudio");
+let DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
 let TargetFactory = devtools.TargetFactory;
 let audioNodes = devtools.require("devtools/server/actors/utils/audionodes.json");
 let mm = null;
 
 const FRAME_SCRIPT_UTILS_URL = "chrome://browser/content/devtools/frame-script-utils.js";
 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/webaudioeditor/test/";
 const SIMPLE_CONTEXT_URL = EXAMPLE_URL + "doc_simple-context.html";
 const COMPLEX_CONTEXT_URL = EXAMPLE_URL + "doc_complex-context.html";
@@ -36,20 +37,20 @@ const CONNECT_MULTI_PARAM_URL = EXAMPLE_
 const IFRAME_CONTEXT_URL = EXAMPLE_URL + "doc_iframe-context.html";
 const AUTOMATION_URL = EXAMPLE_URL + "doc_automation.html";
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 let gToolEnabled = Services.prefs.getBoolPref("devtools.webaudioeditor.enabled");
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 
 registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
   info("finish() was called, cleaning up...");
   Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
   Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", gToolEnabled);
   Cu.forceGC();
 });
 
 /**
  * Call manually in tests that use frame script utils after initializing
--- a/browser/devtools/webaudioeditor/views/context.js
+++ b/browser/devtools/webaudioeditor/views/context.js
@@ -217,17 +217,17 @@ let ContextView = {
       let currentNode = InspectorView.getCurrentAudioNode();
       if (currentNode) {
         this.focusNode(currentNode.id);
       }
 
       // Fire an event upon completed rendering, with extra information
       // if in testing mode only.
       let info = {};
-      if (gDevTools.testing) {
+      if (DevToolsUtils.testing) {
         info = gAudioNodes.getInfo();
       }
       window.emit(EVENTS.UI_GRAPH_RENDERED, info.nodes, info.edges, info.paramEdges);
     });
 
     let layout = dagreD3.layout().rankDir("LR");
     renderer.layout(layout).run(graph, d3.select("#graph-target"));
 
--- a/browser/devtools/webconsole/test/head.js
+++ b/browser/devtools/webconsole/test/head.js
@@ -8,16 +8,17 @@
 let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
 let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
 let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let {require, TargetFactory} = devtools;
 let {Utils: WebConsoleUtils} = require("devtools/toolkit/webconsole/utils");
 let {Messages} = require("devtools/webconsole/console-output");
+let DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
 const asyncStorage = require("devtools/toolkit/shared/async-storage");
 
 // Services.prefs.setBoolPref("devtools.debugger.log", true);
 
 let gPendingOutputTest = 0;
 
 // The various categories of messages.
 const CATEGORY_NETWORK = 0;
@@ -36,17 +37,17 @@ const SEVERITY_LOG = 3;
 
 // The indent of a console group in pixels.
 const GROUP_INDENT = 12;
 
 const WEBCONSOLE_STRINGS_URI = "chrome://browser/locale/devtools/" +
                                "webconsole.properties";
 let WCUL10n = new WebConsoleUtils.l10n(WEBCONSOLE_STRINGS_URI);
 
-gDevTools.testing = true;
+DevToolsUtils.testing = true;
 
 function asyncTest(generator) {
   return () => {
     Task.spawn(generator).then(finishTest);
   };
 }
 
 function loadTab(url) {
@@ -328,17 +329,17 @@ let finishTest = Task.async(function* ()
 
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   yield gDevTools.closeToolbox(target);
 
   finish();
 });
 
 registerCleanupFunction(function*() {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
 
   // Remove stored console commands in between tests
   yield asyncStorage.removeItem("webConsoleHistory");
 
   dumpConsoles();
 
   if (HUDService.getBrowserConsole()) {
     HUDService.toggleBrowserConsole();
--- a/browser/devtools/webide/test/head.js
+++ b/browser/devtools/webide/test/head.js
@@ -9,17 +9,18 @@ Cu.import('resource://gre/modules/Servic
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 
 const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 const {require} = devtools;
 const promise = require("promise");
 const {AppProjects} = require("devtools/app-manager/app-projects");
-gDevTools.testing = true;
+const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
+DevToolsUtils.testing = true;
 
 let TEST_BASE;
 if (window.location === "chrome://browser/content/browser.xul") {
   TEST_BASE = "chrome://mochitests/content/browser/browser/devtools/webide/test/";
 } else {
   TEST_BASE = "chrome://mochitests/content/chrome/browser/devtools/webide/test/";
 }
 
@@ -32,17 +33,17 @@ Services.prefs.setCharPref("devtools.web
 Services.prefs.setCharPref("devtools.webide.adbAddonURL", TEST_BASE + "addons/adbhelper-#OS#.xpi");
 Services.prefs.setCharPref("devtools.webide.adaptersAddonURL", TEST_BASE + "addons/fxdt-adapters-#OS#.xpi");
 Services.prefs.setCharPref("devtools.webide.templatesURL", TEST_BASE + "templates.json");
 Services.prefs.setCharPref("devtools.devices.url", TEST_BASE + "browser_devices.json");
 
 let registerCleanupFunction = registerCleanupFunction ||
                               SimpleTest.registerCleanupFunction;
 registerCleanupFunction(() => {
-  gDevTools.testing = false;
+  DevToolsUtils.testing = false;
   Services.prefs.clearUserPref("devtools.webide.enabled");
   Services.prefs.clearUserPref("devtools.webide.enableLocalRuntime");
   Services.prefs.clearUserPref("devtools.webide.autoinstallADBHelper");
   Services.prefs.clearUserPref("devtools.webide.autoinstallFxdtAdapters");
   Services.prefs.clearUserPref("devtools.webide.sidebars");
   Services.prefs.clearUserPref("devtools.webide.busyTimeout");
   Services.prefs.clearUserPref("devtools.webide.lastSelectedProject");
   Services.prefs.clearUserPref("devtools.webide.lastConnectedRuntime");
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -144,16 +144,17 @@ browser.jar:
   skin/classic/browser/loop/toolbar@2x.png            (loop/toolbar@2x.png)
   skin/classic/browser/loop/toolbar-inverted.png      (loop/toolbar-inverted.png)
   skin/classic/browser/loop/toolbar-inverted@2x.png   (loop/toolbar-inverted@2x.png)
 * skin/classic/browser/controlcenter/panel.css        (controlcenter/panel.css)
   skin/classic/browser/controlcenter/arrow-subview.svg  (../shared/controlcenter/arrow-subview.svg)
   skin/classic/browser/controlcenter/conn-not-secure.svg  (../shared/controlcenter/conn-not-secure.svg)
   skin/classic/browser/controlcenter/conn-secure-dv.svg  (../shared/controlcenter/conn-secure-dv.svg)
   skin/classic/browser/controlcenter/conn-secure-ev.svg  (../shared/controlcenter/conn-secure-ev.svg)
+  skin/classic/browser/controlcenter/mcb-disabled.svg  (../shared/controlcenter/mcb-disabled.svg)
   skin/classic/browser/controlcenter/permissions.svg  (../shared/controlcenter/permissions.svg)
   skin/classic/browser/controlcenter/tracking-protection.svg                 (../shared/controlcenter/tracking-protection.svg)
   skin/classic/browser/controlcenter/tracking-protection-disabled.svg        (../shared/controlcenter/tracking-protection-disabled.svg)
   skin/classic/browser/customizableui/background-noise-toolbar.png  (customizableui/background-noise-toolbar.png)
   skin/classic/browser/customizableui/customize-illustration.png  (../shared/customizableui/customize-illustration.png)
   skin/classic/browser/customizableui/customize-illustration-rtl.png  (../shared/customizableui/customize-illustration-rtl.png)
   skin/classic/browser/customizableui/customizeMode-gridTexture.png  (customizableui/customizeMode-gridTexture.png)
   skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png  (customizableui/customizeMode-separatorHorizontal.png)
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -188,16 +188,17 @@ browser.jar:
   skin/classic/browser/yosemite/loop/menuPanel@2x.png       (loop/menuPanel-yosemite@2x.png)
   skin/classic/browser/yosemite/loop/toolbar.png            (loop/toolbar-yosemite.png)
   skin/classic/browser/yosemite/loop/toolbar@2x.png         (loop/toolbar-yosemite@2x.png)
 * skin/classic/browser/controlcenter/panel.css        (controlcenter/panel.css)
   skin/classic/browser/controlcenter/arrow-subview.svg  (../shared/controlcenter/arrow-subview.svg)
   skin/classic/browser/controlcenter/conn-not-secure.svg  (../shared/controlcenter/conn-not-secure.svg)
   skin/classic/browser/controlcenter/conn-secure-dv.svg  (../shared/controlcenter/conn-secure-dv.svg)
   skin/classic/browser/controlcenter/conn-secure-ev.svg  (../shared/controlcenter/conn-secure-ev.svg)
+  skin/classic/browser/controlcenter/mcb-disabled.svg  (../shared/controlcenter/mcb-disabled.svg)
   skin/classic/browser/controlcenter/permissions.svg  (../shared/controlcenter/permissions.svg)
   skin/classic/browser/controlcenter/tracking-protection.svg                 (../shared/controlcenter/tracking-protection.svg)
   skin/classic/browser/controlcenter/tracking-protection-disabled.svg        (../shared/controlcenter/tracking-protection-disabled.svg)
   skin/classic/browser/customizableui/background-noise-toolbar.png  (customizableui/background-noise-toolbar.png)
   skin/classic/browser/customizableui/customize-titleBar-toggle.png  (customizableui/customize-titleBar-toggle.png)
   skin/classic/browser/customizableui/customize-titleBar-toggle@2x.png  (customizableui/customize-titleBar-toggle@2x.png)
   skin/classic/browser/customizableui/customize-illustration.png  (../shared/customizableui/customize-illustration.png)
   skin/classic/browser/customizableui/customize-illustration@2x.png  (../shared/customizableui/customize-illustration@2x.png)
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/controlcenter/mcb-disabled.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-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/. -->
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     width="24" height="24" viewBox="0 0 24 24">
+  <defs>
+    <rect id="shape-lock-clasp-outer" x="5" y="1" width="14" height="20" rx="7" ry="7" />
+    <rect id="shape-lock-clasp-inner" x="8" y="4" width="8" height="14" rx="4" ry="4" />
+    <rect id="shape-lock-base" x="3" y="10" width="18" height="13" rx="1.5" ry="1.5" />
+
+    <mask id="mask-clasp-cutout">
+      <rect width="24" height="24" fill="#000" />
+      <use xlink:href="#shape-lock-clasp-outer" fill="#fff" />
+      <use xlink:href="#shape-lock-clasp-inner" fill="#000" />
+      <line x1="3" y1="21" x2="21.5" y2="0.5" stroke="#000" stroke-width="3" />
+      <line x1="3" y1="25" x2="21.5" y2="4.5" stroke="#000" stroke-width="3" />
+      <rect x="3" y="10" width="18" height="13" rx="1.5" ry="1.5" />
+    </mask>
+
+    <mask id="mask-base-cutout">
+      <rect width="24" height="24" fill="#000" />
+      <use xlink:href="#shape-lock-base" fill="#fff" />
+      <line x1="2.25" y1="24.75" x2="21.5" y2="4.5" stroke="#000" stroke-width="3" />
+    </mask>
+  </defs>
+
+  <use xlink:href="#shape-lock-clasp-outer" mask="url(#mask-clasp-cutout)" fill="#999" />
+  <use xlink:href="#shape-lock-base" mask="url(#mask-base-cutout)" fill="#999" />
+
+  <line x1="2.25" y1="22.75" x2="21.5" y2="2.5" stroke="#d92d21" stroke-width="3" />
+</svg>
--- a/browser/themes/shared/controlcenter/panel.inc.css
+++ b/browser/themes/shared/controlcenter/panel.inc.css
@@ -203,16 +203,21 @@
   background-image: url(chrome://browser/skin/controlcenter/conn-secure-dv.svg);
 }
 
 #identity-popup-securityView.verifiedIdentity,
 #identity-popup-security-content.verifiedIdentity {
   background-image: url(chrome://browser/skin/controlcenter/conn-secure-ev.svg);
 }
 
+#identity-popup-securityView.mixedActiveContent,
+#identity-popup-security-content.mixedActiveContent {
+  background-image: url(chrome://browser/skin/controlcenter/mcb-disabled.svg);
+}
+
 #identity-popup-securityView-header {
   border-bottom: 1px solid #e5e5e5;
   padding-bottom: 1em;
   margin-bottom: 1em;
 }
 
 #identity-popup-content-owner {
   font-weight: 700;
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -191,16 +191,17 @@ browser.jar:
         skin/classic/browser/loop/toolbar-XP@2x.png                  (loop/toolbar-XP@2x.png)
         skin/classic/browser/loop/toolbar-lunaSilver.png             (loop/toolbar-lunaSilver.png)
         skin/classic/browser/loop/toolbar-lunaSilver@2x.png          (loop/toolbar-lunaSilver@2x.png)
 *       skin/classic/browser/controlcenter/panel.css                 (controlcenter/panel.css)
         skin/classic/browser/controlcenter/arrow-subview.svg  (../shared/controlcenter/arrow-subview.svg)
         skin/classic/browser/controlcenter/conn-not-secure.svg  (../shared/controlcenter/conn-not-secure.svg)
         skin/classic/browser/controlcenter/conn-secure-dv.svg  (../shared/controlcenter/conn-secure-dv.svg)
         skin/classic/browser/controlcenter/conn-secure-ev.svg  (../shared/controlcenter/conn-secure-ev.svg)
+        skin/classic/browser/controlcenter/mcb-disabled.svg  (../shared/controlcenter/mcb-disabled.svg)
         skin/classic/browser/controlcenter/permissions.svg  (../shared/controlcenter/permissions.svg)
         skin/classic/browser/controlcenter/tracking-protection.svg                 (../shared/controlcenter/tracking-protection.svg)
         skin/classic/browser/controlcenter/tracking-protection-disabled.svg        (../shared/controlcenter/tracking-protection-disabled.svg)
         skin/classic/browser/customizableui/background-noise-toolbar.png  (customizableui/background-noise-toolbar.png)
         skin/classic/browser/customizableui/customizeFavicon.ico  (../shared/customizableui/customizeFavicon.ico)
         skin/classic/browser/customizableui/customize-illustration.png  (../shared/customizableui/customize-illustration.png)
         skin/classic/browser/customizableui/customize-illustration-rtl.png  (../shared/customizableui/customize-illustration-rtl.png)
         skin/classic/browser/customizableui/customize-titleBar-toggle.png  (customizableui/customize-titleBar-toggle.png)
--- a/dom/base/Console.h
+++ b/dom/base/Console.h
@@ -13,16 +13,17 @@
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsIObserver.h"
 #include "nsWrapperCache.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsPIDOMWindow.h"
 
 class nsIConsoleAPIStorage;
+class nsIPrincipal;
 class nsIProfiler;
 class nsIXPConnectJSObjectHolder;
 
 namespace mozilla {
 namespace dom {
 
 class ConsoleCallData;
 struct ConsoleStackEntry;
--- a/dom/base/PerformanceEntry.cpp
+++ b/dom/base/PerformanceEntry.cpp
@@ -1,17 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PerformanceEntry.h"
+#include "MainThreadUtils.h"
+#include "mozilla/dom/PerformanceEntryBinding.h"
 #include "nsIURI.h"
-#include "mozilla/dom/PerformanceEntryBinding.h"
 
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PerformanceEntry, mParent)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceEntry)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceEntry)
 
--- a/dom/base/PerformanceEntry.h
+++ b/dom/base/PerformanceEntry.h
@@ -3,16 +3,18 @@
 /* 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_PerformanceEntry_h___
 #define mozilla_dom_PerformanceEntry_h___
 
 #include "nsDOMNavigationTiming.h"
+#include "nsString.h"
+#include "nsWrapperCache.h"
 
 class nsISupports;
 
 namespace mozilla {
 namespace dom {
 
 // http://www.w3.org/TR/performance-timeline/#performanceentry
 class PerformanceEntry : public nsISupports,
--- a/dom/base/PerformanceMark.cpp
+++ b/dom/base/PerformanceMark.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PerformanceMark.h"
+#include "MainThreadUtils.h"
 #include "mozilla/dom/PerformanceMarkBinding.h"
 
 using namespace mozilla::dom;
 
 PerformanceMark::PerformanceMark(nsISupports* aParent,
                                  const nsAString& aName,
                                  DOMHighResTimeStamp aStartTime)
   : PerformanceEntry(aParent, aName, NS_LITERAL_STRING("mark"))
--- a/dom/base/PerformanceMeasure.cpp
+++ b/dom/base/PerformanceMeasure.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PerformanceMeasure.h"
+#include "MainThreadUtils.h"
 #include "mozilla/dom/PerformanceMeasureBinding.h"
 
 using namespace mozilla::dom;
 
 PerformanceMeasure::PerformanceMeasure(nsISupports* aParent,
                                        const nsAString& aName,
                                        DOMHighResTimeStamp aStartTime,
                                        DOMHighResTimeStamp aEndTime)
--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/PMessagePort.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "mozilla/EventDispatcher.h"
 #include "nsGlobalWindow.h"
 #include "nsIPresShell.h"
 #include "nsIPrincipal.h"
+#include "nsPresContext.h"
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
 struct StructuredCloneInfo
 {
--- a/dom/base/PostMessageEvent.h
+++ b/dom/base/PostMessageEvent.h
@@ -6,19 +6,21 @@
 
 #ifndef mozilla_dom_PostMessageEvent_h
 #define mozilla_dom_PostMessageEvent_h
 
 #include "js/StructuredClone.h"
 #include "nsCOMPtr.h"
 #include "nsRefPtr.h"
 #include "nsTArray.h"
+#include "nsThreadUtils.h"
 
 class nsGlobalWindow;
 class nsIPrincipal;
+class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class MessagePortBase;
 class MessagePortIdentifier;
 
 /**
--- a/dom/base/ProcessGlobal.cpp
+++ b/dom/base/ProcessGlobal.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ProcessGlobal.h"
 
 #include "nsContentCID.h"
 #include "nsDOMClassInfoID.h"
+#include "mozilla/HoldDropJSObjects.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 ProcessGlobal::ProcessGlobal(nsFrameMessageManager* aMessageManager)
  : mInitialized(false),
    mMessageManager(aMessageManager)
 {
--- a/dom/base/SameProcessMessageQueue.cpp
+++ b/dom/base/SameProcessMessageQueue.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SameProcessMessageQueue.h"
+#include "nsThreadUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 SameProcessMessageQueue* SameProcessMessageQueue::sSingleton;
 
 SameProcessMessageQueue::SameProcessMessageQueue()
 {
--- a/dom/base/nsCCUncollectableMarker.cpp
+++ b/dom/base/nsCCUncollectableMarker.cpp
@@ -28,16 +28,17 @@
 #include "nsJSEnvironment.h"
 #include "nsInProcessTabChildGlobal.h"
 #include "nsFrameLoader.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/dom/Element.h"
 #include "xpcpublic.h"
 #include "nsObserverService.h"
 #include "nsFocusManager.h"
+#include "nsIInterfaceRequestorUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static bool sInited = 0;
 uint32_t nsCCUncollectableMarker::sGeneration = 0;
 #ifdef MOZ_XUL
 #include "nsXULPrototypeCache.h"
--- a/dom/base/nsContentPolicy.cpp
+++ b/dom/base/nsContentPolicy.cpp
@@ -11,21 +11,23 @@
 #include "mozilla/Logging.h"
 
 #include "nsISupports.h"
 #include "nsXPCOM.h"
 #include "nsContentPolicyUtils.h"
 #include "nsContentPolicy.h"
 #include "nsIURI.h"
 #include "nsIDocShell.h"
+#include "nsIDOMElement.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMWindow.h"
 #include "nsIContent.h"
 #include "nsILoadContext.h"
 #include "nsCOMArray.h"
+#include "nsContentUtils.h"
 
 using mozilla::LogLevel;
 
 NS_IMPL_ISUPPORTS(nsContentPolicy, nsIContentPolicy)
 
 static PRLogModuleInfo* gConPolLog;
 
 nsresult
--- a/dom/base/nsDOMMutationObserver.cpp
+++ b/dom/base/nsDOMMutationObserver.cpp
@@ -12,16 +12,18 @@
 #include "nsContentUtils.h"
 #include "nsThreadUtils.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsTextFragment.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/dom/Animation.h"
 #include "mozilla/dom/KeyframeEffect.h"
 
+using mozilla::dom::Animation;
+
 nsAutoTArray<nsRefPtr<nsDOMMutationObserver>, 4>*
   nsDOMMutationObserver::sScheduledMutationObservers = nullptr;
 
 nsDOMMutationObserver* nsDOMMutationObserver::sCurrentObserver = nullptr;
 
 uint32_t nsDOMMutationObserver::sMutationLevel = 0;
 uint64_t nsDOMMutationObserver::sCount = 0;
 
@@ -340,22 +342,22 @@ void nsMutationReceiver::NodeWillBeDestr
   NS_ASSERTION(!mParent, "Shouldn't have mParent here!");
   Disconnect(true);
 }
 
 void
 nsAnimationReceiver::RecordAnimationMutation(Animation* aAnimation,
                                              AnimationMutation aMutationType)
 {
-  KeyframeEffectReadOnly* effect = aAnimation->GetEffect();
+  mozilla::dom::KeyframeEffectReadOnly* effect = aAnimation->GetEffect();
   if (!effect) {
     return;
   }
 
-  Element* animationTarget = effect->GetTarget();
+  mozilla::dom::Element* animationTarget = effect->GetTarget();
   if (!animationTarget) {
     return;
   }
 
   if (!Animations() || !(Subtree() || animationTarget == Target()) ||
       animationTarget->ChromeOnlyAccess()) {
     return;
   }
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3531,27 +3531,37 @@ nsDOMWindowUtils::RequestCompositorPrope
   }
 
   return NS_ERROR_NOT_AVAILABLE;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetOMTAStyle(nsIDOMElement* aElement,
                                const nsAString& aProperty,
+                               const nsAString& aPseudoElement,
                                nsAString& aResult)
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   nsCOMPtr<Element> element = do_QueryInterface(aElement);
   if (!element) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsRefPtr<nsROCSSPrimitiveValue> cssValue = nullptr;
   nsIFrame* frame = element->GetPrimaryFrame();
+  if (frame && !aPseudoElement.IsEmpty()) {
+    if (aPseudoElement.EqualsLiteral("::before")) {
+      frame = nsLayoutUtils::GetBeforeFrame(frame);
+    } else if (aPseudoElement.EqualsLiteral("::after")) {
+      frame = nsLayoutUtils::GetAfterFrame(frame);
+    } else {
+      return NS_ERROR_INVALID_ARG;
+    }
+  }
   if (frame && nsLayoutUtils::AreAsyncAnimationsEnabled()) {
     if (aProperty.EqualsLiteral("opacity")) {
       Layer* layer =
         FrameLayerBuilder::GetDedicatedLayer(frame,
                                              nsDisplayItem::TYPE_OPACITY);
       if (layer) {
         float value;
         ShadowLayerForwarder* forwarder = layer->Manager()->AsShadowForwarder();
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3899,16 +3899,19 @@ PLDHashOperator RequestDiscardEnumerator
 
 void
 nsDocument::DeleteShell()
 {
   mExternalResourceMap.HideViewers();
   if (IsEventHandlingEnabled()) {
     RevokeAnimationFrameNotifications();
   }
+  if (nsPresContext* presContext = mPresShell->GetPresContext()) {
+    presContext->RefreshDriver()->CancelPendingEvents(this);
+  }
 
   // When our shell goes away, request that all our images be immediately
   // discarded, so we don't carry around decoded image data for a document we
   // no longer intend to paint.
   mImageTracker.EnumerateRead(RequestDiscardEnumerator, nullptr);
 
   // Now that we no longer have a shell, we need to forget about any FontFace
   // objects for @font-face rules that came from the style set.
@@ -9209,24 +9212,41 @@ static bool
 NotifyPageHide(nsIDocument* aDocument, void* aData)
 {
   const bool* aPersistedPtr = static_cast<const bool*>(aData);
   aDocument->OnPageHide(*aPersistedPtr, nullptr);
   return true;
 }
 
 static void
+DispatchCustomEventWithFlush(nsINode* aTarget, const nsAString& aEventType,
+                             bool aBubbles, bool aOnlyChromeDispatch)
+{
+  nsCOMPtr<nsIDOMEvent> event;
+  NS_NewDOMEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
+  nsresult rv = event->InitEvent(aEventType, aBubbles, false);
+  if (NS_FAILED(rv)) {
+    return;
+  }
+  event->SetTrusted(true);
+  if (aOnlyChromeDispatch) {
+    event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+  }
+  if (nsIPresShell* shell = aTarget->OwnerDoc()->GetShell()) {
+    shell->GetPresContext()->
+      RefreshDriver()->ScheduleEventDispatch(aTarget, event);
+  }
+}
+
+static void
 DispatchFullScreenChange(nsIDocument* aTarget)
 {
-  nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
-    new AsyncEventDispatcher(aTarget,
-                             NS_LITERAL_STRING("mozfullscreenchange"),
-                             true,
-                             false);
-  asyncDispatcher->PostDOMEvent();
+  DispatchCustomEventWithFlush(
+    aTarget, NS_LITERAL_STRING("mozfullscreenchange"),
+    /* Bubbles */ true, /* OnlyChrome */ false);
 }
 
 void
 nsDocument::OnPageHide(bool aPersisted,
                        EventTarget* aDispatchStartTarget)
 {
   // Send out notifications that our <link> elements are detached,
   // but only if this is not a full unload.
@@ -11162,21 +11182,20 @@ ExitFullscreenInDocTree(nsIDocument* aMa
   }
 
   NS_ASSERTION(!root->IsFullScreenDoc(),
     "Fullscreen root should no longer be a fullscreen doc...");
 
   // Dispatch MozDOMFullscreen:Exited to the last document in
   // the list since we want this event to follow the same path
   // MozDOMFullscreen:Entered dispatched.
-  nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
-    new AsyncEventDispatcher(changed.LastElement(),
-                             NS_LITERAL_STRING("MozDOMFullscreen:Exited"),
-                             true, true);
-  asyncDispatcher->PostDOMEvent();
+  nsContentUtils::DispatchEventOnlyToChrome(
+    changed.LastElement(), ToSupports(changed.LastElement()),
+    NS_LITERAL_STRING("MozDOMFullscreen:Exited"),
+    /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   // Move the top-level window out of fullscreen mode.
   FullscreenRoots::Remove(root);
   SetWindowFullScreen(root, false);
 }
 
 /* static */
 void
 nsDocument::ExitFullscreen(nsIDocument* aDoc)
@@ -11245,19 +11264,20 @@ nsDocument::RestorePreviousFullScreenSta
       exitingFullscreen = false;
       break;
     }
   }
   if (exitingFullscreen) {
     // If we are fully exiting fullscreen, don't touch anything here,
     // just wait for the window to get out from fullscreen first.
     if (XRE_GetProcessType() == GeckoProcessType_Content) {
-      (new AsyncEventDispatcher(
-        this, NS_LITERAL_STRING("MozDOMFullscreen:Exit"),
-        /* Bubbles */ true, /* ChromeOnly */ true))->PostDOMEvent();
+      nsContentUtils::DispatchEventOnlyToChrome(
+        this, ToSupports(this), NS_LITERAL_STRING("MozDOMFullscreen:Exit"),
+        /* Bubbles */ true, /* Cancelable */ false,
+        /* DefaultAction */ nullptr);
     } else {
       SetWindowFullScreen(this, false);
     }
     return;
   }
 
   // If fullscreen mode is updated the pointer should be unlocked
   UnlockPointer();
@@ -11290,21 +11310,19 @@ nsDocument::RestorePreviousFullScreenSta
       if (fullScreenDoc != doc) {
         // We've popped so enough off the stack that we've rolled back to
         // a fullscreen element in a parent document. If this document isn't
         // approved for fullscreen, or if it's cross origin, dispatch an
         // event to chrome so it knows to show the authorization/warning UI.
         if (!nsContentUtils::HaveEqualPrincipals(fullScreenDoc, doc) ||
             (!nsContentUtils::IsSitePermAllow(doc->NodePrincipal(), "fullscreen") &&
              !static_cast<nsDocument*>(doc)->mIsApprovedForFullscreen)) {
-          nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
-            new AsyncEventDispatcher(
-                doc, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
-                /* Bubbles */ true, /* ChromeOnly */ true);
-          asyncDispatcher->PostDOMEvent();
+          DispatchCustomEventWithFlush(
+            doc, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
+            /* Bubbles */ true, /* ChromeOnly */ true);
         }
       }
       break;
     }
   }
 
   MOZ_ASSERT(doc, "If we were going to exit from fullscreen on all documents "
              "in this doctree, we should've asked the window to exit first "
@@ -11686,19 +11704,19 @@ nsDocument::RequestFullScreen(UniquePtr<
   if (!FullscreenElementReadyCheck(elem, aRequest->mIsCallerChrome)) {
     return;
   }
 
   sPendingFullscreenRequests.insertBack(aRequest.release());
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     // If we are not the top level process, dispatch an event to make
     // our parent process go fullscreen first.
-    (new AsyncEventDispatcher(
-       this, NS_LITERAL_STRING("MozDOMFullscreen:Request"),
-       /* Bubbles */ true, /* ChromeOnly */ true))->PostDOMEvent();
+    nsContentUtils::DispatchEventOnlyToChrome(
+      this, ToSupports(this), NS_LITERAL_STRING("MozDOMFullscreen:Request"),
+      /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   } else {
     // Make the window fullscreen.
     FullscreenRequest* lastRequest = sPendingFullscreenRequests.getLast();
     SetWindowFullScreen(this, true, lastRequest->mVRHMDDevice);
   }
 }
 
 /* static */ bool
@@ -11815,65 +11833,61 @@ nsDocument::ApplyFullscreen(const Fullsc
       // We've reached either the root, or a point in the doctree where the
       // new full-screen element container is the same as the previous
       // full-screen element's container. No more changes need to be made
       // to the full-screen stacks of documents further up the tree.
       break;
     }
   }
 
-  // Dispatch "mozfullscreenchange" events. Note this loop is in reverse
-  // order so that the events for the root document arrives before the leaf
-  // document, as required by the spec.
-  for (uint32_t i = 0; i < changed.Length(); ++i) {
-    DispatchFullScreenChange(changed[changed.Length() - i - 1]);
-  }
-
   // If this document hasn't already been approved in this session,
   // check to see if the user has granted the fullscreen access
   // to the document's principal's host, if it has one. Note that documents
   // in web apps which are the same origin as the web app are considered
   // trusted and so are automatically approved.
   if (!mIsApprovedForFullscreen) {
     mIsApprovedForFullscreen =
       !Preferences::GetBool("full-screen-api.approval-required") ||
       NodePrincipal()->GetAppStatus() >= nsIPrincipal::APP_STATUS_INSTALLED ||
       nsContentUtils::IsSitePermAllow(NodePrincipal(), "fullscreen");
   }
 
+  FullscreenRoots::Add(this);
+
   // If it is the first entry of the fullscreen, trigger an event so
   // that the UI can response to this change, e.g. hide chrome, or
   // notifying parent process to enter fullscreen. Note that chrome
   // code may also want to listen to MozDOMFullscreen:NewOrigin event
   // to pop up warning/approval UI.
   if (!previousFullscreenDoc) {
-    nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
-      new AsyncEventDispatcher(
-        elem, NS_LITERAL_STRING("MozDOMFullscreen:Entered"),
-        /* Bubbles */ true, /* ChromeOnly */ true);
-    asyncDispatcher->PostDOMEvent();
+    nsContentUtils::DispatchEventOnlyToChrome(
+      this, ToSupports(elem), NS_LITERAL_STRING("MozDOMFullscreen:Entered"),
+      /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   }
 
   // The origin which is fullscreen gets changed. Trigger an event so
   // that the chrome knows to pop up a warning/approval UI. Note that
   // previousFullscreenDoc == nullptr upon first entry, so we always
   // take this path on the first entry. Also note that, in a multi-
   // process browser, the code in content process is responsible for
   // sending message with the origin to its parent, and the parent
   // shouldn't rely on this event itself.
   if (aRequest.mShouldNotifyNewOrigin &&
       !nsContentUtils::HaveEqualPrincipals(previousFullscreenDoc, this)) {
-    nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
-      new AsyncEventDispatcher(
-        this, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
-        /* Bubbles */ true, /* ChromeOnly */ true);
-    asyncDispatcher->PostDOMEvent();
-  }
-
-  FullscreenRoots::Add(this);
+    DispatchCustomEventWithFlush(
+      this, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
+      /* Bubbles */ true, /* ChromeOnly */ true);
+  }
+
+  // Dispatch "mozfullscreenchange" events. Note this loop is in reverse
+  // order so that the events for the root document arrives before the leaf
+  // document, as required by the spec.
+  for (uint32_t i = 0; i < changed.Length(); ++i) {
+    DispatchFullScreenChange(changed[changed.Length() - i - 1]);
+  }
 }
 
 NS_IMETHODIMP
 nsDocument::GetMozFullScreenElement(nsIDOMElement **aFullScreenElement)
 {
   ErrorResult rv;
   Element* el = GetMozFullScreenElement(rv);
   if (rv.Failed()) {
--- a/dom/base/nsHostObjectProtocolHandler.cpp
+++ b/dom/base/nsHostObjectProtocolHandler.cpp
@@ -201,17 +201,17 @@ class BlobURLsReporter final : public ns
   }
 
   static PLDHashOperator ReportCallback(nsCStringHashKey::KeyType aKey,
                                         DataInfo* aInfo,
                                         void* aUserArg)
   {
     EnumArg* envp = static_cast<EnumArg*>(aUserArg);
     nsCOMPtr<nsIDOMBlob> tmp = do_QueryInterface(aInfo->mObject);
-    nsRefPtr<Blob> blob = static_cast<Blob*>(tmp.get());
+    nsRefPtr<mozilla::dom::Blob> blob = static_cast<mozilla::dom::Blob*>(tmp.get());
 
     if (blob) {
       NS_NAMED_LITERAL_CSTRING
         (desc, "A blob URL allocated with URL.createObjectURL; the referenced "
          "blob cannot be freed until all URLs for it have been explicitly "
          "invalidated with URL.revokeObjectURL.");
       nsAutoCString path, url, owner, specialDesc;
       nsCOMPtr<nsIURI> principalURI;
--- a/dom/base/nsHostObjectURI.cpp
+++ b/dom/base/nsHostObjectURI.cpp
@@ -101,17 +101,17 @@ nsHostObjectURI::Serialize(mozilla::ipc:
     PrincipalInfo info;
     nsresult rv = PrincipalToPrincipalInfo(mPrincipal, &info);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return;
     }
 
     hostParams.principal() = info;
   } else {
-    hostParams.principal() = void_t();
+    hostParams.principal() = mozilla::void_t();
   }
 
   aParams = hostParams;
 }
 
 bool
 nsHostObjectURI::Deserialize(const mozilla::ipc::URIParams& aParams)
 {
--- a/dom/base/nsIGlobalObject.cpp
+++ b/dom/base/nsIGlobalObject.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIGlobalObject.h"
 #include "nsContentUtils.h"
+#include "nsThreadUtils.h"
+#include "nsHostObjectProtocolHandler.h"
 
 nsIGlobalObject::~nsIGlobalObject()
 {
   UnlinkHostObjectURIs();
 }
 
 nsIPrincipal*
 nsIGlobalObject::PrincipalOrNull()
--- a/dom/base/nsNoDataProtocolContentPolicy.cpp
+++ b/dom/base/nsNoDataProtocolContentPolicy.cpp
@@ -12,16 +12,17 @@
 
 #include "nsNoDataProtocolContentPolicy.h"
 #include "nsIDOMWindow.h"
 #include "nsString.h"
 #include "nsIProtocolHandler.h"
 #include "nsIIOService.h"
 #include "nsIExternalProtocolHandler.h"
 #include "nsNetUtil.h"
+#include "nsContentUtils.h"
 
 NS_IMPL_ISUPPORTS(nsNoDataProtocolContentPolicy, nsIContentPolicy)
 
 NS_IMETHODIMP
 nsNoDataProtocolContentPolicy::ShouldLoad(uint32_t aContentType,
                                           nsIURI *aContentLocation,
                                           nsIURI *aRequestingLocation,
                                           nsISupports *aRequestingContext,
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/after_clear.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test app for bug 1172562</title>
+    <script src='test.js'></script>
+    <script type='application/javascript;version=1.7'>
+
+function runTests() {
+  return Promise.resolve()
+    .then(() => { return navigator.serviceWorker.ready })
+    .then((registration) => {
+      return new Promise((resolve) => {
+        var worker = registration.waiting || registration.active;
+        worker.postMessage('read');
+        navigator.serviceWorker.onmessage = (message) => {
+          if (message.data.type == 'done') {
+            ok(!message.data.cached, 'No cached data');
+            resolve();
+          }
+        };
+      });
+    })
+    .then(done);
+}
+  </script>
+  </head>
+  <body onload='runTests()'>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/before_clear.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test app for bug 1172562</title>
+    <script src='test.js'></script>
+    <script type='application/javascript;version=1.7'>
+
+function runTests() {
+  return Promise.resolve()
+    .then(() => { return navigator.serviceWorker.ready })
+    .then((registration) => {
+      return new Promise((resolve) => {
+        var worker = registration.waiting || registration.active;
+        worker.postMessage('write');
+        navigator.serviceWorker.onmessage = (message) => {
+          if (message.data.type == 'written') {
+            worker.postMessage('read');
+          } else if (message.data.type == 'done') {
+            ok(message.data.cached, 'Write success');
+            resolve();
+          }
+        };
+      });
+    })
+    .then(done);
+}
+  </script>
+  </head>
+  <body onload='runTests()'>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/index.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test app for bug 1172562</title>
+    <script type='application/javascript;version=1.7'>
+function ok(aCondition, aMessage) {
+  if (aCondition) {
+    alert('OK: ' + aMessage);
+  } else {
+    alert('KO: ' + aMessage);
+  }
+}
+
+function ready() {
+  alert('READY');
+}
+
+function registerServiceWorker() {
+  return new Promise((resolve, reject) => {
+    navigator.serviceWorker.ready.then(() => {
+      ready();
+      resolve();
+    });
+    navigator.serviceWorker.register('sw.js', {scope: '.'})
+    .then(registration => {
+      ok(true, 'service worker registered');
+    })
+    .catch(reject);
+  });
+}
+
+function runTests() {
+  return Promise.resolve()
+    .then(registerServiceWorker)
+    .then(ready)
+}
+  </script>
+  </head>
+  <body onload='runTests()'>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/manifest.webapp
@@ -0,0 +1,5 @@
+{
+  "name": "App",
+  "launch_path": "/index.html",
+  "description": "Test app for bug 1172562"
+}
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/manifest.webapp^headers^
@@ -0,0 +1,1 @@
+Content-Type: application/manifest+json
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/sw.js
@@ -0,0 +1,18 @@
+self.addEventListener('message', (message) => {
+  caches.open('acache').then((cache) => {
+    if(message.data == 'write') {
+      cache.add('aurl').then(() => {
+        message.source.postMessage({
+          type: 'written'
+        });
+      });
+    } else if (message.data == 'read') {
+      cache.match('aurl').then((result) => {
+        message.source.postMessage({
+          type: 'done',
+          cached: !!result
+        });
+      });
+    }
+  });
+});
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/test.js
@@ -0,0 +1,15 @@
+function ok(aCondition, aMessage) {
+  if (aCondition) {
+    alert('OK: ' + aMessage);
+  } else {
+    alert('KO: ' + aMessage);
+  }
+}
+
+function ready() {
+  alert('READY');
+}
+
+function done() {
+  alert('DONE');
+}
--- a/dom/cache/test/mochitest/mochitest.ini
+++ b/dom/cache/test/mochitest/mochitest.ini
@@ -18,16 +18,17 @@ support-files =
   test_cache_keys.js
   test_cache_put.js
   test_cache_requestCache.js
   test_cache_delete.js
   test_cache_put_reorder.js
   test_cache_https.js
   large_url_list.js
   empty.html
+  app/*
 
 [test_cache.html]
 [test_cache_add.html]
 [test_cache_match_request.html]
 [test_cache_matchAll_request.html]
 [test_cache_overwrite.html]
 [test_cache_match_vary.html]
 [test_caches.html]
@@ -35,11 +36,13 @@ support-files =
 [test_cache_put.html]
 [test_cache_requestCache.html]
 [test_cache_delete.html]
 [test_cache_put_reorder.html]
 [test_cache_https.html]
   skip-if = buildapp == 'b2g' # bug 1162353
 [test_cache_restart.html]
 [test_cache_shrink.html]
+[test_cache_clear_on_app_uninstall.html]
+  skip-if = e10s || buildapp == 'b2g' # bug 1178685
 [test_cache_orphaned_cache.html]
 [test_cache_orphaned_body.html]
 [test_cache_untrusted.html]
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/test_cache_clear_on_app_uninstall.html
@@ -0,0 +1,163 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 1172562 - Clear QuotaManager storage when uninstalling an app</title>
+  <script type='text/javascript' src='/tests/SimpleTest/SimpleTest.js'></script>
+  <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css' />
+</head>
+<body onload='runTests()'>
+<p id='display'></p>
+<div id='content' style='display: none'></div>
+<pre id='test'></pre>
+<script class='testbody' type='application/javascript;version=1.7'>
+
+SimpleTest.waitForExplicitFinish();
+
+const gOrigin = 'http://mochi.test:8888/tests/dom/cache/test/mochitest/app';
+const appManifestURL = gOrigin + '/manifest.webapp';
+let gApp;
+
+function setup() {
+  return new Promise((resolve, reject) => {
+    SpecialPowers.setAllAppsLaunchable(true);
+    SpecialPowers.pushPrefEnv({'set': [
+      ['dom.mozBrowserFramesEnabled', true],
+      ['dom.serviceWorkers.exemptFromPerDomainMax', true],
+      ['dom.serviceWorkers.enabled', true],
+      ['dom.serviceWorkers.testing.enabled', true],
+      ['dom.caches.enabled', true],
+    ]}, () => {
+      SpecialPowers.pushPermissions([
+        { 'type': 'webapps-manage', 'allow': 1, 'context': document },
+        { 'type': 'browser', 'allow': 1, 'context': document },
+        { 'type': 'embed-apps', 'allow': 1, 'context': document }
+      ], () => {
+        SpecialPowers.autoConfirmAppInstall(() => {
+          SpecialPowers.autoConfirmAppUninstall(resolve);
+        });
+      });
+    });
+  });
+}
+
+function installApp() {
+  return new Promise((resolve, reject) => {
+    let req = navigator.mozApps.install(appManifestURL);
+    req.onsuccess = function() {
+      gApp = req.result;
+      is(req.result.manifestURL, appManifestURL, 'app installed');
+      if (req.result.installState == 'installed') {
+        is(req.result.installState, 'installed', 'app downloaded');
+        resolve()
+      } else {
+        req.result.ondownloadapplied = function() {
+          is(req.result.installState, 'installed', 'app downloaded');
+          resolve();
+        }
+      }
+    }
+    req.onerror = reject;
+  });
+}
+
+function launchApp() {
+  if (!gApp) {
+    ok(false, 'No test application to launch');
+    return Promise.reject();
+  }
+  return new Promise((resolve, reject) => {
+    let iframe = document.createElement('iframe');
+    iframe.setAttribute('mozbrowser', 'true');
+    iframe.setAttribute('mozapp', gApp.manifestURL);
+    iframe.addEventListener('mozbrowsershowmodalprompt', function listener(e) {
+      let message = e.detail.message;
+      if (/OK/.exec(message)) {
+        ok(true, "Message from app: " + message);
+      } else if (/KO/.exec(message)) {
+        ok(false, "Message from app: " + message);
+      } else if (/READY/.exec(message)) {
+        ok(true, "Message from app: " + message);
+        resolve();
+      } else {
+        ok(false, "Unexpected message received: " + message);
+      }
+    }, false);
+    let domParent = document.getElementById('container');
+    domParent.appendChild(iframe);
+    SpecialPowers.wrap(iframe.contentWindow).location =
+      gOrigin + gApp.manifest.launch_path;
+  });
+}
+
+function loadControlled(aUrl) {
+  return new Promise((resolve, reject) => {
+    let iframe = document.createElement('iframe');
+    iframe.setAttribute('mozbrowser', 'true');
+    iframe.setAttribute('mozapp', gApp.manifestURL);
+    iframe.addEventListener('mozbrowsershowmodalprompt', function listener(e) {
+      let message = e.detail.message;
+      if (/OK/.exec(message)) {
+        ok(true, "Message from app: " + message);
+      } else if (/KO/.exec(message)) {
+        ok(false, "Message from app: " + message);
+      } else if (/DONE/.exec(message)) {
+        ok(true, "Messaging from app complete");
+        iframe.removeEventListener('mozbrowsershowmodalprompt', listener);
+        let domParent = document.getElementById('container');
+        domParent.removeChild(iframe);
+        resolve();
+      } else {
+        ok(false, "Unexpected message received: " + message);
+      }
+      }, false);
+    let domParent = document.getElementById('container');
+    domParent.appendChild(iframe);
+    SpecialPowers.wrap(iframe.contentWindow).location =
+      gOrigin + aUrl;
+  });
+}
+
+function loadBeforeClear() {
+  return loadControlled('/before_clear.html');
+}
+
+function loadAfterClear() {
+  return loadControlled('/after_clear.html');
+}
+
+function uninstallApp() {
+  return new Promise((resolve, reject) => {
+    if (!gApp) {
+      return reject();
+    }
+    let req = navigator.mozApps.mgmt.uninstall(gApp);
+    req.onsuccess = resolve;
+    req.onerror = reject;
+  });
+}
+
+function runTests() {
+  setup()
+    .then(installApp)
+    .then(launchApp)
+    .then(loadBeforeClear)
+    .then(uninstallApp)
+    .then(installApp)
+    .then(launchApp)
+    .then(loadAfterClear)
+    .then(uninstallApp)
+    .then(SimpleTest.finish)
+    .catch((e) => {
+      ok(false, 'Unexpected error ' + e.target.error.name);
+      SimpleTest.finish();
+    });
+}
+
+</script>
+<div id='container'></div>
+</body>
+</html>
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -44,17 +44,17 @@ interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsITranslationNodeList;
 interface nsIJSRAIIHelper;
 interface nsIContentPermissionRequest;
 interface nsIObserver;
 
-[scriptable, uuid(e7b44320-8255-4ad1-bbe9-d78a8a1867c9)]
+[scriptable, uuid(336a8683-5626-4512-a3d5-ec280c13e5c2)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -1741,17 +1741,18 @@ interface nsIDOMWindowUtils : nsISupport
     */
    void runBeforeNextEvent(in nsIRunnable runnable);
 
    /*
     * Returns the value of a given property animated on the compositor thread.
     * If the property is NOT currently being animated on the compositor thread,
     * returns an empty string.
     */
-   AString getOMTAStyle(in nsIDOMElement aElement, in AString aProperty);
+   AString getOMTAStyle(in nsIDOMElement aElement, in AString aProperty,
+                        [optional] in AString aPseudoElement);
 
    /**
     * Special function that gets a property syncronously from the last composite
     * that occured.
     *
     * Supported properties:
     *   "overdraw": Report a percentage between 0 and 999 indicate how many times
     *               each pixels on the destination window have been touched.
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ScriptLoader.h"
 
 #include "nsIChannel.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIHttpChannel.h"
+#include "nsIHttpChannelInternal.h"
 #include "nsIInputStreamPump.h"
 #include "nsIIOService.h"
 #include "nsIProtocolHandler.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIStreamLoader.h"
 #include "nsIStreamListenerTee.h"
 #include "nsIThreadRetargetableRequest.h"
 #include "nsIURI.h"
@@ -865,16 +866,26 @@ private:
     // We don't care about progress so just use the simple stream loader for
     // OnStreamComplete notification only.
     nsCOMPtr<nsIStreamLoader> loader;
     rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
+    // If we are loading a script for a ServiceWorker then we must not
+    // try to intercept it.  If the interception matches the current
+    // ServiceWorker's scope then we could deadlock the load.
+    if (mWorkerPrivate->IsServiceWorker()) {
+      nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(channel);
+      if (internal) {
+        internal->ForceNoIntercept();
+      }
+    }
+
     if (loadInfo.mCacheStatus != ScriptLoadInfo::ToBeCached) {
       rv = channel->AsyncOpen(loader, indexSupports);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     } else {
       nsCOMPtr<nsIOutputStream> writer;
 
--- a/dom/workers/ServiceWorker.cpp
+++ b/dom/workers/ServiceWorker.cpp
@@ -46,16 +46,21 @@ ServiceWorker::ServiceWorker(nsPIDOMWind
   : DOMEventTargetHelper(aWindow),
     mInfo(aInfo),
     mSharedWorker(aSharedWorker)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aInfo);
   MOZ_ASSERT(mSharedWorker);
 
+  if (aWindow) {
+    mDocument = aWindow->GetExtantDoc();
+    mWindow = aWindow->GetOuterWindow();
+  }
+
   // This will update our state too.
   mInfo->AppendWorker(this);
 }
 
 ServiceWorker::~ServiceWorker()
 {
   AssertIsOnMainThread();
   mInfo->RemoveWorker(this);
@@ -63,17 +68,17 @@ ServiceWorker::~ServiceWorker()
 
 NS_IMPL_ADDREF_INHERITED(ServiceWorker, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(ServiceWorker, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorker)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorker, DOMEventTargetHelper,
-                                   mSharedWorker)
+                                   mSharedWorker, mDocument, mWindow)
 
 JSObject*
 ServiceWorker::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   AssertIsOnMainThread();
 
   return ServiceWorkerBinding::Wrap(aCx, this, aGivenProto);
 }
@@ -92,19 +97,22 @@ ServiceWorker::PostMessage(JSContext* aC
   WorkerPrivate* workerPrivate = GetWorkerPrivate();
   MOZ_ASSERT(workerPrivate);
 
   if (State() == ServiceWorkerState::Redundant) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(GetParentObject());
-  nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
-  nsAutoPtr<ServiceWorkerClientInfo> clientInfo(new ServiceWorkerClientInfo(doc));
+  MOZ_ASSERT(mDocument && mWindow,
+             "Cannot call PostMessage on a ServiceWorker object that doesn't "
+             "have a window");
+
+  nsAutoPtr<ServiceWorkerClientInfo> clientInfo(
+    new ServiceWorkerClientInfo(mDocument, mWindow));
 
   workerPrivate->PostMessageToServiceWorker(aCx, aMessage, aTransferable,
                                             clientInfo, aRv);
 }
 
 WorkerPrivate*
 ServiceWorker::GetWorkerPrivate() const
 {
--- a/dom/workers/ServiceWorker.h
+++ b/dom/workers/ServiceWorker.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_dom_workers_serviceworker_h__
 #define mozilla_dom_workers_serviceworker_h__
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/ServiceWorkerBinding.h" // For ServiceWorkerState.
 
+class nsIDocument;
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 namespace workers {
 
 class ServiceWorkerInfo;
@@ -86,15 +87,19 @@ private:
   ServiceWorkerState mState;
   const nsRefPtr<ServiceWorkerInfo> mInfo;
 
   // To allow ServiceWorkers to potentially drop the backing DOMEventTargetHelper and
   // re-instantiate it later, they simply own a SharedWorker member that
   // can be released and recreated as required rather than re-implement some of
   // the SharedWorker logic.
   nsRefPtr<SharedWorker> mSharedWorker;
+  // We need to keep the document and window alive for PostMessage to be able
+  // to access them.
+  nsCOMPtr<nsIDocument> mDocument;
+  nsCOMPtr<nsPIDOMWindow> mWindow;
 };
 
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_workers_serviceworker_h__
--- a/dom/workers/ServiceWorkerClient.cpp
+++ b/dom/workers/ServiceWorkerClient.cpp
@@ -23,17 +23,18 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Se
 NS_IMPL_CYCLE_COLLECTING_ADDREF(ServiceWorkerClient)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(ServiceWorkerClient)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerClient)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc)
+ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc,
+                                                 nsPIDOMWindow* aWindow)
   : mWindowId(0)
 {
   MOZ_ASSERT(aDoc);
   nsresult rv = aDoc->GetId(mClientId);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to get the UUID of the document.");
   }
 
@@ -48,17 +49,17 @@ ServiceWorkerClientInfo::ServiceWorkerCl
   mVisibilityState = aDoc->VisibilityState();
 
   ErrorResult result;
   mFocused = aDoc->HasFocus(result);
   if (result.Failed()) {
     NS_WARNING("Failed to get focus information.");
   }
 
-  nsRefPtr<nsGlobalWindow> outerWindow = static_cast<nsGlobalWindow*>(aDoc->GetWindow());
+  nsRefPtr<nsGlobalWindow> outerWindow = static_cast<nsGlobalWindow*>(aWindow);
   MOZ_ASSERT(outerWindow);
   if (!outerWindow->IsTopLevelWindow()) {
     mFrameType = FrameType::Nested;
   } else if (outerWindow->HadOriginalOpener()) {
     mFrameType = FrameType::Auxiliary;
   } else {
     mFrameType = FrameType::Top_level;
   }
--- a/dom/workers/ServiceWorkerClient.h
+++ b/dom/workers/ServiceWorkerClient.h
@@ -9,32 +9,35 @@
 #define mozilla_dom_workers_serviceworkerclient_h
 
 #include "nsCOMPtr.h"
 #include "nsWrapperCache.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/ClientBinding.h"
 
+class nsIDocument;
+class nsPIDOMWindow;
+
 namespace mozilla {
 namespace dom {
 namespace workers {
 
 class ServiceWorkerClient;
 class ServiceWorkerWindowClient;
 
 // Used as a container object for information needed to create
 // client objects.
 class ServiceWorkerClientInfo final
 {
   friend class ServiceWorkerClient;
   friend class ServiceWorkerWindowClient;
 
 public:
-  explicit ServiceWorkerClientInfo(nsIDocument* aDoc);
+  ServiceWorkerClientInfo(nsIDocument* aDoc, nsPIDOMWindow* aWindow);
 
 private:
   nsString mClientId;
   uint64_t mWindowId;
   nsString mUrl;
 
   // Window Clients
   VisibilityState mVisibilityState;
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -3546,17 +3546,17 @@ ServiceWorkerManager::DispatchFetchEvent
     return;
   }
 
   nsAutoPtr<ServiceWorkerClientInfo> clientInfo;
 
   if (!isNavigation) {
     MOZ_ASSERT(aDoc);
     aRv = GetDocumentController(aDoc->GetInnerWindow(), getter_AddRefs(serviceWorker));
-    clientInfo = new ServiceWorkerClientInfo(aDoc);
+    clientInfo = new ServiceWorkerClientInfo(aDoc, aDoc->GetWindow());
   } else {
     nsCOMPtr<nsIChannel> internalChannel;
     aRv = aChannel->GetChannel(getter_AddRefs(internalChannel));
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
 
     nsCOMPtr<nsIURI> uri;
@@ -3919,17 +3919,17 @@ EnumControlledDocuments(nsISupports* aKe
   }
 
   nsCOMPtr<nsIDocument> document = do_QueryInterface(aKey);
 
   if (!document || !document->GetWindow()) {
     return PL_DHASH_NEXT;
   }
 
-  ServiceWorkerClientInfo clientInfo(document);
+  ServiceWorkerClientInfo clientInfo(document, document->GetWindow());
   data->mDocuments.AppendElement(clientInfo);
 
   return PL_DHASH_NEXT;
 }
 
 static void
 FireControllerChangeOnDocument(nsIDocument* aDocument)
 {
--- a/dom/workers/ServiceWorkerWindowClient.cpp
+++ b/dom/workers/ServiceWorkerWindowClient.cpp
@@ -82,17 +82,18 @@ public:
     AssertIsOnMainThread();
     nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
     UniquePtr<ServiceWorkerClientInfo> clientInfo;
 
     if (window) {
       ErrorResult result;
       //FIXME(catalinb): Bug 1144660 - check if we are allowed to focus here.
       window->Focus(result);
-      clientInfo.reset(new ServiceWorkerClientInfo(window->GetDocument()));
+      clientInfo.reset(new ServiceWorkerClientInfo(window->GetDocument(),
+                                                   window->GetOuterWindow()));
     }
 
     DispatchResult(Move(clientInfo));
     return NS_OK;
   }
 
 private:
   void
--- a/ipc/glue/BackgroundUtils.h
+++ b/ipc/glue/BackgroundUtils.h
@@ -6,16 +6,17 @@
 #define mozilla_ipc_backgroundutils_h__
 
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/BasePrincipal.h"
 #include "nsCOMPtr.h"
 #include "nscore.h"
 
+class nsILoadInfo;
 class nsIPrincipal;
 
 namespace IPC {
 
 template<>
 struct ParamTraits<mozilla::OriginAttributes>
 {
   typedef mozilla::OriginAttributes paramType;
--- a/layout/base/ActiveLayerTracker.cpp
+++ b/layout/base/ActiveLayerTracker.cpp
@@ -281,22 +281,17 @@ ActiveLayerTracker::IsStyleAnimated(nsDi
   if (layerActivity) {
     if (layerActivity->RestyleCountForProperty(aProperty) >= 2) {
       return true;
     }
   }
   if (aProperty == eCSSProperty_transform && aFrame->Preserves3D()) {
     return IsStyleAnimated(aBuilder, aFrame->GetParent(), aProperty);
   }
-  nsIContent* content = aFrame->GetContent();
-  if (content) {
-    return nsLayoutUtils::HasCurrentAnimationsForProperties(content, &aProperty, 1);
-  }
-
-  return false;
+  return nsLayoutUtils::HasCurrentAnimationsForProperties(aFrame, &aProperty, 1);
 }
 
 /* static */ bool
 ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(nsIFrame* aFrame)
 {
   LayerActivity* layerActivity = GetLayerActivity(aFrame);
   if (layerActivity) {
     if (layerActivity->mLeftRestyleCount >= 2 ||
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -4768,21 +4768,20 @@ ChooseScaleAndSetTransform(FrameLayerBui
   }
 
   bool canDraw2D = transform.CanDraw2D(&transform2d);
   gfxSize scale;
   // XXX Should we do something for 3D transforms?
   if (canDraw2D) {
     // If the container's transform is animated off main thread, fix a suitable scale size
     // for animation
-    if (aContainerFrame->GetContent() &&
-        aContainerItem &&
+    if (aContainerItem &&
         aContainerItem->GetType() == nsDisplayItem::TYPE_TRANSFORM &&
         nsLayoutUtils::HasAnimationsForCompositor(
-          aContainerFrame->GetContent(), eCSSProperty_transform)) {
+          aContainerFrame, eCSSProperty_transform)) {
       // Use the size of the nearest widget as the maximum size.  This
       // is important since it might be a popup that is bigger than the
       // pres context's size.
       nsPresContext* presContext = aContainerFrame->PresContext();
       nsIWidget* widget = aContainerFrame->GetNearestWidget();
       nsSize displaySize;
       if (widget) {
         IntSize widgetSize = widget->GetClientSize();
@@ -4790,17 +4789,17 @@ ChooseScaleAndSetTransform(FrameLayerBui
         displaySize.width = NSIntPixelsToAppUnits(widgetSize.width, p2a);
         displaySize.height = NSIntPixelsToAppUnits(widgetSize.height, p2a);
       } else {
         displaySize = presContext->GetVisibleArea().Size();
       }
       // compute scale using the animation on the container (ignoring
       // its ancestors)
       scale = nsLayoutUtils::ComputeSuitableScaleForAnimation(
-                aContainerFrame->GetContent(), aVisibleRect.Size(),
+                aContainerFrame, aVisibleRect.Size(),
                 displaySize);
       // multiply by the scale inherited from ancestors
       scale.width *= aIncomingScale.mXScale;
       scale.height *= aIncomingScale.mYScale;
     } else {
       // Scale factors are normalized to a power of 2 to reduce the number of resolution changes
       scale = RoundToFloatPrecision(ThebesMatrix(transform2d).ScaleFactors(true));
       // For frames with a changing transform that's not just a translation,
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -510,24 +510,21 @@ nsDisplayListBuilder::AddAnimationsAndTr
   // any early returns since even if we don't add any animations to the
   // layer, we still need to mark it as up-to-date with regards to animations.
   // Otherwise, in RestyleManager we'll notice the discrepancy between the
   // animation generation numbers and update the layer indefinitely.
   uint64_t animationGeneration =
     RestyleManager::GetMaxAnimationGenerationForFrame(aFrame);
   aLayer->SetAnimationGeneration(animationGeneration);
 
-  nsIContent* content = aFrame->GetContent();
-  if (!content) {
-    return;
-  }
+  nsPresContext* presContext = aFrame->PresContext();
   AnimationCollection* transitions =
-    nsTransitionManager::GetAnimationsForCompositor(content, aProperty);
+    presContext->TransitionManager()->GetAnimationsForCompositor(aFrame, aProperty);
   AnimationCollection* animations =
-    nsAnimationManager::GetAnimationsForCompositor(content, aProperty);
+    presContext->AnimationManager()->GetAnimationsForCompositor(aFrame, aProperty);
 
   if (!animations && !transitions) {
     return;
   }
 
   // If the frame is not prerendered, bail out.
   // Do this check only during layer construction; during updating the
   // caller is required to check it appropriately.
@@ -718,18 +715,17 @@ void nsDisplayListBuilder::MarkOutOfFlow
       clipPtr = &clip;
     }
   }
 
   nsRect dirty = dirtyRectRelativeToDirtyFrame - aFrame->GetOffsetTo(aDirtyFrame);
   nsRect overflowRect = aFrame->GetVisualOverflowRect();
 
   if (aFrame->IsTransformed() &&
-      nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
-                                                eCSSProperty_transform)) {
+      nsLayoutUtils::HasAnimationsForCompositor(aFrame, eCSSProperty_transform)) {
    /**
     * Add a fuzz factor to the overflow rectangle so that elements only just
     * out of view are pulled into the display list, so they can be
     * prerendered if necessary.
     */
     overflowRect.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
   }
 
@@ -3851,21 +3847,18 @@ IsItemTooSmallForActiveLayer(nsDisplayIt
 }
 
 bool
 nsDisplayOpacity::NeedsActiveLayer(nsDisplayListBuilder* aBuilder)
 {
   if (ActiveLayerTracker::IsStyleAnimated(aBuilder, mFrame, eCSSProperty_opacity) &&
       !IsItemTooSmallForActiveLayer(this))
     return true;
-  if (mFrame->GetContent()) {
-    if (nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(),
-                                                  eCSSProperty_opacity)) {
-      return true;
-    }
+  if (nsLayoutUtils::HasAnimationsForCompositor(mFrame, eCSSProperty_opacity)) {
+    return true;
   }
   return false;
 }
 
 void
 nsDisplayOpacity::ApplyOpacity(nsDisplayListBuilder* aBuilder,
                              float aOpacity,
                              const DisplayItemClip* aClip)
@@ -5082,19 +5075,17 @@ nsDisplayTransform::ShouldPrerenderTrans
                                                       nsIFrame* aFrame,
                                                       bool aLogAnimations)
 {
   // Elements whose transform has been modified recently, or which
   // have a compositor-animated transform, can be prerendered. An element
   // might have only just had its transform animated in which case
   // the ActiveLayerManager may not have been notified yet.
   if (!ActiveLayerTracker::IsStyleMaybeAnimated(aFrame, eCSSProperty_transform) &&
-      (!aFrame->GetContent() ||
-       !nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
-                                                  eCSSProperty_transform))) {
+      !nsLayoutUtils::HasAnimationsForCompositor(aFrame, eCSSProperty_transform)) {
     if (aLogAnimations) {
       nsCString message;
       message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for transform animation");
       AnimationCollection::LogAsyncAnimationFailure(message,
                                                     aFrame->GetContent());
     }
     return false;
   }
@@ -5240,21 +5231,18 @@ nsDisplayTransform::GetLayerState(nsDisp
   if (!GetTransform().Is2D() || mFrame->Preserves3D()) {
     return LAYER_ACTIVE_FORCE;
   }
   // Here we check if the *post-transform* bounds of this item are big enough
   // to justify an active layer.
   if (ActiveLayerTracker::IsStyleAnimated(aBuilder, mFrame, eCSSProperty_transform) &&
       !IsItemTooSmallForActiveLayer(this))
     return LAYER_ACTIVE;
-  if (mFrame->GetContent()) {
-    if (nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(),
-                                                  eCSSProperty_transform)) {
-      return LAYER_ACTIVE;
-    }
+  if (nsLayoutUtils::HasAnimationsForCompositor(mFrame, eCSSProperty_transform)) {
+    return LAYER_ACTIVE;
   }
 
   const nsStyleDisplay* disp = mFrame->StyleDisplay();
   if ((disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_TRANSFORM)) {
     return LAYER_ACTIVE;
   }
 
   // Expect the child display items to have this frame as their animated
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -367,91 +367,89 @@ TextAlignTrueEnabledPrefChangeCallback(c
   nsCSSProps::kTextAlignKTable[sIndexOfTrueInTextAlignTable] =
     isTextAlignTrueEnabled ? eCSSKeyword_true : eCSSKeyword_UNKNOWN;
   MOZ_ASSERT(sIndexOfTrueInTextAlignLastTable >= 0);
   nsCSSProps::kTextAlignLastKTable[sIndexOfTrueInTextAlignLastTable] =
     isTextAlignTrueEnabled ? eCSSKeyword_true : eCSSKeyword_UNKNOWN;
 }
 
 bool
-nsLayoutUtils::HasAnimationsForCompositor(nsIContent* aContent,
+nsLayoutUtils::HasAnimationsForCompositor(const nsIFrame* aFrame,
                                           nsCSSProperty aProperty)
 {
-  return nsAnimationManager::GetAnimationsForCompositor(aContent, aProperty) ||
-         nsTransitionManager::GetAnimationsForCompositor(aContent, aProperty);
-}
-
-static AnimationCollection*
-GetAnimationsOrTransitions(nsIContent* aContent,
-                           nsIAtom* aAnimationProperty,
-                           nsCSSProperty aProperty)
-{
+  nsPresContext* presContext = aFrame->PresContext();
+  return presContext->AnimationManager()->GetAnimationsForCompositor(aFrame, aProperty) ||
+         presContext->TransitionManager()->GetAnimationsForCompositor(aFrame, aProperty);
+}
+
+bool
+nsLayoutUtils::HasAnimations(const nsIFrame* aFrame,
+                             nsCSSProperty aProperty)
+{
+  nsPresContext* presContext = aFrame->PresContext();
   AnimationCollection* collection =
-    static_cast<AnimationCollection*>(aContent->GetProperty(
-        aAnimationProperty));
-  if (collection) {
-    bool propertyMatches = collection->HasAnimationOfProperty(aProperty);
-    if (propertyMatches) {
-      return collection;
-    }
-  }
-  return nullptr;
+    presContext->AnimationManager()->GetAnimationCollection(aFrame);
+  if (collection &&
+      collection->HasAnimationOfProperty(aProperty)) {
+    return true;
+  }
+  collection =
+    presContext->TransitionManager()->GetAnimationCollection(aFrame);
+  if (collection &&
+      collection->HasAnimationOfProperty(aProperty)) {
+    return true;
+  }
+  return false;
 }
 
 bool
-nsLayoutUtils::HasAnimations(nsIContent* aContent,
-                             nsCSSProperty aProperty)
-{
-  if (!aContent->MayHaveAnimations())
-    return false;
-  return GetAnimationsOrTransitions(aContent, nsGkAtoms::animationsProperty,
-                                    aProperty) ||
-         GetAnimationsOrTransitions(aContent, nsGkAtoms::transitionsProperty,
-                                    aProperty);
+nsLayoutUtils::HasCurrentAnimations(const nsIFrame* aFrame)
+{
+  nsPresContext* presContext = aFrame->PresContext();
+  AnimationCollection* collection =
+    presContext->AnimationManager()->GetAnimationCollection(aFrame);
+  return collection &&
+         collection->HasCurrentAnimations();
+}
+
+bool
+nsLayoutUtils::HasCurrentTransitions(const nsIFrame* aFrame)
+{
+  nsPresContext* presContext = aFrame->PresContext();
+  AnimationCollection* collection =
+    presContext->TransitionManager()->GetAnimationCollection(aFrame);
+  return collection &&
+         collection->HasCurrentAnimations();
 }
 
 bool
-nsLayoutUtils::HasCurrentAnimations(nsIContent* aContent,
-                                    nsIAtom* aAnimationProperty)
-{
-  if (!aContent->MayHaveAnimations())
-    return false;
-
-  AnimationCollection* collection =
-    static_cast<AnimationCollection*>(
-      aContent->GetProperty(aAnimationProperty));
-  return (collection && collection->HasCurrentAnimations());
-}
-
-bool
-nsLayoutUtils::HasCurrentAnimationsForProperties(nsIContent* aContent,
+nsLayoutUtils::HasCurrentAnimationsForProperties(const nsIFrame* aFrame,
                                                  const nsCSSProperty* aProperties,
                                                  size_t aPropertyCount)
 {
-  if (!aContent->MayHaveAnimations())
-    return false;
-
-  static nsIAtom* const sAnimProps[] = { nsGkAtoms::transitionsProperty,
-                                         nsGkAtoms::animationsProperty,
-                                         nullptr };
-  for (nsIAtom* const* animProp = sAnimProps; *animProp; animProp++) {
-    AnimationCollection* collection =
-      static_cast<AnimationCollection*>(aContent->GetProperty(*animProp));
-    if (collection &&
-        collection->HasCurrentAnimationsForProperties(aProperties,
-                                                      aPropertyCount)) {
-      return true;
-    }
-  }
-
+  nsPresContext* presContext = aFrame->PresContext();
+  AnimationCollection* collection =
+    presContext->AnimationManager()->GetAnimationCollection(aFrame);
+  if (collection &&
+      collection->HasCurrentAnimationsForProperties(aProperties,
+                                                    aPropertyCount)) {
+    return true;
+  }
+  collection =
+    presContext->TransitionManager()->GetAnimationCollection(aFrame);
+  if (collection &&
+      collection->HasCurrentAnimationsForProperties(aProperties,
+                                                    aPropertyCount)) {
+    return true;
+  }
   return false;
 }
 
 static gfxSize
-GetScaleForValue(const StyleAnimationValue& aValue, nsIFrame* aFrame)
+GetScaleForValue(const StyleAnimationValue& aValue, const nsIFrame* aFrame)
 {
   if (!aFrame) {
     NS_WARNING("No frame.");
     return gfxSize();
   }
   if (aValue.GetUnit() != StyleAnimationValue::eUnit_Transform) {
     NS_WARNING("Expected a transform.");
     return gfxSize();
@@ -486,73 +484,72 @@ GetSuitableScale(float aMaxScale, float 
   // We want to rasterize based on the largest scale used during the
   // transform animation, unless that would make us rasterize something
   // larger than the screen.  But we never want to go smaller than the
   // minimum scale over the animation.
   return std::max(std::min(aMaxScale, displayVisibleRatio), aMinScale);
 }
 
 static void
-GetMinAndMaxScaleForAnimationProperty(nsIContent* aContent,
+GetMinAndMaxScaleForAnimationProperty(const nsIFrame* aFrame,
                                       AnimationCollection* aAnimations,
                                       gfxSize& aMaxScale,
                                       gfxSize& aMinScale)
 {
   for (size_t animIdx = aAnimations->mAnimations.Length(); animIdx-- != 0; ) {
     dom::Animation* anim = aAnimations->mAnimations[animIdx];
     if (!anim->GetEffect() || anim->GetEffect()->IsFinishedTransition()) {
       continue;
     }
     dom::KeyframeEffectReadOnly* effect = anim->GetEffect();
     for (size_t propIdx = effect->Properties().Length(); propIdx-- != 0; ) {
       AnimationProperty& prop = effect->Properties()[propIdx];
       if (prop.mProperty == eCSSProperty_transform) {
         for (uint32_t segIdx = prop.mSegments.Length(); segIdx-- != 0; ) {
           AnimationPropertySegment& segment = prop.mSegments[segIdx];
-          gfxSize from = GetScaleForValue(segment.mFromValue,
-                                          aContent->GetPrimaryFrame());
+          gfxSize from = GetScaleForValue(segment.mFromValue, aFrame);
           aMaxScale.width = std::max<float>(aMaxScale.width, from.width);
           aMaxScale.height = std::max<float>(aMaxScale.height, from.height);
           aMinScale.width = std::min<float>(aMinScale.width, from.width);
           aMinScale.height = std::min<float>(aMinScale.height, from.height);
-          gfxSize to = GetScaleForValue(segment.mToValue,
-                                        aContent->GetPrimaryFrame());
+          gfxSize to = GetScaleForValue(segment.mToValue, aFrame);
           aMaxScale.width = std::max<float>(aMaxScale.width, to.width);
           aMaxScale.height = std::max<float>(aMaxScale.height, to.height);
           aMinScale.width = std::min<float>(aMinScale.width, to.width);
           aMinScale.height = std::min<float>(aMinScale.height, to.height);
         }
       }
     }
   }
 }
 
 gfxSize
-nsLayoutUtils::ComputeSuitableScaleForAnimation(nsIContent* aContent,
+nsLayoutUtils::ComputeSuitableScaleForAnimation(const nsIFrame* aFrame,
                                                 const nsSize& aVisibleSize,
                                                 const nsSize& aDisplaySize)
 {
   gfxSize maxScale(std::numeric_limits<gfxFloat>::min(),
                    std::numeric_limits<gfxFloat>::min());
   gfxSize minScale(std::numeric_limits<gfxFloat>::max(),
                    std::numeric_limits<gfxFloat>::max());
+  nsPresContext* presContext = aFrame->PresContext();
 
   AnimationCollection* animations =
-    nsAnimationManager::GetAnimationsForCompositor(aContent,
-                                                   eCSSProperty_transform);
+    presContext->AnimationManager()->GetAnimationsForCompositor(
+      aFrame, eCSSProperty_transform);
   if (animations) {
-    GetMinAndMaxScaleForAnimationProperty(aContent, animations,
+    GetMinAndMaxScaleForAnimationProperty(aFrame, animations,
                                           maxScale, minScale);
   }
 
   animations =
-    nsTransitionManager::GetAnimationsForCompositor(aContent,
-                                                    eCSSProperty_transform);
+    presContext->TransitionManager()->GetAnimationsForCompositor(
+      aFrame, eCSSProperty_transform);
   if (animations) {
-    GetMinAndMaxScaleForAnimationProperty(aContent, animations,
+    GetMinAndMaxScaleForAnimationProperty(aFrame, animations,
                                           maxScale, minScale);
   }
 
   if (maxScale.width == std::numeric_limits<gfxFloat>::min()) {
     // We didn't encounter a transform
     return gfxSize(1.0, 1.0);
   }
 
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2130,67 +2130,83 @@ public:
    *    (void)SizeOfTextRunsForFrames(rootFrame, nullptr, true);
    *    total = SizeOfTextRunsForFrames(rootFrame, mallocSizeOf, false);
    */
   static size_t SizeOfTextRunsForFrames(nsIFrame* aFrame,
                                         mozilla::MallocSizeOf aMallocSizeOf,
                                         bool clear);
 
   /**
-   * Returns true if the content node has animations or transitions that can be
+   * Given a frame with possibly animated content, finds the content node
+   * that contains its animations as well as the frame's pseudo-element type
+   * relative to the resulting content node. Returns true if animated content
+   * was found, otherwise it returns false and the output parameters are
+   * undefined.
+   */
+  static bool GetAnimationContent(const nsIFrame* aFrame,
+                                  nsIContent* &aContentResult,
+                                  nsCSSPseudoElements::Type &aPseudoTypeResult);
+
+  /**
+   * Returns true if the frame has animations or transitions that can be
    * performed on the compositor.
    */
-  static bool HasAnimationsForCompositor(nsIContent* aContent,
+  static bool HasAnimationsForCompositor(const nsIFrame* aFrame,
                                          nsCSSProperty aProperty);
 
   /**
-   * Returns true if the content node has animations or transitions for the
+   * Returns true if the frame has animations or transitions for the
    * property.
    */
-  static bool HasAnimations(nsIContent* aContent, nsCSSProperty aProperty);
+  static bool HasAnimations(const nsIFrame* aFrame, nsCSSProperty aProperty);
 
   /**
-   * Returns true if the content node has any current animations or transitions
-   * (depending on the value of |aAnimationProperty|).
+   * Returns true if the frame has any current animations.
    * A current animation is any animation that has not yet finished playing
    * including paused animations.
    */
-  static bool HasCurrentAnimations(nsIContent* aContent,
-                                   nsIAtom* aAnimationProperty);
+  static bool HasCurrentAnimations(const nsIFrame* aFrame);
 
   /**
-   * Returns true if the content node has any current animations or transitions
+   * Returns true if the frame has any current transitions.
+   * A current transition is any transition that has not yet finished playing
+   * including paused transitions.
+   */
+  static bool HasCurrentTransitions(const nsIFrame* aFrame);
+
+  /**
+   * Returns true if the frame has any current animations or transitions
    * for any of the specified properties.
    */
-  static bool HasCurrentAnimationsForProperties(nsIContent* aContent,
+  static bool HasCurrentAnimationsForProperties(const nsIFrame* aFrame,
                                                 const nsCSSProperty* aProperties,
                                                 size_t aPropertyCount);
 
   /**
    * Checks if off-main-thread animations are enabled.
    */
   static bool AreAsyncAnimationsEnabled();
 
   /**
    * Checks if we should warn about animations that can't be async
    */
   static bool IsAnimationLoggingEnabled();
 
   /**
-   * Find a suitable scale for an element (aContent) over the course of any
+   * Find a suitable scale for a element (aFrame's content) over the course of any
    * animations and transitions of the CSS transform property on the
    * element that run on the compositor thread.
    * It will check the maximum and minimum scale during the animations and
    * transitions and return a suitable value for performance and quality.
    * Will return scale(1,1) if there are no such animations.
    * Always returns a positive value.
    * @param aVisibleSize is the size of the area we want to paint
    * @param aDisplaySize is the size of the display area of the pres context
    */
-  static gfxSize ComputeSuitableScaleForAnimation(nsIContent* aContent,
+  static gfxSize ComputeSuitableScaleForAnimation(const nsIFrame* aFrame,
                                                   const nsSize& aVisibleSize,
                                                   const nsSize& aDisplaySize);
 
   /**
    * Checks if we should forcibly use nearest pixel filtering for the
    * background.
    */
   static bool UseBackgroundNearestFiltering();
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -22,16 +22,17 @@
 // mmsystem isn't part of WIN32_LEAN_AND_MEAN, so we have
 // to manually include it
 #include <mmsystem.h>
 #include "WinUtils.h"
 #endif
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/AutoRestore.h"
+#include "mozilla/IntegerRange.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "nsRefreshDriver.h"
 #include "nsITimer.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsComponentManagerUtils.h"
 #include "mozilla/Logging.h"
 #include "nsAutoPtr.h"
@@ -1336,16 +1337,17 @@ nsRefreshDriver::ObserverCount() const
   }
 
   // Even while throttled, we need to process layout and style changes.  Style
   // changes can trigger transitions which fire events when they complete, and
   // layout changes can affect media queries on child documents, triggering
   // style changes, etc.
   sum += mStyleFlushObservers.Length();
   sum += mLayoutFlushObservers.Length();
+  sum += mPendingEvents.Length();
   sum += mFrameRequestCallbackDocs.Length();
   sum += mThrottledFrameRequestCallbackDocs.Length();
   sum += mViewManagerFlushIsPending;
   return sum;
 }
 
 /* static */ PLDHashOperator
 nsRefreshDriver::StartTableRequestCounter(const uint32_t& aKey,
@@ -1472,16 +1474,27 @@ static void
 TakeFrameRequestCallbacksFrom(nsIDocument* aDocument,
                               nsTArray<DocumentFrameCallbacks>& aTarget)
 {
   aTarget.AppendElement(aDocument);
   aDocument->TakeFrameRequestCallbacks(aTarget.LastElement().mCallbacks);
 }
 
 void
+nsRefreshDriver::DispatchPendingEvents()
+{
+  // Swap out the current pending events
+  nsTArray<PendingEvent> pendingEvents(Move(mPendingEvents));
+  for (PendingEvent& event : pendingEvents) {
+    bool dummy;
+    event.mTarget->DispatchEvent(event.mEvent, &dummy);
+  }
+}
+
+void
 nsRefreshDriver::RunFrameRequestCallbacks(int64_t aNowEpoch, TimeStamp aNowTime)
 {
   // Grab all of our frame request callbacks up front.
   nsTArray<DocumentFrameCallbacks>
     frameRequestCallbacks(mFrameRequestCallbackDocs.Length() +
                           mThrottledFrameRequestCallbackDocs.Length());
 
   // First, grab throttled frame request callbacks.
@@ -1652,16 +1665,17 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
         StopTimer();
         return;
       }
     }
 
     if (i == 0) {
       // This is the Flush_Style case.
 
+      DispatchPendingEvents();
       RunFrameRequestCallbacks(aNowEpoch, aNowTime);
 
       if (mPresContext && mPresContext->GetPresShell()) {
         bool tracingStyleFlush = false;
         nsAutoTArray<nsIPresShell*, 16> observers;
         observers.AppendElements(mStyleFlushObservers);
         for (uint32_t j = observers.Length();
              j && mPresContext && mPresContext->GetPresShell(); --j) {
@@ -2126,9 +2140,27 @@ nsRefreshDriver::RevokeFrameRequestCallb
 {
   mFrameRequestCallbackDocs.RemoveElement(aDocument);
   mThrottledFrameRequestCallbackDocs.RemoveElement(aDocument);
   ConfigureHighPrecision();
   // No need to worry about restarting our timer in slack mode if it's already
   // running; that will happen automatically when it fires.
 }
 
+void
+nsRefreshDriver::ScheduleEventDispatch(nsINode* aTarget, nsIDOMEvent* aEvent)
+{
+  mPendingEvents.AppendElement(PendingEvent{aTarget, aEvent});
+  // make sure that the timer is running
+  EnsureTimerStarted();
+}
+
+void
+nsRefreshDriver::CancelPendingEvents(nsIDocument* aDocument)
+{
+  for (auto i : Reversed(MakeRange(mPendingEvents.Length()))) {
+    if (mPendingEvents[i].mTarget->OwnerDoc() == aDocument) {
+      mPendingEvents.RemoveElementAt(i);
+    }
+  }
+}
+
 #undef LOG
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -24,16 +24,18 @@
 #include "mozilla/Maybe.h"
 #include "GeckoProfiler.h"
 #include "mozilla/layers/TransactionIdAllocator.h"
 
 class nsPresContext;
 class nsIPresShell;
 class nsIDocument;
 class imgIRequest;
+class nsIDOMEvent;
+class nsINode;
 
 namespace mozilla {
 class RefreshDriverTimer;
 namespace layout {
 class VsyncChild;
 }
 }
 
@@ -218,16 +220,27 @@ public:
   void ScheduleFrameRequestCallbacks(nsIDocument* aDocument);
 
   /**
    * Remove a document for which we have nsIFrameRequestCallbacks
    */
   void RevokeFrameRequestCallbacks(nsIDocument* aDocument);
 
   /**
+   * Queue a new event to dispatch in next tick before the style flush
+   */
+  void ScheduleEventDispatch(nsINode* aTarget, nsIDOMEvent* aEvent);
+
+  /**
+   * Cancel all pending events scheduled by ScheduleEventDispatch which
+   * targets any node in aDocument.
+   */
+  void CancelPendingEvents(nsIDocument* aDocument);
+
+  /**
    * Tell the refresh driver that it is done driving refreshes and
    * should stop its timer and forget about its pres context.  This may
    * be called from within a refresh.
    */
   void Disconnect() {
     StopTimer();
     mPresContext = nullptr;
   }
@@ -303,16 +316,17 @@ private:
     {
     }
 
     mozilla::Maybe<mozilla::TimeStamp> mStartTime;
     RequestTable mEntries;
   };
   typedef nsClassHashtable<nsUint32HashKey, ImageStartData> ImageStartTable;
 
+  void DispatchPendingEvents();
   void RunFrameRequestCallbacks(int64_t aNowEpoch, mozilla::TimeStamp aNowTime);
 
   void Tick(int64_t aNowEpoch, mozilla::TimeStamp aNowTime);
 
   enum EnsureTimerStartedFlags {
     eNone = 0,
     eAdjustingTimer = 1 << 0,
     eAllowTimeToGoBackwards = 1 << 1
@@ -398,23 +412,29 @@ private:
   mozilla::TimeStamp mNextThrottledFrameRequestTick;
   mozilla::TimeStamp mNextRecomputeVisibilityTick;
 
   // separate arrays for each flush type we support
   ObserverArray mObservers[3];
   RequestTable mRequests;
   ImageStartTable mStartTable;
 
+  struct PendingEvent {
+    nsCOMPtr<nsINode> mTarget;
+    nsCOMPtr<nsIDOMEvent> mEvent;
+  };
+
   nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
   nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
   nsAutoTArray<nsIPresShell*, 16> mPresShellsToInvalidateIfHidden;
   // nsTArray on purpose, because we want to be able to swap.
   nsTArray<nsIDocument*> mFrameRequestCallbackDocs;
   nsTArray<nsIDocument*> mThrottledFrameRequestCallbackDocs;
   nsTObserverArray<nsAPostRefreshObserver*> mPostRefreshObservers;
+  nsTArray<PendingEvent> mPendingEvents;
 
   // Helper struct for processing image requests
   struct ImageRequestParameters {
     mozilla::TimeStamp mCurrent;
     mozilla::TimeStamp mPrevious;
     RequestTable* mRequests;
     mozilla::TimeStamp mDesired;
   };
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1077,31 +1077,31 @@ nsIFrame::GetMarginRectRelativeToSelf() 
 
 bool
 nsIFrame::IsTransformed() const
 {
   return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
           (StyleDisplay()->HasTransform(this) ||
            IsSVGTransformed() ||
            (mContent &&
-            nsLayoutUtils::HasAnimationsForCompositor(mContent,
+            nsLayoutUtils::HasAnimationsForCompositor(this,
                                                       eCSSProperty_transform) &&
             IsFrameOfType(eSupportsCSSTransforms) &&
             mContent->GetPrimaryFrame() == this)));
 }
 
 bool
 nsIFrame::HasOpacityInternal(float aThreshold) const
 {
   MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument");
   const nsStyleDisplay* displayStyle = StyleDisplay();
   return StyleDisplay()->mOpacity < aThreshold ||
          (displayStyle->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) ||
          (mContent &&
-           nsLayoutUtils::HasAnimationsForCompositor(mContent,
+           nsLayoutUtils::HasAnimationsForCompositor(this,
                                                      eCSSProperty_opacity) &&
            mContent->GetPrimaryFrame() == this);
 }
 
 bool
 nsIFrame::IsSVGTransformed(gfx::Matrix *aOwnTransforms,
                            gfx::Matrix *aFromParentTransforms) const
 {
@@ -1941,17 +1941,17 @@ nsIFrame::BuildDisplayListForStackingCon
   // we're painting, and we're not animating opacity. Don't do this
   // if we're going to compute plugin geometry, since opacity-0 plugins
   // need to have display items built for them.
   bool needEventRegions = aBuilder->IsBuildingLayerEventRegions() &&
       StyleVisibility()->GetEffectivePointerEvents(this) != NS_STYLE_POINTER_EVENTS_NONE;
   if (disp->mOpacity == 0.0 && aBuilder->IsForPainting() &&
       !aBuilder->WillComputePluginGeometry() &&
       !(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) &&
-      !nsLayoutUtils::HasAnimations(mContent, eCSSProperty_opacity) &&
+      !nsLayoutUtils::HasAnimations(this, eCSSProperty_opacity) &&
       !needEventRegions) {
     return;
   }
 
   if (disp->mWillChangeBitField != 0) {
     aBuilder->AddToWillChangeBudget(this, GetSize());
   }
 
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -2586,17 +2586,17 @@ public:
   virtual bool IsSelfEmpty() = 0;
 
   /**
    * IsGeneratedContentFrame returns whether a frame corresponds to
    * generated content
    *
    * @return whether the frame correspods to generated content
    */
-  bool IsGeneratedContentFrame() {
+  bool IsGeneratedContentFrame() const {
     return (mState & NS_FRAME_GENERATED_CONTENT) != 0;
   }
 
   /**
    * IsPseudoFrame returns whether a frame is a pseudo frame (eg an
    * anonymous table-row frame created for a CSS table-cell without an
    * enclosing table-row.
    *
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -129,25 +129,55 @@ CommonAnimationManager::NeedsRefresh() c
     if (static_cast<AnimationCollection*>(l)->mNeedsRefreshes) {
       return true;
     }
   }
   return false;
 }
 
 AnimationCollection*
-CommonAnimationManager::GetAnimationsForCompositor(nsIContent* aContent,
-                                                   nsIAtom* aElementProperty,
+CommonAnimationManager::GetAnimationCollection(const nsIFrame* aFrame)
+{
+  nsIContent* content = aFrame->GetContent();
+  if (!content) {
+    return nullptr;
+  }
+  nsIAtom* animProp;
+  if (aFrame->IsGeneratedContentFrame()) {
+    nsIFrame* parent = aFrame->GetParent();
+    if (parent->IsGeneratedContentFrame()) {
+      return nullptr;
+    }
+    nsIAtom* name = content->NodeInfo()->NameAtom();
+    if (name == nsGkAtoms::mozgeneratedcontentbefore) {
+      animProp = GetAnimationsBeforeAtom();
+    } else if (name == nsGkAtoms::mozgeneratedcontentafter) {
+      animProp = GetAnimationsAfterAtom();
+    } else {
+      return nullptr;
+    }
+    content = content->GetParent();
+    if (!content) {
+      return nullptr;
+    }
+  } else {
+    if (!content->MayHaveAnimations()) {
+      return nullptr;
+    }
+    animProp = GetAnimationsAtom();
+  }
+
+  return static_cast<AnimationCollection*>(content->GetProperty(animProp));
+}
+
+AnimationCollection*
+CommonAnimationManager::GetAnimationsForCompositor(const nsIFrame* aFrame,
                                                    nsCSSProperty aProperty)
 {
-  if (!aContent->MayHaveAnimations())
-    return nullptr;
-
-  AnimationCollection* collection =
-    static_cast<AnimationCollection*>(aContent->GetProperty(aElementProperty));
+  AnimationCollection* collection = GetAnimationCollection(aFrame);
   if (!collection ||
       !collection->HasAnimationOfProperty(aProperty) ||
       !collection->CanPerformOnCompositorThread(
         AnimationCollection::CanAnimate_AllowPartial)) {
     return nullptr;
   }
 
   // This animation can be done on the compositor.
@@ -332,21 +362,22 @@ CommonAnimationManager::GetAnimations(do
   if (!collection && aCreateIfNeeded) {
     // FIXME: Consider arena-allocating?
     collection = new AnimationCollection(aElement, propName, this);
     nsresult rv =
       aElement->SetProperty(propName, collection,
                             &AnimationCollection::PropertyDtor, false);
     if (NS_FAILED(rv)) {
       NS_WARNING("SetProperty failed");
-      delete collection;
+      // The collection must be destroyed via PropertyDtor, otherwise
+      // mCalledPropertyDtor assertion is triggered in destructor.
+      AnimationCollection::PropertyDtor(aElement, propName, collection, nullptr);
       return nullptr;
     }
-    if (propName == nsGkAtoms::animationsProperty ||
-        propName == nsGkAtoms::transitionsProperty) {
+    if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
       aElement->SetMayHaveAnimations();
     }
 
     AddElementCollection(collection);
   }
 
   return collection;
 }
@@ -572,31 +603,22 @@ AnimationCollection::IsCompositorAnimati
   void* prop = aFrame->Properties().Get(nsIFrame::RefusedAsyncAnimation());
   return bool(reinterpret_cast<intptr_t>(prop));
 }
 
 bool
 AnimationCollection::CanPerformOnCompositorThread(
   CanAnimateFlags aFlags) const
 {
-  nsIFrame* frame = nsLayoutUtils::GetStyleFrame(mElement);
-  if (!frame) {
+  dom::Element* element = GetElementToRestyle();
+  if (!element) {
     return false;
   }
-
-  if (mElementProperty != nsGkAtoms::transitionsProperty &&
-      mElementProperty != nsGkAtoms::animationsProperty) {
-    if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
-      nsCString message;
-      message.AppendLiteral("Gecko bug: Async animation of pseudoelements"
-                            " not supported.  See bug 771367 (");
-      message.Append(nsAtomCString(mElementProperty));
-      message.Append(")");
-      LogAsyncAnimationFailure(message, mElement);
-    }
+  nsIFrame* frame = nsLayoutUtils::GetStyleFrame(element);
+  if (!frame) {
     return false;
   }
 
   for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
     const Animation* anim = mAnimations[animIdx];
     if (!anim->IsPlaying()) {
       continue;
     }
@@ -623,17 +645,17 @@ AnimationCollection::CanPerformOnComposi
     const KeyframeEffectReadOnly* effect = anim->GetEffect();
     MOZ_ASSERT(effect, "A playing animation should have an effect");
 
     existsProperty = existsProperty || effect->Properties().Length() > 0;
 
     for (size_t propIdx = 0, propEnd = effect->Properties().Length();
          propIdx != propEnd; ++propIdx) {
       const AnimationProperty& prop = effect->Properties()[propIdx];
-      if (!CanAnimatePropertyOnCompositor(mElement,
+      if (!CanAnimatePropertyOnCompositor(element,
                                           prop.mProperty,
                                           aFlags) ||
           IsCompositorAnimationDisabledForFrame(frame)) {
         return false;
       }
     }
   }
 
@@ -834,20 +856,25 @@ AnimationCollection::CanThrottleTransfor
   }
 
   // If this animation can cause overflow, we can throttle some of the ticks.
   if (!mStyleRuleRefreshTime.IsNull() &&
       (aTime - mStyleRuleRefreshTime) < TimeDuration::FromMilliseconds(200)) {
     return true;
   }
 
+  dom::Element* element = GetElementToRestyle();
+  if (!element) {
+    return false;
+  }
+
   // If the nearest scrollable ancestor has overflow:hidden,
   // we don't care about overflow.
   nsIScrollableFrame* scrollable = nsLayoutUtils::GetNearestScrollableFrame(
-                                     nsLayoutUtils::GetStyleFrame(mElement));
+                                     nsLayoutUtils::GetStyleFrame(element));
   if (!scrollable) {
     return true;
   }
 
   ScrollbarStyles ss = scrollable->GetScrollbarStyles();
   if (ss.mVertical == NS_STYLE_OVERFLOW_HIDDEN &&
       ss.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN &&
       scrollable->GetLogicalScrollPosition() == nsPoint(0, 0)) {
@@ -855,17 +882,21 @@ AnimationCollection::CanThrottleTransfor
   }
 
   return false;
 }
 
 bool
 AnimationCollection::CanThrottleAnimation(TimeStamp aTime)
 {
-  nsIFrame* frame = nsLayoutUtils::GetStyleFrame(mElement);
+  dom::Element* element = GetElementToRestyle();
+  if (!element) {
+    return false;
+  }
+  nsIFrame* frame = nsLayoutUtils::GetStyleFrame(element);
   if (!frame) {
     return false;
   }
 
 
   const auto& info = css::CommonAnimationManager::sLayerAnimationInfo;
   for (size_t i = 0; i < ArrayLength(info); i++) {
     auto record = info[i];
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -156,29 +156,36 @@ protected:
   virtual nsIAtom* GetAnimationsAtom() = 0;
   virtual nsIAtom* GetAnimationsBeforeAtom() = 0;
   virtual nsIAtom* GetAnimationsAfterAtom() = 0;
 
   virtual bool IsAnimationManager() {
     return false;
   }
 
+
+public:
   // Return an AnimationCollection* if we have an animation for
-  // the element aContent and pseudo-element indicator aElementProperty
-  // that can be performed on the compositor thread (as defined by 
-  // AnimationCollection::CanPerformOnCompositorThread).
+  // the frame aFrame that can be performed on the compositor thread (as
+  // defined by AnimationCollection::CanPerformOnCompositorThread).
   //
-  // Note that this does not test whether the element's layer uses
+  // Note that this does not test whether the frame's layer uses
   // off-main-thread compositing, although it does check whether
   // off-main-thread compositing is enabled as a whole.
-  static AnimationCollection*
-  GetAnimationsForCompositor(nsIContent* aContent,
-                             nsIAtom* aElementProperty,
+  AnimationCollection*
+  GetAnimationsForCompositor(const nsIFrame* aFrame,
                              nsCSSProperty aProperty);
 
+  // Given the frame aFrame with possibly animated content, finds its
+  // associated collection of animations. If it is a generated content
+  // frame, it may examine the parent frame to search for such animations.
+  AnimationCollection*
+  GetAnimationCollection(const nsIFrame* aFrame);
+
+protected:
   PRCList mElementCollections;
   nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect)
   bool mIsObservingRefreshDriver;
 };
 
 /**
  * A style rule that maps property-StyleAnimationValue pairs.
  */
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -158,23 +158,16 @@ class nsAnimationManager final
   : public mozilla::css::CommonAnimationManager
 {
 public:
   explicit nsAnimationManager(nsPresContext *aPresContext)
     : mozilla::css::CommonAnimationManager(aPresContext)
   {
   }
 
-  static mozilla::AnimationCollection*
-  GetAnimationsForCompositor(nsIContent* aContent, nsCSSProperty aProperty)
-  {
-    return mozilla::css::CommonAnimationManager::GetAnimationsForCompositor(
-      aContent, nsGkAtoms::animationsProperty, aProperty);
-  }
-
   void UpdateStyleAndEvents(mozilla::AnimationCollection* aEA,
                             mozilla::TimeStamp aRefreshTime,
                             mozilla::EnsureStyleRuleFlags aFlags);
   void QueueEvents(mozilla::AnimationCollection* aEA,
                    mozilla::EventArray &aEventsToDispatch);
 
   void MaybeUpdateCascadeResults(mozilla::AnimationCollection* aCollection);
 
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -112,23 +112,16 @@ public:
   explicit nsTransitionManager(nsPresContext *aPresContext)
     : mozilla::css::CommonAnimationManager(aPresContext)
     , mInAnimationOnlyStyleUpdate(false)
   {
   }
 
   typedef mozilla::AnimationCollection AnimationCollection;
 
-  static AnimationCollection*
-  GetAnimationsForCompositor(nsIContent* aContent, nsCSSProperty aProperty)
-  {
-    return mozilla::css::CommonAnimationManager::GetAnimationsForCompositor(
-      aContent, nsGkAtoms::transitionsProperty, aProperty);
-  }
-
   /**
    * StyleContextChanged
    *
    * To be called from nsFrameManager::ReResolveStyleContext when the
    * style of an element has changed, to initiate transitions from
    * that style change.  For style contexts with :before and :after
    * pseudos, aElement is expected to be the generated before/after
    * element.
--- a/layout/style/test/animation_utils.js
+++ b/layout/style/test/animation_utils.js
@@ -399,29 +399,33 @@ const RunningOn = {
 };
 
 const ExpectComparisonTo = {
   Pass: 1,
   Fail: 2
 };
 
 (function() {
-  window.omta_todo_is = function(elem, property, expected, runningOn, desc) {
+  window.omta_todo_is = function(elem, property, expected, runningOn, desc,
+                                 pseudo) {
     return omta_is_approx(elem, property, expected, 0, runningOn, desc,
-                          ExpectComparisonTo.Fail);
+                          ExpectComparisonTo.Fail, pseudo);
   };
 
-  window.omta_is = function(elem, property, expected, runningOn, desc) {
-    return omta_is_approx(elem, property, expected, 0, runningOn, desc);
+  window.omta_is = function(elem, property, expected, runningOn, desc,
+                            pseudo) {
+    return omta_is_approx(elem, property, expected, 0, runningOn, desc,
+                          ExpectComparisonTo.Pass, pseudo);
   };
 
   // Many callers of this method will pass 'undefined' for
   // expectedComparisonResult.
   window.omta_is_approx = function(elem, property, expected, tolerance,
-                                   runningOn, desc, expectedComparisonResult) {
+                                   runningOn, desc, expectedComparisonResult,
+                                   pseudo) {
     // Check input
     const omtaProperties = [ "transform", "opacity" ];
     if (omtaProperties.indexOf(property) === -1) {
       ok(false, property + " is not an OMTA property");
       return;
     }
     var isTransform = property == "transform";
     var normalize = isTransform ? convertTo3dMatrix : parseFloat;
@@ -429,18 +433,18 @@ const ExpectComparisonTo = {
                   matricesRoughlyEqual :
                   function(a, b, error) { return Math.abs(a - b) <= error; };
     var normalizedToString = isTransform ?
                              convert3dMatrixToString :
                              JSON.stringify;
 
     // Get actual values
     var compositorStr =
-      SpecialPowers.DOMWindowUtils.getOMTAStyle(elem, property);
-    var computedStr = window.getComputedStyle(elem)[property];
+      SpecialPowers.DOMWindowUtils.getOMTAStyle(elem, property, pseudo);
+    var computedStr = window.getComputedStyle(elem, pseudo)[property];
 
     // Prepare expected value
     var expectedValue = normalize(expected);
     if (expectedValue === null) {
       ok(false, desc + ": test author should provide a valid 'expected' value" +
                 " - got " + expected.toString());
       return;
     }
--- a/layout/style/test/test_animations_omta.html
+++ b/layout/style/test/test_animations_omta.html
@@ -81,16 +81,22 @@ https://bugzilla.mozilla.org/show_bug.cg
       75%  { transform: translate(120px); animation-timing-function: linear }
       100% { transform: translate(20px); animation-timing-function: ease-out }
     }
 
     @keyframes always_fifty {
       from, to { transform: translate(50px) }
     }
 
+    #withbefore::before, #withafter::after {
+      content: "test";
+      animation: anim4 1s linear alternate 3;
+      display:block;
+    }
+
     @keyframes multiprop {
       0% {
         transform: translate(10px); opacity: 0.3;
         animation-timing-function: ease;
       }
       25% {
         opacity: 0.5;
         animation-timing-function: ease-out;
@@ -1431,18 +1437,82 @@ addAsyncAnimTest(function *() {
 
 // animation-fill-mode is tested in the tests for section (2).
 
 /*
  * css3-animations:  3.10. The 'animation' Shorthand Property
  * http://dev.w3.org/csswg/css3-animations/#the-animation-shorthand-property-
  */
 
-// (Unlike test_animations.html, pseudo-elements are not tested here since they
-//  are currently not run on the compositor thread.)
+/**
+ * Basic tests of animations on pseudo-elements
+ */
+addAsyncAnimTest(function *() {
+  new_div("");
+  listen();
+  gDiv.id = "withbefore";
+  yield waitForPaintsFlushed();
+  omta_is("transform", { ty: 0 }, RunningOn.Compositor,
+          ":before test at 0ms", "::before");
+  advance_clock(400);
+  omta_is("transform", { ty: 40 }, RunningOn.Compositor,
+          ":before test at 400ms", "::before");
+  advance_clock(800);
+  omta_is("transform", { ty: 80 }, RunningOn.Compositor,
+          ":before test at 1200ms", "::before");
+  omta_is("transform", { ty: 0 }, RunningOn.MainThread,
+          ":before animation should not affect element");
+  advance_clock(800);
+  omta_is("transform", { ty: 0 }, RunningOn.Compositor,
+          ":before test at 2000ms", "::before");
+  advance_clock(300);
+  omta_is("transform", { ty: 30 }, RunningOn.Compositor,
+          ":before test at 2300ms", "::before");
+  advance_clock(700);
+  check_events([ { type: "animationstart", animationName: "anim4",
+                   elapsedTime: 0, pseudoElement: "::before" },
+                 { type: "animationiteration", animationName: "anim4",
+                   elapsedTime: 1, pseudoElement: "::before" },
+                 { type: "animationiteration", animationName: "anim4",
+                   elapsedTime: 2, pseudoElement: "::before" },
+                 { type: "animationend", animationName: "anim4",
+                   elapsedTime: 3, pseudoElement: "::before" }]);
+  done_div();
+
+  new_div("");
+  listen();
+  gDiv.id = "withafter";
+  yield waitForPaintsFlushed();
+  omta_is("transform", { ty: 0 }, RunningOn.Compositor,
+          ":after test at 0ms", "::after");
+  advance_clock(400);
+  omta_is("transform", { ty: 40 }, RunningOn.Compositor,
+          ":after test at 400ms", "::after");
+  advance_clock(800);
+  omta_is("transform", { ty: 80 }, RunningOn.Compositor,
+          ":after test at 1200ms", "::after");
+  omta_is("transform", { ty: 0 }, RunningOn.MainThread,
+          ":before animation should not affect element");
+  advance_clock(800);
+  omta_is("transform", { ty: 0 }, RunningOn.Compositor,
+          ":after test at 2000ms", "::after");
+  advance_clock(300);
+  omta_is("transform", { ty: 30 }, RunningOn.Compositor,
+          ":after test at 2300ms", "::after");
+  advance_clock(700);
+  check_events([ { type: "animationstart", animationName: "anim4",
+                   elapsedTime: 0, pseudoElement: "::after" },
+                 { type: "animationiteration", animationName: "anim4",
+                   elapsedTime: 1, pseudoElement: "::after" },
+                 { type: "animationiteration", animationName: "anim4",
+                   elapsedTime: 2, pseudoElement: "::after" },
+                 { type: "animationend", animationName: "anim4",
+                   elapsedTime: 3, pseudoElement: "::after" }]);
+  done_div();
+});
 
 /**
  * Test handling of properties that are present in only some of the
  * keyframes.
  */
 addAsyncAnimTest(function *() {
   new_div("animation: multiprop 1s ease-in-out alternate infinite");
   yield waitForPaintsFlushed();
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -516,18 +516,17 @@ nsMenuPopupFrame::LayoutPopup(nsBoxLayou
   if (mIsOpenChanged) {
     mIsOpenChanged = false;
 
 #ifndef MOZ_WIDGET_GTK
     // If the animate attribute is set to open, check for a transition and wait
     // for it to finish before firing the popupshown event.
     if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::animate,
                               nsGkAtoms::open, eCaseMatters) &&
-        nsLayoutUtils::HasCurrentAnimations(mContent,
-                                            nsGkAtoms::transitionsProperty)) {
+        nsLayoutUtils::HasCurrentTransitions(this)) {
       mPopupShownDispatcher = new nsXULPopupShownEvent(mContent, pc);
       mContent->AddSystemEventListener(NS_LITERAL_STRING("transitionend"),
                                        mPopupShownDispatcher, false, false);
       return;
     }
 #endif
 
     // If there are no transitions, fire the popupshown event right away.
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -1468,18 +1468,17 @@ nsXULPopupManager::FirePopupHidingEvent(
             (!animate.EqualsLiteral("cancel") || aIsCancel)) {
           presShell->FlushPendingNotifications(Flush_Layout);
 
           // Get the frame again in case the flush caused it to go away
           popupFrame = do_QueryFrame(aPopup->GetPrimaryFrame());
           if (!popupFrame)
             return;
 
-          if (nsLayoutUtils::HasCurrentAnimations(aPopup,
-                nsGkAtoms::transitionsProperty)) {
+          if (nsLayoutUtils::HasCurrentTransitions(popupFrame)) {
             nsRefPtr<TransitionEnder> ender = new TransitionEnder(aPopup, aDeselectMenu);
             aPopup->AddSystemEventListener(NS_LITERAL_STRING("transitionend"),
                                            ender, false, false);
             return;
           }
         }
       }
 #endif
--- a/media/mtransport/gonk_addrs.cpp
+++ b/media/mtransport/gonk_addrs.cpp
@@ -114,17 +114,17 @@ GetInterfaces(std::vector<NetworkInterfa
     aInterfaces->push_back(interface);
   }
   return NS_OK;
 }
 } // anonymous namespace
 
 int
 nr_stun_get_addrs(nr_local_addr aAddrs[], int aMaxAddrs,
-                  int aDropLoopback, int* aCount)
+                  int aDropLoopback, int aDropLinkLocal, int* aCount)
 {
   nsresult rv;
   int r;
 
   // Get network interface list.
   std::vector<NetworkInterface> interfaces;
   nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
   mozilla::SyncRunnable::DispatchToThread(
@@ -136,30 +136,29 @@ nr_stun_get_addrs(nr_local_addr aAddrs[]
   }
 
   // Translate to nr_transport_addr.
   int32_t n = 0;
   size_t num_interface = std::min(interfaces.size(), (size_t)aMaxAddrs);
   for (size_t i = 0; i < num_interface; ++i) {
     NetworkInterface &interface = interfaces[i];
     if (nr_sockaddr_to_transport_addr((sockaddr*)&(interface.addr),
-                                      sizeof(struct sockaddr_in),
                                       IPPROTO_UDP, 0, &(aAddrs[n].addr))) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Problem transforming address");
       return R_FAILED;
     }
     strlcpy(aAddrs[n].addr.ifname, interface.name.c_str(),
             sizeof(aAddrs[n].addr.ifname));
     aAddrs[n].interface.type = interface.type;
     aAddrs[n].interface.estimated_speed = 0;
     n++;
   }
 
   *aCount = n;
-  r = nr_stun_remove_duplicate_addrs(aAddrs, aDropLoopback, aCount);
+  r = nr_stun_remove_duplicate_addrs(aAddrs, aDropLoopback, aDropLinkLocal, aCount);
   if (r != 0) {
     return r;
   }
 
   for (int i = 0; i < *aCount; ++i) {
     char typestr[100];
     nr_local_addr_fmt_info_string(aAddrs + i, typestr, sizeof(typestr));
     r_log(NR_LOG_STUN, LOG_DEBUG, "Address %d: %s on %s, type: %s\n",
--- a/media/mtransport/nr_socket_prsock.cpp
+++ b/media/mtransport/nr_socket_prsock.cpp
@@ -332,30 +332,21 @@ static int nr_transport_addr_to_praddr(n
 
     switch(addr->ip_version){
       case NR_IPV4:
         naddr->inet.family = PR_AF_INET;
         naddr->inet.port = addr->u.addr4.sin_port;
         naddr->inet.ip = addr->u.addr4.sin_addr.s_addr;
         break;
       case NR_IPV6:
-#if 0
         naddr->ipv6.family = PR_AF_INET6;
         naddr->ipv6.port = addr->u.addr6.sin6_port;
-#ifdef LINUX
-        memcpy(naddr->ipv6.ip._S6_un._S6_u8,
-               &addr->u.addr6.sin6_addr.__in6_u.__u6_addr8, 16);
-#else
-        memcpy(naddr->ipv6.ip._S6_un._S6_u8,
-               &addr->u.addr6.sin6_addr.__u6_addr.__u6_addr8, 16);
-#endif
-#else
-        // TODO: make IPv6 work
-        ABORT(R_INTERNAL);
-#endif
+        naddr->ipv6.flowinfo = addr->u.addr6.sin6_flowinfo;
+        memcpy(&naddr->ipv6.ip, &addr->u.addr6.sin6_addr, sizeof(in6_addr));
+        naddr->ipv6.scope_id = addr->u.addr6.sin6_scope_id;
         break;
       default:
         ABORT(R_BAD_ARGS);
     }
 
     _status = 0;
   abort:
     return(_status);
@@ -435,35 +426,37 @@ int nr_netaddr_to_transport_addr(const n
 
 int nr_praddr_to_transport_addr(const PRNetAddr *praddr,
                                 nr_transport_addr *addr, int protocol,
                                 int keep)
   {
     int _status;
     int r;
     struct sockaddr_in ip4;
+    struct sockaddr_in6 ip6;
 
     switch(praddr->raw.family) {
       case PR_AF_INET:
         ip4.sin_family = PF_INET;
         ip4.sin_addr.s_addr = praddr->inet.ip;
         ip4.sin_port = praddr->inet.port;
         if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip4,
-                                               sizeof(ip4),
                                                protocol, keep,
                                                addr)))
           ABORT(r);
         break;
       case PR_AF_INET6:
-#if 0
-        r = nr_sockaddr_to_transport_addr((sockaddr *)&praddr->raw,
-          sizeof(struct sockaddr_in6),IPPROTO_UDP,keep,addr);
+        ip6.sin6_family = PF_INET6;
+        ip6.sin6_port = praddr->ipv6.port;
+        ip6.sin6_flowinfo = praddr->ipv6.flowinfo;
+        memcpy(&ip6.sin6_addr, &praddr->ipv6.ip, sizeof(in6_addr));
+        ip6.sin6_scope_id = praddr->ipv6.scope_id;
+        if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip6,protocol,keep,addr)))
+          ABORT(r);
         break;
-#endif
-        ABORT(R_BAD_ARGS);
       default:
         MOZ_ASSERT(false);
         ABORT(R_BAD_ARGS);
     }
 
     _status=0;
  abort:
     return(_status);
@@ -511,24 +504,26 @@ int NrSocket::create(nr_transport_addr *
     ABORT(R_INTERNAL);
   }
 
   if((r=nr_transport_addr_to_praddr(addr, &naddr)))
     ABORT(r);
 
   switch (addr->protocol) {
     case IPPROTO_UDP:
-      if (!(fd_ = PR_NewUDPSocket())) {
-        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
+      if (!(fd_ = PR_OpenUDPSocket(naddr.raw.family))) {
+        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create UDP socket, "
+              "family=%d, err=%d", naddr.raw.family, PR_GetError());
         ABORT(R_INTERNAL);
       }
       break;
     case IPPROTO_TCP:
-      if (!(fd_ = PR_NewTCPSocket())) {
-        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
+      if (!(fd_ = PR_OpenTCPSocket(naddr.raw.family))) {
+        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create TCP socket, "
+              "family=%d, err=%d", naddr.raw.family, PR_GetError());
         ABORT(R_INTERNAL);
       }
       // Set ReuseAddr for TCP sockets to enable having several
       // sockets bound to same local IP and port
       PRSocketOptionData opt_reuseaddr;
       opt_reuseaddr.option = PR_SockOpt_Reuseaddr;
       opt_reuseaddr.value.reuse_addr = PR_TRUE;
       status = PR_SetSocketOption(fd_, &opt_reuseaddr);
@@ -681,17 +676,18 @@ int NrSocket::sendto(const void *msg, si
   }
 
   // TODO: Convert flags?
   status = PR_SendTo(fd_, msg, len, flags, &naddr, PR_INTERVAL_NO_WAIT);
   if (status < 0 || (size_t)status != len) {
     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
       ABORT(R_WOULDBLOCK);
 
-    r_log(LOG_GENERIC, LOG_INFO, "Error in sendto: %s", to->as_string);
+    r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s: %d",
+          to->as_string, PR_GetError());
     ABORT(R_IO_ERROR);
   }
 
   _status=0;
 abort:
   return(_status);
 }
 
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -375,17 +375,18 @@ void NrIceCtx::trickle_cb(void *arg, nr_
 
   s->SignalCandidate(s, candidate_str);
 }
 
 RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
                                   bool offerer,
                                   bool set_interface_priorities,
                                   bool allow_loopback,
-                                  bool tcp_enabled) {
+                                  bool tcp_enabled,
+                                  bool allow_link_local) {
 
   RefPtr<NrIceCtx> ctx = new NrIceCtx(name, offerer);
 
   // Initialize the crypto callbacks and logging stuff
   if (!initialized) {
     NR_reg_init(NR_REG_MODE_LOCAL);
     RLogRingBuffer::CreateInstance();
     nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
@@ -467,16 +468,20 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const 
     NR_reg_set_int4((char *)NR_ICE_REG_ICE_TCP_LISTEN_BACKLOG,
                      ice_tcp_listen_backlog);
 
     NR_reg_set_char((char *)NR_ICE_REG_ICE_TCP_DISABLE, !tcp_enabled);
 
     if (allow_loopback) {
       NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, 1);
     }
+
+    if (allow_link_local) {
+      NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS, 1);
+    }
   }
 
   // Create the ICE context
   int r;
 
   UINT4 flags = offerer ? NR_ICE_CTX_FLAGS_OFFERER:
       NR_ICE_CTX_FLAGS_ANSWERER;
   flags |= NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;
--- a/media/mtransport/nricectx.h
+++ b/media/mtransport/nricectx.h
@@ -207,17 +207,18 @@ class NrIceCtx {
   enum Controlling { ICE_CONTROLLING,
                      ICE_CONTROLLED
   };
 
   static RefPtr<NrIceCtx> Create(const std::string& name,
                                  bool offerer,
                                  bool set_interface_priorities = true,
                                  bool allow_loopback = false,
-                                 bool tcp_enabled = true);
+                                 bool tcp_enabled = true,
+                                 bool allow_link_local = false);
 
   // Deinitialize all ICE global state. Used only for testing.
   static void internal_DeinitializeGlobal();
 
 
   nr_ice_ctx *ctx() { return ctx_; }
   nr_ice_peer_ctx *peer() { return peer_; }
 
--- a/media/mtransport/nriceresolver.cpp
+++ b/media/mtransport/nriceresolver.cpp
@@ -145,30 +145,43 @@ int NrIceResolver::resolve(void *obj,
 int NrIceResolver::resolve(nr_resolver_resource *resource,
                            int (*cb)(void *cb_arg, nr_transport_addr *addr),
                            void *cb_arg,
                            void **handle) {
   int _status;
   MOZ_ASSERT(allocated_resolvers_ > 0);
   ASSERT_ON_THREAD(sts_thread_);
   nsRefPtr<PendingResolution> pr;
+  uint32_t resolve_flags = 0;
 
   if (resource->transport_protocol != IPPROTO_UDP &&
       resource->transport_protocol != IPPROTO_TCP) {
     MOZ_MTLOG(ML_ERROR, "Only UDP and TCP are is supported.");
     ABORT(R_NOT_FOUND);
   }
   pr = new PendingResolution(sts_thread_,
                              resource->port? resource->port : 3478,
                              resource->transport_protocol ?
                              resource->transport_protocol :
                              IPPROTO_UDP,
                              cb, cb_arg);
+
+  switch(resource->address_family) {
+    case AF_INET:
+      resolve_flags |= nsIDNSService::RESOLVE_DISABLE_IPV6;
+      break;
+    case AF_INET6:
+      resolve_flags |= nsIDNSService::RESOLVE_DISABLE_IPV4;
+      break;
+    default:
+      ABORT(R_BAD_ARGS);
+  }
+
   if (NS_FAILED(dns_->AsyncResolve(nsAutoCString(resource->domain_name),
-                                   nsIDNSService::RESOLVE_DISABLE_IPV6, pr,
+                                   resolve_flags, pr,
                                    sts_thread_, getter_AddRefs(pr->request_)))) {
     MOZ_MTLOG(ML_ERROR, "AsyncResolve failed.");
     ABORT(R_NOT_FOUND);
   }
   // Because the C API offers no "finished" method to release the handle we
   // return, we cannot return the request we got from AsyncResolve directly.
   //
   // Instead, we return an addref'ed reference to PendingResolution itself,
--- a/media/mtransport/nriceresolverfake.cpp
+++ b/media/mtransport/nriceresolverfake.cpp
@@ -117,16 +117,17 @@ int NrIceResolverFake::resolve(void *obj
 
   PendingResolution *pending =
       new PendingResolution(fake,
                             resource->domain_name,
                             resource->port ? resource->port : 3478,
                             resource->transport_protocol ?
                             resource->transport_protocol :
                             IPPROTO_UDP,
+                            resource->address_family,
                             cb, cb_arg);
 
   if ((r=NR_ASYNC_TIMER_SET(fake->delay_ms_,NrIceResolverFake::resolve_cb,
                             (void *)pending, &pending->timer_handle_))) {
     delete pending;
     ABORT(r);
   }
   *handle = pending;
@@ -135,17 +136,18 @@ int NrIceResolverFake::resolve(void *obj
 abort:
   return(_status);
 }
 
 void NrIceResolverFake::resolve_cb(NR_SOCKET s, int how, void *cb_arg) {
   MOZ_ASSERT(cb_arg);
   PendingResolution *pending = static_cast<PendingResolution *>(cb_arg);
 
-  const PRNetAddr *addr=pending->resolver_->Resolve(pending->hostname_);
+  const PRNetAddr *addr=pending->resolver_->Resolve(pending->hostname_,
+                                                    pending->address_family_);
 
   if (addr) {
     nr_transport_addr transport_addr;
 
     int r = nr_praddr_to_transport_addr(addr, &transport_addr,
                                         pending->transport_, 0);
     MOZ_ASSERT(!r);
     if (r)
--- a/media/mtransport/nriceresolverfake.h
+++ b/media/mtransport/nriceresolverfake.h
@@ -58,17 +58,26 @@ typedef struct nr_resolver_resource_ nr_
 namespace mozilla {
 
 class NrIceResolverFake {
  public:
   NrIceResolverFake();
   ~NrIceResolverFake();
 
   void SetAddr(const std::string& hostname, const PRNetAddr& addr) {
-    addrs_[hostname] = addr;
+    switch (addr.raw.family) {
+      case AF_INET:
+        addrs_[hostname] = addr;
+        break;
+      case AF_INET6:
+        addrs6_[hostname] = addr;
+        break;
+      default:
+        MOZ_CRASH();
+    }
   }
 
   nr_resolver *AllocateResolver();
 
   void DestroyResolver();
 
 private:
   // Implementations of vtbl functions
@@ -78,47 +87,61 @@ private:
                      int (*cb)(void *cb_arg,
                                nr_transport_addr *addr),
                      void *cb_arg,
                      void **handle);
   static void resolve_cb(NR_SOCKET s, int how, void *cb_arg);
   static int cancel(void *obj, void *handle);
 
   // Get an address.
-  const PRNetAddr *Resolve(const std::string& hostname) {
-    if (!addrs_.count(hostname))
-      return nullptr;
+  const PRNetAddr *Resolve(const std::string& hostname, int address_family) {
+    switch (address_family) {
+      case AF_INET:
+        if (!addrs_.count(hostname))
+          return nullptr;
 
-    return &addrs_[hostname];
+        return &addrs_[hostname];
+      case AF_INET6:
+        if (!addrs6_.count(hostname))
+          return nullptr;
+
+        return &addrs6_[hostname];
+      default:
+        MOZ_CRASH();
+    }
   }
 
 
   struct PendingResolution {
     PendingResolution(NrIceResolverFake *resolver,
                       const std::string& hostname,
                       uint16_t port,
                       int transport,
+                      int address_family,
                       int (*cb)(void *cb_arg, nr_transport_addr *addr),
                       void *cb_arg) :
         resolver_(resolver),
         hostname_(hostname),
         port_(port),
         transport_(transport),
+        address_family_(address_family),
         cb_(cb), cb_arg_(cb_arg) {}
 
     NrIceResolverFake *resolver_;
     std::string hostname_;
     uint16_t port_;
     int transport_;
+    int address_family_;
     int (*cb_)(void *cb_arg, nr_transport_addr *addr);
     void *cb_arg_;
     void *timer_handle_;
   };
 
   nr_resolver_vtbl* vtbl_;
   std::map<std::string, PRNetAddr> addrs_;
+  std::map<std::string, PRNetAddr> addrs6_;
   uint32_t delay_ms_;
   int allocated_resolvers_;
 };
 
 }  // End of namespace mozilla
 
 #endif
--- a/media/mtransport/nrinterfaceprioritizer.cpp
+++ b/media/mtransport/nrinterfaceprioritizer.cpp
@@ -13,29 +13,31 @@ MOZ_MTLOG_MODULE("mtransport")
 namespace {
 
 class LocalAddress {
 public:
   LocalAddress()
     : key_(),
       is_vpn_(-1),
       estimated_speed_(-1),
-      type_preference_(-1) {}
+      type_preference_(-1),
+      ip_version_(-1) {}
 
   bool Init(const nr_local_addr& local_addr) {
     char buf[MAXIFNAME + 41];
     int r = nr_transport_addr_fmt_ifname_addr_string(&local_addr.addr, buf, sizeof(buf));
     if (r) {
       MOZ_MTLOG(ML_ERROR, "Error formatting interface address string.");
       return false;
     }
     key_ = buf;
     is_vpn_ = (local_addr.interface.type & NR_INTERFACE_TYPE_VPN) != 0 ? 1 : 0;
     estimated_speed_ = local_addr.interface.estimated_speed;
     type_preference_ = GetNetworkTypePreference(local_addr.interface.type);
+    ip_version_ = local_addr.addr.ip_version;
     return true;
   }
 
   bool operator<(const LocalAddress& rhs) const {
     // Interface that is "less" here is preferred.
     // If type preferences are different, we should simply sort by
     // |type_preference_|.
     if (type_preference_ != rhs.type_preference_) {
@@ -49,16 +51,21 @@ public:
       return is_vpn_ < rhs.is_vpn_;
     }
 
     // Compare estimated speed.
     if (estimated_speed_ != rhs.estimated_speed_) {
       return estimated_speed_ > rhs.estimated_speed_;
     }
 
+    // Prefer IPV6 over IPV4
+    if (ip_version_ != rhs.ip_version_) {
+      return ip_version_ > rhs.ip_version_;
+    }
+
     // All things above are the same, we can at least sort with key.
     return key_ < rhs.key_;
   }
 
   const std::string& GetKey() const {
     return key_;
   }
 
@@ -77,16 +84,17 @@ private:
     }
     return 4;
   }
 
   std::string key_;
   int is_vpn_;
   int estimated_speed_;
   int type_preference_;
+  int ip_version_;
 };
 
 class InterfacePrioritizer {
 public:
   InterfacePrioritizer()
     : local_addrs_(),
       preference_map_(),
       sorted_(false) {}
--- a/media/mtransport/stun_udp_socket_filter.cpp
+++ b/media/mtransport/stun_udp_socket_filter.cpp
@@ -16,52 +16,61 @@ extern "C" {
 #include "nr_socket_prsock.h"
 #if defined(MOZILLA_XPCOMRT_API)
 #include "mozilla/Module.h"
 #include "mozilla/ModuleUtils.h"
 #endif
 
 namespace {
 
-class NetAddressAdapter {
+class NetAddrCompare {
  public:
-  MOZ_IMPLICIT NetAddressAdapter(const mozilla::net::NetAddr& netaddr)
-    : addr_(ntohl(netaddr.inet.ip)),
-      port_(ntohs(netaddr.inet.port)) {
-    MOZ_ASSERT(netaddr.raw.family == AF_INET);
-  }
+   bool operator()(const mozilla::net::NetAddr& lhs,
+                   const mozilla::net::NetAddr& rhs) const {
+     if (lhs.raw.family != rhs.raw.family) {
+       return lhs.raw.family < rhs.raw.family;
+     }
 
-  bool operator<(const NetAddressAdapter& rhs) const {
-    return addr_ != rhs.addr_ ? (addr_ < rhs.addr_) : (port_ < rhs.port_);
-  }
-
-  bool operator!=(const NetAddressAdapter& rhs) const {
-    return (*this < rhs) || (rhs < *this);
-  }
-
- private:
-  const uint32_t addr_;
-  const uint16_t port_;
+     switch (lhs.raw.family) {
+       case AF_INET:
+         if (lhs.inet.port != rhs.inet.port) {
+           return lhs.inet.port < rhs.inet.port;
+         }
+         return lhs.inet.ip < rhs.inet.ip;
+       case AF_INET6:
+         if (lhs.inet6.port != rhs.inet6.port) {
+           return lhs.inet6.port < rhs.inet6.port;
+         }
+         return memcmp(&lhs.inet6.ip, &rhs.inet6.ip, sizeof(lhs.inet6.ip)) < 0;
+       default:
+         MOZ_ASSERT(false);
+     }
+     return false;
+   }
 };
 
 class PendingSTUNRequest {
  public:
-  PendingSTUNRequest(const NetAddressAdapter& netaddr, const UINT12 &id)
+  PendingSTUNRequest(const mozilla::net::NetAddr& netaddr, const UINT12 &id)
     : id_(id),
       net_addr_(netaddr),
       is_id_set_(true) {}
 
-  MOZ_IMPLICIT PendingSTUNRequest(const NetAddressAdapter& netaddr)
+  MOZ_IMPLICIT PendingSTUNRequest(const mozilla::net::NetAddr& netaddr)
     : id_(),
       net_addr_(netaddr),
       is_id_set_(false) {}
 
   bool operator<(const PendingSTUNRequest& rhs) const {
-    if (net_addr_ != rhs.net_addr_) {
-      return net_addr_ < rhs.net_addr_;
+    if (NetAddrCompare()(net_addr_, rhs.net_addr_)) {
+      return true;
+    }
+
+    if (NetAddrCompare()(rhs.net_addr_, net_addr_)) {
+      return false;
     }
 
     if (!is_id_set_ && !rhs.is_id_set_) {
       // PendingSTUNRequest can be stored to set only when it has id,
       // so comparing two PendingSTUNRequst without id is not going
       // to happen.
       MOZ_CRASH();
     }
@@ -71,17 +80,17 @@ class PendingSTUNRequest {
       return false;
     }
 
     return memcmp(id_.octet, rhs.id_.octet, sizeof(id_.octet)) < 0;
   }
 
  private:
   const UINT12 id_;
-  const NetAddressAdapter net_addr_;
+  const mozilla::net::NetAddr net_addr_;
   const bool is_id_set_;
 };
 
 class STUNUDPSocketFilter : public nsIUDPSocketFilter {
  public:
   STUNUDPSocketFilter()
     : white_list_(),
       pending_requests_() {}
@@ -96,35 +105,29 @@ class STUNUDPSocketFilter : public nsIUD
   bool filter_incoming_packet(const mozilla::net::NetAddr *remote_addr,
                               const uint8_t *data,
                               uint32_t len);
 
   bool filter_outgoing_packet(const mozilla::net::NetAddr *remote_addr,
                               const uint8_t *data,
                               uint32_t len);
 
-  std::set<NetAddressAdapter> white_list_;
+  std::set<mozilla::net::NetAddr, NetAddrCompare> white_list_;
   std::set<PendingSTUNRequest> pending_requests_;
   std::set<PendingSTUNRequest> response_allowed_;
 };
 
 NS_IMPL_ISUPPORTS(STUNUDPSocketFilter, nsIUDPSocketFilter)
 
 NS_IMETHODIMP
 STUNUDPSocketFilter::FilterPacket(const mozilla::net::NetAddr *remote_addr,
                                   const uint8_t *data,
                                   uint32_t len,
                                   int32_t direction,
                                   bool *result) {
-  // Allowing IPv4 address only.
-  if (remote_addr->raw.family != AF_INET) {
-    *result = false;
-    return NS_OK;
-  }
-
   switch (direction) {
     case nsIUDPSocketFilter::SF_INCOMING:
       *result = filter_incoming_packet(remote_addr, data, len);
       break;
     case nsIUDPSocketFilter::SF_OUTGOING:
       *result = filter_outgoing_packet(remote_addr, data, len);
       break;
     default:
--- a/media/mtransport/test/buffered_stun_socket_unittest.cpp
+++ b/media/mtransport/test/buffered_stun_socket_unittest.cpp
@@ -59,17 +59,17 @@ class BufferedStunSocketTest : public ::
     int r = nr_socket_buffered_stun_create(
         dummy->get_nr_socket(),
         kStunMessageLen,
         TURN_TCP_FRAMING,
         &test_socket_);
     ASSERT_EQ(0, r);
     dummy_ = dummy.forget();  // Now owned by test_socket_.
 
-    r = nr_ip4_str_port_to_transport_addr(
+    r = nr_str_port_to_transport_addr(
         (char *)"192.0.2.133", 3333, IPPROTO_TCP, &remote_addr_);
     ASSERT_EQ(0, r);
 
     r = nr_socket_connect(test_socket_,
                           &remote_addr_);
     ASSERT_EQ(0, r);
   }
 
@@ -179,17 +179,17 @@ TEST_F(BufferedStunSocketTest, TestSendT
   ASSERT_EQ(R_WOULDBLOCK, r);
 
   dummy_->CheckWriteBuffer(nullptr, 0);
 }
 
 TEST_F(BufferedStunSocketTest, TestSendToWrongAddr) {
   nr_transport_addr addr;
 
-  int r = nr_ip4_str_port_to_transport_addr(
+  int r = nr_str_port_to_transport_addr(
       (char *)"192.0.2.134", 3333, IPPROTO_TCP, &addr);
   ASSERT_EQ(0, r);
 
   r = nr_socket_sendto(test_socket_,
                        kStunMessage,
                        kStunMessageLen,
                        0, &addr);
   ASSERT_EQ(R_BAD_DATA, r);
--- a/media/mtransport/test/ice_unittest.cpp
+++ b/media/mtransport/test/ice_unittest.cpp
@@ -349,18 +349,18 @@ class IceTestPeer : public sigslot::has_
     SetStunServers(stun_servers);
   }
 
   void SetStunServers(const std::vector<NrIceStunServer> &servers) {
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(servers)));
   }
 
   void UseTestStunServer() {
-    SetStunServer(TestStunServer::GetInstance()->addr(),
-                  TestStunServer::GetInstance()->port());
+    SetStunServer(TestStunServer::GetInstance(AF_INET)->addr(),
+                  TestStunServer::GetInstance(AF_INET)->port());
   }
 
   void SetTurnServer(const std::string addr, uint16_t port,
                      const std::string username,
                      const std::string password,
                      const char* transport) {
     std::vector<unsigned char> password_vec(password.begin(), password.end());
     SetTurnServer(addr, port, username, password_vec, transport);
@@ -377,25 +377,25 @@ class IceTestPeer : public sigslot::has_
     turn_servers.push_back(*server);
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(turn_servers)));
   }
 
   void SetTurnServers(const std::vector<NrIceTurnServer> servers) {
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(servers)));
   }
 
-  void SetFakeResolver() {
+  void SetFakeResolver(const std::string& ip = g_stun_server_address,
+                       const std::string& fqdn = g_stun_server_hostname) {
     ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init()));
-    if (!g_stun_server_address.empty() && !g_stun_server_hostname.empty()) {
+    if (!ip.empty() && !fqdn.empty()) {
       PRNetAddr addr;
-      PRStatus status = PR_StringToNetAddr(g_stun_server_address.c_str(),
-                                            &addr);
+      PRStatus status = PR_StringToNetAddr(ip.c_str(), &addr);
       addr.inet.port = kDefaultStunServerPort;
       ASSERT_EQ(PR_SUCCESS, status);
-      fake_resolver_.SetAddr(g_stun_server_hostname, addr);
+      fake_resolver_.SetAddr(fqdn, addr);
     }
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(
         fake_resolver_.AllocateResolver())));
   }
 
   void SetDNSResolver() {
     ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init()));
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(
@@ -1093,19 +1093,26 @@ void SchedulableTrickleCandidate::Trickl
   timer_handle_ = nullptr;
   nsresult res = peer_->TrickleCandidate_s(candidate_, stream_);
   ASSERT_TRUE(NS_SUCCEEDED(res));
 }
 
 class IceGatherTest : public ::testing::Test {
  public:
   void SetUp() {
-    test_utils->sts_target()->Dispatch(WrapRunnable(TestStunServer::GetInstance(),
-                                                    &TestStunServer::Reset),
-                                       NS_DISPATCH_SYNC);
+    test_utils->sts_target()->Dispatch(
+        WrapRunnable(TestStunServer::GetInstance(AF_INET),
+                     &TestStunServer::Reset),
+        NS_DISPATCH_SYNC);
+    if (TestStunServer::GetInstance(AF_INET6)) {
+      test_utils->sts_target()->Dispatch(
+          WrapRunnable(TestStunServer::GetInstance(AF_INET6),
+                       &TestStunServer::Reset),
+          NS_DISPATCH_SYNC);
+    }
   }
 
   void TearDown() {
     peer_ = nullptr;
 
     test_utils->sts_target()->Dispatch(WrapRunnable(this,
                                                     &IceGatherTest::TearDown_s),
                                        NS_DISPATCH_SYNC);
@@ -1130,64 +1137,100 @@ class IceGatherTest : public ::testing::
       WaitForGather(waitTime);
     }
   }
 
   void WaitForGather(unsigned int waitTime = kDefaultTimeout) {
     ASSERT_TRUE_WAIT(peer_->gathering_complete(), waitTime);
   }
 
-  void UseFakeStunUdpServerWithResponse(const std::string& fake_addr,
-                                        uint16_t fake_port) {
-    EnsurePeer();
-    TestStunServer::GetInstance()->SetResponseAddr(fake_addr, fake_port);
-    // Sets an additional stun server
-    peer_->SetStunServer(TestStunServer::GetInstance()->addr(),
-                         TestStunServer::GetInstance()->port(),
-                         kNrIceTransportUdp);
+  void AddStunServerWithResponse(
+      const std::string& fake_addr,
+      uint16_t fake_port,
+      const std::string& fqdn,
+      const std::string& proto,
+      std::vector<NrIceStunServer>* stun_servers) {
+    int family;
+    if (fake_addr.find(':') != std::string::npos) {
+      family = AF_INET6;
+    } else {
+      family = AF_INET;
+    }
+
+    std::string stun_addr;
+    uint16_t stun_port;
+    if (proto == kNrIceTransportUdp) {
+      TestStunServer::GetInstance(family)->SetResponseAddr(fake_addr,
+                                                           fake_port);
+      stun_addr = TestStunServer::GetInstance(family)->addr();
+      stun_port = TestStunServer::GetInstance(family)->port();
+    } else if (proto == kNrIceTransportTcp) {
+      TestStunTcpServer::GetInstance(family)->SetResponseAddr(fake_addr,
+                                                              fake_port);
+      stun_addr = TestStunTcpServer::GetInstance(family)->addr();
+      stun_port = TestStunTcpServer::GetInstance(family)->port();
+    } else {
+      MOZ_CRASH();
+    }
+
+    if (!fqdn.empty()) {
+      peer_->SetFakeResolver(stun_addr, fqdn);
+      stun_addr = fqdn;
+    }
+
+    stun_servers->push_back(*NrIceStunServer::Create(stun_addr,
+                                                     stun_port,
+                                                     proto.c_str()));
   }
 
-  void UseFakeStunTcpServerWithResponse(const std::string& fake_addr,
-                                        uint16_t fake_port) {
-    EnsurePeer();
-    TestStunTcpServer::GetInstance()->SetResponseAddr(fake_addr, fake_port);
-    // Sets an additional stun server
-    peer_->SetStunServer(TestStunTcpServer::GetInstance()->addr(),
-                         TestStunTcpServer::GetInstance()->port(),
-                         kNrIceTransportTcp);
-  }
-
-  void UseFakeStunUdpTcpServersWithResponse(const std::string& fake_udp_addr,
-                                            uint16_t fake_udp_port,
-                                            const std::string& fake_tcp_addr,
-                                            uint16_t fake_tcp_port) {
+  void UseFakeStunUdpServerWithResponse(
+      const std::string& fake_addr,
+      uint16_t fake_port,
+      const std::string& fqdn = std::string()) {
     EnsurePeer();
     std::vector<NrIceStunServer> stun_servers;
-
-    stun_servers.push_back(*NrIceStunServer::Create(
-        TestStunServer::GetInstance()->addr(),
-        TestStunServer::GetInstance()->port(),
-        kNrIceTransportUdp));
-    stun_servers.push_back(*NrIceStunServer::Create(
-        TestStunTcpServer::GetInstance()->addr(),
-        TestStunTcpServer::GetInstance()->port(),
-        kNrIceTransportTcp));
-
-    TestStunServer::GetInstance()->SetResponseAddr(fake_udp_addr,
-                                                   fake_udp_port);
-    TestStunTcpServer::GetInstance()->SetResponseAddr(fake_tcp_addr,
-                                                      fake_tcp_port);
-    // Sets an additional stun server
+    AddStunServerWithResponse(fake_addr, fake_port, fqdn, "udp", &stun_servers);
+    peer_->SetStunServers(stun_servers);
+  }
+
+  void UseFakeStunTcpServerWithResponse(
+      const std::string& fake_addr,
+      uint16_t fake_port,
+      const std::string& fqdn = std::string()) {
+    EnsurePeer();
+    std::vector<NrIceStunServer> stun_servers;
+    AddStunServerWithResponse(fake_addr, fake_port, fqdn, "tcp", &stun_servers);
+    peer_->SetStunServers(stun_servers);
+  }
+
+  void UseFakeStunUdpTcpServersWithResponse(
+      const std::string& fake_udp_addr,
+      uint16_t fake_udp_port,
+      const std::string& fake_tcp_addr,
+      uint16_t fake_tcp_port) {
+    EnsurePeer();
+    std::vector<NrIceStunServer> stun_servers;
+    AddStunServerWithResponse(fake_udp_addr,
+                              fake_udp_port,
+                              "", // no fqdn
+                              "udp",
+                              &stun_servers);
+    AddStunServerWithResponse(fake_tcp_addr,
+                              fake_tcp_port,
+                              "", // no fqdn
+                              "tcp",
+                              &stun_servers);
+
     peer_->SetStunServers(stun_servers);
   }
 
   void UseTestStunServer() {
-    TestStunServer::GetInstance()->Reset();
-    peer_->SetStunServer(TestStunServer::GetInstance()->addr(),
-                         TestStunServer::GetInstance()->port());
+    TestStunServer::GetInstance(AF_INET)->Reset();
+    peer_->SetStunServer(TestStunServer::GetInstance(AF_INET)->addr(),
+                         TestStunServer::GetInstance(AF_INET)->port());
   }
 
   // NB: Only does substring matching, watch out for stuff like "1.2.3.4"
   // matching "21.2.3.47". " 1.2.3.4 " should not have false positives.
   bool StreamHasMatchingCandidate(unsigned int stream,
                                   const std::string& match,
                                   const std::string& match2 = "") {
     std::vector<std::string> candidates = peer_->GetCandidates(stream);
@@ -1309,17 +1352,17 @@ class IceConnectTest : public ::testing:
     mapping_type_ = type;
   }
 
   void BlockUdp() {
     block_udp_ = true;
   }
 
   void UseTestStunServer() {
-    TestStunServer::GetInstance()->Reset();
+    TestStunServer::GetInstance(AF_INET)->Reset();
     p1_->UseTestStunServer();
     p2_->UseTestStunServer();
   }
 
   void SetTurnServer(const std::string addr, uint16_t port,
                      const std::string username,
                      const std::string password,
                      const char* transport = kNrIceTransportUdp) {
@@ -1477,18 +1520,18 @@ class PrioritizerTest : public ::testing
 
   void AddInterface(const std::string& num, int type, int estimated_speed) {
     std::string str_addr = "10.0.0." + num;
     std::string ifname = "eth" + num;
     nr_local_addr local_addr;
     local_addr.interface.type = type;
     local_addr.interface.estimated_speed = estimated_speed;
 
-    int r = nr_ip4_str_port_to_transport_addr(str_addr.c_str(), 0,
-                                              IPPROTO_UDP, &(local_addr.addr));
+    int r = nr_str_port_to_transport_addr(str_addr.c_str(), 0,
+                                          IPPROTO_UDP, &(local_addr.addr));
     ASSERT_EQ(0, r);
     strncpy(local_addr.addr.ifname, ifname.c_str(), MAXIFNAME);
 
     r = nr_interface_prioritizer_add_interface(prioritizer_, &local_addr);
     ASSERT_EQ(0, r);
     r = nr_interface_prioritizer_sort_preference(prioritizer_);
     ASSERT_EQ(0, r);
   }
@@ -1786,63 +1829,109 @@ TEST_F(IceGatherTest, VerifyTestStunServ
 
 TEST_F(IceGatherTest, VerifyTestStunTcpServer) {
   UseFakeStunTcpServerWithResponse("192.0.2.233", 3333);
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.233 3333 typ srflx",
     " tcptype "));
 }
 
+TEST_F(IceGatherTest, VerifyTestStunServerV6) {
+  if (!TestStunServer::GetInstance(AF_INET6)) {
+    // No V6 addresses
+    return;
+  }
+  UseFakeStunUdpServerWithResponse("beef::", 3333);
+  Gather();
+  ASSERT_TRUE(StreamHasMatchingCandidate(0, " beef:: 3333 "));
+}
+
+TEST_F(IceGatherTest, VerifyTestStunServerFQDN) {
+  UseFakeStunUdpServerWithResponse("192.0.2.133", 3333, "stun.example.com");
+  Gather();
+  ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.133 3333 "));
+}
+
+TEST_F(IceGatherTest, VerifyTestStunServerV6FQDN) {
+  if (!TestStunServer::GetInstance(AF_INET6)) {
+    // No V6 addresses
+    return;
+  }
+  UseFakeStunUdpServerWithResponse("beef::", 3333, "stun.example.com");
+  Gather();
+  ASSERT_TRUE(StreamHasMatchingCandidate(0, " beef:: 3333 "));
+}
+
 TEST_F(IceGatherTest, TestStunServerReturnsWildcardAddr) {
   UseFakeStunUdpServerWithResponse("0.0.0.0", 3333);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 0.0.0.0 "));
 }
 
+TEST_F(IceGatherTest, TestStunServerReturnsWildcardAddrV6) {
+  if (!TestStunServer::GetInstance(AF_INET6)) {
+    // No V6 addresses
+    return;
+  }
+  UseFakeStunUdpServerWithResponse("::", 3333);
+  Gather(kDefaultTimeout * 3);
+  ASSERT_FALSE(StreamHasMatchingCandidate(0, " :: "));
+}
+
 TEST_F(IceGatherTest, TestStunServerReturnsPort0) {
   UseFakeStunUdpServerWithResponse("192.0.2.133", 0);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.2.133 0 "));
 }
 
 TEST_F(IceGatherTest, TestStunServerReturnsLoopbackAddr) {
   UseFakeStunUdpServerWithResponse("127.0.0.133", 3333);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 127.0.0.133 "));
 }
 
+TEST_F(IceGatherTest, TestStunServerReturnsLoopbackAddrV6) {
+  if (!TestStunServer::GetInstance(AF_INET6)) {
+    // No V6 addresses
+    return;
+  }
+  UseFakeStunUdpServerWithResponse("::1", 3333);
+  Gather(kDefaultTimeout * 3);
+  ASSERT_FALSE(StreamHasMatchingCandidate(0, " ::1 "));
+}
+
 TEST_F(IceGatherTest, TestStunServerTrickle) {
   UseFakeStunUdpServerWithResponse("192.0.2.1", 3333);
-  TestStunServer::GetInstance()->SetActive(false);
+  TestStunServer::GetInstance(AF_INET)->SetActive(false);
   Gather(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1"));
-  TestStunServer::GetInstance()->SetActive(true);
+  TestStunServer::GetInstance(AF_INET)->SetActive(true);
   WaitForGather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1"));
 }
 
 TEST_F(IceGatherTest, TestStunTcpServerTrickle) {
   UseFakeStunTcpServerWithResponse("192.0.3.1", 3333);
-  TestStunTcpServer::GetInstance()->SetActive(false);
+  TestStunTcpServer::GetInstance(AF_INET)->SetActive(false);
   Gather(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
-  TestStunTcpServer::GetInstance()->SetActive(true);
+  TestStunTcpServer::GetInstance(AF_INET)->SetActive(true);
   WaitForGather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
 }
 
 TEST_F(IceGatherTest, TestStunTcpAndUdpServerTrickle) {
   UseFakeStunUdpTcpServersWithResponse("192.0.2.1", 3333, "192.0.3.1", 3333);
-  TestStunServer::GetInstance()->SetActive(false);
-  TestStunTcpServer::GetInstance()->SetActive(false);
+  TestStunServer::GetInstance(AF_INET)->SetActive(false);
+  TestStunTcpServer::GetInstance(AF_INET)->SetActive(false);
   Gather(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
-  TestStunServer::GetInstance()->SetActive(true);
-  TestStunTcpServer::GetInstance()->SetActive(true);
+  TestStunServer::GetInstance(AF_INET)->SetActive(true);
+  TestStunTcpServer::GetInstance(AF_INET)->SetActive(true);
   WaitForGather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
 }
 
 TEST_F(IceConnectTest, TestGather) {
   AddStream("first", 1);
   ASSERT_TRUE(Gather());
@@ -2858,20 +2947,28 @@ int main(int argc, char **argv)
   ::testing::InitGoogleTest(&argc, argv);
 
   ::testing::TestEventListeners& listeners =
         ::testing::UnitTest::GetInstance()->listeners();
   // Adds a listener to the end.  Google Test takes the ownership.
 
   listeners.Append(new test::RingbufferDumper(test_utils));
   test_utils->sts_target()->Dispatch(
-    WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC);
+      WrapRunnableNM(&TestStunServer::GetInstance, AF_INET),
+                     NS_DISPATCH_SYNC);
+  test_utils->sts_target()->Dispatch(
+    WrapRunnableNM(&TestStunServer::GetInstance, AF_INET6),
+                   NS_DISPATCH_SYNC);
 
   test_utils->sts_target()->Dispatch(
-    WrapRunnableNM(&TestStunTcpServer::GetInstance), NS_DISPATCH_SYNC);
+      WrapRunnableNM(&TestStunTcpServer::GetInstance, AF_INET),
+                     NS_DISPATCH_SYNC);
+  test_utils->sts_target()->Dispatch(
+    WrapRunnableNM(&TestStunTcpServer::GetInstance, AF_INET6),
+                   NS_DISPATCH_SYNC);
 
   int rv = RUN_ALL_TESTS();
 
   test_utils->sts_target()->Dispatch(
     WrapRunnableNM(&TestStunServer::ShutdownInstance), NS_DISPATCH_SYNC);
 
   test_utils->sts_target()->Dispatch(
     WrapRunnableNM(&TestStunTcpServer::ShutdownInstance), NS_DISPATCH_SYNC);
--- a/media/mtransport/test/multi_tcp_socket_unittest.cpp
+++ b/media/mtransport/test/multi_tcp_socket_unittest.cpp
@@ -107,17 +107,17 @@ class MultiTcpSocketTest : public ::test
           stun_host, port, kNrIceTransportTcp));
       stun_servers.push_back(*server);
 
       ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(stun_servers)));
     }
 
     r = 1;
     for (int tries=10; tries && r; --tries) {
-      r = nr_ip4_str_port_to_transport_addr(
+      r = nr_str_port_to_transport_addr(
         (char *)"127.0.0.1", EnsureEphemeral(port_s++), IPPROTO_TCP, &local);
       ASSERT_EQ(0, r);
 
       r = nr_socket_multi_tcp_create(ice_ctx_->ctx(),
           &local, tcp_type, 1, use_framing, 2048, sock);
     }
 
     ASSERT_EQ(0, r);
--- a/media/mtransport/test/proxy_tunnel_socket_unittest.cpp
+++ b/media/mtransport/test/proxy_tunnel_socket_unittest.cpp
@@ -79,17 +79,17 @@ class DummyResolver {
 
   static int resolve(void *obj,
                      nr_resolver_resource *resource,
                      int (*cb)(void *cb_arg, nr_transport_addr *addr),
                      void *cb_arg,
                      void **handle) {
     nr_transport_addr addr;
 
-    nr_ip4_str_port_to_transport_addr(
+    nr_str_port_to_transport_addr(
         (char *)kProxyAddr.c_str(), kProxyPort, IPPROTO_TCP, &addr);
 
     cb(cb_arg, &addr);
     return 0;
   }
 
   static int cancel(void *obj, void *handle) {
     return 0;
@@ -115,21 +115,21 @@ class ProxyTunnelSocketTest : public ::t
     nr_proxy_tunnel_config_destroy(&config_);
   }
 
   void SetUp() {
     nsRefPtr<DummySocket> dummy(new DummySocket());
 
     nr_resolver_ = resolver_impl_.get_nr_resolver();
 
-    int r = nr_ip4_str_port_to_transport_addr(
+    int r = nr_str_port_to_transport_addr(
         (char *)kRemoteAddr.c_str(), kRemotePort, IPPROTO_TCP, &remote_addr_);
     ASSERT_EQ(0, r);
 
-    r = nr_ip4_str_port_to_transport_addr(
+    r = nr_str_port_to_transport_addr(
         (char *)kProxyAddr.c_str(), kProxyPort, IPPROTO_TCP, &proxy_addr_);
     ASSERT_EQ(0, r);
 
     nr_proxy_tunnel_config_create(&config_);
     nr_proxy_tunnel_config_set_resolver(config_, nr_resolver_);
     nr_proxy_tunnel_config_set_proxy(config_, kProxyAddr.c_str(), kProxyPort);
 
     r = nr_socket_proxy_tunnel_create(
--- a/media/mtransport/test/stunserver.cpp
+++ b/media/mtransport/test/stunserver.cpp
@@ -183,16 +183,18 @@ int nr_socket_wrapped_create(nr_socket *
 }
 
 
 // Instance static.
 // Note: Calling Create() at static init time is not going to be safe, since
 // we have no reason to expect this will be initted to a nullptr yet.
 TestStunServer* TestStunServer::instance;
 TestStunTcpServer* TestStunTcpServer::instance;
+TestStunServer* TestStunServer::instance6;
+TestStunTcpServer* TestStunTcpServer::instance6;
 uint16_t TestStunServer::instance_port = 3478;
 uint16_t TestStunTcpServer::instance_port = 3478;
 
 TestStunServer::~TestStunServer() {
   // TODO(ekr@rtfm.com): Put this on the right thread.
 
   // Unhook callback from our listen socket.
   if (listen_sock_) {
@@ -238,36 +240,49 @@ int TestStunServer::TryOpenListenSocket(
   if (nr_socket_local_create(nullptr, &addr->addr, &listen_sock_)) {
     MOZ_MTLOG(ML_ERROR, "Couldn't create listen socket");
     return R_ALREADY;
   }
 
   return 0;
 }
 
-int TestStunServer::Initialize() {
-  nr_local_addr addrs[100];
+int TestStunServer::Initialize(int address_family) {
+  static const size_t max_addrs = 100;
+  nr_local_addr addrs[max_addrs];
   int addr_ct;
   int r;
+  int i;
 
-  r = nr_stun_find_local_addresses(addrs, 100, &addr_ct);
+  r = nr_stun_find_local_addresses(addrs, max_addrs, &addr_ct);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't retrieve addresses");
     return R_INTERNAL;
   }
 
   if (addr_ct < 1) {
     MOZ_MTLOG(ML_ERROR, "No local addresses");
     return R_INTERNAL;
   }
 
+  for (i = 0; i < addr_ct; ++i) {
+    if (addrs[i].addr.addr->sa_family == address_family) {
+      break;
+    }
+  }
+
+  if (i == addr_ct) {
+    MOZ_MTLOG(ML_ERROR, "No local addresses of the configured IP version");
+    return R_INTERNAL;
+  }
+
   int tries = 100;
   while (tries--) {
-    // Bind to the first address (arbitrarily) on configured port (default 3478)
-    r = TryOpenListenSocket(&addrs[0], instance_port);
+    // Bind on configured port (default 3478)
+    r = TryOpenListenSocket(&addrs[i], instance_port);
     // We interpret R_ALREADY to mean the addr is probably in use. Try another.
     // Otherwise, it either worked or it didn't, and we check below.
     if (r != R_ALREADY) {
       break;
     }
     ++instance_port;
   }
 
@@ -286,35 +301,35 @@ int TestStunServer::Initialize() {
                                 &stun_server_);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't create STUN server");
     return R_INTERNAL;
   }
 
   // Cache the address and port.
   char addr_string[INET6_ADDRSTRLEN];
-  r = nr_transport_addr_get_addrstring(&addrs[0].addr, addr_string,
+  r = nr_transport_addr_get_addrstring(&addrs[i].addr, addr_string,
                                        sizeof(addr_string));
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Failed to convert listen addr to a string representation");
     return R_INTERNAL;
   }
 
   listen_addr_ = addr_string;
   listen_port_ = instance_port;
 
   return 0;
 }
 
-TestStunServer* TestStunServer::Create() {
+TestStunServer* TestStunServer::Create(int address_family) {
   NR_reg_init(NR_REG_MODE_LOCAL);
 
   ScopedDeletePtr<TestStunServer> server(new TestStunServer());
 
-  if (server->Initialize())
+  if (server->Initialize(address_family))
     return nullptr;
 
   NR_SOCKET fd;
   int r = nr_socket_getfd(server->listen_sock_, &fd);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't get fd");
     return nullptr;
   }
@@ -323,28 +338,39 @@ TestStunServer* TestStunServer::Create()
 
   return server.forget();
 }
 
 void TestStunServer::ConfigurePort(uint16_t port) {
   instance_port = port;
 }
 
-TestStunServer* TestStunServer::GetInstance() {
-  if (!instance)
-    instance = Create();
+TestStunServer* TestStunServer::GetInstance(int address_family) {
+  switch (address_family) {
+    case AF_INET:
+      if (!instance)
+        instance = Create(address_family);
 
-  MOZ_ASSERT(instance);
-  return instance;
+      MOZ_ASSERT(instance);
+      return instance;
+    case AF_INET6:
+      if (!instance6)
+        instance6 = Create(address_family);
+
+      return instance6;
+    default:
+      MOZ_CRASH();
+  }
 }
 
 void TestStunServer::ShutdownInstance() {
   delete instance;
-
   instance = nullptr;
+  delete instance6;
+  instance6 = nullptr;
 }
 
 
 struct DeferredStunOperation {
   DeferredStunOperation(TestStunServer *server,
                         const char *data, size_t len,
                         nr_transport_addr *addr) :
       server_(server),
@@ -448,19 +474,19 @@ nsresult TestStunServer::SetResponseAddr
 
   return NS_OK;
 }
 
 nsresult TestStunServer::SetResponseAddr(const std::string& addr,
                                          uint16_t port) {
   nr_transport_addr addr2;
 
-  int r = nr_ip4_str_port_to_transport_addr(addr.c_str(),
-                                            port, IPPROTO_UDP,
-                                            &addr2);
+  int r = nr_str_port_to_transport_addr(addr.c_str(),
+                                        port, IPPROTO_UDP,
+                                        &addr2);
   if (r)
     return NS_ERROR_FAILURE;
 
   return SetResponseAddr(&addr2);
 }
 
 void TestStunServer::Reset() {
   delay_ms_ = 0;
@@ -474,22 +500,32 @@ void TestStunServer::Reset() {
 
 
 // TestStunTcpServer
 
 void TestStunTcpServer::ConfigurePort(uint16_t port) {
   instance_port = port;
 }
 
-TestStunTcpServer* TestStunTcpServer::GetInstance() {
-  if (!instance)
-    instance = Create();
+TestStunTcpServer* TestStunTcpServer::GetInstance(int address_family) {
+  switch (address_family) {
+    case AF_INET:
+      if (!instance)
+        instance = Create(address_family);
 
-  MOZ_ASSERT(instance);
-  return instance;
+      MOZ_ASSERT(instance);
+      return instance;
+    case AF_INET6:
+      if (!instance6)
+        instance6 = Create(address_family);
+
+      return instance6;
+    default:
+      MOZ_CRASH();
+  }
 }
 
 void TestStunTcpServer::ShutdownInstance() {
   delete instance;
 
   instance = nullptr;
 }
 
@@ -518,22 +554,24 @@ int TestStunTcpServer::TryOpenListenSock
   if(nr_socket_listen(listen_sock_, 10)) {
     MOZ_MTLOG(ML_ERROR, "Couldn't listen on socket");
     return R_ALREADY;
   }
 
   return 0;
 }
 
-TestStunTcpServer* TestStunTcpServer::Create() {
+TestStunTcpServer* TestStunTcpServer::Create(int address_family) {
   NR_reg_init(NR_REG_MODE_LOCAL);
 
   ScopedDeletePtr<TestStunTcpServer> server(new TestStunTcpServer());
 
-  server->Initialize();
+  if (server->Initialize(address_family)) {
+    return nullptr;
+  }
 
   nr_socket_multi_tcp_set_readable_cb(server->listen_sock_,
     &TestStunServer::readable_cb, server.get());
 
   return server.forget();
 }
 
 TestStunTcpServer::~TestStunTcpServer() {
--- a/media/mtransport/test/stunserver.h
+++ b/media/mtransport/test/stunserver.h
@@ -19,22 +19,23 @@ typedef struct nr_socket_ nr_socket;
 typedef struct nr_local_addr_ nr_local_addr;
 
 namespace mozilla {
 
 class TestStunServer {
  public:
   // Generally, you should only call API in this class from the same thread that
   // the initial |GetInstance| call was made from.
-  static TestStunServer *GetInstance();
+  static TestStunServer *GetInstance(int address_family = AF_INET);
   static void ShutdownInstance();
   // |ConfigurePort| will only have an effect if called before the first call
   // to |GetInstance| (possibly following a |ShutdownInstance| call)
   static void ConfigurePort(uint16_t port);
-  static TestStunServer *Create();
+  // AF_INET, AF_INET6
+  static TestStunServer *Create(int address_family);
 
   virtual ~TestStunServer();
 
   void SetActive(bool active);
   void SetDelay(uint32_t delay_ms);
   void SetDropInitialPackets(uint32_t count);
   const std::string& addr() const { return listen_addr_; }
   uint16_t port() const { return listen_port_; }
@@ -54,17 +55,17 @@ class TestStunServer {
         stun_server_(nullptr),
         active_(true),
         delay_ms_(0),
         initial_ct_(0),
         response_addr_(nullptr),
         timer_handle_(nullptr) {}
 
   int SetInternalPort(nr_local_addr* addr, uint16_t port);
-  int Initialize();
+  int Initialize(int address_family);
   static void readable_cb(NR_SOCKET sock, int how, void *cb_arg);
 
  private:
   void Process(const uint8_t *msg, size_t len, nr_transport_addr *addr_in);
   virtual int TryOpenListenSocket(nr_local_addr* addr, uint16_t port);
   static void process_cb(NR_SOCKET sock, int how, void *cb_arg);
 
  protected:
@@ -77,31 +78,33 @@ class TestStunServer {
   bool active_;
   uint32_t delay_ms_;
   uint32_t initial_ct_;
   nr_transport_addr *response_addr_;
   void *timer_handle_;
   std::map<std::string, uint32_t> received_ct_;
 
   static TestStunServer* instance;
+  static TestStunServer* instance6;
   static uint16_t instance_port;
 };
 
 class TestStunTcpServer: public TestStunServer {
  public:
-  static TestStunTcpServer *GetInstance();
+  static TestStunTcpServer *GetInstance(int address_family);
   static void ShutdownInstance();
   static void ConfigurePort(uint16_t port);
   virtual ~TestStunTcpServer();
  protected:
   TestStunTcpServer()
       : ice_ctx_(nullptr) {}
 
   nsRefPtr<NrIceCtx> ice_ctx_;
  private:
   virtual int TryOpenListenSocket(nr_local_addr* addr, uint16_t port);
-  static TestStunTcpServer *Create();
+  static TestStunTcpServer *Create(int address_family);
 
   static TestStunTcpServer* instance;
+  static TestStunTcpServer* instance6;
   static uint16_t instance_port;
 };
 } // End of namespace mozilla
 #endif
--- a/media/mtransport/test/test_nr_socket_unittest.cpp
+++ b/media/mtransport/test/test_nr_socket_unittest.cpp
@@ -62,17 +62,17 @@ class TestNrSocketTest : public ::testin
   }
 
   nsRefPtr<TestNrSocket> CreateTestNrSocket_s(const char *ip_str,
                                               TestNat *nat) {
     // If no nat is supplied, we create a default NAT which is disabled. This
     // is how we simulate a non-natted socket.
     nsRefPtr<TestNrSocket> sock(new TestNrSocket(nat ? nat : new TestNat));
     nr_transport_addr address;
-    nr_ip4_str_port_to_transport_addr(ip_str, 0, IPPROTO_UDP, &address);
+    nr_str_port_to_transport_addr(ip_str, 0, IPPROTO_UDP, &address);
     int r = sock->create(&address);
     if (r) {
       return nullptr;
     }
     return sock;
   }
 
   void CreatePublicAddrs(size_t count, const char *ip_str = "127.0.0.1") {
--- a/media/mtransport/test/turn_unittest.cpp
+++ b/media/mtransport/test/turn_unittest.cpp
@@ -127,17 +127,17 @@ class TurnClient : public ::testing::Tes
           nr_socket_buffered_stun_create(real_socket_, 100000, TURN_TCP_FRAMING,
                                          &buffered_socket_);
       ASSERT_EQ(0, r);
       net_socket_ = buffered_socket_;
     } else {
       net_socket_ = real_socket_;
     }
 
-    r = nr_ip4_str_port_to_transport_addr(turn_server_.c_str(), 3478,
+    r = nr_str_port_to_transport_addr(turn_server_.c_str(), 3478,
       protocol_, &addr);
     ASSERT_EQ(0, r);
 
     std::vector<unsigned char> password_vec(
         g_turn_password.begin(), g_turn_password.end());
     Data password;
     INIT_DATA(password, &password_vec[0], password_vec.size());
     r = nr_turn_client_ctx_create("test", net_socket_,
@@ -232,20 +232,20 @@ class TurnClient : public ::testing::Tes
     ASSERT_EQ(0, target.compare(0, 4, "IP4:"));
 
     size_t offset = target.rfind(':');
     ASSERT_NE(std::string::npos, offset);
 
     std::string host = target.substr(4, offset - 4);
     std::string port = target.substr(offset + 1);
 
-    r = nr_ip4_str_port_to_transport_addr(host.c_str(),
-                                          atoi(port.c_str()),
-                                          IPPROTO_UDP,
-                                          &addr);
+    r = nr_str_port_to_transport_addr(host.c_str(),
+                                      atoi(port.c_str()),
+                                      IPPROTO_UDP,
+                                      &addr);
     ASSERT_EQ(0, r);
 
     r = nr_turn_client_ensure_perm(turn_ctx_, &addr);
     ASSERT_EQ(0, r);
   }
 
   void RequestPermission(const std::string& target) {
     RUN_ON_THREAD(test_utils->sts_target(),
@@ -319,20 +319,20 @@ class TurnClient : public ::testing::Tes
     ASSERT_EQ(0, target.compare(0, 4, "IP4:"));
 
     size_t offset = target.rfind(':');
     ASSERT_NE(std::string::npos, offset);
 
     std::string host = target.substr(4, offset - 4);
     std::string port = target.substr(offset + 1);
 
-    r = nr_ip4_str_port_to_transport_addr(host.c_str(),
-                                          atoi(port.c_str()),
-                                          IPPROTO_UDP,
-                                          &addr);
+    r = nr_str_port_to_transport_addr(host.c_str(),
+                                      atoi(port.c_str()),
+                                      IPPROTO_UDP,
+                                      &addr);
     ASSERT_EQ(0, r);
 
     unsigned char test[100];
     for (size_t i=0; i<sizeof(test); i++) {
       test[i] = i & 0xff;
     }
 
     std::cerr << "Sending test message to " << target << " ..." << std::endl;
@@ -483,33 +483,33 @@ int main(int argc, char **argv)
       g_turn_password.empty()) {
     printf(
         "Set TURN_SERVER_ADDRESS, TURN_SERVER_USER, and TURN_SERVER_PASSWORD\n"
         "environment variables to run this test\n");
     return 0;
   }
   {
     nr_transport_addr addr;
-    if (nr_ip4_str_port_to_transport_addr(g_turn_server.c_str(), 3478,
-                                          IPPROTO_UDP, &addr)) {
+    if (nr_str_port_to_transport_addr(g_turn_server.c_str(), 3478,
+                                      IPPROTO_UDP, &addr)) {
       printf("Invalid TURN_SERVER_ADDRESS \"%s\". Only IP numbers supported.\n",
              g_turn_server.c_str());
       return 0;
     }
   }
   test_utils = new MtransportTestUtils();
   NSS_NoDB_Init(nullptr);
   NSS_SetDomesticPolicy();
 
   // Set up the ICE registry, etc.
   // TODO(ekr@rtfm.com): Clean up
   std::string dummy("dummy");
   RUN_ON_THREAD(test_utils->sts_target(),
                 WrapRunnableNM(&NrIceCtx::Create,
-                               dummy, false, false, false, false),
+                               dummy, false, false, false, false, false),
                 NS_DISPATCH_SYNC);
 
   // Start the tests
   ::testing::InitGoogleTest(&argc, argv);
 
   int rv = RUN_ALL_TESTS();
   delete test_utils;
   return rv;
--- a/media/mtransport/third_party/nICEr/IMPORT_FILES
+++ b/media/mtransport/third_party/nICEr/IMPORT_FILES
@@ -32,16 +32,18 @@
                 ./src/net/transport_addr.c
                 ./src/net/transport_addr.h
                 ./src/net/transport_addr_reg.c
                 ./src/net/transport_addr_reg.h
 
                 # STUN
                 ./src/stun/addrs.c
                 ./src/stun/addrs.h
+                ./src/stun/ifaddrs-android.c
+                ./src/stun/ifaddrs-android.h
                 ./src/stun/nr_socket_turn.c
                 ./src/stun/nr_socket_turn.h
                 ./src/stun/stun.h
                 ./src/stun/stun_build.c
                 ./src/stun/stun_build.h
                 ./src/stun/stun_client_ctx.c
                 ./src/stun/stun_client_ctx.h
                 ./src/stun/stun_codec.c
--- a/media/mtransport/third_party/nICEr/nicer.gyp
+++ b/media/mtransport/third_party/nICEr/nicer.gyp
@@ -83,16 +83,18 @@
                 "./src/net/local_addr.c",
                 "./src/net/local_addr.h",
                 "./src/net/nr_interface_prioritizer.c",
                 "./src/net/nr_interface_prioritizer.h",
 
                 # STUN
                 "./src/stun/addrs.c",
                 "./src/stun/addrs.h",
+                "./src/stun/ifaddrs-android.c",
+                "./src/stun/ifaddrs-android.h",
                 "./src/stun/nr_socket_turn.c",
                 "./src/stun/nr_socket_turn.h",
                 "./src/stun/nr_socket_buffered_stun.c",
                 "./src/stun/nr_socket_buffered_stun.h",
                 "./src/stun/stun.h",
                 "./src/stun/stun_build.c",
                 "./src/stun/stun_build.h",
                 "./src/stun/stun_client_ctx.c",
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
@@ -59,17 +59,17 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #include "ice_candidate.h"
 #include "ice_codeword.h"
 #include "ice_reg.h"
 #include "ice_util.h"
 #include "nr_socket_turn.h"
 #include "nr_socket.h"
 #include "nr_socket_multi_tcp.h"
 
-static int next_automatic_preference = 224;
+static int next_automatic_preference = 127;
 
 static int nr_ice_candidate_initialize2(nr_ice_candidate *cand);
 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand);
 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand);
 static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg);
 #ifdef USE_TURN
 static int nr_ice_start_relay_turn(nr_ice_candidate *cand);
 static void nr_ice_turn_allocated_cb(NR_SOCKET sock, int how, void *cb_arg);
@@ -465,18 +465,22 @@ int nr_ice_candidate_compute_priority(nr
             r_log(LOG_ICE,LOG_ERR,"Out of preference values. Can't assign one for interface %s",cand->base.ifname);
             ABORT(R_NOT_FOUND);
           }
           r_log(LOG_ICE,LOG_DEBUG,"Automatically assigning preference for interface %s->%d",cand->base.ifname,
             next_automatic_preference);
           if (r=NR_reg_set2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,next_automatic_preference)){
             ABORT(r);
           }
-          interface_preference=next_automatic_preference;
+          interface_preference=next_automatic_preference << 1;
           next_automatic_preference--;
+          if (cand->base.ip_version == NR_IPV6) {
+            /* Prefer IPV6 over IPV4 on the same interface. */
+            interface_preference += 1;
+          }
         }
         else {
           ABORT(r);
         }
       }
     }
     else {
       char key_of_interface[MAXIFNAME + 41];
@@ -545,16 +549,21 @@ int nr_ice_candidate_initialize(nr_ice_c
       case RELAYED:
         protocol=NR_RESOLVE_PROTOCOL_TURN;
         /* Fall through */
 #endif
       case SERVER_REFLEXIVE:
         cand->state=NR_ICE_CAND_STATE_INITIALIZING;
 
         if(cand->stun_server->type == NR_ICE_STUN_SERVER_TYPE_ADDR) {
+          if(cand->base.ip_version != cand->stun_server->u.addr.ip_version) {
+            r_log(LOG_ICE, LOG_INFO, "ICE-CANDIDATE(%s): Skipping srflx/relayed candidate with different IP version (%d) than STUN/TURN server (%d).", cand->label,cand->base.ip_version,cand->stun_server->u.addr.ip_version);
+            ABORT(R_NOT_FOUND); /* Same error code when DNS lookup fails */
+          }
+
           /* Just copy the address */
           if (r=nr_transport_addr_copy(&cand->stun_server_addr,
                                        &cand->stun_server->u.addr)) {
             r_log(LOG_ICE,LOG_ERR,"ICE-CANDIDATE(%s): Could not copy STUN server addr", cand->label);
             ABORT(r);
           }
 
           if(r=nr_ice_candidate_initialize2(cand))
@@ -562,16 +571,27 @@ int nr_ice_candidate_initialize(nr_ice_c
         }
         else {
           nr_resolver_resource resource;
           resource.domain_name=cand->stun_server->u.dnsname.host;
           resource.port=cand->stun_server->u.dnsname.port;
           resource.stun_turn=protocol;
           resource.transport_protocol=cand->stun_server->transport;
 
+          switch (cand->base.ip_version) {
+            case NR_IPV4:
+              resource.address_family=AF_INET;
+              break;
+            case NR_IPV6:
+              resource.address_family=AF_INET6;
+              break;
+            default:
+              ABORT(R_BAD_ARGS);
+          }
+
           /* Try to resolve */
           if(!cand->ctx->resolver) {
             r_log(LOG_ICE, LOG_ERR, "ICE-CANDIDATE(%s): Can't use DNS names without a resolver", cand->label);
             ABORT(R_BAD_ARGS);
           }
 
           if(r=nr_resolver_resolve(cand->ctx->resolver,
                                    &resource,
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.c
@@ -994,16 +994,19 @@ int nr_ice_component_pair_candidate(nr_i
       if (!lcand->tcp_type && pcand->tcp_type)
         continue;
       if (lcand->tcp_type == TCP_TYPE_ACTIVE && pcand->tcp_type != TCP_TYPE_PASSIVE)
         continue;
       if (lcand->tcp_type == TCP_TYPE_SO && pcand->tcp_type != TCP_TYPE_SO)
         continue;
       if (lcand->tcp_type == TCP_TYPE_PASSIVE)
         continue;
+      if(pcand->addr.ip_version != lcand->addr.ip_version)
+        continue;
+
       /*
         Two modes, depending on |pair_all_remote|
 
         1. Pair remote candidates which have not been paired
            (used in initial pairing or in processing the other side's
            trickle candidates).
         2. Pair any remote candidate (used when processing our own
            trickle candidates).
@@ -1329,8 +1332,49 @@ int nr_ice_component_insert_pair(nr_ice_
       }
     }
 
     _status=0;
   abort:
     return(_status);
   }
 
+int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version)
+  {
+    int _status;
+    nr_ice_candidate *cand;
+    nr_ice_candidate *best_cand = NULL;
+
+    /* We have the component. Now find the "best" candidate, making
+       use of the fact that more "reliable" candidate types have
+       higher numbers. So, we sort by type and then priority within
+       type
+    */
+    cand=TAILQ_FIRST(&comp->candidates);
+    while(cand){
+      if (cand->state == NR_ICE_CAND_STATE_INITIALIZED &&
+          cand->addr.ip_version == ip_version) {
+        if (!best_cand) {
+          best_cand = cand;
+        }
+        else if (best_cand->type < cand->type) {
+          best_cand = cand;
+        } else if (best_cand->type == cand->type &&
+                   best_cand->priority < cand->priority) {
+          best_cand = cand;
+        }
+      }
+
+      cand=TAILQ_NEXT(cand,entry_comp);
+    }
+
+    /* No candidates */
+    if (!best_cand)
+      ABORT(R_NOT_FOUND);
+
+    *candp = best_cand;
+
+    _status=0;
+  abort:
+    return(_status);
+
+  }
+
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.h
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.h
@@ -88,13 +88,14 @@ int nr_ice_component_pair_candidates(nr_
 int nr_ice_component_service_pre_answer_requests(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, char *username, int *serviced);
 int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair);
 int nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair);
 int nr_ice_component_check_if_failed(nr_ice_component *comp);
 int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp);
 int nr_ice_component_set_failed(nr_ice_component *comp);
 int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp);
 int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair);
+int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version);
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 #endif
--- a/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.c
@@ -218,66 +218,39 @@ int nr_ice_media_stream_get_attributes(n
           RFREE(attrs[index]);
         }
         RFREE(attrs);
       }
     }
     return(_status);
   }
 
-
 /* Get a default candidate per 4.1.4 */
 int nr_ice_media_stream_get_default_candidate(nr_ice_media_stream *stream, int component, nr_ice_candidate **candp)
   {
-    int _status;
+    int r,_status;
     nr_ice_component *comp;
-    nr_ice_candidate *cand;
-    nr_ice_candidate *best_cand = NULL;
 
     comp=STAILQ_FIRST(&stream->components);
     while(comp){
       if (comp->component_id == component)
         break;
 
       comp=STAILQ_NEXT(comp,entry);
     }
 
     if (!comp)
       ABORT(R_NOT_FOUND);
 
-    /* We have the component. Now find the "best" candidate, making
-       use of the fact that more "reliable" candidate types have
-       higher numbers. So, we sort by type and then priority within
-       type
-    */
-    cand=TAILQ_FIRST(&comp->candidates);
-    while(cand){
-      if (cand->state == NR_ICE_CAND_STATE_INITIALIZED) {
-        if (!best_cand) {
-          best_cand = cand;
-        }
-        else {
-          if (best_cand->type < cand->type) {
-            best_cand = cand;
-          } else if (best_cand->type == cand->type) {
-            if (best_cand->priority < cand->priority)
-              best_cand = cand;
-          }
-        }
-      }
-
-      cand=TAILQ_NEXT(cand,entry_comp);
+    /* If there aren't any IPV4 candidates, try IPV6 */
+    if((r=nr_ice_component_get_default_candidate(comp, candp, NR_IPV4)) &&
+       (r=nr_ice_component_get_default_candidate(comp, candp, NR_IPV6))) {
+      ABORT(r);
     }
 
-    /* No candidates */
-    if (!best_cand)
-      ABORT(R_NOT_FOUND);
-
-    *candp = best_cand;
-
     _status=0;
   abort:
     return(_status);
   }
 
 
 int nr_ice_media_stream_pair_candidates(nr_ice_peer_ctx *pctx,nr_ice_media_stream *lstream,nr_ice_media_stream *pstream)
   {
--- a/media/mtransport/third_party/nICEr/src/ice/ice_parser.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_parser.c
@@ -115,17 +115,16 @@ abort:
 int
 nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_stream *stream,nr_ice_candidate **candp)
 {
     int r,_status;
     char* str = orig;
     nr_ice_candidate *cand;
     char *connection_address=0;
     unsigned int port;
-    in_addr_t addr;
     int i;
     unsigned int component_id;
     char *rel_addr=0;
     unsigned char transport;
 
     if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
         ABORT(R_NO_MEMORY);
 
@@ -207,32 +206,27 @@ nr_ice_peer_candidate_from_attribute(nr_
 
     /* Peer address/port */
     if ((r=grab_token(&str, &connection_address)))
         ABORT(r);
 
     if (*str == '\0')
         ABORT(R_BAD_DATA);
 
-    addr = inet_addr(connection_address);
-    if (addr == INADDR_NONE)
-        ABORT(R_BAD_DATA);
-
     skip_whitespace(&str);
     if (*str == '\0')
         ABORT(R_BAD_DATA);
 
     if (sscanf(str, "%u", &port) != 1)
         ABORT(R_BAD_DATA);
 
     if (port < 1 || port > 0x0FFFF)
         ABORT(R_BAD_DATA);
 
-    /* Assume v4 for now */
-    if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,transport,&cand->addr))
+    if ((r=nr_str_port_to_transport_addr(connection_address,port,transport,&cand->addr)))
       ABORT(r);
 
     skip_to_past_space(&str);
     if (*str == '\0')
         ABORT(R_BAD_DATA);
 
     /* Type */
     if (strncasecmp("typ", str, 3))
@@ -284,20 +278,16 @@ nr_ice_peer_candidate_from_attribute(nr_
             ABORT(R_BAD_DATA);
 
         if ((r=grab_token(&str, &rel_addr)))
             ABORT(r);
 
         if (*str == '\0')
             ABORT(R_BAD_DATA);
 
-        addr = inet_addr(rel_addr);
-        if (addr == INADDR_NONE)
-            ABORT(R_BAD_DATA);
-
         skip_whitespace(&str);
         if (*str == '\0')
             ABORT(R_BAD_DATA);
 
         if (strncasecmp("rport", str, 5))
               ABORT(R_BAD_DATA);
 
         fast_forward(&str, 5);
@@ -309,18 +299,17 @@ nr_ice_peer_candidate_from_attribute(nr_
             ABORT(R_BAD_DATA);
 
         if (sscanf(str, "%u", &port) != 1)
             ABORT(R_BAD_DATA);
 
         if (port < 1 || port > 0x0FFFF)
             ABORT(R_BAD_DATA);
 
-        /* Assume v4 for now */
-        if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,transport,&cand->base))
+        if ((r=nr_str_port_to_transport_addr(rel_addr,port,transport,&cand->base)))
           ABORT(r);
 
         skip_to_past_space(&str);
         /* it's expected to be at EOD at this point */
 
         break;
     default:
         ABORT(R_INTERNAL);
--- a/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c
+++ b/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c
@@ -251,17 +251,17 @@ int nr_socket_proxy_tunnel_connect(void 
 
   if ((r=nr_transport_addr_copy(&sock->remote_addr, addr))) {
     ABORT(r);
   }
 
   assert(config->proxy_host);
 
   /* Check if the proxy_host is already an IP address */
-  has_addr = !nr_ip4_str_port_to_transport_addr(config->proxy_host,
+  has_addr = !nr_str_port_to_transport_addr(config->proxy_host,
       config->proxy_port, IPPROTO_TCP, &proxy_addr);
 
   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_connect: %s", config->proxy_host);
 
   if (!has_addr && !config->resolver) {
     r_log(LOG_GENERIC,LOG_ERR,"nr_socket_proxy_tunnel_connect name resolver not configured");
     ABORT(R_NOT_FOUND);
   }
--- a/media/mtransport/third_party/nICEr/src/net/nr_resolver.h
+++ b/media/mtransport/third_party/nICEr/src/net/nr_resolver.h
@@ -41,16 +41,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 #define NR_RESOLVE_PROTOCOL_STUN 1
 #define NR_RESOLVE_PROTOCOL_TURN 2
 
 typedef struct nr_resolver_resource_ {
   char *domain_name;
   UINT2 port;
   int stun_turn;
   UCHAR transport_protocol;
+  UCHAR address_family;
 } nr_resolver_resource;
 
 typedef struct nr_resolver_vtbl_ {
   int (*destroy)(void **obj);
   int (*resolve)(void *obj,
                  nr_resolver_resource *resource,
                  int (*cb)(void *cb_arg, nr_transport_addr *addr),
                  void *cb_arg,
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr.c
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.c
@@ -95,54 +95,61 @@ int nr_transport_addr_fmt_ifname_addr_st
     int _status;
     char buffer[40];
 
     switch(addr->ip_version){
       case NR_IPV4:
         if (!inet_ntop(AF_INET, &addr->u.addr4.sin_addr,buffer,sizeof(buffer))) {
            strncpy(buffer, "[error]", len);
         }
-        snprintf(buf,len,"%s:%s",addr->ifname,buffer);
+        break;
+      case NR_IPV6:
+        if (!inet_ntop(AF_INET6, &addr->u.addr6.sin6_addr,buffer,sizeof(buffer))) {
+           strncpy(buffer, "[error]", len);
+        }
         break;
       default:
         ABORT(R_INTERNAL);
     }
+    snprintf(buf,len,"%s:%s",addr->ifname,buffer);
 
     _status=0;
   abort:
     return(_status);
   }
 
-int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int saddr_len, int protocol, int keep, nr_transport_addr *addr)
+int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int protocol, int keep, nr_transport_addr *addr)
   {
     int r,_status;
 
     if(!keep) memset(addr,0,sizeof(nr_transport_addr));
 
-    if(saddr->sa_family==PF_INET){
-      if(saddr_len != sizeof(struct sockaddr_in))
+    switch(protocol){
+      case IPPROTO_TCP:
+      case IPPROTO_UDP:
+        break;
+      default:
         ABORT(R_BAD_ARGS);
+    }
 
-      switch(protocol){
-        case IPPROTO_TCP:
-        case IPPROTO_UDP:
-          break;
-        default:
-          ABORT(R_BAD_ARGS);
-      }
+    addr->protocol=protocol;
+
+    if(saddr->sa_family==AF_INET){
       addr->ip_version=NR_IPV4;
-      addr->protocol=protocol;
 
       memcpy(&addr->u.addr4,saddr,sizeof(struct sockaddr_in));
       addr->addr=(struct sockaddr *)&addr->u.addr4;
-      addr->addr_len=saddr_len;
+      addr->addr_len=sizeof(struct sockaddr_in);
     }
-    else if(saddr->sa_family==PF_INET6){
-      /* Not implemented */
-      ABORT(R_INTERNAL);
+    else if(saddr->sa_family==AF_INET6){
+      addr->ip_version=NR_IPV6;
+
+      memcpy(&addr->u.addr6, saddr, sizeof(struct sockaddr_in6));
+      addr->addr=(struct sockaddr *)&addr->u.addr6;
+      addr->addr_len=sizeof(struct sockaddr_in6);
     }
     else
       ABORT(R_BAD_ARGS);
 
     if(r=nr_transport_addr_fmt_addr_string(addr))
       ABORT(r);
 
     _status=0;
@@ -201,26 +208,52 @@ int nr_ip4_port_to_transport_addr(UINT4 
     if(r=nr_transport_addr_fmt_addr_string(addr))
       ABORT(r);
 
     _status=0;
   abort:
     return(_status);
   }
 
-int nr_ip4_str_port_to_transport_addr(const char *ip4, UINT2 port, int protocol, nr_transport_addr *addr)
+int nr_str_port_to_transport_addr(const char *ip, UINT2 port, int protocol, nr_transport_addr *addr_out)
   {
     int r,_status;
-    in_addr_t ip_addr;
+    struct in_addr addr;
+    struct in6_addr addr6;
+
+    if (inet_pton(AF_INET, ip, &addr) == 1) {
+      if(r=nr_ip4_port_to_transport_addr(ntohl(addr.s_addr),port,protocol,addr_out))
+        ABORT(r);
+    } else if (inet_pton(AF_INET6, ip, &addr6) == 1) {
+      if(r=nr_ip6_port_to_transport_addr(&addr6,port,protocol,addr_out))
+        ABORT(r);
+    } else {
+      ABORT(R_BAD_DATA);
+    }
 
-    ip_addr=inet_addr(ip4);
-    if (ip_addr == INADDR_NONE)
-      ABORT(R_BAD_DATA);
-    /* Assume v4 for now */
-    if(r=nr_ip4_port_to_transport_addr(ntohl(ip_addr),port,protocol,addr))
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ip6_port_to_transport_addr(struct in6_addr* addr6, UINT2 port, int protocol, nr_transport_addr *addr)
+  {
+    int r,_status;
+
+    memset(addr, 0, sizeof(nr_transport_addr));
+
+    addr->ip_version=NR_IPV6;
+    addr->protocol=protocol;
+    addr->u.addr6.sin6_family=PF_INET6;
+    addr->u.addr6.sin6_port=htons(port);
+    memcpy(addr->u.addr6.sin6_addr.s6_addr, addr6->s6_addr, sizeof(addr6->s6_addr));
+    addr->addr=(struct sockaddr *)&addr->u.addr6;
+    addr->addr_len=sizeof(struct sockaddr_in6);
+
+    if(r=nr_transport_addr_fmt_addr_string(addr))
       ABORT(r);
 
     _status=0;
   abort:
     return(_status);
   }
 
 int nr_transport_addr_get_addrstring(nr_transport_addr *addr, char *str, int maxlen)
@@ -286,36 +319,16 @@ int nr_transport_addr_set_port(nr_transp
         ABORT(R_INTERNAL);
     }
 
     _status=0;
   abort:
     return(_status);
   }
 
-int nr_transport_addr_get_ip4(nr_transport_addr *addr, UINT4 *ip4p)
-  {
-    int _status;
-
-    switch(addr->ip_version){
-      case NR_IPV4:
-        *ip4p=ntohl(addr->u.addr4.sin_addr.s_addr);
-        break;
-      case NR_IPV6:
-        ABORT(R_NOT_FOUND);
-        break;
-      default:
-        ABORT(R_INTERNAL);
-    }
-
-    _status=0;
-  abort:
-    return(_status);
-  }
-
 /* memcmp() may not work if, for instance, the string or interface
    haven't been made. Hmmm.. */
 int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int mode)
   {
     assert(mode);
 
     if(addr1->ip_version != addr2->ip_version)
       return(1);
@@ -335,17 +348,23 @@ int nr_transport_addr_cmp(nr_transport_a
         if(addr1->u.addr4.sin_addr.s_addr != addr2->u.addr4.sin_addr.s_addr)
           return(1);
         if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ALL)
           return(0);
         if(addr1->u.addr4.sin_port != addr2->u.addr4.sin_port)
           return(1);
         break;
       case NR_IPV6:
-        UNIMPLEMENTED;
+        if(memcmp(addr1->u.addr6.sin6_addr.s6_addr,addr2->u.addr6.sin6_addr.s6_addr,sizeof(struct in6_addr)))
+          return(1);
+        if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ALL)
+          return(0);
+        if(addr1->u.addr6.sin6_port != addr2->u.addr6.sin6_port)
+          return(1);
+        break;
       default:
         abort();
     }
 
     return(0);
   }
 
 int nr_transport_addr_is_loopback(nr_transport_addr *addr)
@@ -358,30 +377,52 @@ int nr_transport_addr_is_loopback(nr_tra
               return 1;
             break;
           default:
             UNIMPLEMENTED;
             break;
         }
         break;
 
+      case NR_IPV6:
+        if(!memcmp(addr->u.addr6.sin6_addr.s6_addr,in6addr_loopback.s6_addr,sizeof(struct in6_addr)))
+          return(1);
+        break;
       default:
         UNIMPLEMENTED;
     }
 
     return(0);
   }
 
+int nr_transport_addr_is_link_local(nr_transport_addr *addr)
+  {
+    if(addr->ip_version == NR_IPV6){
+      UINT4* addrTop = (UINT4*)(addr->u.addr6.sin6_addr.s6_addr);
+      return ((*addrTop & htonl(0xFFC00000)) == htonl(0xFE800000));
+    } else {
+      assert(0);
+    }
+
+    return(0);
+  }
+
 int nr_transport_addr_is_wildcard(nr_transport_addr *addr)
   {
     switch(addr->ip_version){
       case NR_IPV4:
         if(addr->u.addr4.sin_addr.s_addr==INADDR_ANY)
           return(1);
         if(addr->u.addr4.sin_port==0)
           return(1);
         break;
+      case NR_IPV6:
+        if(!memcmp(addr->u.addr6.sin6_addr.s6_addr,in6addr_any.s6_addr,sizeof(struct in6_addr)))
+          return(1);
+        if(addr->u.addr6.sin6_port==0)
+          return(1);
+        break;
       default:
         UNIMPLEMENTED;
     }
 
     return(0);
   }
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr.h
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.h
@@ -66,33 +66,34 @@ typedef struct nr_transport_addr_ {
     struct sockaddr_in6 addr6;
   } u;
   char ifname[MAXIFNAME];
   /* A string version.
      56 = 5 ("IP6:[") + 39 (ipv6 address) + 2 ("]:") + 5 (port) + 4 (/UDP) + 1 (null) */
   char as_string[56];
 } nr_transport_addr;
 
-int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int saddr_len, int protocol, int keep, nr_transport_addr *addr);
+int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int protocol, int keep, nr_transport_addr *addr);
 
 // addresses, ports in local byte order
 int nr_ip4_port_to_transport_addr(UINT4 ip4, UINT2 port, int protocol, nr_transport_addr *addr);
-int nr_ip4_str_port_to_transport_addr(const char *ip4, UINT2 port, int protocol, nr_transport_addr *addr);
+int nr_str_port_to_transport_addr(const char *ip4, UINT2 port, int protocol, nr_transport_addr *addr);
+int nr_ip6_port_to_transport_addr(struct in6_addr* addr6, UINT2 port, int protocol, nr_transport_addr *addr);
 
 int nr_transport_addr_get_addrstring(nr_transport_addr *addr, char *str, int maxlen);
 int nr_transport_addr_get_port(nr_transport_addr *addr, int *port);
-int nr_transport_addr_get_ip4(nr_transport_addr *addr, UINT4 *ip4p);
 int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int mode);
 #define NR_TRANSPORT_ADDR_CMP_MODE_VERSION   1
 #define NR_TRANSPORT_ADDR_CMP_MODE_PROTOCOL  2
 #define NR_TRANSPORT_ADDR_CMP_MODE_ADDR      3
 #define NR_TRANSPORT_ADDR_CMP_MODE_ALL       4
 
 int nr_transport_addr_is_wildcard(nr_transport_addr *addr);
 int nr_transport_addr_is_loopback(nr_transport_addr *addr);
+int nr_transport_addr_is_link_local(nr_transport_addr *addr);
 int nr_transport_addr_copy(nr_transport_addr *to, nr_transport_addr *from);
 int nr_transport_addr_copy_keep_ifname(nr_transport_addr *to, nr_transport_addr *from);
 int nr_transport_addr_fmt_addr_string(nr_transport_addr *addr);
 int nr_transport_addr_fmt_ifname_addr_string(const nr_transport_addr *addr, char *buf, int len);
 int nr_transport_addr_set_port(nr_transport_addr *addr, int port);
 
 #endif
 
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c
@@ -48,16 +48,19 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #endif
 #include <assert.h>
 #include "nr_api.h"
 #include "transport_addr.h"
 #include "transport_addr_reg.h"
 
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46 /* Value used by linux/BSD */
+#endif
 
 int
 nr_reg_get_transport_addr(NR_registry prefix, int keep, nr_transport_addr *addr)
 {
     int r,_status;
     unsigned int count;
     char *address = 0;
     UINT2 port = 0;
@@ -102,17 +105,17 @@ nr_reg_get_transport_addr(NR_registry pr
         else if (!strcasecmp("udp", protocol))
             p = IPPROTO_UDP;
         else
             ABORT(R_BAD_DATA);
     }
 
     if (!keep) memset(addr, 0, sizeof(*addr));
 
-    if ((r=nr_ip4_str_port_to_transport_addr(address?address:"0.0.0.0", port, p, addr)))
+    if ((r=nr_str_port_to_transport_addr(address?address:"0.0.0.0", port, p, addr)))
         ABORT(r);
 
     if (ifname)
         strlcpy(addr->ifname, ifname, sizeof(addr->ifname));
 
     _status=0;
   abort:
     RFREE(protocol);
@@ -128,54 +131,69 @@ nr_reg_set_transport_addr(NR_registry pr
 
     if (! keep) {
         if ((r=NR_reg_del(prefix)))
             ABORT(r);
     }
 
     switch (addr->ip_version) {
     case NR_IPV4:
-        if (addr->u.addr4.sin_addr.s_addr != INADDR_ANY) {
+        if (!nr_transport_addr_is_wildcard(addr)) {
             if ((r=NR_reg_set2_string(prefix, "address", inet_ntoa(addr->u.addr4.sin_addr))))
                 ABORT(r);
         }
 
         if (addr->u.addr4.sin_port != 0) {
             if ((r=NR_reg_set2_uint2(prefix, "port", ntohs(addr->u.addr4.sin_port))))
                 ABORT(r);
         }
-
-        switch (addr->protocol) {
-        case IPPROTO_TCP:
-            if ((r=NR_reg_set2_string(prefix, "protocol", "tcp")))
-                ABORT(r);
-            break;
-        case IPPROTO_UDP:
-            if ((r=NR_reg_set2_string(prefix, "protocol", "udp")))
-                ABORT(r);
-            break;
-        default:
-            UNIMPLEMENTED;
-            break;
-        }
-
-        if (strlen(addr->ifname) > 0) {
-            if ((r=NR_reg_set2_string(prefix, "ifname", addr->ifname)))
-                ABORT(r);
-        }
         break;
 
     case NR_IPV6:
-        UNIMPLEMENTED;
+        if (!nr_transport_addr_is_wildcard(addr)) {
+          char address[INET6_ADDRSTRLEN];
+          if(!inet_ntop(AF_INET6, &addr->u.addr6.sin6_addr,address,sizeof(address))) {
+            ABORT(R_BAD_DATA);
+          }
+
+          if ((r=NR_reg_set2_string(prefix, "address", address))) {
+            ABORT(r);
+          }
+        }
+
+        if (addr->u.addr6.sin6_port != 0) {
+            if ((r=NR_reg_set2_uint2(prefix, "port", ntohs(addr->u.addr6.sin6_port))))
+                ABORT(r);
+        }
         break;
     default:
         ABORT(R_INTERNAL);
         break;
     }
 
+    /* We abort if neither NR_IPV4 or NR_IPV6 above */
+    switch (addr->protocol) {
+      case IPPROTO_TCP:
+        if ((r=NR_reg_set2_string(prefix, "protocol", "tcp")))
+          ABORT(r);
+        break;
+      case IPPROTO_UDP:
+        if ((r=NR_reg_set2_string(prefix, "protocol", "udp")))
+          ABORT(r);
+        break;
+      default:
+        UNIMPLEMENTED;
+        break;
+    }
+
+    if (strlen(addr->ifname) > 0) {
+      if ((r=NR_reg_set2_string(prefix, "ifname", addr->ifname)))
+        ABORT(r);
+    }
+
     _status=0;
   abort:
     if (_status)
         NR_reg_del(prefix);
     return _status;
 }
 
 int
--- a/media/mtransport/third_party/nICEr/src/stun/addrs.c
+++ b/media/mtransport/third_party/nICEr/src/stun/addrs.c
@@ -36,277 +36,52 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #include <csi_platform.h>
 #include <assert.h>
 #include <string.h>
 
 #ifdef WIN32
 #include <winsock2.h>
 #include <iphlpapi.h>
 #include <tchar.h>
-#else   /* UNIX */
-#include <sys/param.h>
+#else   /* !WIN32 */
+
 #include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
 #ifndef ANDROID
-#include <sys/syslog.h>
+/* This works on linux and BSD, but not android */
+#include <sys/types.h> /* getifaddrs */
+#include <ifaddrs.h> /* getifaddrs */
 #else
-#include <syslog.h>
+#include "ifaddrs-android.h"
+#define getifaddrs android_getifaddrs
+#define freeifaddrs android_freeifaddrs
+#endif
+
+#ifdef LINUX
+
+#ifdef ANDROID
 /* Work around an Android NDK < r8c bug */
 #undef __unused
-#endif
-#ifndef LINUX
-#include <net/if.h>
-#if !defined(__OpenBSD__) && !defined(__NetBSD__)
-#include <net/if_var.h>
-#endif
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <sys/sockio.h>
 #else
-#include <linux/sockios.h>
-#include <linux/if.h>
-#include <linux/kernel.h>
-#include <linux/wireless.h>
-#ifndef ANDROID
-#include <linux/ethtool.h>
-#endif
-#endif
-#include <net/route.h>
+#include <linux/if.h> /* struct ifreq, IFF_POINTTOPOINT */
+#include <linux/wireless.h> /* struct iwreq */
+#include <linux/ethtool.h> /* struct ethtool_cmd */
+#include <linux/sockios.h> /* SIOCETHTOOL */
+#endif /* ANDROID */
 
-/* IP */
-#include <netinet/in.h>
-#ifdef LINUX
-#include "sys/ioctl.h"
-#else
-#include <netinet/in_var.h>
-#endif
-#include <arpa/inet.h>
-#include <netdb.h>
-#endif  /* UNIX */
+#endif /* LINUX */
+
+#endif  /* !WIN32 */
 
 #include "stun.h"
 #include "addrs.h"
 
-
-
-#if defined(BSD) || defined(DARWIN)
-/*
- * Copyright (c) 1983, 1993
- *    The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *[3 Deleted as of 22nd July 1999; see
- *    ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
- *    for details]
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <sys/sysctl.h>
-
-static void stun_rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
-static int stun_grab_addrs(char *name, int addrcount,
-               struct ifa_msghdr *ifam,
-               nr_local_addr addrs[], int maxaddrs, int *count);
-static int
-nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr);
-
-
-/*
- * Expand the compacted form of addresses as returned via the
- * configuration read via sysctl().
- */
-#define ROUNDUP(a) \
-    ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-
-static void
-stun_rt_xaddrs(cp, cplim, rtinfo)
-    caddr_t cp, cplim;
-    struct rt_addrinfo *rtinfo;
-{
-    struct sockaddr *sa;
-    int i;
-
-    memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
-    for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
-        if ((rtinfo->rti_addrs & (1 << i)) == 0)
-            continue;
-        rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
-        ADVANCE(cp, sa);
-    }
-}
-
-static int
-stun_grab_addrs(char *name, int addrcount, struct ifa_msghdr *ifam, nr_local_addr addrs[], int maxaddrs, int *count)
-{
-    int r,_status;
-    int s = -1;
-    struct ifreq ifr;
-    struct rt_addrinfo info;
-    struct sockaddr_in *sin;
-
-    ifr.ifr_addr.sa_family = AF_INET;
-    strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-
-    if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) {
-      r_log(NR_LOG_STUN, LOG_ERR, "unable to obtain addresses from socket");
-      ABORT(R_FAILED);
-    }
-
-    while (addrcount > 0) {
-        info.rti_addrs = ifam->ifam_addrs;
-
-        /* Expand the compacted addresses */
-        stun_rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info);
-        addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
-        addrs[*count].interface.estimated_speed = 0;
-        /* TODO (Bug 895790) Get interface properties for Darwin */
-
-        switch (info.rti_info[RTAX_IFA]->sa_family) {
-        case AF_INET:
-            sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
-
-            if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sin, sizeof(*sin), IPPROTO_UDP, 0, &(addrs[*count].addr))))
-                ABORT(r);
-
-            strlcpy(addrs[*count].addr.ifname, name, sizeof(addrs[*count].addr.ifname));
-
-            ++*count;
-            break;
-        case AF_INET6:
-            UNIMPLEMENTED;
-            break;
-        }
-
-        addrcount--;
-
-        if (*count >= maxaddrs) {
-            r_log(NR_LOG_STUN, LOG_WARNING, "Address list truncated at %d out of %d entries", maxaddrs, maxaddrs+addrcount);
-            break;
-        }
-
-        ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
-    }
-
-    _status = 0;
-  abort:
-    if (s != -1) close(s);
-    return _status;
-}
-
-static int
-stun_get_mib_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
-{
-    int _status;
-    char name[32];
-    int flags;
-    int addrcount;
-    struct if_msghdr *ifm, *nextifm;
-    struct ifa_msghdr *ifam;
-    struct sockaddr_dl *sdl;
-    char *buf = 0;
-    char *lim;
-    char *next;
-    size_t needed;
-    int mib[6];
-
-    *count = 0;
-
-    mib[0] = CTL_NET;
-    mib[1] = PF_ROUTE;
-    mib[2] = 0;
-    mib[3] = AF_INET;
-    mib[4] = NET_RT_IFLIST;
-    mib[5] = 0;
-
-    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
-        errx(1, "iflist-sysctl-estimate");
-        ABORT(R_INTERNAL);
-    }
-
-    if ((buf = malloc(needed)) == NULL) {
-        errx(1, "malloc");
-        ABORT(R_NO_MEMORY);
-    }
-
-    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
-        errx(1, "actual retrieval of interface table");
-        ABORT(R_INTERNAL);
-    }
-
-    lim = buf + needed;
-
-    next = buf;
-    while (next < lim) {
-        ifm = (struct if_msghdr *)next;
-
-        if (ifm->ifm_type == RTM_IFINFO) {
-            sdl = (struct sockaddr_dl *)(ifm + 1);
-            flags = ifm->ifm_flags;
-        } else {
-            r_log(NR_LOG_STUN, LOG_WARNING, "out of sync parsing NET_RT_IFLIST");
-            r_log(NR_LOG_STUN, LOG_DEBUG, "expected %d, got %d, msglen = %d, buf:%p, next:%p, lim:%p", RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen, buf, next, lim);
-            ABORT(R_FAILED);
-        }
-
-        next += ifm->ifm_msglen;
-        ifam = NULL;
-        addrcount = 0;
-        while (next < lim) {
-
-            nextifm = (struct if_msghdr *)next;
-
-            if (nextifm->ifm_type != RTM_NEWADDR)
-                break;
-
-            if (ifam == NULL)
-                ifam = (struct ifa_msghdr *)nextifm;
-
-            addrcount++;
-            next += nextifm->ifm_msglen;
-        }
-
-        if (sdl->sdl_nlen > sizeof(name) - 1) {
-            ABORT(R_INTERNAL);
-        }
-
-        memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
-        name[sdl->sdl_nlen] = '\0';
-
-        stun_grab_addrs(name, addrcount, ifam, addrs, maxaddrs, count);
-    }
-
-    _status = 0;
-abort:
-    if (buf) free(buf);
-    return _status;
-}
-
-#elif defined(WIN32)
+#if defined(WIN32)
 
 #define WIN32_MAX_NUM_INTERFACES  20
 
 
 #define _NR_MAX_KEY_LENGTH 256
 #define _NR_MAX_NAME_LENGTH 512
 
 #define _ADAPTERS_BASE_REG "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
@@ -363,135 +138,16 @@ static int nr_win32_get_adapter_friendly
 
 abort:
     if (_status) {
       if (my_fn) free(my_fn);
     }
     return(_status);
 }
 
-
-static int
-stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
-{
-    int r,_status;
-    PIP_ADAPTER_INFO pAdapterInfo;
-    PIP_ADAPTER_INFO pAdapter = NULL;
-    PIP_ADDR_STRING pAddrString;
-    ULONG out_buf_len;
-    char *friendly_name=0;
-    char munged_ifname[IFNAMSIZ];
-    int n = 0;
-
-    *count = 0;
-
-    pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(sizeof(IP_ADAPTER_INFO));
-    out_buf_len = sizeof(IP_ADAPTER_INFO);
-
-    /* First call to GetAdaptersInfo is mainly to get length */
-
-    if (GetAdaptersInfo(pAdapterInfo, &out_buf_len) == ERROR_BUFFER_OVERFLOW) {
-      RFREE(pAdapterInfo);
-      pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(out_buf_len);
-      if (pAdapterInfo == NULL) {
-        r_log(NR_LOG_STUN, LOG_ERR, "Error allocating memory for GetAdaptersInfo output");
-        ABORT(R_NO_MEMORY);
-      }
-    }
-    if ((r = GetAdaptersInfo(pAdapterInfo, &out_buf_len)) != NO_ERROR) {
-      r_log(NR_LOG_STUN, LOG_ERR, "Got error from GetAdaptersInfo");
-      ABORT(R_INTERNAL);
-    }
-    r_log(NR_LOG_STUN, LOG_DEBUG, "Got AdaptersInfo");
-
-    pAdapter = pAdapterInfo;
-
-    while (pAdapter) {
-      char *c;
-
-      r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Name (GUID) = %s", pAdapter->AdapterName);
-      r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Description = %s", pAdapter->Description);
-
-      if (nr_win32_get_adapter_friendly_name(pAdapter->AdapterName, &friendly_name)) {
-        friendly_name = 0;
-      }
-      if (friendly_name && *friendly_name) {
-        r_log(NR_LOG_STUN, LOG_INFO, "Found adapter with friendly name: %s", friendly_name);
-        snprintf(munged_ifname, IFNAMSIZ, "%s%c", friendly_name, 0);
-        RFREE(friendly_name);
-        friendly_name = 0;
-      } else {
-        // Not all adapters follow the friendly name convention. Windows' PPTP
-        // VPN adapter puts "VPN Connection 2" in the Description field instead.
-        // Windows's renaming-logic appears to enforce uniqueness in spite of this.
-        r_log(NR_LOG_STUN, LOG_INFO, "Found adapter with description: %s", pAdapter->Description);
-        snprintf(munged_ifname, IFNAMSIZ, "%s%c", pAdapter->Description, 0);
-      }
-      /* replace spaces with underscores */
-      c = strchr(munged_ifname, ' ');
-      while (c != NULL) {
-        *c = '_';
-         c = strchr(munged_ifname, ' ');
-      }
-      c = strchr(munged_ifname, '.');
-      while (c != NULL) {
-        *c = '+';
-         c = strchr(munged_ifname, '.');
-      }
-
-      r_log(NR_LOG_STUN, LOG_INFO, "Converted ifname: %s", munged_ifname);
-
-      for (pAddrString = &(pAdapter->IpAddressList); pAddrString != NULL; pAddrString = pAddrString->Next) {
-        unsigned long this_addr = inet_addr(pAddrString->IpAddress.String);
-        nr_transport_addr *addr = &(addrs[n].addr);
-
-        if (this_addr == 0)
-          continue;
-
-        r_log(NR_LOG_STUN, LOG_INFO, "Adapter %s address: %s", munged_ifname, pAddrString->IpAddress.String);
-
-        addr->ip_version=NR_IPV4;
-        addr->protocol = IPPROTO_UDP;
-
-        addr->u.addr4.sin_family=PF_INET;
-        addr->u.addr4.sin_port=0;
-        addr->u.addr4.sin_addr.s_addr=this_addr;
-        addr->addr=(struct sockaddr *)&(addr->u.addr4);
-        addr->addr_len=sizeof(struct sockaddr_in);
-
-        strlcpy(addr->ifname, munged_ifname, sizeof(addr->ifname));
-        snprintf(addr->as_string,40,"IP4:%s:%d",
-                 inet_ntoa(addr->u.addr4.sin_addr),
-                 ntohs(addr->u.addr4.sin_port));
-
-        /* TODO: (Bug 895793) Getting interface properties for Windows */
-        addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
-        addrs[n].interface.estimated_speed = 0;
-
-        if (++n >= maxaddrs)
-          goto done;
-      }
-
-      pAdapter = pAdapter->Next;
-    }
-
-  done:
-    *count = n;
-    _status = 0;
-
-  abort:
-    RFREE(pAdapterInfo);
-    RFREE(friendly_name);
-    return _status;
-}
-
-#ifdef GET_WIN32_ADDRS_NO_WIN2K
-   /* Here's a nice way to get adapter addresses and names, but it
-    * isn't supported on Win2000.
-    */
 static int
 stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
 {
     int r,_status;
     PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL, tmpAddress = NULL;
     ULONG buflen;
     char munged_ifname[IFNAMSIZ];
     int n = 0;
@@ -500,31 +156,31 @@ stun_get_win32_addrs(nr_local_addr addrs
 
     if (maxaddrs <= 0)
       ABORT(R_INTERNAL);
 
     /* Call GetAdaptersAddresses() twice.  First, just to get the buf length */
 
     buflen = 0;
 
-    r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen);
+    r = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, AdapterAddresses, &buflen);
     if (r != ERROR_BUFFER_OVERFLOW) {
       r_log(NR_LOG_STUN, LOG_ERR, "Error getting buf len from GetAdaptersAddresses()");
       ABORT(R_INTERNAL);
     }
 
     AdapterAddresses = (PIP_ADAPTER_ADDRESSES) RMALLOC(buflen);
     if (AdapterAddresses == NULL) {
       r_log(NR_LOG_STUN, LOG_ERR, "Error allocating buf for GetAdaptersAddresses()");
       ABORT(R_NO_MEMORY);
     }
 
     /* for real, this time */
 
-    r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen);
+    r = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, AdapterAddresses, &buflen);
     if (r != NO_ERROR) {
       r_log(NR_LOG_STUN, LOG_ERR, "Error getting addresses from GetAdaptersAddresses()");
       ABORT(R_INTERNAL);
     }
 
     /* Loop through the adapters */
 
     for (tmpAddress = AdapterAddresses; tmpAddress != NULL; tmpAddress = tmpAddress->Next) {
@@ -549,17 +205,17 @@ stun_get_win32_addrs(nr_local_addr addrs
       if ((tmpAddress->IfIndex != 0) || (tmpAddress->Ipv6IfIndex != 0)) {
         IP_ADAPTER_UNICAST_ADDRESS *u = 0;
 
         for (u = tmpAddress->FirstUnicastAddress; u != 0; u = u->Next) {
           SOCKET_ADDRESS *sa_addr = &u->Address;
 
           if ((sa_addr->lpSockaddr->sa_family == AF_INET) ||
               (sa_addr->lpSockaddr->sa_family == AF_INET6)) {
-            if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, sizeof(*sa_addr->lpSockaddr), IPPROTO_UDP, 0, &(addrs[n].addr))))
+            if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, IPPROTO_UDP, 0, &(addrs[n].addr))))
                 ABORT(r);
           }
           else {
             r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized sa_family for adapteraddress %s",munged_ifname);
             continue;
           }
 
           strlcpy(addrs[n].addr.ifname, munged_ifname, sizeof(addrs[n].addr.ifname));
@@ -575,141 +231,108 @@ stun_get_win32_addrs(nr_local_addr addrs
    done:
     *count = n;
     _status = 0;
 
   abort:
     RFREE(AdapterAddresses);
     return _status;
 }
-#endif  /* GET_WIN32_ADDRS_NO_WIN2K */
 
-#elif defined(__sparc__)
+#else /* WIN32 */
 
 static int
-stun_get_sparc_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
-{
-    *count = 0;
-    UNIMPLEMENTED; /*TODO !nn! - sparc */
-    return 0;
-}
-
-#else
+nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr);
 
 static int
-stun_get_siocgifconf_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
+stun_getifaddrs(nr_local_addr addrs[], int maxaddrs, int *count)
 {
-   struct ifconf ifc;
-   int _status;
-   int s = socket( AF_INET, SOCK_DGRAM, 0 );
-   int len = 100 * sizeof(struct ifreq);
-   int r;
-   int e;
-   char *ptr;
-   int tl;
-   int n;
-   struct ifreq ifr2;
+  int r,_status;
+  struct ifaddrs* if_addrs_head=NULL;
+  struct ifaddrs* if_addr;
 
-   char buf[ len ];
-
-   ifc.ifc_len = len;
-   ifc.ifc_buf = buf;
-
-   e = ioctl(s,SIOCGIFCONF,&ifc);
+  *count=0;
 
-   if ( e == -1 )
-   {
-      return(R_INTERNAL);
-   }
+  if (getifaddrs(&if_addrs_head) == -1) {
+    r_log(NR_LOG_STUN, LOG_ERR, "getifaddrs error e = %d", errno);
+    ABORT(R_INTERNAL);
+  }
 
-   ptr = buf;
-   tl = ifc.ifc_len;
-   n=0;
+  if_addr = if_addrs_head;
 
-   while ( (tl > 0) && ( n < maxaddrs) )
-   {
-      struct ifreq* ifr = (struct ifreq *)ptr;
-
-#ifdef LINUX
-      int si = sizeof(struct ifreq);
-#ifndef ANDROID
-      struct ethtool_cmd ecmd;
-      struct iwreq wrq;
-#endif
-#else
-      int si = sizeof(ifr->ifr_name) + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr));
-#endif
-      tl -= si;
-      ptr += si;
+  while (if_addr && *count < maxaddrs) {
+    switch (if_addr->ifa_addr->sa_family) {
+      case AF_INET:
+      case AF_INET6:
+        if (r=nr_sockaddr_to_transport_addr(if_addr->ifa_addr, IPPROTO_UDP, 0, &(addrs[*count].addr))) {
+          r_log(NR_LOG_STUN, LOG_ERR, "nr_sockaddr_to_transport_addr error r = %d", r);
+        } else {
+#if defined(LINUX) && !defined(ANDROID)
+          struct ethtool_cmd ecmd;
+          struct ifreq ifr;
+          struct iwreq wrq;
+          int e;
+          int s = socket(AF_INET, SOCK_DGRAM, 0);
 
-      ifr2 = *ifr;
-
-      e = ioctl(s,SIOCGIFADDR,&ifr2);
-      if ( e == -1 )
-      {
-          continue;
-      }
-
-      //r_log(NR_LOG_STUN, LOG_ERR, "ioctl addr e = %d",e);
-
-      if ((r=nr_sockaddr_to_transport_addr(&ifr2.ifr_addr, sizeof(ifr2.ifr_addr), IPPROTO_UDP, 0, &(addrs[n].addr)))) {
-          r_log(NR_LOG_STUN, LOG_WARNING, "Problem transforming address");
-      }
-      else {
-          addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
-          addrs[n].interface.estimated_speed = 0;
-#if defined(LINUX) && !defined(ANDROID)
+          strncpy(ifr.ifr_name, if_addr->ifa_name, sizeof(ifr.ifr_name));
           /* TODO (Bug 896851): interface property for Android */
           /* Getting ethtool for ethernet information. */
           ecmd.cmd = ETHTOOL_GSET;
-          ifr2.ifr_data = (void*)&ecmd;
-          e = ioctl(s, SIOCETHTOOL, &ifr2);
+          /* In/out param */
+          ifr.ifr_data = (void*)&ecmd;
+
+          e = ioctl(s, SIOCETHTOOL, &ifr);
           if (e == 0)
           {
              /* For wireless network, we won't get ethtool, it's a wired
-                connection */
-             addrs[n].interface.type = NR_INTERFACE_TYPE_WIRED;
+              * connection */
+             addrs[*count].interface.type = NR_INTERFACE_TYPE_WIRED;
 #ifdef DONT_HAVE_ETHTOOL_SPEED_HI
-             addrs[n].interface.estimated_speed = ecmd.speed;
+             addrs[*count].interface.estimated_speed = ecmd.speed;
 #else
-             addrs[n].interface.estimated_speed = ((ecmd.speed_hi << 16) | ecmd.speed) * 1000;
+             addrs[*count].interface.estimated_speed = ((ecmd.speed_hi << 16) | ecmd.speed) * 1000;
 #endif
           }
 
-          strncpy(wrq.ifr_name, ifr->ifr_name, sizeof(wrq.ifr_name));
+          strncpy(wrq.ifr_name, if_addr->ifa_name, sizeof(wrq.ifr_name));
           e = ioctl(s, SIOCGIWRATE, &wrq);
           if (e == 0)
           {
-             addrs[n].interface.type = NR_INTERFACE_TYPE_WIFI;
-             addrs[n].interface.estimated_speed = wrq.u.bitrate.value / 1000;
+             addrs[*count].interface.type = NR_INTERFACE_TYPE_WIFI;
+             addrs[*count].interface.estimated_speed = wrq.u.bitrate.value / 1000;
           }
 
-          ifr2 = *ifr;
-          e = ioctl(s, SIOCGIFFLAGS, &ifr2);
-          if (e == 0)
+          if (if_addr->ifa_flags & IFF_POINTOPOINT)
           {
-             if (ifr2.ifr_flags & IFF_POINTOPOINT)
-             {
-                addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN | NR_INTERFACE_TYPE_VPN;
-                /* TODO (Bug 896913): find backend network type of this VPN */
-             }
+             addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN | NR_INTERFACE_TYPE_VPN;
+             /* TODO (Bug 896913): find backend network type of this VPN */
           }
+#else
+          addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
+          addrs[*count].interface.estimated_speed = 0;
 #endif
-          strlcpy(addrs[n].addr.ifname, ifr->ifr_name, sizeof(addrs[n].addr.ifname));
-          ++n;
-      }
-   }
+          strlcpy(addrs[*count].addr.ifname, if_addr->ifa_name, sizeof(addrs[*count].addr.ifname));
+          ++(*count);
+        }
+        break;
+      default:
+        ;
+    }
 
-   close(s);
-
-   *count = n;
+    if_addr = if_addr->ifa_next;
+  }
 
-    _status = 0;
-    return _status;
+  _status=0;
+abort:
+  if (if_addrs_head) {
+    freeifaddrs(if_addrs_head);
+  }
+  return(_status);
 }
+
 #endif
 
 static int
 nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr)
 {
     int i;
     int different;
 
@@ -719,17 +342,17 @@ nr_stun_is_duplicate_addr(nr_local_addr 
         if (!different)
             return 1;  /* duplicate */
     }
 
     return 0;
 }
 
 int
-nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int *count)
+nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int remove_link_local, int *count)
 {
     int r, _status;
     nr_local_addr *tmp = 0;
     int i;
     int n;
 
     tmp = RMALLOC(*count * sizeof(*tmp));
     if (!tmp)
@@ -738,16 +361,21 @@ nr_stun_remove_duplicate_addrs(nr_local_
     n = 0;
     for (i = 0; i < *count; ++i) {
         if (nr_stun_is_duplicate_addr(tmp, n, &addrs[i])) {
             /* skip addrs[i], it's a duplicate */
         }
         else if (remove_loopback && nr_transport_addr_is_loopback(&addrs[i].addr)) {
             /* skip addrs[i], it's a loopback */
         }
+        else if (remove_link_local &&
+                 addrs[i].addr.ip_version == NR_IPV6 &&
+                 nr_transport_addr_is_link_local(&addrs[i].addr)) {
+            /* skip addrs[i], it's a link-local address */
+        }
         else {
             /* otherwise, copy it to the temporary array */
             if ((r=nr_local_addr_copy(&tmp[n], &addrs[i])))
                 ABORT(r);
             ++n;
         }
     }
 
@@ -763,33 +391,29 @@ nr_stun_remove_duplicate_addrs(nr_local_
   abort:
     RFREE(tmp);
     return _status;
 }
 
 #ifndef USE_PLATFORM_NR_STUN_GET_ADDRS
 
 int
-nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int drop_loopback, int *count)
+nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int drop_loopback, int drop_link_local, int *count)
 {
     int _status=0;
     int i;
     char typestr[100];
 
-#if defined(BSD) || defined(DARWIN)
-    _status = stun_get_mib_addrs(addrs, maxaddrs, count);
-#elif defined(WIN32)
+#ifdef WIN32
     _status = stun_get_win32_addrs(addrs, maxaddrs, count);
-#elif defined(__sparc__)
-    _status = stun_get_sparc_addrs(addrs, maxaddrs, count);
 #else
-    _status = stun_get_siocgifconf_addrs(addrs, maxaddrs, count);
+    _status = stun_getifaddrs(addrs, maxaddrs, count);
 #endif
 
-    nr_stun_remove_duplicate_addrs(addrs, drop_loopback, count);
+    nr_stun_remove_duplicate_addrs(addrs, drop_loopback, drop_link_local, count);
 
     for (i = 0; i < *count; ++i) {
     nr_local_addr_fmt_info_string(addrs+i,typestr,sizeof(typestr));
         r_log(NR_LOG_STUN, LOG_DEBUG, "Address %d: %s on %s, type: %s\n",
             i,addrs[i].addr.as_string,addrs[i].addr.ifname,typestr);
     }
 
     return _status;
--- a/media/mtransport/third_party/nICEr/src/stun/addrs.h
+++ b/media/mtransport/third_party/nICEr/src/stun/addrs.h
@@ -32,12 +32,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
 
 #ifndef _addrs_h_
 #define _addrs_h_
 
 #include "transport_addr.h"
 #include "local_addr.h"
 
-int nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int remove_loopback, int *count);
-int nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback,int *count);
+int nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int remove_loopback, int remove_link_local, int *count);
+int nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int remove_link_local, int *count);
 
 #endif
copy from media/webrtc/trunk/webrtc/base/ifaddrs-android.cc
copy to media/mtransport/third_party/nICEr/src/stun/ifaddrs-android.c
--- a/media/webrtc/trunk/webrtc/base/ifaddrs-android.cc
+++ b/media/mtransport/third_party/nICEr/src/stun/ifaddrs-android.c
@@ -1,223 +1,242 @@
 /*
- *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
+Copyright (c) 2011, The WebRTC project authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
 
-#if defined(WEBRTC_ANDROID)
-#include "webrtc/base/ifaddrs-android.h"
+  * Neither the name of Google nor the names of its contributors may
+    be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if defined(ANDROID)
+#include "ifaddrs-android.h"
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/utsname.h>
 #include <sys/ioctl.h>
 #include <netinet/in.h>
 #include <net/if.h>
 #include <unistd.h>
 #include <errno.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 
-namespace {
-
 struct netlinkrequest {
-  nlmsghdr header;
-  ifaddrmsg msg;
+  struct nlmsghdr header;
+  struct ifaddrmsg msg;
 };
 
-const int kMaxReadSize = 4096;
-
-}  // namespace
+static const int kMaxReadSize = 4096;
 
-namespace rtc {
-
-int set_ifname(struct ifaddrs* ifaddr, int interface) {
+static int set_ifname(struct ifaddrs* ifaddr, int interface) {
   char buf[IFNAMSIZ] = {0};
   char* name = if_indextoname(interface, buf);
   if (name == NULL) {
     return -1;
   }
-  ifaddr->ifa_name = new char[strlen(name) + 1];
+  ifaddr->ifa_name = malloc(strlen(name) + 1);
   strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
   return 0;
 }
 
-int set_flags(struct ifaddrs* ifaddr) {
+static int set_flags(struct ifaddrs* ifaddr) {
   int fd = socket(AF_INET, SOCK_DGRAM, 0);
   if (fd == -1) {
     return -1;
   }
-  ifreq ifr;
+  struct ifreq ifr;
   memset(&ifr, 0, sizeof(ifr));
   strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
   int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
   close(fd);
   if (rc == -1) {
     return -1;
   }
   ifaddr->ifa_flags = ifr.ifr_flags;
   return 0;
 }
 
-int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data,
+static int set_addresses(struct ifaddrs* ifaddr, struct ifaddrmsg* msg, void* data,
                   size_t len) {
   if (msg->ifa_family == AF_INET) {
-    sockaddr_in* sa = new sockaddr_in;
+    struct sockaddr_in* sa = malloc(sizeof(struct sockaddr_in));
+    memset(sa, 0, sizeof(struct sockaddr_in));
     sa->sin_family = AF_INET;
     memcpy(&sa->sin_addr, data, len);
-    ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
+    ifaddr->ifa_addr = (struct sockaddr*)sa;
   } else if (msg->ifa_family == AF_INET6) {
-    sockaddr_in6* sa = new sockaddr_in6;
+    struct sockaddr_in6* sa = malloc(sizeof(struct sockaddr_in6));
+    memset(sa, 0, sizeof(struct sockaddr_in6));
     sa->sin6_family = AF_INET6;
     sa->sin6_scope_id = msg->ifa_index;
     memcpy(&sa->sin6_addr, data, len);
-    ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
+    ifaddr->ifa_addr = (struct sockaddr*)sa;
   } else {
     return -1;
   }
   return 0;
 }
 
-int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
+static int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
   char* prefix = NULL;
   if (family == AF_INET) {
-    sockaddr_in* mask = new sockaddr_in;
+    struct sockaddr_in* mask = malloc(sizeof(struct sockaddr_in));
+    memset(mask, 0, sizeof(struct sockaddr_in));
     mask->sin_family = AF_INET;
-    memset(&mask->sin_addr, 0, sizeof(in_addr));
-    ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
+    memset(&mask->sin_addr, 0, sizeof(struct in_addr));
+    ifaddr->ifa_netmask = (struct sockaddr*)mask;
     if (prefixlen > 32) {
       prefixlen = 32;
     }
-    prefix = reinterpret_cast<char*>(&mask->sin_addr);
+    prefix = (char*)&mask->sin_addr;
   } else if (family == AF_INET6) {
-    sockaddr_in6* mask = new sockaddr_in6;
+    struct sockaddr_in6* mask = malloc(sizeof(struct sockaddr_in6));
+    memset(mask, 0, sizeof(struct sockaddr_in6));
     mask->sin6_family = AF_INET6;
-    memset(&mask->sin6_addr, 0, sizeof(in6_addr));
-    ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
+    memset(&mask->sin6_addr, 0, sizeof(struct in6_addr));
+    ifaddr->ifa_netmask = (struct sockaddr*)mask;
     if (prefixlen > 128) {
       prefixlen = 128;
     }
-    prefix = reinterpret_cast<char*>(&mask->sin6_addr);
+    prefix = (char*)&mask->sin6_addr;
   } else {
     return -1;
   }
   for (int i = 0; i < (prefixlen / 8); i++) {
     *prefix++ = 0xFF;
   }
   char remainder = 0xff;
   remainder <<= (8 - prefixlen % 8);
   *prefix = remainder;
   return 0;
 }
 
-int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes,
+static int populate_ifaddrs(struct ifaddrs* ifaddr, struct ifaddrmsg* msg, void* bytes,
                      size_t len) {
   if (set_ifname(ifaddr, msg->ifa_index) != 0) {
     return -1;
   }
   if (set_flags(ifaddr) != 0) {
     return -1;
   }
   if (set_addresses(ifaddr, msg, bytes, len) != 0) {
     return -1;
   }
   if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
     return -1;
   }
   return 0;
 }
 
-int getifaddrs(struct ifaddrs** result) {
+int android_getifaddrs(struct ifaddrs** result) {
   int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
   if (fd < 0) {
     return -1;
   }
 
-  netlinkrequest ifaddr_request;
+  struct netlinkrequest ifaddr_request;
   memset(&ifaddr_request, 0, sizeof(ifaddr_request));
   ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
   ifaddr_request.header.nlmsg_type = RTM_GETADDR;
-  ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg));
+  ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
 
   ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
-  if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) {
+  if ((size_t)count != ifaddr_request.header.nlmsg_len) {
     close(fd);
     return -1;
   }
   struct ifaddrs* start = NULL;
   struct ifaddrs* current = NULL;
   char buf[kMaxReadSize];
   ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
   while (amount_read > 0) {
-    nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
-    size_t header_size = static_cast<size_t>(amount_read);
+    struct nlmsghdr* header = (struct nlmsghdr*)&buf[0];
+    size_t header_size = (size_t)amount_read;
     for ( ; NLMSG_OK(header, header_size);
           header = NLMSG_NEXT(header, header_size)) {
       switch (header->nlmsg_type) {
         case NLMSG_DONE:
-          // Success. Return.
+          /* Success. Return. */
           *result = start;
           close(fd);
           return 0;
         case NLMSG_ERROR:
           close(fd);
-          freeifaddrs(start);
+          android_freeifaddrs(start);
           return -1;
         case RTM_NEWADDR: {
-          ifaddrmsg* address_msg =
-              reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
-          rtattr* rta = IFA_RTA(address_msg);
+          struct ifaddrmsg* address_msg =
+              (struct ifaddrmsg*)NLMSG_DATA(header);
+          struct rtattr* rta = IFA_RTA(address_msg);
           ssize_t payload_len = IFA_PAYLOAD(header);
           while (RTA_OK(rta, payload_len)) {
             if (rta->rta_type == IFA_ADDRESS) {
               int family = address_msg->ifa_family;
               if (family == AF_INET || family == AF_INET6) {
-                ifaddrs* newest = new ifaddrs;
-                memset(newest, 0, sizeof(ifaddrs));
+                struct ifaddrs* newest = malloc(sizeof(struct ifaddrs));
+                memset(newest, 0, sizeof(struct ifaddrs));
                 if (current) {
                   current->ifa_next = newest;
                 } else {
                   start = newest;
                 }
                 if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta),
                                      RTA_PAYLOAD(rta)) != 0) {
-                  freeifaddrs(start);
+                  android_freeifaddrs(start);
                   *result = NULL;
                   return -1;
                 }
                 current = newest;
               }
             }
             rta = RTA_NEXT(rta, payload_len);
           }
           break;
         }
       }
     }
     amount_read = recv(fd, &buf, kMaxReadSize, 0);
   }
   close(fd);
-  freeifaddrs(start);
+  android_freeifaddrs(start);
   return -1;
 }
 
-void freeifaddrs(struct ifaddrs* addrs) {
+void android_freeifaddrs(struct ifaddrs* addrs) {
   struct ifaddrs* last = NULL;
   struct ifaddrs* cursor = addrs;
   while (cursor) {
-    delete[] cursor->ifa_name;
-    delete cursor->ifa_addr;
-    delete cursor->ifa_netmask;
+    free(cursor->ifa_name);
+    free(cursor->ifa_addr);
+    free(cursor->ifa_netmask);
     last = cursor;
     cursor = cursor->ifa_next;
-    delete last;
+    free(last);
   }
 }
 
-}  // namespace rtc
-#endif  // defined(WEBRTC_ANDROID)
+#endif  /* defined(ANDROID) */
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/stun/ifaddrs-android.h
@@ -0,0 +1,57 @@
+/*
+Copyright (c) 2011, The WebRTC project authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+  * Neither the name of Google nor the names of its contributors may
+    be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef WEBRTC_BASE_IFADDRS_ANDROID_H_
+#define WEBRTC_BASE_IFADDRS_ANDROID_H_
+
+#include <stdio.h>
+#include <sys/socket.h>
+
+/* Implementation of getifaddrs for Android.
+ * Fills out a list of ifaddr structs (see below) which contain information
+ * about every network interface available on the host.
+ * See 'man getifaddrs' on Linux or OS X (nb: it is not a POSIX function). */
+struct ifaddrs {
+  struct ifaddrs* ifa_next;
+  char* ifa_name;
+  unsigned int ifa_flags;
+  struct sockaddr* ifa_addr;
+  struct sockaddr* ifa_netmask;
+  /* Real ifaddrs has broadcast, point to point and data members.
+   * We don't need them (yet?). */
+};
+
+int android_getifaddrs(struct ifaddrs** result);
+void android_freeifaddrs(struct ifaddrs* addrs);
+
+#endif  /* WEBRTC_BASE_IFADDRS_ANDROID_H_ */
+
--- a/media/mtransport/third_party/nICEr/src/stun/stun_codec.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_codec.c
@@ -441,19 +441,25 @@ nr_stun_attr_codec_addr_encode(nr_stun_a
          || nr_stun_encode(&pad, 1               , buflen, buf, &offset)
          || nr_stun_encode(&family, 1            , buflen, buf, &offset)
          || nr_stun_encode_htons(ntohs(addr->u.addr4.sin_port), buflen, buf, &offset)
          || nr_stun_encode_htonl(ntohl(addr->u.addr4.sin_addr.s_addr), buflen, buf, &offset))
             ABORT(R_FAILED);
         break;
 
     case NR_IPV6:
-        assert(0);
-        ABORT(R_INTERNAL);
+        family = NR_STUN_IPV6_FAMILY;
+        if (nr_stun_encode_htons(20              , buflen, buf, &offset)
+         || nr_stun_encode(&pad, 1               , buflen, buf, &offset)
+         || nr_stun_encode(&family, 1            , buflen, buf, &offset)
+         || nr_stun_encode_htons(ntohs(addr->u.addr6.sin6_port), buflen, buf, &offset)
+         || nr_stun_encode(addr->u.addr6.sin6_addr.s6_addr, 16, buflen, buf, &offset))
+            ABORT(R_FAILED);
         break;
+
     default:
         assert(0);
         ABORT(R_INTERNAL);
         break;
     }
 
     *attrlen = offset - start;
 
@@ -465,16 +471,17 @@ nr_stun_attr_codec_addr_encode(nr_stun_a
 static int
 nr_stun_attr_codec_addr_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
 {
     int _status;
     UCHAR pad;
     UCHAR family;
     UINT2 port;
     UINT4 addr4;
+    struct in6_addr addr6;
     nr_transport_addr *result = data;
 
     if (nr_stun_decode(1, buf, buflen, &offset, &pad)
      || nr_stun_decode(1, buf, buflen, &offset, &family))
         ABORT(R_FAILED);
 
     switch (family) {
     case NR_STUN_IPV4_FAMILY:
@@ -487,27 +494,27 @@ nr_stun_attr_codec_addr_decode(nr_stun_a
          || nr_stun_decode_htonl(buf, buflen, &offset, &addr4))
             ABORT(R_FAILED);
 
         if (nr_ip4_port_to_transport_addr(addr4, port, IPPROTO_UDP, result))
             ABORT(R_FAILED);
         break;
 
     case NR_STUN_IPV6_FAMILY:
-        if (attrlen != 16) {
+        if (attrlen != 20) {
             r_log(NR_LOG_STUN, LOG_WARNING, "Illegal attribute length: %d", attrlen);
             ABORT(R_FAILED);
         }
 
-        r_log(NR_LOG_STUN, LOG_WARNING, "IPv6 not supported");
-#ifdef NDEBUG
-        ABORT(SKIP_ATTRIBUTE_DECODE);
-#else
-        UNIMPLEMENTED;
-#endif /* NDEBUG */
+        if (nr_stun_decode_htons(buf, buflen, &offset, &port)
+         || nr_stun_decode(16, buf, buflen, &offset, addr6.s6_addr))
+            ABORT(R_FAILED);
+
+        if (nr_ip6_port_to_transport_addr(&addr6, port, IPPROTO_UDP, result))
+            ABORT(R_FAILED);
         break;
 
     default:
         r_log(NR_LOG_STUN, LOG_WARNING, "Illegal address family: %d", family);
         ABORT(R_FAILED);
         break;
     }
 
@@ -1089,17 +1096,17 @@ nr_stun_attr_codec_xor_mapped_address_en
     r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
 
     /* this needs to be the magic cookie in the header and not
      * the MAGIC_COOKIE constant because if we're talking to
      * older servers (that don't have a magic cookie) they use
      * message ID for this */
     magic_cookie = ntohl(header->magic_cookie);
 
-    nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->unmasked, &xor_mapped_address->masked);
+    nr_stun_xor_mapped_address(magic_cookie, header->id, &xor_mapped_address->unmasked, &xor_mapped_address->masked);
 
     r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
 
     if (nr_stun_attr_codec_addr.encode(attr_info, &xor_mapped_address->masked, offset, buflen, buf, attrlen))
         return R_FAILED;
 
     return 0;
 }
@@ -1118,17 +1125,17 @@ nr_stun_attr_codec_xor_mapped_address_de
     r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
 
     /* this needs to be the magic cookie in the header and not
      * the MAGIC_COOKIE constant because if we're talking to
      * older servers (that don't have a magic cookie) they use
      * message ID for this */
     magic_cookie = ntohl(header->magic_cookie);
 
-    nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->masked, &xor_mapped_address->unmasked);
+    nr_stun_xor_mapped_address(magic_cookie, header->id, &xor_mapped_address->masked, &xor_mapped_address->unmasked);
 
     r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
 
     _status = 0;
   abort:
     return _status;
 }
 
--- a/media/mtransport/third_party/nICEr/src/stun/stun_reg.h
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_reg.h
@@ -40,16 +40,17 @@ extern "C" {
 #endif /* __cplusplus */
 
 #define NR_STUN_REG_PREF_CLNT_RETRANSMIT_TIMEOUT    "stun.client.retransmission_timeout"
 #define NR_STUN_REG_PREF_CLNT_RETRANSMIT_BACKOFF    "stun.client.retransmission_backoff_factor"
 #define NR_STUN_REG_PREF_CLNT_MAXIMUM_TRANSMITS     "stun.client.maximum_transmits"
 #define NR_STUN_REG_PREF_CLNT_FINAL_RETRANSMIT_BACKOFF   "stun.client.final_retransmit_backoff"
 
 #define NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS            "stun.allow_loopback"
+#define NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS     "stun.allow_link_local"
 #define NR_STUN_REG_PREF_ADDRESS_PRFX               "stun.address"
 #define NR_STUN_REG_PREF_SERVER_NAME                "stun.server.name"
 #define NR_STUN_REG_PREF_SERVER_NONCE_SIZE          "stun.server.nonce_size"
 #define NR_STUN_REG_PREF_SERVER_REALM               "stun.server.realm"
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
--- a/media/mtransport/third_party/nICEr/src/stun/stun_util.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_util.c
@@ -66,30 +66,48 @@ nr_stun_startup(void)
       ABORT(r);
 
    _status=0;
  abort:
    return _status;
 }
 
 int
-nr_stun_xor_mapped_address(UINT4 magicCookie, nr_transport_addr *from, nr_transport_addr *to)
+nr_stun_xor_mapped_address(UINT4 magicCookie, UINT12 transactionId, nr_transport_addr *from, nr_transport_addr *to)
 {
     int _status;
 
     switch (from->ip_version) {
     case NR_IPV4:
         nr_ip4_port_to_transport_addr(
             (ntohl(from->u.addr4.sin_addr.s_addr) ^ magicCookie),
             (ntohs(from->u.addr4.sin_port) ^ (magicCookie>>16)),
             from->protocol, to);
         break;
     case NR_IPV6:
-        assert(0);
-        ABORT(R_INTERNAL);
+        {
+          union {
+            unsigned char addr[16];
+            UINT4 addr32[4];
+          } maskedAddr;
+
+          maskedAddr.addr32[0] = htonl(magicCookie); /* Passed in host byte order */
+          memcpy(&maskedAddr.addr32[1], transactionId.octet, sizeof(transactionId));
+
+          /* We now have the mask in network byte order */
+          /* Xor the address in network byte order */
+          for (int i = 0; i < sizeof(maskedAddr); ++i) {
+            maskedAddr.addr[i] ^= from->u.addr6.sin6_addr.s6_addr[i];
+          }
+
+          nr_ip6_port_to_transport_addr(
+              (struct in6_addr*)&maskedAddr,
+              (ntohs(from->u.addr6.sin6_port) ^ (magicCookie>>16)),
+              from->protocol, to);
+        }
         break;
     default:
         assert(0);
         ABORT(R_INTERNAL);
         break;
     }
 
     _status = 0;
@@ -106,25 +124,33 @@ nr_stun_find_local_addresses(nr_local_ad
     if ((r=NR_reg_get_child_count(NR_STUN_REG_PREF_ADDRESS_PRFX, (unsigned int*)count)))
         if (r == R_NOT_FOUND)
             *count = 0;
         else
             ABORT(r);
 
     if (*count == 0) {
         char allow_loopback;
+        char allow_link_local;
 
         if ((r=NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, &allow_loopback))) {
             if (r == R_NOT_FOUND)
                 allow_loopback = 0;
             else
                 ABORT(r);
         }
 
-        if ((r=nr_stun_get_addrs(addrs, maxaddrs, !allow_loopback, count)))
+        if ((r=NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS, &allow_link_local))) {
+            if (r == R_NOT_FOUND)
+                allow_link_local = 0;
+            else
+                ABORT(r);
+        }
+
+        if ((r=nr_stun_get_addrs(addrs, maxaddrs, !allow_loopback, !allow_link_local, count)))
             ABORT(r);
 
         goto done;
     }
 
     if (*count >= maxaddrs) {
         r_log(NR_LOG_STUN, LOG_INFO, "Address list truncated from %d to %d", *count, maxaddrs);
        *count = maxaddrs;
--- a/media/mtransport/third_party/nICEr/src/stun/stun_util.h
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_util.h
@@ -37,17 +37,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
 #include "stun.h"
 #include "local_addr.h"
 
 extern int NR_LOG_STUN;
 
 int nr_stun_startup(void);
 
-int nr_stun_xor_mapped_address(UINT4 magicCookie, nr_transport_addr *from, nr_transport_addr *to);
+int nr_stun_xor_mapped_address(UINT4 magicCookie, UINT12 transactionId, nr_transport_addr *from, nr_transport_addr *to);
 
 int nr_stun_find_local_addresses(nr_local_addr addrs[], int maxaddrs, int *count);
 
 int nr_stun_different_transaction(UCHAR *msg, int len, nr_stun_message *req);
 
 char* nr_stun_msg_type(int type);
 
 int nr_random_alphanum(char *alphanum, int size);
--- a/media/mtransport/third_party/nrappkit/src/util/util.c
+++ b/media/mtransport/third_party/nrappkit/src/util/util.c
@@ -719,16 +719,41 @@ inet_ntop6(const unsigned char *src, cha
     errno = ENOSPC;
     return (NULL);
   }
   strlcpy(dst, tmp, size);
   return (dst);
 }
 #endif /* INET6 */
 
+#ifdef WIN32
+/* Not exactly, will forgive stuff like <addr>:<port> */
+int inet_pton(int af, const char *src, void *dst)
+{
+  struct sockaddr_storage ss;
+  int addrlen = sizeof(ss);
+
+  if (af != AF_INET && af != AF_INET6) {
+    return -1;
+  }
+
+  if (!WSAStringToAddressA(src, af, NULL, (struct sockaddr*)&ss, &addrlen)) {
+    if (af == AF_INET) {
+      struct sockaddr_in *in = (struct sockaddr_in*)&ss;
+      memcpy(dst, &in->sin_addr, sizeof(struct in_addr));
+    } else {
+      struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&ss;
+      memcpy(dst, &in6->sin6_addr, sizeof(struct in6_addr));
+    }
+    return 1;
+  }
+  return 0;
+}
+#endif /* WIN32 */
+
 #endif
 
 #ifdef WIN32
 #include <time.h>
 /* this is only millisecond-accurate, but that should be OK */
 
 int gettimeofday(struct timeval *tv, void *tz)
   {
--- a/media/mtransport/third_party/nrappkit/src/util/util.h
+++ b/media/mtransport/third_party/nrappkit/src/util/util.h
@@ -62,12 +62,13 @@ int nr_rm_tree(char *path);
 int nr_write_pid_file(char *pid_filename);
 
 int nr_reg_uint4_fetch_and_check(NR_registry key, UINT4 min, UINT4 max, int log_fac, int die, UINT4 *val);
 int nr_reg_uint8_fetch_and_check(NR_registry key, UINT8 min, UINT8 max, int log_fac, int die, UINT8 *val);
 
 #ifdef WIN32
 int snprintf(char *buffer, size_t n, const char *format, ...);
 const char *inet_ntop(int af, const void *src, char *dst, size_t size);
+int inet_pton(int af, const char *src, void *dst);
 #endif
 
 #endif
 
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -371,16 +371,17 @@ PeerConnectionImpl::PeerConnectionImpl(c
   , mIceConnectionState(PCImplIceConnectionState::New)
   , mIceGatheringState(PCImplIceGatheringState::New)
   , mDtlsConnected(false)
   , mWindow(nullptr)
   , mIdentity(nullptr)
   , mPrivacyRequested(false)
   , mSTSThread(nullptr)
   , mAllowIceLoopback(false)
+  , mAllowIceLinkLocal(false)
   , mMedia(nullptr)
   , mUuidGen(MakeUnique<PCUuidGenerator>())
   , mNumAudioStreams(0)
   , mNumVideoStreams(0)
   , mHaveDataStream(false)
   , mAddCandidateErrorCount(0)
   , mTrickle(true) // TODO(ekr@rtfm.com): Use pref
   , mShouldSuppressNegotiationNeeded(false)
@@ -392,16 +393,18 @@ PeerConnectionImpl::PeerConnectionImpl(c
   }
 #endif
   CSFLogInfo(logTag, "%s: PeerConnectionImpl constructor for %s",
              __FUNCTION__, mHandle.c_str());
   STAMP_TIMECARD(mTimeCard, "Constructor Completed");
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
   mAllowIceLoopback = Preferences::GetBool(
     "media.peerconnection.ice.loopback", false);
+  mAllowIceLinkLocal = Preferences::GetBool(
+    "media.peerconnection.ice.link_local", false);
 #endif
 }
 
 PeerConnectionImpl::~PeerConnectionImpl()
 {
   if (mTimeCard) {
     STAMP_TIMECARD(mTimeCard, "Destructor Invoked");
     print_timecard(mTimeCard);
@@ -727,17 +730,16 @@ PeerConnectionImpl::Initialize(PeerConne
     if (NS_FAILED(res)) {
       CSFLogError(logTag, "%s: Invalid RTCConfiguration", __FUNCTION__);
       return res;
     }
     aConfiguration = &converted;
   }
 
   mMedia = new PeerConnectionMedia(this);
-  mMedia->SetAllowIceLoopback(mAllowIceLoopback);
 
   // Connect ICE slots.
   mMedia->SignalIceGatheringStateChange.connect(
       this,
       &PeerConnectionImpl::IceGatheringStateChange);
   mMedia->SignalEndOfLocalCandidates.connect(
       this,
       &PeerConnectionImpl::EndOfLocalCandidates);
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -282,16 +282,21 @@ public:
   // Get the media object
   const nsRefPtr<PeerConnectionMedia>& media() const {
     PC_AUTO_ENTER_API_CALL_NO_CHECK();
     return mMedia;
   }
 
   // Configure the ability to use localhost.
   void SetAllowIceLoopback(bool val) { mAllowIceLoopback = val; }
+  bool GetAllowIceLoopback() const { return mAllowIceLoopback; }
+
+  // Configure the ability to use IPV6 link-local addresses.
+  void SetAllowIceLinkLocal(bool val) { mAllowIceLinkLocal = val; }
+  bool GetAllowIceLinkLocal() const { return mAllowIceLinkLocal; }
 
   // Handle system to allow weak references to be passed through C code
   virtual const std::string& GetHandle();
 
   // Name suitable for exposing to content
   virtual const std::string& GetName();
 
   // ICE events
@@ -734,16 +739,17 @@ private:
   nsCOMPtr<nsIEventTarget> mSTSThread;
 
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
   // DataConnection that's used to get all the DataChannels
   nsRefPtr<mozilla::DataChannelConnection> mDataConnection;
 #endif
 
   bool mAllowIceLoopback;
+  bool mAllowIceLinkLocal;
   nsRefPtr<PeerConnectionMedia> mMedia;
 
   // The JSEP negotiation session.
   mozilla::UniquePtr<PCUuidGenerator> mUuidGen;
   mozilla::UniquePtr<mozilla::JsepSession> mJsepSession;
 
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
   // Start time of ICE, used for telemetry
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -214,17 +214,16 @@ PeerConnectionMedia::ProtocolProxyQueryH
 
 NS_IMPL_ISUPPORTS(PeerConnectionMedia::ProtocolProxyQueryHandler, nsIProtocolProxyCallback)
 #endif // !defined(MOZILLA_XPCOMRT_API)
 
 PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
     : mParent(parent),
       mParentHandle(parent->GetHandle()),
       mParentName(parent->GetName()),
-      mAllowIceLoopback(false),
       mIceCtx(nullptr),
       mDNSResolver(new NrIceResolver()),
       mUuidGen(MakeUnique<PCUuidGenerator>()),
       mMainThread(mParent->GetMainThread()),
       mSTSThread(mParent->GetSTSThread()),
       mProxyResolveCompleted(false) {
 }
 
@@ -306,18 +305,19 @@ nsresult PeerConnectionMedia::Init(const
   bool ice_tcp = false;
 #endif
 
   // TODO(ekr@rtfm.com): need some way to set not offerer later
   // Looks like a bug in the NrIceCtx API.
   mIceCtx = NrIceCtx::Create("PC:" + mParentName,
                              true, // Offerer
                              true, // Explicitly set priorities
-                             mAllowIceLoopback,
-                             ice_tcp);
+                             mParent->GetAllowIceLoopback(),
+                             ice_tcp,
+                             mParent->GetAllowIceLinkLocal());
   if(!mIceCtx) {
     CSFLogError(logTag, "%s: Failed to create Ice Context", __FUNCTION__);
     return NS_ERROR_FAILURE;
   }
 
   if (NS_FAILED(rv = mIceCtx->SetStunServers(stun_servers))) {
     CSFLogError(logTag, "%s: Failed to set stun servers", __FUNCTION__);
     return rv;
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -227,19 +227,16 @@ class PeerConnectionMedia : public sigsl
   explicit PeerConnectionMedia(PeerConnectionImpl *parent);
 
   PeerConnectionImpl* GetPC() { return mParent; }
   nsresult Init(const std::vector<NrIceStunServer>& stun_servers,
                 const std::vector<NrIceTurnServer>& turn_servers);
   // WARNING: This destroys the object!
   void SelfDestruct();
 
-  // Configure the ability to use localhost.
-  void SetAllowIceLoopback(bool val) { mAllowIceLoopback = val; }
-
   RefPtr<NrIceCtx> ice_ctx() const { return mIceCtx; }
 
   RefPtr<NrIceMediaStream> ice_media_stream(size_t i) const {
     return mIceCtx->GetStream(i);
   }
 
   size_t num_ice_media_streams() const {
     return mIceCtx->GetStreamCount();
@@ -486,19 +483,16 @@ class PeerConnectionMedia : public sigsl
   nsTArray<nsRefPtr<LocalSourceStreamInfo> > mLocalSourceStreams;
 
   // A list of streams provided by the other side
   // This is only accessed on the main thread (with one special exception)
   nsTArray<nsRefPtr<RemoteSourceStreamInfo> > mRemoteSourceStreams;
 
   std::map<size_t, std::pair<bool, RefPtr<MediaSessionConduit>>> mConduits;
 
-  // Allow loopback for ICE.
-  bool mAllowIceLoopback;
-
   // ICE objects
   RefPtr<NrIceCtx> mIceCtx;
 
   // DNS
   nsRefPtr<NrIceResolver> mDNSResolver;
 
   // Transport flows: even is RTP, odd is RTCP
   std::map<int, RefPtr<TransportFlow> > mTransportFlows;
--- a/media/webrtc/signaling/src/sdp/SdpMediaSection.h
+++ b/media/webrtc/signaling/src/sdp/SdpMediaSection.h
@@ -281,16 +281,21 @@ public:
   GetAddress() const
   {
     return mAddr;
   }
   void
   SetAddress(const std::string& address)
   {
     mAddr = address;
+    if (mAddr.find(':') != std::string::npos) {
+      mAddrType = sdp::kIPv6;
+    } else {
+      mAddrType = sdp::kIPv4;
+    }
   }
   uint8_t
   GetTtl() const
   {
     return mTtl;
   }
   uint32_t
   GetCount() const
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -908,16 +908,17 @@ class SignalingAgent {
     mRemoteDescriptionSet(false) {
     cfg_.addStunServer(stun_addr, stun_port, kNrIceTransportUdp);
     cfg_.addStunServer(stun_addr, stun_port, kNrIceTransportTcp);
 
     PeerConnectionImpl *pcImpl =
       PeerConnectionImpl::CreatePeerConnection();
     EXPECT_TRUE(pcImpl);
     pcImpl->SetAllowIceLoopback(true);
+    pcImpl->SetAllowIceLinkLocal(true);
     pc = new PCDispatchWrapper(pcImpl);
   }
 
 
   ~SignalingAgent() {
     mozilla::SyncRunnable::DispatchToThread(gMainThread,
       WrapRunnable(this, &SignalingAgent::Close));
   }
@@ -4704,17 +4705,17 @@ int main(int argc, char **argv) {
   NSS_NoDB_Init(nullptr);
   NSS_SetDomesticPolicy();
 
   ::testing::TestEventListeners& listeners =
         ::testing::UnitTest::GetInstance()->listeners();
   // Adds a listener to the end.  Google Test takes the ownership.
   listeners.Append(new test::RingbufferDumper(test_utils));
   test_utils->sts_target()->Dispatch(
-    WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC);
+    WrapRunnableNM(&TestStunServer::GetInstance, AF_INET), NS_DISPATCH_SYNC);
 
   // Set the main thread global which is this thread.
   nsIThread *thread;
   NS_GetMainThread(&thread);
   gMainThread = thread;
   MOZ_ASSERT(NS_IsMainThread());
 
   // Now create the GTest thread and run all of the tests on it
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -564,17 +564,16 @@ if CONFIG['MOZ_CRASHREPORTER']:
 
 if CONFIG['MOZ_ANDROID_SHARE_OVERLAY']:
     gbjar.sources += [
         'overlays/OverlayConstants.java',
         'overlays/service/OverlayActionService.java',
         'overlays/service/ShareData.java',
         'overlays/service/sharemethods/AddBookmark.java',
         'overlays/service/sharemethods/AddToReadingList.java',
-        'overlays/service/sharemethods/ParcelableClientRecord.java',
         'overlays/service/sharemethods/SendTab.java',
         'overlays/service/sharemethods/ShareMethod.java',
         'overlays/ui/OverlayDialogButton.java',
         'overlays/ui/OverlayToastHelper.java',
         'overlays/ui/SendTabDeviceListArrayAdapter.java',
         'overlays/ui/SendTabList.java',
         'overlays/ui/SendTabTargetSelectedListener.java',
         'overlays/ui/ShareDialog.java',
--- a/mobile/android/base/mozglue/GeckoLoader.java
+++ b/mobile/android/base/mozglue/GeckoLoader.java
@@ -276,18 +276,31 @@ public final class GeckoLoader {
         File outDirFile = new File(outDir);
         if (!outDirFile.isDirectory()) {
             if (!outDirFile.mkdirs()) {
                 Log.e(LOGTAG, "Couldn't create " + outDir);
                 return false;
             }
         }
 
-        final String abi = getCPUABI();
+        if (AppConstants.Versions.feature21Plus) {
+            String[] abis = Build.SUPPORTED_ABIS;
+            for (String abi : abis) {
+                if (tryLoadWithABI(lib, outDir, apkPath, abi)) {
+                    return true;
+                }
+            }
+            return false;
+        } else {
+            final String abi = getCPUABI();
+            return tryLoadWithABI(lib, outDir, apkPath, abi);
+        }
+    }
 
+    private static boolean tryLoadWithABI(String lib, String outDir, String apkPath, String abi) {
         try {
             final ZipFile zipFile = new ZipFile(new File(apkPath));
             try {
                 final String libPath = "lib/" + abi + "/lib" + lib + ".so";
                 final ZipEntry entry = zipFile.getEntry(libPath);
                 if (entry == null) {
                     Log.w(LOGTAG, libPath + " not found in APK " + apkPath);
                     return false;
deleted file mode 100644
--- a/mobile/android/base/overlays/service/sharemethods/ParcelableClientRecord.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.overlays.service.sharemethods;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
-
-/**
- * An immutable representation of a Sync ClientRecord for Parceling, storing only name, guid, type.
- * Implemented this way instead of by making ClientRecord itself parcelable to avoid an undesirable
- * dependency between Sync and the IPC system used by the share system (things which really should
- * be kept as independent as possible).
- */
-public class ParcelableClientRecord implements Parcelable {
-    private static final String LOGTAG = "GeckoParcelableClientRecord";
-
-    public final String name;
-    public final String type;
-    public final String guid;
-
-    private ParcelableClientRecord(String aName, String aType, String aGUID) {
-        name = aName;
-        type = aType;
-        guid = aGUID;
-    }
-
-    /**
-     * Create a ParcelableClientRecord from a vanilla ClientRecord.
-     */
-    public static ParcelableClientRecord fromClientRecord(ClientRecord record) {
-        return new ParcelableClientRecord(record.name, record.type, record.guid);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeString(name);
-        parcel.writeString(type);
-        parcel.writeString(guid);
-    }
-
-    public static final Creator<ParcelableClientRecord> CREATOR = new Creator<ParcelableClientRecord>() {
-        @Override
-        public ParcelableClientRecord createFromParcel(final Parcel source) {
-            String name = source.readString();
-            String type = source.readString();
-            String guid = source.readString();
-
-            return new ParcelableClientRecord(name, type, guid);
-        }
-
-        @Override
-        public ParcelableClientRecord[] newArray(final int size) {
-            return new ParcelableClientRecord[size];
-        }
-    };
-
-    /**
-     * Used by SendTabDeviceListArrayAdapter to populate ListViews.
-     */
-    @Override
-    public String toString() {
-        return name;
-    }
-}
--- a/mobile/android/base/overlays/ui/SendTabDeviceListArrayAdapter.java
+++ b/mobile/android/base/overlays/ui/SendTabDeviceListArrayAdapter.java
@@ -5,17 +5,16 @@
 package org.mozilla.gecko.overlays.ui;
 
 import java.util.Collection;
 
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.Assert;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.db.RemoteClient;
-import org.mozilla.gecko.overlays.service.sharemethods.ParcelableClientRecord;
 import org.mozilla.gecko.overlays.ui.SendTabList.State;
 
 import android.app.AlertDialog;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
--- a/mobile/android/base/overlays/ui/ShareDialog.java
+++ b/mobile/android/base/overlays/ui/ShareDialog.java
@@ -13,17 +13,16 @@ import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.Locales;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.db.LocalBrowserDB;
 import org.mozilla.gecko.db.RemoteClient;
 import org.mozilla.gecko.overlays.OverlayConstants;
 import org.mozilla.gecko.overlays.service.OverlayActionService;
-import org.mozilla.gecko.overlays.service.sharemethods.ParcelableClientRecord;
 import org.mozilla.gecko.overlays.service.sharemethods.SendTab;
 import org.mozilla.gecko.overlays.service.sharemethods.ShareMethod;
 import org.mozilla.gecko.sync.setup.activities.WebURLFinder;
 import org.mozilla.gecko.mozglue.ContextUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.util.UIAsyncTask;
 
 import android.content.BroadcastReceiver;
--- a/mobile/android/base/sync/CommandProcessor.java
+++ b/mobile/android/base/sync/CommandProcessor.java
@@ -13,16 +13,17 @@ import java.util.concurrent.atomic.Atomi
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
 import org.mozilla.gecko.BrowserLocaleManager;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
 import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
+import org.mozilla.gecko.tabqueue.TabQueueDispatcher;
 
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
 
@@ -273,15 +274,16 @@ public class CommandProcessor {
     }
 
     final long when = System.currentTimeMillis();
     Notification notification = new Notification(icon, notificationTitle, when);
     notification.flags = Notification.FLAG_AUTO_CANCEL;
 
     // Set pending intent associated with the notification.
     Intent notificationIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
+    notificationIntent.putExtra(TabQueueDispatcher.SKIP_TAB_QUEUE_FLAG, true);
     PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
     notification.setLatestEventInfo(context, notificationTitle, uri, contentIntent);
 
     // Send notification.
     notificationManager.notify(currentId.getAndIncrement(), notification);
   }
 }
--- a/mobile/android/base/tabqueue/TabQueueDispatcher.java
+++ b/mobile/android/base/tabqueue/TabQueueDispatcher.java
@@ -22,16 +22,17 @@ import android.util.Log;
 /**
  * This class takes over external url loads (Intent.VIEW) from the BrowserApp class.  It determines if
  * the tab queue functionality is enabled and forwards the intent to the TabQueueService to process if it is.
  *
  * If the tab queue functionality is not enabled then it forwards the intent to BrowserApp to handle as normal.
  */
 public class TabQueueDispatcher extends Locales.LocaleAwareActivity {
     private static final String LOGTAG = "Gecko" + TabQueueDispatcher.class.getSimpleName();
+    public static final String SKIP_TAB_QUEUE_FLAG = "skip_tab_queue";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         GeckoAppShell.ensureCrashHandling();
 
         // The EXCLUDE_FROM_RECENTS flag is sticky
@@ -45,16 +46,23 @@ public class TabQueueDispatcher extends 
 
         // For the moment lets exit early and start fennec as normal if we're not in nightly with
         // the tab queue build flag.
         if (!AppConstants.MOZ_ANDROID_TAB_QUEUE || !AppConstants.NIGHTLY_BUILD) {
             loadNormally(safeIntent.getUnsafe());
             return;
         }
 
+        // Skip the Tab Queue if instructed.
+        boolean shouldSkipTabQueue = safeIntent.getBooleanExtra(SKIP_TAB_QUEUE_FLAG, false);
+        if (shouldSkipTabQueue) {
+            loadNormally(safeIntent.getUnsafe());
+            return;
+        }
+
         // The URL is usually hiding somewhere in the extra text. Extract it.
         final String dataString = safeIntent.getDataString();
         if (TextUtils.isEmpty(dataString)) {
             abortDueToNoURL(dataString);
             return;
         }
 
         boolean shouldShowOpenInBackgroundToast = TabQueueHelper.isTabQueueEnabled(this);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -370,16 +370,17 @@ pref("media.getusermedia.browser.enabled
 pref("media.peerconnection.video.min_bitrate", 200);
 pref("media.peerconnection.video.start_bitrate", 300);
 pref("media.peerconnection.video.max_bitrate", 2000);
 #endif
 pref("media.navigator.permission.disabled", false);
 pref("media.peerconnection.default_iceservers", "[]");
 pref("media.peerconnection.ice.loopback", false); // Set only for testing in offline environments.
 pref("media.peerconnection.ice.tcp", false);
+pref("media.peerconnection.ice.link_local", false); // Set only for testing IPV6 in networks that don't assign IPV6 addresses
 pref("media.peerconnection.use_document_iceservers", true);
 pref("media.peerconnection.identity.enabled", true);
 pref("media.peerconnection.identity.timeout", 10000);
 pref("media.peerconnection.ice.stun_client_maximum_transmits", 7);
 pref("media.peerconnection.ice.trickle_grace_period", 5000);
 // These values (aec, agc, and noice) are from media/webrtc/trunk/webrtc/common_types.h
 // kXxxUnchanged = 0, kXxxDefault = 1, and higher values are specific to each
 // setting (for Xxx = Ec, Agc, or Ns).  Defaults are all set to kXxxDefault here.
--- a/netwerk/base/nsSocketTransport2.cpp
+++ b/netwerk/base/nsSocketTransport2.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=4 sw=4 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 "nsSocketTransport2.h"
 
 #include "mozilla/Attributes.h"
+#include "mozilla/Telemetry.h"
 #include "nsIOService.h"
 #include "nsStreamUtils.h"
 #include "nsNetSegmentUtils.h"
 #include "nsNetAddr.h"
 #include "nsTransportUtils.h"
 #include "nsProxyInfo.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
@@ -46,16 +47,21 @@
 #include <winsock2.h>
 #include <mstcpip.h>
 #elif defined(XP_UNIX)
 #include <errno.h>
 #include <netinet/tcp.h>
 #endif
 /* End keepalive config inclusions. */
 
+#define SUCCESSFUL_CONNECTING_TO_IPV4_ADDRESS 0
+#define UNSUCCESSFUL_CONNECTING_TO_IPV4_ADDRESS 1
+#define SUCCESSFUL_CONNECTING_TO_IPV6_ADDRESS 2
+#define UNSUCCESSFUL_CONNECTING_TO_IPV6_ADDRESS 3
+
 using namespace mozilla;
 using namespace mozilla::net;
 
 //-----------------------------------------------------------------------------
 
 static NS_DEFINE_CID(kSocketProviderServiceCID, NS_SOCKETPROVIDERSERVICE_CID);
 static NS_DEFINE_CID(kDNSServiceCID, NS_DNSSERVICE_CID);
 
@@ -1496,16 +1502,26 @@ nsSocketTransport::RecoverFromError()
         mCondition != NS_ERROR_PROXY_CONNECTION_REFUSED &&
         mCondition != NS_ERROR_NET_TIMEOUT &&
         mCondition != NS_ERROR_UNKNOWN_HOST &&
         mCondition != NS_ERROR_UNKNOWN_PROXY_HOST)
         return false;
 
     bool tryAgain = false;
 
+    if (mSocketTransportService->IsTelemetryEnabled()) {
+        if (mNetAddr.raw.family == AF_INET) {
+            Telemetry::Accumulate(Telemetry::IPV4_AND_IPV6_ADDRESS_CONNECTIVITY,
+                                  UNSUCCESSFUL_CONNECTING_TO_IPV4_ADDRESS);
+        } else if (mNetAddr.raw.family == AF_INET6) {
+            Telemetry::Accumulate(Telemetry::IPV4_AND_IPV6_ADDRESS_CONNECTIVITY,
+                                  UNSUCCESSFUL_CONNECTING_TO_IPV6_ADDRESS);
+        }
+    }
+
     if (mConnectionFlags & (DISABLE_IPV6 | DISABLE_IPV4) &&
         mCondition == NS_ERROR_UNKNOWN_HOST &&
         mState == STATE_RESOLVING &&
         !mProxyTransparentResolvesHost) {
         SOCKET_LOG(("  trying lookup again with both ipv4/ipv6 enabled\n"));
         mConnectionFlags &= ~(DISABLE_IPV6 | DISABLE_IPV4);
         tryAgain = true;
     }
@@ -1850,16 +1866,28 @@ nsSocketTransport::OnSocketReady(PRFileD
     }
     else if (mState == STATE_CONNECTING) {
         PRStatus status = PR_ConnectContinue(fd, outFlags);
         if (status == PR_SUCCESS) {
             //
             // we are connected!
             //
             OnSocketConnected();
+
+            if (mSocketTransportService->IsTelemetryEnabled()) {
+                if (mNetAddr.raw.family == AF_INET) {
+                    Telemetry::Accumulate(
+                        Telemetry::IPV4_AND_IPV6_ADDRESS_CONNECTIVITY,
+                        SUCCESSFUL_CONNECTING_TO_IPV4_ADDRESS);
+                } else if (mNetAddr.raw.family == AF_INET6) {
+                    Telemetry::Accumulate(
+                        Telemetry::IPV4_AND_IPV6_ADDRESS_CONNECTIVITY,
+                        SUCCESSFUL_CONNECTING_TO_IPV6_ADDRESS);
+                }
+            }
         }
         else {
             PRErrorCode code = PR_GetError();
 #if defined(TEST_CONNECT_ERRORS)
             code = RandomizeConnectError(code);
 #endif
             //
             // If the connect is still not ready, then continue polling...
--- a/netwerk/base/nsSocketTransportService2.h
+++ b/netwerk/base/nsSocketTransportService2.h
@@ -104,16 +104,18 @@ public:
     // Called by the networking dashboard on the socket thread only
     // Fills the passed array with socket information
     void GetSocketConnections(nsTArray<mozilla::net::SocketInfo> *);
     uint64_t GetSentBytes() { return mSentBytesCount; }
     uint64_t GetReceivedBytes() { return mReceivedBytesCount; }
 
     // Returns true if keepalives are enabled in prefs.
     bool IsKeepaliveEnabled() { return mKeepaliveEnabledPref; }
+
+    bool IsTelemetryEnabled() { return mTelemetryEnabledPref; }
 protected:
 
     virtual ~nsSocketTransportService();
 
 private:
 
     //-------------------------------------------------------------------------
     // misc (any thread)
--- a/security/manager/ssl/tests/unit/test_ocsp_caching.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_caching.js
@@ -1,14 +1,17 @@
 // -*- indent-tabs-mode: nil; js-indent-level: 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/.
 "use strict";
 
+// Checks various aspects of the OCSP cache, mainly to to ensure we do not fetch
+// responses more than necessary.
+
 let gFetchCount = 0;
 let gGoodOCSPResponse = null;
 
 function generateGoodOCSPResponse() {
   let args = [ ["good", "localhostAndExampleCom", "unused" ] ];
   let responses = generateOCSPResponses(args, "tlsserver");
   return responses[0];
 }
@@ -79,29 +82,37 @@ function add_tests() {
   //---------------------------------------------------------------------------
 
   // Reset state
   add_test(function() { clearOCSPCache(); gFetchCount = 0; run_next_test(); });
 
   // This test assumes that OCSPStaplingServer uses the same cert for
   // ocsp-stapling-unknown.example.com and ocsp-stapling-none.example.com.
 
-  // Get an Unknown response for the *.exmaple.com cert and put it in the
+  // Get an Unknown response for the *.example.com cert and put it in the
   // OCSP cache.
   add_connection_test("ocsp-stapling-unknown.example.com",
                       SEC_ERROR_OCSP_UNKNOWN_CERT,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 0); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 0,
+          "Stapled Unknown response -> a fetch should not have been attempted");
+    run_next_test();
+  });
 
-  // A failure to retrieve an OCSP response must result in the cached Unkown
+  // A failure to retrieve an OCSP response must result in the cached Unknown
   // response being recognized and honored.
   add_connection_test("ocsp-stapling-none.example.com",
                       SEC_ERROR_OCSP_UNKNOWN_CERT,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 1); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 1,
+          "No stapled response -> a fetch should have been attempted");
+    run_next_test();
+  });
 
   // A valid Good response from the OCSP responder must override the cached
   // Unknown response.
   //
   // Note that We need to make sure that the Unknown response and the Good
   // response have different thisUpdate timestamps; otherwise, the Good
   // response will be seen as "not newer" and it won't replace the existing
   // entry.
@@ -112,46 +123,67 @@ function add_tests() {
     timer.initWithCallback(run_next_test, duration, Ci.nsITimer.TYPE_ONE_SHOT);
   });
   add_test(function() {
     gGoodOCSPResponse = generateGoodOCSPResponse();
     run_next_test();
   });
   add_connection_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 2); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 2,
+          "Cached Unknown response, no stapled response -> a fetch should" +
+          " have been attempted");
+    run_next_test();
+  });
 
   // The Good response retrieved from the previous fetch must have replaced
   // the Unknown response in the cache, resulting in the catched Good response
   // being returned and no fetch.
   add_connection_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 2); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 2,
+          "Cached Good response -> a fetch should not have been attempted");
+    run_next_test();
+  });
 
 
   //---------------------------------------------------------------------------
 
   // Reset state
   add_test(function() { clearOCSPCache(); gFetchCount = 0; run_next_test(); });
 
   // A failure to retrieve an OCSP response will result in an error entry being
   // added to the cache.
   add_connection_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 1); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 1,
+          "No stapled response -> a fetch should have been attempted");
+    run_next_test();
+  });
 
   // The error entry will prevent a fetch from happening for a while.
   add_connection_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 1); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 1,
+          "Noted OCSP server failure -> a fetch should not have been attempted");
+    run_next_test();
+  });
 
   // The error entry must not prevent a stapled OCSP response from being
   // honored.
   add_connection_test("ocsp-stapling-revoked.example.com",
                       SEC_ERROR_REVOKED_CERTIFICATE,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 1); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 1,
+          "Stapled Revoked response -> a fetch should not have been attempted");
+    run_next_test();
+  });
 
   //---------------------------------------------------------------------------
 
   // Reset state
   add_test(function() { clearOCSPCache(); gFetchCount = 0; run_next_test(); });
 }
--- a/security/manager/ssl/tests/unit/test_ocsp_no_hsts_upgrade.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_no_hsts_upgrade.js
@@ -40,13 +40,15 @@ function run_test() {
   add_test(function () { ocspResponder.stop(run_next_test); });
 
   let SSService = Cc["@mozilla.org/ssservice;1"]
                     .getService(Ci.nsISiteSecurityService);
   let uri = Services.io.newURI("http://localhost", null, null);
   let sslStatus = new FakeSSLStatus();
   SSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
                           "max-age=10000", sslStatus, 0);
-  do_check_true(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
-                                       "localhost", 0));
+  ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+                            "localhost", 0),
+     "Domain for the OCSP AIA URI should be considered a HSTS host, otherwise" +
+     " we wouldn't be testing what we think we're testing");
 
   run_next_test();
 }
--- a/security/manager/ssl/tests/unit/test_ocsp_required.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_required.js
@@ -42,13 +42,14 @@ function run_test() {
 
 function add_tests()
 {
   add_connection_test("ocsp-stapling-none.example.com",
                       SEC_ERROR_OCSP_BAD_SIGNATURE);
   add_connection_test("ocsp-stapling-none.example.com",
                       SEC_ERROR_OCSP_BAD_SIGNATURE);
   add_test(function () {
-    do_check_eq(gOCSPRequestCount, 1);
+    equal(gOCSPRequestCount, 1,
+          "OCSP request count should be 1 due to OCSP response caching");
     gOCSPRequestCount = 0;
     run_next_test();
   });
 }
--- a/security/manager/ssl/tests/unit/test_ocsp_stapling.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_stapling.js
@@ -165,37 +165,43 @@ function add_tests(certDB, otherTestCA) 
                 SEC_ERROR_REVOKED_CERTIFICATE, true);
 }
 
 function check_ocsp_stapling_telemetry() {
   let histogram = Cc["@mozilla.org/base/telemetry;1"]
                     .getService(Ci.nsITelemetry)
                     .getHistogramById("SSL_OCSP_STAPLING")
                     .snapshot();
-  do_check_eq(histogram.counts[0], 0); // histogram bucket 0 is unused
-  do_check_eq(histogram.counts[1], 5); // 5 connections with a good response
-  do_check_eq(histogram.counts[2], 18); // 18 connections with no stapled resp.
-  do_check_eq(histogram.counts[3], 0); // 0 connections with an expired response
-  do_check_eq(histogram.counts[4], 21); // 21 connections with bad responses
+  equal(histogram.counts[0], 0,
+        "Should have 0 connections for unused histogram bucket 0");
+  equal(histogram.counts[1], 5,
+        "Actual and expected connections with a good response should match");
+  equal(histogram.counts[2], 18,
+        "Actual and expected connections with no stapled response should match");
+  equal(histogram.counts[3], 0,
+        "Actual and expected connections with an expired response should match");
+  equal(histogram.counts[4], 21,
+        "Actual and expected connections with bad responses should match");
   run_next_test();
 }
 
 function run_test() {
   do_get_profile();
 
   let certDB = Cc["@mozilla.org/security/x509certdb;1"]
                   .getService(Ci.nsIX509CertDB);
   let otherTestCAFile = do_get_file("tlsserver/other-test-ca.der", false);
   let otherTestCADER = readFile(otherTestCAFile);
   let otherTestCA = certDB.constructX509(otherTestCADER, otherTestCADER.length);
 
   let fakeOCSPResponder = new HttpServer();
   fakeOCSPResponder.registerPrefixHandler("/", function (request, response) {
     response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
-    do_check_true(gExpectOCSPRequest);
+    ok(gExpectOCSPRequest,
+       "Should be getting an OCSP request only when expected");
   });
   fakeOCSPResponder.start(8888);
 
   add_tls_server_setup("OCSPStaplingServer");
 
   add_tests(certDB, otherTestCA);
 
   add_test(function () {
--- a/security/manager/ssl/tests/unit/test_ocsp_stapling_expired.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_stapling_expired.js
@@ -16,17 +16,17 @@ function add_ocsp_test(aHost, aExpectedR
   add_connection_test(aHost, aExpectedResult,
     function() {
       clearOCSPCache();
       clearSessionCache();
       gCurrentOCSPResponse = aOCSPResponseToServe;
       gOCSPRequestCount = 0;
     },
     function() {
-      do_check_eq(gOCSPRequestCount, 1);
+      equal(gOCSPRequestCount, 1, "Should have made 1 fallback OCSP request");
     });
 }
 
 do_get_profile();
 Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
 Services.prefs.setIntPref("security.OCSP.enabled", 1);
 let args = [["good", "localhostAndExampleCom", "unused"],
              ["expiredresponse", "localhostAndExampleCom", "unused"],
@@ -153,15 +153,20 @@ function run_test() {
   run_next_test();
 }
 
 function check_ocsp_stapling_telemetry() {
   let histogram = Cc["@mozilla.org/base/telemetry;1"]
                     .getService(Ci.nsITelemetry)
                     .getHistogramById("SSL_OCSP_STAPLING")
                     .snapshot();
-  do_check_eq(histogram.counts[0], 0); // histogram bucket 0 is unused
-  do_check_eq(histogram.counts[1], 0); // 0 connections with a good response
-  do_check_eq(histogram.counts[2], 0); // 0 connections with no stapled resp.
-  do_check_eq(histogram.counts[3], 21); // 21 connections with an expired response
-  do_check_eq(histogram.counts[4], 0); // 0 connections with bad responses
+  equal(histogram.counts[0], 0,
+        "Should have 0 connections for unused histogram bucket 0");
+  equal(histogram.counts[1], 0,
+        "Actual and expected connections with a good response should match");
+  equal(histogram.counts[2], 0,
+        "Actual and expected connections with no stapled response should match");
+  equal(histogram.counts[3], 21,
+        "Actual and expected connections with an expired response should match");
+  equal(histogram.counts[4], 0,
+        "Actual and expected connections with bad responses should match");
   run_next_test();
 }
--- a/security/manager/ssl/tests/unit/test_ocsp_stapling_with_intermediate.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_stapling_with_intermediate.js
@@ -33,13 +33,13 @@ function run_test() {
 
   add_tls_server_setup("OCSPStaplingServer");
 
   add_ocsp_test("ocsp-stapling-with-intermediate.example.com",
                 PRErrorCodeSuccess);
 
   add_test(function () { ocspResponder.stop(run_next_test); });
   add_test(function() {
-    do_check_eq(gOCSPRequestCount, 0);
+    equal(gOCSPRequestCount, 0, "No OCSP requests should have been made");
     run_next_test();
   });
   run_next_test();
 }
--- a/security/manager/ssl/tests/unit/test_ocsp_timeout.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_timeout.js
@@ -65,21 +65,24 @@ function add_tests_in_mode(useHardFail) 
 
     // With OCSP hard-fail on, we timeout after 10 seconds.
     // With OCSP soft-fail, we timeout after 2 seconds.
     // Date() is not guaranteed to be monotonic, so add extra fuzz time to
     // prevent intermittent failures (this only appeared to be a problem on
     // Windows XP). See Bug 1121117.
     const FUZZ_MS = 300;
     if (useHardFail) {
-      do_check_true(timeDifference + FUZZ_MS > 10000);
+      ok(timeDifference + FUZZ_MS > 10000,
+         "Automatic OCSP timeout should be about 10s for hard-fail");
     } else {
-      do_check_true(timeDifference + FUZZ_MS > 2000);
+      ok(timeDifference + FUZZ_MS > 2000,
+         "Automatic OCSP timeout should be about 2s for soft-fail");
     }
     // Make sure we didn't wait too long.
     // (Unfortunately, we probably can't have a tight upper bound on
     // how long is too long for this test, because we might be running
     // on slow hardware.)
-    do_check_true(timeDifference < 60000);
+    ok(timeDifference < 60000,
+       "Automatic OCSP timeout shouldn't be more than 60s");
     clearOCSPCache();
     run_next_test();
   });
 }
--- a/toolkit/components/passwordmgr/storage-json.js
+++ b/toolkit/components/passwordmgr/storage-json.js
@@ -55,17 +55,17 @@ this.LoginManagerStorage_json.prototype 
 
       // Set the reference to LoginStore synchronously.
       let jsonPath = OS.Path.join(OS.Constants.Path.profileDir,
                                   "logins.json");
       this._store = new LoginStore(jsonPath);
 
       return Task.spawn(function () {
         // Load the data asynchronously.
-        this.log("Opening database at " + this._store.path);
+        this.log("Opening database at", this._store.path);
         yield this._store.load();
 
         // The import from previous versions operates the first time
         // that this built-in storage back-end is used.  This may be
         // later than expected, in case add-ons have registered an
         // alternate storage that disabled the default one.
         try {
           if (Services.prefs.getBoolPref("signon.importedFromSqlite")) {
@@ -87,17 +87,17 @@ this.LoginManagerStorage_json.prototype 
           yield loginImport.import().catch(Cu.reportError);
           this._store.saveSoon();
         }
 
         // We won't attempt import again on next startup.
         Services.prefs.setBoolPref("signon.importedFromSqlite", true);
       }.bind(this)).catch(Cu.reportError);
     } catch (e) {
-      this.log("Initialization failed: " + e);
+      this.log("Initialization failed:", e);
       throw new Error("Initialization failed");
     }
   },
 
 
   /*
    * terminate
    *
@@ -252,17 +252,17 @@ this.LoginManagerStorage_json.prototype 
    * Returns an array of nsILoginInfo.
    */
   getAllLogins : function (count) {
     let [logins, ids] = this._searchLogins({});
 
     // decrypt entries for caller.
     logins = this._decryptLogins(logins);
 
-    this.log("_getAllLogins: returning " + logins.length + " logins.");
+    this.log("_getAllLogins: returning", logins.length, "logins.");
     if (count)
       count.value = logins.length; // needed for XPCOM
     return logins;
   },
 
 
   /*
    * searchLogins
@@ -398,20 +398,20 @@ this.LoginManagerStorage_json.prototype 
         } else {
           fallbackLogins.push(login);
           fallbackIds.push(loginItem.id);
         }
       }
     }
 
     if (!foundLogins.length && fallbackLogins.length) {
-      this.log("_searchLogins: returning " + fallbackLogins.length + " fallback logins");
+      this.log("_searchLogins: returning", fallbackLogins.length, "fallback logins");
       return [fallbackLogins, fallbackIds];
     }
-    this.log("_searchLogins: returning " + foundLogins.length + " logins");
+    this.log("_searchLogins: returning", foundLogins.length, "logins");
     return [foundLogins, foundIds];
   },
 
   /*
    * removeAllLogins
    *
    * Removes all logins from storage.
    *
@@ -432,46 +432,46 @@ this.LoginManagerStorage_json.prototype 
    * getAllDisabledHosts
    *
    */
   getAllDisabledHosts : function (count) {
     this._store.ensureDataReady();
 
     let disabledHosts = this._store.data.disabledHosts.slice(0);
 
-    this.log("_getAllDisabledHosts: returning " + disabledHosts.length + " disabled hosts.");
+    this.log("_getAllDisabledHosts: returning", disabledHosts.length, "disabled hosts.");
     if (count)
       count.value = disabledHosts.length; // needed for XPCOM
     return disabledHosts;
   },
 
 
   /*
    * getLoginSavingEnabled
    *
    */
   getLoginSavingEnabled : function (hostname) {
     this._store.ensureDataReady();
 
-    this.log("Getting login saving is enabled for " + hostname);
+    this.log("Getting login saving is enabled for", hostname);
     return this._store.data.disabledHosts.indexOf(hostname) == -1;
   },
 
 
   /*
    * setLoginSavingEnabled
    *
    */
   setLoginSavingEnabled : function (hostname, enabled) {
     this._store.ensureDataReady();
 
     // Throws if there are bogus values.
     LoginHelper.checkHostnameValue(hostname);
 
-    this.log("Setting login saving enabled for " + hostname + " to " + enabled);
+    this.log("Setting login saving enabled for", hostname, "to", enabled);
     let foundIndex = this._store.data.disabledHosts.indexOf(hostname);
     if (enabled) {
       if (foundIndex != -1) {
         this._store.data.disabledHosts.splice(foundIndex, 1);
         this._store.saveSoon();
       }
     } else {
       if (foundIndex == -1) {
@@ -498,17 +498,17 @@ this.LoginManagerStorage_json.prototype 
     for each (let field in ["hostname", "formSubmitURL", "httpRealm"])
       if (loginData[field] != '')
         matchData[field] = loginData[field];
     let [logins, ids] = this._searchLogins(matchData);
 
     // Decrypt entries found for the caller.
     logins = this._decryptLogins(logins);
 
-    this.log("_findLogins: returning " + logins.length + " logins");
+    this.log("_findLogins: returning", logins.length, "logins");
     count.value = logins.length; // needed for XPCOM
     return logins;
   },
 
 
   /*
    * countLogins
    *
@@ -521,17 +521,17 @@ this.LoginManagerStorage_json.prototype 
       httpRealm: httpRealm
     };
     let matchData = { };
     for each (let field in ["hostname", "formSubmitURL", "httpRealm"])
       if (loginData[field] != '')
         matchData[field] = loginData[field];
     let [logins, ids] = this._searchLogins(matchData);
 
-    this.log("_countLogins: counted logins: " + logins.length);
+    this.log("_countLogins: counted logins:", logins.length);
     return logins.length;
   },
 
 
   /*
    * uiBusy
    */
   get uiBusy() {
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -2481,16 +2481,22 @@
   },
   "STS_POLL_BLOCK_TIME": {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": "60000",
     "n_buckets": 1000,
     "description": "Time spend blocked on poll (ms)."
   },
+  "IPV4_AND_IPV6_ADDRESS_CONNECTIVITY": {
+    "expires_in_version": "never",
+    "kind": "enumerated",
+    "n_values": 4,
+    "description": "Count the number of 0) successful connections to an ipv4 address, 1) failed connection an ipv4 address, 2) successful connection to an ipv6 address and 3) failed connections to an ipv6 address."
+  },
   "URL_PATH_ENDS_IN_EXCLAMATION": {
     "expires_in_version": "never",
     "kind": "boolean",
     "description": "The URL path ends in !"
   },
   "URL_PATH_CONTAINS_EXCLAMATION_SLASH": {
     "expires_in_version": "never",
     "kind": "boolean",
--- a/toolkit/devtools/DevToolsUtils.js
+++ b/toolkit/devtools/DevToolsUtils.js
@@ -646,8 +646,22 @@ exports.settleAll = values => {
     } else {
       // Given value is not a promise, forward it as a resolution value.
       resolver(value);
     }
   }
 
   return deferred.promise;
 };
+
+/**
+ * When the testing flag is set, various behaviors may be altered from
+ * production mode, typically to enable easier testing or enhanced debugging.
+ */
+let testing = false;
+Object.defineProperty(exports, "testing", {
+  get: function() {
+    return testing;
+  },
+  set: function(state) {
+    testing = state;
+  }
+});
--- a/toolkit/devtools/server/actors/inspector.js
+++ b/toolkit/devtools/server/actors/inspector.js
@@ -1,11 +1,12 @@
 /* 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/. */
+/* globals DevToolsUtils, DOMParser, eventListenerService, CssLogic */
 
 "use strict";
 
 /**
  * Here's the server side of the remote inspector.
  *
  * The WalkerActor is the client's view of the debuggee's DOM.  It's gives
  * the client a tree of NodeActor objects.
@@ -112,17 +113,18 @@ const PSEUDO_SELECTORS = [
 ];
 
 
 let HELPER_SHEET = ".__fx-devtools-hide-shortcut__ { visibility: hidden !important } ";
 HELPER_SHEET += ":-moz-devtools-highlighted { outline: 2px dashed #F06!important; outline-offset: -2px!important } ";
 
 Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm");
 
-loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
+loader.lazyRequireGetter(this, "DevToolsUtils",
+                         "devtools/toolkit/DevToolsUtils");
 
 loader.lazyGetter(this, "DOMParser", function() {
   return Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
 });
 
 loader.lazyGetter(this, "eventListenerService", function() {
   return Cc["@mozilla.org/eventlistenerservice;1"]
            .getService(Ci.nsIEventListenerService);
@@ -3670,17 +3672,17 @@ var InspectorActor = exports.InspectorAc
 
     // If the URL doesn't point to a resource, reject
     img.onerror = () => {
       deferred.reject(new Error("Image " + url+ " not available"));
     }
 
     // If the request hangs for too long, kill it to avoid queuing up other requests
     // to the same actor, except if we're running tests
-    if (!gDevTools.testing) {
+    if (!DevToolsUtils.testing) {
       this.window.setTimeout(() => {
         deferred.reject(new Error("Image " + url + " could not be retrieved in time"));
       }, IMAGE_FETCHING_TIMEOUT);
     }
 
     img.src = url;
 
     return deferred.promise;
--- a/toolkit/devtools/server/tests/browser/browser_animation_actors_15.js
+++ b/toolkit/devtools/server/tests/browser/browser_animation_actors_15.js
@@ -7,65 +7,80 @@
 // When a transition finishes, no "removed" event is sent because it may still
 // be used, but when it restarts again (transitions back), then a new
 // AnimationPlayerFront should be sent, and the old one should be removed.
 
 const {AnimationsFront} = require("devtools/server/actors/animation");
 const {InspectorFront} = require("devtools/server/actors/inspector");
 
 add_task(function*() {
-  let doc = yield addTab(MAIN_DOMAIN + "animation.html");
+  yield addTab(MAIN_DOMAIN + "animation.html");
 
   initDebuggerServer();
   let client = new DebuggerClient(DebuggerServer.connectPipe());
   let form = yield connectDebuggerClient(client);
   let inspector = InspectorFront(client, form);
   let walker = yield inspector.getWalker();
   let animations = AnimationsFront(client, form);
 
   info("Retrieve the test node");
   let node = yield walker.querySelector(walker.rootNode, ".all-transitions");
 
   info("Retrieve the animation players for the node");
   let players = yield animations.getAnimationPlayersForNode(node);
   is(players.length, 0, "The node has no animation players yet");
 
-  info("Listen for new animations");
-  let reportedMutations = [];
-  function onMutations(mutations) {
-    reportedMutations = [...reportedMutations, ...mutations];
-  }
-  animations.on("mutations", onMutations);
-
-  info("Transition the node by adding the expand class");
+  info("Play a transition by adding the expand class, wait for mutations");
+  let onMutations = expectMutationEvents(animations, 2);
   let cpow = content.document.querySelector(".all-transitions");
   cpow.classList.add("expand");
-  info("Wait for longer than the transition");
-  yield wait(500);
+  let reportedMutations = yield onMutations;
 
   is(reportedMutations.length, 2, "2 mutation events were received");
   is(reportedMutations[0].type, "added", "The first event was 'added'");
   is(reportedMutations[1].type, "added", "The second event was 'added'");
 
-  reportedMutations = [];
+  info("Wait for the transitions to be finished");
+  yield waitForEnd(reportedMutations[0].player);
+  yield waitForEnd(reportedMutations[1].player);
 
-  info("Transition back by removing the expand class");
+  info("Play the transition back by removing the class, wait for mutations");
+  onMutations = expectMutationEvents(animations, 4);
   cpow.classList.remove("expand");
-  info("Wait for longer than the transition");
-  yield wait(500);
+  reportedMutations = yield onMutations;
 
   is(reportedMutations.length, 4, "4 new mutation events were received");
   is(reportedMutations.filter(m => m.type === "removed").length, 2,
     "2 'removed' events were sent (for the old transitions)");
   is(reportedMutations.filter(m => m.type === "added").length, 2,
     "2 'added' events were sent (for the new transitions)");
 
-  animations.off("mutations", onMutations);
-
   yield closeDebuggerClient(client);
   gBrowser.removeCurrentTab();
 });
 
-function wait(ms) {
+function expectMutationEvents(animationsFront, nbOfEvents) {
   return new Promise(resolve => {
-    setTimeout(resolve, ms);
+    let reportedMutations = [];
+    function onMutations(mutations) {
+      reportedMutations = [...reportedMutations, ...mutations];
+      info("Received " + reportedMutations.length + " mutation events, " +
+           "expecting " + nbOfEvents);
+      if (reportedMutations.length === nbOfEvents) {
+        animationsFront.off("mutations", onMutations);
+        resolve(reportedMutations);
+      }
+    }
+
+    info("Start listening for mutation events from the AnimationsFront");
+    animationsFront.on("mutations", onMutations);
   });
 }
+
+function* waitForEnd(animationFront) {
+  let playState;
+  while (playState !== "finished") {
+    let state = yield animationFront.getCurrentState();
+    playState = state.playState;
+    info("Wait for transition " + animationFront.state.name +
+         " to finish, playState=" + playState);
+  }
+}
--- a/toolkit/devtools/webconsole/network-monitor.js
+++ b/toolkit/devtools/webconsole/network-monitor.js
@@ -1,37 +1,29 @@
 /* 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/. */
+/* globals NetworkHelper, Services, DevToolsUtils, NetUtil,
+   gActivityDistributor */
 
 "use strict";
 
 const {Cc, Ci, Cu, Cr} = require("chrome");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-loader.lazyGetter(this, "NetworkHelper", () => require("devtools/toolkit/webconsole/network-helper"));
+loader.lazyRequireGetter(this, "NetworkHelper",
+                         "devtools/toolkit/webconsole/network-helper");
 loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
-loader.lazyImporter(this, "DevToolsUtils", "resource://gre/modules/devtools/DevToolsUtils.jsm");
+loader.lazyRequireGetter(this, "DevToolsUtils",
+                         "devtools/toolkit/DevToolsUtils");
 loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
 loader.lazyServiceGetter(this, "gActivityDistributor",
                          "@mozilla.org/network/http-activity-distributor;1",
                          "nsIHttpActivityDistributor");
-let _testing = false;
-Object.defineProperty(this, "gTesting", {
-  get: function() {
-    try {
-      const { gDevTools } = require("resource:///modules/devtools/gDevTools.jsm");
-      _testing = gDevTools.testing;
-    } catch (e) {
-      // gDevTools is not present on B2G.
-    }
-    return _testing;
-  }
-});
 
 ///////////////////////////////////////////////////////////////////////////////
 // Network logging
 ///////////////////////////////////////////////////////////////////////////////
 
 // The maximum uint32 value.
 const PR_UINT32_MAX = 4294967295;
 
@@ -751,19 +743,19 @@ NetworkMonitor.prototype = {
   {
     if (this._logEverything) {
       return true;
     }
 
     // Ignore requests from chrome or add-on code when we are monitoring
     // content.
     // TODO: one particular test (browser_styleeditor_fetch-from-cache.js) needs
-    // the gDevTools.testing check. We will move to a better way to serve its
-    // needs in bug 1167188, where this check should be removed.
-    if (!gTesting && aChannel.loadInfo &&
+    // the DevToolsUtils.testing check. We will move to a better way to serve
+    // its needs in bug 1167188, where this check should be removed.
+    if (!DevToolsUtils.testing && aChannel.loadInfo &&
         aChannel.loadInfo.loadingDocument === null &&
         aChannel.loadInfo.loadingPrincipal === Services.scriptSecurityManager.getSystemPrincipal()) {
       return false;
     }
 
     if (this.window) {
       // Since frames support, this.window may not be the top level content
       // frame, so that we can't only compare with win.top.
--- a/toolkit/mozapps/installer/packager.mk
+++ b/toolkit/mozapps/installer/packager.mk
@@ -199,16 +199,16 @@ upload: checksum
 		$(UPLOAD_FILES) \
 		$(CHECKSUM_FILES)
 
 # source-package creates a source tarball from the files in MOZ_PKG_SRCDIR,
 # which is either set to a clean checkout or defaults to $topsrcdir
 source-package:
 	@echo 'Packaging source tarball...'
 	$(MKDIR) -p $(DIST)/$(PKG_SRCPACK_PATH)
-	(cd $(MOZ_PKG_SRCDIR) && $(CREATE_SOURCE_TAR) - $(DIR_TO_BE_PACKAGED)) | xz -9e > $(SOURCE_TAR)
+	(cd $(MOZ_PKG_SRCDIR) && $(CREATE_SOURCE_TAR) - ./ ) | xz -9e > $(SOURCE_TAR)
 
 hg-bundle:
 	$(MKDIR) -p $(DIST)/$(PKG_SRCPACK_PATH)
 	$(CREATE_HG_BUNDLE_CMD)
 
 source-upload:
 	$(MAKE) upload UPLOAD_FILES='$(SOURCE_UPLOAD_FILES)' CHECKSUM_FILE='$(SOURCE_CHECKSUM_FILE)'
--- a/toolkit/mozapps/installer/upload-files.mk
+++ b/toolkit/mozapps/installer/upload-files.mk
@@ -770,30 +770,30 @@ endif
 ifdef MOZ_STUB_INSTALLER
 UPLOAD_FILES += $(call QUOTED_WILDCARD,$(DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe)
 endif
 
 ifndef MOZ_PKG_SRCDIR
 MOZ_PKG_SRCDIR = $(topsrcdir)
 endif
 
-DIR_TO_BE_PACKAGED ?= ../$(notdir $(topsrcdir))
+SRC_TAR_PREFIX = $(MOZ_APP_NAME)-$(MOZ_PKG_VERSION)
 SRC_TAR_EXCLUDE_PATHS += \
   --exclude='.hg*' \
   --exclude='CVS' \
   --exclude='.cvs*' \
   --exclude='.mozconfig*' \
   --exclude='*.pyc' \
   --exclude='$(MOZILLA_DIR)/Makefile' \
   --exclude='$(MOZILLA_DIR)/dist'
 ifdef MOZ_OBJDIR
 SRC_TAR_EXCLUDE_PATHS += --exclude='$(MOZ_OBJDIR)'
 endif
 CREATE_SOURCE_TAR = $(TAR) -c --owner=0 --group=0 --numeric-owner \
-  --mode=go-w $(SRC_TAR_EXCLUDE_PATHS) -f
+  --mode=go-w $(SRC_TAR_EXCLUDE_PATHS) --transform='s,^\./,$(SRC_TAR_PREFIX)/,' -f
 
 SOURCE_TAR = $(DIST)/$(PKG_SRCPACK_PATH)$(PKG_SRCPACK_BASENAME).tar.xz
 HG_BUNDLE_FILE = $(DIST)/$(PKG_SRCPACK_PATH)$(PKG_BUNDLE_BASENAME).bundle
 SOURCE_CHECKSUM_FILE = $(DIST)/$(PKG_SRCPACK_PATH)$(PKG_SRCPACK_BASENAME).checksums
 SOURCE_UPLOAD_FILES = $(SOURCE_TAR)
 
 HG ?= hg
 CREATE_HG_BUNDLE_CMD  = $(HG) -v -R $(topsrcdir) bundle --base null
--- a/toolkit/themes/shared/extensions/extensions.inc.css
+++ b/toolkit/themes/shared/extensions/extensions.inc.css
@@ -671,24 +671,23 @@
 }
 
 #detail-name-container {
   font-size: 200%;
 }
 
 #detail-screenshot-box {
   -moz-margin-end: 2em;
-  padding: 10px;
-  background-color: white;
-  box-shadow: 0 1px 2px #666;
 }
 
 #detail-screenshot {
   max-width: 300px;
   max-height: 300px;
+  background-color: white;
+  box-shadow: 0 1px 2px #666;
 }
 
 #detail-screenshot[loading] {
   background-image: url("chrome://global/skin/icons/loading_16.png"),
                     linear-gradient(rgba(255, 255, 255, 0.5), transparent);
   background-position: 50% 50%;
   background-repeat: no-repeat;
   border-radius: 2px;
--- a/view/nsView.cpp
+++ b/view/nsView.cpp
@@ -224,20 +224,20 @@ nsIntRect nsView::CalcWidgetBounds(nsWin
       viewBounds += nsPoint(NSIntPixelsToAppUnits(screenPoint.x, p2a),
                             NSIntPixelsToAppUnits(screenPoint.y, p2a));
     }
   }
 
   // Compute widget bounds in device pixels
   nsIntRect newBounds = viewBounds.ToNearestPixels(p2a);
 
-#ifdef XP_MACOSX
-  // cocoa rounds widget coordinates to the nearest global "display pixel"
-  // integer value. So we avoid fractional display pixel values by rounding
-  // to the nearest value that won't yield a fractional display pixel.
+#if defined(XP_MACOSX) || (MOZ_WIDGET_GTK == 3)
+  // cocoa and GTK round widget coordinates to the nearest global "display
+  // pixel" integer value. So we avoid fractional display pixel values by
+  // rounding to the nearest value that won't yield a fractional display pixel.
   nsIWidget* widget = parentWidget ? parentWidget : mWindow.get();
   uint32_t round;
   if (aType == eWindowType_popup && widget &&
       ((round = widget->RoundsWidgetCoordinatesTo()) > 1)) {
     nsIntSize pixelRoundedSize = newBounds.Size();
     // round the top left and bottom right to the nearest round pixel
     newBounds.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.x, p2a) / round) * round;
     newBounds.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.y, p2a) / round) * round;
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -6572,8 +6572,14 @@ nsWindow::SynthesizeNativeMouseScrollEve
     return NS_OK;
   }
 #endif
 
   gdk_event_put(&event);
 
   return NS_OK;
 }
+
+int32_t
+nsWindow::RoundsWidgetCoordinatesTo()
+{
+    return GdkScaleFactor();
+}
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -477,16 +477,18 @@ private:
     // nsBaseWidget
     virtual LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
                                           LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                                           LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                                           bool* aAllowRetaining = nullptr) override;
 
     void CleanLayerManagerRecursive();
 
+    virtual int32_t RoundsWidgetCoordinatesTo() override;
+
     /**
      * |mIMModule| takes all IME related stuff.
      *
      * This is owned by the top-level nsWindow or the topmost child
      * nsWindow embedded in a non-Gecko widget.
      *
      * The instance is created when the top level widget is created.  And when
      * the widget is destroyed, it's released.  All child windows refer its
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -406,21 +406,20 @@ nsWindow::nsWindow() : nsWindowBase()
   sInstanceCount++;
 }
 
 nsWindow::~nsWindow()
 {
   mInDtor = true;
 
   // If the widget was released without calling Destroy() then the native window still
-  // exists, and we need to destroy it. This will also result in a call to OnDestroy.
-  //
-  // XXX How could this happen???
-  if (nullptr != mWnd)
-    Destroy();
+  // exists, and we need to destroy it.
+  // Destroy() will early-return if it was already called. In any case it is important
+  // to call it before destroying mPresentLock (cf. 1156182).
+  Destroy();
 
   // Free app icon resources.  This must happen after `OnDestroy` (see bug 708033).
   if (mIconSmall)
     ::DestroyIcon(mIconSmall);
 
   if (mIconBig)
     ::DestroyIcon(mIconBig);
 
--- a/xpcom/idl-parser/header.py
+++ b/xpcom/idl-parser/header.py
@@ -2,87 +2,103 @@
 # header.py - Generate C++ header files from IDL.
 #
 # 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/.
 
 """Print a C++ header file for the IDL files specified on the command line"""
 
-import sys, os.path, re, xpidl, itertools, glob
+import sys
+import os.path
+import re
+import xpidl
+import itertools
+import glob
 
 printdoccomments = False
 
 if printdoccomments:
     def printComments(fd, clist, indent):
         for c in clist:
             fd.write("%s%s\n" % (indent, c))
 else:
     def printComments(fd, clist, indent):
         pass
 
+
 def firstCap(str):
     return str[0].upper() + str[1:]
 
+
 def attributeParamName(a):
     return "a" + firstCap(a.name)
 
+
 def attributeParamNames(a):
     l = [attributeParamName(a)]
     if a.implicit_jscontext:
         l.insert(0, "cx")
     return ", ".join(l)
 
+
 def attributeNativeName(a, getter):
     binaryname = a.binaryname is not None and a.binaryname or firstCap(a.name)
     return "%s%s" % (getter and 'Get' or 'Set', binaryname)
 
+
 def attributeReturnType(a, macro):
     """macro should be NS_IMETHOD or NS_IMETHODIMP"""
     if (a.nostdcall):
         return macro == "NS_IMETHOD" and "virtual nsresult" or "nsresult"
     else:
         return macro
 
+
 def attributeParamlist(a, getter):
     l = ["%s%s" % (a.realtype.nativeType(getter and 'out' or 'in'),
                    attributeParamName(a))]
     if a.implicit_jscontext:
         l.insert(0, "JSContext* cx")
 
     return ", ".join(l)
 
+
 def attributeAsNative(a, getter):
         deprecated = a.deprecated and "NS_DEPRECATED " or ""
         params = {'deprecated': deprecated,
                   'returntype': attributeReturnType(a, 'NS_IMETHOD'),
                   'binaryname': attributeNativeName(a, getter),
                   'paramlist': attributeParamlist(a, getter)}
         return "%(deprecated)s%(returntype)s %(binaryname)s(%(paramlist)s)" % params
 
+
 def methodNativeName(m):
     return m.binaryname is not None and m.binaryname or firstCap(m.name)
 
+
 def methodReturnType(m, macro):
     """macro should be NS_IMETHOD or NS_IMETHODIMP"""
     if m.nostdcall and m.notxpcom:
         return "%s%s" % (macro == "NS_IMETHOD" and "virtual " or "",
                          m.realtype.nativeType('in').strip())
     elif m.nostdcall:
         return "%snsresult" % (macro == "NS_IMETHOD" and "virtual " or "")
     elif m.notxpcom:
         return "%s_(%s)" % (macro, m.realtype.nativeType('in').strip())
     else:
         return macro
 
+
 def methodAsNative(m):
     return "%s %s(%s)" % (methodReturnType(m, 'NS_IMETHOD'),
                           methodNativeName(m),
                           paramlistAsNative(m))
 
+
 def paramlistAsNative(m, empty='void'):
     l = [paramAsNative(p) for p in m.params]
 
     if m.implicit_jscontext:
         l.append("JSContext* cx")
 
     if m.optional_argc:
         l.append('uint8_t _argc')
@@ -95,20 +111,22 @@ def paramlistAsNative(m, empty='void'):
                                            location=None,
                                            realtype=m.realtype)))
 
     if len(l) == 0:
         return empty
 
     return ", ".join(l)
 
+
 def paramAsNative(p):
     return "%s%s" % (p.nativeType(),
                      p.name)
 
+
 def paramlistNames(m):
     names = [p.name for p in m.params]
 
     if m.implicit_jscontext:
         names.append('cx')
 
     if m.optional_argc:
         names.append('_argc')
@@ -152,20 +170,22 @@ header_end = """/* For IDL files that do
 footer = """
 #endif /* __gen_%(basename)s_h__ */
 """
 
 forward_decl = """class %(name)s; /* forward declaration */
 
 """
 
+
 def idl_basename(f):
     """returns the base name of a file with the last extension stripped"""
     return os.path.basename(f).rpartition('.')[0]
 
+
 def print_header(idl, fd, filename):
     fd.write(header % {'filename': filename,
                        'basename': idl_basename(filename)})
 
     foundinc = False
     for inc in idl.includes():
         if not foundinc:
             foundinc = True
@@ -181,17 +201,18 @@ def print_header(idl, fd, filename):
             if attr.infallible:
                 fd.write(infallible_includes)
                 break
 
     fd.write('\n')
     fd.write(header_end)
 
     for p in idl.productions:
-        if p.kind == 'include': continue
+        if p.kind == 'include':
+            continue
         if p.kind == 'cdata':
             fd.write(p.data)
             continue
 
         if p.kind == 'forward':
             fd.write(forward_decl % {'name': p.name})
             continue
         if p.kind == 'interface':
@@ -216,17 +237,17 @@ iface_header = r"""
 
 uuid_decoder = re.compile(r"""(?P<m0>[a-f0-9]{8})-
                               (?P<m1>[a-f0-9]{4})-
                               (?P<m2>[a-f0-9]{4})-
                               (?P<m3>[a-f0-9]{4})-
                               (?P<m4>[a-f0-9]{12})$""", re.X)
 
 iface_prolog = """ {
- public: 
+ public:
 
   NS_DECLARE_STATIC_IID_ACCESSOR(%(defname)s_IID)
 
 """
 
 iface_epilog = """};
 
   NS_DEFINE_STATIC_IID_ACCESSOR(%(name)s, %(defname)s_IID)
@@ -297,16 +318,17 @@ attr_infallible_tmpl = """\
   {
     %(realtype)sresult;
     mozilla::DebugOnly<nsresult> rv = %(nativename)s(%(argnames)s&result);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
     return result;
   }
 """
 
+
 def write_interface(iface, fd):
     if iface.namemap is None:
         raise Exception("Interface was not resolved.")
 
     def write_const_decls(g):
         fd.write("  enum {\n")
         enums = []
         for c in g:
@@ -320,21 +342,21 @@ def write_interface(iface, fd):
         fd.write(",\n".join(enums))
         fd.write("\n  };\n\n")
 
     def write_method_decl(m):
         printComments(fd, m.doccomments, '  ')
 
         fd.write("  /* %s */\n" % m.toIDL())
         fd.write("  %s = 0;\n\n" % methodAsNative(m))
-                                                                           
+
     def write_attr_decl(a):
         printComments(fd, a.doccomments, '  ')
 
-        fd.write("  /* %s */\n" % a.toIDL());
+        fd.write("  /* %s */\n" % a.toIDL())
 
         fd.write("  %s = 0;\n" % attributeAsNative(a, True))
         if a.infallible:
             fd.write(attr_infallible_tmpl %
                      {'realtype': a.realtype.nativeType('in'),
                       'nativename': attributeNativeName(a, getter=True),
                       'args': '' if not a.implicit_jscontext else 'JSContext* cx',
                       'argnames': '' if not a.implicit_jscontext else 'cx, '})
@@ -379,17 +401,17 @@ def write_interface(iface, fd):
         fd.write("MOZ_DEPRECATED ")
     fd.write(iface.name)
     if iface.base:
         fd.write(" : public %s" % iface.base)
     fd.write(iface_prolog % names)
 
     for key, group in itertools.groupby(iface.members, key=type):
         if key == xpidl.ConstMember:
-            write_const_decls(group) # iterator of all the consts
+            write_const_decls(group)  # iterator of all the consts
         else:
             for member in group:
                 if key == xpidl.Attribute:
                     write_attr_decl(member)
                 elif key == xpidl.Method:
                     write_method_decl(member)
                 elif key == xpidl.CDATA:
                     fd.write(" %s" % member.data)
@@ -405,22 +427,22 @@ def write_interface(iface, fd):
             fd.write("\\\n  %s override; " % attributeAsNative(member, True))
             if not member.readonly:
                 fd.write("\\\n  %s override; " % attributeAsNative(member, False))
         elif isinstance(member, xpidl.Method):
             fd.write("\\\n  %s override; " % methodAsNative(member))
     if len(iface.members) == 0:
         fd.write('\\\n  /* no methods! */')
     elif not member.kind in ('attribute', 'method'):
-       fd.write('\\')
+        fd.write('\\')
 
     fd.write(iface_forward % names)
 
     def emitTemplate(forward_infallible, tmpl, tmpl_notxpcom=None):
-        if tmpl_notxpcom == None:
+        if tmpl_notxpcom is None:
             tmpl_notxpcom = tmpl
         for member in iface.members:
             if isinstance(member, xpidl.Attribute):
                 if forward_infallible and member.infallible:
                     fd.write("\\\n  using %s::%s; " % (iface.name, attributeNativeName(member, True)))
                 fd.write(tmpl % {'asNative': attributeAsNative(member, True),
                                  'nativeName': attributeNativeName(member, True),
                                  'paramList': attributeParamNames(member)})
@@ -452,17 +474,18 @@ def write_interface(iface, fd):
     # implement them.
     emitTemplate(False,
                  "\\\n  %(asNative)s override { return !_to ? NS_ERROR_NULL_POINTER : _to->%(nativeName)s(%(paramList)s); } ",
                  "\\\n  %(asNative)s override; ")
 
     fd.write(iface_template_prolog % names)
 
     for member in iface.members:
-        if isinstance(member, xpidl.ConstMember) or isinstance(member, xpidl.CDATA): continue
+        if isinstance(member, xpidl.ConstMember) or isinstance(member, xpidl.CDATA):
+            continue
         fd.write("/* %s */\n" % member.toIDL())
         if isinstance(member, xpidl.Attribute):
             fd.write(example_tmpl % {'implclass': implclass,
                                      'returntype': attributeReturnType(member, 'NS_IMETHODIMP'),
                                      'nativeName': attributeNativeName(member, True),
                                      'paramList': attributeParamlist(member, True)})
             if not member.readonly:
                 fd.write(example_tmpl % {'implclass': implclass,
--- a/xpcom/idl-parser/runtests.py
+++ b/xpcom/idl-parser/runtests.py
@@ -4,20 +4,21 @@
 # http://creativecommons.org/publicdomain/zero/1.0/
 #
 # Unit tests for xpidl.py
 
 import mozunit
 import unittest
 import xpidl
 
+
 class TestParser(unittest.TestCase):
     def setUp(self):
         self.p = xpidl.IDLParser()
-    
+
     def testEmpty(self):
         i = self.p.parse("", filename='f')
         self.assertTrue(isinstance(i, xpidl.IDL))
         self.assertEqual([], i.productions)
 
     def testForwardInterface(self):
         i = self.p.parse("interface foo;", filename='f')
         self.assertTrue(isinstance(i, xpidl.IDL))
--- a/xpcom/idl-parser/typelib.py
+++ b/xpcom/idl-parser/typelib.py
@@ -4,17 +4,18 @@
 # 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/.
 
 """Generate an XPIDL typelib for the IDL files specified on the command line"""
 
 import os
 import sys
-import xpidl, xpt
+import xpidl
+import xpt
 
 # A map of xpidl.py types to xpt.py types
 TypeMap = {
     # nsresult is not strictly an xpidl.py type, but it's useful here
     'nsresult':           xpt.Type.Tags.uint32,
     # builtins
     'boolean':            xpt.Type.Tags.boolean,
     'void':               xpt.Type.Tags.void,
@@ -42,38 +43,40 @@ TypeMap = {
     'nsid':               xpt.Type.Tags.nsIID,
     'domstring':          xpt.Type.Tags.DOMString,
     'astring':            xpt.Type.Tags.AString,
     'utf8string':         xpt.Type.Tags.UTF8String,
     'cstring':            xpt.Type.Tags.CString,
     'jsval':              xpt.Type.Tags.jsval
 }
 
+
 # XXXkhuey dipper types should go away (bug 677784)
 def isDipperType(type):
     return type == xpt.Type.Tags.DOMString or type == xpt.Type.Tags.AString or type == xpt.Type.Tags.CString or type == xpt.Type.Tags.UTF8String
 
+
 def build_interface(iface, ifaces):
     def get_type(type, calltype, iid_is=None, size_is=None):
         """ Return the appropriate xpt.Type object for this param """
 
         while isinstance(type, xpidl.Typedef):
             type = type.realtype
 
         if isinstance(type, xpidl.Builtin):
-            if type.name == 'string' and size_is != None:
-                  return xpt.StringWithSizeType(size_is, size_is)
-            elif type.name == 'wstring' and size_is != None:
-                  return xpt.WideStringWithSizeType(size_is, size_is)
+            if type.name == 'string' and size_is is not None:
+                return xpt.StringWithSizeType(size_is, size_is)
+            elif type.name == 'wstring' and size_is is not None:
+                return xpt.WideStringWithSizeType(size_is, size_is)
             else:
-                  tag = TypeMap[type.name]
-                  isPtr = (tag == xpt.Type.Tags.char_ptr or tag == xpt.Type.Tags.wchar_t_ptr)
-                  return xpt.SimpleType(tag,
-                                        pointer=isPtr,
-                                        reference=False)
+                tag = TypeMap[type.name]
+                isPtr = (tag == xpt.Type.Tags.char_ptr or tag == xpt.Type.Tags.wchar_t_ptr)
+                return xpt.SimpleType(tag,
+                                      pointer=isPtr,
+                                      reference=False)
 
         if isinstance(type, xpidl.Array):
             # NB: For an Array<T> we pass down the iid_is to get the type of T.
             #     This allows Arrays of InterfaceIs types to work.
             return xpt.ArrayType(get_type(type.type, calltype, iid_is), size_is,
                                  #XXXkhuey length_is duplicates size_is (bug 677788),
                                  size_is)
 
@@ -92,17 +95,17 @@ def build_interface(iface, ifaces):
         if isinstance(type, xpidl.Native):
             if type.specialtype:
                 # XXXkhuey jsval is marked differently in the typelib and in the headers :-(
                 isPtr = (type.isPtr(calltype) or type.isRef(calltype)) and not type.specialtype == 'jsval'
                 isRef = type.isRef(calltype) and not type.specialtype == 'jsval'
                 return xpt.SimpleType(TypeMap[type.specialtype],
                                       pointer=isPtr,
                                       reference=isRef)
-            elif iid_is != None:
+            elif iid_is is not None:
                 return xpt.InterfaceIsType(iid_is)
             else:
                 # void ptr
                 return xpt.SimpleType(TypeMap['void'],
                                       pointer=True,
                                       reference=False)
 
         raise Exception("Unknown type!")
@@ -230,16 +233,17 @@ def build_interface(iface, ifaces):
 
     return xpt.Interface(iface.name, iface.attributes.uuid, methods=methods,
                          constants=consts, resolved=True, parent=parent,
                          scriptable=iface.attributes.scriptable,
                          function=iface.attributes.function,
                          builtinclass=iface.attributes.builtinclass,
                          main_process_scriptable_only=iface.attributes.main_process_scriptable_only)
 
+
 def write_typelib(idl, fd, filename):
     """ Generate the typelib. """
 
     # We only care about interfaces
     ifaces = []
     for p in idl.productions:
         if p.kind == 'interface':
             ifaces.append(build_interface(p, ifaces))
--- a/xpcom/idl-parser/xpidl.py
+++ b/xpcom/idl-parser/xpidl.py
@@ -2,18 +2,21 @@
 # xpidl.py - A parser for cross-platform IDL (XPIDL) files.
 #
 # 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/.
 
 """A parser for cross-platform IDL (XPIDL) files."""
 
-import sys, os.path, re
-from ply import lex, yacc
+import sys
+import os.path
+import re
+from ply import lex
+from ply import yacc
 
 """A type conforms to the following pattern:
 
     def isScriptable(self):
         'returns True or False'
 
     def nativeType(self, calltype):
         'returns a string representation of the native type
@@ -22,31 +25,33 @@ from ply import lex, yacc
 Interface members const/method/attribute conform to the following pattern:
 
     name = 'string'
 
     def toIDL(self):
         'returns the member signature as IDL'
 """
 
+
 def attlistToIDL(attlist):
     if len(attlist) == 0:
         return ''
 
     attlist = list(attlist)
-    attlist.sort(cmp=lambda a,b: cmp(a[0], b[0]))
+    attlist.sort(cmp=lambda a, b: cmp(a[0], b[0]))
 
     return '[%s] ' % ','.join(["%s%s" % (name, value is not None and '(%s)' % value or '')
                               for name, value, aloc in attlist])
 
 _paramsHardcode = {
     2: ('array', 'shared', 'iid_is', 'size_is', 'retval'),
     3: ('array', 'size_is', 'const'),
 }
 
+
 def paramAttlistToIDL(attlist):
     if len(attlist) == 0:
         return ''
 
     # Hack alert: g_hash_table_foreach is pretty much unimitatable... hardcode
     # quirk
     attlist = list(attlist)
     sorted = []
@@ -61,39 +66,43 @@ def paramAttlistToIDL(attlist):
 
                 i += 1
 
     sorted.extend(attlist)
 
     return '[%s] ' % ', '.join(["%s%s" % (name, value is not None and ' (%s)' % value or '')
                                 for name, value, aloc in sorted])
 
+
 def unaliasType(t):
     while t.kind == 'typedef':
         t = t.realtype
     assert t is not None
     return t
 
+
 def getBuiltinOrNativeTypeName(t):
     t = unaliasType(t)
     if t.kind == 'builtin':
         return t.name
     elif t.kind == 'native':
         assert t.specialtype is not None
         return '[%s]' % t.specialtype
     else:
         return None
 
+
 class BuiltinLocation(object):
     def get(self):
         return "<builtin type>"
 
     def __str__(self):
         return self.get()
 
+
 class Builtin(object):
     kind = 'builtin'
     location = BuiltinLocation
 
     def __init__(self, name, nativename, signed=False, maybeConst=False):
         self.name = name
         self.nativename = nativename
         self.signed = signed
@@ -134,28 +143,29 @@ builtinNames = [
     Builtin('wchar', 'char16_t', False, False),
     Builtin('wstring', 'char16_t *', False, False),
 ]
 
 builtinMap = {}
 for b in builtinNames:
     builtinMap[b.name] = b
 
+
 class Location(object):
     _line = None
 
     def __init__(self, lexer, lineno, lexpos):
         self._lineno = lineno
         self._lexpos = lexpos
         self._lexdata = lexer.lexdata
         self._file = getattr(lexer, 'filename', "<unknown>")
 
     def __eq__(self, other):
-        return self._lexpos == other._lexpos and \
-               self._file == other._file
+        return (self._lexpos == other._lexpos and
+                self._file == other._file)
 
     def resolve(self):
         if self._line:
             return
 
         startofline = self._lexdata.rfind('\n', 0, self._lexpos) + 1
         endofline = self._lexdata.find('\n', self._lexpos, self._lexpos + 80)
         self._line = self._lexdata[startofline:endofline]
@@ -173,16 +183,17 @@ class Location(object):
         self.resolve()
         return "%s line %s:%s" % (self._file, self._lineno, self._colno)
 
     def __str__(self):
         self.resolve()
         return "%s line %s:%s\n%s\n%s" % (self._file, self._lineno, self._colno,
                                           self._line, self.pointerline())
 
+
 class NameMap(object):
     """Map of name -> object. Each object must have a .name and .location property.
     Setting the same name twice throws an error."""
     def __init__(self):
         self._d = {}
 
     def __getitem__(self, key):
         if key in builtinMap:
@@ -197,42 +208,45 @@ class NameMap(object):
 
     def set(self, object):
         if object.name in builtinMap:
             raise IDLError("name '%s' is a builtin and cannot be redeclared" % (object.name), object.location)
         if object.name.startswith("_"):
             object.name = object.name[1:]
         if object.name in self._d:
             old = self._d[object.name]
-            if old == object: return
+            if old == object:
+                return
             if isinstance(old, Forward) and isinstance(object, Interface):
                 self._d[object.name] = object
             elif isinstance(old, Interface) and isinstance(object, Forward):
                 pass
             else:
                 raise IDLError("name '%s' specified twice. Previous location: %s" % (object.name, self._d[object.name].location), object.location)
         else:
             self._d[object.name] = object
 
     def get(self, id, location):
         try:
             return self[id]
         except KeyError:
             raise IDLError("Name '%s' not found", location)
 
+
 class IDLError(Exception):
     def __init__(self, message, location, warning=False):
         self.message = message
         self.location = location
         self.warning = warning
 
     def __str__(self):
         return "%s: %s, %s" % (self.warning and 'warning' or 'error',
                                self.message, self.location)
 
+
 class Include(object):
     kind = 'include'
 
     def __init__(self, filename, location):
         self.filename = filename
         self.location = location
 
     def __str__(self):
@@ -240,27 +254,29 @@ class Include(object):
 
     def resolve(self, parent):
         def incfiles():
             yield self.filename
             for dir in parent.incdirs:
                 yield os.path.join(dir, self.filename)
 
         for file in incfiles():
-            if not os.path.exists(file): continue
+            if not os.path.exists(file):
+                continue
 
             self.IDL = parent.parser.parse(open(file).read(), filename=file)
             self.IDL.resolve(parent.incdirs, parent.parser)
             for type in self.IDL.getNames():
                 parent.setName(type)
             parent.deps.extend(self.IDL.deps)
             return
 
         raise IDLError("File '%s' not found" % self.filename, self.location)
 
+
 class IDL(object):
     def __init__(self, productions):
         self.productions = productions
         self.deps = []
 
     def setName(self, object):
         self.namemap.set(object)
 
@@ -292,16 +308,17 @@ class IDL(object):
                 yield p
 
     def needsJSTypes(self):
         for p in self.productions:
             if p.kind == 'interface' and p.needsJSTypes():
                 return True
         return False
 
+
 class CDATA(object):
     kind = 'cdata'
     _re = re.compile(r'\n+')
 
     def __init__(self, data, location):
         self.data = self._re.sub('\n', data)
         self.location = location
 
@@ -309,16 +326,17 @@ class CDATA(object):
         pass
 
     def __str__(self):
         return "cdata: %s\n\t%r\n" % (self.location.get(), self.data)
 
     def count(self):
         return 0
 
+
 class Typedef(object):
     kind = 'typedef'
 
     def __init__(self, type, name, location, doccomments):
         self.type = type
         self.name = name
         self.location = location
         self.doccomments = doccomments
@@ -335,33 +353,35 @@ class Typedef(object):
 
     def nativeType(self, calltype):
         return "%s %s" % (self.name,
                           calltype != 'in' and '*' or '')
 
     def __str__(self):
         return "typedef %s %s\n" % (self.type, self.name)
 
+
 class Forward(object):
     kind = 'forward'
 
     def __init__(self, name, location, doccomments):
         self.name = name
         self.location = location
         self.doccomments = doccomments
 
     def __eq__(self, other):
         return other.kind == 'forward' and other.name == self.name
 
     def resolve(self, parent):
         # Hack alert: if an identifier is already present, move the doccomments
         # forward.
         if parent.hasName(self.name):
             for i in xrange(0, len(parent.productions)):
-                if parent.productions[i] is self: break
+                if parent.productions[i] is self:
+                    break
             for i in xrange(i + 1, len(parent.productions)):
                 if hasattr(parent.productions[i], 'doccomments'):
                     parent.productions[i].doccomments[0:0] = self.doccomments
                     break
 
         parent.setName(self)
 
     def isScriptable(self):
@@ -369,16 +389,17 @@ class Forward(object):
 
     def nativeType(self, calltype):
         return "%s %s" % (self.name,
                           calltype != 'in' and '* *' or '*')
 
     def __str__(self):
         return "forward-declared %s\n" % self.name
 
+
 class Native(object):
     kind = 'native'
 
     modifier = None
     specialtype = None
 
     specialtypes = {
         'nsid': None,
@@ -406,20 +427,20 @@ class Native(object):
                     raise IDLError("More than one special type", aloc)
                 self.specialtype = name
                 if self.specialtypes[name] is not None:
                     self.nativename = self.specialtypes[name]
             else:
                 raise IDLError("Unexpected attribute", aloc)
 
     def __eq__(self, other):
-        return self.name == other.name and \
-               self.nativename == other.nativename and \
-               self.modifier == other.modifier and \
-               self.specialtype == other.specialtype
+        return (self.name == other.name and
+                self.nativename == other.nativename and
+                self.modifier == other.modifier and
+                self.specialtype == other.specialtype)
 
     def resolve(self, parent):
         parent.setName(self)
 
     def isScriptable(self):
         if self.specialtype is None:
             return False
 
@@ -454,16 +475,17 @@ class Native(object):
             m = '*' + ((self.modifier == 'ptr' and calltype != 'in') and '*' or '')
         else:
             m = calltype != 'in' and '*' or ''
         return "%s%s %s" % (const and 'const ' or '', self.nativename, m)
 
     def __str__(self):
         return "native %s(%s)\n" % (self.name, self.nativename)
 
+
 class Interface(object):
     kind = 'interface'
 
     def __init__(self, name, attlist, base, members, location, doccomments):
         self.name = name
         self.attributes = InterfaceAttributes(attlist, location)
         self.base = base
         self.members = members
@@ -515,18 +537,17 @@ class Interface(object):
         for member in self.members:
             member.resolve(self)
 
         # The number 250 is NOT arbitrary; this number is the maximum number of
         # stub entries defined in xpcom/reflect/xptcall/genstubs.pl
         # Do not increase this value without increasing the number in that
         # location, or you WILL cause otherwise unknown problems!
         if self.countEntries() > 250 and not self.attributes.builtinclass:
-            raise IDLError("interface '%s' has too many entries" % self.name,
-                self.location)
+            raise IDLError("interface '%s' has too many entries" % self.name, self.location)
 
     def isScriptable(self):
         # NOTE: this is not whether *this* interface is scriptable... it's
         # whether, when used as a type, it's scriptable, which is true of all
         # interfaces.
         return True
 
     def nativeType(self, calltype, const=False):
@@ -547,17 +568,17 @@ class Interface(object):
         return "".join(l)
 
     def getConst(self, name, location):
         # The constant may be in a base class
         iface = self
         while name not in iface.namemap and iface is not None:
             iface = self.idl.getName(self.base, self.location)
         if iface is None:
-            raise IDLError("cannot find symbol '%s'" % name, c.location)
+            raise IDLError("cannot find symbol '%s'" % name)
         c = iface.namemap.get(name, location)
         if c.kind != 'const':
             raise IDLError("symbol '%s' is not a constant", c.location)
 
         return c.getValue()
 
     def needsJSTypes(self):
         for m in self.members:
@@ -570,16 +591,17 @@ class Interface(object):
     def countEntries(self):
         ''' Returns the number of entries in the vtable for this interface. '''
         total = sum(member.count() for member in self.members)
         if self.base is not None:
             realbase = self.idl.getName(self.base, self.location)
             total += realbase.countEntries()
         return total
 
+
 class InterfaceAttributes(object):
     uuid = None
     scriptable = False
     builtinclass = False
     function = False
     deprecated = False
     noscript = False
     main_process_scriptable_only = False
@@ -647,18 +669,20 @@ class InterfaceAttributes(object):
         if self.builtinclass:
             l.append("\tbuiltinclass\n")
         if self.function:
             l.append("\tfunction\n")
         if self.main_process_scriptable_only:
             l.append("\tmain_process_scriptable_only\n")
         return "".join(l)
 
+
 class ConstMember(object):
     kind = 'const'
+
     def __init__(self, type, name, value, location, doccomments):
         self.type = type
         self.name = name
         self.value = value
         self.location = location
         self.doccomments = doccomments
 
     def resolve(self, parent):
@@ -676,16 +700,17 @@ class ConstMember(object):
         return self.value(self.iface)
 
     def __str__(self):
         return "\tconst %s %s = %s\n" % (self.type, self.name, self.getValue())
 
     def count(self):
         return 0
 
+
 class Attribute(object):
     kind = 'attribute'
     noscript = False
     readonly = False
     implicit_jscontext = False
     nostdcall = False
     binaryname = None
     null = None
@@ -710,30 +735,30 @@ class Attribute(object):
                 self.binaryname = value
                 continue
 
             if name == 'Null':
                 if value is None:
                     raise IDLError("'Null' attribute requires a value", aloc)
                 if readonly:
                     raise IDLError("'Null' attribute only makes sense for setters",
-                                   aloc);
+                                   aloc)
                 if value not in ('Empty', 'Null', 'Stringify'):
                     raise IDLError("'Null' attribute value must be 'Empty', 'Null' or 'Stringify'",
-                                   aloc);
+                                   aloc)
                 self.null = value
             elif name == 'Undefined':
                 if value is None:
                     raise IDLError("'Undefined' attribute requires a value", aloc)
                 if readonly: