Merge m-i to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Wed, 26 Oct 2016 18:40:50 -0700
changeset 319647 3f4c3a3cabaf94958834d3a8935adfb4a887942d
parent 319573 54f7bdea89765bb113513f00000160f4dd25c317 (current diff)
parent 319646 39d9931967d49fc2ecd8f3952f967f4678ac5f51 (diff)
child 319648 b160bea535476764a8ac51e52bde61c066d81642
child 319659 1181ec8f8ceed76b314aaa6ef583e66be232b42e
child 319687 58220cbd66045f85c22d8c830973643dab017810
push id30873
push userphilringnalda@gmail.com
push dateThu, 27 Oct 2016 01:41:13 +0000
treeherdermozilla-central@3f4c3a3cabaf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone52.0a1
first release with
nightly linux32
3f4c3a3cabaf / 52.0a1 / 20161027030211 / files
nightly linux64
3f4c3a3cabaf / 52.0a1 / 20161027030211 / files
nightly mac
3f4c3a3cabaf / 52.0a1 / 20161027030211 / files
nightly win32
3f4c3a3cabaf / 52.0a1 / 20161027030211 / files
nightly win64
3f4c3a3cabaf / 52.0a1 / 20161027030211 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-i to m-c, a=merge MozReview-Commit-ID: CysKZsvYf69
dom/tests/mochitest/bugs/test_bug411103.html
dom/webidl/Navigator.webidl
dom/webidl/moz.build
intl/unicharutil/tools/genUnicodePropertyData.pl
modules/libpref/init/all.js
taskcluster/taskgraph/transforms/task.py
--- a/browser/base/content/browser-charsetmenu.inc
+++ b/browser/base/content/browser-charsetmenu.inc
@@ -1,13 +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/.
 
 <menu id="charsetMenu"
     label="&charsetMenu2.label;"
     accesskey="&charsetMenu2.accesskey;"
     oncommand="BrowserSetForcedCharacterSet(event.target.getAttribute('charset'));"
-    onpopupshowing="CharsetMenu.build(event.target);"
-    onpopupshown="UpdateCurrentCharset(this);">
+    onpopupshowing="CharsetMenu.build(event.target); UpdateCurrentCharset(this);">
   <menupopup>
   </menupopup>
 </menu>
new file mode 100644
--- /dev/null
+++ b/browser/config/tooltool-manifests/win32/build-clang-cl.manifest
@@ -0,0 +1,63 @@
+[
+{
+"size": 266240,
+"digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
+"algorithm": "sha512",
+"filename": "mozmake.exe"
+},
+{
+"version": "rustc 1.12.0 (3191fbae9 2016-09-23) repack",
+"size": 89434100,
+"digest": "4da0efd2c36c77f29846f328d9f3c095a7b7e0dfd94f76b3159d441aae02b25007a475a979fb5bf313cf8fecb22fec81684871809effcb6b514419bc3854f398",
+"algorithm": "sha512",
+"filename": "rustc.tar.bz2",
+"unpack": true
+},
+{
+"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
+"size": 2402000,
+"digest": "56f12f7ac437742ed717ce0ccfb0b4134160948e45d73016e48d9033567e5b01a171ac95dd7965eb007702c31da73274b5913281655f461f611ddeee37181ecc",
+"algorithm": "sha512",
+"filename": "cargo.tar.bz2",
+"unpack": true
+},
+{
+"size": 167175,
+"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
+"algorithm": "sha512",
+"filename": "sccache.tar.bz2",
+"unpack": true
+},
+{
+"version": "Visual Studio 2015 Update 3 14.0.25425.01 / SDK 10.0.14393.0",
+"size": 326656969,
+"digest": "babc414ffc0457d27f5a1ed24a8e4873afbe2f1c1a4075469a27c005e1babc3b2a788f643f825efedff95b79686664c67ec4340ed535487168a3482e68559bc7",
+"algorithm": "sha512",
+"filename": "vs2015u3.zip",
+"unpack": true
+},
+{
+"version": "SVN 1.9.4, repacked from SlikSvn (https://sliksvn.com/download/)",
+"size": 3934520,
+"digest": "d3b8f74936857ecbf542e403ed6835938a31d65302985729cbfa7191bf2cf94138565cefcc2f31517098013fbfc51868348863a55b588250902f9dec214dbc42",
+"algorithm": "sha512",
+"filename": "svn194.zip",
+"unpack": true
+},
+{
+"version": "CMake 3.6.2 repack",
+"size": 19832889,
+"digest": "39b0508b60f655969d1b54c76753b14b5b2e92dab58613c835aed798a6aeb9077a7df78aebc011c2c753661fdc15007d3353c0c8773a53148380e2ec02afb629",
+"algorithm": "sha512",
+"filename": "cmake362.zip",
+"unpack": true
+},
+{
+"version": "Ninja 1.7.1",
+"size": 184821,
+"digest": "e4f9a1ae624a2630e75264ba37d396d9c7407d6e6aea3763056210ba6e1387908bd31cf4037a6a3661a418e86c4d2761e0c333e6a3bd0d66549d2b0d72d3f43b",
+"algorithm": "sha512",
+"filename": "ninja171.zip",
+"unpack": true
+}
+]
--- a/browser/locales/search/list.json
+++ b/browser/locales/search/list.json
@@ -15,16 +15,21 @@
         "visibleDefaultEngines": [
           "yahoo", "google-nocodes", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
         ]
       },
       "CA": {
         "visibleDefaultEngines": [
           "google-nocodes", "yahoo", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
         ]
+      },
+      "experimental-hidden": {
+        "visibleDefaultEngines": [
+          "yahoo-en-CA"
+        ]
       }
     },
     "ach": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
         ]
       }
@@ -386,16 +391,41 @@
         ]
       }
     },
     "kk": {
       "default": {
         "visibleDefaultEngines": [
           "yandex", "google", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
         ]
+      },
+      "KZ": {
+        "visibleDefaultEngines": [
+          "yandex", "google-nocodes", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
+        ]
+      },
+      "BY": {
+        "visibleDefaultEngines": [
+          "yandex", "google-nocodes", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
+        ]
+      },
+      "RU": {
+        "visibleDefaultEngines": [
+          "yandex", "google-nocodes", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
+        ]
+      },
+      "TR": {
+        "visibleDefaultEngines": [
+          "yandex", "google-nocodes", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
+        ]
+      },
+      "UA": {
+        "visibleDefaultEngines": [
+          "yandex", "google-nocodes", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
+        ]
       }
     },
     "km": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo", "bing", "amazondotcom", "ddg", "twitter", "wikipedia-km"
         ]
       }
@@ -561,16 +591,41 @@
         ]
       }
     },
     "ru": {
       "default": {
         "visibleDefaultEngines": [
           "yandex", "google", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
         ]
+      },
+      "RU": {
+        "visibleDefaultEngines": [
+          "yandex", "google-nocodes", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
+        ]
+      },
+      "BY": {
+        "visibleDefaultEngines": [
+          "yandex", "google-nocodes", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
+        ]
+      },
+      "KZ": {
+        "visibleDefaultEngines": [
+          "yandex", "google-nocodes", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
+        ]
+      },
+      "TR": {
+        "visibleDefaultEngines": [
+          "yandex", "google-nocodes", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
+        ]
+      },
+      "UA": {
+        "visibleDefaultEngines": [
+          "yandex", "google-nocodes", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
+        ]
       }
     },
     "si": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo", "amazondotcom", "ddg", "wikipedia-si"
         ]
       }
@@ -645,23 +700,73 @@
         ]
       }
     },
     "tr": {
       "default": {
         "visibleDefaultEngines": [
           "yandex-tr", "google", "ddg", "twitter", "wikipedia-tr"
         ]
+      },
+      "TR": {
+        "visibleDefaultEngines": [
+          "yandex-tr", "google-nocodes", "ddg", "twitter", "wikipedia-tr"
+        ]
+      },
+      "BY": {
+        "visibleDefaultEngines": [
+          "yandex-tr", "google-nocodes", "ddg", "twitter", "wikipedia-tr"
+        ]
+      },
+      "KZ": {
+        "visibleDefaultEngines": [
+          "yandex-tr", "google-nocodes", "ddg", "twitter", "wikipedia-tr"
+        ]
+      },
+      "RU": {
+        "visibleDefaultEngines": [
+          "yandex-tr", "google-nocodes", "ddg", "twitter", "wikipedia-tr"
+        ]
+      },
+      "UA": {
+        "visibleDefaultEngines": [
+          "yandex-tr", "google-nocodes", "ddg", "twitter", "wikipedia-tr"
+        ]
       }
     },
     "uk": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yandex", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
         ]
+      },
+      "UA": {
+        "visibleDefaultEngines": [
+          "google-nocodes", "yandex", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
+        ]
+      },
+      "TR": {
+        "visibleDefaultEngines": [
+          "google-nocodes", "yandex", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
+        ]
+      },
+      "BY": {
+        "visibleDefaultEngines": [
+          "google-nocodes", "yandex", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
+        ]
+      },
+      "KZ": {
+        "visibleDefaultEngines": [
+          "google-nocodes", "yandex", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
+        ]
+      },
+      "RU": {
+        "visibleDefaultEngines": [
+          "google-nocodes", "yandex", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
+        ]
       }
     },
     "ur": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yahoo", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
         ]
       }
@@ -701,12 +806,22 @@
         ]
       }
     },
     "zh-TW": {
       "default": {
         "visibleDefaultEngines": [
           "yahoo-zh-TW", "google", "ddg", "findbook-zh-TW", "wikipedia-zh-TW", "yahoo-zh-TW-HK", "yahoo-bid-zh-TW", "yahoo-answer-zh-TW"
         ]
+      },
+      "TW": {
+        "visibleDefaultEngines": [
+          "yahoo-zh-TW", "google-nocodes", "ddg", "findbook-zh-TW", "wikipedia-zh-TW", "yahoo-zh-TW-HK", "yahoo-bid-zh-TW", "yahoo-answer-zh-TW"
+        ]
+      },
+      "HK": {
+        "visibleDefaultEngines": [
+          "yahoo-zh-TW-HK", "google-nocodes", "ddg", "findbook-zh-TW", "wikipedia-zh-TW", "yahoo-zh-TW", "yahoo-bid-zh-TW", "yahoo-answer-zh-TW"
+        ]
       }
     }
   }
 }
--- a/build/build-clang/build-clang.py
+++ b/build/build-clang/build-clang.py
@@ -8,18 +8,20 @@ import os.path
 import shutil
 import subprocess
 import platform
 import json
 import argparse
 import tempfile
 import glob
 import errno
+import re
 from contextlib import contextmanager
 import sys
+import which
 
 DEBUG = os.getenv("DEBUG")
 
 
 def symlink(source, link_name):
     os_symlink = getattr(os, "symlink", None)
     if callable(os_symlink):
         os_symlink(source, link_name)
@@ -72,17 +74,20 @@ def updated_env(env):
     os.environ.update(old_env)
 
 
 def build_tar_package(tar, name, base, directory):
     name = os.path.realpath(name)
     # On Windows, we have to convert this into an msys path so that tar can
     # understand it.
     if is_windows():
-        name = name.replace('\\', '/').replace('c:', '/c')
+        name = name.replace('\\', '/')
+        def f(match):
+            return '/' + match.group(1).lower()
+        name = re.sub(r'^([A-Z]):', f, name)
     run_in(base, [tar,
                   "-c",
                   "-%s" % ("J" if ".xz" in name else "j"),
                   "-f",
                   name, directory])
 
 
 def copy_dir_contents(src, dest):
@@ -128,21 +133,21 @@ def install_libgcc(gcc_dir, clang_dir):
     clang_lib_dir = os.path.join(clang_dir, "lib")
     copy_dir_contents(libgcc_dir, clang_lib_dir)
     include_dir = os.path.join(gcc_dir, "include")
     clang_include_dir = os.path.join(clang_dir, "include")
     copy_dir_contents(include_dir, clang_include_dir)
 
 
 def svn_co(source_dir, url, directory, revision):
-    run_in(source_dir, ["svn", "co", "-r", revision, url, directory])
+    run_in(source_dir, ["svn", "co", "-q", "-r", revision, url, directory])
 
 
 def svn_update(directory, revision):
-    run_in(directory, ["svn", "update", "-r", revision])
+    run_in(directory, ["svn", "update", "-q", "-r", revision])
 
 
 def get_platform():
     p = platform.system()
     if p == "Darwin":
         return "macosx64"
     elif p == "Linux":
         if platform.architecture() == "AMD64":
@@ -177,43 +182,72 @@ def build_one_stage(cc, cxx, src_dir, st
 
     build_dir = stage_dir + "/build"
     inst_dir = stage_dir + "/clang"
 
     run_cmake = True
     if os.path.exists(build_dir + "/build.ninja"):
         run_cmake = False
 
+    # cmake doesn't deal well with backslashes in paths.
+    def slashify_path(path):
+        return path.replace('\\', '/')
+
     cmake_args = ["-GNinja",
-                  "-DCMAKE_C_COMPILER=%s" % cc[0],
-                  "-DCMAKE_CXX_COMPILER=%s" % cxx[0],
+                  "-DCMAKE_C_COMPILER=%s" % slashify_path(cc[0]),
+                  "-DCMAKE_CXX_COMPILER=%s" % slashify_path(cxx[0]),
+                  "-DCMAKE_ASM_COMPILER=%s" % slashify_path(cc[0]),
                   "-DCMAKE_C_FLAGS=%s" % ' '.join(cc[1:]),
                   "-DCMAKE_CXX_FLAGS=%s" % ' '.join(cxx[1:]),
                   "-DCMAKE_BUILD_TYPE=%s" % build_type,
                   "-DLLVM_TARGETS_TO_BUILD=X86;ARM",
                   "-DLLVM_ENABLE_ASSERTIONS=%s" % ("ON" if assertions else "OFF"),
-                  "-DPYTHON_EXECUTABLE=%s" % python_path,
+                  "-DPYTHON_EXECUTABLE=%s" % slashify_path(python_path),
                   "-DCMAKE_INSTALL_PREFIX=%s" % inst_dir,
                   "-DLLVM_TOOL_LIBCXX_BUILD=%s" % ("ON" if build_libcxx else "OFF"),
                   "-DLIBCXX_LIBCPPABI_VERSION=\"\"",
                   src_dir];
     build_package(build_dir, run_cmake, cmake_args)
 
     if is_linux():
         install_libgcc(gcc_dir, inst_dir)
 
 
+def get_compiler(config, key):
+    if key not in config:
+        raise ValueError("Config file needs to set %s" % key)
+
+    f = config[key]
+    if os.path.isabs(f):
+        if not os.path.exists(f):
+            raise ValueError("%s must point to an existing path" % key)
+        return f
+
+    # Assume that we have the name of some program that should be on PATH.
+    try:
+        return which.which(f)
+    except which.WhichError:
+        raise ValueError("%s not found on PATH" % f)
+
 if __name__ == "__main__":
     # The directories end up in the debug info, so the easy way of getting
     # a reproducible build is to run it in a know absolute directory.
     # We use a directory in /builds/slave because the mozilla infrastructure
     # cleans it up automatically.
     base_dir = "/builds/slave/moz-toolchain"
     if is_windows():
-        base_dir = "c:%s" % base_dir
+        # TODO: Because Windows taskcluster builds are run with distinct
+        # user IDs for each job, we can't store things in some globally
+        # accessible directory: one job will run, checkout LLVM to that
+        # directory, and then if another job runs, the new user won't be
+        # able to access the previously-checked out code--or be able to
+        # delete it.  So on Windows, we build in the task-specific home
+        # directory; we will eventually add -fdebug-prefix-map options
+        # to the LLVM build to bring back reproducibility.
+        base_dir = os.path.join(os.getcwd(), 'llvm-sources')
 
     source_dir = base_dir + "/src"
     build_dir = base_dir + "/build"
 
     llvm_source_dir = source_dir + "/llvm"
     clang_source_dir = source_dir + "/clang"
     compiler_rt_source_dir = source_dir + "/compiler-rt"
     libcxx_source_dir = source_dir + "/libcxx"
@@ -279,30 +313,18 @@ if __name__ == "__main__":
     python_path = config["python_path"]
     gcc_dir = None
     if "gcc_dir" in config:
         gcc_dir = config["gcc_dir"]
         if not os.path.exists(gcc_dir):
             raise ValueError("gcc_dir must point to an existing path")
     if is_linux() and gcc_dir is None:
         raise ValueError("Config file needs to set gcc_dir")
-    cc = None
-    if "cc" in config:
-        cc = config["cc"]
-        if not os.path.exists(cc):
-            raise ValueError("cc must point to an existing path")
-    else:
-        raise ValueError("Config file needs to set cc")
-    cxx = None
-    if "cxx" in config:
-        cxx = config["cxx"]
-        if not os.path.exists(cxx):
-            raise ValueError("cxx must point to an existing path")
-    else:
-        raise ValueError("Config file needs to set cxx")
+    cc = get_compiler(config, "cc")
+    cxx = get_compiler(config, "cxx")
 
     if not os.path.exists(source_dir):
         os.makedirs(source_dir)
         svn_co(source_dir, llvm_repo, llvm_source_dir, llvm_revision)
         svn_co(source_dir, clang_repo, clang_source_dir, llvm_revision)
         svn_co(source_dir, compiler_repo, compiler_rt_source_dir, llvm_revision)
         svn_co(source_dir, libcxx_repo, libcxx_source_dir, llvm_revision)
         if libcxxabi_repo:
@@ -357,18 +379,21 @@ if __name__ == "__main__":
 
         if os.environ.has_key('LD_LIBRARY_PATH'):
             os.environ['LD_LIBRARY_PATH'] = '%s/lib64/:%s' % (gcc_dir, os.environ['LD_LIBRARY_PATH']);
         else:
             os.environ['LD_LIBRARY_PATH'] = '%s/lib64/' % gcc_dir
     elif is_windows():
         extra_cflags = []
         extra_cxxflags = []
+        # clang-cl would like to figure out what it's supposed to be emulating
+        # by looking at an MSVC install, but we don't really have that here.
+        # Force things on.
         extra_cflags2 = []
-        extra_cxxflags2 = []
+        extra_cxxflags2 = ['-fms-compatibility-version=19.00.23918', '-Xclang', '-std=c++14']
 
     build_one_stage(
         [cc] + extra_cflags,
         [cxx] + extra_cxxflags,
         llvm_source_dir, stage1_dir, build_libcxx,
         build_type, assertions, python_path, gcc_dir)
 
     if stages > 1:
--- a/build/build-clang/clang-static-analysis-win32.json
+++ b/build/build-clang/clang-static-analysis-win32.json
@@ -1,16 +1,16 @@
 {
-    "llvm_revision": "262971",
+    "llvm_revision": "283955",
     "stages": "3",
     "build_libcxx": false,
     "build_type": "Release",
     "assertions": false,
     "llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
     "clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
     "compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/trunk",
     "libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
     "python_path": "c:/mozilla-build/python/python.exe",
-    "cc": "c:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/BIN/amd64_x86/cl.exe",
-    "cxx": "c:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/BIN/amd64_x86/cl.exe",
+    "cc": "cl.exe",
+    "cxx": "cl.exe",
     "patches": {
     }
 }
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -206,17 +206,17 @@ class RemoteAutomation(Automation):
             print "MOZ_UPLOAD_DIR not defined; tombstone check skipped"
 
     def checkForCrashes(self, directory, symbolsPath):
         self.checkForANRs()
         self.checkForTombstones()
 
         logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters)
 
-        javaException = mozcrash.check_for_java_exception(logcat)
+        javaException = mozcrash.check_for_java_exception(logcat, test_name=self.lastTestSeen)
         if javaException:
             return True
 
         # If crash reporting is disabled (MOZ_CRASHREPORTER!=1), we can't say
         # anything.
         if not self.CRASHREPORTER:
             return False
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -8759,36 +8759,31 @@ nsDocShell::RestoreFromHistory()
     newCv->SetMinFontSize(minFontSize);
     newCv->SetTextZoom(textZoom);
     newCv->SetFullZoom(pageZoom);
     newCv->SetOverrideDPPX(overrideDPPX);
     newCv->SetAuthorStyleDisabled(styleDisabled);
   }
 
   nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
-  uint32_t parentSuspendCount = 0;
   if (document) {
     RefPtr<nsDocShell> parent = GetParentDocshell();
     if (parent) {
       nsCOMPtr<nsIDocument> d = parent->GetDocument();
       if (d) {
         if (d->EventHandlingSuppressed()) {
           document->SuppressEventHandling(nsIDocument::eEvents,
                                           d->EventHandlingSuppressed());
         }
 
         // Ick, it'd be nicer to not rewalk all of the subdocs here.
         if (d->AnimationsPaused()) {
           document->SuppressEventHandling(nsIDocument::eAnimationsOnly,
                                           d->AnimationsPaused());
         }
-
-        if (nsCOMPtr<nsPIDOMWindowOuter> parentWindow = d->GetWindow()) {
-          parentSuspendCount = parentWindow->TimeoutSuspendCount();
-        }
       }
     }
 
     // Use the uri from the mLSHE we had when we entered this function
     // (which need not match the document's URI if anchors are involved),
     // since that's the history entry we're loading.  Note that if we use
     // origLSHE we don't have to worry about whether the entry in question
     // is still mLSHE or whether it's now mOSHE.
@@ -8915,26 +8910,26 @@ nsDocShell::RestoreFromHistory()
                             rootViewSibling,
                             rootViewSibling ? true : false);
 
       NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling,
                    "error in InsertChild");
     }
   }
 
+  nsCOMPtr<nsPIDOMWindowInner> privWinInner = privWin->GetCurrentInnerWindow();
+
   // If parent is suspended, increase suspension count.
   // This can't be done as early as event suppression since this
   // depends on docshell tree.
-  if (parentSuspendCount) {
-    privWin->SuspendTimeouts(parentSuspendCount, false);
-  }
+  privWinInner->SyncStateFromParentWindow();
 
   // Now that all of the child docshells have been put into place, we can
   // restart the timers for the window and all of the child frames.
-  privWin->ResumeTimeouts();
+  privWinInner->Resume();
 
   // Restore the refresh URI list.  The refresh timers will be restarted
   // when EndPageLoad() is called.
   mRefreshURIList = refreshURIList;
 
   // Meta-refresh timers have been restarted for this shell, but not
   // for our children.  Walk the child shells and restart their timers.
   nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2274,28 +2274,34 @@ nsDOMWindowUtils::GetCurrentInnerWindowI
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SuspendTimeouts()
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
-  window->SuspendTimeouts(1, true, false);
+  nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow();
+  NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE);
+
+  inner->Suspend();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::ResumeTimeouts()
 {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
-  window->ResumeTimeouts(true, false);
+  nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow();
+  NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE);
+
+  inner->Resume();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetLayerManagerType(nsAString& aType)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -8191,18 +8191,23 @@ nsDocument::EnumerateSubDocuments(nsSubD
 
 bool
 nsDocument::CanSavePresentation(nsIRequest *aNewRequest)
 {
   if (EventHandlingSuppressed()) {
     return false;
   }
 
+  // Do not allow suspended windows to be placed in the
+  // bfcache.  This method is also used to verify a document
+  // coming out of the bfcache is ok to restore, though.  So
+  // we only want to block suspend windows that aren't also
+  // frozen.
   nsPIDOMWindowInner* win = GetInnerWindow();
-  if (win && win->TimeoutSuspendCount()) {
+  if (win && win->IsSuspended() && !win->IsFrozen()) {
     return false;
   }
 
   // Check our event listener manager for unload/beforeunload listeners.
   nsCOMPtr<EventTarget> piTarget = do_QueryInterface(mScriptGlobalObject);
   if (piTarget) {
     EventListenerManager* manager = piTarget->GetExistingListenerManager();
     if (manager && manager->HasUnloadListeners()) {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1177,17 +1177,16 @@ NewOuterWindowProxy(JSContext *cx, JS::H
 //*****************************************************************************
 
 nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
   : nsPIDOMWindow<nsISupports>(aOuterWindow ? aOuterWindow->AsOuter() : nullptr),
     mIdleFuzzFactor(0),
     mIdleCallbackIndex(-1),
     mCurrentlyIdle(false),
     mAddActiveEventFuzzTime(true),
-    mIsFrozen(false),
     mFullScreen(false),
     mFullscreenMode(false),
     mIsClosed(false),
     mInClose(false),
     mHavePendingClose(false),
     mHadOriginalOpener(false),
     mOriginalOpenerWasSecureContext(false),
     mIsPopupSpam(false),
@@ -1208,17 +1207,18 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
 #ifdef MOZ_GAMEPAD
     mHasSeenGamepadInput(false),
 #endif
     mNotifiedIDDestroyed(false),
     mAllowScriptsToClose(false),
     mTimeoutInsertionPoint(nullptr),
     mTimeoutPublicIdCounter(1),
     mTimeoutFiringDepth(0),
-    mTimeoutsSuspendDepth(0),
+    mSuspendDepth(0),
+    mFreezeDepth(0),
     mFocusMethod(0),
     mSerial(0),
 #ifdef DEBUG
     mSetOpenerWindowCalled(false),
 #endif
 #ifdef MOZ_B2G
     mNetworkUploadObserverEnabled(false),
     mNetworkDownloadObserverEnabled(false),
@@ -1255,19 +1255,18 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
         // events. Use a strong reference.
         os->AddObserver(mObserver, "dom-storage2-changed", false);
       }
 
       Preferences::AddStrongObserver(mObserver, "intl.accept_languages");
     }
   } else {
     // |this| is an outer window. Outer windows start out frozen and
-    // remain frozen until they get an inner window, so freeze this
-    // outer window here.
-    Freeze();
+    // remain frozen until they get an inner window.
+    MOZ_ASSERT(IsFrozen());
 
     // As an outer window, we may be the root of a constellation. This initial
     // static constellation may be overridden as this window is given a parent
     // window or an opener.
     mStaticConstellation = WindowID();
   }
 
   // We could have failed the first time through trying
@@ -2295,17 +2294,17 @@ NS_DEFINE_STATIC_IID_ACCESSOR(WindowStat
 
 WindowStateHolder::WindowStateHolder(nsGlobalWindow* aWindow)
   : mInnerWindow(aWindow),
     mInnerWindowReflector(RootingCx(), aWindow->GetWrapper())
 {
   NS_PRECONDITION(aWindow, "null window");
   NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
 
-  aWindow->SuspendTimeouts();
+  aWindow->Suspend();
 
   // When a global goes into the bfcache, we disable script.
   xpc::Scriptability::Get(mInnerWindowReflector).SetDocShellAllowsScript(false);
 }
 
 WindowStateHolder::~WindowStateHolder()
 {
   if (mInnerWindow) {
@@ -2545,23 +2544,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
                                                     aForceReuseInnerWindow);
   }
 
   NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows");
 
   // Bail out early if we're in process of closing down the window.
   NS_ENSURE_STATE(!mCleanedUp);
 
-  if (IsFrozen()) {
-    // This outer is now getting its first inner, thaw the outer now
-    // that it's ready and is getting an inner window.
-
-    Thaw();
-  }
-
   NS_ASSERTION(!AsOuter()->GetCurrentInnerWindow() ||
                AsOuter()->GetCurrentInnerWindow()->GetExtantDoc() == mDoc,
                "Uh, mDoc doesn't match the current inner window "
                "document!");
 
   bool wouldReuseInnerWindow = WouldReuseInnerWindow(aDocument);
   if (aForceReuseInnerWindow &&
       !wouldReuseInnerWindow &&
@@ -2695,44 +2687,43 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       if (thisChrome) {
         newInnerWindow = nsGlobalChromeWindow::Create(this);
       } else if (mIsModalContentWindow) {
         newInnerWindow = nsGlobalModalWindow::Create(this);
       } else {
         newInnerWindow = nsGlobalWindow::Create(this);
       }
 
-      // Freeze the outer window and null out the inner window so
-      // that initializing classes on the new inner doesn't end up
-      // reaching into the old inner window for classes etc.
+      // The outer window is automatically treated as frozen when we
+      // null out the inner window. As a result, initializing classes
+      // on the new inner won't end up reaching into the old inner
+      // window for classes etc.
       //
       // [This happens with Object.prototype when XPConnect creates
       // a temporary global while initializing classes; the reason
       // being that xpconnect creates the temp global w/o a parent
       // and proto, which makes the JS engine look up classes in
       // cx->globalObject, i.e. this outer window].
 
       mInnerWindow = nullptr;
 
-      Freeze();
       mCreatingInnerWindow = true;
       // Every script context we are initialized with must create a
       // new global.
       rv = CreateNativeGlobalForInner(cx, newInnerWindow,
                                       aDocument->GetDocumentURI(),
                                       aDocument->NodePrincipal(),
                                       &newInnerGlobal,
                                       ComputeIsSecureContext(aDocument));
       NS_ASSERTION(NS_SUCCEEDED(rv) && newInnerGlobal &&
                    newInnerWindow->GetWrapperPreserveColor() == newInnerGlobal,
                    "Failed to get script global");
 
       mCreatingInnerWindow = false;
       createdInnerWindow = true;
-      Thaw();
 
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     if (currentInner && currentInner->GetWrapperPreserveColor()) {
       if (oldDoc == aDocument) {
         // Move the navigator from the old inner window to the new one since
         // this is a document.write. This is safe from a same-origin point of
@@ -2853,23 +2844,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
     JS::Rooted<JSObject*> rootedJSObject(cx, GetWrapperPreserveColor());
     JS::Rooted<JSObject*> proto1(cx), proto2(cx);
     JS_GetPrototype(cx, rootedJSObject, &proto1);
     JS_GetPrototype(cx, newInnerGlobal, &proto2);
     NS_ASSERTION(proto1 == proto2,
                  "outer and inner globals should have the same prototype");
 #endif
 
-    nsCOMPtr<Element> frame = AsOuter()->GetFrameElementInternal();
-    if (frame) {
-      nsPIDOMWindowOuter* parentWindow = frame->OwnerDoc()->GetWindow();
-      if (parentWindow && parentWindow->TimeoutSuspendCount()) {
-        SuspendTimeouts(parentWindow->TimeoutSuspendCount());
-      }
-    }
+    mInnerWindow->SyncStateFromParentWindow();
   }
 
   // Add an extra ref in case we release mContext during GC.
   nsCOMPtr<nsIScriptContext> kungFuDeathGrip(mContext);
 
   aDocument->SetScriptGlobalObject(newInnerWindow);
 
   if (!aState) {
@@ -3871,16 +3856,46 @@ nsPIDOMWindowInner::CreatePerformanceObj
 }
 
 bool
 nsPIDOMWindowInner::IsSecureContext() const
 {
   return nsGlobalWindow::Cast(this)->IsSecureContext();
 }
 
+void
+nsPIDOMWindowInner::Suspend()
+{
+  nsGlobalWindow::Cast(this)->Suspend();
+}
+
+void
+nsPIDOMWindowInner::Resume()
+{
+  nsGlobalWindow::Cast(this)->Resume();
+}
+
+void
+nsPIDOMWindowInner::Freeze()
+{
+  nsGlobalWindow::Cast(this)->Freeze();
+}
+
+void
+nsPIDOMWindowInner::Thaw()
+{
+  nsGlobalWindow::Cast(this)->Thaw();
+}
+
+void
+nsPIDOMWindowInner::SyncStateFromParentWindow()
+{
+  nsGlobalWindow::Cast(this)->SyncStateFromParentWindow();
+}
+
 SuspendTypes
 nsPIDOMWindowOuter::GetMediaSuspend() const
 {
   if (IsInnerWindow()) {
     return mOuterWindow->GetMediaSuspend();
   }
 
   return mMediaSuspend;
@@ -8802,114 +8817,61 @@ nsGlobalWindow::EnterModalState()
 
   if (topWin->mModalStateDepth == 0) {
     NS_ASSERTION(!topWin->mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
 
     topWin->mSuspendedDoc = topDoc;
     if (topDoc) {
       topDoc->SuppressEventHandling(nsIDocument::eAnimationsOnly);
     }
+
+    nsGlobalWindow* inner = topWin->GetCurrentInnerWindowInternal();
+    if (inner) {
+      topWin->GetCurrentInnerWindowInternal()->Suspend();
+    }
   }
   topWin->mModalStateDepth++;
 }
 
-// static
-void
-nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
-                                            nsGlobalWindow *aWindow)
-{
-  nsGlobalWindow *inner;
-
-  // Return early if we're frozen or have no inner window.
-  if (!(inner = aWindow->GetCurrentInnerWindowInternal()) ||
-      inner->IsFrozen()) {
-    return;
-  }
-
-  inner->RunTimeout(nullptr);
-
-  // Check again if we're frozen since running pending timeouts
-  // could've frozen us.
-  if (inner->IsFrozen()) {
-    return;
-  }
-
-  nsCOMPtr<nsIDOMWindowCollection> frames = aWindow->GetFrames();
-  if (!frames) {
-    return;
-  }
-
-  uint32_t length = 0;
-  frames->GetLength(&length);
-
-  for (uint32_t i = 0; i < length && aTopWindow->mModalStateDepth == 0; i++) {
-    nsCOMPtr<mozIDOMWindowProxy> child;
-    frames->Item(i, getter_AddRefs(child));
-
-    if (!child) {
-      return;
-    }
-
-    auto* childWin = nsGlobalWindow::Cast(child);
-
-    RunPendingTimeoutsRecursive(aTopWindow, childWin);
-  }
-}
-
-class nsPendingTimeoutRunner : public Runnable
-{
-public:
-  explicit nsPendingTimeoutRunner(nsGlobalWindow* aWindow)
-    : mWindow(aWindow)
-  {
-    NS_ASSERTION(mWindow, "mWindow is null.");
-  }
-
-  NS_IMETHOD Run() override
-  {
-    nsGlobalWindow::RunPendingTimeoutsRecursive(mWindow, mWindow);
-
-    return NS_OK;
-  }
-
-private:
-  RefPtr<nsGlobalWindow> mWindow;
-};
-
 void
 nsGlobalWindow::LeaveModalState()
 {
   MOZ_ASSERT(IsOuterWindow(), "Modal state is maintained on outer windows");
 
   nsGlobalWindow* topWin = GetScriptableTopInternal();
 
   if (!topWin) {
     NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");
     return;
   }
 
+  MOZ_ASSERT(topWin->mModalStateDepth != 0);
+  MOZ_ASSERT(IsSuspended());
+  MOZ_ASSERT(topWin->IsSuspended());
   topWin->mModalStateDepth--;
 
+  nsGlobalWindow* inner = topWin->GetCurrentInnerWindowInternal();
+
   if (topWin->mModalStateDepth == 0) {
-    nsCOMPtr<nsIRunnable> runner = new nsPendingTimeoutRunner(topWin);
-    if (NS_FAILED(NS_DispatchToCurrentThread(runner)))
-      NS_WARNING("failed to dispatch pending timeout runnable");
+    if (inner) {
+      inner->Resume();
+    }
 
     if (topWin->mSuspendedDoc) {
       nsCOMPtr<nsIDocument> currentDoc = topWin->GetExtantDoc();
       topWin->mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eAnimationsOnly,
                                                                   currentDoc == topWin->mSuspendedDoc);
       topWin->mSuspendedDoc = nullptr;
     }
   }
 
   // Remember the time of the last dialog quit.
-  nsGlobalWindow *inner = topWin->GetCurrentInnerWindowInternal();
-  if (inner)
+  if (inner) {
     inner->mLastDialogQuitTime = TimeStamp::Now();
+  }
 
   if (topWin->mModalStateDepth == 0) {
     RefPtr<Event> event = NS_NewDOMEvent(inner, nullptr, nullptr);
     event->InitEvent(NS_LITERAL_STRING("endmodalstate"), true, false);
     event->SetTrusted(true);
     event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
     bool dummy;
     topWin->DispatchEvent(event, &dummy);
@@ -11699,16 +11661,352 @@ nsGlobalWindow::CloneStorageEvent(const 
   MOZ_ASSERT(storage->IsForkOf(storageArea));
 
   dict.mStorageArea = storage;
 
   RefPtr<StorageEvent> event = StorageEvent::Constructor(this, aType, dict);
   return event.forget();
 }
 
+void
+nsGlobalWindow::Suspend()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(IsInnerWindow());
+
+  // All children are also suspended.  This ensure mSuspendDepth is
+  // set properly and the timers are properly canceled for each child.
+  CallOnChildren(&nsGlobalWindow::Suspend);
+
+  mSuspendDepth += 1;
+  if (mSuspendDepth != 1) {
+    return;
+  }
+
+  nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
+  if (ac) {
+    for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
+      ac->RemoveWindowListener(mEnabledSensors[i], this);
+  }
+  DisableGamepadUpdates();
+  DisableVRUpdates();
+
+  mozilla::dom::workers::SuspendWorkersForWindow(AsInner());
+
+  for (nsTimeout* t = mTimeouts.getFirst(); t; t = t->getNext()) {
+    // Leave the timers with the current time remaining.  This will
+    // cause the timers to potentially fire when the window is
+    // Resume()'d.  Time effectively passes while suspended.
+
+    // Drop the XPCOM timer; we'll reschedule when restoring the state.
+    if (t->mTimer) {
+      t->mTimer->Cancel();
+      t->mTimer = nullptr;
+
+      // Drop the reference that the timer's closure had on this timeout, we'll
+      // add it back in Resume().
+      t->Release();
+    }
+  }
+
+  // Suspend all of the AudioContexts for this window
+  for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
+    ErrorResult dummy;
+    RefPtr<Promise> d = mAudioContexts[i]->Suspend(dummy);
+  }
+}
+
+void
+nsGlobalWindow::Resume()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(IsInnerWindow());
+
+  // Resume all children.  This restores timers recursively canceled
+  // in Suspend() and ensures all children have the correct mSuspendDepth.
+  CallOnChildren(&nsGlobalWindow::Resume);
+
+  MOZ_ASSERT(mSuspendDepth != 0);
+  mSuspendDepth -= 1;
+  if (mSuspendDepth != 0) {
+    return;
+  }
+
+  // We should not be able to resume a frozen window.  It must be Thaw()'d first.
+  MOZ_ASSERT(mFreezeDepth == 0);
+
+  nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
+  if (ac) {
+    for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
+      ac->AddWindowListener(mEnabledSensors[i], this);
+  }
+  EnableGamepadUpdates();
+  EnableVRUpdates();
+
+  // Resume all of the AudioContexts for this window
+  for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
+    ErrorResult dummy;
+    RefPtr<Promise> d = mAudioContexts[i]->Resume(dummy);
+  }
+
+  TimeStamp now = TimeStamp::Now();
+  DebugOnly<bool> _seenDummyTimeout = false;
+
+  for (nsTimeout* t = mTimeouts.getFirst(); t; t = t->getNext()) {
+    // There's a chance we're being called with RunTimeout on the stack in which
+    // case we have a dummy timeout in the list that *must not* be resumed. It
+    // can be identified by a null mWindow.
+    if (!t->mWindow) {
+      NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
+      _seenDummyTimeout = true;
+      continue;
+    }
+
+    MOZ_ASSERT(!t->mTimer);
+
+    // The timeout mWhen is set to the absolute time when the timer should
+    // fire.  Recalculate the delay from now until that deadline.  If the
+    // the deadline has already passed or falls within our minimum delay
+    // deadline, then clamp the resulting value to the minimum delay.  The
+    // mWhen will remain at its absolute time, but we won't fire the OS
+    // timer until our calculated delay has passed.
+    int32_t remaining = 0;
+    if (t->mWhen > now) {
+      remaining = static_cast<int32_t>((t->mWhen - now).ToMilliseconds());
+    }
+    uint32_t delay = std::max(remaining, DOMMinTimeoutValue());
+
+    t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
+    if (!t->mTimer) {
+      t->remove();
+      continue;
+    }
+
+    nsresult rv = t->InitTimer(delay);
+    if (NS_FAILED(rv)) {
+      t->mTimer = nullptr;
+      t->remove();
+      continue;
+    }
+
+    // Add a reference for the new timer's closure.
+    t->AddRef();
+  }
+
+  // Resume all of the workers for this window.  We must do this
+  // after timeouts since workers may have queued events that can trigger
+  // a setTimeout().
+  mozilla::dom::workers::ResumeWorkersForWindow(AsInner());
+}
+
+bool
+nsGlobalWindow::IsSuspended() const
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // No inner means we are effectively suspended
+  if (IsOuterWindow()) {
+    if (!mInnerWindow) {
+      return true;
+    }
+    return mInnerWindow->IsSuspended();
+  }
+  return mSuspendDepth != 0;
+}
+
+void
+nsGlobalWindow::Freeze()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(IsInnerWindow());
+  Suspend();
+  FreezeInternal();
+}
+
+void
+nsGlobalWindow::FreezeInternal()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(IsSuspended());
+
+  CallOnChildren(&nsGlobalWindow::FreezeInternal);
+
+  mFreezeDepth += 1;
+  MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
+  if (mFreezeDepth != 1) {
+    return;
+  }
+
+  mozilla::dom::workers::FreezeWorkersForWindow(AsInner());
+
+  TimeStamp now = TimeStamp::Now();
+  for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
+    // Save the current remaining time for this timeout.  We will
+    // re-apply it when the window is Thaw()'d.  This effectively
+    // shifts timers to the right as if time does not pass while
+    // the window is frozen.
+    if (t->mWhen > now) {
+      t->mTimeRemaining = t->mWhen - now;
+    } else {
+      t->mTimeRemaining = TimeDuration(0);
+    }
+
+    // Since we are suspended there should be no OS timer set for
+    // this timeout entry.
+    MOZ_ASSERT(!t->mTimer);
+  }
+
+  NotifyDOMWindowFrozen(this);
+}
+
+void
+nsGlobalWindow::Thaw()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(IsInnerWindow());
+  ThawInternal();
+  Resume();
+}
+
+void
+nsGlobalWindow::ThawInternal()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(IsSuspended());
+
+  CallOnChildren(&nsGlobalWindow::ThawInternal);
+
+  MOZ_ASSERT(mFreezeDepth != 0);
+  mFreezeDepth -= 1;
+  MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
+  if (mFreezeDepth != 0) {
+    return;
+  }
+
+  TimeStamp now = TimeStamp::Now();
+  DebugOnly<bool> _seenDummyTimeout = false;
+
+  for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
+    // There's a chance we're being called with RunTimeout on the stack in which
+    // case we have a dummy timeout in the list that *must not* be resumed. It
+    // can be identified by a null mWindow.
+    if (!t->mWindow) {
+      NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
+      _seenDummyTimeout = true;
+      continue;
+    }
+
+    // Set mWhen back to the time when the timer is supposed to fire.
+    t->mWhen = now + t->mTimeRemaining;
+
+    MOZ_ASSERT(!t->mTimer);
+  }
+
+  mozilla::dom::workers::ThawWorkersForWindow(AsInner());
+
+  NotifyDOMWindowThawed(this);
+}
+
+bool
+nsGlobalWindow::IsFrozen() const
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // No inner means we are effectively frozen
+  if (IsOuterWindow()) {
+    if (!mInnerWindow) {
+      return true;
+    }
+    return mInnerWindow->IsFrozen();
+  }
+  bool frozen = mFreezeDepth != 0;
+  MOZ_ASSERT_IF(frozen, IsSuspended());
+  return frozen;
+}
+
+void
+nsGlobalWindow::SyncStateFromParentWindow()
+{
+  // This method should only be called on an inner window that has been
+  // assigned to an outer window already.
+  MOZ_ASSERT(IsInnerWindow());
+  nsPIDOMWindowOuter* outer = GetOuterWindow();
+  MOZ_ASSERT(outer);
+
+  // Attempt to find our parent windows.
+  nsCOMPtr<Element> frame = outer->GetFrameElementInternal();
+  nsPIDOMWindowOuter* parentOuter = frame ? frame->OwnerDoc()->GetWindow()
+                                          : nullptr;
+  nsGlobalWindow* parentInner =
+    parentOuter ? nsGlobalWindow::Cast(parentOuter->GetCurrentInnerWindow())
+                : nullptr;
+
+  // If our outer is in a modal state, but our parent is not in a modal
+  // state, then we must apply the suspend directly.  If our parent is
+  // in a modal state then we should get the suspend automatically
+  // via the parentSuspendDepth application below.
+  if ((!parentInner || !parentInner->IsInModalState()) && IsInModalState()) {
+    Suspend();
+  }
+
+  uint32_t parentFreezeDepth = parentInner ? parentInner->mFreezeDepth : 0;
+  uint32_t parentSuspendDepth = parentInner ? parentInner->mSuspendDepth : 0;
+
+  // Since every Freeze() calls Suspend(), the suspend count must
+  // be equal or greater to the freeze count.
+  MOZ_ASSERT(parentFreezeDepth <= parentSuspendDepth);
+
+  // First apply the Freeze() calls.
+  for (uint32_t i = 0; i < parentFreezeDepth; ++i) {
+    Freeze();
+  }
+
+  // Now apply only the number of Suspend() calls to reach the target
+  // suspend count after applying the Freeze() calls.
+  for (uint32_t i = 0; i < (parentSuspendDepth - parentFreezeDepth); ++i) {
+    Suspend();
+  }
+}
+
+template<typename Method>
+void
+nsGlobalWindow::CallOnChildren(Method aMethod)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
+  if (!docShell) {
+    return;
+  }
+
+  int32_t childCount = 0;
+  docShell->GetChildCount(&childCount);
+
+  for (int32_t i = 0; i < childCount; ++i) {
+    nsCOMPtr<nsIDocShellTreeItem> childShell;
+    docShell->GetChildAt(i, getter_AddRefs(childShell));
+    NS_ASSERTION(childShell, "null child shell");
+
+    nsCOMPtr<nsPIDOMWindowOuter> pWin = childShell->GetWindow();
+    if (!pWin) {
+      continue;
+    }
+
+    auto* win = nsGlobalWindow::Cast(pWin);
+    nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
+
+    // This is a bit hackish. Only freeze/suspend windows which are truly our
+    // subwindows.
+    nsCOMPtr<Element> frame = pWin->GetFrameElementInternal();
+    if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) {
+      continue;
+    }
+
+    (inner->*aMethod)();
+  }
+}
+
 nsresult
 nsGlobalWindow::FireDelayedDOMEvents()
 {
   FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED);
 
   for (uint32_t i = 0, len = mPendingStorageEvents.Length(); i < len; ++i) {
     Observe(mPendingStorageEvents[i], "dom-storage2-changed", nullptr);
   }
@@ -12158,46 +12456,48 @@ nsGlobalWindow::SetTimeoutOrInterval(nsI
   if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL) {
     // Don't allow timeouts less than DOMMinTimeoutValue() from
     // now...
     realInterval = std::max(realInterval, uint32_t(DOMMinTimeoutValue()));
   }
 
   TimeDuration delta = TimeDuration::FromMilliseconds(realInterval);
 
-  if (!IsFrozen() && !mTimeoutsSuspendDepth) {
-    // If we're not currently frozen, then we set timeout->mWhen to be the
-    // actual firing time of the timer (i.e., now + delta). We also actually
-    // create a timer and fire it off.
-
+  if (IsFrozen()) {
+    // If we are frozen simply set timeout->mTimeRemaining to be the
+    // "time remaining" in the timeout (i.e., the interval itself).  This
+    // will be used to create a new mWhen time when the window is thawed.
+    // The end effect is that time does not appear to pass for frozen windows.
+    timeout->mTimeRemaining = delta;
+  } else {
+    // Since we are not frozen we must set a precise mWhen target wakeup
+    // time.  Even if we are suspended we want to use this target time so
+    // that it appears time passes while suspended.
     timeout->mWhen = TimeStamp::Now() + delta;
+  }
+
+  // If we're not suspended, then set the timer.
+  if (!IsSuspended()) {
+    MOZ_ASSERT(!timeout->mWhen.IsNull());
 
     nsresult rv;
     timeout->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     RefPtr<nsTimeout> copy = timeout;
 
     rv = timeout->InitTimer(realInterval);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     // The timeout is now also held in the timer's closure.
     Unused << copy.forget();
-  } else {
-    // If we are frozen, however, then we instead simply set
-    // timeout->mTimeRemaining to be the "time remaining" in the timeout (i.e.,
-    // the interval itself). We don't create a timer for it, since that will
-    // happen when we are thawed and the timeout will then get a timer and run
-    // to completion.
-
-    timeout->mTimeRemaining = delta;
   }
 
   timeout->mWindow = this;
 
   if (!aIsInterval) {
     timeout->mNestingLevel = nestingLevel;
   }
 
@@ -12433,17 +12733,17 @@ nsGlobalWindow::RescheduleTimeout(nsTime
   // And make sure delay is nonnegative; that might happen if the timer
   // thread is firing our timers somewhat early or if they're taking a long
   // time to run the callback.
   if (delay < TimeDuration(0)) {
     delay = TimeDuration(0);
   }
 
   if (!aTimeout->mTimer) {
-    NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth,
+    NS_ASSERTION(IsFrozen() || IsSuspended(),
                  "How'd our timer end up null if we're not frozen or "
                  "suspended?");
 
     aTimeout->mTimeRemaining = delay;
     return true;
   }
 
   aTimeout->mWhen = currentNow + delay;
@@ -12472,19 +12772,17 @@ nsGlobalWindow::RescheduleTimeout(nsTime
   }
 
   return true;
 }
 
 void
 nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
 {
-  // If a modal dialog is open for this window, return early. Pending
-  // timeouts will run when the modal dialog is dismissed.
-  if (IsInModalState() || mTimeoutsSuspendDepth) {
+  if (IsSuspended()) {
     return;
   }
 
   NS_ASSERTION(IsInnerWindow(), "Timeout running on outer window!");
   NS_ASSERTION(!IsFrozen(), "Timeout running on a window in the bfcache!");
 
   nsTimeout *nextTimeout;
   nsTimeout *last_expired_timeout, *last_insertion_point;
@@ -12566,17 +12864,17 @@ nsGlobalWindow::RunTimeout(nsTimeout *aT
 
     if (timeout->mFiringDepth != firingDepth) {
       // We skip the timeout since it's on the list to run at another
       // depth.
 
       continue;
     }
 
-    if (mTimeoutsSuspendDepth) {
+    if (IsSuspended()) {
       // Some timer did suspend us. Make sure the
       // rest of the timers get executed later.
       timeout->mFiringDepth = 0;
       continue;
     }
 
     // The timeout is on the list to run at this depth, go ahead and
     // process it.
@@ -12667,17 +12965,17 @@ nsGlobalWindow::ClearTimeoutOrInterval(i
   }
 }
 
 nsresult nsGlobalWindow::ResetTimersForNonBackgroundWindow()
 {
   FORWARD_TO_INNER(ResetTimersForNonBackgroundWindow, (),
                    NS_ERROR_NOT_INITIALIZED);
 
-  if (IsFrozen() || mTimeoutsSuspendDepth) {
+  if (IsFrozen() || IsSuspended()) {
     return NS_OK;
   }
 
   TimeStamp now = TimeStamp::Now();
 
   // If mTimeoutInsertionPoint is non-null, we're in the middle of firing
   // timers and the timers we're planning to fire all come before
   // mTimeoutInsertionPoint; mTimeoutInsertionPoint itself is a dummy timeout
@@ -12806,17 +13104,17 @@ nsGlobalWindow::InsertTimeoutIntoList(ns
   // Start at mLastTimeout and go backwards.  Don't go further than
   // mTimeoutInsertionPoint, though.  This optimizes for the common case of
   // insertion at the end.
   nsTimeout* prevSibling;
   for (prevSibling = mTimeouts.getLast();
        prevSibling && prevSibling != mTimeoutInsertionPoint &&
          // This condition needs to match the one in SetTimeoutOrInterval that
          // determines whether to set mWhen or mTimeRemaining.
-         ((IsFrozen() || mTimeoutsSuspendDepth) ?
+         (IsFrozen() ?
           prevSibling->mTimeRemaining > aTimeout->mTimeRemaining :
           prevSibling->mWhen > aTimeout->mWhen);
        prevSibling = prevSibling->getPrevious()) {
     /* Do nothing; just searching */
   }
 
   // Now link in aTimeout after prevSibling.
   if (prevSibling) {
@@ -13048,226 +13346,16 @@ nsGlobalWindow::RestoreWindowState(nsISu
   inner->Thaw();
 
   holder->DidRestoreWindow();
 
   return NS_OK;
 }
 
 void
-nsGlobalWindow::SuspendTimeouts(uint32_t aIncrease,
-                                bool aFreezeChildren,
-                                bool aFreezeWorkers)
-{
-  FORWARD_TO_INNER_VOID(SuspendTimeouts,
-                        (aIncrease, aFreezeChildren, aFreezeWorkers));
-
-  bool suspended = (mTimeoutsSuspendDepth != 0);
-  mTimeoutsSuspendDepth += aIncrease;
-
-  if (!suspended) {
-    nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
-    if (ac) {
-      for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
-        ac->RemoveWindowListener(mEnabledSensors[i], this);
-    }
-    DisableGamepadUpdates();
-    DisableVRUpdates();
-
-    // Freeze or suspend all of the workers for this window.
-    if (aFreezeWorkers) {
-      mozilla::dom::workers::FreezeWorkersForWindow(AsInner());
-    } else {
-      mozilla::dom::workers::SuspendWorkersForWindow(AsInner());
-    }
-
-    TimeStamp now = TimeStamp::Now();
-    for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
-      // Set mTimeRemaining to be the time remaining for this timer.
-      if (t->mWhen > now)
-        t->mTimeRemaining = t->mWhen - now;
-      else
-        t->mTimeRemaining = TimeDuration(0);
-
-      // Drop the XPCOM timer; we'll reschedule when restoring the state.
-      if (t->mTimer) {
-        t->mTimer->Cancel();
-        t->mTimer = nullptr;
-
-        // Drop the reference that the timer's closure had on this timeout, we'll
-        // add it back in ResumeTimeouts. Note that it shouldn't matter that we're
-        // passing null for the context, since this shouldn't actually release this
-        // timeout.
-        t->Release();
-      }
-    }
-
-    // Suspend all of the AudioContexts for this window
-    for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
-      ErrorResult dummy;
-      RefPtr<Promise> d = mAudioContexts[i]->Suspend(dummy);
-    }
-  }
-
-  // Suspend our children as well.
-  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
-  if (docShell) {
-    int32_t childCount = 0;
-    docShell->GetChildCount(&childCount);
-
-    for (int32_t i = 0; i < childCount; ++i) {
-      nsCOMPtr<nsIDocShellTreeItem> childShell;
-      docShell->GetChildAt(i, getter_AddRefs(childShell));
-      NS_ASSERTION(childShell, "null child shell");
-
-      if (nsCOMPtr<nsPIDOMWindowOuter> pWin = childShell->GetWindow()) {
-        auto* win = nsGlobalWindow::Cast(pWin);
-        nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
-
-        // This is a bit hackish. Only freeze/suspend windows which are truly our
-        // subwindows.
-        nsCOMPtr<Element> frame = pWin->GetFrameElementInternal();
-        if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) {
-          continue;
-        }
-
-        win->SuspendTimeouts(aIncrease, aFreezeChildren, aFreezeWorkers);
-
-        if (inner && aFreezeChildren) {
-          inner->Freeze();
-        }
-      }
-    }
-  }
-}
-
-nsresult
-nsGlobalWindow::ResumeTimeouts(bool aThawChildren, bool aThawWorkers)
-{
-  FORWARD_TO_INNER(ResumeTimeouts, (aThawChildren, aThawWorkers),
-                   NS_ERROR_NOT_INITIALIZED);
-
-  NS_ASSERTION(mTimeoutsSuspendDepth, "Mismatched calls to ResumeTimeouts!");
-  --mTimeoutsSuspendDepth;
-  bool shouldResume = (mTimeoutsSuspendDepth == 0) && !mInnerObjectsFreed;
-  nsresult rv;
-
-  if (shouldResume) {
-    nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
-    if (ac) {
-      for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
-        ac->AddWindowListener(mEnabledSensors[i], this);
-    }
-    EnableGamepadUpdates();
-    EnableVRUpdates();
-
-    // Resume all of the AudioContexts for this window
-    for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
-      ErrorResult dummy;
-      RefPtr<Promise> d = mAudioContexts[i]->Resume(dummy);
-    }
-
-    // Restore all of the timeouts, using the stored time remaining
-    // (stored in timeout->mTimeRemaining).
-
-    TimeStamp now = TimeStamp::Now();
-
-#ifdef DEBUG
-    bool _seenDummyTimeout = false;
-#endif
-
-    for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
-      // There's a chance we're being called with RunTimeout on the stack in which
-      // case we have a dummy timeout in the list that *must not* be resumed. It
-      // can be identified by a null mWindow.
-      if (!t->mWindow) {
-#ifdef DEBUG
-        NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
-        _seenDummyTimeout = true;
-#endif
-        continue;
-      }
-
-      // XXXbz the combination of the way |delay| and |t->mWhen| are set here
-      // makes no sense.  Are we trying to impose that min timeout value or
-      // not???
-      uint32_t delay =
-        std::max(int32_t(t->mTimeRemaining.ToMilliseconds()),
-               DOMMinTimeoutValue());
-
-      // Set mWhen back to the time when the timer is supposed to
-      // fire.
-      t->mWhen = now + t->mTimeRemaining;
-
-      t->mTimer = do_CreateInstance("@mozilla.org/timer;1");
-      NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY);
-
-      rv = t->InitTimer(delay);
-      if (NS_FAILED(rv)) {
-        t->mTimer = nullptr;
-        return rv;
-      }
-
-      // Add a reference for the new timer's closure.
-      t->AddRef();
-    }
-
-    // Thaw or resume all of the workers for this window.  We must do this
-    // after timeouts since workers may have queued events that can trigger
-    // a setTimeout().
-    if (aThawWorkers) {
-      mozilla::dom::workers::ThawWorkersForWindow(AsInner());
-    } else {
-      mozilla::dom::workers::ResumeWorkersForWindow(AsInner());
-    }
-  }
-
-  // Resume our children as well.
-  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
-  if (docShell) {
-    int32_t childCount = 0;
-    docShell->GetChildCount(&childCount);
-
-    for (int32_t i = 0; i < childCount; ++i) {
-      nsCOMPtr<nsIDocShellTreeItem> childShell;
-      docShell->GetChildAt(i, getter_AddRefs(childShell));
-      NS_ASSERTION(childShell, "null child shell");
-
-      if (nsCOMPtr<nsPIDOMWindowOuter> pWin = childShell->GetWindow()) {
-        auto* win = nsGlobalWindow::Cast(pWin);
-        nsGlobalWindow* inner = win->GetCurrentInnerWindowInternal();
-
-        // This is a bit hackish. Only thaw/resume windows which are truly our
-        // subwindows.
-        nsCOMPtr<Element> frame = pWin->GetFrameElementInternal();
-        if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) {
-          continue;
-        }
-
-        if (inner && aThawChildren) {
-          inner->Thaw();
-        }
-
-        rv = win->ResumeTimeouts(aThawChildren, aThawWorkers);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-    }
-  }
-
-  return NS_OK;
-}
-
-uint32_t
-nsGlobalWindow::TimeoutSuspendCount()
-{
-  FORWARD_TO_INNER(TimeoutSuspendCount, (), 0);
-  return mTimeoutsSuspendDepth;
-}
-
-void
 nsGlobalWindow::EnableDeviceSensor(uint32_t aType)
 {
   MOZ_ASSERT(IsInnerWindow());
 
   bool alreadyEnabled = false;
   for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) {
     if (mEnabledSensors[i] == aType) {
       alreadyEnabled = true;
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -433,27 +433,26 @@ public:
   virtual void SetInitialPrincipalToSubject() override;
 
   virtual PopupControlState PushPopupControlState(PopupControlState state, bool aForce) const override;
   virtual void PopPopupControlState(PopupControlState state) const override;
   virtual PopupControlState GetPopupControlState() const override;
 
   virtual already_AddRefed<nsISupports> SaveWindowState() override;
   virtual nsresult RestoreWindowState(nsISupports *aState) override;
-  virtual void SuspendTimeouts(uint32_t aIncrease = 1,
-                               bool aFreezeChildren = true,
-                               bool aFreezeWorkers = true) override;
-  virtual nsresult ResumeTimeouts(bool aThawChildren = true,
-                                  bool aThawWorkers = true) override;
-  virtual uint32_t TimeoutSuspendCount() override;
+
+  virtual void Suspend();
+  virtual void Resume();
+  virtual bool IsSuspended() const override;
+  virtual void Freeze();
+  virtual void Thaw();
+  virtual bool IsFrozen() const override;
+  virtual void SyncStateFromParentWindow();
+
   virtual nsresult FireDelayedDOMEvents() override;
-  virtual bool IsFrozen() const override
-  {
-    return mIsFrozen;
-  }
   virtual bool IsRunningTimeout() override { return mTimeoutFiringDepth > 0; }
 
   // Outer windows only.
   virtual bool WouldReuseInnerWindow(nsIDocument* aNewDocument) override;
 
   virtual void SetDocShell(nsIDocShell* aDocShell) override;
   virtual void DetachFromDocShell() override;
   virtual nsresult SetNewDocument(nsIDocument *aDocument,
@@ -648,19 +647,16 @@ public:
   // Outer windows only.
   void UnblockScriptedClosing();
 
   static void Init();
   static void ShutDown();
   static void CleanupCachedXBLHandlers(nsGlobalWindow* aWindow);
   static bool IsCallerChrome();
 
-  static void RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
-                                          nsGlobalWindow *aWindow);
-
   friend class WindowStateHolder;
 
   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsGlobalWindow,
                                                                    nsIDOMEventTarget)
 
 #ifdef DEBUG
   // Call Unlink on this window. This may cause bad things to happen, so use
   // with caution.
@@ -1492,16 +1488,22 @@ private:
                         bool aDoJSFixups,
                         bool aNavigate,
                         nsIArray *argv,
                         nsISupports *aExtraArgument,
                         nsIDocShellLoadInfo* aLoadInfo,
                         bool aForceNoOpener,
                         nsPIDOMWindowOuter **aReturn);
 
+  template<typename Method>
+  void CallOnChildren(Method aMethod);
+
+  void FreezeInternal();
+  void ThawInternal();
+
 public:
   // Timeout Functions
   // Language agnostic timeout function (all args passed).
   // |interval| is in milliseconds.
   nsresult SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
                                 int32_t interval,
                                 bool aIsInterval, int32_t* aReturn);
   int32_t SetTimeoutOrInterval(JSContext* aCx,
@@ -1611,29 +1613,16 @@ public:
   // to determine who the caller is.  If it's false, it'll use |this| as the
   // caller.
   bool WindowExists(const nsAString& aName, bool aForceNoOpener,
                     bool aLookForCallerOnJSStack);
 
   already_AddRefed<nsIWidget> GetMainWidget();
   nsIWidget* GetNearestWidget() const;
 
-  void Freeze()
-  {
-    NS_ASSERTION(!IsFrozen(), "Double-freezing?");
-    mIsFrozen = true;
-    NotifyDOMWindowFrozen(this);
-  }
-
-  void Thaw()
-  {
-    mIsFrozen = false;
-    NotifyDOMWindowThawed(this);
-  }
-
   bool IsInModalState();
 
   // Convenience functions for the many methods that need to scale
   // from device to CSS pixels or vice versa.  Note: if a presentation
   // context is not available, they will assume a 1:1 ratio.
   int32_t DevToCSSIntPixels(int32_t px);
   int32_t CSSToDevIntPixels(int32_t px);
   nsIntSize DevToCSSIntPixels(nsIntSize px);
@@ -1750,24 +1739,16 @@ private:
   // IsSecureContext() for the inner window that corresponds to aDocument.
   bool ComputeIsSecureContext(nsIDocument* aDocument);
 
 public:
 
   void GetConstellation(nsACString& aConstellation);
 
 protected:
-  // This member is also used on both inner and outer windows, but
-  // for slightly different purposes. On inner windows it means the
-  // inner window is held onto by session history and should not
-  // change. On outer windows it means that the window is in a state
-  // where we don't want to force creation of a new inner window since
-  // we're in the middle of doing just that.
-  bool                          mIsFrozen : 1;
-
   // These members are only used on outer window objects. Make sure
   // you never set any of these on an inner object!
   bool                          mFullScreen : 1;
   bool                          mFullscreenMode : 1;
   bool                          mIsClosed : 1;
   bool                          mInClose : 1;
   // mHavePendingClose means we've got a termination function set to
   // close us when the JS stops executing or that we have a close
@@ -1896,17 +1877,18 @@ protected:
   RefPtr<mozilla::dom::CustomElementRegistry> mCustomElements;
 
   // These member variables are used on both inner and the outer windows.
   nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
 
   typedef nsTArray<RefPtr<mozilla::dom::StorageEvent>> nsDOMStorageEventArray;
   nsDOMStorageEventArray mPendingStorageEvents;
 
-  uint32_t mTimeoutsSuspendDepth;
+  uint32_t mSuspendDepth;
+  uint32_t mFreezeDepth;
 
   // the method that was used to focus mFocusedNode
   uint32_t mFocusMethod;
 
   uint32_t mSerial;
 
 #ifdef DEBUG
   bool mSetOpenerWindowCalled;
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -210,33 +210,27 @@ public:
 
   // Returns an object containing the window's state.  This also suspends
   // all running timeouts in the window.
   virtual already_AddRefed<nsISupports> SaveWindowState() = 0;
 
   // Restore the window state from aState.
   virtual nsresult RestoreWindowState(nsISupports *aState) = 0;
 
-  // Suspend timeouts in this window and in child windows.
-  virtual void SuspendTimeouts(uint32_t aIncrease = 1,
-                               bool aFreezeChildren = true,
-                               bool aFreezeWorkers = true) = 0;
-
-  // Resume suspended timeouts in this window and in child windows.
-  virtual nsresult ResumeTimeouts(bool aThawChildren = true,
-                                  bool aThawWorkers = true) = 0;
-
-  virtual uint32_t TimeoutSuspendCount() = 0;
+  // Determine if the window is suspended or frozen.  Outer windows
+  // will forward this call to the inner window for convenience.  If
+  // there is no inner window then the outer window is considered
+  // suspended and frozen by default.
+  virtual bool IsSuspended() const = 0;
+  virtual bool IsFrozen() const = 0;
 
   // Fire any DOM notification events related to things that happened while
   // the window was frozen.
   virtual nsresult FireDelayedDOMEvents() = 0;
 
-  virtual bool IsFrozen() const = 0;
-
   nsPIDOMWindowOuter* GetOuterWindow()
   {
     return mIsInnerWindow ? mOuterWindow.get() : AsOuter();
   }
 
   bool IsInnerWindow() const
   {
     return mIsInnerWindow;
@@ -817,16 +811,40 @@ public:
     return mInnerObjectsFreed;
   }
 
   /**
    * Check whether this window is a secure context.
    */
   bool IsSecureContext() const;
 
+  // Calling suspend should prevent any asynchronous tasks from
+  // executing javascript for this window.  This means setTimeout,
+  // requestAnimationFrame, and events should not be fired. Suspending
+  // a window also suspends its children and workers.  Workers may
+  // continue to perform computations in the background.  A window
+  // can have Suspend() called multiple times and will only resume after
+  // a matching number of Resume() calls.
+  void Suspend();
+  void Resume();
+
+  // Calling Freeze() on a window will automatically Suspend() it.  In
+  // addition, the window and its children are further treated as no longer
+  // suitable for interaction with the user.  For example, it may be marked
+  // non-visible, cannot be focused, etc.  All worker threads are also frozen
+  // bringing them to a complete stop.  A window can have Freeze() called
+  // multiple times and will only thaw after a matching number of Thaw()
+  // calls.
+  void Freeze();
+  void Thaw();
+
+  // Apply the parent window's suspend, freeze, and modal state to the current
+  // window.
+  void SyncStateFromParentWindow();
+
 protected:
   void CreatePerformanceObjectIfNeeded();
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsPIDOMWindowInner, NS_PIDOMWINDOWINNER_IID)
 
 // NB: It's very very important that these two classes have identical vtables
 // and memory layout!
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -2726,18 +2726,18 @@ IsNonExposedGlobal(JSContext* aCx, JSObj
   }
 
   return false;
 }
 
 void
 HandlePrerenderingViolation(nsPIDOMWindowInner* aWindow)
 {
-  // Suspend the window and its workers, and its children too.
-  aWindow->SuspendTimeouts();
+  // Freeze the window and its workers, and its children too.
+  aWindow->Freeze();
 
   // Suspend event handling on the document
   nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
   if (doc) {
     doc->SuppressEventHandling(nsIDocument::eEvents);
   }
 }
 
--- a/dom/cache/test/mochitest/test_cache_orphaned_body.html
+++ b/dom/cache/test/mochitest/test_cache_orphaned_body.html
@@ -83,17 +83,18 @@ function gc() {
     SpecialPowers.exactGC(resolve);
   });
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv({
   "set": [["dom.caches.enabled", true],
           ["dom.caches.testing.enabled", true],
-          ["dom.quotaManager.testing", true]],
+          ["dom.quotaManager.testing", true],
+          ["dom.storageManager.enabled", true]],
 }, function() {
   var name = 'orphanedBodyOwner';
   var cache = null;
   var response = null;
   var initialUsage = 0;
   var fullUsage = 0;
   var resetUsage = 0;
   var endUsage = 0;
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -2205,25 +2205,21 @@ public:
                                            MediaStreamTrackSource)
 
   explicit StreamCaptureTrackSource(MediaStreamTrackSource* aCapturedTrackSource)
     : MediaStreamTrackSource(aCapturedTrackSource->GetPrincipal(),
                              true,
                              nsString())
     , mCapturedTrackSource(aCapturedTrackSource)
   {
-    mCapturedTrackSource->RegisterSink(this);
   }
 
   void Destroy() override
   {
     MOZ_ASSERT(mCapturedTrackSource);
-    if (mCapturedTrackSource) {
-      mCapturedTrackSource->UnregisterSink(this);
-    }
   }
 
   MediaSourceEnum GetMediaSource() const override
   {
     return MediaSourceEnum::Other;
   }
 
   CORSMode GetCORSMode() const override
--- a/dom/indexedDB/test/test_storage_manager_estimate.html
+++ b/dom/indexedDB/test/test_storage_manager_estimate.html
@@ -9,11 +9,11 @@
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7" src="unit/test_storage_manager_estimate.js"></script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
-<body onload="runTest();"></body>
+<body onload="setup();"></body>
 
 </html>
--- a/dom/indexedDB/test/unit/test_storage_manager_estimate.js
+++ b/dom/indexedDB/test/unit/test_storage_manager_estimate.js
@@ -49,8 +49,15 @@ function testSteps()
   });
   let usageAfterPut = yield undefined;
   ok(usageAfterPut > usageAfterCreate, 'estimated usage must increase after putting large object');
   db.close();
 
   finishTest();
   yield undefined;
 }
+
+function setup()
+{
+  SpecialPowers.pushPrefEnv({
+    "set": [["dom.storageManager.enabled", true]]
+  },  runTest);
+}
--- a/dom/media/MediaStreamTrack.cpp
+++ b/dom/media/MediaStreamTrack.cpp
@@ -383,26 +383,49 @@ MediaStreamTrack::Clone()
   MediaStreamGraph* graph = Graph();
   newStream->InitOwnedStreamCommon(graph);
   newStream->InitPlaybackStreamCommon(graph);
 
   return newStream->CloneDOMTrack(*this, mTrackID);
 }
 
 void
+MediaStreamTrack::SetReadyState(MediaStreamTrackState aState)
+{
+  MOZ_ASSERT(!(mReadyState == MediaStreamTrackState::Ended &&
+               aState == MediaStreamTrackState::Live),
+             "We don't support overriding the ready state from ended to live");
+
+  if (mReadyState == MediaStreamTrackState::Live &&
+      aState == MediaStreamTrackState::Ended &&
+      mSource) {
+    mSource->UnregisterSink(this);
+  }
+
+  mReadyState = aState;
+}
+
+void
 MediaStreamTrack::NotifyEnded()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (Ended()) {
     return;
   }
 
   LOG(LogLevel::Info, ("MediaStreamTrack %p ended", this));
 
+  if (!mSource) {
+    MOZ_ASSERT(false);
+    return;
+  }
+
+  mSource->UnregisterSink(this);
+
   mReadyState = MediaStreamTrackState::Ended;
 
   DispatchTrustedEvent(NS_LITERAL_STRING("ended"));
 }
 
 DOMMediaStream*
 MediaStreamTrack::GetInputDOMStream()
 {
--- a/dom/media/MediaStreamTrack.h
+++ b/dom/media/MediaStreamTrack.h
@@ -292,17 +292,17 @@ public:
    * Convenience (and legacy) method for when ready state is "ended".
    */
   bool Ended() const { return mReadyState == MediaStreamTrackState::Ended; }
 
   /**
    * Forces the ready state to a particular value, for instance when we're
    * cloning an already ended track.
    */
-  void SetReadyState(MediaStreamTrackState aState) { mReadyState = aState; }
+  void SetReadyState(MediaStreamTrackState aState);
 
   /**
    * Notified by the MediaStreamGraph, through our owning MediaStream on the
    * main thread.
    *
    * Note that this sets the track to ended and raises the "ended" event
    * synchronously.
    */
--- a/dom/media/tests/mochitest/mediaStreamPlayback.js
+++ b/dom/media/tests/mochitest/mediaStreamPlayback.js
@@ -27,21 +27,21 @@ MediaStreamPlayback.prototype = {
 
    /**
    * Starts media element with a media stream, runs it until a canplaythrough
    * and timeupdate event fires, and calls stop() on all its tracks.
    *
    * @param {Boolean} isResume specifies if this media element is being resumed
    *                           from a previous run
    */
-  playMediaWithMediaStreamTracksStop : function(isResume) {
+  playMedia : function(isResume) {
     this.startMedia(isResume);
     return this.verifyPlaying()
       .then(() => this.stopTracksForStreamInMediaPlayback())
-      .then(() => this.stopMediaElement());
+      .then(() => this.detachFromMediaElement());
   },
 
   /**
    * Stops the local media stream's tracks while it's currently in playback in
    * a media element.
    *
    * Precondition: The media stream and element should both be actively
    *               being played. All the stream's tracks must be local.
@@ -75,25 +75,25 @@ MediaStreamPlayback.prototype = {
     this.mediaStream.stop();
     return timeout(waitForEnded(), ENDED_TIMEOUT_LENGTH, "ended event never fired")
              .then(() => ok(true, "ended event successfully fired"))
              .then(() => noTrackEnded);
   },
 
   /**
    * Starts media with a media stream, runs it until a canplaythrough and
-   * timeupdate event fires, and stops the media.
+   * timeupdate event fires, and detaches from the element without stopping media.
    *
    * @param {Boolean} isResume specifies if this media element is being resumed
    *                           from a previous run
    */
-  playMedia : function(isResume) {
+  playMediaWithoutStoppingTracks : function(isResume) {
     this.startMedia(isResume);
     return this.verifyPlaying()
-      .then(() => this.stopMediaElement());
+      .then(() => this.detachFromMediaElement());
   },
 
   /**
    * Starts the media with the associated stream.
    *
    * @param {Boolean} isResume specifies if the media element playback
    *                           is being resumed from a previous run
    */
@@ -151,22 +151,22 @@ MediaStreamPlayback.prototype = {
         is(this.mediaElement.preload, "", "Preload should not exist");
         is(this.mediaElement.src, "", "No src should be defined");
         is(this.mediaElement.currentSrc, "",
            "Current src should still be an empty string");
       });
   },
 
   /**
-   * Stops the media with the associated stream.
+   * Detaches from the element without stopping the media.
    *
    * Precondition: The media stream and element should both be actively
    *               being played.
    */
-  stopMediaElement : function() {
+  detachFromMediaElement : function() {
     this.mediaElement.pause();
     this.mediaElement.srcObject = null;
   }
 }
 
 
 /**
  * This class is basically the same as MediaStreamPlayback except
@@ -193,17 +193,17 @@ LocalMediaStreamPlayback.prototype = Obj
    * @param {Boolean} isResume specifies if this media element is being resumed
    *                           from a previous run
    */
   playMediaWithDeprecatedStreamStop : {
     value: function(isResume) {
       this.startMedia(isResume);
       return this.verifyPlaying()
         .then(() => this.deprecatedStopStreamInMediaPlayback())
-        .then(() => this.stopMediaElement());
+        .then(() => this.detachFromMediaElement());
     }
   },
 
   /**
    * DEPRECATED - MediaStream.stop() is going away. Use MediaStreamTrack.stop()!
    *
    * Stops the local media stream while it's currently in playback in
    * a media element.
@@ -249,11 +249,28 @@ var scriptsReady = Promise.all([
   document.head.appendChild(el);
   return new Promise(r => el.onload = r);
 }));
 
 function createHTML(options) {
   return scriptsReady.then(() => realCreateHTML(options));
 }
 
+var pushPrefs = (...p) => new Promise(r => SpecialPowers.pushPrefEnv({set: p}, r));
+
+// noGum - Helper to detect whether active guM tracks still exist.
+//
+// It relies on the fact that, by spec, device labels from enumerateDevices are
+// only visible during active gum calls. They're also visible when persistent
+// permissions are granted, so turn off media.navigator.permission.disabled
+// (which is normally on otherwise in our tests). Lastly, we must turn on
+// media.navigator.permission.fake otherwise fake devices don't count as active.
+
+var noGum = () => pushPrefs(["media.navigator.permission.disabled", false],
+                            ["media.navigator.permission.fake", true])
+  .then(() => navigator.mediaDevices.enumerateDevices())
+  .then(([device]) => device &&
+      is(device.label, "", "Test must leave no active gUM streams behind."));
+
 var runTest = testFunction => scriptsReady
   .then(() => runTestWhenReady(testFunction))
+  .then(() => noGum())
   .then(() => finish());
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -75,16 +75,17 @@ skip-if = android_version == '18' # andr
 [test_getUserMedia_playVideoTwice.html]
 [test_getUserMedia_spinEventLoop.html]
 [test_getUserMedia_stopAudioStream.html]
 [test_getUserMedia_stopAudioStreamWithFollowupAudio.html]
 [test_getUserMedia_stopVideoAudioStream.html]
 [test_getUserMedia_stopVideoAudioStreamWithFollowupVideoAudio.html]
 [test_getUserMedia_stopVideoStream.html]
 [test_getUserMedia_stopVideoStreamWithFollowupVideo.html]
+[test_getUserMedia_trackCloneCleanup.html]
 [test_getUserMedia_trackEnded.html]
 [test_getUserMedia_peerIdentity.html]
 [test_peerConnection_addIceCandidate.html]
 [test_peerConnection_addtrack_removetrack_events.html]
 skip-if = android_version == '18' # android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_basicAudio.html]
 skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_basicAudioNATSrflx.html]
--- a/dom/media/tests/mochitest/test_getUserMedia_addTrackRemoveTrack.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_addTrackRemoveTrack.html
@@ -23,33 +23,33 @@
         stream.addTrack(track);
         checkMediaStreamContains(stream, [track], "Re-added audio");
 
         stream.addTrack(otherTrack);
         checkMediaStreamContains(stream, [track, otherTrack], "Added video");
 
         var testElem = createMediaElement('video', 'testAddTrackAudioVideo');
         var playback = new LocalMediaStreamPlayback(testElem, stream);
-        return playback.playMediaWithMediaStreamTracksStop(false);
+        return playback.playMedia(false);
     }))
     .then(() => getUserMedia({video: true})).then(stream =>
       getUserMedia({video: true}).then(otherStream => {
         info("Test addTrack()ing a video track to a video-only gUM stream");
         var track = stream.getTracks()[0];
         var otherTrack = otherStream.getTracks()[0];
 
         stream.addTrack(track);
         checkMediaStreamContains(stream, [track], "Re-added video");
 
         stream.addTrack(otherTrack);
         checkMediaStreamContains(stream, [track, otherTrack], "Added video");
 
         var test = createMediaElement('video', 'testAddTrackDoubleVideo');
         var playback = new LocalMediaStreamPlayback(test, stream);
-        return playback.playMediaWithMediaStreamTracksStop(false);
+        return playback.playMedia(false);
     }))
     .then(() => getUserMedia({video: true})).then(stream =>
       getUserMedia({video: true}).then(otherStream => {
         info("Test removeTrack() existing and added video tracks from a video-only gUM stream");
         var track = stream.getTracks()[0];
         var otherTrack = otherStream.getTracks()[0];
 
         stream.removeTrack(otherTrack);
@@ -76,17 +76,17 @@
           ok(!loadeddata, "Stream without tracks shall not raise 'loadeddata' on media element");
           elem.pause();
           elem.srcObject = null;
         })
         .then(() => {
           stream.addTrack(track);
           checkMediaStreamContains(stream, [track], "Re-added added-then-removed track");
           var playback = new LocalMediaStreamPlayback(elem, stream);
-          return playback.playMediaWithMediaStreamTracksStop(false);
+          return playback.playMedia(false);
         })
         .then(() => otherTrack.stop());
     }))
     .then(() => getUserMedia({ audio: true })).then(audioStream =>
       getUserMedia({ video: true }).then(videoStream => {
         info("Test adding track and removing the original");
         var audioTrack = audioStream.getTracks()[0];
         var videoTrack = videoStream.getTracks()[0];
@@ -94,17 +94,17 @@
         audioStream.addTrack(videoTrack);
 
         checkMediaStreamContains(videoStream, [], "1, Removed original track");
         checkMediaStreamContains(audioStream, [audioTrack, videoTrack],
                                  "2, Added external track");
 
         var elem = createMediaElement('video', 'testAddRemoveOriginalTrackVideo');
         var playback = new LocalMediaStreamPlayback(elem, audioStream);
-        return playback.playMediaWithMediaStreamTracksStop(false);
+        return playback.playMedia(false);
       }))
     .then(() => {
       var ac = new AudioContext();
 
       var osc1k = createOscillatorStream(ac, 1000);
       var audioTrack1k = osc1k.getTracks()[0];
 
       var osc5k = createOscillatorStream(ac, 5000);
--- a/dom/media/tests/mochitest/test_getUserMedia_addtrack_removetrack_events.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_addtrack_removetrack_events.html
@@ -13,16 +13,17 @@ createHTML({
   bug: "1208328"
 });
 
 var spinEventLoop = () => new Promise(r => setTimeout(r, 0));
 
 var stream;
 var clone;
 var newStream;
+var tracks = [];
 
 var addTrack = track => {
   info("Adding track " + track.id);
   stream.addTrack(track);
 };
 var removeTrack = track => {
   info("Removing track " + track.id);
   stream.removeTrack(track);
@@ -44,25 +45,24 @@ runTest(() => getUserMedia({audio: true,
     stream.addEventListener("removetrack", function onRemovetrack(event) {
       ok(false, "removetrack fired unexpectedly for track " + event.track.id);
     });
 
     return getUserMedia({audio: true, video: true});
   })
   .then(s => {
     newStream = s;
-
     info("Stopping an original track");
     stopTrack(stream.getTracks()[0]);
 
     return spinEventLoop();
   })
   .then(() => {
     info("Removing original tracks");
-    stream.getTracks().forEach(t => stream.removeTrack(t));
+    stream.getTracks().forEach(t => (stream.removeTrack(t), tracks.push(t)));
 
     return spinEventLoop();
   })
   .then(() => {
     info("Adding other gUM tracks");
     newStream.getTracks().forEach(t => addTrack(t))
 
     return spinEventLoop();
@@ -84,16 +84,17 @@ runTest(() => getUserMedia({audio: true,
     info("Stopping clones");
     clone.getTracks().forEach(t => stopTrack(t));
 
     return spinEventLoop();
   })
   .then(() => {
     info("Stopping originals");
     stream.getTracks().forEach(t => stopTrack(t));
+    tracks.forEach(t => stopTrack(t));
 
     return spinEventLoop();
   })
   .then(() => {
     info("Removing remaining tracks");
     stream.getTracks().forEach(t => removeTrack(t));
 
     return spinEventLoop();
--- a/dom/media/tests/mochitest/test_getUserMedia_basicScreenshare.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicScreenshare.html
@@ -82,16 +82,16 @@
         playback.startMedia(false);
         return playback.verifyPlaying()
           .then(() => Promise.all([
             () => testVideo.srcObject.getVideoTracks()[0].applyConstraints(videoConstraints[1]),
             () => listenUntil(testVideo, "resize", () => true)
           ]))
           .then(() => playback.verifyPlaying()) // still playing
           .then(() => playback.deprecatedStopStreamInMediaPlayback())
-          .then(() => playback.stopMediaElement());
+          .then(() => playback.detachFromMediaElement());
       });
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html
@@ -55,16 +55,16 @@
               viewportOffsetY: 50,
               viewportWidth: 90,
               viewportHeight: 50
             }),
             () => listenUntil(testVideo, "resize", () => true)
           ]))
           .then(() => playback.verifyPlaying()) // still playing
           .then(() => playback.deprecatedStopStreamInMediaPlayback())
-          .then(() => playback.stopMediaElement());
+          .then(() => playback.detachFromMediaElement());
       });
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_basicVideo_playAfterLoadedmetadata.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicVideo_playAfterLoadedmetadata.html
@@ -26,16 +26,17 @@
       return new Promise(resolve => {
         ok(playback.mediaElement.paused,
            "Media element should be paused before play()ing");
         video.addEventListener('loadedmetadata', function() {
           ok(video.videoWidth > 0, "Expected nonzero video width");
           ok(video.videoHeight > 0, "Expected nonzero video width");
           resolve();
         });
-      });
+      })
+      .then(() => stream.getTracks().forEach(t => t.stop()));
     });
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_bug1223696.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_bug1223696.html
@@ -11,38 +11,42 @@
 
   createHTML({
     title: "Testing that removeTrack+addTrack of video tracks still render the correct track in a media element",
     bug: "1223696",
     visible: true
   });
 
   runTest(() => Promise.resolve()
-      .then(() => getUserMedia({audio:true, video: true})).then(stream => {
+    .then(() => getUserMedia({audio:true, video: true})).then(stream => {
       info("Test addTrack()ing a video track to an audio-only gUM stream");
 
       var video = createMediaElement("video", "test_video_track");
       video.srcObject = stream;
       video.play();
 
       var h = new CaptureStreamTestHelper2D();
-      stream.removeTrack(stream.getVideoTracks()[0]);
+      var removedTrack = stream.getVideoTracks()[0];
+      stream.removeTrack(removedTrack);
       video.onloadeddata = () => {
         info("loadeddata");
         var canvas = document.createElement("canvas");
         canvas.getContext("2d");
         var canvasStream = canvas.captureStream();
         setInterval(() => h.drawColor(canvas, h.grey), 1000);
 
         stream.addTrack(canvasStream.getVideoTracks()[0]);
 
         checkMediaStreamContains(stream, [stream.getAudioTracks()[0],
                                           canvasStream.getVideoTracks()[0]]);
       };
 
       return listenUntil(video, "loadeddata", () => true)
         .then(() => h.waitForPixelColor(video, h.grey, 5,
-                                        "The canvas track should be rendered by the media element"));
+            "The canvas track should be rendered by the media element"))
+        .then(() => {
+          [removedTrack, ...stream.getAudioTracks()].forEach(t => t.stop());
+        });
     }));
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_constraints.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_constraints.html
@@ -97,60 +97,57 @@ var mustFailWith = (msg, reason, constra
     }
   });
 
 /**
  * Starts the test run by running through each constraint
  * test by verifying that the right resolution and rejection is fired.
  */
 
-runTest(function() {
+runTest(() => Promise.resolve()
+  .then(() => {
+    // Check supported constraints first.
+    var dict = navigator.mediaDevices.getSupportedConstraints();
+    var supported = Object.keys(dict);
 
-  // Check supported constraints first.
-  var dict = navigator.mediaDevices.getSupportedConstraints();
-  var supported = Object.keys(dict);
-
-  mustSupport.forEach(key => ok(supported.indexOf(key) != -1 && dict[key],
-                                "Supports " + key));
+    mustSupport.forEach(key => ok(supported.indexOf(key) != -1 && dict[key],
+                                  "Supports " + key));
 
-  var unexpected = supported.filter(key => mustSupport.indexOf(key) == -1);
-  is(unexpected.length, 0,
-     "Unanticipated support (please update test): " + unexpected);
-
-  // Run constraint tests
-
-  var p = new Promise(resolve => SpecialPowers.pushPrefEnv({
-      set : [ ['media.getusermedia.browser.enabled', false],
-              ['media.getusermedia.screensharing.enabled', false] ]
-    }, resolve));
-
-  return tests.reduce((p, test) =>
-    p.then(() => navigator.mediaDevices.getUserMedia(test.constraints))
-    .then(() => is(null, test.error, test.message), e => {
+    var unexpected = supported.filter(key => mustSupport.indexOf(key) == -1);
+    is(unexpected.length, 0,
+       "Unanticipated support (please update test): " + unexpected);
+  })
+  .then(() => pushPrefs(["media.getusermedia.browser.enabled", false],
+                        ["media.getusermedia.screensharing.enabled", false]))
+  .then(() => tests.reduce((p, test) => p.then(() => getUserMedia(test.constraints))
+    .then(stream => {
+      is(null, test.error, test.message);
+      stream.getTracks().forEach(t => t.stop());
+    }, e => {
       is(e.name, test.error, test.message + ": " + e.message);
       if (test.constraint) {
         is(e.constraint, test.constraint,
            test.message + " w/correct constraint.");
       }
-    }), p)
-    .then(() => navigator.mediaDevices.getUserMedia({video: true, audio: true}))
-    .then(stream => stream.getVideoTracks()[0].applyConstraints({ width: 320 })
-      .then(() => stream.getAudioTracks()[0].applyConstraints({ })))
-    .then(() => ok(true, "applyConstraints code exercised"))
-    // TODO: Test outcome once fake devices support constraints (Bug 1088621)
-    .then(() => mustFailWith("applyConstraints fails on non-Gum tracks",
-                             "OverconstrainedError", "",
-                             () => (new AudioContext())
-                                 .createMediaStreamDestination().stream
-                                 .getAudioTracks()[0].applyConstraints()))
-    .then(() => mustFailWith(
-        "getUserMedia with unsatisfied required constraint",
-        "OverconstrainedError", "deviceId",
-        () => navigator.mediaDevices.getUserMedia({
-          audio: true,
-          video: { deviceId: { exact: "unheardof" } },
-        })));
-});
+    }), Promise.resolve()))
+  .then(() => getUserMedia({video: true, audio: true}))
+  .then(stream => stream.getVideoTracks()[0].applyConstraints({ width: 320 })
+    .then(() => stream.getAudioTracks()[0].applyConstraints({ }))
+    .then(() => {
+      stream.getTracks().forEach(track => track.stop());
+      ok(true, "applyConstraints code exercised");
+    }))
+  // TODO: Test outcome once fake devices support constraints (Bug 1088621)
+  .then(() => mustFailWith("applyConstraints fails on non-Gum tracks",
+                           "OverconstrainedError", "",
+                           () => (new AudioContext())
+                               .createMediaStreamDestination().stream
+                               .getAudioTracks()[0].applyConstraints()))
+  .then(() => mustFailWith(
+      "getUserMedia with unsatisfied required constraint",
+      "OverconstrainedError", "deviceId",
+      () => getUserMedia({ audio: true,
+                           video: { deviceId: { exact: "unheardof" } } }))));
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_getTrackById.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_getTrackById.html
@@ -35,15 +35,16 @@
 
       newStream.addTrack(audioTrack);
       is(newStream.getTrackById(audioTrack.id), audioTrack,
          "getTrackByid with matching id should return the track");
 
       newStream.addTrack(videoTrack);
       is(newStream.getTrackById(videoTrack.id), videoTrack,
          "getTrackByid with matching id should return the track");
+      [audioTrack, videoTrack].forEach(t => t.stop());
     });
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_loadedmetadata.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_loadedmetadata.html
@@ -19,19 +19,21 @@
   runTest(function () {
     var v = document.createElement("video");
     document.body.appendChild(v);
     v.preload = "metadata";
 
     var constraints = {video: true, audio: true};
     return getUserMedia(constraints).then(stream => new Promise(resolve => {
       v.srcObject = stream;
-      v.onloadedmetadata = resolve;
-    })).then(() => {
-      isnot(v.videoWidth, 0, "videoWidth shall be set on 'loadedmetadata'");
-      isnot(v.videoHeight, 0, "videoHeight shall be set on 'loadedmetadata'");
-    });
+      v.onloadedmetadata = () => {
+        isnot(v.videoWidth, 0, "videoWidth shall be set on 'loadedmetadata'");
+        isnot(v.videoHeight, 0, "videoHeight shall be set on 'loadedmetadata'");
+        resolve();
+      };
+    })
+    .then(() => stream.getTracks().forEach(t => t.stop())));
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_audio.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_audio.html
@@ -99,17 +99,19 @@ runTest(() => getUserMedia({audio: true}
     is(gUMAudioElement.srcObject.getTracks().length, 1,
        "A track should have been removed");
 
     return analyser.waitForAnalysisSuccess(array =>
       array[analyser.binIndexForFrequency(50)]              < 50 &&
       array[analyser.binIndexForFrequency(TEST_AUDIO_FREQ)] < 50 &&
       array[analyser.binIndexForFrequency(1500)]            < 50 &&
       array[analyser.binIndexForFrequency(2000)]            > 200 &&
-      array[analyser.binIndexForFrequency(2500)]            < 50);
+      array[analyser.binIndexForFrequency(2500)]            < 50)
+        .then(() => [gUMTrack, ...gUMAudioElement.srcObject.getTracks()]
+            .forEach(t => t.stop()));
   })
   .then(() => ok(true, "Test passed."))
   .catch(e => ok(false, "Test failed: " + e + (e.stack ? "\n" + e.stack : ""))));
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_video.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_video.html
@@ -105,15 +105,18 @@ runTest(() => getUserMedia({video: true,
     return checkVideoPaused(captureStreamElement).then(() => track);
   })
   .then(track => {
     info("Video paused. Changing source by track manipulation. Add first.");
     gUMVideoElement.srcObject.addTrack(track);
     gUMVideoElement.play();
     return checkVideoPlaying(captureStreamElement);
   })
-  .then(() => ok(true, "Test passed."))
+  .then(() => {
+    gUMVideoElement.srcObject.getTracks().forEach(t => t.stop());
+    ok(true, "Test passed.");
+  })
   .catch(e => ok(false, "Test failed: " + e + (e.stack ? "\n" + e.stack : ""))));
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_mediaStreamClone.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_mediaStreamClone.html
@@ -31,17 +31,17 @@
             "Audio track clone should have an id string");
 
       info("Stopping original tracks");
       stream.getTracks().forEach(t => t.stop());
 
       info("Playing from track clones");
       var test = createMediaElement('video', 'testClonePlayback');
       var playback = new MediaStreamPlayback(test, clone);
-      return playback.playMediaWithMediaStreamTracksStop(false);
+      return playback.playMedia(false);
     })
     .then(() => getUserMedia({video: true})).then(stream =>
       getUserMedia({video: true}).then(otherStream => {
         info("Test addTrack()ing a video track to a stream without affecting its clone");
         var track = stream.getTracks()[0];
         var otherTrack = otherStream.getTracks()[0];
 
         var streamClone = stream.clone();
@@ -62,35 +62,37 @@
                                  "Original not affected");
 
         // Not part of streamClone. Does not get stopped by the playback test.
         otherTrack.stop();
         otherStream.stop();
 
         var test = createMediaElement('video', 'testClonePlayback');
         var playback = new MediaStreamPlayback(test, streamClone);
-        return playback.playMediaWithMediaStreamTracksStop(false)
+        return playback.playMedia(false)
           .then(() => stream.getTracks().forEach(t => t.stop()))
           .then(() => stream.stop());
     }))
     .then(() => getUserMedia({audio: true, video: true})).then(stream => {
       info("Test cloning a stream into inception");
-      var inceptionClone = stream.clone().clone().clone().clone().clone()
-                                 .clone().clone().clone().clone().clone();
+      var clone = stream;
+      var clones = Array(10).fill().map(() => clone = clone.clone());
+      var inceptionClone = clones.pop();
       checkMediaStreamCloneAgainstOriginal(inceptionClone, stream);
       stream.getTracks().forEach(t => (stream.removeTrack(t),
                                        inceptionClone.addTrack(t)));
       is(inceptionClone.getAudioTracks().length, 2,
          "The inception clone should contain the original audio track and a track clone");
       is(inceptionClone.getVideoTracks().length, 2,
          "The inception clone should contain the original video track and a track clone");
 
       var test = createMediaElement('video', 'testClonePlayback');
       var playback = new MediaStreamPlayback(test, inceptionClone);
-      return playback.playMediaWithMediaStreamTracksStop(false);
+      return playback.playMedia(false)
+        .then(() => clones.forEach(c => c.getTracks().forEach(t => t.stop())));
     })
     .then(() => getUserMedia({audio: true, video: true})).then(stream => {
       info("Test adding tracks from many stream clones to the original stream");
 
       const LOOPS = 3;
       for (var i = 0; i < LOOPS; i++) {
         stream.clone().getTracks().forEach(t => stream.addTrack(t));
       }
@@ -100,17 +102,17 @@
          "The original track should contain the original video track and all the video clones");
       stream.getTracks().forEach(t1 => is(stream.getTracks()
                                                 .filter(t2 => t1.id == t2.id)
                                                 .length,
                                           1, "Each track should be unique"));
 
       var test = createMediaElement('video', 'testClonePlayback');
       var playback = new MediaStreamPlayback(test, stream);
-      return playback.playMediaWithMediaStreamTracksStop(false);
+      return playback.playMedia(false);
     })
     .then(() => {
       info("Testing audio content routing with MediaStream.clone()");
       var ac = new AudioContext();
 
       var osc1kOriginal = createOscillatorStream(ac, 1000);
       var audioTrack1kOriginal = osc1kOriginal.getTracks()[0];
       var audioTrack1kClone = osc1kOriginal.clone().getTracks()[0];
--- a/dom/media/tests/mochitest/test_getUserMedia_mediaStreamTrackClone.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_mediaStreamTrackClone.html
@@ -26,41 +26,47 @@
 
     info("Creating new stream for clone");
     var cloneStream = new MediaStream([clone]);
     checkMediaStreamContains(cloneStream, [clone]);
 
     info("Testing playback of track clone");
     var test = createMediaElement('video', 'testClonePlayback');
     var playback = new MediaStreamPlayback(test, cloneStream);
-    return playback.playMediaWithMediaStreamTracksStop(false);
+    return playback.playMedia(false);
   });
 
   runTest(() => Promise.resolve()
     .then(() => testSingleTrackClonePlayback({audio: true}))
     .then(() => testSingleTrackClonePlayback({video: true}))
     .then(() => getUserMedia({video: true})).then(stream => {
       info("Test cloning a track into inception");
       var track = stream.getTracks()[0];
-      var inceptionClone = track.clone().clone().clone().clone().clone()
-                                .clone().clone().clone().clone().clone();
+      var clone = track;
+      var clones = Array(10).fill().map(() => clone = clone.clone());
+      var inceptionClone = clones.pop();
       checkMediaStreamTrackCloneAgainstOriginal(inceptionClone, track);
 
       var cloneStream = new MediaStream();
       cloneStream.addTrack(inceptionClone);
 
       // cloneStream is now essentially the same as stream.clone();
       checkMediaStreamCloneAgainstOriginal(cloneStream, stream);
 
       var test = createMediaElement('video', 'testClonePlayback');
       var playback = new MediaStreamPlayback(test, cloneStream);
-      return playback.playMediaWithMediaStreamTracksStop(false)
-        .then(() => info("Testing that clones of ended tracks are ended"))
-        .then(() => cloneStream.clone().getTracks().forEach(t =>
-          is(t.readyState, "ended", "Track " + t.id + " should be ended")));
+      return playback.playMedia(false).then(() => {
+          info("Testing that clones of ended tracks are ended");
+          cloneStream.clone().getTracks().forEach(t =>
+            is(t.readyState, "ended", "Track " + t.id + " should be ended"));
+        })
+        .then(() => {
+          clones.forEach(t => t.stop());
+          track.stop();
+        });
     })
     .then(() => getUserMedia({audio: true, video: true})).then(stream => {
       info("Test adding many track clones to the original stream");
 
       const LOOPS = 3;
       for (var i = 0; i < LOOPS; i++) {
         stream.getTracks().forEach(t => stream.addTrack(t.clone()));
       }
@@ -68,17 +74,17 @@
          "The original track should contain the original video track and all the video clones");
       stream.getTracks().forEach(t1 => is(stream.getTracks()
                                                 .filter(t2 => t1.id == t2.id)
                                                 .length,
                                           1, "Each track should be unique"));
 
       var test = createMediaElement('video', 'testClonePlayback');
       var playback = new MediaStreamPlayback(test, stream);
-      return playback.playMediaWithMediaStreamTracksStop(false);
+      return playback.playMedia(false);
     })
     .then(() => {
       info("Testing audio content routing with MediaStreamTrack.clone()");
       var ac = new AudioContext();
 
       var osc1kOriginal = createOscillatorStream(ac, 1000);
       var audioTrack1kOriginal = osc1kOriginal.getTracks()[0];
       var audioTrack1kClone = audioTrack1kOriginal.clone();
--- a/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html
@@ -17,17 +17,17 @@ function theTest() {
     if (withConstraint) {
       config.peerIdentity = 'user@example.com';
     }
     info('getting media with constraints: ' + JSON.stringify(config));
     return getUserMedia(config)
       .then(stream => Promise.all([
         audioIsSilence(withConstraint, stream),
         videoIsBlack(withConstraint, stream)
-      ]));
+      ]).then(() => stream.getTracks().forEach(t => t.stop())));
   };
 
   // both without and with the constraint
   return testPeerIdentityConstraint(false)
     .then(() => testPeerIdentityConstraint(true));
 }
 
 runTest(theTest);
--- a/dom/media/tests/mochitest/test_getUserMedia_playAudioTwice.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_playAudioTwice.html
@@ -10,17 +10,16 @@
   /**
    * Run a test that we can complete an audio playback cycle twice in a row.
    */
   runTest(function () {
     return getUserMedia({audio: true}).then(audioStream => {
       var testAudio = createMediaElement('audio', 'testAudio');
       var playback = new LocalMediaStreamPlayback(testAudio, audioStream);
 
-      return playback.playMedia(false)
-        .then(() => playback.playMedia(true))
-        .then(() => audioStream.stop());
+      return playback.playMediaWithoutStoppingTracks(false)
+        .then(() => playback.playMedia(true));
     });
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_playVideoAudioTwice.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_playVideoAudioTwice.html
@@ -10,18 +10,17 @@
   /**
    * Run a test that we can complete a video playback cycle twice in a row.
    */
   runTest(function () {
     return getUserMedia({video: true, audio: true}).then(stream => {
       var testVideo = createMediaElement('video', 'testVideo');
       var playback = new LocalMediaStreamPlayback(testVideo, stream);
 
-      return playback.playMedia(false)
-        .then(() => playback.playMedia(true))
-        .then(() => stream.stop());
+      return playback.playMediaWithoutStoppingTracks(false)
+        .then(() => playback.playMedia(true));
     });
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_playVideoTwice.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_playVideoTwice.html
@@ -10,18 +10,17 @@
   /**
    * Run a test that we can complete a video playback cycle twice in a row.
    */
   runTest(function () {
     return getUserMedia({video: true}).then(stream => {
       var testVideo = createMediaElement('video', 'testVideo');
       var streamPlayback = new LocalMediaStreamPlayback(testVideo, stream);
 
-      return streamPlayback.playMedia(false)
-        .then(() => streamPlayback.playMedia(true))
-        .then(() => stream.stop());
+      return streamPlayback.playMediaWithoutStoppingTracks(false)
+        .then(() => streamPlayback.playMedia(true));
     });
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_spinEventLoop.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_spinEventLoop.html
@@ -8,20 +8,21 @@
 <script type="application/javascript">
   createHTML({ title: "getUserMedia Basic Audio Test", bug: "1208656" });
   /**
    * Run a test to verify that we can spin the event loop from within a mozGUM callback.
    */
   runTest(() => {
     var testAudio = createMediaElement('audio', 'testAudio');
     return new Promise((resolve, reject) => {
-      navigator.mozGetUserMedia({ audio: true }, () => {
+      navigator.mozGetUserMedia({ audio: true }, stream => {
         SpecialPowers.spinEventLoop(window);
-               ok(true, "Didn't crash");
-               resolve();
+        ok(true, "Didn't crash");
+        stream.getTracks().forEach(t => t.stop());
+        resolve();
       }, () => {});
     });
   });
 
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_getUserMedia_trackCloneCleanup.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+  "use strict";
+
+  createHTML({
+    title: "Stopping a MediaStreamTrack and its clones should deallocate the device",
+    bug: "1294605"
+  });
+
+  runTest(() => getUserMedia({audio: true, video: true}).then(stream => {
+    let clone = stream.clone();
+    stream.getTracks().forEach(t => t.stop());
+    stream.clone().getTracks().forEach(t => stream.addTrack(t));
+    is(stream.getTracks().filter(t => t.readyState == "live").length, 0,
+       "Cloning ended tracks should make them ended");
+    [...stream.getTracks(), ...clone.getTracks()].forEach(t => t.stop());
+
+    // Bug 1295352: better to be explicit about noGum here wrt future refactoring.
+    return noGum();
+  }));
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -330,16 +330,20 @@ void
 MediaEngineRemoteVideoSource::NotifyPull(MediaStreamGraph* aGraph,
                                          SourceMediaStream* aSource,
                                          TrackID aID, StreamTime aDesiredTime,
                                          const PrincipalHandle& aPrincipalHandle)
 {
   VideoSegment segment;
 
   MonitorAutoLock lock(mMonitor);
+  if (mState != kStarted) {
+    return;
+  }
+
   StreamTime delta = aDesiredTime - aSource->GetEndOfAppendedData(aID);
 
   if (delta > 0) {
     // nullptr images are allowed
     AppendToTrack(aSource, mImage, aID, delta, aPrincipalHandle);
   }
 }
 
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp
@@ -114,16 +114,27 @@ MediaEngineTabVideoSource::InitRunnable:
     mVideoSource->mWindow = nsPIDOMWindowOuter::From(win);
     MOZ_ASSERT(mVideoSource->mWindow);
   }
   nsCOMPtr<nsIRunnable> start(new StartRunnable(mVideoSource));
   start->Run();
   return NS_OK;
 }
 
+nsresult
+MediaEngineTabVideoSource::DestroyRunnable::Run()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  mVideoSource->mWindow = nullptr;
+  mVideoSource->mTabSource = nullptr;
+
+  return NS_OK;
+}
+
 void
 MediaEngineTabVideoSource::GetName(nsAString_internal& aName) const
 {
   aName.AssignLiteral(u"&getUserMedia.videoSource.tabShare;");
 }
 
 void
 MediaEngineTabVideoSource::GetUUID(nsACString_internal& aUuid) const
@@ -144,16 +155,22 @@ MediaEngineTabVideoSource::Allocate(cons
                                     const char** aOutBadConstraint)
 {
   // windowId is not a proper constraint, so just read it.
   // It has no well-defined behavior in advanced, so ignore it there.
 
   mWindowId = aConstraints.mBrowserWindow.WasPassed() ?
               aConstraints.mBrowserWindow.Value() : -1;
   *aOutHandle = nullptr;
+
+  {
+    MonitorAutoLock mon(mMonitor);
+    mState = kAllocated;
+  }
+
   return Restart(nullptr, aConstraints, aPrefs, aDeviceId, aOutBadConstraint);
 }
 
 nsresult
 MediaEngineTabVideoSource::Restart(AllocationHandle* aHandle,
                                    const dom::MediaTrackConstraints& aConstraints,
                                    const mozilla::MediaEnginePrefs& aPrefs,
                                    const nsString& aDeviceId,
@@ -182,42 +199,56 @@ MediaEngineTabVideoSource::Restart(Alloc
   }
   return NS_OK;
 }
 
 nsresult
 MediaEngineTabVideoSource::Deallocate(AllocationHandle* aHandle)
 {
   MOZ_ASSERT(!aHandle);
+  NS_DispatchToMainThread(do_AddRef(new DestroyRunnable(this)));
+
+  {
+    MonitorAutoLock mon(mMonitor);
+    mState = kReleased;
+  }
   return NS_OK;
 }
 
 nsresult
 MediaEngineTabVideoSource::Start(SourceMediaStream* aStream, TrackID aID,
                                  const PrincipalHandle& aPrincipalHandle)
 {
   nsCOMPtr<nsIRunnable> runnable;
   if (!mWindow)
     runnable = new InitRunnable(this);
   else
     runnable = new StartRunnable(this);
   NS_DispatchToMainThread(runnable);
   aStream->AddTrack(aID, 0, new VideoSegment());
 
+  {
+    MonitorAutoLock mon(mMonitor);
+    mState = kStarted;
+  }
+
   return NS_OK;
 }
 
 void
 MediaEngineTabVideoSource::NotifyPull(MediaStreamGraph*,
                                       SourceMediaStream* aSource,
                                       TrackID aID, StreamTime aDesiredTime,
                                       const PrincipalHandle& aPrincipalHandle)
 {
   VideoSegment segment;
   MonitorAutoLock mon(mMonitor);
+  if (mState != kStarted) {
+    return;
+  }
 
   // Note: we're not giving up mImage here
   RefPtr<layers::SourceSurfaceImage> image = mImage;
   StreamTime delta = aDesiredTime - aSource->GetEndOfAppendedData(aID);
   if (delta > 0) {
     // nullptr images are allowed
     gfx::IntSize size = image ? image->GetSize() : IntSize(0, 0);
     segment.AppendFrame(image.forget().downcast<layers::Image>(), delta, size,
@@ -330,25 +361,32 @@ MediaEngineTabVideoSource::Draw() {
 
   RefPtr<layers::SourceSurfaceImage> image = new layers::SourceSurfaceImage(size, surface);
 
   MonitorAutoLock mon(mMonitor);
   mImage = image;
 }
 
 nsresult
-MediaEngineTabVideoSource::Stop(mozilla::SourceMediaStream*, mozilla::TrackID)
+MediaEngineTabVideoSource::Stop(mozilla::SourceMediaStream* aSource,
+                                mozilla::TrackID aID)
 {
   // If mBlackedoutWindow is true, we may be running
   // despite mWindow == nullptr.
   if (!mWindow && !mBlackedoutWindow) {
     return NS_OK;
   }
 
   NS_DispatchToMainThread(new StopRunnable(this));
+
+  {
+    MonitorAutoLock mon(mMonitor);
+    mState = kStopped;
+    aSource->EndTrack(aID);
+  }
   return NS_OK;
 }
 
 bool
 MediaEngineTabVideoSource::IsFake()
 {
   return false;
 }
--- a/dom/media/webrtc/MediaEngineTabVideoSource.h
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.h
@@ -76,16 +76,23 @@ class MediaEngineTabVideoSource : public
 
     class InitRunnable : public Runnable {
     public:
       explicit InitRunnable(MediaEngineTabVideoSource *videoSource) : mVideoSource(videoSource) {}
       NS_IMETHOD Run();
       RefPtr<MediaEngineTabVideoSource> mVideoSource;
     };
 
+    class DestroyRunnable : public Runnable {
+    public:
+      explicit DestroyRunnable(MediaEngineTabVideoSource* videoSource) : mVideoSource(videoSource) {}
+      NS_IMETHOD Run();
+      RefPtr<MediaEngineTabVideoSource> mVideoSource;
+    };
+
 protected:
     ~MediaEngineTabVideoSource() {}
 
 private:
     int32_t mBufWidthMax;
     int32_t mBufHeightMax;
     int64_t mWindowId;
     bool mScrollWithPage;
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -2697,18 +2697,23 @@ PluginModuleParent::NPP_NewInternal(NPMI
 
     nsDependentCString strPluginType(pluginType);
     PluginInstanceParent* parentInstance =
         new PluginInstanceParent(this, instance, strPluginType, mNPNIface);
 
     if (mIsFlashPlugin) {
         parentInstance->InitMetadata(strPluginType, srcAttribute);
 #ifdef XP_WIN
-        bool supportsAsyncRender = false;
-        CallModuleSupportsAsyncRender(&supportsAsyncRender);
+        bool supportsAsyncRender =
+          Preferences::GetBool("dom.ipc.plugins.asyncdrawing.enabled", false);
+        if (supportsAsyncRender) {
+          // Prefs indicates we want async plugin rendering, make sure
+          // the flash module has support.
+          CallModuleSupportsAsyncRender(&supportsAsyncRender);
+        }
 #ifdef _WIN64
         // For 64-bit builds force windowless if the flash library doesn't support
         // async rendering regardless of sandbox level.
         if (!supportsAsyncRender) {
 #else
         // For 32-bit builds force windowless if the flash library doesn't support
         // async rendering and the sandbox level is 2 or greater.
         if (!supportsAsyncRender && mSandboxLevel >= 2) {
--- a/dom/quota/StorageManager.cpp
+++ b/dom/quota/StorageManager.cpp
@@ -327,16 +327,30 @@ StorageManager::Estimate(ErrorResult& aR
   runnnable->Dispatch(aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   return promise.forget();
 }
 
+// static
+bool
+StorageManager::PrefEnabled(JSContext* aCx, JSObject* aObj)
+{
+  if (NS_IsMainThread()) {
+    return Preferences::GetBool("dom.storageManager.enabled");
+  }
+
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  MOZ_ASSERT(workerPrivate);
+
+  return workerPrivate->StorageManagerEnabled();
+}
+
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(StorageManager, mOwner)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(StorageManager)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(StorageManager)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StorageManager)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
--- a/dom/quota/StorageManager.h
+++ b/dom/quota/StorageManager.h
@@ -20,16 +20,20 @@ struct StorageEstimate;
 
 class StorageManager final
   : public nsISupports
   , public nsWrapperCache
 {
   nsCOMPtr<nsIGlobalObject> mOwner;
 
 public:
+  // Return dom.quota.storageManager.enabled on main/worker thread.
+  static bool
+  PrefEnabled(JSContext* aCx, JSObject* aObj);
+
   explicit
   StorageManager(nsIGlobalObject* aGlobal);
 
   nsIGlobalObject*
   GetParentObject() const
   {
     return mOwner;
   }
--- a/dom/tests/mochitest/bugs/mochitest.ini
+++ b/dom/tests/mochitest/bugs/mochitest.ini
@@ -71,17 +71,16 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug393974.html]
 [test_bug394769.html]
 [test_bug396843.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
 [test_bug400204.html]
 [test_bug404748.html]
 [test_bug406375.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
-[test_bug411103.html]
 [test_bug414291.html]
 tags = openwindow
 [test_bug427744.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
 [test_bug42976.html]
 [test_bug430276.html]
 [test_bug437361.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # b2g(dom.disable_open_during_load not implemented in b2g, showmodaldialog) b2g-debug(dom.disable_open_during_load not implemented in b2g, showmodaldialog) b2g-desktop(dom.disable_open_during_load not implemented in b2g, showmodaldialog)
deleted file mode 100644
--- a/dom/tests/mochitest/bugs/test_bug411103.html
+++ /dev/null
@@ -1,188 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=411103
--->
-<head>
-  <title>Test for Bug 411103</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=411103">Mozilla Bug 411103</a>
-<p id="display"></p>
-<div id="content" style="display: none"></div>
-
-<!-- XML's createElement and createElementNS aren't HTML's, of course -->
-<iframe src="data:application/xml,%3Cfoo%3EXML%3C/foo%3E" name="xmlWindow"></iframe>
-
-<!-- for good measure... -->
-<iframe src="data:application/xhtml+xml,%3Chtml%20xmlns=%22http://www.w3.org/1999/xhtml%22%3E%3Cbody%3E%3Cp%3EXHTML%3C/p%3E%3C/body%3E%3C/html%3E"
-        name="xhtmlWindow"></iframe>
-
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
-SimpleTest.waitForExplicitFinish();
-
-/** Test for Bug 411103 **/
-var allNSTests =
-  [
-   { args: [undefined, undefined] },
-   { args: [null, undefined] },
-   { args: [undefined, null] },
-   { args: [null, null] },
-   { args: [null, ""], code: 5 },
-   { args: ["", null] },
-   { args: ["", ""], code: 5 },
-   { args: [null, "<div>"], code: 5 },
-   { args: [null, "0div"], code: 5 },
-   { args: [null, "di v"], code: 5 },
-   { args: [null, "di<v"], code: 5 },
-   { args: [null, "-div"], code: 5 },
-   { args: [null, ".div"], code: 5 },
-   { args: ["http://example.com/", "<div>"], code: 5 },
-   { args: ["http://example.com/", "0div"], code: 5 },
-   { args: ["http://example.com/", "di<v"], code: 5 },
-   { args: ["http://example.com/", "-div"], code: 5 },
-   { args: ["http://example.com/", ".div"], code: 5 },
-   { args: [null, ":div"], code: 14 },
-   { args: [null, "div:"], code: 14 },
-   { args: ["http://example.com/", ":div"], code: 14 },
-   { args: ["http://example.com/", "div:"], code: 14 },
-   { args: [null, "d:iv"], code: 14 },
-   { args: [null, "a:b:c"], code: 14, message: "valid XML name, invalid QName" },
-   { args: ["http://example.com/", "a:b:c"], code: 14, message: "valid XML name, invalid QName" },
-   { args: [null, "a::c"], code: 14, message: "valid XML name, invalid QName" },
-   { args: ["http://example.com/", "a::c"], code: 14, message: "valid XML name, invalid QName" },
-   { args: ["http://example.com/", "a:0"], code: 5, message: "valid XML name, not a valid QName" },
-   { args: ["http://example.com/", "0:a"], code: 5, message: "0 at start makes it not a valid XML name" },
-   { args: ["http://example.com/", "a:_"] },
-   { args: ["http://example.com/", "a:\u0BC6"], code: 14,
-     message: "non-ASCII character after colon is CombiningChar, which is " +
-              "NCNameChar but not (Letter | \"_\") so invalid at start of " +
-              "NCName (but still a valid XML name, hence not 5)" },
-   { args: ["http://example.com/", "\u0BC6:a"], code: 14,
-     message: "non-ASCII character after colon is CombiningChar, which is " +
-              "NCNameChar but not (Letter | \"_\") so invalid at start of " +
-              "NCName (Gecko chooses to throw 14 here, but either is valid " +
-              "as this is both an invalid XML name and an invalid QName)" },
-   { args: ["http://example.com/", "a:a\u0BC6"] },
-   { args: ["http://example.com/", "a\u0BC6:a"] },
-   { args: ["http://example.com/", "xml:test"], code: 14, message: "binding xml prefix wrong" },
-   { args: ["http://example.com/", "xmlns:test"], code: 14, message: "binding xmlns prefix wrong" },
-   { args: ["http://www.w3.org/2000/xmlns/", "x:test"], code: 14, message: "binding namespace namespace to wrong prefix" },
-   { args: ["http://www.w3.org/2000/xmlns/", "xmlns:test"] },
-   { args: ["http://www.w3.org/XML/1998/namespace", "xml:test"] },
-   { args: ["http://www.w3.org/XML/1998/namespace", "x:test"] },
-  ];
-
-var allNoNSTests =
-  [
-   { args: [undefined] },
-   { args: [null] },
-   { args: [""], code: 5 },
-   { args: ["<div>"], code: 5 },
-   { args: ["0div"], code: 5 },
-   { args: ["di v"], code: 5 },
-   { args: ["di<v"], code: 5 },
-   { args: ["-div"], code: 5 },
-   { args: [".div"], code: 5 },
-   { args: [":"], message: "valid XML name, invalid QName" },
-   { args: [":div"], message: "valid XML name, invalid QName" },
-   { args: ["div:"], message: "valid XML name, invalid QName" },
-   { args: ["d:iv"] },
-   { args: ["a:b:c"], message: "valid XML name, invalid QName" },
-   { args: ["a::c"], message: "valid XML name, invalid QName" },
-   { args: ["a::c:"], message: "valid XML name, invalid QName" },
-   { args: ["a:0"], message: "valid XML name, not a valid QName" },
-   { args: ["0:a"], code: 5, message: "0 at start makes it not a valid XML name" },
-   { args: ["a:_"] },
-   { args: ["a:\u0BC6"],
-     message: "non-ASCII character after colon is CombiningChar, which is " +
-              "valid in pre-namespace XML" },
-   { args: ["\u0BC6:a"], code: 5, message: "not a valid start character" },
-   { args: ["a:a\u0BC6"] },
-   { args: ["a\u0BC6:a"] },
-   { args: ["xml:test"] },
-   { args: ["xmlns:test"] },
-   { args: ["x:test"] },
-   { args: ["xmlns:test"] },
-  ];
-
-function sourceify(v)
-{
-  switch (typeof v)
-  {
-    case "undefined":
-      return v;
-
-    case "string":
-      return '"' + v.replace('"', '\\"') + '"';
-
-    default:
-      return String(v);
-  }
-}
-
-function sourceifyArgs(args)
-{
-  var copy = new Array(args.length);
-  for (var i = 0, sz = args.length; i < sz; i++)
-    copy[i] = sourceify(args[i]);
-
-  return copy.join(", ");
-}
-
-function runTests(tests, methodName, document)
-{
-  for (var i = 0, sz = tests.length; i < sz; i++)
-  {
-    var test = tests[i];
-  
-    var argStr = sourceifyArgs(test.args);
-    try
-    {
-      document[methodName].apply(document, test.args);
-      var msg = "expected no exception for " +
-                "document." + methodName + "(" + argStr + ")";
-      if ("message" in test)
-        msg += "; " + test.message;
-      ok(!("code" in test), msg);
-    }
-    catch (e)
-    {
-      msg = "exception code for document." + methodName + "(" + argStr + ")";
-      if ("message" in test)
-        msg += "; " + test.message;
-      is(e.code, test.code || "no exception", msg);
-    }
-  }
-}
-
-
-function run()
-{
-  // HTML document
-  runTests(allNSTests, "createElementNS", document);
-  runTests(allNoNSTests, "createElement", document);
-
-  // XML document
-  var xmlDocument = window.frames.xmlWindow.document;
-  runTests(allNSTests, "createElementNS", xmlDocument);
-  runTests(allNoNSTests, "createElement", xmlDocument);
-
-  // XHTML document, for good measure
-  var xhtmlDocument = window.frames.xhtmlWindow.document;
-  runTests(allNSTests, "createElementNS", xhtmlDocument);
-  runTests(allNoNSTests, "createElement", xhtmlDocument);
-
-  SimpleTest.finish();
-}
-
-window.addEventListener("load", run, false);
-
-</script>
-</pre>
-</body>
-</html>
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -83,16 +83,17 @@ interface NavigatorContentUtils {
   //DOMString isProtocolHandlerRegistered(DOMString scheme, DOMString url);
   //DOMString isContentHandlerRegistered(DOMString mimeType, DOMString url);
   //void unregisterProtocolHandler(DOMString scheme, DOMString url);
   //void unregisterContentHandler(DOMString mimeType, DOMString url);
 };
 
 [NoInterfaceObject, Exposed=(Window,Worker)]
 interface NavigatorStorage {
+  [Func="mozilla::dom::StorageManager::PrefEnabled"]
   readonly attribute StorageManager storage;
 };
 
 [NoInterfaceObject]
 interface NavigatorStorageUtils {
   // NOT IMPLEMENTED
   //void yieldForStorageUpdates();
 };
--- a/dom/webidl/StorageManager.webidl
+++ b/dom/webidl/StorageManager.webidl
@@ -3,17 +3,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * https://storage.spec.whatwg.org/#storagemanager
  *
  */
 
-[Exposed=(Window,Worker)]
+[Exposed=(Window,Worker),
+ Func="mozilla::dom::StorageManager::PrefEnabled"]
 interface StorageManager {
   // [Throws]
   // Promise<boolean> persisted();
   // [Throws]
   // [Exposed=Window] Promise<boolean> persist();
   [Throws]
   Promise<StorageEstimate> estimate();
 };
--- a/dom/workers/WorkerPrefs.h
+++ b/dom/workers/WorkerPrefs.h
@@ -29,16 +29,17 @@ WORKER_SIMPLE_PREF("dom.caches.enabled",
 WORKER_SIMPLE_PREF("dom.caches.testing.enabled", DOMCachesTestingEnabled, DOM_CACHES_TESTING)
 WORKER_SIMPLE_PREF("dom.performance.enable_user_timing_logging", PerformanceLoggingEnabled, PERFORMANCE_LOGGING_ENABLED)
 WORKER_SIMPLE_PREF("dom.webnotifications.enabled", DOMWorkerNotificationEnabled, DOM_WORKERNOTIFICATION)
 WORKER_SIMPLE_PREF("dom.webnotifications.serviceworker.enabled", DOMServiceWorkerNotificationEnabled, DOM_SERVICEWORKERNOTIFICATION)
 WORKER_SIMPLE_PREF("dom.webnotifications.requireinteraction.enabled", DOMWorkerNotificationRIEnabled, DOM_WORKERNOTIFICATIONRI)
 WORKER_SIMPLE_PREF("dom.serviceWorkers.enabled", ServiceWorkersEnabled, SERVICEWORKERS_ENABLED)
 WORKER_SIMPLE_PREF("dom.serviceWorkers.testing.enabled", ServiceWorkersTestingEnabled, SERVICEWORKERS_TESTING_ENABLED)
 WORKER_SIMPLE_PREF("dom.serviceWorkers.openWindow.enabled", OpenWindowEnabled, OPEN_WINDOW_ENABLED)
+WORKER_SIMPLE_PREF("dom.storageManager.enabled", StorageManagerEnabled, STORAGEMANAGER_ENABLED)
 WORKER_SIMPLE_PREF("dom.push.enabled", PushEnabled, PUSH_ENABLED)
 WORKER_SIMPLE_PREF("dom.requestcontext.enabled", RequestContextEnabled, REQUESTCONTEXT_ENABLED)
 WORKER_SIMPLE_PREF("gfx.offscreencanvas.enabled", OffscreenCanvasEnabled, OFFSCREENCANVAS_ENABLED)
 WORKER_SIMPLE_PREF("dom.webkitBlink.dirPicker.enabled", WebkitBlinkDirectoryPickerEnabled, DOM_WEBKITBLINK_DIRPICKER_WEBKITBLINK)
 WORKER_PREF("dom.workers.latestJSVersion", JSVersionChanged)
 WORKER_PREF("intl.accept_languages", PrefLanguagesChanged)
 WORKER_PREF("general.appname.override", AppNameOverrideChanged)
 WORKER_PREF("general.appversion.override", AppVersionOverrideChanged)
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2207,16 +2207,20 @@ WorkerPrivateParent<Derived>::WorkerPriv
     // And manually set our mIsSecureContext, though it's not really relevant to
     // dedicated workers...
     mIsSecureContext = aParent->IsSecureContext();
     MOZ_ASSERT_IF(mIsChromeWorker, mIsSecureContext);
 
     MOZ_ASSERT(IsDedicatedWorker());
     mNowBaseTimeStamp = aParent->NowBaseTimeStamp();
     mNowBaseTimeHighRes = aParent->NowBaseTime();
+
+    if (aParent->mParentFrozen) {
+      Freeze(nullptr);
+    }
   }
   else {
     AssertIsOnMainThread();
 
     RuntimeService::GetDefaultJSSettings(mJSSettings);
 
     // Our secure context state depends on the kind of worker we have.
     if (UsesSystemPrincipal() || IsServiceWorker()) {
@@ -2244,16 +2248,26 @@ WorkerPrivateParent<Derived>::WorkerPriv
         GetNavigationStartTimeStamp();
       mNowBaseTimeHighRes =
       mLoadInfo.mWindow->GetPerformance()->GetDOMTiming()->
         GetNavigationStartHighRes();
     } else {
       mNowBaseTimeStamp = CreationTimeStamp();
       mNowBaseTimeHighRes = CreationTime();
     }
+
+    // Our parent can get suspended after it initiates the async creation
+    // of a new worker thread.  In this case suspend the new worker as well.
+    if (mLoadInfo.mWindow && mLoadInfo.mWindow->IsSuspended()) {
+      ParentWindowPaused();
+    }
+
+    if (mLoadInfo.mWindow && mLoadInfo.mWindow->IsFrozen()) {
+      Freeze(mLoadInfo.mWindow);
+    }
   }
 }
 
 template <class Derived>
 WorkerPrivateParent<Derived>::~WorkerPrivateParent()
 {
   DropJSObjects(this);
 }
@@ -2605,22 +2619,17 @@ WorkerPrivateParent<Derived>::Freeze(nsP
 }
 
 template <class Derived>
 bool
 WorkerPrivateParent<Derived>::Thaw(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnParentThread();
 
-  if (IsDedicatedWorker() && !mParentFrozen) {
-    // If we are in here, it means that this worker has been created when the
-    // parent was actually suspended (maybe during a sync XHR), and in this case
-    // we don't need to thaw.
-    return true;
-  }
+  MOZ_ASSERT(mParentFrozen);
 
   // Shared workers are resumed if any of their owning documents are thawed.
   // It can happen that mSharedWorkers is empty but this thread has not been
   // unregistered yet.
   if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
     AssertIsOnMainThread();
 
     bool anyRunning = false;
@@ -3115,17 +3124,17 @@ WorkerPrivateParent<Derived>::RegisterSh
       return false;
     }
   }
 
   mSharedWorkers.AppendElement(aSharedWorker);
 
   // If there were other SharedWorker objects attached to this worker then they
   // may all have been frozen and this worker would need to be thawed.
-  if (mSharedWorkers.Length() > 1 && !Thaw(nullptr)) {
+  if (mSharedWorkers.Length() > 1 && IsFrozen() && !Thaw(nullptr)) {
     return false;
   }
 
   return true;
 }
 
 template <class Derived>
 void
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -131,17 +131,17 @@ NS_IMPL_ISUPPORTS(nsXHRParseEndListener,
 
 class nsResumeTimeoutsEvent : public Runnable
 {
 public:
   explicit nsResumeTimeoutsEvent(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) {}
 
   NS_IMETHOD Run() override
   {
-    mWindow->ResumeTimeouts(false);
+    mWindow->Resume();
     return NS_OK;
   }
 
 private:
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
 };
 
 
@@ -2918,17 +2918,17 @@ XMLHttpRequestMainThread::SendInternal(c
     nsCOMPtr<nsIRunnable> resumeTimeoutRunnable;
     if (GetOwner()) {
       if (nsCOMPtr<nsPIDOMWindowOuter> topWindow = GetOwner()->GetOuterWindow()->GetTop()) {
         if (nsCOMPtr<nsPIDOMWindowInner> topInner = topWindow->GetCurrentInnerWindow()) {
           suspendedDoc = topWindow->GetExtantDoc();
           if (suspendedDoc) {
             suspendedDoc->SuppressEventHandling(nsIDocument::eEvents);
           }
-          topWindow->SuspendTimeouts(1, false);
+          topInner->Suspend();
           resumeTimeoutRunnable = new nsResumeTimeoutsEvent(topInner);
         }
       }
     }
 
     StopProgressEventTimer();
 
     SyncTimeoutType syncTimeoutType = MaybeStartSyncTimeoutTimer();
--- a/gfx/thebes/gfxPrefs.cpp
+++ b/gfx/thebes/gfxPrefs.cpp
@@ -71,17 +71,17 @@ void gfxPrefs::AssertMainThread()
 }
 
 void
 gfxPrefs::Pref::OnChange()
 {
   if (auto gpm = gfx::GPUProcessManager::Get()) {
     if (gfx::GPUChild* gpu = gpm->GetGPUChild()) {
       GfxPrefValue value;
-      GetCachedValue(&value);
+      GetLiveValue(&value);
       Unused << gpu->SendUpdatePref(gfx::GfxPrefSetting(mIndex, value));
     }
   }
   FireChangeCallback();
 }
 
 void
 gfxPrefs::Pref::FireChangeCallback()
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -108,16 +108,19 @@ public:
     void SetChangeCallback(ChangeCallback aCallback);
 
     virtual const char* Name() const = 0;
 
     // Returns true if the value is default, false if changed.
     virtual bool HasDefaultValue() const = 0;
 
     // Returns the pref value as a discriminated union.
+    virtual void GetLiveValue(GfxPrefValue* aOutValue) const = 0;
+
+    // Returns the pref value as a discriminated union.
     virtual void GetCachedValue(GfxPrefValue* aOutValue) const = 0;
 
     // Change the cached value. GfxPrefValue must be a compatible type.
     virtual void SetCachedValue(const GfxPrefValue& aOutValue) = 0;
 
   protected:
     void FireChangeCallback();
 
@@ -153,17 +156,17 @@ private:
 
       if (mValue != newValue) {
         mValue = newValue;
         FireChangeCallback();
       }
     }
 
   protected:
-    T GetLiveValue(const char* aPrefName) const {
+    T GetLiveValueByName(const char* aPrefName) const {
       if (IsPrefsServiceAvailable()) {
         return PrefGet(aPrefName, mValue);
       }
       return mValue;
     }
 
   public:
     T mValue;
@@ -223,21 +226,25 @@ private:
           break;
         default:
           MOZ_CRASH("Incomplete switch");
       }
     }
     const char *Name() const override {
       return Prefname();
     }
+    void GetLiveValue(GfxPrefValue* aOutValue) const override {
+      T value = GetLiveValue();
+      CopyPrefValue(&value, aOutValue);
+    }
     // When using the Preferences service, the change callback can be triggered
     // *before* our cached value is updated, so we expose a method to grab the
     // true live value.
     T GetLiveValue() const {
-      return BaseClass::GetLiveValue(Prefname());
+      return BaseClass::GetLiveValueByName(Prefname());
     }
     bool HasDefaultValue() const override {
       return this->mValue == Default();
     }
   };
 
   // This is where DECL_GFX_PREF for each of the preferences should go.
   // We will keep these in an alphabetical order to make it easier to see if
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -377,16 +377,20 @@ VectorImage::Init(const char* aMimeType,
 
   mIsInitialized = true;
   return NS_OK;
 }
 
 size_t
 VectorImage::SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const
 {
+  if (!mSVGDocumentWrapper) {
+    return 0; // No document, so no memory used for the document.
+  }
+
   nsIDocument* doc = mSVGDocumentWrapper->GetDocument();
   if (!doc) {
     return 0; // No document, so no memory used for the document.
   }
 
   nsWindowSizes windowSizes(aMallocSizeOf);
   doc->DocAddSizeOfIncludingThis(&windowSizes);
 
old mode 100644
new mode 100755
--- a/ipc/glue/SendStream.h
+++ b/ipc/glue/SendStream.h
@@ -61,22 +61,22 @@ public:
   // Create a SendStreamChild using a PBackground IPC manager on the
   // main thread or a Worker thread.  This can return nullptr if the provided
   // stream is blocking or if the Worker thread is already shutting down.
   static SendStreamChild*
   Create(nsIAsyncInputStream* aInputStream, PBackgroundChild* aManager);
 
   // Start reading data from the nsIAsyncInputStream used to create the actor.
   // This must be called after the actor is passed to the parent.  If you
-  // use AutoIPCStreamChild this is handled automatically.
+  // use AutoIPCStream this is handled automatically.
   virtual void
   Start() = 0;
 
   // Start cleaning up the actor.  This must be called if the actor is never
-  // sent to the parent.  If you use AutoIPCStreamChild this is handled
+  // sent to the parent.  If you use AutoIPCStream this is handled
   // automatically.
   virtual void
   StartDestroy() = 0;
 
 protected:
   virtual
   ~SendStreamChild() = 0;
 };
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -568,18 +568,17 @@ js::ArraySetLength(JSContext* cx, Handle
     }
 
     // Steps 9-11.
     bool lengthIsWritable = arr->lengthIsWritable();
 #ifdef DEBUG
     {
         RootedShape lengthShape(cx, arr->lookupPure(id));
         MOZ_ASSERT(lengthShape);
-        MOZ_ASSERT_IF(lengthIsWritable, lengthShape->writable());
-        MOZ_ASSERT_IF(lengthShape->writable() && !lengthIsWritable, arr->denseElementsAreFrozen());
+        MOZ_ASSERT(lengthShape->writable() == lengthIsWritable);
     }
 #endif
     uint32_t oldLen = arr->length();
 
     // Part of steps 1.a, 12.a, and 16: Fail if we're being asked to change
     // enumerability or configurability, or otherwise break the object
     // invariants. (ES6 checks these by calling OrdinaryDefineOwnProperty, but
     // in SM, the array length property is hardly ordinary.)
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/Array/frozen-dict-mode-length.js
@@ -0,0 +1,18 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ * Author: Emilio Cobos Álvarez <ecoal95@gmail.com>
+ */
+var BUGNUMBER = 1312948;
+var summary = "Freezing a dictionary mode object with a length property should make Object.isFrozen report true";
+
+print(BUGNUMBER + ": " + summary);
+
+/* Convert to dictionary mode */
+delete Array.prototype.slice;
+
+Object.freeze(Array.prototype);
+assertEq(Object.isFrozen(Array.prototype), true);
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
--- a/js/src/vm/ArrayObject-inl.h
+++ b/js/src/vm/ArrayObject-inl.h
@@ -18,16 +18,17 @@
 #include "vm/TypeInference-inl.h"
 
 namespace js {
 
 inline void
 ArrayObject::setLength(ExclusiveContext* cx, uint32_t length)
 {
     MOZ_ASSERT(lengthIsWritable());
+    MOZ_ASSERT_IF(length != getElementsHeader()->length, !denseElementsAreFrozen());
 
     if (length > INT32_MAX) {
         /* Track objects with overflowing lengths in type information. */
         MarkObjectGroupFlags(cx, this, OBJECT_FLAG_LENGTH_OVERFLOW);
     }
 
     getElementsHeader()->length = length;
 }
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -223,18 +223,17 @@ class ObjectElements
         // Note: allow isCopyOnWrite() here, see comment above.
         flags |= CONVERT_DOUBLE_ELEMENTS;
     }
     void clearShouldConvertDoubleElements() {
         MOZ_ASSERT(!isCopyOnWrite());
         flags &= ~CONVERT_DOUBLE_ELEMENTS;
     }
     bool hasNonwritableArrayLength() const {
-        return flags & NONWRITABLE_ARRAY_LENGTH ||
-               flags & FROZEN;
+        return flags & NONWRITABLE_ARRAY_LENGTH;
     }
     void setNonwritableArrayLength() {
         MOZ_ASSERT(!isCopyOnWrite());
         flags |= NONWRITABLE_ARRAY_LENGTH;
     }
     bool isCopyOnWrite() const {
         return flags & COPY_ON_WRITE;
     }
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -3388,31 +3388,31 @@ nsPrintEngine::TurnScriptingOn(bool aDoT
       doc->GetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview,
                        &propThere);
       if (aDoTurnOn) {
         if (propThere != NS_PROPTABLE_PROP_NOT_THERE) {
           doc->DeleteProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview);
           if (go && go->GetGlobalJSObject()) {
             xpc::Scriptability::Get(go->GetGlobalJSObject()).Unblock();
           }
-          window->ResumeTimeouts(false);
+          window->Resume();
         }
       } else {
         // Have to be careful, because people call us over and over again with
         // aDoTurnOn == false.  So don't set the property if it's already
         // set, since in that case we'd set it to the wrong value.
         if (propThere == NS_PROPTABLE_PROP_NOT_THERE) {
           // Stash the current value of IsScriptEnabled on the document, so
           // that layout code running in print preview doesn't get confused.
           doc->SetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview,
                            NS_INT32_TO_PTR(doc->IsScriptEnabled()));
           if (go && go->GetGlobalJSObject()) {
             xpc::Scriptability::Get(go->GetGlobalJSObject()).Block();
           }
-          window->SuspendTimeouts(1, false);
+          window->Suspend();
         }
       }
     }
   }
 }
 
 //-----------------------------------------------------------------
 //-- Done: Misc Support Methods
--- a/media/libpng/CHANGES
+++ b/media/libpng/CHANGES
@@ -588,17 +588,17 @@ Version 1.0.5d [November 29, 1999]
   Added PNG_EXPORT_VAR macro to accommodate making DLL's.
 
 Version 1.0.5e [November 30, 1999]
   Added iCCP, iTXt, and sPLT support; added "lang" member to the png_text
     structure; refactored the inflate/deflate support to make adding new chunks
     with trailing compressed parts easier in the future, and added new functions
     png_free_iCCP, png_free_pCAL, png_free_sPLT, png_free_text, png_get_iCCP,
     png_get_spalettes, png_set_iCCP, png_set_spalettes (Eric S. Raymond).
-  NOTE: Applications that write text chunks MUST define png_text->lang
+    NOTE: Applications that write text chunks MUST define png_text->lang
     before calling png_set_text(). It must be set to NULL if you want to
     write tEXt or zTXt chunks.  If you want your application to be able to
     run with older versions of libpng, use
 
       #ifdef PNG_iTXt_SUPPORTED
          png_text[i].lang = NULL;
       #endif
 
@@ -5698,16 +5698,67 @@ Version 1.6.25rc04 [August 30, 2016]
   Added MIPS support for SUB, AVG, and PAETH filters (Mandar Sahastrabuddhe).
 
 Version 1.6.25rc05 [August 30, 2016]
   Rebased contrib/intel/intel_sse.patch after the MIPS implementation update..
 
 Version 1.6.25 [September 1, 2016]
   No changes.
 
+Version 1.6.26beta01 [September 26, 2016]
+  Fixed handling zero length IDAT in pngfix (bug report by Agostino Sarubbo,
+    bugfix by John Bowler).
+  Do not issue a png_error() on read in png_set_pCAL() because png_handle_pCAL
+    has allocated memory that libpng needs to free.
+  Conditionally compile png_set_benign_errors() in pngread.c and pngtest.c
+  Issue a png_benign_error instead of a png_error on ADLER32 mismatch
+    while decoding compressed data chunks.
+  Changed PNG_ZLIB_VERNUM to ZLIB_VERNUM in pngpriv.h, pngstruct.h, and
+    pngrutil.c.
+  If CRC handling of critical chunks has been set to PNG_CRC_QUIET_USE,
+    ignore the ADLER32 checksum in the IDAT chunk as well as the chunk CRCs.
+  Issue png_benign_error() on ADLER32 checksum mismatch instead of png_error().
+  Add tests/badcrc.png and tests/badadler.png to tests/pngtest.
+  Merged pngtest.c with libpng-1.7.0beta84/pngtest.c
+
+Version 1.6.26beta02 [October 1, 2016]
+  Updated the documentation about CRC and ADLER32 handling.
+  Quieted 117 warnings from clang-3.8 in pngtrans.c, pngread.c,
+     pngwrite.c, pngunknown.c, and pngvalid.c.
+  Quieted 58 (out of 144) -Wconversion compiler warnings by changing
+    flag definitions in pngpriv.h from 0xnnnn to 0xnnnnU and trivial changes
+    in png.c, pngread.c, and pngwutil.c.
+
+Version 1.6.26beta03 [October 2, 2016]
+  Removed contrib/libtests/*.orig and *.rej that slipped into the tarballs.
+  Quieted the 86 remaining -Wconversion compiler warnings by
+    revising the png_isaligned() macro and trivial changes in png.c,
+    pngerror.c, pngget.c, pngmem.c, pngset.c, pngrtran.c, pngrutil.c,
+    pngwtran.c, pngwrite.c, and pngwutil.c.
+
+Version 1.6.26beta04 [October 3, 2016]
+  Quieted (bogus?) clang warnings about "absolute value has no effect"
+    when PNG_USE_ABS is defined.
+  Fixed offsets in contrib/intel/intel_sse.patch
+
+Version 1.6.26beta05 [October 6, 2016]
+  Changed integer constant 4294967294 to unsigned 4294967294U in pngconf.h
+    to avoid a signed/unsigned compare in the preprocessor.
+
+Version 1.6.26beta06 [October 7, 2016]
+  Use zlib-1.2.8.1 inflateValidate() instead of inflateReset2() to
+    optionally avoid ADLER32 evaluation.
+
+Version 1.6.26rc01 [October 12, 2016]
+  No changes.
+
+Version 1.6.26 [October 20, 2016]
+  Cosmetic change, "ptr != 0" to "ptr != NULL" in png.c and pngrutil.c
+  Despammed email addresses (replaced "@" with " at ").
+
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
 (subscription required; visit
 https://lists.sourceforge.net/lists/listinfo/png-mng-implement
 to subscribe)
 or to glennrp at users.sourceforge.net
 
 Glenn R-P
 #endif
--- a/media/libpng/LICENSE
+++ b/media/libpng/LICENSE
@@ -21,17 +21,17 @@ surrounding them in the modified libpng 
 This modified version of libpng code adds Intel-SSE support and is
 released under the libpng license described below. The modifications are
 Copyright (c) 2016 Google, Inc., and consist of the source files in the
 "sse2" subdirectory and added code in pngpriv.h delimited by
 #ifndef PNG_INTEL_SSE_OPT / #endif directives.
 
 This code is released under the libpng license.
 
-libpng versions 1.0.7, July 1, 2000 through 1.6.25, September 1, 2016 are
+libpng versions 1.0.7, July 1, 2000 through 1.6.26, Octoaber 20, 2016 are
 Copyright (c) 2000-2002, 2004, 2006-2016 Glenn Randers-Pehrson, are
 derived from libpng-1.0.6, and are distributed according to the same
 disclaimer and license as libpng-1.0.6 with the following individuals
 added to the list of Contributing Authors:
 
    Simon-Pierre Cadieux
    Eric S. Raymond
    Mans Rullgard
@@ -138,9 +138,9 @@ The Copyright owner believes that the Ex
 Number (ECCN) for libpng is EAR99, which means not subject to export
 controls or International Traffic in Arms Regulations (ITAR) because
 it is open source, publicly available software, that does not contain
 any encryption software.  See the EAR, paragraphs 734.3(b)(3) and
 734.7(b).
 
 Glenn Randers-Pehrson
 glennrp at users.sourceforge.net
-September 1, 2016
+October 20, 2016
--- a/media/libpng/MOZCHANGES
+++ b/media/libpng/MOZCHANGES
@@ -1,11 +1,13 @@
 
 Changes made to pristine libpng source by mozilla.org developers.
 
+2016/10/20  -- Synced with libpng-1.6.26 (bug #1311776).
+
 2016/09/01  -- Synced with libpng-1.6.25 (bug #1299590).
 
 2016/08/11  -- Enabled SSE2 support (bug #1276127).
 
 2016/08/06  -- Synced with libpng-1.6.24 (bug #1291986).
 
 2016/06/09  -- Synced with libpng-1.6.23 (bug #1275901).
 
--- a/media/libpng/README
+++ b/media/libpng/README
@@ -1,9 +1,9 @@
-README for libpng version 1.6.25 - September 1, 2016 (shared library 16.0)
+README for libpng version 1.6.26 - October 20, 2016 (shared library 16.0)
 See the note about version numbers near the top of png.h
 
 See INSTALL for instructions on how to install libpng.
 
 Libpng comes in several distribution formats.  Get libpng-*.tar.gz or
 libpng-*.tar.xz or if you want UNIX-style line endings in the text files,
 or lpng*.7z or lpng*.zip if you want DOS-style line endings.
 
--- a/media/libpng/apng.patch
+++ b/media/libpng/apng.patch
@@ -9,17 +9,17 @@ Index: LICENSE
 +This modified version of libpng code adds animated PNG support and is
 +released under the libpng license described below. The modifications are
 +Copyright (c) 2006-2007 Andrew Smith, Copyright (c) 2008-2016 Max Stepin,
 +and are delimited by "#ifdef PNG_APNG_SUPPORTED / #endif" directives
 +surrounding them in the modified libpng source files.
 +
  This code is released under the libpng license.
  
- libpng versions 1.0.7, July 1, 2000 through 1.6.25, September 1, 2016 are
+ libpng versions 1.0.7, July 1, 2000 through 1.6.26, October 20, 2016 are
 Index: pngread.c
 ===================================================================
 --- pngread.c
 +++ pngread.c
 @@ -161,6 +161,9 @@
  
        else if (chunk_name == png_IDAT)
        {
@@ -294,29 +294,29 @@ Index: pngget.c
 Index: png.c
 ===================================================================
 --- png.c
 +++ png.c
 @@ -775,17 +775,21 @@
  #else
  #  ifdef __STDC__
     return PNG_STRING_NEWLINE \
--      "libpng version 1.6.25 - September 1, 2016" PNG_STRING_NEWLINE \
-+      "libpng version 1.6.25+apng - September 1, 2016" PNG_STRING_NEWLINE \
+-      "libpng version 1.6.26 - October 20, 2016" PNG_STRING_NEWLINE \
++      "libpng version 1.6.26+apng - October 20, 2016" PNG_STRING_NEWLINE \
        "Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson" \
        PNG_STRING_NEWLINE \
        "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
        "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
 -      PNG_STRING_NEWLINE;
 +      PNG_STRING_NEWLINE \
 +      "Portions Copyright (c) 2006-2007 Andrew Smith" PNG_STRING_NEWLINE \
 +      "Portions Copyright (c) 2008-2016 Max Stepin" PNG_STRING_NEWLINE ;
  #  else
--   return "libpng version 1.6.25 - September 1, 2016\
-+   return "libpng version 1.6.25+apng - September 1, 2016\
+-   return "libpng version 1.6.26 - October 20, 2016\
++   return "libpng version 1.6.26+apng - October 20, 2016\
        Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson\
        Copyright (c) 1996-1997 Andreas Dilger\
 -      Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
 +      Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\
 +      Portions Copyright (c) 2006-2007 Andrew Smith\
 +      Portions Copyright (c) 2008-2016 Max Stepin";
  #  endif
  #endif
@@ -337,21 +337,21 @@ Index: png.h
 + *
   * This code is released under the libpng license.
   *
   * Some files in the "contrib" directory and some configure-generated
 @@ -314,8 +320,9 @@
   */
  
  /* Version information for png.h - this should match the version in png.c */
--#define PNG_LIBPNG_VER_STRING "1.6.25"
--#define PNG_HEADER_VERSION_STRING " libpng version 1.6.25 - September 1, 2016\n"
-+#define PNG_LIBPNG_VER_STRING "1.6.25+apng"
+-#define PNG_LIBPNG_VER_STRING "1.6.26"
+-#define PNG_HEADER_VERSION_STRING " libpng version 1.6.26 - October 20, 2016\n"
++#define PNG_LIBPNG_VER_STRING "1.6.26+apng"
 +#define PNG_HEADER_VERSION_STRING \
-+     " libpng version 1.6.25+apng - September 1, 2016\n"
++     " libpng version 1.6.26+apng - October 20, 2016\n"
  
  #define PNG_LIBPNG_VER_SONUM   16
  #define PNG_LIBPNG_VER_DLLNUM  16
 @@ -366,6 +373,10 @@
  #   include "pnglibconf.h"
  #endif
  
 +#define PNG_APNG_SUPPORTED
@@ -488,45 +488,45 @@ Index: png.h
 +#endif /* APNG */
  #endif
  
  #ifdef __cplusplus
 Index: pngpriv.h
 ===================================================================
 --- pngpriv.h
 +++ pngpriv.h
-@@ -566,6 +566,10 @@
- #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
-                    /*             0x4000 (unused) */
- #define PNG_IS_READ_STRUCT        0x8000 /* Else is a write struct */
+@@ -567,6 +567,10 @@
+ #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
+                    /*             0x4000U (unused) */
+ #define PNG_IS_READ_STRUCT        0x8000U /* Else is a write struct */
 +#ifdef PNG_APNG_SUPPORTED
-+#define PNG_HAVE_acTL            0x10000
-+#define PNG_HAVE_fcTL            0x20000
++#define PNG_HAVE_acTL            0x10000U
++#define PNG_HAVE_fcTL            0x20000U
 +#endif
  
  /* Flags for the transformations the PNG library does on the image data */
- #define PNG_BGR                 0x0001
-@@ -783,6 +787,16 @@
+ #define PNG_BGR                 0x0001U
+@@ -802,6 +806,16 @@
  #define png_tRNS PNG_U32(116,  82,  78,  83)
  #define png_zTXt PNG_U32(122,  84,  88, 116)
  
 +#ifdef PNG_APNG_SUPPORTED
 +#define png_acTL PNG_U32( 97,  99,  84,  76)
 +#define png_fcTL PNG_U32(102,  99,  84,  76)
 +#define png_fdAT PNG_U32(102, 100,  65,  84)
 +
 +/* For png_struct.apng_flags: */
-+#define PNG_FIRST_FRAME_HIDDEN       0x0001
-+#define PNG_APNG_APP                 0x0002
++#define PNG_FIRST_FRAME_HIDDEN       0x0001U
++#define PNG_APNG_APP                 0x0002U
 +#endif
 +
  /* The following will work on (signed char*) strings, whereas the get_uint_32
   * macro will fail on top-bit-set values because of the sign extension.
   */
-@@ -1489,6 +1503,49 @@
+@@ -1508,6 +1522,49 @@
  
  #endif /* PROGRESSIVE_READ */
  
 +#ifdef PNG_APNG_SUPPORTED
 +PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
 +   png_uint_32 width, png_uint_32 height,
 +   png_uint_32 x_offset, png_uint_32 y_offset,
 +   png_uint_16 delay_num, png_uint_16 delay_den,
@@ -648,17 +648,17 @@ Index: pngwrite.c
 +#ifdef PNG_WRITE_APNG_SUPPORTED
 +   if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
 +      png_error(png_ptr, "Not enough frames written");
 +#endif
 +
  #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
     if (png_ptr->num_palette_max > png_ptr->num_palette)
        png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
-@@ -2380,4 +2389,42 @@
+@@ -2382,4 +2391,42 @@
  }
  #endif /* SIMPLIFIED_WRITE_STDIO */
  #endif /* SIMPLIFIED_WRITE */
 +
 +#ifdef PNG_WRITE_APNG_SUPPORTED
 +void PNGAPI
 +png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
 +    png_bytepp row_pointers, png_uint_32 width, png_uint_32 height,
@@ -906,17 +906,17 @@ Index: pngpread.c
 +      png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
 +      return;
 +   }
 +#endif
 +
     /* This routine must process all the data it has been given
      * before returning, calling the row callback as required to
      * handle the uncompressed results.
-@@ -1079,6 +1236,18 @@
+@@ -1084,6 +1241,18 @@
     png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
  }
  
 +#ifdef PNG_READ_APNG_SUPPORTED
 +void PNGAPI
 +png_set_progressive_frame_fn(png_structp png_ptr,
 +   png_progressive_frame_ptr frame_info_fn,
 +   png_progressive_frame_ptr frame_end_fn)
@@ -941,17 +941,17 @@ Index: pngset.c
 +
 +#ifdef PNG_APNG_SUPPORTED
 +   /* for non-animated png. this may be overwritten from an acTL chunk later */
 +   info_ptr->num_frames = 1;
 +#endif
  }
  
  #ifdef PNG_oFFs_SUPPORTED
-@@ -1096,6 +1101,146 @@
+@@ -1110,6 +1115,146 @@
  }
  #endif /* sPLT */
  
 +#ifdef PNG_APNG_SUPPORTED
 +png_uint_32 PNGAPI
 +png_set_acTL(png_structp png_ptr, png_infop info_ptr,
 +    png_uint_32 num_frames, png_uint_32 num_plays)
 +{
@@ -1092,29 +1092,29 @@ Index: pngset.c
 +
  #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
  static png_byte
  check_location(png_const_structrp png_ptr, int location)
 Index: pngrutil.c
 ===================================================================
 --- pngrutil.c
 +++ pngrutil.c
-@@ -857,6 +857,11 @@
+@@ -860,6 +860,11 @@
     filter_type = buf[11];
     interlace_type = buf[12];
  
 +#ifdef PNG_READ_APNG_SUPPORTED
 +   png_ptr->first_frame_width = width;
 +   png_ptr->first_frame_height = height;
 +#endif
 +
     /* Set internal variables */
     png_ptr->width = width;
     png_ptr->height = height;
-@@ -2757,6 +2762,180 @@
+@@ -2760,6 +2765,180 @@
  }
  #endif
  
 +#ifdef PNG_READ_APNG_SUPPORTED
 +void /* PRIVATE */
 +png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 +{
 +    png_byte data[8];
@@ -1285,17 +1285,17 @@ Index: pngrutil.c
 +
 +    png_ptr->next_seq_num++;
 +}
 +#endif /* READ_APNG */
 +
  #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
  /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
  static int
-@@ -4016,6 +4195,38 @@
+@@ -4022,6 +4201,38 @@
           uInt avail_in;
           png_bytep buffer;
  
 +#ifdef PNG_READ_APNG_SUPPORTED
 +         png_uint_32 bytes_to_skip = 0;
 +
 +         while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
 +         {
@@ -1324,35 +1324,35 @@ Index: pngrutil.c
 +
 +               png_ptr->idat_size -= 4;
 +            }
 +         }
 +#else
           while (png_ptr->idat_size == 0)
           {
              png_crc_finish(png_ptr, 0);
-@@ -4027,6 +4238,7 @@
+@@ -4033,6 +4244,7 @@
              if (png_ptr->chunk_name != png_IDAT)
                 png_error(png_ptr, "Not enough image data");
           }
 +#endif /* READ_APNG */
  
           avail_in = png_ptr->IDAT_read_size;
  
-@@ -4090,6 +4302,9 @@
+@@ -4096,6 +4308,9 @@
  
           png_ptr->mode |= PNG_AFTER_IDAT;
           png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
 +#ifdef PNG_READ_APNG_SUPPORTED
 +         png_ptr->num_frames_read++;
 +#endif
  
           if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
              png_chunk_benign_error(png_ptr, "Extra compressed data");
-@@ -4528,4 +4743,80 @@
+@@ -4542,4 +4757,80 @@
  
     png_ptr->flags |= PNG_FLAG_ROW_INIT;
  }
 +
 +#ifdef PNG_READ_APNG_SUPPORTED
 +/* This function is to be called after the main IDAT set has been read and
 + * before a new IDAT is read. It resets some parts of png_ptr
 + * to make them usable by the read functions again */
--- a/media/libpng/libpng-manual.txt
+++ b/media/libpng/libpng-manual.txt
@@ -1,22 +1,22 @@
 libpng-manual.txt - A description on how to use and modify libpng
 
- libpng version 1.6.25 - September 1, 2016
+ libpng version 1.6.26 - October 20, 2016
  Updated and distributed by Glenn Randers-Pehrson
  <glennrp at users.sourceforge.net>
  Copyright (c) 1998-2016 Glenn Randers-Pehrson
 
  This document is released under the libpng license.
  For conditions of distribution and use, see the disclaimer
  and license in png.h
 
  Based on:
 
- libpng versions 0.97, January 1998, through 1.6.25 - September 1, 2016
+ libpng versions 0.97, January 1998, through 1.6.26 - October 20, 2016
  Updated and distributed by Glenn Randers-Pehrson
  Copyright (c) 1998-2016 Glenn Randers-Pehrson
 
  libpng 1.0 beta 6 - version 0.96 - May 28, 1997
  Updated and distributed by Andreas Dilger
  Copyright (c) 1996, 1997 Andreas Dilger
 
  libpng 1.0 beta 2 - version 0.88 - January 26, 1996
@@ -462,34 +462,38 @@ instead of setting a flag to be acted up
 
 If you want CRC errors to be handled in a different manner than
 the default, use
 
     png_set_crc_action(png_ptr, crit_action, ancil_action);
 
 The values for png_set_crc_action() say how libpng is to handle CRC errors in
 ancillary and critical chunks, and whether to use the data contained
-therein.  Note that it is impossible to "discard" data in a critical
-chunk.
+therein. Starting with libpng-1.6.26, this also governs how an ADLER32 error
+is handled while reading the IDAT chunk. Note that it is impossible to
+"discard" data in a critical chunk.
 
 Choices for (int) crit_action are
    PNG_CRC_DEFAULT      0  error/quit
    PNG_CRC_ERROR_QUIT   1  error/quit
    PNG_CRC_WARN_USE     3  warn/use data
    PNG_CRC_QUIET_USE    4  quiet/use data
    PNG_CRC_NO_CHANGE    5  use the current value
 
 Choices for (int) ancil_action are
    PNG_CRC_DEFAULT      0  error/quit
    PNG_CRC_ERROR_QUIT   1  error/quit
    PNG_CRC_WARN_DISCARD 2  warn/discard data
    PNG_CRC_WARN_USE     3  warn/use data
    PNG_CRC_QUIET_USE    4  quiet/use data
    PNG_CRC_NO_CHANGE    5  use the current value
 
+When the setting for crit_action is PNG_CRC_QUIET_USE, the CRC and ADLER32
+checksums are not only ignored, but they are not evaluated.
+
 Setting up callback code
 
 You can set up a callback function to handle any unknown chunks in the
 input stream. You must supply the function
 
     read_chunk_callback(png_structp png_ptr,
          png_unknown_chunkp chunk);
     {
@@ -5330,32 +5334,33 @@ with "defined".
 We express integer constants that are used as bit masks in hex format,
 with an even number of lower-case hex digits, and to make them unsigned
 (e.g., 0x00U, 0xffU, 0x0100U) and long if they are greater than 0x7fff
 (e.g., 0xffffUL).
 
 We prefer to use underscores rather than camelCase in names, except
 for a few type names that we inherit from zlib.h.
 
-We prefer "if (something != 0)" and "if (something == 0)"
-over "if (something)" and if "(!something)", respectively.
+We prefer "if (something != 0)" and "if (something == 0)" over
+"if (something)" and if "(!something)", respectively, and for pointers
+we prefer "if (some_pointer != NULL)" or "if (some_pointer == NULL)". 
 
 We do not use the TAB character for indentation in the C sources.
 
 Lines do not exceed 80 characters.
 
 Other rules can be inferred by inspecting the libpng source.
 
 XVI. Y2K Compliance in libpng
 
 Since the PNG Development group is an ad-hoc body, we can't make
 an official declaration.
 
 This is your unofficial assurance that libpng from version 0.71 and
-upward through 1.6.25 are Y2K compliant.  It is my belief that earlier
+upward through 1.6.26 are Y2K compliant.  It is my belief that earlier
 versions were also Y2K compliant.
 
 Libpng only has two year fields.  One is a 2-byte unsigned integer
 that will hold years up to 65535.  The other, which is deprecated,
 holds the date in text format, and will hold years up to 9999.
 
 The integer is
     "png_uint_16 year" in png_time_struct.
--- a/media/libpng/png.c
+++ b/media/libpng/png.c
@@ -1,25 +1,25 @@
 
 /* png.c - location for general purpose libpng functions
  *
- * Last changed in libpng 1.6.25 [September 1, 2016]
+ * Last changed in libpng 1.6.26 [October 20, 2016]
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  */
 
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_25 Your_png_h_is_not_version_1_6_25;
+typedef png_libpng_version_1_6_26 Your_png_h_is_not_version_1_6_26;
 
 /* Tells libpng that we have already handled the first "num_bytes" bytes
  * of the PNG file signature.  If the PNG data is embedded into another
  * stream we can set num_bytes = 8 so that libpng will not attempt to read
  * or write any of the magic bytes before it starts on the IHDR.
  */
 
 #ifdef PNG_READ_SUPPORTED
@@ -453,17 +453,17 @@ png_free_data(png_const_structrp png_ptr
 {
    png_debug(1, "in png_free_data");
 
    if (png_ptr == NULL || info_ptr == NULL)
       return;
 
 #ifdef PNG_TEXT_SUPPORTED
    /* Free text item num or (if num == -1) all text items */
-   if (info_ptr->text != 0 &&
+   if (info_ptr->text != NULL &&
        ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0)
    {
       if (num != -1)
       {
          png_free(png_ptr, info_ptr->text[num].key);
          info_ptr->text[num].key = NULL;
       }
 
@@ -536,17 +536,17 @@ png_free_data(png_const_structrp png_ptr
       info_ptr->iccp_name = NULL;
       info_ptr->iccp_profile = NULL;
       info_ptr->valid &= ~PNG_INFO_iCCP;
    }
 #endif
 
 #ifdef PNG_sPLT_SUPPORTED
    /* Free a given sPLT entry, or (if num == -1) all sPLT entries */
-   if (info_ptr->splt_palettes != 0 &&
+   if (info_ptr->splt_palettes != NULL &&
        ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0)
    {
       if (num != -1)
       {
          png_free(png_ptr, info_ptr->splt_palettes[num].name);
          png_free(png_ptr, info_ptr->splt_palettes[num].entries);
          info_ptr->splt_palettes[num].name = NULL;
          info_ptr->splt_palettes[num].entries = NULL;
@@ -566,17 +566,17 @@ png_free_data(png_const_structrp png_ptr
          info_ptr->splt_palettes = NULL;
          info_ptr->splt_palettes_num = 0;
          info_ptr->valid &= ~PNG_INFO_sPLT;
       }
    }
 #endif
 
 #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
-   if (info_ptr->unknown_chunks != 0 &&
+   if (info_ptr->unknown_chunks != NULL &&
        ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0)
    {
       if (num != -1)
       {
           png_free(png_ptr, info_ptr->unknown_chunks[num].data);
           info_ptr->unknown_chunks[num].data = NULL;
       }
 
@@ -612,17 +612,17 @@ png_free_data(png_const_structrp png_ptr
       info_ptr->valid &= ~PNG_INFO_PLTE;
       info_ptr->num_palette = 0;
    }
 
 #ifdef PNG_INFO_IMAGE_SUPPORTED
    /* Free any image bits attached to the info structure */
    if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0)
    {
-      if (info_ptr->row_pointers != 0)
+      if (info_ptr->row_pointers != NULL)
       {
          png_uint_32 row;
          for (row = 0; row < info_ptr->height; row++)
             png_free(png_ptr, info_ptr->row_pointers[row]);
 
          png_free(png_ptr, info_ptr->row_pointers);
          info_ptr->row_pointers = NULL;
       }
@@ -679,17 +679,17 @@ png_init_io(png_structrp png_ptr, png_FI
  *
  * Where UNSIGNED_MAX is the appropriate maximum unsigned value, so when the
  * negative integral value is added the result will be an unsigned value
  * correspnding to the 2's complement representation.
  */
 void PNGAPI
 png_save_int_32(png_bytep buf, png_int_32 i)
 {
-   png_save_uint_32(buf, i);
+   png_save_uint_32(buf, (png_uint_32)i);
 }
 #  endif
 
 #  ifdef PNG_TIME_RFC1123_SUPPORTED
 /* Convert the supplied time into an RFC 1123 string suitable for use in
  * a "Creation Time" or other text-based time string.
  */
 int PNGAPI
@@ -770,26 +770,26 @@ png_const_charp PNGAPI
 png_get_copyright(png_const_structrp png_ptr)
 {
    PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */
 #ifdef PNG_STRING_COPYRIGHT
    return PNG_STRING_COPYRIGHT
 #else
 #  ifdef __STDC__
    return PNG_STRING_NEWLINE \
-      "libpng version 1.6.25+apng - September 1, 2016" PNG_STRING_NEWLINE \
+      "libpng version 1.6.26+apng - October 20, 2016" PNG_STRING_NEWLINE \
       "Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson" \
       PNG_STRING_NEWLINE \
       "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
       "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
       PNG_STRING_NEWLINE \
       "Portions Copyright (c) 2006-2007 Andrew Smith" PNG_STRING_NEWLINE \
       "Portions Copyright (c) 2008-2016 Max Stepin" PNG_STRING_NEWLINE ;
 #  else
-   return "libpng version 1.6.25+apng - September 1, 2016\
+   return "libpng version 1.6.26+apng - October 20, 2016\
       Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson\
       Copyright (c) 1996-1997 Andreas Dilger\
       Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\
       Portions Copyright (c) 2006-2007 Andrew Smith\
       Portions Copyright (c) 2008-2016 Max Stepin";
 #  endif
 #endif
 }
@@ -2528,17 +2528,17 @@ png_check_IHDR(png_const_structrp png_pt
    }
 
    if (width > PNG_UINT_31_MAX)
    {
       png_warning(png_ptr, "Invalid image width in IHDR");
       error = 1;
    }
 
-   if (png_gt(((width + 7) & (~7)),
+   if (png_gt(((width + 7) & (~7U)),
        ((PNG_SIZE_MAX
            - 48        /* big_row_buf hack */
            - 1)        /* filter byte */
            / 8)        /* 8-byte RGBA pixels */
            - 1))       /* extra max_pixel_depth pad */
    {
       /* The size of the row must be within the limits of this architecture.
        * Because the read code can perform arbitrary transformations the
@@ -2939,17 +2939,17 @@ png_ascii_from_fp(png_const_structrp png
             unsigned int czero, clead, cdigits;
             char exponent[10];
 
             /* Allow up to two leading zeros - this will not lengthen
              * the number compared to using E-n.
              */
             if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */
             {
-               czero = -exp_b10; /* PLUS 2 digits: TOTAL 3 */
+               czero = (unsigned int)(-exp_b10); /* PLUS 2 digits: TOTAL 3 */
                exp_b10 = 0;      /* Dot added below before first output. */
             }
             else
                czero = 0;    /* No zeros to add */
 
             /* Generate the digit list, stripping trailing zeros and
              * inserting a '.' before a digit if the exponent is 0.
              */
@@ -3117,21 +3117,21 @@ png_ascii_from_fp(png_const_structrp png
              * better optimization.
              */
             {
                unsigned int uexp_b10;
 
                if (exp_b10 < 0)
                {
                   *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */
-                  uexp_b10 = -exp_b10;
+                  uexp_b10 = (unsigned int)(-exp_b10);
                }
 
                else
-                  uexp_b10 = exp_b10;
+                  uexp_b10 = (unsigned int)exp_b10;
 
                cdigits = 0;
 
                while (uexp_b10 > 0)
                {
                   exponent[cdigits++] = (char)(48 + uexp_b10 % 10);
                   uexp_b10 /= 10;
                }
@@ -3183,19 +3183,19 @@ png_ascii_from_fixed(png_const_structrp 
     * trailing \0, 13 characters:
     */
    if (size > 12)
    {
       png_uint_32 num;
 
       /* Avoid overflow here on the minimum integer. */
       if (fp < 0)
-         *ascii++ = 45, num = -fp;
+         *ascii++ = 45, num = (png_uint_32)(-fp);
       else
-         num = fp;
+         num = (png_uint_32)fp;
 
       if (num <= 0x80000000) /* else overflowed */
       {
          unsigned int ndigits = 0, first = 16 /* flag value */;
          char digits[10];
 
          while (num)
          {
--- a/media/libpng/png.h
+++ b/media/libpng/png.h
@@ -1,23 +1,23 @@
 
 /* png.h - header file for PNG reference library
  *
- * libpng version 1.6.25, September 1, 2016
+ * libpng version 1.6.26, October 20, 2016
  *
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license (See LICENSE, below)
  *
  * Authors and maintainers:
  *   libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
  *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
- *   libpng versions 0.97, January 1998, through 1.6.25, September 1, 2016:
+ *   libpng versions 0.97, January 1998, through 1.6.26, October 20, 2016:
  *     Glenn Randers-Pehrson.
  *   See also "Contributing Authors", below.
  */
 
 /*
  * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
  *
  * If you modify libpng you may insert additional notices immediately following
@@ -36,17 +36,17 @@
  * #ifndef PNG_INTEL_SSE_OPT / #endif directives.
  *
  * This code is released under the libpng license.
  *
  * Some files in the "contrib" directory and some configure-generated
  * files that are distributed with libpng have other copyright owners and
  * are released under other open source licenses.
  *
- * libpng versions 1.0.7, July 1, 2000 through 1.6.25, September 1, 2016 are
+ * libpng versions 1.0.7, July 1, 2000 through 1.6.26, October 20, 2016 are
  * Copyright (c) 2000-2002, 2004, 2006-2016 Glenn Randers-Pehrson, are
  * derived from libpng-1.0.6, and are distributed according to the same
  * disclaimer and license as libpng-1.0.6 with the following individuals
  * added to the list of Contributing Authors:
  *
  *    Simon-Pierre Cadieux
  *    Eric S. Raymond
  *    Mans Rullgard
@@ -225,17 +225,17 @@
  *    1.0.7                    1    10007  (still compatible)
  *    ...
  *    1.0.19                  10    10019  10.so.0.19[.0]
  *    ...
  *    1.2.56                  13    10256  12.so.0.56[.0]
  *    ...
  *    1.5.27                  15    10527  15.so.15.27[.0]
  *    ...
- *    1.6.25                  16    10625  16.so.16.25[.0]
+ *    1.6.26                  16    10626  16.so.16.26[.0]
  *
  *    Henceforth the source version will match the shared-library major
  *    and minor numbers; the shared-library major version number will be
  *    used for changes in backward compatibility, as it is intended.  The
  *    PNG_LIBPNG_VER macro, which is not used within libpng but is available
  *    for applications, is an unsigned integer of the form xyyzz corresponding
  *    to the source version x.y.z (leading zeros in y and z).  Beta versions
  *    were given the previous public release number plus a letter, until
@@ -253,23 +253,23 @@
  * is available as a W3C Recommendation and as an ISO Specification,
  * <http://www.w3.org/TR/2003/REC-PNG-20031110/
  */
 
 /*
  * Y2K compliance in libpng:
  * =========================
  *
- *    September 1, 2016
+ *    October 20, 2016
  *
  *    Since the PNG Development group is an ad-hoc body, we can't make
  *    an official declaration.
  *
  *    This is your unofficial assurance that libpng from version 0.71 and
- *    upward through 1.6.25 are Y2K compliant.  It is my belief that
+ *    upward through 1.6.26 are Y2K compliant.  It is my belief that
  *    earlier versions were also Y2K compliant.
  *
  *    Libpng only has two year fields.  One is a 2-byte unsigned integer
  *    that will hold years up to 65535.  The other, which is deprecated,
  *    holds the date in text format, and will hold years up to 9999.
  *
  *    The integer is
  *        "png_uint_16 year" in png_time_struct.
@@ -321,27 +321,27 @@
  * file has been stripped from your copy of libpng, you can find it at
  * <http://www.libpng.org/pub/png/libpng-manual.txt>
  *
  * If you just need to read a PNG file and don't want to read the documentation
  * skip to the end of this file and read the section entitled 'simplified API'.
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.25+apng"
+#define PNG_LIBPNG_VER_STRING "1.6.26+apng"
 #define PNG_HEADER_VERSION_STRING \
-     " libpng version 1.6.25+apng - September 1, 2016\n"
+     " libpng version 1.6.26+apng - October 20, 2016\n"
 
 #define PNG_LIBPNG_VER_SONUM   16
 #define PNG_LIBPNG_VER_DLLNUM  16
 
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   6
-#define PNG_LIBPNG_VER_RELEASE 25
+#define PNG_LIBPNG_VER_RELEASE 26
 
 /* This should match the numeric part of the final component of
  * PNG_LIBPNG_VER_STRING, omitting any leading zero:
  */
 
 #define PNG_LIBPNG_VER_BUILD  0
 
 /* Release Status */
@@ -362,17 +362,17 @@
 #define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE
 
 /* Careful here.  At one time, Guy wanted to use 082, but that would be octal.
  * We must not include leading zeros.
  * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only
  * version 1.0.0 was mis-numbered 100 instead of 10000).  From
  * version 1.0.1 it's    xxyyzz, where x=major, y=minor, z=release
  */
-#define PNG_LIBPNG_VER 10625 /* 1.6.25 */
+#define PNG_LIBPNG_VER 10626 /* 1.6.26 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
  */
 #ifndef PNGLCONF_H
 /* If pnglibconf.h is missing, you can
  * copy scripts/pnglibconf.h.prebuilt to pnglibconf.h
  */
@@ -487,17 +487,17 @@ extern "C" {
 /* blend_op flags from inside fcTL */
 #define PNG_BLEND_OP_SOURCE        0x00
 #define PNG_BLEND_OP_OVER          0x01
 #endif /* APNG */
 
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char* png_libpng_version_1_6_25;
+typedef char* png_libpng_version_1_6_26;
 
 /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
  *
  * png_struct is the cache of information used while reading or writing a single
  * PNG file.  One of these is always required, although the simplified API
  * (below) hides the creation and destruction of it.
  */
 typedef struct png_struct_def png_struct;
--- a/media/libpng/pngconf.h
+++ b/media/libpng/pngconf.h
@@ -1,12 +1,12 @@
 
 /* pngconf.h - machine configurable file for libpng
  *
- * libpng version 1.6.25, September 1, 2016
+ * libpng version 1.6.26, October 20, 2016
  *
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
@@ -502,19 +502,19 @@
 #if INT_MIN < -2147483646 && INT_MAX > 2147483646
    typedef int png_int_32;
 #elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646
    typedef long int png_int_32;
 #else
 #  error "libpng requires a signed 32-bit (or more) type"
 #endif
 
-#if UINT_MAX > 4294967294
+#if UINT_MAX > 4294967294U
    typedef unsigned int png_uint_32;
-#elif ULONG_MAX > 4294967294
+#elif ULONG_MAX > 4294967294U
    typedef unsigned long int png_uint_32;
 #else
 #  error "libpng requires an unsigned 32-bit (or more) type"
 #endif
 
 /* Prior to 1.6.0 it was possible to disable the use of size_t, 1.6.0, however,
  * requires an ISOC90 compiler and relies on consistent behavior of sizeof.
  */
--- a/media/libpng/pngerror.c
+++ b/media/libpng/pngerror.c
@@ -1,12 +1,12 @@
 
 /* pngerror.c - stub functions for i/o and memory allocation
  *
- * Last changed in libpng 1.6.24 [August 4, 2016]
+ * Last changed in libpng 1.6.26 [October 20, 2016]
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  *
@@ -568,17 +568,17 @@ png_chunk_report(png_const_structrp png_
 
 #ifdef PNG_ERROR_TEXT_SUPPORTED
 #ifdef PNG_FLOATING_POINT_SUPPORTED
 PNG_FUNCTION(void,
 png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN)
 {
 #  define fixed_message "fixed point overflow in "
 #  define fixed_message_ln ((sizeof fixed_message)-1)
-   int  iin;
+   unsigned int  iin;
    char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT];
    memcpy(msg, fixed_message, fixed_message_ln);
    iin = 0;
    if (name != NULL)
       while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0)
       {
          msg[fixed_message_ln + iin] = name[iin];
          ++iin;
--- a/media/libpng/pngget.c
+++ b/media/libpng/pngget.c
@@ -1,12 +1,12 @@
 
 /* pngget.c - retrieval of values from info struct
  *
- * Last changed in libpng 1.6.24 [August 4, 2016]
+ * Last changed in libpng 1.6.26 [October 20, 2016]
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  *
@@ -333,17 +333,17 @@ ppi_from_ppm(png_uint_32 ppm)
    return (ppm + 16) >> 5;/* .00000110100000001001110101001001 */
 #else
    /* The argument is a PNG unsigned integer, so it is not permitted
     * to be bigger than 2^31.
     */
    png_fixed_point result;
    if (ppm <= PNG_UINT_31_MAX && png_muldiv(&result, (png_int_32)ppm, 127,
        5000) != 0)
-      return result;
+      return (png_uint_32)result;
 
    /* Overflow. */
    return 0;
 #endif
 }
 
 png_uint_32 PNGAPI
 png_get_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr)
--- a/media/libpng/pngmem.c
+++ b/media/libpng/pngmem.c
@@ -1,12 +1,12 @@
 
 /* pngmem.c - stub functions for memory allocation
  *
- * Last changed in libpng 1.6.24 [August 4, 2016%]
+ * Last changed in libpng 1.6.26 [October 20, 2016]
  * Copyright (c) 1998-2002,2004,2006-2014,2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  *
@@ -104,17 +104,17 @@ png_malloc_base,(png_const_structrp png_
 /* This is really here only to work round a spurious warning in GCC 4.6 and 4.7
  * that arises because of the checks in png_realloc_array that are repeated in
  * png_malloc_array.
  */
 static png_voidp
 png_malloc_array_checked(png_const_structrp png_ptr, int nelements,
     size_t element_size)
 {
-   png_alloc_size_t req = nelements; /* known to be > 0 */
+   png_alloc_size_t req = (png_alloc_size_t)nelements; /* known to be > 0 */
 
    if (req <= PNG_SIZE_MAX/element_size)
       return png_malloc_base(png_ptr, req * element_size);
 
    /* The failure case when the request is too large */
    return NULL;
 }
 
--- a/media/libpng/pngpread.c
+++ b/media/libpng/pngpread.c
@@ -836,17 +836,22 @@ png_process_IDAT_data(png_structrp png_p
          /* This may be a truncated stream (missing or
           * damaged end code).  Treat that as a warning.
           */
          if (png_ptr->row_number >= png_ptr->num_rows ||
              png_ptr->pass > 6)
             png_warning(png_ptr, "Truncated compressed data in IDAT");
 
          else
-            png_error(png_ptr, "Decompression error in IDAT");
+         {
+            if (ret == Z_DATA_ERROR)
+               png_benign_error(png_ptr, "IDAT: ADLER32 checksum mismatch");
+            else
+               png_error(png_ptr, "Decompression error in IDAT");
+         }
 
          /* Skip the check on unprocessed input */
          return;
       }
 
       /* Did inflate output any data? */
       if (png_ptr->zstream.next_out != png_ptr->row_buf)
       {
--- a/media/libpng/pngpriv.h
+++ b/media/libpng/pngpriv.h
@@ -1,12 +1,12 @@
 
 /* pngpriv.h - private declarations for use inside libpng
  *
- * Last changed in libpng 1.6.25 [September 1, 2016]
+ * Last changed in libpng 1.6.26 [October 20, 2016]
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  */
@@ -564,123 +564,124 @@
 #     endif
       /* Else leave png_alignof undefined to prevent use thereof */
 #  endif
 #endif
 
 /* This implicitly assumes alignment is always to a power of 2. */
 #ifdef png_alignof
 #  define png_isaligned(ptr, type)\
-   ((((const char*)ptr-(const char*)0) & (png_alignof(type)-1)) == 0)
+   (((type)((const char*)ptr-(const char*)0) & \
+   (type)(png_alignof(type)-1)) == 0)
 #else
 #  define png_isaligned(ptr, type) 0
 #endif
 
 /* End of memory model/platform independent support */
 /* End of 1.5.0beta36 move from pngconf.h */
 
 /* CONSTANTS and UTILITY MACROS
  * These are used internally by libpng and not exposed in the API
  */
 
 /* Various modes of operation.  Note that after an init, mode is set to
  * zero automatically when the structure is created.  Three of these
  * are defined in png.h because they need to be visible to applications
  * that call png_set_unknown_chunk().
  */
-/* #define PNG_HAVE_IHDR            0x01 (defined in png.h) */
-/* #define PNG_HAVE_PLTE            0x02 (defined in png.h) */
-#define PNG_HAVE_IDAT               0x04
-/* #define PNG_AFTER_IDAT           0x08 (defined in png.h) */
-#define PNG_HAVE_IEND               0x10
-                   /*               0x20 (unused) */
-                   /*               0x40 (unused) */
-                   /*               0x80 (unused) */
-#define PNG_HAVE_CHUNK_HEADER      0x100
-#define PNG_WROTE_tIME             0x200
-#define PNG_WROTE_INFO_BEFORE_PLTE 0x400
-#define PNG_BACKGROUND_IS_GRAY     0x800
-#define PNG_HAVE_PNG_SIGNATURE    0x1000
-#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
-                   /*             0x4000 (unused) */
-#define PNG_IS_READ_STRUCT        0x8000 /* Else is a write struct */
+/* #define PNG_HAVE_IHDR            0x01U (defined in png.h) */
+/* #define PNG_HAVE_PLTE            0x02U (defined in png.h) */
+#define PNG_HAVE_IDAT               0x04U
+/* #define PNG_AFTER_IDAT           0x08U (defined in png.h) */
+#define PNG_HAVE_IEND               0x10U
+                   /*               0x20U (unused) */
+                   /*               0x40U (unused) */
+                   /*               0x80U (unused) */
+#define PNG_HAVE_CHUNK_HEADER      0x100U
+#define PNG_WROTE_tIME             0x200U
+#define PNG_WROTE_INFO_BEFORE_PLTE 0x400U
+#define PNG_BACKGROUND_IS_GRAY     0x800U
+#define PNG_HAVE_PNG_SIGNATURE    0x1000U
+#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
+                   /*             0x4000U (unused) */
+#define PNG_IS_READ_STRUCT        0x8000U /* Else is a write struct */
 #ifdef PNG_APNG_SUPPORTED
-#define PNG_HAVE_acTL            0x10000
-#define PNG_HAVE_fcTL            0x20000
+#define PNG_HAVE_acTL            0x10000U
+#define PNG_HAVE_fcTL            0x20000U
 #endif
 
 /* Flags for the transformations the PNG library does on the image data */
-#define PNG_BGR                 0x0001
-#define PNG_INTERLACE           0x0002
-#define PNG_PACK                0x0004
-#define PNG_SHIFT               0x0008
-#define PNG_SWAP_BYTES          0x0010
-#define PNG_INVERT_MONO         0x0020
-#define PNG_QUANTIZE            0x0040
-#define PNG_COMPOSE             0x0080     /* Was PNG_BACKGROUND */
-#define PNG_BACKGROUND_EXPAND   0x0100
-#define PNG_EXPAND_16           0x0200     /* Added to libpng 1.5.2 */
-#define PNG_16_TO_8             0x0400     /* Becomes 'chop' in 1.5.4 */
-#define PNG_RGBA                0x0800
-#define PNG_EXPAND              0x1000
-#define PNG_GAMMA               0x2000
-#define PNG_GRAY_TO_RGB         0x4000
-#define PNG_FILLER              0x8000
-#define PNG_PACKSWAP           0x10000
-#define PNG_SWAP_ALPHA         0x20000
-#define PNG_STRIP_ALPHA        0x40000
-#define PNG_INVERT_ALPHA       0x80000
-#define PNG_USER_TRANSFORM    0x100000
-#define PNG_RGB_TO_GRAY_ERR   0x200000
-#define PNG_RGB_TO_GRAY_WARN  0x400000
-#define PNG_RGB_TO_GRAY       0x600000 /* two bits, RGB_TO_GRAY_ERR|WARN */
-#define PNG_ENCODE_ALPHA      0x800000 /* Added to libpng-1.5.4 */
-#define PNG_ADD_ALPHA        0x1000000 /* Added to libpng-1.2.7 */
-#define PNG_EXPAND_tRNS      0x2000000 /* Added to libpng-1.2.9 */
-#define PNG_SCALE_16_TO_8    0x4000000 /* Added to libpng-1.5.4 */
-                       /*    0x8000000 unused */
-                       /*   0x10000000 unused */
-                       /*   0x20000000 unused */
-                       /*   0x40000000 unused */
+#define PNG_BGR                 0x0001U
+#define PNG_INTERLACE           0x0002U
+#define PNG_PACK                0x0004U
+#define PNG_SHIFT               0x0008U
+#define PNG_SWAP_BYTES          0x0010U
+#define PNG_INVERT_MONO         0x0020U
+#define PNG_QUANTIZE            0x0040U
+#define PNG_COMPOSE             0x0080U    /* Was PNG_BACKGROUND */
+#define PNG_BACKGROUND_EXPAND   0x0100U
+#define PNG_EXPAND_16           0x0200U    /* Added to libpng 1.5.2 */
+#define PNG_16_TO_8             0x0400U    /* Becomes 'chop' in 1.5.4 */
+#define PNG_RGBA                0x0800U
+#define PNG_EXPAND              0x1000U
+#define PNG_GAMMA               0x2000U
+#define PNG_GRAY_TO_RGB         0x4000U
+#define PNG_FILLER              0x8000U
+#define PNG_PACKSWAP           0x10000U
+#define PNG_SWAP_ALPHA         0x20000U
+#define PNG_STRIP_ALPHA        0x40000U
+#define PNG_INVERT_ALPHA       0x80000U
+#define PNG_USER_TRANSFORM    0x100000U
+#define PNG_RGB_TO_GRAY_ERR   0x200000U
+#define PNG_RGB_TO_GRAY_WARN  0x400000U
+#define PNG_RGB_TO_GRAY       0x600000U /* two bits, RGB_TO_GRAY_ERR|WARN */
+#define PNG_ENCODE_ALPHA      0x800000U /* Added to libpng-1.5.4 */
+#define PNG_ADD_ALPHA        0x1000000U /* Added to libpng-1.2.7 */
+#define PNG_EXPAND_tRNS      0x2000000U /* Added to libpng-1.2.9 */
+#define PNG_SCALE_16_TO_8    0x4000000U /* Added to libpng-1.5.4 */
+                       /*    0x8000000U unused */
+                       /*   0x10000000U unused */
+                       /*   0x20000000U unused */
+                       /*   0x40000000U unused */
 /* Flags for png_create_struct */
-#define PNG_STRUCT_PNG   0x0001
-#define PNG_STRUCT_INFO  0x0002
+#define PNG_STRUCT_PNG   0x0001U
+#define PNG_STRUCT_INFO  0x0002U
 
 /* Flags for the png_ptr->flags rather than declaring a byte for each one */
-#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY     0x0001
-#define PNG_FLAG_ZSTREAM_INITIALIZED      0x0002 /* Added to libpng-1.6.0 */
-                                  /*      0x0004    unused */
-#define PNG_FLAG_ZSTREAM_ENDED            0x0008 /* Added to libpng-1.6.0 */
-                                  /*      0x0010    unused */
-                                  /*      0x0020    unused */
-#define PNG_FLAG_ROW_INIT                 0x0040
-#define PNG_FLAG_FILLER_AFTER             0x0080
-#define PNG_FLAG_CRC_ANCILLARY_USE        0x0100
-#define PNG_FLAG_CRC_ANCILLARY_NOWARN     0x0200
-#define PNG_FLAG_CRC_CRITICAL_USE         0x0400
-#define PNG_FLAG_CRC_CRITICAL_IGNORE      0x0800
-#define PNG_FLAG_ASSUME_sRGB              0x1000 /* Added to libpng-1.5.4 */
-#define PNG_FLAG_OPTIMIZE_ALPHA           0x2000 /* Added to libpng-1.5.4 */
-#define PNG_FLAG_DETECT_UNINITIALIZED     0x4000 /* Added to libpng-1.5.4 */
-/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS      0x8000 */
-/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS      0x10000 */
-#define PNG_FLAG_LIBRARY_MISMATCH        0x20000
-#define PNG_FLAG_STRIP_ERROR_NUMBERS     0x40000
-#define PNG_FLAG_STRIP_ERROR_TEXT        0x80000
-#define PNG_FLAG_BENIGN_ERRORS_WARN     0x100000 /* Added to libpng-1.4.0 */
-#define PNG_FLAG_APP_WARNINGS_WARN      0x200000 /* Added to libpng-1.6.0 */
-#define PNG_FLAG_APP_ERRORS_WARN        0x400000 /* Added to libpng-1.6.0 */
-                                  /*    0x800000    unused */
-                                  /*   0x1000000    unused */
-                                  /*   0x2000000    unused */
-                                  /*   0x4000000    unused */
-                                  /*   0x8000000    unused */
-                                  /*  0x10000000    unused */
-                                  /*  0x20000000    unused */
-                                  /*  0x40000000    unused */
+#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY     0x0001U
+#define PNG_FLAG_ZSTREAM_INITIALIZED      0x0002U /* Added to libpng-1.6.0 */
+                                  /*      0x0004U    unused */
+#define PNG_FLAG_ZSTREAM_ENDED            0x0008U /* Added to libpng-1.6.0 */
+                                  /*      0x0010U    unused */
+                                  /*      0x0020U    unused */
+#define PNG_FLAG_ROW_INIT                 0x0040U
+#define PNG_FLAG_FILLER_AFTER             0x0080U
+#define PNG_FLAG_CRC_ANCILLARY_USE        0x0100U
+#define PNG_FLAG_CRC_ANCILLARY_NOWARN     0x0200U
+#define PNG_FLAG_CRC_CRITICAL_USE         0x0400U
+#define PNG_FLAG_CRC_CRITICAL_IGNORE      0x0800U
+#define PNG_FLAG_ASSUME_sRGB              0x1000U /* Added to libpng-1.5.4 */
+#define PNG_FLAG_OPTIMIZE_ALPHA           0x2000U /* Added to libpng-1.5.4 */
+#define PNG_FLAG_DETECT_UNINITIALIZED     0x4000U /* Added to libpng-1.5.4 */
+/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS      0x8000U */
+/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS      0x10000U */
+#define PNG_FLAG_LIBRARY_MISMATCH        0x20000U
+#define PNG_FLAG_STRIP_ERROR_NUMBERS     0x40000U
+#define PNG_FLAG_STRIP_ERROR_TEXT        0x80000U
+#define PNG_FLAG_BENIGN_ERRORS_WARN     0x100000U /* Added to libpng-1.4.0 */
+#define PNG_FLAG_APP_WARNINGS_WARN      0x200000U /* Added to libpng-1.6.0 */
+#define PNG_FLAG_APP_ERRORS_WARN        0x400000U /* Added to libpng-1.6.0 */
+                                  /*    0x800000U    unused */
+                                  /*   0x1000000U    unused */
+                                  /*   0x2000000U    unused */
+                                  /*   0x4000000U    unused */
+                                  /*   0x8000000U    unused */
+                                  /*  0x10000000U    unused */
+                                  /*  0x20000000U    unused */
+                                  /*  0x40000000U    unused */
 
 #define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \
                                      PNG_FLAG_CRC_ANCILLARY_NOWARN)
 
 #define PNG_FLAG_CRC_CRITICAL_MASK  (PNG_FLAG_CRC_CRITICAL_USE | \
                                      PNG_FLAG_CRC_CRITICAL_IGNORE)
 
 #define PNG_FLAG_CRC_MASK           (PNG_FLAG_CRC_ANCILLARY_MASK | \
@@ -704,16 +705,34 @@
 #define PNG_DIV257(v16) PNG_DIV65535((png_uint_32)(v16) * 255)
 
 /* Added to libpng-1.2.6 JB */
 #define PNG_ROWBYTES(pixel_bits, width) \
     ((pixel_bits) >= 8 ? \
     ((png_size_t)(width) * (((png_size_t)(pixel_bits)) >> 3)) : \
     (( ((png_size_t)(width) * ((png_size_t)(pixel_bits))) + 7) >> 3) )
 
+/* This returns the number of trailing bits in the last byte of a row, 0 if the
+ * last byte is completely full of pixels.  It is, in principle, (pixel_bits x
+ * width) % 8, but that would overflow for large 'width'.  The second macro is
+ * the same except that it returns the number of unused bits in the last byte;
+ * (8-TRAILBITS), but 0 when TRAILBITS is 0.
+ *
+ * NOTE: these macros are intended to be self-evidently correct and never
+ * overflow on the assumption that pixel_bits is in the range 0..255.  The
+ * arguments are evaluated only once and they can be signed (e.g. as a result of
+ * the integral promotions).  The result of the expression always has type
+ * (png_uint_32), however the compiler always knows it is in the range 0..7.
+ */
+#define PNG_TRAILBITS(pixel_bits, width) \
+    (((pixel_bits) * ((width) % (png_uint_32)8)) % 8)
+
+#define PNG_PADBITS(pixel_bits, width) \
+    ((8 - PNG_TRAILBITS(pixel_bits, width)) % 8)
+
 /* PNG_OUT_OF_RANGE returns true if value is outside the range
  * ideal-delta..ideal+delta.  Each argument is evaluated twice.
  * "ideal" and "delta" should be constants, normally simple
  * integers, "value" a variable. Added to libpng-1.2.6 JB
  */
 #define PNG_OUT_OF_RANGE(value, ideal, delta) \
    ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) )
 
@@ -824,18 +843,18 @@
 #define png_zTXt PNG_U32(122,  84,  88, 116)
 
 #ifdef PNG_APNG_SUPPORTED
 #define png_acTL PNG_U32( 97,  99,  84,  76)
 #define png_fcTL PNG_U32(102,  99,  84,  76)
 #define png_fdAT PNG_U32(102, 100,  65,  84)
 
 /* For png_struct.apng_flags: */
-#define PNG_FIRST_FRAME_HIDDEN       0x0001
-#define PNG_APNG_APP                 0x0002
+#define PNG_FIRST_FRAME_HIDDEN       0x0001U
+#define PNG_APNG_APP                 0x0002U
 #endif
 
 /* The following will work on (signed char*) strings, whereas the get_uint_32
  * macro will fail on top-bit-set values because of the sign extension.
  */
 #define PNG_CHUNK_FROM_STRING(s)\
    PNG_U32(0xff & (s)[0], 0xff & (s)[1], 0xff & (s)[2], 0xff & (s)[3])
 
@@ -1323,17 +1342,17 @@ PNG_INTERNAL_FUNCTION(void,png_read_fini
 PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr),
    PNG_EMPTY);
    /* Finish a row while reading, dealing with interlacing passes, etc. */
 #endif /* SEQUENTIAL_READ */
 
 /* Initialize the row buffers, etc. */
 PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY);
 
-#if PNG_ZLIB_VERNUM >= 0x1240
+#if ZLIB_VERNUM >= 0x1240
 PNG_INTERNAL_FUNCTION(int,png_zlib_inflate,(png_structrp png_ptr, int flush),
       PNG_EMPTY);
 #  define PNG_INFLATE(pp, flush) png_zlib_inflate(pp, flush)
 #else /* Zlib < 1.2.4 */
 #  define PNG_INFLATE(pp, flush) inflate(&(pp)->zstream, flush)
 #endif /* Zlib < 1.2.4 */
 
 #ifdef PNG_READ_TRANSFORMS_SUPPORTED
--- a/media/libpng/pngread.c
+++ b/media/libpng/pngread.c
@@ -1,12 +1,12 @@
 
 /* pngread.c - read a PNG file
  *
- * Last changed in libpng 1.6.24 [August 4, 2016]
+ * Last changed in libpng 1.6.26 [October 20, 2016]
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  *
@@ -434,19 +434,19 @@ png_do_read_intrapixel(png_row_infop row
          else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
             bytes_per_pixel = 8;
 
          else
             return;
 
          for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
          {
-            png_uint_32 s0   = (*(rp    ) << 8) | *(rp + 1);
-            png_uint_32 s1   = (*(rp + 2) << 8) | *(rp + 3);
-            png_uint_32 s2   = (*(rp + 4) << 8) | *(rp + 5);
+            png_uint_32 s0   = (png_uint_32)(*(rp    ) << 8) | *(rp + 1);
+            png_uint_32 s1   = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3);
+            png_uint_32 s2   = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5);
             png_uint_32 red  = (s0 + s1 + 65536) & 0xffff;
             png_uint_32 blue = (s2 + s1 + 65536) & 0xffff;
             *(rp    ) = (png_byte)((red >> 8) & 0xff);
             *(rp + 1) = (png_byte)(red & 0xff);
             *(rp + 4) = (png_byte)((blue >> 8) & 0xff);
             *(rp + 5) = (png_byte)(blue & 0xff);
          }
       }
@@ -1468,17 +1468,19 @@ png_gamma_not_sRGB(png_fixed_point g)
  */
 static int
 png_image_read_header(png_voidp argument)
 {
    png_imagep image = png_voidcast(png_imagep, argument);
    png_structrp png_ptr = image->opaque->png_ptr;
    png_inforp info_ptr = image->opaque->info_ptr;
 
+#ifdef PNG_BENIGN_ERRORS_SUPPORTED
    png_set_benign_errors(png_ptr, 1/*warn*/);
+#endif
    png_read_info(png_ptr, info_ptr);
 
    /* Do this the fast way; just read directly out of png_struct. */
    image->width = png_ptr->width;
    image->height = png_ptr->height;
 
    {
       png_uint_32 format = png_image_format(png_ptr);
@@ -1506,17 +1508,17 @@ png_image_read_header(png_voidp argument
 
       switch (png_ptr->color_type)
       {
          case PNG_COLOR_TYPE_GRAY:
             cmap_entries = 1U << png_ptr->bit_depth;
             break;
 
          case PNG_COLOR_TYPE_PALETTE:
-            cmap_entries = png_ptr->num_palette;
+            cmap_entries = (png_uint_32)png_ptr->num_palette;
             break;
 
          default:
             cmap_entries = 256;
             break;
       }
 
       if (cmap_entries > 256)
@@ -2041,28 +2043,28 @@ png_create_colormap_entry(png_image_read
 static int
 make_gray_file_colormap(png_image_read_control *display)
 {
    unsigned int i;
 
    for (i=0; i<256; ++i)
       png_create_colormap_entry(display, i, i, i, i, 255, P_FILE);
 
-   return i;
+   return (int)i;
 }
 
 static int
 make_gray_colormap(png_image_read_control *display)
 {
    unsigned int i;
 
    for (i=0; i<256; ++i)
       png_create_colormap_entry(display, i, i, i, i, 255, P_sRGB);
 
-   return i;
+   return (int)i;
 }
 #define PNG_GRAY_COLORMAP_ENTRIES 256
 
 static int
 make_ga_colormap(png_image_read_control *display)
 {
    unsigned int i, a;
 
@@ -2106,17 +2108,17 @@ make_ga_colormap(png_image_read_control 
    {
       unsigned int g;
 
       for (g=0; g<6; ++g)
          png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51,
              P_sRGB);
    }
 
-   return i;
+   return (int)i;
 }
 
 #define PNG_GA_COLORMAP_ENTRIES 256
 
 static int
 make_rgb_colormap(png_image_read_control *display)
 {
    unsigned int i, r;
@@ -2131,17 +2133,17 @@ make_rgb_colormap(png_image_read_control
          unsigned int b;
 
          for (b=0; b<6; ++b)
             png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255,
                 P_sRGB);
       }
    }
 
-   return i;
+   return (int)i;
 }
 
 #define PNG_RGB_COLORMAP_ENTRIES 216
 
 /* Return a palette index to the above palette given three 8-bit sRGB values. */
 #define PNG_RGB_INDEX(r,g,b) \
    ((png_byte)(6 * (6 * PNG_DIV51(r) + PNG_DIV51(g)) + PNG_DIV51(b)))
 
@@ -2324,17 +2326,17 @@ png_image_read_colormap(png_voidp argume
              * ensuring that the corresponding gray level matches the background
              * color exactly.
              */
             data_encoding = P_sRGB;
 
             if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)
                png_error(png_ptr, "gray[16] color-map: too few entries");
 
-            cmap_entries = make_gray_colormap(display);
+            cmap_entries = (unsigned int)make_gray_colormap(display);
 
             if (png_ptr->num_trans > 0)
             {
                unsigned int back_alpha;
 
                if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
                   back_alpha = 0;
 
@@ -2422,17 +2424,17 @@ png_image_read_colormap(png_voidp argume
           */
          data_encoding = P_sRGB;
 
          if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
          {
             if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)
                png_error(png_ptr, "gray+alpha color-map: too few entries");
 
-            cmap_entries = make_ga_colormap(display);
+            cmap_entries = (unsigned int)make_ga_colormap(display);
 
             background_index = PNG_CMAP_GA_BACKGROUND;
             output_processing = PNG_CMAP_GA;
          }
 
          else /* alpha is removed */
          {
             /* Alpha must be removed as the PNG data is processed when the
@@ -2456,17 +2458,17 @@ png_image_read_colormap(png_voidp argume
             {
                /* Background is gray; no special processing will be required. */
                png_color_16 c;
                png_uint_32 gray = back_g;
 
                if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)
                   png_error(png_ptr, "gray-alpha color-map: too few entries");
 
-               cmap_entries = make_gray_colormap(display);
+               cmap_entries = (unsigned int)make_gray_colormap(display);
 
                if (output_encoding == P_LINEAR)
                {
                   gray = PNG_sRGB_FROM_LINEAR(gray * 255);
 
                   /* And make sure the corresponding palette entry matches. */
                   png_create_colormap_entry(display, gray, back_g, back_g,
                       back_g, 65535, P_LINEAR);
@@ -2595,17 +2597,17 @@ png_image_read_colormap(png_voidp argume
                 * processing is required; just map the GA bytes to the right
                 * color-map entry.
                 */
                expand_tRNS = 1;
 
                if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)
                   png_error(png_ptr, "rgb[ga] color-map: too few entries");
 
-               cmap_entries = make_ga_colormap(display);
+               cmap_entries = (unsigned int)make_ga_colormap(display);
                background_index = PNG_CMAP_GA_BACKGROUND;
                output_processing = PNG_CMAP_GA;
             }
 
             else
             {
                /* Either the input or the output has no alpha channel, so there
                 * will be no non-opaque pixels in the color-map; it will just be
@@ -2621,22 +2623,22 @@ png_image_read_colormap(png_voidp argume
                 * this case and doing it in the palette; this will result in
                 * duplicate palette entries, but that's better than the
                 * alternative of double gamma correction.
                 */
                if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
                   png_ptr->num_trans > 0) &&
                   png_gamma_not_sRGB(png_ptr->colorspace.gamma) != 0)
                {
-                  cmap_entries = make_gray_file_colormap(display);
+                  cmap_entries = (unsigned int)make_gray_file_colormap(display);
                   data_encoding = P_FILE;
                }
 
                else
-                  cmap_entries = make_gray_colormap(display);
+                  cmap_entries = (unsigned int)make_gray_colormap(display);
 
                /* But if the input has alpha or transparency it must be removed
                 */
                if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
                   png_ptr->num_trans > 0)
                {
                   png_color_16 c;
                   png_uint_32 gray = back_g;
@@ -2714,17 +2716,17 @@ png_image_read_colormap(png_voidp argume
                 */
                if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
                {
                   png_uint_32 r;
 
                   if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries)
                      png_error(png_ptr, "rgb+alpha color-map: too few entries");
 
-                  cmap_entries = make_rgb_colormap(display);
+                  cmap_entries = (unsigned int)make_rgb_colormap(display);
 
                   /* Add a transparent entry. */
                   png_create_colormap_entry(display, cmap_entries, 255, 255,
                       255, 0, P_sRGB);
 
                   /* This is stored as the background index for the processing
                    * algorithm.
                    */
@@ -2763,17 +2765,17 @@ png_image_read_colormap(png_voidp argume
                    */
                   unsigned int sample_size =
                      PNG_IMAGE_SAMPLE_SIZE(output_format);
                   png_uint_32 r, g, b; /* sRGB background */
 
                   if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries)
                      png_error(png_ptr, "rgb-alpha color-map: too few entries");
 
-                  cmap_entries = make_rgb_colormap(display);
+                  cmap_entries = (unsigned int)make_rgb_colormap(display);
 
                   png_create_colormap_entry(display, cmap_entries, back_r,
                       back_g, back_b, 0/*unused*/, output_encoding);
 
                   if (output_encoding == P_LINEAR)
                   {
                      r = PNG_sRGB_FROM_LINEAR(back_r * 255);
                      g = PNG_sRGB_FROM_LINEAR(back_g * 255);
@@ -2848,17 +2850,17 @@ png_image_read_colormap(png_voidp argume
             else /* no alpha or transparency in the input */
             {
                /* Alpha in the output is irrelevant, simply map the opaque input
                 * pixels to the 6x6x6 color-map.
                 */
                if (PNG_RGB_COLORMAP_ENTRIES > image->colormap_entries)
                   png_error(png_ptr, "rgb color-map: too few entries");
 
-               cmap_entries = make_rgb_colormap(display);
+               cmap_entries = (unsigned int)make_rgb_colormap(display);
                output_processing = PNG_CMAP_RGB;
             }
          }
          break;
 
       case PNG_COLOR_TYPE_PALETTE:
          /* It's already got a color-map.  It may be necessary to eliminate the
           * tRNS entries though.
@@ -2872,21 +2874,21 @@ png_image_read_colormap(png_voidp argume
             unsigned int i;
 
             /* Just in case: */
             if (trans == NULL)
                num_trans = 0;
 
             output_processing = PNG_CMAP_NONE;
             data_encoding = P_FILE; /* Don't change from color-map indices */
-            cmap_entries = png_ptr->num_palette;
+            cmap_entries = (unsigned int)png_ptr->num_palette;
             if (cmap_entries > 256)
                cmap_entries = 256;
 
-            if (cmap_entries > image->colormap_entries)
+            if (cmap_entries > (unsigned int)image->colormap_entries)
                png_error(png_ptr, "palette color-map: too few entries");
 
             for (i=0; i < cmap_entries; ++i)
             {
                if (do_background != 0 && i < num_trans && trans[i] < 255)
                {
                   if (trans[i] == 0)
                      png_create_colormap_entry(display, i, back_r, back_g,
@@ -2988,17 +2990,17 @@ png_image_read_colormap(png_voidp argume
 
       default:
          png_error(png_ptr, "bad processing option (internal error)");
 
       bad_background:
          png_error(png_ptr, "bad background index (internal error)");
    }
 
-   display->colormap_processing = output_processing;
+   display->colormap_processing = (int)output_processing;
 
    return 1/*ok*/;
 }
 
 /* The final part of the color-map read called from png_image_finish_read. */
 static int
 png_image_read_and_map(png_voidp argument)
 {
@@ -3297,24 +3299,24 @@ png_image_read_colormapped(png_voidp arg
       display->local_row = NULL;
       png_free(png_ptr, row);
 
       return result;
    }
 
    else
    {
-      png_alloc_size_t row_bytes = display->row_bytes;
+      png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;
 
       while (--passes >= 0)
       {
          png_uint_32      y = image->height;
          png_bytep        row = png_voidcast(png_bytep, display->first_row);
 
-         while (y-- > 0)
+         for (; y > 0; --y)
          {
             png_read_row(png_ptr, row, NULL);
             row += row_bytes;
          }
       }
 
       return 1;
    }
@@ -3632,18 +3634,19 @@ png_image_read_background(png_voidp argu
           */
          {
             png_uint_16p first_row = png_voidcast(png_uint_16p,
                 display->first_row);
             /* The division by two is safe because the caller passed in a
              * stride which was multiplied by 2 (below) to get row_bytes.
              */
             ptrdiff_t    step_row = display->row_bytes / 2;
-            int preserve_alpha = (image->format & PNG_FORMAT_FLAG_ALPHA) != 0;
-            unsigned int outchannels = 1+preserve_alpha;
+            unsigned int preserve_alpha = (image->format &
+                PNG_FORMAT_FLAG_ALPHA) != 0;
+            unsigned int outchannels = 1U+preserve_alpha;
             int swap_alpha = 0;
 
 #           ifdef PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED
                if (preserve_alpha != 0 &&
                    (image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
                   swap_alpha = 1;
 #           endif
 
@@ -4130,24 +4133,24 @@ png_image_read_direct(png_voidp argument
       display->local_row = NULL;
       png_free(png_ptr, row);
 
       return result;
    }
 
    else
    {
-      png_alloc_size_t row_bytes = display->row_bytes;
+      png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;
 
       while (--passes >= 0)
       {
          png_uint_32      y = image->height;
          png_bytep        row = png_voidcast(png_bytep, display->first_row);
 
-         while (y-- > 0)
+         for (; y > 0; --y)
          {
             png_read_row(png_ptr, row, NULL);
             row += row_bytes;
          }
       }
 
       return 1;
    }
@@ -4166,29 +4169,29 @@ png_image_finish_read(png_imagep image, 
       const unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format);
 
       /* The following checks just the 'row_stride' calculation to ensure it
        * fits in a signed 32-bit value.  Because channels/components can be
        * either 1 or 2 bytes in size the length of a row can still overflow 32
        * bits; this is just to verify that the 'row_stride' argument can be
        * represented.
        */
-      if (image->width <= 0x7FFFFFFFU/channels) /* no overflow */
+      if (image->width <= 0x7fffffffU/channels) /* no overflow */
       {
          png_uint_32 check;
          const png_uint_32 png_row_stride = image->width * channels;
 
          if (row_stride == 0)
             row_stride = (png_int_32)/*SAFE*/png_row_stride;
 
          if (row_stride < 0)
-            check = -row_stride;
+            check = (png_uint_32)(-row_stride);
 
          else
-            check = row_stride;
+            check = (png_uint_32)row_stride;
 
          /* This verifies 'check', the absolute value of the actual stride
           * passed in and detects overflow in the application calculation (i.e.
           * if the app did actually pass in a non-zero 'row_stride'.
           */
          if (image->opaque != NULL && buffer != NULL && check >= png_row_stride)
          {
             /* Now check for overflow of the image buffer calculation; this
@@ -4203,17 +4206,17 @@ png_image_finish_read(png_imagep image, 
              * number of *bytes* that the application is saying are available
              * does actually fit into a 32-bit number.
              *
              * NOTE: this will be changed in 1.7 because PNG_IMAGE_BUFFER_SIZE
              * will be changed to use png_alloc_size_t; bigger images can be
              * accomodated on 64-bit systems.
              */
             if (image->height <=
-                0xFFFFFFFFU/PNG_IMAGE_PIXEL_COMPONENT_SIZE(image->format)/check)
+                0xffffffffU/PNG_IMAGE_PIXEL_COMPONENT_SIZE(image->format)/check)
             {
                if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 ||
                   (image->colormap_entries > 0 && colormap != NULL))
                {
                   int result;
                   png_image_read_control display;
 
                   memset(&display, 0, (sizeof display));
--- a/media/libpng/pngrtran.c
+++ b/media/libpng/pngrtran.c
@@ -424,34 +424,34 @@ png_set_quantize(png_structrp png_ptr, p
 
    png_ptr->transformations |= PNG_QUANTIZE;
 
    if (full_quantize == 0)
    {
       int i;
 
       png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
-          (png_uint_32)(num_palette * (sizeof (png_byte))));
+          (png_uint_32)((png_uint_32)num_palette * (sizeof (png_byte))));
       for (i = 0; i < num_palette; i++)
          png_ptr->quantize_index[i] = (png_byte)i;
    }
 
    if (num_palette > maximum_colors)
    {
       if (histogram != NULL)
       {
          /* This is easy enough, just throw out the least used colors.
           * Perhaps not the best solution, but good enough.
           */
 
          int i;
 
          /* Initialize an array to sort colors */
          png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
-             (png_uint_32)(num_palette * (sizeof (png_byte))));
+             (png_uint_32)((png_uint_32)num_palette * (sizeof (png_byte))));
 
          /* Initialize the quantize_sort array */
          for (i = 0; i < num_palette; i++)
             png_ptr->quantize_sort[i] = (png_byte)i;
 
          /* Find the least used palette entries by starting a
           * bubble sort, and running it until we have sorted
           * out enough colors.  Note that we don't care about
@@ -575,19 +575,19 @@ png_set_quantize(png_structrp png_ptr, p
          int num_new_palette;
          png_dsortp t;
          png_dsortpp hash;
 
          t = NULL;
 
          /* Initialize palette index arrays */
          png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
-             (png_uint_32)(num_palette * (sizeof (png_byte))));
+             (png_uint_32)((png_uint_32)num_palette * (sizeof (png_byte))));
          png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
-             (png_uint_32)(num_palette * (sizeof (png_byte))));
+             (png_uint_32)((png_uint_32)num_palette * (sizeof (png_byte))));
 
          /* Initialize the sort array */
          for (i = 0; i < num_palette; i++)
          {
             png_ptr->index_to_palette[i] = (png_byte)i;
             png_ptr->palette_to_index[i] = (png_byte)i;
          }
 
@@ -2145,17 +2145,17 @@ png_do_unpack(png_row_infop row_info, pn
       png_uint_32 row_width=row_info->width;
 
       switch (row_info->bit_depth)
       {
          case 1:
          {
             png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
             png_bytep dp = row + (png_size_t)row_width - 1;
-            png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
+            png_uint_32 shift = 7U - ((row_width + 7U) & 0x07);
             for (i = 0; i < row_width; i++)
             {
                *dp = (png_byte)((*sp >> shift) & 0x01);
 
                if (shift == 7)
                {
                   shift = 0;
                   sp--;
@@ -2169,17 +2169,17 @@ png_do_unpack(png_row_infop row_info, pn
             break;
          }
 
          case 2:
          {
 
             png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
             png_bytep dp = row + (png_size_t)row_width - 1;
-            png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
+            png_uint_32 shift = ((3U - ((row_width + 3U) & 0x03)) << 1);
             for (i = 0; i < row_width; i++)
             {
                *dp = (png_byte)((*sp >> shift) & 0x03);
 
                if (shift == 6)
                {
                   shift = 0;
                   sp--;
@@ -2192,17 +2192,17 @@ png_do_unpack(png_row_infop row_info, pn
             }
             break;
          }
 
          case 4:
          {
             png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
             png_bytep dp = row + (png_size_t)row_width - 1;
-            png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
+            png_uint_32 shift = ((1U - ((row_width + 1U) & 0x01)) << 2);
             for (i = 0; i < row_width; i++)
             {
                *dp = (png_byte)((*sp >> shift) & 0x0f);
 
                if (shift == 4)
                {
                   shift = 0;
                   sp--;
@@ -3218,17 +3218,18 @@ png_do_compose(png_row_infop row_info, p
                   sp = row;
                   shift = 7;
                   for (i = 0; i < row_width; i++)
                   {
                      if ((png_uint_16)((*sp >> shift) & 0x01)
                         == png_ptr->trans_color.gray)
                      {
                         unsigned int tmp = *sp & (0x7f7f >> (7 - shift));
-                        tmp |= png_ptr->background.gray << shift;
+                        tmp |=
+                            (unsigned int)(png_ptr->background.gray << shift);
                         *sp = (png_byte)(tmp & 0xff);
                      }
 
                      if (shift == 0)
                      {
                         shift = 7;
                         sp++;
                      }
@@ -3247,27 +3248,28 @@ png_do_compose(png_row_infop row_info, p
                      sp = row;
                      shift = 6;
                      for (i = 0; i < row_width; i++)
                      {
                         if ((png_uint_16)((*sp >> shift) & 0x03)
                             == png_ptr->trans_color.gray)
                         {
                            unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
-                           tmp |= png_ptr->background.gray << shift;
+                           tmp |=
+                              (unsigned int)png_ptr->background.gray << shift;
                            *sp = (png_byte)(tmp & 0xff);
                         }
 
                         else
                         {
                            unsigned int p = (*sp >> shift) & 0x03;
                            unsigned int g = (gamma_table [p | (p << 2) |
                                (p << 4) | (p << 6)] >> 6) & 0x03;
                            unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
-                           tmp |= g << shift;
+                           tmp |= (unsigned int)(g << shift);
                            *sp = (png_byte)(tmp & 0xff);
                         }
 
                         if (shift == 0)
                         {
                            shift = 6;
                            sp++;
                         }
@@ -3283,17 +3285,18 @@ png_do_compose(png_row_infop row_info, p
                      sp = row;
                      shift = 6;
                      for (i = 0; i < row_width; i++)
                      {
                         if ((png_uint_16)((*sp >> shift) & 0x03)
                             == png_ptr->trans_color.gray)
                         {
                            unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
-                           tmp |= png_ptr->background.gray << shift;
+                           tmp |=
+                               (unsigned int)png_ptr->background.gray << shift;
                            *sp = (png_byte)(tmp & 0xff);
                         }
 
                         if (shift == 0)
                         {
                            shift = 6;
                            sp++;
                         }
@@ -3313,27 +3316,28 @@ png_do_compose(png_row_infop row_info, p
                      sp = row;
                      shift = 4;
                      for (i = 0; i < row_width; i++)
                      {
                         if ((png_uint_16)((*sp >> shift) & 0x0f)
                             == png_ptr->trans_color.gray)
                         {
                            unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
-                           tmp |= png_ptr->background.gray << shift;
+                           tmp |= 
+                              (unsigned int)(png_ptr->background.gray << shift);
                            *sp = (png_byte)(tmp & 0xff);
                         }
 
                         else
                         {
                            unsigned int p = (*sp >> shift) & 0x0f;
                            unsigned int g = (gamma_table[p | (p << 4)] >> 4) &
                               0x0f;
                            unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
-                           tmp |= g << shift;
+                           tmp |= (unsigned int)(g << shift);
                            *sp = (png_byte)(tmp & 0xff);
                         }
 
                         if (shift == 0)
                         {
                            shift = 4;
                            sp++;
                         }
@@ -3349,17 +3353,18 @@ png_do_compose(png_row_infop row_info, p
                      sp = row;
                      shift = 4;
                      for (i = 0; i < row_width; i++)
                      {
                         if ((png_uint_16)((*sp >> shift) & 0x0f)
                             == png_ptr->trans_color.gray)
                         {
                            unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
-                           tmp |= png_ptr->background.gray << shift;
+                           tmp |=
+                              (unsigned int)(png_ptr->background.gray << shift);
                            *sp = (png_byte)(tmp & 0xff);
                         }
 
                         if (shift == 0)
                         {
                            shift = 4;
                            sp++;
                         }
--- a/media/libpng/pngrutil.c
+++ b/media/libpng/pngrutil.c
@@ -1,12 +1,12 @@
 
 /* pngrutil.c - utilities to read a PNG file
  *
- * Last changed in libpng 1.6.25 [September 1, 2016]
+ * Last changed in libpng 1.6.26 [October 20, 2016]
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  *
@@ -81,17 +81,17 @@ png_get_uint_32)(png_const_bytep buf)
  * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore
  * the following code does a two's complement to native conversion.
  */
 png_int_32 (PNGAPI
 png_get_int_32)(png_const_bytep buf)
 {
    png_uint_32 uval = png_get_uint_32(buf);
    if ((uval & 0x80000000) == 0) /* non-negative */
-      return uval;
+      return (png_int_32)uval;
 
    uval = (uval ^ 0xffffffff) + 1;  /* 2's complement: -x = ~x+1 */
    if ((uval & 0x80000000) == 0) /* no overflow */
       return -(png_int_32)uval;
    /* The following has to be safe; this function only gets called on PNG data
     * and if we get here that data is invalid.  0 is the most safe value and
     * if not then an attacker would surely just generate a PNG with 0 instead.
     */
@@ -365,82 +365,85 @@ png_inflate_claim(png_structrp png_ptr, 
     * size (zlib doesn't have an interface to say "this or lower"!).
     *
     * inflateReset2 was added to zlib 1.2.4; before this the window could not be
     * reset, therefore it is necessary to always allocate the maximum window
     * size with earlier zlibs just in case later compressed chunks need it.
     */
    {
       int ret; /* zlib return code */
-#if PNG_ZLIB_VERNUM >= 0x1240
+#if ZLIB_VERNUM >= 0x1240
+      int window_bits = 0;
 
 # if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_MAXIMUM_INFLATE_WINDOW)
-      int window_bits;
-
       if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) ==
           PNG_OPTION_ON)
       {
          window_bits = 15;
          png_ptr->zstream_start = 0; /* fixed window size */
       }
 
       else
       {
-         window_bits = 0;
          png_ptr->zstream_start = 1;
       }
-# else
-#   define window_bits 0
 # endif
-#endif
+
+#endif /* ZLIB_VERNUM >= 0x1240 */
 
       /* Set this for safety, just in case the previous owner left pointers to
        * memory allocations.
        */
       png_ptr->zstream.next_in = NULL;
       png_ptr->zstream.avail_in = 0;
       png_ptr->zstream.next_out = NULL;
       png_ptr->zstream.avail_out = 0;
 
       if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)
       {
-#if PNG_ZLIB_VERNUM < 0x1240
+#if ZLIB_VERNUM >= 0x1240
+         ret = inflateReset2(&png_ptr->zstream, window_bits);
+#else
          ret = inflateReset(&png_ptr->zstream);
-#else
-         ret = inflateReset2(&png_ptr->zstream, window_bits);
 #endif
       }
 
       else
       {
-#if PNG_ZLIB_VERNUM < 0x1240
+#if ZLIB_VERNUM >= 0x1240
+         ret = inflateInit2(&png_ptr->zstream, window_bits);
+#else
          ret = inflateInit(&png_ptr->zstream);
-#else
-         ret = inflateInit2(&png_ptr->zstream, window_bits);
 #endif
 
          if (ret == Z_OK)
             png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
       }
 
+#if ZLIB_VERNUM >= 0x1281
+      /* Turn off validation of the ADLER32 checksum */
+      if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0)
+         ret = inflateValidate(&png_ptr->zstream, 0);
+#endif
+
       if (ret == Z_OK)
          png_ptr->zowner = owner;
 
       else
          png_zstream_error(png_ptr, ret);
 
       return ret;
    }
 
 #ifdef window_bits
 # undef window_bits
 #endif
 }
 
-#if PNG_ZLIB_VERNUM >= 0x1240
+#if ZLIB_VERNUM >= 0x1240
 /* Handle the start of the inflate stream if we called inflateInit2(strm,0);
  * in this case some zlib versions skip validation of the CINFO field and, in
  * certain circumstances, libpng may end up displaying an invalid image, in
  * contrast to implementations that call zlib in the normal way (e.g. libpng
  * 1.5).
  */
 int /* PRIVATE */
 png_zlib_inflate(png_structrp png_ptr, int flush)
@@ -1011,17 +1014,17 @@ png_handle_PLTE(png_structrp png_ptr, pn
     * whatever the normal CRC configuration tells us.  However, if we
     * have an RGB image, the PLTE can be considered ancillary, so
     * we will act as though it is.
     */
 #ifndef PNG_READ_OPT_PLTE_SUPPORTED
    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
 #endif
    {
-      png_crc_finish(png_ptr, (int) length - num * 3);
+      png_crc_finish(png_ptr, (png_uint_32) (length - (unsigned int)num * 3));
    }
 
 #ifndef PNG_READ_OPT_PLTE_SUPPORTED
    else if (png_crc_error(png_ptr) != 0)  /* Only if we have a CRC error */
    {
       /* If we don't want to use the data from an ancillary chunk,
        * we have two options: an error abort, or a warning and we
        * ignore the data in this chunk (which should be OK, since
@@ -1717,35 +1720,35 @@ png_handle_sPLT(png_structrp png_ptr, pn
    new_palette.depth = *entry_start++;
    entry_size = (new_palette.depth == 8 ? 6 : 10);
    /* This must fit in a png_uint_32 because it is derived from the original
     * chunk data length.
     */
    data_length = length - (png_uint_32)(entry_start - buffer);
 
    /* Integrity-check the data length */
-   if ((data_length % entry_size) != 0)
+   if ((data_length % (unsigned int)entry_size) != 0)
    {
       png_warning(png_ptr, "sPLT chunk has bad length");
       return;
    }
 
-   dl = (png_int_32)(data_length / entry_size);
+   dl = (png_uint_32)(data_length / (unsigned int)entry_size);
    max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry));
 
    if (dl > max_dl)
    {
       png_warning(png_ptr, "sPLT chunk too long");
       return;
    }
 
-   new_palette.nentries = (png_int_32)(data_length / entry_size);
-
-   new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
-       png_ptr, new_palette.nentries * (sizeof (png_sPLT_entry)));
+   new_palette.nentries = (png_int_32)(data_length / (unsigned int)entry_size);
+
+   new_palette.entries = (png_sPLT_entryp)png_malloc_warn(png_ptr,
+       (png_alloc_size_t) new_palette.nentries * (sizeof (png_sPLT_entry)));
 
    if (new_palette.entries == NULL)
    {
       png_warning(png_ptr, "sPLT chunk requires too much memory");
       return;
    }
 
 #ifdef PNG_POINTER_INDEXING_SUPPORTED
@@ -3273,17 +3276,17 @@ png_combine_row(png_const_structrp png_p
    if (end_mask != 0)
    {
       /* end_ptr == NULL is a flag to say do nothing */
       end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1;
       end_byte = *end_ptr;
 #     ifdef PNG_READ_PACKSWAP_SUPPORTED
       if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
          /* little-endian byte */
-         end_mask = 0xff << end_mask;
+         end_mask = (unsigned int)(0xff << end_mask);
 
       else /* big-endian byte */
 #     endif
       end_mask = 0xff >> end_mask;
       /* end_mask is now the bits to *keep* from the destination row */
    }
 
    /* For non-interlaced images this reduces to a memcpy(). A memcpy()
@@ -3719,224 +3722,227 @@ png_combine_row(png_const_structrp png_p
 
 #ifdef PNG_READ_INTERLACING_SUPPORTED
 void /* PRIVATE */
 png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
     png_uint_32 transformations /* Because these may affect the byte layout */)
 {
    /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
    /* Offset to next interlace block */
-   static PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+   static PNG_CONST unsigned int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
 
    png_debug(1, "in png_do_read_interlace");
    if (row != NULL && row_info != NULL)
    {
       png_uint_32 final_width;
 
       final_width = row_info->width * png_pass_inc[pass];
 
       switch (row_info->pixel_depth)
       {
          case 1:
          {
             png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
             png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
-            int sshift, dshift;
-            int s_start, s_end, s_inc;
-            int jstop = png_pass_inc[pass];
+            unsigned int sshift, dshift;
+            unsigned int s_start, s_end;
+            int s_inc;
+            int jstop = (int)png_pass_inc[pass];
             png_byte v;
             png_uint_32 i;
             int j;
 
 #ifdef PNG_READ_PACKSWAP_SUPPORTED
             if ((transformations & PNG_PACKSWAP) != 0)
             {
-                sshift = (int)((row_info->width + 7) & 0x07);
-                dshift = (int)((final_width + 7) & 0x07);
+                sshift = ((row_info->width + 7) & 0x07);
+                dshift = ((final_width + 7) & 0x07);
                 s_start = 7;
                 s_end = 0;
                 s_inc = -1;
             }
 
             else
 #endif
             {
-                sshift = 7 - (int)((row_info->width + 7) & 0x07);
-                dshift = 7 - (int)((final_width + 7) & 0x07);
+                sshift = 7 - ((row_info->width + 7) & 0x07);
+                dshift = 7 - ((final_width + 7) & 0x07);
                 s_start = 0;
                 s_end = 7;
                 s_inc = 1;
             }
 
             for (i = 0; i < row_info->width; i++)
             {
                v = (png_byte)((*sp >> sshift) & 0x01);
                for (j = 0; j < jstop; j++)
                {
                   unsigned int tmp = *dp & (0x7f7f >> (7 - dshift));
-                  tmp |= v << dshift;
+                  tmp |= (unsigned int)(v << dshift);
                   *dp = (png_byte)(tmp & 0xff);
 
                   if (dshift == s_end)
                   {
                      dshift = s_start;
                      dp--;
                   }
 
                   else
-                     dshift += s_inc;
+                     dshift = (unsigned int)((int)dshift + s_inc);
                }
 
                if (sshift == s_end)
                {
                   sshift = s_start;
                   sp--;
                }
 
                else
-                  sshift += s_inc;
+                  sshift = (unsigned int)((int)sshift + s_inc);
             }
             break;
          }
 
          case 2:
          {
             png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
             png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
-            int sshift, dshift;
-            int s_start, s_end, s_inc;
-            int jstop = png_pass_inc[pass];
+            unsigned int sshift, dshift;
+            unsigned int s_start, s_end;
+            int s_inc;
+            int jstop = (int)png_pass_inc[pass];
             png_uint_32 i;
 
 #ifdef PNG_READ_PACKSWAP_SUPPORTED
             if ((transformations & PNG_PACKSWAP) != 0)
             {
-               sshift = (int)(((row_info->width + 3) & 0x03) << 1);
-               dshift = (int)(((final_width + 3) & 0x03) << 1);
+               sshift = (((row_info->width + 3) & 0x03) << 1);
+               dshift = (((final_width + 3) & 0x03) << 1);
                s_start = 6;
                s_end = 0;
                s_inc = -2;
             }
 
             else
 #endif
             {
-               sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
-               dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
+               sshift = ((3 - ((row_info->width + 3) & 0x03)) << 1);
+               dshift = ((3 - ((final_width + 3) & 0x03)) << 1);
                s_start = 0;
                s_end = 6;
                s_inc = 2;
             }
 
             for (i = 0; i < row_info->width; i++)
             {
                png_byte v;
                int j;
 
                v = (png_byte)((*sp >> sshift) & 0x03);
                for (j = 0; j < jstop; j++)
                {
                   unsigned int tmp = *dp & (0x3f3f >> (6 - dshift));
-                  tmp |= v << dshift;
+                  tmp |= (unsigned int)(v << dshift);
                   *dp = (png_byte)(tmp & 0xff);
 
                   if (dshift == s_end)
                   {
                      dshift = s_start;
                      dp--;
                   }
 
                   else
-                     dshift += s_inc;
+                     dshift = (unsigned int)((int)dshift + s_inc);
                }
 
                if (sshift == s_end)
                {
                   sshift = s_start;
                   sp--;
                }
 
                else
-                  sshift += s_inc;
+                  sshift = (unsigned int)((int)sshift + s_inc);
             }
             break;
          }
 
          case 4:
          {
             png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
             png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
-            int sshift, dshift;
-            int s_start, s_end, s_inc;
+            unsigned int sshift, dshift;
+            unsigned int s_start, s_end;
+            int s_inc;
             png_uint_32 i;
-            int jstop = png_pass_inc[pass];
+            int jstop = (int)png_pass_inc[pass];
 
 #ifdef PNG_READ_PACKSWAP_SUPPORTED
             if ((transformations & PNG_PACKSWAP) != 0)
             {
-               sshift = (int)(((row_info->width + 1) & 0x01) << 2);
-               dshift = (int)(((final_width + 1) & 0x01) << 2);
+               sshift = (((row_info->width + 1) & 0x01) << 2);
+               dshift = (((final_width + 1) & 0x01) << 2);
                s_start = 4;
                s_end = 0;
                s_inc = -4;
             }
 
             else
 #endif
             {
-               sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
-               dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
+               sshift = ((1 - ((row_info->width + 1) & 0x01)) << 2);
+               dshift = ((1 - ((final_width + 1) & 0x01)) << 2);
                s_start = 0;
                s_end = 4;
                s_inc = 4;
             }
 
             for (i = 0; i < row_info->width; i++)
             {
                png_byte v = (png_byte)((*sp >> sshift) & 0x0f);
                int j;
 
                for (j = 0; j < jstop; j++)
                {
                   unsigned int tmp = *dp & (0xf0f >> (4 - dshift));
-                  tmp |= v << dshift;
+                  tmp |= (unsigned int)(v << dshift);
                   *dp = (png_byte)(tmp & 0xff);
 
                   if (dshift == s_end)
                   {
                      dshift = s_start;
                      dp--;
                   }
 
                   else
-                     dshift += s_inc;
+                     dshift = (unsigned int)((int)dshift + s_inc);
                }
 
                if (sshift == s_end)
                {
                   sshift = s_start;
                   sp--;
                }
 
                else
-                  sshift += s_inc;
+                  sshift = (unsigned int)((int)sshift + s_inc);
             }
             break;
          }
 
          default:
          {
             png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
 
             png_bytep sp = row + (png_size_t)(row_info->width - 1)
                 * pixel_bytes;
 
             png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
 
-            int jstop = png_pass_inc[pass];
+            int jstop = (int)png_pass_inc[pass];
             png_uint_32 i;
 
             for (i = 0; i < row_info->width; i++)
             {
                png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */
                int j;
 
                memcpy(v, sp, pixel_bytes);
@@ -4070,30 +4076,30 @@ png_read_filter_row_paeth_1byte_pixel(pn
       *row++ = (png_byte)a;
    }
 }
 
 static void
 png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row,
     png_const_bytep prev_row)
 {
-   int bpp = (row_info->pixel_depth + 7) >> 3;
+   unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
    png_bytep rp_end = row + bpp;
 
    /* Process the first pixel in the row completely (this is the same as 'up'
     * because there is only one candidate predictor for the first row).
     */
    while (row < rp_end)
    {
       int a = *row + *prev_row++;
       *row++ = (png_byte)a;
    }
 
    /* Remainder */
-   rp_end += row_info->rowbytes - bpp;
+   rp_end = rp_end + (row_info->rowbytes - bpp);
 
    while (row < rp_end)
    {
       int a, b, c, pa, pb, pc, p;
 
       c = *(prev_row - bpp);
       a = *(row - bpp);
       b = *prev_row++;
@@ -4311,17 +4317,25 @@ png_read_IDAT_data(png_structrp png_ptr,
          break;
       }
 
       if (ret != Z_OK)
       {
          png_zstream_error(png_ptr, ret);
 
          if (output != NULL)
-            png_chunk_error(png_ptr, png_ptr->zstream.msg);
+         {
+            if(!strncmp(png_ptr->zstream.msg,"incorrect data check",20))
+            {
+               png_chunk_benign_error(png_ptr, "ADLER32 checksum mismatch");
+               continue;
+            }
+            else
+               png_chunk_error(png_ptr, png_ptr->zstream.msg);
+         }
 
          else /* checking */
          {
             png_chunk_benign_error(png_ptr, png_ptr->zstream.msg);
             return;
          }
       }
    } while (avail_out > 0);
@@ -4464,17 +4478,17 @@ png_read_start_row(png_structrp png_ptr)
    static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
 
    /* Start of interlace block in the y direction */
    static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
 
    /* Offset to next interlace block in the y direction */
    static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
 
-   int max_pixel_depth;
+   unsigned int max_pixel_depth;
    png_size_t row_bytes;
 
    png_debug(1, "in png_read_start_row");
 
 #ifdef PNG_READ_TRANSFORMS_SUPPORTED
    png_init_read_transformations(png_ptr);
 #endif
    if (png_ptr->interlaced != 0)
@@ -4493,17 +4507,17 @@ png_read_start_row(png_structrp png_ptr)
    }
 
    else
    {
       png_ptr->num_rows = png_ptr->height;
       png_ptr->iwidth = png_ptr->width;
    }
 
-   max_pixel_depth = png_ptr->pixel_depth;
+   max_pixel_depth = (unsigned int)png_ptr->pixel_depth;
 
    /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpler set of
     * calculations to calculate the final pixel depth, then
     * png_do_read_transforms actually does the transforms.  This means that the
     * code which effectively calculates this value is actually repeated in three
     * separate places.  They must all match.  Innocent changes to the order of
     * transformations can and will break libpng in a way that causes memory
     * overwrites.
@@ -4628,17 +4642,17 @@ png_read_start_row(png_structrp png_ptr)
       }
    }
 #endif
 
 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
 defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
    if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)
    {
-      int user_pixel_depth = png_ptr->user_transform_depth *
+      unsigned int user_pixel_depth = png_ptr->user_transform_depth *
          png_ptr->user_transform_channels;
 
       if (user_pixel_depth > max_pixel_depth)
          max_pixel_depth = user_pixel_depth;
    }
 #endif
 
    /* This value is stored in png_struct and double checked in the row read
@@ -4650,17 +4664,17 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED
    /* Align the width on the next larger 8 pixels.  Mainly used
     * for interlacing
     */
    row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
    /* Calculate the maximum bytes needed, adding a byte and a pixel
     * for safety's sake
     */
    row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
-       1 + ((max_pixel_depth + 7) >> 3);
+       1 + ((max_pixel_depth + 7) >> 3U);
 
 #ifdef PNG_MAX_MALLOC_64K
    if (row_bytes > (png_uint_32)65536L)
       png_error(png_ptr, "This image requires a row greater than 64KB");
 #endif
 
    if (row_bytes + 48 > png_ptr->old_big_row_buf_size)
    {
@@ -4719,17 +4733,17 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED
    png_debug1(3, "rowbytes = %lu,", (unsigned long)png_ptr->rowbytes);
    png_debug1(3, "irowbytes = %lu",
        (unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);
 
    /* The sequential reader needs a buffer for IDAT, but the progressive reader
     * does not, so free the read buffer now regardless; the sequential reader
     * reallocates it on demand.
     */
-   if (png_ptr->read_buffer != 0)
+   if (png_ptr->read_buffer != NULL)
    {
       png_bytep buffer = png_ptr->read_buffer;
 
       png_ptr->read_buffer_size = 0;
       png_ptr->read_buffer = NULL;
       png_free(png_ptr, buffer);
    }
 
--- a/media/libpng/pngset.c
+++ b/media/libpng/pngset.c
@@ -1,12 +1,12 @@
 
 /* pngset.c - storage of image information into info struct
  *
- * Last changed in libpng 1.6.24 [August 4, 2016]
+ * Last changed in libpng 1.6.26 [October 20, 2016]
  * Copyright (c) 1998-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  *
@@ -283,36 +283,48 @@ png_set_pCAL(png_const_structrp png_ptr,
    length = strlen(purpose) + 1;
    png_debug1(3, "allocating purpose for info (%lu bytes)",
        (unsigned long)length);
 
    /* TODO: validate format of calibration name and unit name */
 
    /* Check that the type matches the specification. */
    if (type < 0 || type > 3)
-      png_error(png_ptr, "Invalid pCAL equation type");
+   {
+      png_chunk_report(png_ptr, "Invalid pCAL equation type",
+            PNG_CHUNK_WRITE_ERROR);
+      return;
+   }
 
    if (nparams < 0 || nparams > 255)
-      png_error(png_ptr, "Invalid pCAL parameter count");
+   {
+      png_chunk_report(png_ptr, "Invalid pCAL parameter count",
+            PNG_CHUNK_WRITE_ERROR);
+      return;
+   }
 
    /* Validate params[nparams] */
    for (i=0; i<nparams; ++i)
    {
       if (params[i] == NULL ||
           !png_check_fp_string(params[i], strlen(params[i])))
-         png_error(png_ptr, "Invalid format for pCAL parameter");
+      {
+         png_chunk_report(png_ptr, "Invalid format for pCAL parameter",
+               PNG_CHUNK_WRITE_ERROR);
+         return;
+      }
    }
 
    info_ptr->pcal_purpose = png_voidcast(png_charp,
        png_malloc_warn(png_ptr, length));
 
    if (info_ptr->pcal_purpose == NULL)
    {
-      png_warning(png_ptr, "Insufficient memory for pCAL purpose");
-
+      png_chunk_report(png_ptr, "Insufficient memory for pCAL purpose",
+            PNG_CHUNK_WRITE_ERROR);
       return;
    }
 
    memcpy(info_ptr->pcal_purpose, purpose, length);
 
    png_debug(3, "storing X0, X1, type, and nparams in info");
    info_ptr->pcal_X0 = X0;
    info_ptr->pcal_X1 = X1;
@@ -331,26 +343,27 @@ png_set_pCAL(png_const_structrp png_ptr,
       png_warning(png_ptr, "Insufficient memory for pCAL units");
 
       return;
    }
 
    memcpy(info_ptr->pcal_units, units, length);
 
    info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,
-       (png_size_t)((nparams + 1) * (sizeof (png_charp)))));
+       (png_size_t)(((unsigned int)nparams + 1) * (sizeof (png_charp)))));
 
    if (info_ptr->pcal_params == NULL)
    {
       png_warning(png_ptr, "Insufficient memory for pCAL params");
 
       return;
    }
 
-   memset(info_ptr->pcal_params, 0, (nparams + 1) * (sizeof (png_charp)));
+   memset(info_ptr->pcal_params, 0, ((unsigned int)nparams + 1) *
+       (sizeof (png_charp)));
 
    for (i = 0; i < nparams; i++)
    {
       length = strlen(params[i]) + 1;
       png_debug2(3, "allocating parameter %d for info (%lu bytes)", i,
           (unsigned long)length);
 
       info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length);
@@ -563,17 +576,18 @@ png_set_PLTE(png_structrp png_ptr, png_i
    /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
     * of num_palette entries, in case of an invalid PNG file or incorrect
     * call to png_set_PLTE() with too-large sample values.
     */
    png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
        PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
 
    if (num_palette > 0)
-      memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color)));
+      memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
+          (sizeof (png_color)));
    info_ptr->palette = png_ptr->palette;
    info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
 
    info_ptr->free_me |= PNG_FREE_PLTE;
 
    info_ptr->valid |= PNG_INFO_PLTE;
 }
 
@@ -1080,17 +1094,17 @@ png_set_sPLT(png_const_structrp png_ptr,
          break;
       }
 
       np->nentries = entries->nentries;
       /* This multiply can't overflow because png_malloc_array has already
        * checked it when doing the allocation.
        */
       memcpy(np->entries, entries->entries,
-          entries->nentries * sizeof (png_sPLT_entry));
+          (unsigned int)entries->nentries * sizeof (png_sPLT_entry));
 
       /* Note that 'continue' skips the advance of the out pointer and out
        * count, so an invalid entry is not added.
        */
       info_ptr->valid |= PNG_INFO_sPLT;
       ++(info_ptr->splt_palettes_num);
       ++np;
    }
@@ -1389,17 +1403,17 @@ png_set_unknown_chunk_location(png_const
     */
    if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 &&
       chunk < info_ptr->unknown_chunks_num)
    {
       if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0)
       {
          png_app_error(png_ptr, "invalid unknown chunk location");
          /* Fake out the pre 1.6.0 behavior: */
-         if ((location & PNG_HAVE_IDAT) != 0) /* undocumented! */
+         if (((unsigned int)location & PNG_HAVE_IDAT) != 0) /* undocumented! */
             location = PNG_AFTER_IDAT;
 
          else
             location = PNG_HAVE_IHDR; /* also undocumented */
       }
 
       info_ptr->unknown_chunks[chunk].location =
          check_location(png_ptr, location);
@@ -1513,17 +1527,17 @@ png_set_keep_unknown_chunks(png_structrp
          /* Prior to 1.6.0 this was silently ignored, now it is an app_error
           * which can be switched off.
           */
          png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list");
 
          return;
       }
 
-      num_chunks = num_chunks_in;
+      num_chunks = (unsigned int)num_chunks_in;
    }
 
    old_num_chunks = png_ptr->num_chunk_list;
    if (png_ptr->chunk_list == NULL)
       old_num_chunks = 0;
 
    /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.
     */
@@ -1703,17 +1717,17 @@ png_set_compression_buffer_size(png_stru
    }
 #  endif
 }
 
 void PNGAPI
 png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask)
 {
    if (png_ptr != NULL && info_ptr != NULL)
-      info_ptr->valid &= ~mask;
+      info_ptr->valid &= (unsigned int)(~mask);
 }
 
 
 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
 /* This function was added to libpng 1.2.6 */
 void PNGAPI
 png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max,
     png_uint_32 user_height_max)
--- a/media/libpng/pngstruct.h
+++ b/media/libpng/pngstruct.h
@@ -258,17 +258,17 @@ struct png_struct_def
 #ifdef PNG_WRITE_SUPPORTED
    png_byte usr_channels;     /* channels at start of write: write only */
 #endif
    png_byte sig_bytes;        /* magic bytes read/written from start of file */
    png_byte maximum_pixel_depth;
                               /* pixel depth used for the row buffers */
    png_byte transformed_pixel_depth;
                               /* pixel depth after read/write transforms */
-#if PNG_ZLIB_VERNUM >= 0x1240
+#if ZLIB_VERNUM >= 0x1240
    png_byte zstream_start;    /* at start of an input zlib stream */
 #endif /* Zlib >= 1.2.4 */
 #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
    png_uint_16 filler;           /* filler bytes for pixel expansion */
 #endif
 
 #if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
    defined(PNG_READ_ALPHA_MODE_SUPPORTED)
--- a/media/libpng/pngtrans.c
+++ b/media/libpng/pngtrans.c
@@ -1,12 +1,12 @@
 
 /* pngtrans.c - transforms the data in a row (used by both readers and writers)
  *
- * Last changed in libpng 1.6.24 [August 4, 2016]
+ * Last changed in libpng 1.6.26 [October 20, 2016]
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  */
@@ -590,17 +590,17 @@ png_do_strip_channel(png_row_infop row_i
       if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
          row_info->color_type = PNG_COLOR_TYPE_RGB;
    }
 
    else
       return; /* The filler channel has gone already */
 
    /* Fix the rowbytes value. */
-   row_info->rowbytes = dp-row;
+   row_info->rowbytes = (unsigned int)(dp-row);
 }
 #endif
 
 #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
 /* Swaps red and blue bytes within a pixel */
 void /* PRIVATE */
 png_do_bgr(png_row_infop row_info, png_bytep row)
 {
@@ -688,17 +688,17 @@ png_do_check_palette_indexes(png_structr
       png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */
    {
       /* Calculations moved outside switch in an attempt to stop different
        * compiler warnings.  'padding' is in *bits* within the last byte, it is
        * an 'int' because pixel_depth becomes an 'int' in the expression below,
        * and this calculation is used because it avoids warnings that other
        * forms produced on either GCC or MSVC.
        */
-      int padding = (-row_info->pixel_depth * row_info->width) & 7;
+      int padding = PNG_PADBITS(row_info->pixel_depth, row_info->width);
       png_bytep rp = png_ptr->row_buf + row_info->rowbytes;
 
       switch (row_info->bit_depth)
       {
          case 1:
          {
             /* in this case, all bytes must be 0 so we don't need
              * to unpack the pixels except for the rightmost one.
--- a/media/libpng/pngwrite.c
+++ b/media/libpng/pngwrite.c
@@ -1,12 +1,12 @@
 
 /* pngwrite.c - general routines to write a PNG file
  *
- * Last changed in libpng 1.6.24 [August 4, 2016]
+ * Last changed in libpng 1.6.26 [October 20, 2016]
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  */
@@ -670,19 +670,19 @@ png_do_write_intrapixel(png_row_infop ro
          else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
             bytes_per_pixel = 8;
 
          else
             return;
 
          for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
          {
-            png_uint_32 s0   = (*(rp    ) << 8) | *(rp + 1);
-            png_uint_32 s1   = (*(rp + 2) << 8) | *(rp + 3);
-            png_uint_32 s2   = (*(rp + 4) << 8) | *(rp + 5);
+            png_uint_32 s0   = (png_uint_32)(*(rp    ) << 8) | *(rp + 1);
+            png_uint_32 s1   = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3);
+            png_uint_32 s2   = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5);
             png_uint_32 red  = (png_uint_32)((s0 - s1) & 0xffffL);
             png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL);
             *(rp    ) = (png_byte)(red >> 8);
             *(rp + 1) = (png_byte)red;
             *(rp + 4) = (png_byte)(blue >> 8);
             *(rp + 5) = (png_byte)blue;
          }
       }
@@ -905,17 +905,17 @@ png_write_row(png_structrp png_ptr, png_
 void PNGAPI
 png_set_flush(png_structrp png_ptr, int nrows)
 {
    png_debug(1, "in png_set_flush");
 
    if (png_ptr == NULL)
       return;
 
-   png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
+   png_ptr->flush_dist = (nrows < 0 ? 0 : (png_uint_32)nrows);
 }
 
 /* Flush the current output buffers now */
 void PNGAPI
 png_write_flush(png_structrp png_ptr)
 {
    png_debug(1, "in png_write_flush");
 
@@ -1529,46 +1529,47 @@ png_write_image_16bit(png_voidp argument
        argument);
    png_imagep image = display->image;
    png_structrp png_ptr = image->opaque->png_ptr;
 
    png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,
        display->first_row);
    png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row);
    png_uint_16p row_end;
-   const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1;
+   const unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ?
+       3 : 1;
    int aindex = 0;
    png_uint_32 y = image->height;
 
    if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)
    {
 #   ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
       if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
       {
          aindex = -1;
          ++input_row; /* To point to the first component */
          ++output_row;
       }
          else
-            aindex = channels;
+            aindex = (int)channels;
 #     else
-         aindex = channels;
+         aindex = (int)channels;
 #     endif
    }
 
    else
       png_error(png_ptr, "png_write_image: internal call error");
 
    /* Work out the output row end and count over this, note that the increment
     * above to 'row' means that row_end can actually be beyond the end of the
     * row; this is correct.
     */
    row_end = output_row + image->width * (channels+1);
 
-   while (y-- > 0)
+   for (; y > 0; --y)
    {
       png_const_uint_16p in_ptr = input_row;
       png_uint_16p out_ptr = output_row;
 
       while (out_ptr < row_end)
       {
          const png_uint_16 alpha = in_ptr[aindex];
          png_uint_32 reciprocal = 0;
@@ -1579,17 +1580,17 @@ png_write_image_16bit(png_voidp argument
          /* Calculate a reciprocal.  The correct calculation is simply
           * component/alpha*65535 << 15. (I.e. 15 bits of precision); this
           * allows correct rounding by adding .5 before the shift.  'reciprocal'
           * is only initialized when required.
           */
          if (alpha > 0 && alpha < 65535)
             reciprocal = ((0xffff<<15)+(alpha>>1))/alpha;
 
-         c = channels;
+         c = (int)channels;
          do /* always at least one channel */
          {
             png_uint_16 component = *in_ptr++;
 
             /* The following gives 65535 for an alpha of 0, which is fine,
              * otherwise if 0/0 is represented as some other value there is more
              * likely to be a discontinuity which will probably damage
              * compression when moving from a fully transparent area to a
@@ -1614,17 +1615,17 @@ png_write_image_16bit(png_voidp argument
          while (--c > 0);
 
          /* Skip to next component (skip the intervening alpha channel) */
          ++in_ptr;
          ++out_ptr;
       }
 
       png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row));
-      input_row += display->row_bytes/(sizeof (png_uint_16));
+      input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
    }
 
    return 1;
 }
 
 /* Given 16-bit input (1 to 4 channels) write 8-bit output.  If an alpha channel
  * is present it must be removed from the components, the components are then
  * written in sRGB encoding.  No components are added or removed.
@@ -1687,39 +1688,40 @@ png_write_image_8bit(png_voidp argument)
        argument);
    png_imagep image = display->image;
    png_structrp png_ptr = image->opaque->png_ptr;
 
    png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,
        display->first_row);
    png_bytep output_row = png_voidcast(png_bytep, display->local_row);
    png_uint_32 y = image->height;
-   const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1;
+   const unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ?
+       3 : 1;
 
    if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)
    {
       png_bytep row_end;
       int aindex;
 
 #   ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
       if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
       {
          aindex = -1;
          ++input_row; /* To point to the first component */
          ++output_row;
       }
 
       else
 #   endif
-      aindex = channels;
+      aindex = (int)channels;
 
       /* Use row_end in place of a loop counter: */
       row_end = output_row + image->width * (channels+1);
 
-      while (y-- > 0)
+      for (; y > 0; --y)
       {
          png_const_uint_16p in_ptr = input_row;
          png_bytep out_ptr = output_row;
 
          while (out_ptr < row_end)
          {
             png_uint_16 alpha = in_ptr[aindex];
             png_byte alphabyte = (png_byte)PNG_DIV257(alpha);
@@ -1727,71 +1729,71 @@ png_write_image_8bit(png_voidp argument)
             int c;
 
             /* Scale and write the alpha channel. */
             out_ptr[aindex] = alphabyte;
 
             if (alphabyte > 0 && alphabyte < 255)
                reciprocal = UNP_RECIPROCAL(alpha);
 
-            c = channels;
+            c = (int)channels;
             do /* always at least one channel */
                *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal);
             while (--c > 0);
 
             /* Skip to next component (skip the intervening alpha channel) */
             ++in_ptr;
             ++out_ptr;
          } /* while out_ptr < row_end */
 
          png_write_row(png_ptr, png_voidcast(png_const_bytep,
              display->local_row));
-         input_row += display->row_bytes/(sizeof (png_uint_16));
+         input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
       } /* while y */
    }
 
    else
    {
       /* No alpha channel, so the row_end really is the end of the row and it
        * is sufficient to loop over the components one by one.
        */
       png_bytep row_end = output_row + image->width * channels;
 
-      while (y-- > 0)
+      for (; y > 0; --y)
       {
          png_const_uint_16p in_ptr = input_row;
          png_bytep out_ptr = output_row;
 
          while (out_ptr < row_end)
          {
             png_uint_32 component = *in_ptr++;
 
             component *= 255;
             *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component);
          }
 
          png_write_row(png_ptr, output_row);
-         input_row += display->row_bytes/(sizeof (png_uint_16));
+         input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));
       }
    }
 
    return 1;
 }
 
 static void
 png_image_set_PLTE(png_image_write_control *display)
 {
    const png_imagep image = display->image;
    const void *cmap = display->colormap;
    const int entries = image->colormap_entries > 256 ? 256 :
        (int)image->colormap_entries;
 
    /* NOTE: the caller must check for cmap != NULL and entries != 0 */
    const png_uint_32 format = image->format;
-   const int channels = PNG_IMAGE_SAMPLE_CHANNELS(format);
+   const unsigned int channels = PNG_IMAGE_SAMPLE_CHANNELS(format);
 
 #   if defined(PNG_FORMAT_BGR_SUPPORTED) &&\
       defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED)
       const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 &&
           (format & PNG_FORMAT_FLAG_ALPHA) != 0;
 #   else
 #     define afirst 0
 #   endif
@@ -1813,17 +1815,17 @@ png_image_set_PLTE(png_image_write_contr
    {
       /* This gets automatically converted to sRGB with reversal of the
        * pre-multiplication if the color-map has an alpha channel.
        */
       if ((format & PNG_FORMAT_FLAG_LINEAR) != 0)
       {
          png_const_uint_16p entry = png_voidcast(png_const_uint_16p, cmap);
 
-         entry += i * channels;
+         entry += (unsigned int)i * channels;
 
          if ((channels & 1) != 0) /* no alpha */
          {
             if (channels >= 3) /* RGB */
             {
                palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
                    entry[(2 ^ bgr)]);
                palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 *
@@ -1869,17 +1871,17 @@ png_image_set_PLTE(png_image_write_contr
                    png_unpremultiply(entry[afirst], alpha, reciprocal);
          }
       }
 
       else /* Color-map has sRGB values */
       {
          png_const_bytep entry = png_voidcast(png_const_bytep, cmap);
 
-         entry += i * channels;
+         entry += (unsigned int)i * channels;
 
          switch (channels)
          {
             case 4:
                tRNS[i] = entry[afirst ? 0 : 3];
                if (tRNS[i] < 255)
                   num_trans = i+1;
                /* FALL THROUGH */
@@ -1914,17 +1916,17 @@ png_image_set_PLTE(png_image_write_contr
 
    png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette,
        entries);
 
    if (num_trans > 0)
       png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS,
           num_trans, NULL);
 
-   image->colormap_entries = entries;
+   image->colormap_entries = (png_uint_32)entries;
 }
 
 static int
 png_image_write_main(png_voidp argument)
 {
    png_image_write_control *display = png_voidcast(png_image_write_control*,
        argument);
    png_imagep image = display->image;
@@ -1944,37 +1946,37 @@ png_image_write_main(png_voidp argument)
 #   endif
 
    /* Default the 'row_stride' parameter if required, also check the row stride
     * and total image size to ensure that they are within the system limits.
     */
    {
       const unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format);
 
-      if (image->width <= 0x7FFFFFFFU/channels) /* no overflow */
+      if (image->width <= 0x7fffffffU/channels) /* no overflow */
       {
          png_uint_32 check;
          const png_uint_32 png_row_stride = image->width * channels;
 
          if (display->row_stride == 0)
             display->row_stride = (png_int_32)/*SAFE*/png_row_stride;
 
          if (display->row_stride < 0)
-            check = -display->row_stride;
+            check = (png_uint_32)(-display->row_stride);
 
          else
-            check = display->row_stride;
+            check = (png_uint_32)display->row_stride;
 
          if (check >= png_row_stride)
          {
             /* Now check for overflow of the image buffer calculation; this
              * limits the whole image size to 32 bits for API compatibility with
              * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro.
              */
-            if (image->height > 0xFFFFFFFF/png_row_stride)
+            if (image->height > 0xffffffffU/png_row_stride)
                png_error(image->opaque->png_ptr, "memory image too large");
          }
 
          else
             png_error(image->opaque->png_ptr, "supplied row stride too small");
       }
 
       else
@@ -2140,17 +2142,17 @@ png_image_write_main(png_voidp argument)
     * supported by the rest of the libpng write code; call it directly.
     */
    else
    {
       png_const_bytep row = png_voidcast(png_const_bytep, display->first_row);
       ptrdiff_t row_bytes = display->row_bytes;
       png_uint_32 y = image->height;
 
-      while (y-- > 0)
+      for (; y > 0; --y)
       {
          png_write_row(png_ptr, row);
          row += row_bytes;
       }
    }
 
    png_write_end(png_ptr, info_ptr);
    return 1;
--- a/media/libpng/pngwtran.c
+++ b/media/libpng/pngwtran.c
@@ -1,12 +1,12 @@
 
 /* pngwtran.c - transforms the data in a row for PNG writers
  *
- * Last changed in libpng 1.6.24 [August 4, 2016]
+ * Last changed in libpng 1.6.26 [October 20, 2016]
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  */
@@ -172,17 +172,17 @@ static void
 png_do_shift(png_row_infop row_info, png_bytep row,
     png_const_color_8p bit_depth)
 {
    png_debug(1, "in png_do_shift");
 
    if (row_info->color_type != PNG_COLOR_TYPE_PALETTE)
    {
       int shift_start[4], shift_dec[4];
-      int channels = 0;
+      unsigned int channels = 0;
 
       if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
       {
          shift_start[channels] = row_info->bit_depth - bit_depth->red;
          shift_dec[channels] = bit_depth->red;
          channels++;
 
          shift_start[channels] = row_info->bit_depth - bit_depth->green;
--- a/media/libpng/pngwutil.c
+++ b/media/libpng/pngwutil.c
@@ -1,12 +1,12 @@
 
 /* pngwutil.c - utilities to write a PNG file
  *
- * Last changed in libpng 1.6.24 [August 4, 2016]
+ * Last changed in libpng 1.6.26 [October 20, 2016]
  * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
  * and license in png.h
  */
@@ -403,17 +403,17 @@ png_deflate_claim(png_structrp png_ptr, 
        * doesn't use them on Init, but it might in the future).
        */
       png_ptr->zstream.next_in = NULL;
       png_ptr->zstream.avail_in = 0;
       png_ptr->zstream.next_out = NULL;
       png_ptr->zstream.avail_out = 0;
 
       /* Now initialize if required, setting the new parameters, otherwise just
-       * to a simple reset to the previous parameters.
+       * do a simple reset to the previous parameters.
        */
       if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)
          ret = deflateReset(&png_ptr->zstream);
 
       else
       {
          ret = deflateInit2(&png_ptr->zstream, level, method, windowBits,
              memLevel, strategy);
@@ -1192,17 +1192,17 @@ png_write_iCCP(png_structrp png_ptr, png
 /* Write a sPLT chunk */
 void /* PRIVATE */
 png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette)
 {
    png_uint_32 name_len;
    png_byte new_name[80];
    png_byte entrybuf[10];
    png_size_t entry_size = (spalette->depth == 8 ? 6 : 10);
-   png_size_t palette_size = entry_size * spalette->nentries;
+   png_size_t palette_size = entry_size * (png_size_t)spalette->nentries;
    png_sPLT_entryp ep;
 #ifndef PNG_POINTER_INDEXING_SUPPORTED
    int i;
 #endif
 
    png_debug(1, "in png_write_sPLT");
 
    name_len = png_check_keyword(png_ptr, spalette->name, new_name);
@@ -1759,17 +1759,17 @@ png_write_pCAL(png_structrp png_ptr, png
    ++purpose_len; /* terminator */
 
    png_debug1(3, "pCAL purpose length = %d", (int)purpose_len);
    units_len = strlen(units) + (nparams == 0 ? 0 : 1);
    png_debug1(3, "pCAL units length = %d", (int)units_len);
    total_len = purpose_len + units_len + 10;
 
    params_len = (png_size_tp)png_malloc(png_ptr,
-       (png_alloc_size_t)(nparams * (sizeof (png_size_t))));
+       (png_alloc_size_t)((png_alloc_size_t)nparams * (sizeof (png_size_t))));
 
    /* Find the length of each parameter, making sure we don't count the
     * null terminator for the last parameter.
     */
    for (i = 0; i < nparams; i++)
    {
       params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
       png_debug2(3, "pCAL parameter %d length = %lu", i,
@@ -2347,37 +2347,37 @@ png_write_filtered_row(png_structrp png_
 #ifdef PNG_WRITE_FILTER_SUPPORTED
 static png_size_t /* PRIVATE */
 png_setup_sub_row(png_structrp png_ptr, const png_uint_32 bpp,
     const png_size_t row_bytes, const png_size_t lmins)
 {
    png_bytep rp, dp, lp;
    png_size_t i;
    png_size_t sum = 0;
-   int v;
+   unsigned int v;
 
    png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB;
 
    for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp;
         i++, rp++, dp++)
    {
       v = *dp = *rp;
 #ifdef PNG_USE_ABS
-      sum += 128 - abs(v - 128);
+      sum += 128 - abs((int)v - 128);
 #else
       sum += (v < 128) ? v : 256 - v;
 #endif
    }
 
    for (lp = png_ptr->row_buf + 1; i < row_bytes;
       i++, rp++, lp++, dp++)
    {
       v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
 #ifdef PNG_USE_ABS
-      sum += 128 - abs(v - 128);
+      sum += 128 - abs((int)v - 128);
 #else
       sum += (v < 128) ? v : 256 - v;
 #endif
 
       if (sum > lmins)  /* We are already worse, don't continue. */
         break;
    }
 
@@ -2408,27 +2408,27 @@ png_setup_sub_row_only(png_structrp png_
 
 static png_size_t /* PRIVATE */
 png_setup_up_row(png_structrp png_ptr, const png_size_t row_bytes,
     const png_size_t lmins)
 {
    png_bytep rp, dp, pp;
    png_size_t i;
    png_size_t sum = 0;
-   int v;
+   unsigned int v;
 
    png_ptr->try_row[0] = PNG_FILTER_VALUE_UP;
 
    for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
        pp = png_ptr->prev_row + 1; i < row_bytes;
        i++, rp++, pp++, dp++)
    {
       v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
 #ifdef PNG_USE_ABS
-      sum += 128 - abs(v - 128);
+      sum += 128 - abs((int)v - 128);
 #else
       sum += (v < 128) ? v : 256 - v;
 #endif
 
       if (sum > lmins)  /* We are already worse, don't continue. */
         break;
    }
 
@@ -2452,39 +2452,39 @@ png_setup_up_row_only(png_structrp png_p
 
 static png_size_t /* PRIVATE */
 png_setup_avg_row(png_structrp png_ptr, const png_uint_32 bpp,
     const png_size_t row_bytes, const png_size_t lmins)
 {
    png_bytep rp, dp, pp, lp;
    png_uint_32 i;
    png_size_t sum = 0;
-   int v;
+   unsigned int v;
 
    png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG;
 
    for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
        pp = png_ptr->prev_row + 1; i < bpp; i++)
    {
       v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
 
 #ifdef PNG_USE_ABS
-      sum += 128 - abs(v - 128);
+      sum += 128 - abs((int)v - 128);
 #else
       sum += (v < 128) ? v : 256 - v;
 #endif
    }
 
    for (lp = png_ptr->row_buf + 1; i < row_bytes; i++)
    {
       v = *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
           & 0xff);
 
 #ifdef PNG_USE_ABS
-      sum += 128 - abs(v - 128);
+      sum += 128 - abs((int)v - 128);
 #else
       sum += (v < 128) ? v : 256 - v;
 #endif
 
       if (sum > lmins)  /* We are already worse, don't continue. */
         break;
    }
 
@@ -2514,27 +2514,27 @@ png_setup_avg_row_only(png_structrp png_
 
 static png_size_t /* PRIVATE */
 png_setup_paeth_row(png_structrp png_ptr, const png_uint_32 bpp,
     const png_size_t row_bytes, const png_size_t lmins)
 {
    png_bytep rp, dp, pp, cp, lp;
    png_size_t i;
    png_size_t sum = 0;
-   int v;
+   unsigned int v;
 
    png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH;
 
    for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
        pp = png_ptr->prev_row + 1; i < bpp; i++)
    {
       v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
 
 #ifdef PNG_USE_ABS
-      sum += 128 - abs(v - 128);
+      sum += 128 - abs((int)v - 128);
 #else
       sum += (v < 128) ? v : 256 - v;
 #endif
    }
 
    for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes;
         i++)
    {
@@ -2557,17 +2557,17 @@ png_setup_paeth_row(png_structrp png_ptr
       pc = (p + pc) < 0 ? -(p + pc) : p + pc;
 #endif
 
       p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
 
       v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
 
 #ifdef PNG_USE_ABS
-      sum += 128 - abs(v - 128);
+      sum += 128 - abs((int)v - 128);
 #else
       sum += (v < 128) ? v : 256 - v;
 #endif
 
       if (sum > lmins)  /* We are already worse, don't continue. */
         break;
    }
 
@@ -2680,24 +2680,24 @@ png_write_find_filter(png_structrp png_p
          filter_to_do != PNG_FILTER_NONE)
    {
       /* Overflow not possible and multiple filters in the list, including the
        * 'none' filter.
        */
       png_bytep rp;
       png_size_t sum = 0;
       png_size_t i;
-      int v;
+      unsigned int v;
 
       {
          for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
          {
             v = *rp;
 #ifdef PNG_USE_ABS
-            sum += 128 - abs(v - 128);
+            sum += 128 - abs((int)v - 128);
 #else
             sum += (v < 128) ? v : 256 - v;
 #endif
          }
       }
 
       mins = sum;
    }
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5498,8 +5498,15 @@ pref("security.mixed_content.send_hsts_p
 // Don't change the order of evaluation of mixed-content and HSTS upgrades in
 // order to be most compatible with current standards
 pref("security.mixed_content.use_hsts", false);
 #else
 // Change the order of evaluation so HSTS upgrades happen before
 // mixed-content blocking
 pref("security.mixed_content.use_hsts", true);
 #endif
+
+// Disable Storage api in release builds.
+#ifdef NIGHTLY_BUILD
+pref("dom.storageManager.enabled", true);
+#else
+pref("dom.storageManager.enabled", false);
+#endif
--- a/netwerk/base/moz.build
+++ b/netwerk/base/moz.build
@@ -299,17 +299,18 @@ EXTRA_JS_MODULES += [
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '/docshell/base',
     '/dom/base',
-    '/netwerk/protocol/http'
+    '/netwerk/protocol/http',
+    '/security/pkix/include'
 ]
 
 if 'rtsp' in CONFIG['NECKO_PROTOCOLS']:
     LOCAL_INCLUDES += [
         '/netwerk/protocol/rtsp/controller',
         '/netwerk/protocol/rtsp/rtsp',
     ]
 
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -64,16 +64,17 @@
 #include "nsInterfaceRequestorAgg.h"
 #include "plstr.h"
 #include "nsINestedURI.h"
 #include "mozilla/dom/nsCSPUtils.h"
 #include "mozilla/net/HttpBaseChannel.h"
 #include "nsIScriptError.h"
 #include "nsISiteSecurityService.h"
 #include "nsHttpHandler.h"
+#include "nsNSSComponent.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsINetworkManager.h"
 #include "nsThreadUtils.h" // for NS_IsMainThread
 #endif
 
 #include <limits>
 
@@ -2120,22 +2121,19 @@ NS_GetFilenameFromDisposition(nsAString 
   if (aFilename.IsEmpty())
     return NS_ERROR_NOT_AVAILABLE;
 
   return NS_OK;
 }
 
 void net_EnsurePSMInit()
 {
-    nsCOMPtr<nsISocketProviderService> spserv =
-            do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID);
-    if (spserv) {
-        nsCOMPtr<nsISocketProvider> provider;
-        spserv->GetSocketProvider("ssl", getter_AddRefs(provider));
-    }
+    nsresult rv;
+    nsCOMPtr<nsISupports> psm = do_GetService(PSM_COMPONENT_CONTRACTID, &rv);
+    MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
 }
 
 bool NS_IsAboutBlank(nsIURI *uri)
 {
     // GetSpec can be expensive for some URIs, so check the scheme first.
     bool isAbout = false;
     if (NS_FAILED(uri->SchemeIs("about", &isAbout)) || !isAbout) {
         return false;
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -3,18 +3,20 @@
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PHttpChannel;
 include protocol PFTPChannel;
 include protocol PRtspChannel;
+include protocol PSendStream;
 include BlobTypes;
 include URIParams;
+include IPCStream;
 include InputStreamParams;
 include PBackgroundSharedTypes;
 
 using mozilla::NeckoOriginAttributes from "mozilla/ipc/BackgroundUtils.h";
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 using RequestHeaderTuples from "mozilla/net/PHttpChannelParams.h";
 using struct nsHttpAtom from "nsHttp.h";
 using class nsHttpResponseHead from "nsHttpResponseHead.h";
@@ -95,32 +97,31 @@ struct HttpChannelOpenArgs
   OptionalURIParams           doc;
   OptionalURIParams           referrer;
   uint32_t                    referrerPolicy;
   OptionalURIParams           apiRedirectTo;
   OptionalURIParams           topWindowURI;
   uint32_t                    loadFlags;
   RequestHeaderTuples         requestHeaders;
   nsCString                   requestMethod;
-  OptionalInputStreamParams   uploadStream;
+  OptionalIPCStream           uploadStream;
   bool                        uploadStreamHasHeaders;
   uint16_t                    priority;
   uint32_t                    classOfService;
   uint8_t                     redirectionLimit;
   bool                        allowPipelining;
   bool                        allowSTS;
   uint32_t                    thirdPartyFlags;
   bool                        resumeAt;
   uint64_t                    startPos;
   nsCString                   entityID;
   bool                        chooseApplicationCache;
   nsCString                   appCacheClientID;
   bool                        allowSpdy;
   bool                        allowAltSvc;
-  OptionalFileDescriptorSet   fds;
   OptionalLoadInfoArgs        loadInfo;
   OptionalHttpResponseHead    synthesizedResponseHead;
   nsCString                   synthesizedSecurityInfoSerialization;
   uint32_t                    cacheKey;
   nsCString                   requestContextID;
   OptionalCorsPreflightArgs   preflightArgs;
   uint32_t                    initialRwin;
   bool                        blockAuthPrompt;
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -18,16 +18,17 @@ include protocol PTCPServerSocket;
 include protocol PUDPSocket;
 include protocol PRemoteOpenFile;
 include protocol PDNSRequest;
 include protocol PChannelDiverter;
 include protocol PBlob; //FIXME: bug #792908
 include protocol PFileDescriptorSet;
 include protocol PDataChannel;
 include protocol PTransportProvider;
+include protocol PSendStream;
 
 include protocol PRtspController;
 include protocol PRtspChannel;
 include URIParams;
 include InputStreamParams;
 include NeckoChannelParams;
 include PBrowserOrId;
 include protocol PAltDataOutputStream;
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -9,16 +9,17 @@
 #include "HttpLog.h"
 
 #include "nsHttp.h"
 #include "nsICacheEntry.h"
 #include "mozilla/Unused.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
+#include "mozilla/ipc/IPCStreamUtils.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/net/HttpChannelChild.h"
 
 #include "nsISupportsPrimitives.h"
 #include "nsChannelClassifier.h"
 #include "nsStringStream.h"
 #include "nsHttpHandler.h"
 #include "nsNetUtil.h"
@@ -1929,63 +1930,45 @@ HttpChannelChild::ContinueAsyncOpen()
   SerializeURI(mReferrer, openArgs.referrer());
   openArgs.referrerPolicy() = mReferrerPolicy;
   SerializeURI(mAPIRedirectToURI, openArgs.apiRedirectTo());
   openArgs.loadFlags() = mLoadFlags;
   openArgs.requestHeaders() = mClientSetRequestHeaders;
   mRequestHead.Method(openArgs.requestMethod());
   openArgs.preferredAlternativeType() = mPreferredCachedAltDataType;
 
-  nsTArray<mozilla::ipc::FileDescriptor> fds;
-  SerializeInputStream(mUploadStream, openArgs.uploadStream(), fds);
-
+  AutoIPCStream autoStream(openArgs.uploadStream());
+  if (mUploadStream) {
+    autoStream.Serialize(mUploadStream, ContentChild::GetSingleton());
+    autoStream.TakeOptionalValue();
+  }
+  
   if (mResponseHead) {
     openArgs.synthesizedResponseHead() = *mResponseHead;
     openArgs.suspendAfterSynthesizeResponse() =
       mSuspendParentAfterSynthesizeResponse;
   } else {
     openArgs.synthesizedResponseHead() = mozilla::void_t();
     openArgs.suspendAfterSynthesizeResponse() = false;
   }
 
   nsCOMPtr<nsISerializable> secInfoSer = do_QueryInterface(mSecurityInfo);
   if (secInfoSer) {
     NS_SerializeToString(secInfoSer, openArgs.synthesizedSecurityInfoSerialization());
   }
 
-  OptionalFileDescriptorSet optionalFDs;
-
-  if (fds.IsEmpty()) {
-    optionalFDs = mozilla::void_t();
-  } else if (fds.Length() <= kMaxFileDescriptorsPerMessage) {
-    optionalFDs = nsTArray<mozilla::ipc::FileDescriptor>();
-    optionalFDs.get_ArrayOfFileDescriptor().SwapElements(fds);
-  } else {
-    MOZ_ASSERT(gNeckoChild->Manager());
-
-    PFileDescriptorSetChild* fdSet =
-      gNeckoChild->Manager()->SendPFileDescriptorSetConstructor(fds[0]);
-    for (uint32_t i = 1; i < fds.Length(); ++i) {
-      Unused << fdSet->SendAddFileDescriptor(fds[i]);
-    }
-
-    optionalFDs = fdSet;
-  }
-
   OptionalCorsPreflightArgs optionalCorsPreflightArgs;
   GetClientSetCorsPreflightParameters(optionalCorsPreflightArgs);
 
   // NB: This call forces us to cache mTopWindowURI if we haven't already.
   nsCOMPtr<nsIURI> uri;
   GetTopWindowURI(getter_AddRefs(uri));
 
   SerializeURI(mTopWindowURI, openArgs.topWindowURI());
 
-  openArgs.fds() = optionalFDs;
-
   openArgs.preflightArgs() = optionalCorsPreflightArgs;
 
   openArgs.uploadStreamHasHeaders() = mUploadStreamHasHeaders;
   openArgs.priority() = mPriority;
   openArgs.classOfService() = mClassOfService;
   openArgs.redirectionLimit() = mRedirectionLimit;
   openArgs.allowPipelining() = mAllowPipelining;
   openArgs.allowSTS() = mAllowSTS;
@@ -2046,25 +2029,16 @@ HttpChannelChild::ContinueAsyncOpen()
 
   PBrowserOrId browser = cc->GetBrowserOrId(tabChild);
   if (!gNeckoChild->SendPHttpChannelConstructor(this, browser,
                                                 IPC::SerializedLoadContext(this),
                                                 openArgs)) {
     return NS_ERROR_FAILURE;
   }
 
-  if (optionalFDs.type() ==
-        OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
-    FileDescriptorSetChild* fdSetActor =
-      static_cast<FileDescriptorSetChild*>(
-        optionalFDs.get_PFileDescriptorSetChild());
-
-    fdSetActor->ForgetFileDescriptors(fds);
-  }
-
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::nsIHttpChannel
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -7,16 +7,17 @@
 // HttpLog.h should generally be included first
 #include "HttpLog.h"
 
 #include "mozilla/ipc/FileDescriptorSetParent.h"
 #include "mozilla/net/HttpChannelParent.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/net/NeckoParent.h"
+#include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "HttpChannelParentListener.h"
 #include "nsHttpHandler.h"
 #include "nsNetUtil.h"
 #include "nsISupportsPriority.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsSerializationHelper.h"
 #include "nsISerializable.h"
@@ -29,16 +30,17 @@
 #include "nsIAuthPromptCallback.h"
 #include "nsIContentPolicy.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "nsICachingChannel.h"
 #include "mozilla/LoadInfo.h"
 #include "nsQueryObject.h"
 #include "mozilla/BasePrincipal.h"
 #include "nsCORSListenerProxy.h"
+#include "nsIIPCSerializableInputStream.h"
 #include "nsIPrompt.h"
 #include "nsIWindowWatcher.h"
 #include "nsIDocument.h"
 #include "nsStringStream.h"
 
 using mozilla::BasePrincipal;
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
@@ -116,17 +118,17 @@ HttpChannelParent::Init(const HttpChanne
     return DoAsyncOpen(a.uri(), a.original(), a.doc(), a.referrer(),
                        a.referrerPolicy(), a.apiRedirectTo(), a.topWindowURI(),
                        a.loadFlags(), a.requestHeaders(),
                        a.requestMethod(), a.uploadStream(),
                        a.uploadStreamHasHeaders(), a.priority(), a.classOfService(),
                        a.redirectionLimit(), a.allowPipelining(), a.allowSTS(),
                        a.thirdPartyFlags(), a.resumeAt(), a.startPos(),
                        a.entityID(), a.chooseApplicationCache(),
-                       a.appCacheClientID(), a.allowSpdy(), a.allowAltSvc(), a.fds(),
+                       a.appCacheClientID(), a.allowSpdy(), a.allowAltSvc(),
                        a.loadInfo(), a.synthesizedResponseHead(),
                        a.synthesizedSecurityInfoSerialization(),
                        a.cacheKey(), a.requestContextID(), a.preflightArgs(),
                        a.initialRwin(), a.blockAuthPrompt(),
                        a.suspendAfterSynthesizeResponse(),
                        a.allowStaleCacheContent(), a.contentTypeHint(),
                        a.channelId(), a.preferredAlternativeType());
   }
@@ -217,43 +219,107 @@ HttpChannelParent::GetInterface(const ns
 
   return QueryInterface(aIID, result);
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelParent::PHttpChannelParent
 //-----------------------------------------------------------------------------
 
+void
+HttpChannelParent::InvokeAsyncOpen(nsresult rv)
+{
+  if (NS_FAILED(rv)) {
+    Unused << SendFailedAsyncOpen(rv);
+    return;
+  }
+
+  nsCOMPtr<nsILoadInfo> loadInfo;
+  rv = mChannel->GetLoadInfo(getter_AddRefs(loadInfo));
+  if (NS_FAILED(rv)) {
+    Unused << SendFailedAsyncOpen(rv);
+    return;
+  }
+  if (loadInfo && loadInfo->GetEnforceSecurity()) {
+    rv = mChannel->AsyncOpen2(mParentListener);
+  }
+  else {
+    rv = mChannel->AsyncOpen(mParentListener, nullptr);
+  }
+  if (NS_FAILED(rv)) {
+    Unused << SendFailedAsyncOpen(rv);
+  }
+}
+
+namespace {
+class InvokeAsyncOpen : public Runnable
+{
+  nsMainThreadPtrHandle<nsIInterfaceRequestor> mChannel;
+  nsresult mStatus;
+public:
+  InvokeAsyncOpen(const nsMainThreadPtrHandle<nsIInterfaceRequestor>& aChannel,
+                  nsresult aStatus)
+  : mChannel(aChannel)
+  , mStatus(aStatus)
+  {
+  }
+
+  NS_IMETHOD Run()
+  {
+    RefPtr<HttpChannelParent> channel = do_QueryObject(mChannel.get());
+    channel->InvokeAsyncOpen(mStatus);
+    return NS_OK;
+  }
+};
+
+struct UploadStreamClosure {
+  nsMainThreadPtrHandle<nsIInterfaceRequestor> mChannel;
+
+  explicit UploadStreamClosure(const nsMainThreadPtrHandle<nsIInterfaceRequestor>& aChannel)
+  : mChannel(aChannel)
+  {
+  }
+};
+
+void
+UploadCopyComplete(void* aClosure, nsresult aStatus) {
+  // Called on the Stream Transport Service thread by NS_AsyncCopy
+  MOZ_ASSERT(!NS_IsMainThread());
+  UniquePtr<UploadStreamClosure> closure(static_cast<UploadStreamClosure*>(aClosure));
+  nsCOMPtr<nsIRunnable> event = new InvokeAsyncOpen(closure->mChannel, aStatus);
+  NS_DispatchToMainThread(event);
+}
+} // anonymous namespace
+
 bool
 HttpChannelParent::DoAsyncOpen(  const URIParams&           aURI,
                                  const OptionalURIParams&   aOriginalURI,
                                  const OptionalURIParams&   aDocURI,
                                  const OptionalURIParams&   aReferrerURI,
                                  const uint32_t&            aReferrerPolicy,
                                  const OptionalURIParams&   aAPIRedirectToURI,
                                  const OptionalURIParams&   aTopWindowURI,
                                  const uint32_t&            aLoadFlags,
                                  const RequestHeaderTuples& requestHeaders,
                                  const nsCString&           requestMethod,
-                                 const OptionalInputStreamParams& uploadStream,
+                                 const OptionalIPCStream&   uploadStream,
                                  const bool&                uploadStreamHasHeaders,
                                  const uint16_t&            priority,
                                  const uint32_t&            classOfService,
                                  const uint8_t&             redirectionLimit,
                                  const bool&                allowPipelining,
                                  const bool&                allowSTS,
                                  const uint32_t&            thirdPartyFlags,
                                  const bool&                doResumeAt,
                                  const uint64_t&            startPos,
                                  const nsCString&           entityID,
                                  const bool&                chooseApplicationCache,
                                  const nsCString&           appCacheClientID,
                                  const bool&                allowSpdy,
                                  const bool&                allowAltSvc,
-                                 const OptionalFileDescriptorSet& aFds,
                                  const OptionalLoadInfoArgs& aLoadInfoArgs,
                                  const OptionalHttpResponseHead& aSynthesizedResponseHead,
                                  const nsCString&           aSecurityInfoSerialization,
                                  const uint32_t&            aCacheKey,
                                  const nsCString&           aRequestContextID,
                                  const OptionalCorsPreflightArgs& aCorsPreflightArgs,
                                  const uint32_t&            aInitialRwin,
                                  const bool&                aBlockAuthPrompt,
@@ -342,39 +408,78 @@ HttpChannelParent::DoAsyncOpen(  const U
   }
 
   mParentListener = new HttpChannelParentListener(this);
 
   mChannel->SetNotificationCallbacks(mParentListener);
 
   mChannel->SetRequestMethod(nsDependentCString(requestMethod.get()));
 
-  nsTArray<mozilla::ipc::FileDescriptor> fds;
-  if (aFds.type() == OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
-    FileDescriptorSetParent* fdSetActor =
-      static_cast<FileDescriptorSetParent*>(aFds.get_PFileDescriptorSetParent());
-    MOZ_ASSERT(fdSetActor);
-
-    fdSetActor->ForgetFileDescriptors(fds);
-    MOZ_ASSERT(!fds.IsEmpty());
-
-    Unused << fdSetActor->Send__delete__(fdSetActor);
-  } else if (aFds.type() == OptionalFileDescriptorSet::TArrayOfFileDescriptor) {
-    const_cast<OptionalFileDescriptorSet&>(aFds).
-      get_ArrayOfFileDescriptor().SwapElements(fds);
-  }
-
   if (aCorsPreflightArgs.type() == OptionalCorsPreflightArgs::TCorsPreflightArgs) {
     const CorsPreflightArgs& args = aCorsPreflightArgs.get_CorsPreflightArgs();
     mChannel->SetCorsPreflightParameters(args.unsafeHeaders());
   }
 
-  nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(uploadStream, fds);
+  bool delayAsyncOpen = false;
+  nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(uploadStream);
   if (stream) {
-    mChannel->InternalSetUploadStream(stream);
+    // FIXME: The fast path of using the existing stream currently only applies to streams
+    //   that have had their entire contents serialized from the child at this point.
+    //   Once bug 1294446 and bug 1294450 are fixed it is worth revisiting this heuristic.
+    nsCOMPtr<nsIIPCSerializableInputStream> completeStream = do_QueryInterface(stream);
+    if (!completeStream) {
+      delayAsyncOpen = true;
+
+      // buffer size matches PSendStream transfer size.
+      const uint32_t kBufferSize = 32768;
+
+      nsCOMPtr<nsIStorageStream> storageStream;
+      nsresult rv = NS_NewStorageStream(kBufferSize, UINT32_MAX,
+                                        getter_AddRefs(storageStream));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return SendFailedAsyncOpen(rv);
+      }
+
+      nsCOMPtr<nsIInputStream> newUploadStream;
+      rv = storageStream->NewInputStream(0, getter_AddRefs(newUploadStream));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return SendFailedAsyncOpen(rv);
+      }
+
+      nsCOMPtr<nsIOutputStream> sink;
+      rv = storageStream->GetOutputStream(0, getter_AddRefs(sink));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return SendFailedAsyncOpen(rv);
+      }
+
+      nsCOMPtr<nsIEventTarget> target =
+          do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
+      if (NS_FAILED(rv) || !target) {
+        return SendFailedAsyncOpen(rv);
+      }
+
+      nsCOMPtr<nsIInterfaceRequestor> iir = static_cast<nsIInterfaceRequestor*>(this);
+      nsMainThreadPtrHandle<nsIInterfaceRequestor> handle =
+          nsMainThreadPtrHandle<nsIInterfaceRequestor>(
+              new nsMainThreadPtrHolder<nsIInterfaceRequestor>(iir));
+      UniquePtr<UploadStreamClosure> closure(new UploadStreamClosure(handle));
+
+      // Accumulate the stream contents as the child sends it. We will continue with
+      // the AsyncOpen process once the full stream has been received.
+      rv = NS_AsyncCopy(stream, sink, target, NS_ASYNCCOPY_VIA_READSEGMENTS,
+                        kBufferSize, // copy segment size
+                        UploadCopyComplete, closure.release());
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return SendFailedAsyncOpen(rv);
+      }
+
+      mChannel->InternalSetUploadStream(newUploadStream);
+    } else {
+      mChannel->InternalSetUploadStream(stream);
+    }
     mChannel->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
   }
 
   if (aSynthesizedResponseHead.type() == OptionalHttpResponseHead::TnsHttpResponseHead) {
     mParentListener->SetupInterception(aSynthesizedResponseHead.get_nsHttpResponseHead());
     mWillSynthesizeResponse = true;
     mChannel->SetCouldBeSynthesized();
 
@@ -463,24 +568,19 @@ HttpChannelParent::DoAsyncOpen(  const U
   }
 
   nsID requestContextID;
   requestContextID.Parse(aRequestContextID.BeginReading());
   mChannel->SetRequestContextID(requestContextID);
 
   mSuspendAfterSynthesizeResponse = aSuspendAfterSynthesizeResponse;
 
-  if (loadInfo && loadInfo->GetEnforceSecurity()) {
-    rv = mChannel->AsyncOpen2(mParentListener);
+  if (!delayAsyncOpen) {
+    InvokeAsyncOpen(NS_OK);
   }
-  else {
-    rv = mChannel->AsyncOpen(mParentListener, nullptr);
-  }
-  if (NS_FAILED(rv))
-    return SendFailedAsyncOpen(rv);
 
   return true;
 }
 
 bool
 HttpChannelParent::ConnectChannel(const uint32_t& registrarId, const bool& shouldIntercept)
 {
   nsresult rv;
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -93,47 +93,47 @@ public:
   void SetApplyConversion(bool aApplyConversion) {
     if (mChannel) {
       mChannel->SetApplyConversion(aApplyConversion);
     }
   }
 
   nsresult OpenAlternativeOutputStream(const nsACString & type, nsIOutputStream * *_retval);
 
+  void InvokeAsyncOpen(nsresult rv);
 protected:
   // used to connect redirected-to channel in parent with just created
   // ChildChannel.  Used during redirects.
   bool ConnectChannel(const uint32_t& channelId, const bool& shouldIntercept);
 
   bool DoAsyncOpen(const URIParams&           uri,
                    const OptionalURIParams&   originalUri,
                    const OptionalURIParams&   docUri,
                    const OptionalURIParams&   referrerUri,
                    const uint32_t&            referrerPolicy,
                    const OptionalURIParams&   internalRedirectUri,
                    const OptionalURIParams&   topWindowUri,
                    const uint32_t&            loadFlags,
                    const RequestHeaderTuples& requestHeaders,
                    const nsCString&           requestMethod,
-                   const OptionalInputStreamParams& uploadStream,
+                   const OptionalIPCStream&   uploadStream,
                    const bool&                uploadStreamHasHeaders,
                    const uint16_t&            priority,
                    const uint32_t&            classOfService,
                    const uint8_t&             redirectionLimit,
                    const bool&                allowPipelining,
                    const bool&                allowSTS,
                    const uint32_t&            thirdPartyFlags,
                    const bool&                doResumeAt,
                    const uint64_t&            startPos,
                    const nsCString&           entityID,
                    const bool&                chooseApplicationCache,
                    const nsCString&           appCacheClientID,
                    const bool&                allowSpdy,
                    const bool&                allowAltSvc,
-                   const OptionalFileDescriptorSet& aFds,
                    const OptionalLoadInfoArgs& aLoadInfoArgs,
                    const OptionalHttpResponseHead& aSynthesizedResponseHead,
                    const nsCString&           aSecurityInfoSerialization,
                    const uint32_t&            aCacheKey,
                    const nsCString&           aRequestContextID,
                    const OptionalCorsPreflightArgs& aCorsPreflightArgs,
                    const uint32_t&            aInitialRwin,
                    const bool&                aBlockAuthPrompt,
--- a/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp
+++ b/netwerk/protocol/http/nsHttpChannelAuthProvider.cpp
@@ -24,16 +24,18 @@
 #include "netCore.h"
 #include "nsIHttpAuthenticableChannel.h"
 #include "nsIURI.h"
 #include "nsContentUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsILoadContext.h"
 #include "nsIURL.h"
 #include "mozilla/Telemetry.h"
+#include "nsIProxiedChannel.h"
+#include "nsIProxyInfo.h"
 
 namespace mozilla {
 namespace net {
 
 #define SUBRESOURCE_AUTH_DIALOG_DISALLOW_ALL 0
 #define SUBRESOURCE_AUTH_DIALOG_DISALLOW_CROSS_ORIGIN 1
 #define SUBRESOURCE_AUTH_DIALOG_ALLOW_ALL 2
 
@@ -61,16 +63,19 @@ GetOriginAttributesSuffix(nsIChannel* aC
         NS_GetOriginAttributes(aChan, oa);
     }
 
     oa.CreateSuffix(aSuffix);
 }
 
 nsHttpChannelAuthProvider::nsHttpChannelAuthProvider()
     : mAuthChannel(nullptr)
+    , mPort(-1)
+    , mUsingSSL(false)
+    , mProxyUsingSSL(false)
     , mIsPrivate(false)
     , mProxyAuthContinuationState(nullptr)
     , mAuthContinuationState(nullptr)
     , mProxyAuth(false)
     , mTriedProxyAuth(false)
     , mTriedHostAuth(false)
     , mSuppressDefensiveAuth(false)
     , mCrossOrigin(false)
@@ -103,16 +108,31 @@ nsHttpChannelAuthProvider::Init(nsIHttpA
     mAuthChannel = channel;
 
     nsresult rv = mAuthChannel->GetURI(getter_AddRefs(mURI));
     if (NS_FAILED(rv)) return rv;
 
     mAuthChannel->GetIsSSL(&mUsingSSL);
     if (NS_FAILED(rv)) return rv;
 
+    nsCOMPtr<nsIProxiedChannel> proxied(do_QueryInterface(channel));
+    if (proxied) {
+        nsCOMPtr<nsIProxyInfo> pi;
+        rv = proxied->GetProxyInfo(getter_AddRefs(pi));
+        if (NS_FAILED(rv)) return rv;
+
+        if (pi) {
+            nsAutoCString proxyType;
+            rv = pi->GetType(proxyType);
+            if (NS_FAILED(rv)) return rv;
+
+            mProxyUsingSSL = proxyType.EqualsLiteral("https");
+        }
+    }
+
     rv = mURI->GetAsciiHost(mHost);
     if (NS_FAILED(rv)) return rv;
 
     // reject the URL if it doesn't specify a host
     if (mHost.IsEmpty())
         return NS_ERROR_MALFORMED_URI;
 
     rv = mURI->GetPort(&mPort);
@@ -811,17 +831,17 @@ nsHttpChannelAuthProvider::GetCredential
         else if (!identFromURI) {
             // hmm... identity invalid, but no auth entry!  the realm probably
             // changed (see bug 201986).
             ident->Clear();
         }
 
         if (!entry && ident->IsEmpty()) {
             uint32_t level = nsIAuthPrompt2::LEVEL_NONE;
-            if (mUsingSSL)
+            if ((!proxyAuth && mUsingSSL) || (proxyAuth && mProxyUsingSSL))
                 level = nsIAuthPrompt2::LEVEL_SECURE;
             else if (authFlags & nsIHttpAuthenticator::IDENTITY_ENCRYPTED)
                 level = nsIAuthPrompt2::LEVEL_PW_ENCRYPTED;
 
             // Collect statistics on how frequently the various types of HTTP
             // authentication are used over SSL and non-SSL connections.
             if (gHttpHandler->IsTelemetryEnabled()) {
               if (NS_LITERAL_CSTRING("basic").LowerCaseEqualsASCII(authType)) {
--- a/netwerk/protocol/http/nsHttpChannelAuthProvider.h
+++ b/netwerk/protocol/http/nsHttpChannelAuthProvider.h
@@ -137,16 +137,17 @@ private:
 private:
     nsIHttpAuthenticableChannel      *mAuthChannel;  // weak ref
 
     nsCOMPtr<nsIURI>                  mURI;
     nsCOMPtr<nsProxyInfo>             mProxyInfo;
     nsCString                         mHost;
     int32_t                           mPort;
     bool                              mUsingSSL;
+    bool                              mProxyUsingSSL;
     bool                              mIsPrivate;
 
     nsISupports                      *mProxyAuthContinuationState;
     nsCString                         mProxyAuthType;
     nsISupports                      *mAuthContinuationState;
     nsCString                         mAuthType;
     nsHttpAuthIdentity                mIdent;
     nsHttpAuthIdentity                mProxyIdent;
--- a/netwerk/protocol/http/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/nsHttpTransaction.cpp
@@ -984,17 +984,26 @@ nsHttpTransaction::Close(nsresult reason
     // request from the point-of-view of the server.  such duplication could
     // have dire consequences including repeated purchases, etc.
     //
     // NOTE: because of the way SSL proxy CONNECT is implemented, it is
     // possible that the transaction may have received data without having
     // sent any data.  for this reason, mSendData == FALSE does not imply
     // mReceivedData == FALSE.  (see bug 203057 for more info.)
     //
-    if (reason == NS_ERROR_NET_RESET || reason == NS_OK) {
+    // Never restart transactions that are marked as sticky to their conenction.
+    // We use that capability to identify transactions bound to connection based
+    // authentication.  Reissuing them on a different connections will break
+    // this bondage.  Major issue may arise when there is an NTLM message auth
+    // header on the transaction and we send it to a different NTLM authenticated
+    // connection.  It will break that connection and also confuse the channel's
+    // auth provider, beliving the cached credentials are wrong and asking for
+    // the password mistakenly again from the user.
+    if ((reason == NS_ERROR_NET_RESET || reason == NS_OK) &&
+        !(mCaps & NS_HTTP_STICKY_CONNECTION)) {
 
         if (mForceRestart && NS_SUCCEEDED(Restart())) {
             if (mResponseHead) {
                 mResponseHead->Reset();
             }
             mContentRead = 0;
             mContentLength = -1;
             delete mChunkedDecoder;
@@ -1218,16 +1227,20 @@ nsHttpTransaction::RestartInProgress()
     MutexAutoLock lock(*nsHttp::GetLock());
 
     // Don't try and RestartInProgress() things that haven't gotten a response
     // header yet. Those should be handled under the normal restart() path if
     // they are eligible.
     if (!mHaveAllHeaders)
         return NS_ERROR_NET_RESET;
 
+    if (mCaps & NS_HTTP_STICKY_CONNECTION) {
+        return NS_ERROR_NET_RESET;
+    }
+
     // don't try and restart 0.9 or non 200/Get HTTP/1
     if (!mRestartInProgressVerifier.IsSetup())
         return NS_ERROR_NET_RESET;
 
     LOG(("Will restart transaction %p and skip first %lld bytes, "
          "old Content-Length %lld",
          this, mContentRead, mContentLength));
 
--- a/parser/expat/lib/moz_extensions.c
+++ b/parser/expat/lib/moz_extensions.c
@@ -40,27 +40,24 @@ int MOZ_XMLCheckQName(const char* ptr, c
           or we've already seen a colon. */
       if (ns_aware && (nmstrt || *colon || ptr + 2 == end)) {
         return MOZ_EXPAT_MALFORMED;
       }
       *colon = ptr;
       nmstrt = ns_aware; /* e.g. "a:0" should be valid if !ns_aware */
       break;
     case BT_NONASCII:
-      if (nmstrt && !IS_NMSTRT_CHAR_MINBPC(ptr)) {
-        /* If this is a valid name character and we're namespace-aware, the
-           QName is malformed.  Otherwise, this character's invalid at the
-           start of a name (or, if we're namespace-aware, at the start of a
-           localpart). */
-        return (IS_NAME_CHAR_MINBPC(ptr) && ns_aware) ?
-               MOZ_EXPAT_MALFORMED :
-               MOZ_EXPAT_INVALID_CHARACTER;
+      if (!IS_NAME_CHAR_MINBPC(ptr) ||
+          (nmstrt && !*colon && !IS_NMSTRT_CHAR_MINBPC(ptr))) {
+        return MOZ_EXPAT_INVALID_CHARACTER;
       }
-      if (!IS_NAME_CHAR_MINBPC(ptr)) {
-        return MOZ_EXPAT_INVALID_CHARACTER;
+      if (nmstrt && *colon && !IS_NMSTRT_CHAR_MINBPC(ptr)) {
+        /* If a non-starting character like a number is right after the colon,
+           this is a namespace error, not invalid character */
+        return MOZ_EXPAT_MALFORMED;
       }
       nmstrt = 0;
       break;
     case BT_NMSTRT:
     case BT_HEX:
       nmstrt = 0;
       break;
     case BT_DIGIT:
--- a/taskcluster/ci/desktop-test/test-sets.yml
+++ b/taskcluster/ci/desktop-test/test-sets.yml
@@ -41,16 +41,17 @@ asan-tests:
     - crashtest
     - firefox-ui-functional-local
     - firefox-ui-functional-remote
     - gtest
     - jittest
     - jsreftest
     - marionette
     - mochitest
+    - mochitest-a11y
     - mochitest-browser-chrome
     - mochitest-chrome
     - mochitest-clipboard
     - mochitest-devtools-chrome
     - mochitest-gpu
     - mochitest-jetpack
     - mochitest-media
     - mochitest-webgl
--- a/taskcluster/ci/toolchain/kind.yml
+++ b/taskcluster/ci/toolchain/kind.yml
@@ -4,53 +4,11 @@
 
 implementation: taskgraph.task.transform:TransformTask
 
 transforms:
    - taskgraph.transforms.build_attrs:transforms
    - taskgraph.transforms.job:transforms
    - taskgraph.transforms.task:transforms
 
-job-defaults:
-    description: toolchain build
-    treeherder:
-        kind: build
-        tier: 1
-        platform: linux64/opt
-    worker-type: aws-provisioner-v1/gecko-{level}-b-linux
-    worker:
-        implementation: docker-worker
-        docker-image: {in-tree: desktop-build}
-        max-run-time: 36000
-
-jobs:
-    linux64-clang/opt:
-        treeherder:
-            symbol: Cc(Clang)
-        run:
-            using: toolchain-script
-            script: build-clang-linux.sh
-        when:
-            files-changed:
-                - 'build/build-clang/**'
-                - 'taskcluster/scripts/misc/build-clang-linux.sh'
-
-    linux64-gcc/opt:
-        treeherder:
-            symbol: Cc(GCC)
-        run:
-            using: toolchain-script
-            script: build-gcc-linux.sh
-        when:
-            files-changed:
-                - 'build/unix/build-gcc/**'
-                - 'taskcluster/scripts/misc/build-gcc-linux.sh'
-
-    linux64-binutils/opt:
-        treeherder:
-            symbol: Cc(binutils)
-        run:
-            using: toolchain-script
-            script: build-binutils-linux.sh
-        when:
-            files-changed:
-                - 'build/unix/build-binutils/**'
-                - 'taskcluster/scripts/misc/build-binutils-linux.sh'
+jobs-from:
+   - linux.yml
+   - windows.yml
new file mode 100644
--- /dev/null
+++ b/taskcluster/ci/toolchain/linux.yml
@@ -0,0 +1,63 @@
+# 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/.
+
+linux64-clang/opt:
+    description: "Clang toolchain build"
+    treeherder:
+        kind: build
+        platform: linux64/opt
+        symbol: Cc(Clang)
+        tier: 1
+    run:
+        using: toolchain-script
+        script: build-clang-linux.sh
+    worker-type: aws-provisioner-v1/gecko-{level}-b-linux
+    worker:
+        implementation: docker-worker
+        docker-image: {in-tree: desktop-build}
+        max-run-time: 36000
+    when:
+        files-changed:
+            - 'build/build-clang/**'
+            - 'taskcluster/scripts/misc/build-clang-linux.sh'
+
+linux64-gcc/opt:
+    description: "GCC toolchain build"
+    treeherder:
+        kind: build
+        platform: linux64/opt
+        symbol: Cc(GCC)
+        tier: 1
+    run:
+        using: toolchain-script
+        script: build-gcc-linux.sh
+    worker-type: aws-provisioner-v1/gecko-{level}-b-linux
+    worker:
+        implementation: docker-worker
+        docker-image: {in-tree: desktop-build}
+        max-run-time: 36000
+    when:
+        files-changed:
+            - 'build/unix/build-gcc/**'
+            - 'taskcluster/scripts/misc/build-gcc-linux.sh'
+
+linux64-binutils/opt:
+    description: "Binutils toolchain build"
+    treeherder:
+        kind: build
+        platform: linux64/opt
+        symbol: Cc(binutils)
+        tier: 1
+    run:
+        using: toolchain-script
+        script: build-binutils-linux.sh
+    worker-type: aws-provisioner-v1/gecko-{level}-b-linux
+    worker:
+        implementation: docker-worker
+        docker-image: {in-tree: desktop-build}
+        max-run-time: 36000
+    when:
+        files-changed:
+            - 'build/unix/build-binutils/**'
+            - 'taskcluster/scripts/misc/build-binutils-linux.sh'
new file mode 100644
--- /dev/null
+++ b/taskcluster/ci/toolchain/windows.yml
@@ -0,0 +1,22 @@
+# 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/.
+
+win32-clang-cl/opt:
+    description: "Clang-cl toolchain build"
+    treeherder:
+        kind: build
+        platform: windows-2012-32/opt
+        symbol: Cc(ClangCL)
+        tier: 2
+    worker-type: aws-provisioner-v1/gecko-{level}-b-win2012
+    worker:
+        implementation: generic-worker
+        max-run-time: 36000
+    run:
+        using: toolchain-script
+        script: build-clang-windows.sh
+    when:
+        files-changed:
+            - 'build/build-clang/**'
+            - 'taskcluster/scripts/misc/build-clang-windows.sh'
--- a/taskcluster/scripts/misc/build-clang-linux.sh
+++ b/taskcluster/scripts/misc/build-clang-linux.sh
@@ -15,15 +15,16 @@ chmod +x tooltool.py
 export TOOLTOOL_CACHE
 cd src
 $HOME_DIR/tooltool.py -m browser/config/tooltool-manifests/linux64/releng.manifest fetch
 
 # gets a bit too verbose here
 set +x
 
 cd build/build-clang
-./build-clang.py -c clang-static-analysis-linux64.json
+# |mach python| sets up a virtualenv for us!
+../../mach python ./build-clang.py -c clang-static-analysis-linux64.json
 
 set -x
 
 # Put a tarball in the artifacts dir
 mkdir -p $UPLOAD_DIR
 cp clang.tar.* $UPLOAD_DIR
new file mode 100755
--- /dev/null
+++ b/taskcluster/scripts/misc/build-clang-windows.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+set -x -e -v
+
+# This script is for building clang-cl on Windows.
+
+# Fetch our toolchain from tooltool.
+wget -O tooltool.py ${TOOLTOOL_REPO}/raw/${TOOLTOOL_REV}/tooltool.py
+chmod +x tooltool.py
+: TOOLTOOL_CACHE                ${TOOLTOOL_CACHE:=/home/worker/tooltool-cache}
+export TOOLTOOL_CACHE
+
+TOOLTOOL_AUTH_FILE=/c/builds/relengapi.tok
+if [ ! -e ${TOOLTOOL_AUTH_FILE} ]; then
+    echo cannot find ${TOOLTOOL_AUTH_FILE}
+    exit 1
+fi
+
+TOOLTOOL_MANIFEST=build/src/browser/config/tooltool-manifests/win32/build-clang-cl.manifest
+./tooltool.py --authentication-file="${TOOLTOOL_AUTH_FILE}" -m "${TOOLTOOL_MANIFEST}" fetch
+
+# Set up all the Visual Studio paths.
+MSVC_DIR=vs2015u3
+VSWINPATH="$(cd ${MSVC_DIR} && pwd)"
+
+echo vswinpath ${VSWINPATH}
+
+export WINDOWSSDKDIR="${VSWINPATH}/SDK"
+export WIN32_REDIST_DIR="${VSWINPATH}/VC/redist/x86/Microsoft.VC140.CRT"
+export WIN_UCRT_REDIST_DIR="${VSWINPATH}/SDK/Redist/ucrt/DLLs/x86"
+
+export PATH="${VSWINPATH}/VC/bin/amd64_x86:${VSWINPATH}/VC/bin/amd64:${VSWINPATH}/VC/bin:${VSWINPATH}/SDK/bin/x86:${VSWINPATH}/SDK/bin/x64:${VSWINPATH}/DIA SDK/bin:${PATH}"
+export PATH="${VSWINPATH}/VC/redist/x86/Microsoft.VC140.CRT:${VSWINPATH}/VC/redist/x64/Microsoft.VC140.CRT:${VSWINPATH}/SDK/Redist/ucrt/DLLs/x86:${VSWINPATH}/SDK/Redist/ucrt/DLLs/x64:${PATH}"
+
+export INCLUDE="${VSWINPATH}/VC/include:${VSWINPATH}/VC/atlmfc/include:${VSWINPATH}/SDK/Include/10.0.14393.0/ucrt:${VSWINPATH}/SDK/Include/10.0.14393.0/shared:${VSWINPATH}/SDK/Include/10.0.14393.0/um:${VSWINPATH}/SDK/Include/10.0.14393.0/winrt:${VSWINPATH}/DIA SDK/include"
+export LIB="${VSWINPATH}/VC/lib:${VSWINPATH}/VC/atlmfc/lib:${VSWINPATH}/SDK/lib/10.0.14393.0/ucrt/x86:${VSWINPATH}/SDK/lib/10.0.14393.0/um/x86:${VSWINPATH}/DIA SDK/lib"
+
+export PATH="$(cd svn && pwd)/bin:${PATH}"
+export PATH="$(cd cmake && pwd)/bin:${PATH}"
+export PATH="$(cd ninja && pwd)/bin:${PATH}"
+
+# We use |mach python| to set up a virtualenv automatically for us.  We create
+# a dummy mozconfig, because the default machinery for config.guess-choosing
+# of the objdir doesn't work very well.
+MOZCONFIG="$(pwd)/mozconfig"
+cat > ${MOZCONFIG} <<EOF
+mk_add_options MOZ_OBJDIR=$(pwd)/objdir
+EOF
+
+# gets a bit too verbose here
+set +x
+
+BUILD_CLANG_DIR=build/src/build/build-clang
+MOZCONFIG=${MOZCONFIG} build/src/mach python ${BUILD_CLANG_DIR}/build-clang.py -c ${BUILD_CLANG_DIR}/clang-static-analysis-win32.json
+
+set -x
+
+# Put a tarball in the artifacts dir
+UPLOAD_PATH=public/build
+mkdir -p ${UPLOAD_PATH}
+cp clang.tar.* ${UPLOAD_PATH}
--- a/taskcluster/taskgraph/transforms/job/toolchain.py
+++ b/taskcluster/taskgraph/transforms/job/toolchain.py
@@ -60,8 +60,50 @@ def docker_worker_toolchain(config, job,
     env['TOOLTOOL_REV'] = 'master'
 
     command = ' && '.join([
         "cd /home/worker/",
         "./bin/checkout-sources.sh",
         "./workspace/build/src/taskcluster/scripts/misc/" + run['script'],
     ])
     worker['command'] = ["/bin/bash", "-c", command]
+
+
+@run_job_using("generic-worker", "toolchain-script", schema=toolchain_run_schema)
+def windows_toolchain(config, job, taskdesc):
+    run = job['run']
+
+    worker = taskdesc['worker']
+
+    worker['artifacts'] = [{
+        'path': r'public\build',
+        'type': 'directory',
+    }]
+
+    docker_worker_add_gecko_vcs_env_vars(config, job, taskdesc)
+
+    # We fetch LLVM SVN into this.
+    svn_cache = 'level-{}-toolchain-clang-cl-build-svn'.format(config.params['level'])
+    worker['mounts'] = [{
+        'cache-name': svn_cache,
+        'path': r'llvm-sources',
+    }]
+    taskdesc['scopes'].extend([
+        'generic-worker:cache:' + svn_cache,
+    ])
+
+    env = worker['env']
+    env.update({
+        'MOZ_BUILD_DATE': time.strftime("%Y%m%d%H%M%S", time.gmtime(config.params['pushdate'])),
+        'MOZ_SCM_LEVEL': config.params['level'],
+        'TOOLTOOL_REPO': 'https://github.com/mozilla/build-tooltool',
+        'TOOLTOOL_REV': 'master',
+    })
+
+    hg = r'c:\Program Files\Mercurial\hg.exe'
+    bash = r'c:\mozilla-build\msys\bin\bash'
+    worker['command'] = [
+        r'mkdir .\build\src',
+        r'"{}" share c:\builds\hg-shared\mozilla-central .\build\src'.format(hg),
+        r'"{}" pull -u -R .\build\src --rev %GECKO_HEAD_REV% %GECKO_HEAD_REPOSITORY%'.format(hg),
+        # do something intelligent.
+        r'{} -c ./build/src/taskcluster/scripts/misc/{}'.format(bash, run['script'])
+    ]
--- a/taskcluster/taskgraph/transforms/task.py
+++ b/taskcluster/taskgraph/transforms/task.py
@@ -212,16 +212,25 @@ task_description_schema = Schema({
         Optional('artifacts'): [{
             # type of artifact -- simple file, or recursive directory
             'type': Any('file', 'directory'),
 
             # task image path from which to read artifact
             'path': basestring,
         }],
 
+        # directories and/or files to be mounted
+        Optional('mounts'): [{
+            # a unique name for the cache volume
+            'cache-name': basestring,
+
+            # task image path for the cache
+            'path': basestring,
+        }],
+
         # environment variables
         Required('env', default={}): {basestring: taskref_or_string},
 
         # the maximum time to run, in seconds
         'max-run-time': int,
 
         # os user groups for test task workers
         Optional('os-groups', default=[]): [basestring],
@@ -395,20 +404,29 @@ def build_generic_worker_payload(config,
 
     for artifact in worker['artifacts']:
         artifacts.append({
             'path': artifact['path'],
             'type': artifact['type'],
             'expires': task_def['expires'],  # always expire with the task
         })
 
+    mounts = []
+
+    for mount in worker.get('mounts', []):
+        mounts.append({
+            'cacheName': mount['cache-name'],
+            'directory': mount['path']
+        })
+
     task_def['payload'] = {
         'command': worker['command'],
         'artifacts': artifacts,
         'env': worker.get('env', {}),
+        'mounts': mounts,
         'maxRunTime': worker['max-run-time'],
         'osGroups': worker.get('os-groups', []),
     }
 
     if 'retry-exit-status' in worker:
         raise Exception("retry-exit-status not supported in generic-worker")
 
 
--- a/testing/mozbase/mozcrash/mozcrash/mozcrash.py
+++ b/testing/mozbase/mozcrash/mozcrash/mozcrash.py
@@ -316,31 +316,42 @@ class CrashInfo(object):
                          os.path.join(self.dump_save_path, os.path.basename(path)))
 
         if os.path.isfile(extra):
             shutil.move(extra, self.dump_save_path)
             self.logger.info("Saved app info as %s" %
                              os.path.join(self.dump_save_path, os.path.basename(extra)))
 
 
-def check_for_java_exception(logcat, quiet=False):
+def check_for_java_exception(logcat, test_name=None, quiet=False):
     """
     Print a summary of a fatal Java exception, if present in the provided
     logcat output.
 
     Example:
-    PROCESS-CRASH | java-exception | java.lang.NullPointerException at org.mozilla.gecko.GeckoApp$21.run(GeckoApp.java:1833) # noqa
+    PROCESS-CRASH | <test-name> | java-exception java.lang.NullPointerException at org.mozilla.gecko.GeckoApp$21.run(GeckoApp.java:1833) # noqa
 
     `logcat` should be a list of strings.
 
+    If `test_name` is set it will be used as the test name in log output. If not set the
+    filename of the calling function will be used.
+
     If `quiet` is set, no PROCESS-CRASH message will be printed to stdout if a
     crash is detected.
 
     Returns True if a fatal Java exception was found, False otherwise.
     """
+
+    # try to get the caller's filename if no test name is given
+    if test_name is None:
+        try:
+            test_name = os.path.basename(sys._getframe(1).f_code.co_filename)
+        except:
+            test_name = "unknown"
+
     found_exception = False
 
     for i, line in enumerate(logcat):
         # Logs will be of form:
         #
         # 01-30 20:15:41.937 E/GeckoAppShell( 1703): >>> REPORTING UNCAUGHT EXCEPTION FROM THREAD 9 ("GeckoBackgroundThread") # noqa
         # 01-30 20:15:41.937 E/GeckoAppShell( 1703): java.lang.NullPointerException
         # 01-30 20:15:41.937 E/GeckoAppShell( 1703): at org.mozilla.gecko.GeckoApp$21.run(GeckoApp.java:1833) # noqa
@@ -353,18 +364,19 @@ def check_for_java_exception(logcat, qui
                 logre = re.compile(r".*\): \t?(.*)")
                 m = logre.search(logcat[i + 1])
                 if m and m.group(1):
                     exception_type = m.group(1)
                 m = logre.search(logcat[i + 2])
                 if m and m.group(1):
                     exception_location = m.group(1)
                 if not quiet:
-                    print "PROCESS-CRASH | java-exception | %s %s" % (exception_type,
-                                                                      exception_location)
+                    print "PROCESS-CRASH | %s | java-exception %s %s" % (test_name,
+                                                                         exception_type,
+                                                                         exception_location)
             else:
                 print "Automation Error: java exception in logcat at line " \
                     "%d of %d: %s" % (i, len(logcat), line)
             break
 
     return found_exception
 
 if mozinfo.isWin:
--- a/testing/web-platform/meta/dom/nodes/DOMImplementation-createDocument.html.ini
+++ b/testing/web-platform/meta/dom/nodes/DOMImplementation-createDocument.html.ini
@@ -1,30 +1,18 @@
 [DOMImplementation-createDocument.html]
   type: testharness
-  [createDocument test 6: null,"̀foo",null,"INVALID_CHARACTER_ERR"]
+  [createDocument test: "http://example.com/","a:0",null,"NAMESPACE_ERR"]
     expected: FAIL
-    bug: 1298818
+    bug: https://github.com/whatwg/dom/issues/319
 
-  [createDocument test 172: metadata for null,null,DocumentType node]
-    expected: FAIL
-    bug: 520969
-
-  [createDocument test 172: null,null,DocumentType node,null]
+  [createDocument test: null,null,DocumentType node <!DOCTYPE html>,null]
     expected: FAIL
     bug: 520969
 
-  [createDocument test 185: null,"",DocumentType node]
+  [createDocument test 195: metadata for null,null,DocumentType node <!DOCTYPE html>]
     expected: FAIL
     bug: 520969
 
-  [createDocument test: null,"̀foo",null,"INVALID_CHARACTER_ERR"]
-    expected: FAIL
-
-  [createDocument test: null,null,DocumentType node <!DOCTYPE html>,null]
-    expected: FAIL
-
-  [createDocument test 170: metadata for null,null,DocumentType node <!DOCTYPE html>]
-    expected: FAIL
-
   [createDocument test: null,"",DocumentType node <!DOCTYPE html -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd>]
     expected: FAIL
+    bug: 520969
 
--- a/testing/web-platform/meta/dom/nodes/Document-createElementNS.html.ini
+++ b/testing/web-platform/meta/dom/nodes/Document-createElementNS.html.ini
@@ -1,8 +1,14 @@
 [Document-createElementNS.html]
   type: testharness
-  [createElementNS test 6: null,"̀foo","INVALID_CHARACTER_ERR"]
+  [createElementNS test in HTML document: "http://example.com/","a:0","NAMESPACE_ERR"]
+    bug: https://github.com/whatwg/dom/issues/319
     expected: FAIL
 
-  [createElementNS test: null,"̀foo","INVALID_CHARACTER_ERR"]
+  [createElementNS test in XML document: "http://example.com/","a:0","NAMESPACE_ERR"]
+    bug: https://github.com/whatwg/dom/issues/319
     expected: FAIL
 
+  [createElementNS test in XHTML document: "http://example.com/","a:0","NAMESPACE_ERR"]
+    bug: https://github.com/whatwg/dom/issues/319
+    expected: FAIL
+
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/common/dummy.xhtml
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<html><head><title>Dummy XHTML document</title></head><body /></html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/common/dummy.xml
@@ -0,0 +1,1 @@
+<foo>Dummy XML document</foo>
--- a/testing/web-platform/tests/dom/nodes/Document-createElement.html
+++ b/testing/web-platform/tests/dom/nodes/Document-createElement.html
@@ -4,82 +4,154 @@
 <link rel=help href="https://dom.spec.whatwg.org/#dom-document-createelement">
 <link rel=help href="https://dom.spec.whatwg.org/#dom-element-localname">
 <link rel=help href="https://dom.spec.whatwg.org/#dom-element-tagname">
 <link rel=help href="https://dom.spec.whatwg.org/#dom-element-prefix">
 <link rel=help href="https://dom.spec.whatwg.org/#dom-element-namespaceuri">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <div id="log"></div>
+<iframe src="/common/dummy.xml"></iframe>
+<iframe src="/common/dummy.xhtml"></iframe>
 <script>
 function toASCIIUppercase(str) {
   var diff = "a".charCodeAt(0) - "A".charCodeAt(0);
   var res = "";
   for (var i = 0; i < str.length; ++i) {
     if ("a" <= str[i] && str[i] <= "z") {
       res += String.fromCharCode(str.charCodeAt(i) - diff);
     } else {
       res += str[i];
     }
   }
   return res;
 }
-test(function() {
-  var HTMLNS = "http://www.w3.org/1999/xhtml",
-      valid = [
-        //[input, localName],
-        [undefined, "undefined"],
-        [null, "null"],
-        ["foo", "foo"],
-        ["f1oo", "f1oo"],
-        ["foo1", "foo1"],
-        ["f\u0300oo", "f\u0300oo"],
-        ["foo\u0300", "foo\u0300"],
-        [":foo", ":foo"],
-        ["f:oo", "f:oo"],
-        ["foo:", "foo:"],
-        ["xml", "xml"],
-        ["xmlns", "xmlns"],
-        ["xmlfoo", "xmlfoo"],
-        ["xml:foo", "xml:foo"],
-        ["xmlns:foo", "xmlns:foo"],
-        ["xmlfoo:bar", "xmlfoo:bar"],
-        ["svg", "svg"],
-        ["math", "math"],
-        ["FOO", "foo"],
-        ["mar\u212a", "mar\u212a"],
-        ["\u0130nput", "\u0130nput"],
-        ["\u0131nput", "\u0131nput"]
-     ],
-     invalid = [
-       "",
-       "1foo",
-       "\u0300foo",
-       "}foo",
-       "f}oo",
-       "foo}",
-       "\ufffffoo",
-       "f\uffffoo",
-       "foo\uffff",
-       "<foo",
-       "foo>",
-       "<foo>",
-       "f<oo"
-     ]
+function toASCIILowercase(str) {
+  var diff = "a".charCodeAt(0) - "A".charCodeAt(0);
+  var res = "";
+  for (var i = 0; i < str.length; ++i) {
+    if ("A" <= str[i] && str[i] <= "Z") {
+      res += String.fromCharCode(str.charCodeAt(i) + diff);
+    } else {
+      res += str[i];
+    }
+  }
+  return res;
+}
+var HTMLNS = "http://www.w3.org/1999/xhtml",
+    valid = [
+      undefined,
+      null,
+      "foo",
+      "f1oo",
+      "foo1",
+      "f\u0BC6",
+      "foo\u0BC6",
+      ":",
+      ":foo",
+      "f:oo",
+      "foo:",
+      "f:o:o",
+      "f::oo",
+      "f::oo:",
+      "foo:0",
+      "foo:_",
+      // combining char after :, invalid QName but valid Name
+      "foo:\u0BC6",
+      "foo:foo\u0BC6",
+      "foo\u0BC6:foo",
+      "xml",
+      "xmlns",
+      "xmlfoo",
+      "xml:foo",
+      "xmlns:foo",
+      "xmlfoo:bar",
+      "svg",
+      "math",
+      "FOO",
+      // Test that non-ASCII chars don't get uppercased/lowercased
+      "mar\u212a",
+      "\u0130nput",
+      "\u0131nput",
+    ],
+    invalid = [
+      "",
+      "1foo",
+      "1:foo",
+      "fo o",
+      "\u0BC6foo",
+      "}foo",
+      "f}oo",
+      "foo}",
+      "\ufffffoo",
+      "f\uffffoo",
+      "foo\uffff",
+      "<foo",
+      "foo>",
+      "<foo>",
+      "f<oo",
+      "-foo",
+      ".foo",
+      "\u0BC6",
+    ]
 
-  valid.forEach(function(t) {
-    test(function() {
-      var elt = document.createElement(t[0])
-      assert_true(elt instanceof Element)
-      assert_true(elt instanceof Node)
-      assert_equals(elt.localName, t[1])
-      assert_equals(elt.tagName, toASCIIUppercase(t[1]))
-      assert_equals(elt.prefix, null)
-      assert_equals(elt.namespaceURI, HTMLNS)
-    }, "createElement(" + format_value(t[0]) + ")");
+var xmlIframe = document.querySelector('[src="/common/dummy.xml"]');
+var xhtmlIframe = document.querySelector('[src="/common/dummy.xhtml"]');
+
+function getWin(desc) {
+  if (desc == "HTML document") {
+    return window;
+  }
+  if (desc == "XML document") {
+    assert_equals(xmlIframe.contentDocument.documentElement.textContent,
+                  "Dummy XML document", "XML document didn't load");
+    return xmlIframe.contentWindow;
+  }
+  if (desc == "XHTML document") {
+    assert_equals(xhtmlIframe.contentDocument.documentElement.textContent,
+                  "Dummy XHTML document", "XHTML document didn't load");
+    return xhtmlIframe.contentWindow;
+  }
+}
+
+
+valid.forEach(function(t) {
+  ["HTML document", "XML document", "XHTML document"].forEach(function(desc) {
+    async_test(function(testObj) {
+      window.addEventListener("load", function() {
+        testObj.step(function() {
+          var win = getWin(desc);
+          var doc = win.document;
+          var elt = doc.createElement(t)
+          assert_true(elt instanceof win.Element, "instanceof Element")
+          assert_true(elt instanceof win.Node, "instanceof Node")
+          assert_equals(elt.localName,
+                        desc == "HTML document" ? toASCIILowercase(String(t))
+                                                : String(t),
+                        "localName")
+          assert_equals(elt.tagName,
+                        desc == "HTML document" ? toASCIIUppercase(String(t))
+                                                : String(t),
+                        "tagName")
+          assert_equals(elt.prefix, null, "prefix")
+          assert_equals(elt.namespaceURI,
+                        desc == "XML document" ? null : HTMLNS, "namespaceURI")
+        });
+        testObj.done();
+      });
+    }, "createElement(" + format_value(t) + ") in " + desc);
   });
-  invalid.forEach(function(arg) {
-    test(function() {
-      assert_throws("INVALID_CHARACTER_ERR", function() { document.createElement(arg) })
-    }, "createElement(" + format_value(arg) + ")");
+});
+invalid.forEach(function(arg) {
+  ["HTML document", "XML document", "XHTML document"].forEach(function(desc) {
+    async_test(function(testObj) {
+      window.addEventListener("load", function() {
+        testObj.step(function() {
+          var doc = getWin(desc).document;
+          assert_throws("InvalidCharacterError",
+                        function() { doc.createElement(arg) })
+        });
+        testObj.done();
+      });
+    }, "createElement(" + format_value(arg) + ") in " + desc);
   });
-})
+});
 </script>
--- a/testing/web-platform/tests/dom/nodes/Document-createElementNS.html
+++ b/testing/web-platform/tests/dom/nodes/Document-createElementNS.html
@@ -1,69 +1,97 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
 <title>Document.createElementNS</title>
 <link rel=help href="https://dom.spec.whatwg.org/#dom-document-createelementns">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="Document-createElementNS.js"></script>
 <div id="log"></div>
+<iframe src="/common/dummy.xml"></iframe>
+<iframe src="/common/dummy.xhtml"></iframe>
 <script>
-test(function() {
-  var tests = createElementNS_tests.concat([
-    /* Arrays with three elements:
-     *   the namespace argument
-     *   the qualifiedName argument
-     *   the expected exception, or null if none
-     */
-    ["", "", "INVALID_CHARACTER_ERR"],
-    [null, null, null],
-    [null, "", "INVALID_CHARACTER_ERR"],
-    [undefined, null, null],
-    [undefined, "", "INVALID_CHARACTER_ERR"],
-    ["http://example.com/", null, null],
-    ["http://example.com/", "", "INVALID_CHARACTER_ERR"],
-    ["/", null, null],
-    ["/", "", "INVALID_CHARACTER_ERR"],
-    ["http://www.w3.org/XML/1998/namespace", null, null],
-    ["http://www.w3.org/XML/1998/namespace", "", "INVALID_CHARACTER_ERR"],
-    ["http://www.w3.org/2000/xmlns/", null, "NAMESPACE_ERR"],
-    ["http://www.w3.org/2000/xmlns/", "", "INVALID_CHARACTER_ERR"],
-    ["foo:", null, null],
-    ["foo:", "", "INVALID_CHARACTER_ERR"],
-  ])
+var tests = createElementNS_tests.concat([
+  /* Arrays with three elements:
+   *   the namespace argument
+   *   the qualifiedName argument
+   *   the expected exception, or null if none
+   */
+  ["", "", "INVALID_CHARACTER_ERR"],
+  [null, null, null],
+  [null, "", "INVALID_CHARACTER_ERR"],
+  [undefined, null, null],
+  [undefined, "", "INVALID_CHARACTER_ERR"],
+  ["http://example.com/", null, null],
+  ["http://example.com/", "", "INVALID_CHARACTER_ERR"],
+  ["/", null, null],
+  ["/", "", "INVALID_CHARACTER_ERR"],
+  ["http://www.w3.org/XML/1998/namespace", null, null],
+  ["http://www.w3.org/XML/1998/namespace", "", "INVALID_CHARACTER_ERR"],
+  ["http://www.w3.org/2000/xmlns/", null, "NAMESPACE_ERR"],
+  ["http://www.w3.org/2000/xmlns/", "", "INVALID_CHARACTER_ERR"],
+  ["foo:", null, null],
+  ["foo:", "", "INVALID_CHARACTER_ERR"],
+])
+
+var xmlIframe = document.querySelector('[src="/common/dummy.xml"]');
+var xhtmlIframe = document.querySelector('[src="/common/dummy.xhtml"]');
 
-  tests.forEach(function(t, i) {
-    test(function() {
-      var namespace = t[0], qualifiedName = t[1], expected = t[2]
-      if (expected != null) {
-        assert_throws(expected, function() { document.createElementNS(namespace, qualifiedName) })
-      } else {
-        var element = document.createElementNS(namespace, qualifiedName)
-        assert_not_equals(element, null)
-        assert_equals(element.nodeType, Node.ELEMENT_NODE)
-        assert_equals(element.nodeType, element.ELEMENT_NODE)
-        assert_equals(element.nodeValue, null)
-        assert_equals(element.ownerDocument, document)
-        var qualified = String(qualifiedName), names = []
-        if (qualified.indexOf(":") >= 0) {
-          names = qualified.split(":", 2)
+function runTest(t, i, desc) {
+  async_test(function(testObj) {
+    window.addEventListener("load", function() {
+      testObj.step(function() {
+        var doc;
+        if (desc == "HTML document") {
+          doc = document;
+        } else if (desc == "XML document") {
+          doc = xmlIframe.contentDocument;
+          // Make sure we're testing the right document
+          assert_equals(doc.documentElement.textContent, "Dummy XML document");
+        } else if (desc == "XHTML document") {
+          doc = xhtmlIframe.contentDocument;
+          assert_equals(doc.documentElement.textContent, "Dummy XHTML document");
+        }
+        var namespace = t[0], qualifiedName = t[1], expected = t[2]
+        if (expected != null) {
+          assert_throws(expected, function() { doc.createElementNS(namespace, qualifiedName) })
         } else {
-          names = [null, qualified]
+          var element = doc.createElementNS(namespace, qualifiedName)
+          assert_not_equals(element, null)
+          assert_equals(element.nodeType, Node.ELEMENT_NODE)
+          assert_equals(element.nodeType, element.ELEMENT_NODE)
+          assert_equals(element.nodeValue, null)
+          assert_equals(element.ownerDocument, doc)
+          var qualified = String(qualifiedName), names = []
+          if (qualified.indexOf(":") >= 0) {
+            names = qualified.split(":", 2)
+          } else {
+            names = [null, qualified]
+          }
+          assert_equals(element.prefix, names[0])
+          assert_equals(element.localName, names[1])
+          assert_equals(element.tagName, qualified)
+          assert_equals(element.nodeName, qualified)
+          assert_equals(element.namespaceURI,
+                        namespace === undefined || namespace === "" ? null
+                                                                    : namespace)
         }
-        assert_equals(element.prefix, names[0])
-        assert_equals(element.localName, names[1])
-        assert_equals(element.tagName, qualified)
-        assert_equals(element.nodeName, qualified)
-        assert_equals(element.namespaceURI, namespace === undefined ? null : namespace)
-      }
-    }, "createElementNS test: " + t.map(format_value))
-  })
+      });
+      testObj.done();
+    });
+  }, "createElementNS test in " + desc + ": " + t.map(format_value))
+}
+
+tests.forEach(function(t, i) {
+  runTest(t, i, "HTML document")
+  runTest(t, i, "XML document")
+  runTest(t, i, "XHTML document")
 })
 
+
 test(function() {
   var HTMLNS = "http://www.w3.org/1999/xhtml";
   var element = document.createElementNS(HTMLNS, "span");
   assert_equals(element.namespaceURI, HTMLNS);
   assert_equals(element.prefix, null);
   assert_equals(element.localName, "span");
   assert_equals(element.tagName, "SPAN");
   assert_true(element instanceof Node, "Should be a Node");
--- a/testing/web-platform/tests/dom/nodes/Document-createElementNS.js
+++ b/testing/web-platform/tests/dom/nodes/Document-createElementNS.js
@@ -1,66 +1,91 @@
 var createElementNS_tests = [
   /* Arrays with three elements:
    *   the namespace argument
    *   the qualifiedName argument
    *   the expected exception, or null if none
    */
+  [null, null, null],
   [null, undefined, null],
   [null, "foo", null],
   [null, "1foo", "INVALID_CHARACTER_ERR"],
   [null, "f1oo", null],
   [null, "foo1", null],
-  [null, "\u0300foo", "INVALID_CHARACTER_ERR"],
+  [null, "\u0BC6foo", "INVALID_CHARACTER_ERR"],
   [null, "}foo", "INVALID_CHARACTER_ERR"],
   [null, "f}oo", "INVALID_CHARACTER_ERR"],
   [null, "foo}", "INVALID_CHARACTER_ERR"],
   [null, "\uFFFFfoo", "INVALID_CHARACTER_ERR"],
   [null, "f\uFFFFoo", "INVALID_CHARACTER_ERR"],
   [null, "foo\uFFFF", "INVALID_CHARACTER_ERR"],
   [null, "<foo", "INVALID_CHARACTER_ERR"],
   [null, "foo>", "INVALID_CHARACTER_ERR"],
   [null, "<foo>", "INVALID_CHARACTER_ERR"],
   [null, "f<oo", "INVALID_CHARACTER_ERR"],
   [null, "^^", "INVALID_CHARACTER_ERR"],
+  [null, "fo o", "INVALID_CHARACTER_ERR"],
+  [null, "-foo", "INVALID_CHARACTER_ERR"],
+  [null, ".foo", "INVALID_CHARACTER_ERR"],
   [null, ":foo", "NAMESPACE_ERR"],
   [null, "f:oo", "NAMESPACE_ERR"],
   [null, "foo:", "NAMESPACE_ERR"],
+  [null, "f:o:o", "NAMESPACE_ERR"],
   [null, ":", "NAMESPACE_ERR"],
   [null, "xml", null],
   [null, "xmlns", "NAMESPACE_ERR"],
   [null, "xmlfoo", null],
   [null, "xml:foo", "NAMESPACE_ERR"],
   [null, "xmlns:foo", "NAMESPACE_ERR"],
   [null, "xmlfoo:bar", "NAMESPACE_ERR"],
   [null, "null:xml", "NAMESPACE_ERR"],
+  ["", null, null],
   ["", ":foo", "NAMESPACE_ERR"],
   ["", "f:oo", "NAMESPACE_ERR"],
   ["", "foo:", "NAMESPACE_ERR"],
+  [undefined, null, null],
   [undefined, undefined, null],
   [undefined, "foo", null],
   [undefined, "1foo", "INVALID_CHARACTER_ERR"],
   [undefined, "f1oo", null],
   [undefined, "foo1", null],
   [undefined, ":foo", "NAMESPACE_ERR"],
   [undefined, "f:oo", "NAMESPACE_ERR"],
   [undefined, "foo:", "NAMESPACE_ERR"],
+  [undefined, "f::oo", "NAMESPACE_ERR"],
   [undefined, "xml", null],
   [undefined, "xmlns", "NAMESPACE_ERR"],
   [undefined, "xmlfoo", null],
   [undefined, "xml:foo", "NAMESPACE_ERR"],
   [undefined, "xmlns:foo", "NAMESPACE_ERR"],
   [undefined, "xmlfoo:bar", "NAMESPACE_ERR"],
   ["http://example.com/", "foo", null],
   ["http://example.com/", "1foo", "INVALID_CHARACTER_ERR"],
+  ["http://example.com/", "<foo>", "INVALID_CHARACTER_ERR"],
+  ["http://example.com/", "fo<o", "INVALID_CHARACTER_ERR"],
+  ["http://example.com/", "-foo", "INVALID_CHARACTER_ERR"],
+  ["http://example.com/", ".foo", "INVALID_CHARACTER_ERR"],
   ["http://example.com/", "f1oo", null],
   ["http://example.com/", "foo1", null],
   ["http://example.com/", ":foo", "NAMESPACE_ERR"],
   ["http://example.com/", "f:oo", null],
+  ["http://example.com/", "f:o:o", "NAMESPACE_ERR"],
   ["http://example.com/", "foo:", "NAMESPACE_ERR"],
+  ["http://example.com/", "f::oo", "NAMESPACE_ERR"],
+  ["http://example.com/", "a:0", "NAMESPACE_ERR"],
+  ["http://example.com/", "0:a", "INVALID_CHARACTER_ERR"],
+  ["http://example.com/", "a:_", null],
+  ["http://example.com/", "a:\u0BC6", "NAMESPACE_ERR"],
+  ["http://example.com/", "\u0BC6:a", "INVALID_CHARACTER_ERR"],
+  ["http://example.com/", "a:a\u0BC6", null],
+  ["http://example.com/", "a\u0BC6:a", null],
+  ["http://example.com/", "xml:test", "NAMESPACE_ERR"],
+  ["http://example.com/", "xmlns:test", "NAMESPACE_ERR"],
+  ["http://example.com/", "test:xmlns", null],
+  ["http://example.com/", "xmlns", "NAMESPACE_ERR"],
   ["http://example.com/", "_:_", null],
   ["http://example.com/", "_:h0", null],
   ["http://example.com/", "_:test", null],
   ["http://example.com/", "l_:_", null],
   ["http://example.com/", "ns:_0", null],
   ["http://example.com/", "ns:a0", null],
   ["http://example.com/", "ns0:test", null],
   ["http://example.com/", "a.b:c", null],
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/chrome_timeout.js
@@ -0,0 +1,11 @@
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+addMessageListener('setTimeout', msg => {
+  let timer = Cc['@mozilla.org/timer;1'].createInstance(Ci.nsITimer);
+  timer.init(_ => {
+    sendAsyncMessage('timeout');
+  }, msg.delay, Ci.nsITimer.TYPE_ONE_SHOT);
+});
+
+sendAsyncMessage('ready');
--- a/toolkit/components/passwordmgr/test/mochitest.ini
+++ b/toolkit/components/passwordmgr/test/mochitest.ini
@@ -3,16 +3,17 @@ skip-if = buildapp == 'mulet' || buildap
 support-files =
   authenticate.sjs
   blank.html
   formsubmit.sjs
   prompt_common.js
   pwmgr_common.js
   subtst_master_pass.html
   subtst_prompt_async.html
+  chrome_timeout.js
 
 [test_master_password.html]
 skip-if = toolkit == 'android' # Tests desktop prompts
 [test_prompt_async.html]
 skip-if = toolkit == 'android' # Tests desktop prompts
 [test_xhr.html]
 skip-if = toolkit == 'android' # Tests desktop prompts
 [test_xml_load.html]
--- a/toolkit/components/passwordmgr/test/test_master_password.html
+++ b/toolkit/components/passwordmgr/test/test_master_password.html
@@ -228,18 +228,25 @@ function checkTest4A() {
     // driven from DOMContentLoaded, if that blocks due to prompting for a MP,
     // the load even will also be blocked until the prompt is dismissed).
     iframe2.onload = checkTest4B_delay;
     iframe2.src = exampleCom + "subtst_master_pass.html";
 }
 
 function checkTest4B_delay() {
     // Testing a negative, wait a little to give the login manager a chance to
-    // (incorrectly) fill in the form.
-    setTimeout(checkTest4B, 500);
+    // (incorrectly) fill in the form.  Note, we cannot use setTimeout()
+    // here because the modal window suspends all window timers.  Instead we
+    // must use a chrome script to use nsITimer directly.
+    let chromeURL = SimpleTest.getTestFileURL("chrome_timeout.js");
+    let script = SpecialPowers.loadChromeScript(chromeURL);
+    script.addMessageListener('ready', _ => {
+      script.sendAsyncMessage('setTimeout', { delay: 500 });
+    });
+    script.addMessageListener('timeout', checkTest4B);
 }
 
 function checkTest4B() {
     ok(true, "checkTest4B starting");
     // iframe2 should load without having triggered a MP prompt (because one
     // is already waiting)
 
     // check contents of iframe2 fields
--- a/toolkit/components/telemetry/TelemetryEnvironment.jsm
+++ b/toolkit/components/telemetry/TelemetryEnvironment.jsm
@@ -35,18 +35,16 @@ if (AppConstants.platform !== "gonk") {
 }
 XPCOMUtils.defineLazyModuleGetter(this, "ProfileAge",
                                   "resource://gre/modules/ProfileAge.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
                                   "resource://gre/modules/UpdateUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry",
                                   "resource://gre/modules/WindowsRegistry.jsm");
 
-const CHANGE_THROTTLE_INTERVAL_MS = 5 * 60 * 1000;
-
 // The maximum length of a string (e.g. description) in the addons section.
 const MAX_ADDON_STRING_LENGTH = 100;
 // The maximum length of a string value in the settings.attribution object.
 const MAX_ATTRIBUTION_STRING_LENGTH = 100;
 
 /**
  * This is a policy object used to override behavior for testing.
  */
@@ -752,19 +750,16 @@ function EnvironmentCache() {
   this._log.trace("constructor");
 
   this._shutdown = false;
   this._delayedInitFinished = false;
 
   // A map of listeners that will be called on environment changes.
   this._changeListeners = new Map();
 
-  // The last change date for the environment, used to throttle environment changes.
-  this._lastEnvironmentChangeDate = null;
-
   // A map of watched preferences which trigger an Environment change when
   // modified. Every entry contains a recording policy (RECORD_PREF_*).
   this._watchedPrefs = DEFAULT_ENVIRONMENT_PREFS;
 
   this._currentEnvironment = {
     build: this._getBuild(),
     partner: this._getPartner(),
     system: this._getSystem(),
@@ -1438,36 +1433,23 @@ EnvironmentCache.prototype = {
       data.device = this._getDeviceData();
     }
 
     return data;
   },
 
   _onEnvironmentChange: function (what, oldEnvironment) {
     this._log.trace("_onEnvironmentChange for " + what);
+
+    // We are already skipping change events in _checkChanges if there is a pending change task running.
     if (this._shutdown) {
       this._log.trace("_onEnvironmentChange - Already shut down.");
       return;
     }
 
-    // We are already skipping change events in _checkChanges if there is a pending change task running.
-    let now = Policy.now();
-    if (this._lastEnvironmentChangeDate &&
-        this._delayedInitFinished &&
-        (CHANGE_THROTTLE_INTERVAL_MS >=
-         (now.getTime() - this._lastEnvironmentChangeDate.getTime()))) {
-      this._log.trace("_onEnvironmentChange - throttling changes, now: " + now +
-                      ", last change: " + this._lastEnvironmentChangeDate);
-      return;
-    }
-
-    if (this._delayedInitFinished) {
-      this._lastEnvironmentChangeDate = now;
-    }
-
     for (let [name, listener] of this._changeListeners) {
       try {
         this._log.debug("_onEnvironmentChange - calling " + name);
         listener(what, oldEnvironment);
       } catch (e) {
         this._log.error("_onEnvironmentChange - listener " + name + " caught error", e);
       }
     }
--- a/toolkit/components/telemetry/TelemetrySession.jsm
+++ b/toolkit/components/telemetry/TelemetrySession.jsm
@@ -91,16 +91,20 @@ const SCHEDULER_TICK_IDLE_INTERVAL_MS = 
 // The tolerance we have when checking if it's midnight (15 minutes).
 const SCHEDULER_MIDNIGHT_TOLERANCE_MS = 15 * 60 * 1000;
 
 // Seconds of idle time before pinging.
 // On idle-daily a gather-telemetry notification is fired, during it probes can
 // start asynchronous tasks to gather data.
 const IDLE_TIMEOUT_SECONDS = Preferences.get("toolkit.telemetry.idleTimeout", 5 * 60);
 
+// To avoid generating too many main pings, we ignore environment changes that
+// happen within this interval since the last main ping.
+const CHANGE_THROTTLE_INTERVAL_MS = 5 * 60 * 1000;
+
 // The frequency at which we persist session data to the disk to prevent data loss
 // in case of aborted sessions (currently 5 minutes).
 const ABORTED_SESSION_UPDATE_INTERVAL_MS = 5 * 60 * 1000;
 
 const TOPIC_CYCLE_COLLECTOR_BEGIN = "cycle-collector-begin";
 
 // How long to wait in millis for all the child memory reports to come in
 const TOTAL_MEMORY_COLLECTOR_TIMEOUT = 200;
@@ -594,16 +598,17 @@ this.TelemetrySession = Object.freeze({
     Impl._sessionId = null;
     Impl._subsessionId = null;
     Impl._previousSessionId = null;
     Impl._previousSubsessionId = null;
     Impl._subsessionCounter = 0;
     Impl._profileSubsessionCounter = 0;
     Impl._subsessionStartActiveTicks = 0;
     Impl._subsessionStartTimeMonotonic = 0;
+    Impl._lastEnvironmentChangeDate = Policy.monotonicNow();
     this.testUninstall();
   },
   /**
    * Triggers shutdown of the module.
    */
   shutdown: function() {
     return Impl.shutdownChromeProcess();
   },
@@ -703,16 +708,17 @@ var Impl = {
   _totalMemoryTimeout: undefined,
   _testing: false,
   // An accumulator of total memory across all processes. Only valid once the final child reports.
   _totalMemory: null,
   // A Set of outstanding USS report ids
   _childrenToHearFrom: null,
   // monotonically-increasing id for USS reports
   _nextTotalMemoryId: 1,
+  _lastEnvironmentChangeDate: 0,
 
 
   get _log() {
     if (!this._logger) {
       this._logger = Log.repository.getLoggerWithMessagePrefix(LOGGER_NAME, LOGGER_PREFIX);
     }
     return this._logger;
   },
@@ -1513,16 +1519,18 @@ var Impl = {
 
           // Write the first aborted-session ping as early as possible. Just do that
           // if we are not testing, since calling Telemetry.reset() will make a previous
           // aborted ping a pending ping.
           if (!this._testing) {
             yield this._saveAbortedSessionPing();
           }
 
+          // The last change date for the environment, used to throttle environment changes.
+          this._lastEnvironmentChangeDate = Policy.monotonicNow();
           TelemetryEnvironment.registerChangeListener(ENVIRONMENT_CHANGE_LISTENER,
                                  (reason, data) => this._onEnvironmentChange(reason, data));
 
           // Start the scheduler.
           // We skip this if unified telemetry is off, so we don't
           // trigger the new unified ping types.
           TelemetryScheduler.init();
         }
@@ -2037,18 +2045,26 @@ var Impl = {
       sessionId: this._sessionId,
       subsessionId: this._subsessionId,
       profileSubsessionCounter: this._profileSubsessionCounter,
     };
   },
 
   _onEnvironmentChange: function(reason, oldEnvironment) {
     this._log.trace("_onEnvironmentChange", reason);
+
+    let now = Policy.monotonicNow();
+    let timeDelta = now - this._lastEnvironmentChangeDate;
+    if (timeDelta <= CHANGE_THROTTLE_INTERVAL_MS) {
+      this._log.trace(`_onEnvironmentChange - throttling; last change was ${Math.round(timeDelta / 1000)}s ago.`);
+      return;
+    }
+
+    this._lastEnvironmentChangeDate = now;
     let payload = this.getSessionPayload(REASON_ENVIRONMENT_CHANGE, true);
-
     TelemetryScheduler.reschedulePings(REASON_ENVIRONMENT_CHANGE, payload);
 
     let options = {
       addClientId: true,
       addEnvironment: true,
       overrideEnvironment: oldEnvironment,
     };
     TelemetryController.submitExternalPing(getPingType(payload), payload, options);
--- a/toolkit/components/telemetry/tests/unit/test_SubsessionChaining.js
+++ b/toolkit/components/telemetry/tests/unit/test_SubsessionChaining.js
@@ -106,20 +106,22 @@ add_task(function* test_subsessionsChain
   const PREFS_TO_WATCH = new Map([
     [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_VALUE}],
   ]);
   Preferences.reset(PREF_TEST);
 
   // Fake the clock data to manually trigger an aborted-session ping and a daily ping.
   // This is also helpful to make sure we get the archived pings in an expected order.
   let now = fakeNow(2009, 9, 18, 0, 0, 0);
+  let monotonicNow = fakeMonotonicNow(1000);
 
   let moveClockForward = (minutes) => {
-    now = futureDate(now, minutes * MILLISECONDS_PER_MINUTE);
-    fakeNow(now);
+    let ms = minutes * MILLISECONDS_PER_MINUTE;
+    now = fakeNow(futureDate(now, ms));
+    monotonicNow = fakeMonotonicNow(monotonicNow + ms);
   }
 
   // Keep track of the ping reasons we're expecting in this test.
   let expectedReasons = [];
 
   // Start and shut down Telemetry. We expect a shutdown ping with profileSubsessionCounter: 1,
   // subsessionCounter: 1, subsessionId: A,  and previousSubsessionId: null to be archived.
   yield TelemetryController.testSetup();
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryController.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryController.js
@@ -180,16 +180,18 @@ add_task(function* test_disableDataUploa
                "All the pending pings but the deletion ping should have been deleted");
 
   // Enable the ping server again.
   PingServer.start();
   // We set the new server using the pref, otherwise it would get reset with
   // |TelemetryController.testReset|.
   Preferences.set(TelemetryController.Constants.PREF_SERVER, "http://localhost:" + PingServer.port);
 
+  // Stop the sending task and then start it again.
+  yield TelemetrySend.shutdown();
   // Reset the controller to spin the ping sending task.
   yield TelemetryController.testReset();
   ping = yield PingServer.promiseNextPing();
   checkPingFormat(ping, DELETION_PING_TYPE, true, false);
 
   // Wait on ping activity to settle before moving on to the next test. If we were
   // to shut down telemetry, even though the PingServer caught the expected pings,
   // TelemetrySend could still be processing them (clearing pings would happen in
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
@@ -24,19 +24,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 // The webserver hosting the addons.
 var gHttpServer = null;
 // The URL of the webserver root.
 var gHttpRoot = null;
 // The URL of the data directory, on the webserver.
 var gDataRoot = null;
 
-var gNow = new Date(2010, 1, 1, 12, 0, 0);
-fakeNow(gNow);
-
 const PLATFORM_VERSION = "1.9.2";
 const APP_VERSION = "1";
 const APP_ID = "xpcshell@tests.mozilla.org";
 const APP_NAME = "XPCShell";
 const APP_HOTFIX_VERSION = "2.3.4a";
 
 const DISTRIBUTION_ID = "distributor-id";
 const DISTRIBUTION_VERSION = "4.5.6b";
@@ -863,18 +860,16 @@ add_task(function* test_prefWatchPolicie
   const PREF_TEST_1 = "toolkit.telemetry.test.pref_new";
   const PREF_TEST_2 = "toolkit.telemetry.test.pref1";
   const PREF_TEST_3 = "toolkit.telemetry.test.pref2";
   const PREF_TEST_4 = "toolkit.telemetry.test.pref_old";
   const PREF_TEST_5 = "toolkit.telemetry.test.requiresRestart";
 
   const expectedValue = "some-test-value";
   const unexpectedValue = "unexpected-test-value";
-  gNow = futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE);
-  fakeNow(gNow);
 
   const PREFS_TO_WATCH = new Map([
     [PREF_TEST_1, {what: TelemetryEnvironment.RECORD_PREF_VALUE}],
     [PREF_TEST_2, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
     [PREF_TEST_3, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
     [PREF_TEST_4, {what: TelemetryEnvironment.RECORD_PREF_VALUE}],
     [PREF_TEST_5, {what: TelemetryEnvironment.RECORD_PREF_VALUE, requiresRestart: true}],
   ]);
@@ -922,19 +917,16 @@ add_task(function* test_prefWatch_prefRe
   const PREF_TEST = "toolkit.telemetry.test.pref1";
   const PREFS_TO_WATCH = new Map([
     [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
   ]);
 
   // Set the preference to a non-default value.
   Preferences.set(PREF_TEST, false);
 
-  gNow = futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE);
-  fakeNow(gNow);
-
   // Set the Environment preferences to watch.
   TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
   let deferred = PromiseUtils.defer();
   TelemetryEnvironment.registerChangeListener("testWatchPrefs_reset", deferred.resolve);
 
   Assert.strictEqual(TelemetryEnvironment.currentEnvironment.settings.userPrefs[PREF_TEST], "<user-set>");
 
   // Trigger a change in the watched preferences.
@@ -952,18 +944,16 @@ add_task(function* test_addonsWatch_Inte
   const ADDON_ID = "tel-restartless-xpi@tests.mozilla.org";
   // We only expect a single notification for each install, uninstall, enable, disable.
   const EXPECTED_NOTIFICATIONS = 4;
 
   let deferred = PromiseUtils.defer();
   let receivedNotifications = 0;
 
   let registerCheckpointPromise = (aExpected) => {
-    gNow = futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE);
-    fakeNow(gNow);
     return new Promise(resolve => TelemetryEnvironment.registerChangeListener(
       "testWatchAddons_Changes" + aExpected, (reason, data) => {
         Assert.equal(reason, "addons-changed");
         receivedNotifications++;
         resolve();
       }));
   };
 
@@ -1003,19 +993,16 @@ add_task(function* test_addonsWatch_Inte
 });
 
 add_task(function* test_pluginsWatch_Add() {
   if (gIsAndroid) {
     Assert.ok(true, "Skipping: there is no Plugin Manager on Android.");
     return;
   }
 
-  gNow = futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE);
-  fakeNow(gNow);
-
   Assert.equal(TelemetryEnvironment.currentEnvironment.addons.activePlugins.length, 1);
 
   let newPlugin = new PluginTag(PLUGIN2_NAME, PLUGIN2_DESC, PLUGIN2_VERSION, true);
   gInstalledPlugins.push(newPlugin);
 
   let deferred = PromiseUtils.defer();
   let receivedNotifications = 0;
   let callback = (reason, data) => {
@@ -1036,19 +1023,16 @@ add_task(function* test_pluginsWatch_Add
 });
 
 add_task(function* test_pluginsWatch_Remove() {
   if (gIsAndroid) {
     Assert.ok(true, "Skipping: there is no Plugin Manager on Android.");
     return;
   }
 
-  gNow = futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE);
-  fakeNow(gNow);
-
   // Find the test plugin.
   let plugin = gInstalledPlugins.find(plugin => (plugin.name == PLUGIN2_NAME));
   Assert.ok(plugin, "The test plugin must exist.");
 
   // Remove it from the PluginHost.
   gInstalledPlugins = gInstalledPlugins.filter(p => p != plugin);
 
   let deferred = PromiseUtils.defer();
@@ -1067,19 +1051,16 @@ add_task(function* test_pluginsWatch_Rem
   Assert.equal(receivedNotifications, 1, "We must only receive one notification.");
 });
 
 add_task(function* test_addonsWatch_NotInterestingChange() {
   // We are not interested to dictionary addons changes.
   const DICTIONARY_ADDON_INSTALL_URL = gDataRoot + "dictionary.xpi";
   const INTERESTING_ADDON_INSTALL_URL = gDataRoot + "restartless.xpi";
 
-  gNow = futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE);
-  fakeNow(gNow);
-
   let receivedNotification = false;
   let deferred = PromiseUtils.defer();
   TelemetryEnvironment.registerChangeListener("testNotInteresting",
     () => {
       Assert.ok(!receivedNotification, "Should not receive multiple notifications");
       receivedNotification = true;
       deferred.resolve();
     });
@@ -1202,18 +1183,16 @@ add_task(function* test_signedAddon() {
     type: "extension",
     foreignInstall: false,
     hasBinaryComponents: false,
     installDay: ADDON_INSTALL_DATE,
     updateDay: ADDON_INSTALL_DATE,
     signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED,
   };
 
-  // Set the clock in the future so our changes don't get throttled.
-  gNow = fakeNow(futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE));
   let deferred = PromiseUtils.defer();
   TelemetryEnvironment.registerChangeListener("test_signedAddon", deferred.resolve);
 
   // Install the addon.
   yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL);
 
   yield deferred.promise;
   // Unregister the listener.
@@ -1229,19 +1208,16 @@ add_task(function* test_signedAddon() {
     Assert.equal(targetAddon[f], EXPECTED_ADDON_DATA[f], f + " must have the correct value.");
   }
 });
 
 add_task(function* test_addonsFieldsLimit() {
   const ADDON_INSTALL_URL = gDataRoot + "long-fields.xpi";
   const ADDON_ID = "tel-longfields-xpi@tests.mozilla.org";
 
-  // Set the clock in the future so our changes don't get throttled.
-  gNow = fakeNow(futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE));
-
   // Install the addon and wait for the TelemetryEnvironment to pick it up.
   let deferred = PromiseUtils.defer();
   TelemetryEnvironment.registerChangeListener("test_longFieldsAddon", deferred.resolve);
   yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL);
   yield deferred.promise;
   TelemetryEnvironment.unregisterChangeListener("test_longFieldsAddon");
 
   let data = TelemetryEnvironment.currentEnvironment;
@@ -1290,18 +1266,16 @@ add_task(function* test_collectionWithbr
     signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING :
                                          AddonManager.SIGNEDSTATE_NOT_REQUIRED,
   };
 
   let deferred = PromiseUtils.defer();
   let receivedNotifications = 0;
 
   let registerCheckpointPromise = (aExpected) => {
-    gNow = futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE);
-    fakeNow(gNow);
     return new Promise(resolve => TelemetryEnvironment.registerChangeListener(
       "testBrokenAddon_collection" + aExpected, (reason, data) => {
         Assert.equal(reason, "addons-changed");
         receivedNotifications++;
         resolve();
       }));
   };
 
@@ -1313,18 +1287,16 @@ add_task(function* test_collectionWithbr
   // Register the broken provider and install the broken addon.
   let checkpointPromise = registerCheckpointPromise(1);
   let brokenAddonProvider = createMockAddonProvider("Broken Extensions Provider");
   AddonManagerPrivate.registerProvider(brokenAddonProvider);
   brokenAddonProvider.addAddon(BROKEN_MANIFEST);
   yield checkpointPromise;
   assertCheckpoint(1);
 
-  // Set the clock in the future so our changes don't get throttled.
-  gNow = fakeNow(futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE));
   // Now install an addon which returns the correct information.
   checkpointPromise = registerCheckpointPromise(2);
   yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL);
   yield checkpointPromise;
   assertCheckpoint(2);
 
   // Check that the new environment contains the Social addon installed with the broken
   // manifest and the rest of the data.
@@ -1343,56 +1315,16 @@ add_task(function* test_collectionWithbr
 
   // Unregister the broken provider so we don't mess with other tests.
   AddonManagerPrivate.unregisterProvider(brokenAddonProvider);
 
   // Uninstall the valid addon.
   yield AddonManagerTesting.uninstallAddonByID(ADDON_ID);
 });
 
-add_task(function* test_changeThrottling() {
-  const PREF_TEST = "toolkit.telemetry.test.pref1";
-  const PREFS_TO_WATCH = new Map([
-    [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
-  ]);
-  Preferences.reset(PREF_TEST);
-
-  gNow = futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE);
-  fakeNow(gNow);
-
-  // Set the Environment preferences to watch.
-  TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
-  let deferred = PromiseUtils.defer();
-  let changeCount = 0;
-  TelemetryEnvironment.registerChangeListener("testWatchPrefs_throttling", () => {
-    ++changeCount;
-    deferred.resolve();
-  });
-
-  // The first pref change should trigger a notification.
-  Preferences.set(PREF_TEST, 1);
-  yield deferred.promise;
-  Assert.equal(changeCount, 1);
-
-  // We should only get a change notification for second of the following changes.
-  deferred = PromiseUtils.defer();
-  gNow = futureDate(gNow, MILLISECONDS_PER_MINUTE);
-  fakeNow(gNow);
-  Preferences.set(PREF_TEST, 2);
-  gNow = futureDate(gNow, 5 * MILLISECONDS_PER_MINUTE);
-  fakeNow(gNow);
-  Preferences.set(PREF_TEST, 3);
-  yield deferred.promise;
-
-  Assert.equal(changeCount, 2);
-
-  // Unregister the listener.
-  TelemetryEnvironment.unregisterChangeListener("testWatchPrefs_throttling");
-});
-
 add_task(function* test_defaultSearchEngine() {
   // Check that no default engine is in the environment before the search service is
   // initialized.
   let data = TelemetryEnvironment.currentEnvironment;
   checkEnvironmentData(data);
   Assert.ok(!("defaultSearchEngine" in data.settings));
   Assert.ok(!("defaultSearchEngineData" in data.settings));
 
@@ -1435,18 +1367,16 @@ add_task(function* test_defaultSearchEng
   Assert.equal(data.settings.defaultSearchEngine, "NONE");
   Assert.deepEqual(data.settings.defaultSearchEngineData, {name:"NONE"});
 
   // Add a new search engine (this will have no engine identifier).
   const SEARCH_ENGINE_ID = "telemetry_default";
   const SEARCH_ENGINE_URL = "http://www.example.org/?search={searchTerms}";
   Services.search.addEngineWithDetails(SEARCH_ENGINE_ID, "", null, "", "get", SEARCH_ENGINE_URL);
 
-  // Set the clock in the future so our changes don't get throttled.
-  gNow = fakeNow(futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE));
   // Register a new change listener and then wait for the search engine change to be notified.
   let deferred = PromiseUtils.defer();
   TelemetryEnvironment.registerChangeListener("testWatch_SearchDefault", deferred.resolve);
   Services.search.defaultEngine = Services.search.getEngineByName(SEARCH_ENGINE_ID);
   yield deferred.promise;
 
   data = TelemetryEnvironment.currentEnvironment;
   checkEnvironmentData(data);
@@ -1459,17 +1389,16 @@ add_task(function* test_defaultSearchEng
     loadPath: "[other]addEngineWithDetails",
     origin: "verified"
   };
   Assert.deepEqual(data.settings.defaultSearchEngineData, EXPECTED_SEARCH_ENGINE_DATA);
   TelemetryEnvironment.unregisterChangeListener("testWatch_SearchDefault");
 
   // Cleanly install an engine from an xml file, and check if origin is
   // recorded as "verified".
-  gNow = fakeNow(futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE));
   let promise = new Promise(resolve => {
     TelemetryEnvironment.registerChangeListener("testWatch_SearchDefault", resolve);
   });
   let engine = yield new Promise((resolve, reject) => {
     Services.obs.addObserver(function obs(subject, topic, data) {
       try {
         let engine = subject.QueryInterface(Ci.nsISearchEngine);
         do_print("Observed " + data + " for " + engine.name);
@@ -1490,17 +1419,16 @@ add_task(function* test_defaultSearchEng
   yield promise;
   TelemetryEnvironment.unregisterChangeListener("testWatch_SearchDefault");
   data = TelemetryEnvironment.currentEnvironment;
   checkEnvironmentData(data);
   Assert.deepEqual(data.settings.defaultSearchEngineData,
                    {"name":"engine-telemetry", "loadPath":"[other]/engine.xml", "origin":"verified"});
 
   // Now break this engine's load path hash.
-  gNow = fakeNow(futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE));
   promise = new Promise(resolve => {
     TelemetryEnvironment.registerChangeListener("testWatch_SearchDefault", resolve);
   });
   engine.wrappedJSObject.setAttr("loadPathHash", "broken");
   Services.obs.notifyObservers(null, "browser-search-engine-modified", "engine-current");
   yield promise;
   TelemetryEnvironment.unregisterChangeListener("testWatch_SearchDefault");
   data = TelemetryEnvironment.currentEnvironment;
@@ -1509,18 +1437,16 @@ add_task(function* test_defaultSearchEng
 
   // Define and reset the test preference.
   const PREF_TEST = "toolkit.telemetry.test.pref1";
   const PREFS_TO_WATCH = new Map([
     [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
   ]);
   Preferences.reset(PREF_TEST);
 
-  // Set the clock in the future so our changes don't get throttled.
-  gNow = fakeNow(futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE));
   // Watch the test preference.
   TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
   deferred = PromiseUtils.defer();
   TelemetryEnvironment.registerChangeListener("testSearchEngine_pref", deferred.resolve);
   // Trigger an environment change.
   Preferences.set(PREF_TEST, 1);
   yield deferred.promise;
   TelemetryEnvironment.unregisterChangeListener("testSearchEngine_pref");
@@ -1583,18 +1509,16 @@ add_task(function* test_osstrings() {
 
 add_task(function* test_environmentShutdown() {
   // Define and reset the test preference.
   const PREF_TEST = "toolkit.telemetry.test.pref1";
   const PREFS_TO_WATCH = new Map([
     [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
   ]);
   Preferences.reset(PREF_TEST);
-  gNow = futureDate(gNow, 10 * MILLISECONDS_PER_MINUTE);
-  fakeNow(gNow);
 
   // Set up the preferences and listener, then the trigger shutdown
   TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
   TelemetryEnvironment.registerChangeListener("test_environmentShutdownChange", () => {
   // Register a new change listener that asserts if change is propogated
     Assert.ok(false, "No change should be propagated after shutdown.");
   });
   TelemetryEnvironment.shutdown();
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
@@ -67,16 +67,17 @@ const DATAREPORTING_DIR = "datareporting
 const ABORTED_PING_FILE_NAME = "aborted-session-ping";
 const ABORTED_SESSION_UPDATE_INTERVAL_MS = 5 * 60 * 1000;
 
 XPCOMUtils.defineLazyGetter(this, "DATAREPORTING_PATH", function() {
   return OS.Path.join(OS.Constants.Path.profileDir, DATAREPORTING_DIR);
 });
 
 var gClientID = null;
+var gMonotonicNow = 0;
 
 function generateUUID() {
   let str = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString();
   // strip {}
   return str.substring(1, str.length - 1);
 }
 
 function truncateDateToDays(date) {
@@ -532,28 +533,28 @@ add_task(function* test_noServerPing() {
 add_task(function* test_simplePing() {
   yield TelemetryStorage.testClearPendingPings();
   PingServer.start();
   Preferences.set(PREF_SERVER, "http://localhost:" + PingServer.port);
 
   let now = new Date(2020, 1, 1, 12, 0, 0);
   let expectedDate = new Date(2020, 1, 1, 0, 0, 0);
   fakeNow(now);
-  const monotonicStart = fakeMonotonicNow(5000);
+  gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 5000);
 
   const expectedSessionUUID = "bd314d15-95bf-4356-b682-b6c4a8942202";
   const expectedSubsessionUUID = "3e2e5f6c-74ba-4e4d-a93f-a48af238a8c7";
   fakeGenerateUUID(() => expectedSessionUUID, () => expectedSubsessionUUID);
   yield TelemetryController.testReset();
 
   // Session and subsession start dates are faked during TelemetrySession setup. We can
   // now fake the session duration.
   const SESSION_DURATION_IN_MINUTES = 15;
   fakeNow(new Date(2020, 1, 1, 12, SESSION_DURATION_IN_MINUTES, 0));
-  fakeMonotonicNow(monotonicStart + SESSION_DURATION_IN_MINUTES * 60 * 1000);
+  gMonotonicNow = fakeMonotonicNow(gMonotonicNow + SESSION_DURATION_IN_MINUTES * 60 * 1000);
 
   yield sendPing();
   let ping = yield PingServer.promiseNextPing();
 
   checkPingFormat(ping, PING_TYPE_MAIN, true, true);
 
   // Check that we get the data we expect.
   let payload = ping.payload;
@@ -1107,24 +1108,24 @@ add_task(function* test_dailyOverdue() {
 });
 
 add_task(function* test_environmentChange() {
   if (gIsAndroid) {
     // We don't split subsessions on environment changes yet on Android.
     return;
   }
 
-  let now = new Date(2040, 1, 1, 12, 0, 0);
   let timerCallback = null;
   let timerDelay = null;
 
   yield TelemetryStorage.testClearPendingPings();
   PingServer.clearRequests();
 
-  fakeNow(now);
+  let now = fakeNow(2040, 1, 1, 12, 0, 0);
+  gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
 
   const PREF_TEST = "toolkit.telemetry.test.pref1";
   Preferences.reset(PREF_TEST);
 
   const PREFS_TO_WATCH = new Map([
     [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_VALUE}],
   ]);
 
@@ -1141,37 +1142,37 @@ add_task(function* test_environmentChang
 
   count.clear();
   keyed.clear();
   count.add(1);
   keyed.add("a", 1);
   keyed.add("b", 1);
 
   // Trigger and collect environment-change ping.
+  gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
   let startDay = truncateDateToDays(now);
-  now = futureDate(now, 10 * MILLISECONDS_PER_MINUTE);
-  fakeNow(now);
+  now = fakeNow(futureDate(now, 10 * MILLISECONDS_PER_MINUTE));
 
   Preferences.set(PREF_TEST, 1);
   let ping = yield PingServer.promiseNextPing();
   Assert.ok(!!ping);
 
   Assert.equal(ping.type, PING_TYPE_MAIN);
   Assert.equal(ping.environment.settings.userPrefs[PREF_TEST], undefined);
   Assert.equal(ping.payload.info.reason, REASON_ENVIRONMENT_CHANGE);
   let subsessionStartDate = new Date(ping.payload.info.subsessionStartDate);
   Assert.equal(subsessionStartDate.toISOString(), startDay.toISOString());
 
   Assert.equal(ping.payload.histograms[COUNT_ID].sum, 1);
   Assert.equal(ping.payload.keyedHistograms[KEYED_ID]["a"].sum, 1);
 
   // Trigger and collect another ping. The histograms should be reset.
   startDay = truncateDateToDays(now);
-  now = futureDate(now, 10 * MILLISECONDS_PER_MINUTE);
-  fakeNow(now);
+  gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
+  now = fakeNow(futureDate(now, 10 * MILLISECONDS_PER_MINUTE));
 
   Preferences.set(PREF_TEST, 2);
   ping = yield PingServer.promiseNextPing();
   Assert.ok(!!ping);
 
   Assert.equal(ping.type, PING_TYPE_MAIN);
   Assert.equal(ping.environment.settings.userPrefs[PREF_TEST], 1);
   Assert.equal(ping.payload.info.reason, REASON_ENVIRONMENT_CHANGE);
@@ -1248,17 +1249,18 @@ add_task(function* test_savedSessionData
   // Start TelemetrySession so that it loads the session data file.
   yield TelemetryController.testReset();
   Assert.equal(0, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_LOAD").sum);
   Assert.equal(0, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_PARSE").sum);
   Assert.equal(0, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_VALIDATION").sum);
 
   // Watch a test preference, trigger and environment change and wait for it to propagate.
   // _watchPreferences triggers a subsession notification
-  fakeNow(new Date(2050, 1, 1, 12, 0, 0));
+  let now = fakeNow(new Date(2050, 1, 1, 12, 0, 0));
+  gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
   TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
   let changePromise = new Promise(resolve =>
     TelemetryEnvironment.registerChangeListener("test_fake_change", resolve));
   Preferences.set(PREF_TEST, 1);
   yield changePromise;
   TelemetryEnvironment.unregisterChangeListener("test_fake_change");
 
   let payload = TelemetrySession.getPayload();
@@ -1613,26 +1615,26 @@ add_task(function* test_schedulerEnviron
     [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_VALUE}],
   ]);
 
   yield TelemetryStorage.testClearPendingPings();
   PingServer.clearRequests();
   yield TelemetryController.testReset();
 
   // Set a fake current date and start Telemetry.
-  let nowDate = new Date(2060, 10, 18, 0, 0, 0);
-  fakeNow(nowDate);
+  let nowDate = fakeNow(2060, 10, 18, 0, 0, 0);
+  gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
   let schedulerTickCallback = null;
   fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
   yield TelemetryController.testReset();
   TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
 
   // Set the current time at midnight.
-  let future = futureDate(nowDate, MS_IN_ONE_DAY);
-  fakeNow(future);
+  let future = fakeNow(futureDate(nowDate, MS_IN_ONE_DAY));
+  gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
 
   // Trigger the environment change.
   Preferences.set(PREF_TEST, 1);
 
   // Wait for the environment-changed ping.
   yield PingServer.promiseNextPing();
 
   // We don't expect to receive any daily ping in this test, so assert if we do.
@@ -1875,14 +1877,65 @@ add_task(function* test_userIdleAndSched
   yield TelemetrySend.testWaitOnOutgoingPings();
 
   // Decode the ping contained in the request and check that's a daily ping.
   Assert.ok(receivedPingRequest, "Telemetry must send one daily ping.");
   const receivedPing = decodeRequestPayload(receivedPingRequest);
   checkPingFormat(receivedPing, PING_TYPE_MAIN, true, true);
   Assert.equal(receivedPing.payload.info.reason, REASON_DAILY);
 
+  PingServer.resetPingHandler();
   yield TelemetryController.testShutdown();
 });
 
+add_task(function* test_changeThrottling() {
+  if (gIsAndroid) {
+    // We don't support subsessions yet on Android.
+    return;
+  }
+
+  let getSubsessionCount = () => {
+    return TelemetrySession.getPayload().info.subsessionCounter;
+  };
+
+  const PREF_TEST = "toolkit.telemetry.test.pref1";
+  const PREFS_TO_WATCH = new Map([
+    [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
+  ]);
+  Preferences.reset(PREF_TEST);
+
+  let now = fakeNow(2050, 1, 2, 0, 0, 0);
+  gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
+  yield TelemetryController.testReset();
+  Assert.equal(getSubsessionCount(), 1);
+
+  // Set the Environment preferences to watch.
+  TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
+
+  // The first pref change should not trigger a notification.
+  Preferences.set(PREF_TEST, 1);
+  Assert.equal(getSubsessionCount(), 1);
+
+  // We should get a change notification after the 5min throttling interval.
+  now = fakeNow(futureDate(now, 5 * MILLISECONDS_PER_MINUTE + 1));
+  gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 5 * MILLISECONDS_PER_MINUTE + 1);
+  Preferences.set(PREF_TEST, 2);
+  Assert.equal(getSubsessionCount(), 2);
+
+  // After that, changes should be throttled again.
+  now = fakeNow(futureDate(now, 1 * MILLISECONDS_PER_MINUTE));
+  gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 1 * MILLISECONDS_PER_MINUTE);
+  Preferences.set(PREF_TEST, 3);
+  Assert.equal(getSubsessionCount(), 2);
+
+  // ... for 5min.
+  now = fakeNow(futureDate(now, 4 * MILLISECONDS_PER_MINUTE + 1));
+  gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 4 * MILLISECONDS_PER_MINUTE + 1);
+  Preferences.set(PREF_TEST, 4);
+  Assert.equal(getSubsessionCount(), 3);
+
+  // Unregister the listener.
+  TelemetryEnvironment.unregisterChangeListener("testWatchPrefs_throttling");
+});
+
 add_task(function* stopServer() {
   yield PingServer.stop();
 });
--- a/toolkit/components/viewsource/content/viewSource.xul
+++ b/toolkit/components/viewsource/content/viewSource.xul
@@ -202,18 +202,18 @@
             </menupopup>
           </menu>
 
           <!-- Charset Menu -->
           <menu id="charsetMenu"
                 label="&charsetMenu2.label;"
                 accesskey="&charsetMenu2.accesskey;"
                 oncommand="viewSourceChrome.onSetCharacterSet(event);"
-                onpopupshowing="CharsetMenu.build(event.target);"
-                onpopupshown="CharsetMenu.update(event.target, content.document.characterSet);">
+                onpopupshowing="CharsetMenu.build(event.target);
+                                CharsetMenu.update(event.target, content.document.characterSet);">
             <menupopup/>
           </menu>
           <menuseparator/>
           <menuitem id="menu_wrapLongLines" type="checkbox" command="cmd_wrapLongLines"
                     label="&menu_wrapLongLines.title;" accesskey="&menu_wrapLongLines.accesskey;"/>
           <menuitem type="checkbox" id="menu_highlightSyntax" command="cmd_highlightSyntax"
                     label="&menu_highlightSyntax.label;" accesskey="&menu_highlightSyntax.accesskey;"/>
         </menupopup>
--- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm
+++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm
@@ -180,16 +180,20 @@ this.LightweightThemeManager = {
   },
 
   addBuiltInTheme: function(theme) {
     if (!theme || !theme.id || this.usedThemes.some(t => t.id == theme.id)) {
       throw new Error("Trying to add invalid builtIn theme");
     }
 
     this._builtInThemes.set(theme.id, theme);
+
+    if (_prefs.getCharPref("selectedThemeID") == theme.id) {
+      this.currentTheme = theme;
+    }
   },
 
   forgetBuiltInTheme: function(id) {
     if (!this._builtInThemes.has(id)) {
       let currentTheme = this.currentTheme;
       if (currentTheme && currentTheme.id == id) {
         this.currentTheme = null;
       }
@@ -691,17 +695,17 @@ function _setCurrentTheme(aData, aLocal)
     let usedThemes = _usedThemesExceptId(aData.id);
     if (current && current.id != aData.id)
       usedThemes.splice(1, 0, aData);
     else
       usedThemes.unshift(aData);
     _updateUsedThemes(usedThemes);
 
     if (isInstall)
-       AddonManagerPrivate.callAddonListeners("onInstalled", wrapper);
+      AddonManagerPrivate.callAddonListeners("onInstalled", wrapper);
   }
 
   if (cancel.data)
     return null;
 
   AddonManagerPrivate.notifyAddonChanged(aData ? aData.id + ID_SUFFIX : null,
                                          ADDON_TYPE, needsRestart);
 
--- a/toolkit/xre/test/win/TestDllInterceptor.cpp
+++ b/toolkit/xre/test/win/TestDllInterceptor.cpp
@@ -155,16 +155,17 @@ int main()
 #ifdef _M_IX86
       // Bug 670967: xpcom/base/AvailableMemoryTracker.cpp
       TestHook("kernel32.dll", "VirtualAlloc") &&
       TestHook("kernel32.dll", "MapViewOfFile") &&
       TestHook("gdi32.dll", "CreateDIBSection") &&
       TestHook("kernel32.dll", "CreateFileW") &&
 #endif
       TestDetour("user32.dll", "CreateWindowExW") &&
+      TestHook("user32.dll", "InSendMessageEx") &&
       TestHook("imm32.dll", "ImmGetContext") &&
       TestHook("imm32.dll", "ImmGetCompositionStringW") &&
       TestHook("imm32.dll", "ImmSetCandidateWindow") &&
 #ifdef _M_X64
       TestHook("user32.dll", "GetKeyState") &&
 #endif
       TestDetour("ntdll.dll", "LdrLoadDll")) {
     printf("TEST-PASS | WindowsDllInterceptor | all checks passed\n");
--- a/xpcom/build/nsWindowsDllInterceptor.h
+++ b/xpcom/build/nsWindowsDllInterceptor.h
@@ -589,16 +589,81 @@ protected:
 
     size_t mHookOffset;
     intptr_t mJumpAddress;
     JumpType mType;
   };
 
 #endif
 
+  enum ePrefixGroupBits
+  {
+    eNoPrefixes = 0,
+    ePrefixGroup1 = (1 << 0),
+    ePrefixGroup2 = (1 << 1),
+    ePrefixGroup3 = (1 << 2),
+    ePrefixGroup4 = (1 << 3)
+  };
+
+  int CountPrefixBytes(byteptr_t aBytes, const int aBytesIndex,
+                       unsigned char* aOutGroupBits)
+  {
+    unsigned char& groupBits = *aOutGroupBits;
+    groupBits = eNoPrefixes;
+    int index = aBytesIndex;
+    while (true) {
+      switch (aBytes[index]) {
+        // Group 1
+        case 0xF0: // LOCK
+        case 0xF2: // REPNZ
+        case 0xF3: // REP / REPZ
+          if (groupBits & ePrefixGroup1) {
+            return -1;
+          }
+          groupBits |= ePrefixGroup1;
+          ++index;
+          break;
+
+        // Group 2
+        case 0x2E: // CS override / branch not taken
+        case 0x36: // SS override
+        case 0x3E: // DS override / branch taken
+        case 0x64: // FS override
+        case 0x65: // GS override
+          if (groupBits & ePrefixGroup2) {
+            return -1;
+          }
+          groupBits |= ePrefixGroup2;
+          ++index;
+          break;
+
+        // Group 3
+        case 0x66: // operand size override
+          if (groupBits & ePrefixGroup3) {
+            return -1;
+          }
+          groupBits |= ePrefixGroup3;
+          ++index;
+          break;
+
+        // Group 4
+        case 0x67: // Address size override
+          if (groupBits & ePrefixGroup4) {
+            return -1;
+          }
+          groupBits |= ePrefixGroup4;
+          ++index;
+          break;
+
+        default:
+          return index - aBytesIndex;
+      }
+    }
+  }
+
   void CreateTrampoline(void* aOrigFunction, intptr_t aDest, void** aOutTramp)
   {
     *aOutTramp = nullptr;
 
     byteptr_t tramp = FindTrampolineSpace();
     if (!tramp) {
       return;
     }
@@ -610,36 +675,35 @@ protected:
 #if defined(_M_IX86)
     int pJmp32 = -1;
     while (nBytes < 5) {
       // Understand some simple instructions that might be found in a
       // prologue; we might need to extend this as necessary.
       //
       // Note!  If we ever need to understand jump instructions, we'll
       // need to rewrite the displacement argument.
+      unsigned char prefixGroups;
+      int numPrefixBytes = CountPrefixBytes(origBytes, nBytes, &prefixGroups);
+      if (numPrefixBytes < 0 || (prefixGroups & (ePrefixGroup3 | ePrefixGroup4))) {
+        // Either the prefix sequence was bad, or there are prefixes that
+        // we don't currently support (groups 3 and 4)
+        return;
+      }
+      nBytes += numPrefixBytes;
       if (origBytes[nBytes] >= 0x88 && origBytes[nBytes] <= 0x8B) {
         // various MOVs
-        unsigned char b = origBytes[nBytes + 1];
-        if (((b & 0xc0) == 0xc0) ||
-            (((b & 0xc0) == 0x00) &&
-             ((b & 0x07) != 0x04) && ((b & 0x07) != 0x05))) {
-          // REG=r, R/M=r or REG=r, R/M=[r]
-          nBytes += 2;
-        } else if ((b & 0xc0) == 0x40) {
-          if ((b & 0x07) == 0x04) {
-            // REG=r, R/M=[SIB + disp8]
-            nBytes += 4;
-          } else {
-            // REG=r, R/M=[r + disp8]
-            nBytes += 3;
-          }
-        } else {
-          // complex MOV, bail
+        ++nBytes;
+        int len = CountModRmSib(origBytes + nBytes);
+        if (len < 0) {
           return;
         }
+        nBytes += len;
+      } else if (origBytes[nBytes] == 0xA1) {
+        // MOV eax, [seg:offset]
+        nBytes += 5;