Merge mozilla-central to autoland
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 20 Jul 2016 11:24:44 +0200
changeset 345834 61336ab346f1c80a5cbe4173a1b1836e474315cb
parent 345833 7dec375fbfaaf33f1e2ce2e824c2b94de8b94c4a (current diff)
parent 345828 e904e18d7dfcd8097f92d44104ca1462fc5d1335 (diff)
child 345835 6d9c0e3bde9e39749ff7dff998f8c9d7c0edd425
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland
browser/themes/shared/permissions.svg
browser/themes/shared/plugins/notification-pluginAlert.png
browser/themes/shared/plugins/notification-pluginAlert@2x.png
browser/themes/shared/plugins/notification-pluginBlocked.png
browser/themes/shared/plugins/notification-pluginBlocked@2x.png
browser/themes/shared/plugins/notification-pluginNormal.png
browser/themes/shared/plugins/notification-pluginNormal@2x.png
dom/media/eme/CDMProxy.cpp
gfx/layers/ipc/CompositorLRU.cpp
gfx/layers/ipc/CompositorLRU.h
layout/style/nsStyleStruct.cpp
media/libyuv/BUILD.gn
media/libyuv/CMakeLists.txt
media/libyuv/PRESUBMIT.py
media/libyuv/README.md
media/libyuv/build_overrides/build.gni
media/libyuv/chromium/README
media/libyuv/docs/environment_variables.md
media/libyuv/docs/filtering.md
media/libyuv/docs/formats.md
media/libyuv/docs/getting_started.md
media/libyuv/docs/rotation.md
media/libyuv/download_vs_toolchain.py
media/libyuv/gyp_libyuv
media/libyuv/gyp_libyuv.py
media/libyuv/include/libyuv/compare_row.h
media/libyuv/include/libyuv/rotate_row.h
media/libyuv/setup_links.py
media/libyuv/source/compare_gcc.cc
media/libyuv/source/compare_neon64.cc
media/libyuv/source/rotate_any.cc
media/libyuv/source/rotate_common.cc
media/libyuv/source/rotate_gcc.cc
media/libyuv/source/rotate_neon64.cc
media/libyuv/source/rotate_win.cc
media/libyuv/source/row_gcc.cc
media/libyuv/source/row_neon64.cc
media/libyuv/source/scale_any.cc
media/libyuv/source/scale_gcc.cc
media/libyuv/source/scale_neon64.cc
media/libyuv/sync_chromium.py
media/libyuv/third_party/gflags/BUILD.gn
media/libyuv/third_party/gflags/LICENSE
media/libyuv/third_party/gflags/README.libyuv
media/libyuv/third_party/gflags/gen/posix/include/gflags/gflags.h
media/libyuv/third_party/gflags/gen/posix/include/gflags/gflags_completions.h
media/libyuv/third_party/gflags/gen/posix/include/gflags/gflags_declare.h
media/libyuv/third_party/gflags/gen/posix/include/gflags/gflags_gflags.h
media/libyuv/third_party/gflags/gen/posix/include/private/config.h
media/libyuv/third_party/gflags/gen/win/include/gflags/gflags.h
media/libyuv/third_party/gflags/gen/win/include/gflags/gflags_completions.h
media/libyuv/third_party/gflags/gen/win/include/gflags/gflags_declare.h
media/libyuv/third_party/gflags/gen/win/include/gflags/gflags_gflags.h
media/libyuv/third_party/gflags/gen/win/include/private/config.h
media/libyuv/third_party/gflags/gflags.gyp
media/libyuv/tools/OWNERS
media/libyuv/tools/gritsettings/README
media/libyuv/tools/gritsettings/resource_ids
media/libyuv/tools/msan/OWNERS
media/libyuv/tools/msan/blacklist.txt
media/libyuv/tools/ubsan/OWNERS
media/libyuv/tools/ubsan/blacklist.txt
media/libyuv/tools/ubsan/vptr_blacklist.txt
media/libyuv/unit_test/color_test.cc
media/libyuv/unit_test/testdata/juno.txt
media/libyuv/util/android/test_runner.py
mobile/android/base/java/org/mozilla/gecko/SurfaceBits.java
netwerk/test/unit/test_bug651100.js
netwerk/test/unit/test_bug712914_secinfo_validation.js
testing/web-platform/meta/2dcontext/drawing-text-to-the-canvas/2d.text.draw.fill.maxWidth.negative.html.ini
testing/web-platform/meta/2dcontext/drawing-text-to-the-canvas/2d.text.draw.fill.maxWidth.zero.html.ini
testing/web-platform/meta/XMLHttpRequest/FormData-append.html.ini
testing/web-platform/meta/XMLHttpRequest/open-open-send.htm.ini
testing/web-platform/meta/XMLHttpRequest/open-open-sync-send.htm.ini
testing/web-platform/meta/XMLHttpRequest/open-send-open.htm.ini
testing/web-platform/meta/XMLHttpRequest/open-sync-open-send.htm.ini
testing/web-platform/meta/XMLHttpRequest/open-url-multi-window-3.htm.ini
testing/web-platform/meta/XMLHttpRequest/send-entity-body-get-head-async.htm.ini
testing/web-platform/meta/XMLHttpRequest/send-entity-body-get-head.htm.ini
testing/web-platform/meta/html/semantics/scripting-1/the-script-element/script-language-type.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-http/fetch-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-http/fetch-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-http/fetch-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-http/iframe-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-http/iframe-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-http/iframe-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-http/script-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-http/script-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-http/script-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-http/xhr-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-http/xhr-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-http/xhr-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/fetch-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/fetch-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/fetch-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/iframe-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/iframe-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/iframe-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/script-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/script-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/script-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/xhr-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/xhr-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/cross-origin/http-https/xhr-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/fetch-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/fetch-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/fetch-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/iframe-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/iframe-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/iframe-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/script-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/script-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/script-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/xhr-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/xhr-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-http/xhr-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-https/fetch-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-https/fetch-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-https/fetch-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-https/iframe-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-https/iframe-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-https/iframe-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-https/script-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-https/script-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-https/script-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-https/xhr-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-https/xhr-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/no-referrer/http-rp/same-origin/http-https/xhr-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-http/fetch-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-http/fetch-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-http/fetch-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-http/iframe-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-http/iframe-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-http/iframe-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-http/script-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-http/script-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-http/script-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-http/xhr-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-http/xhr-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-http/xhr-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-https/fetch-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-https/fetch-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-https/fetch-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-https/iframe-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-https/iframe-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-https/iframe-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-https/script-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-https/script-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-https/script-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-https/xhr-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-https/xhr-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/cross-origin/http-https/xhr-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-http/fetch-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-http/fetch-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-http/fetch-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-http/iframe-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-http/iframe-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-http/iframe-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-http/script-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-http/script-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-http/script-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-http/xhr-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-http/xhr-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-http/xhr-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-https/fetch-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-https/fetch-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-https/fetch-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-https/iframe-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-https/iframe-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-https/iframe-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-https/script-tag/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-https/script-tag/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-https/script-tag/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-https/xhr-request/generic.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-https/xhr-request/generic.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-only/http-rp/same-origin/http-https/xhr-request/generic.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/fetch-request/cross-origin.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/fetch-request/cross-origin.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/fetch-request/cross-origin.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/iframe-tag/cross-origin.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/iframe-tag/cross-origin.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/iframe-tag/cross-origin.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/script-tag/cross-origin.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/script-tag/cross-origin.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/script-tag/cross-origin.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/xhr-request/cross-origin.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/xhr-request/cross-origin.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-http/xhr-request/cross-origin.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/fetch-request/cross-origin.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/fetch-request/cross-origin.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/fetch-request/cross-origin.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/iframe-tag/cross-origin.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/iframe-tag/cross-origin.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/iframe-tag/cross-origin.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/script-tag/cross-origin.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/script-tag/cross-origin.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/script-tag/cross-origin.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/xhr-request/cross-origin.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/xhr-request/cross-origin.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/cross-origin/http-https/xhr-request/cross-origin.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-http/fetch-request/same-origin-insecure.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-http/iframe-tag/same-origin-insecure.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-http/script-tag/same-origin-insecure.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-http/xhr-request/same-origin-insecure.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/same-origin-downgrade.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/same-origin-downgrade.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/same-origin-downgrade.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/same-origin-insecure.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/same-origin-upgrade.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/same-origin-upgrade.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/fetch-request/same-origin-upgrade.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/same-origin-downgrade.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/same-origin-downgrade.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/same-origin-downgrade.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/same-origin-insecure.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/same-origin-upgrade.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/same-origin-upgrade.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/iframe-tag/same-origin-upgrade.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/same-origin-downgrade.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/same-origin-downgrade.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/same-origin-downgrade.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/same-origin-insecure.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/same-origin-upgrade.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/same-origin-upgrade.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/script-tag/same-origin-upgrade.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/same-origin-downgrade.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/same-origin-downgrade.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/same-origin-downgrade.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/same-origin-insecure.swap-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/same-origin-upgrade.keep-origin-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/same-origin-upgrade.no-redirect.http.html.ini
testing/web-platform/meta/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-https/xhr-request/same-origin-upgrade.swap-origin-redirect.http.html.ini
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -149,18 +149,23 @@ nsCoreUtils::DispatchMouseEvent(EventMes
   aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status);
 }
 
 void
 nsCoreUtils::DispatchTouchEvent(EventMessage aMessage, int32_t aX, int32_t aY,
                                 nsIContent* aContent, nsIFrame* aFrame,
                                 nsIPresShell* aPresShell, nsIWidget* aRootWidget)
 {
-  if (!dom::TouchEvent::PrefEnabled())
+  nsIDocShell* docShell = nullptr;
+  if (aPresShell->GetDocument()) {
+    docShell = aPresShell->GetDocument()->GetDocShell();
+  }
+  if (!dom::TouchEvent::PrefEnabled(docShell)) {
     return;
+  }
 
   WidgetTouchEvent event(true, aMessage, aRootWidget);
 
   event.mTime = PR_IntervalNow();
 
   // XXX: Touch has an identifier of -1 to hint that it is synthesized.
   RefPtr<dom::Touch> t = new dom::Touch(-1, LayoutDeviceIntPoint(aX, aY),
                                         LayoutDeviceIntPoint(1, 1), 0.0f, 1.0f);
--- a/accessible/generic/OuterDocAccessible.cpp
+++ b/accessible/generic/OuterDocAccessible.cpp
@@ -110,18 +110,19 @@ OuterDocAccessible::Shutdown()
   }
 
   AccessibleWrap::Shutdown();
 }
 
 bool
 OuterDocAccessible::InsertChildAt(uint32_t aIdx, Accessible* aAccessible)
 {
-  NS_ASSERTION(aAccessible->IsDoc(),
-               "OuterDocAccessible should only have document child!");
+  MOZ_RELEASE_ASSERT(aAccessible->IsDoc(),
+                     "OuterDocAccessible can have a document child only!");
+
   // We keep showing the old document for a bit after creating the new one,
   // and while building the new DOM and frame tree. That's done on purpose
   // to avoid weird flashes of default background color.
   // The old viewer will be destroyed after the new one is created.
   // For a11y, it should be safe to shut down the old document now.
   if (mChildren.Length())
     mChildren[0]->Shutdown();
 
@@ -159,16 +160,24 @@ OuterDocAccessible::RemoveChild(Accessib
   bool wasRemoved = AccessibleWrap::RemoveChild(child);
 
   NS_ASSERTION(!mChildren.Length(),
                "This child document of outerdoc accessible wasn't removed!");
 
   return wasRemoved;
 }
 
+bool
+OuterDocAccessible::IsAcceptableChild(nsIContent* aEl) const
+{
+  // outer document accessible doesn't not participate in ordinal tree
+  // mutations.
+  return false;
+}
+
 ProxyAccessible*
 OuterDocAccessible::RemoteChildDoc() const
 {
   dom::TabParent* tab = dom::TabParent::GetFrom(GetContent());
   if (!tab)
     return nullptr;
 
   return tab->GetTopLevelDocAccessible();
--- a/accessible/generic/OuterDocAccessible.h
+++ b/accessible/generic/OuterDocAccessible.h
@@ -33,16 +33,17 @@ public:
   // Accessible
   virtual void Shutdown() override;
   virtual mozilla::a11y::role NativeRole() override;
   virtual Accessible* ChildAtPoint(int32_t aX, int32_t aY,
                                    EWhichChildAtPoint aWhichChild) override;
 
   virtual bool InsertChildAt(uint32_t aIdx, Accessible* aChild) override;
   virtual bool RemoveChild(Accessible* aAccessible) override;
+  virtual bool IsAcceptableChild(nsIContent* aEl) const override;
 
 protected:
   virtual ~OuterDocAccessible() override;
 };
 
 inline OuterDocAccessible*
 Accessible::AsOuterDoc()
 {
--- a/accessible/ipc/ProxyAccessible.h
+++ b/accessible/ipc/ProxyAccessible.h
@@ -41,17 +41,18 @@ class ProxyAccessible
 {
 public:
 
   ProxyAccessible(uint64_t aID, ProxyAccessible* aParent,
                   DocAccessibleParent* aDoc, role aRole, uint32_t aInterfaces) :
      mParent(aParent), mDoc(aDoc), mWrapper(0), mID(aID), mRole(aRole),
      mOuterDoc(false), mIsDoc(false),
      mHasValue(aInterfaces & Interfaces::VALUE),
-     mIsHyperLink(aInterfaces & Interfaces::HYPERLINK)
+     mIsHyperLink(aInterfaces & Interfaces::HYPERLINK),
+     mIsHyperText(aInterfaces & Interfaces::HYPERTEXT)
   {
     MOZ_COUNT_CTOR(ProxyAccessible);
   }
   ~ProxyAccessible()
   {
     MOZ_COUNT_DTOR(ProxyAccessible);
     MOZ_ASSERT(!mWrapper);
   }
@@ -417,36 +418,37 @@ public:
    */
   bool IsDoc() const { return mIsDoc; }
   DocAccessibleParent* AsDoc() const { return IsDoc() ? mDoc : nullptr; }
 
 protected:
   explicit ProxyAccessible(DocAccessibleParent* aThisAsDoc) :
     mParent(nullptr), mDoc(aThisAsDoc), mWrapper(0), mID(0),
     mRole(roles::DOCUMENT), mOuterDoc(false), mIsDoc(true), mHasValue(false),
-    mIsHyperLink(false)
+    mIsHyperLink(false), mIsHyperText(false)
   { MOZ_COUNT_CTOR(ProxyAccessible); }
 
 protected:
   ProxyAccessible* mParent;
 
 private:
   nsTArray<ProxyAccessible*> mChildren;
   DocAccessibleParent* mDoc;
   uintptr_t mWrapper;
   uint64_t mID;
 protected:
   // XXX DocAccessibleParent gets to change this to change the role of
   // documents.
-  role mRole : 28;
+  role mRole : 27;
 private:
   bool mOuterDoc : 1;
 
 public:
   const bool mIsDoc: 1;
   const bool mHasValue: 1;
   const bool mIsHyperLink: 1;
+  const bool mIsHyperText: 1;
 };
 
 }
 }
 
 #endif
--- a/accessible/tests/browser/browser.ini
+++ b/accessible/tests/browser/browser.ini
@@ -16,17 +16,16 @@ support-files =
 # Caching tests
 [browser_caching_attributes.js]
 [browser_caching_description.js]
 [browser_caching_name.js]
 skip-if = e10s
 [browser_caching_relations.js]
 [browser_caching_states.js]
 [browser_caching_value.js]
-skip-if = e10s # Bug 1276721: QueryInterface is not working with proxies.
 
 # Events tests
 [browser_events_caretmove.js]
 [browser_events_hide.js]
 [browser_events_show.js]
 [browser_events_statechange.js]
 [browser_events_textchange.js]
 
--- a/accessible/xpcom/xpcAccessibleDocument.cpp
+++ b/accessible/xpcom/xpcAccessibleDocument.cpp
@@ -217,16 +217,24 @@ xpcAccessibleDocument::GetXPCAccessible(
   if (aProxy->mHasValue) {
     interfaces |= eValue;
   }
   
   if (aProxy->mIsHyperLink) {
     interfaces |= eHyperLink;
   }
 
+  if (aProxy->mIsHyperText) {
+    interfaces |= eText;
+    acc = new xpcAccessibleHyperText(aProxy, interfaces);
+    mCache.Put(aProxy, acc);
+
+    return acc;
+  }
+
   acc = new xpcAccessibleGeneric(aProxy, interfaces);
   mCache.Put(aProxy, acc);
 
   return acc;
 }
 
 void
 xpcAccessibleDocument::Shutdown()
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -27,16 +27,17 @@ builtin(include, build/autoconf/zlib.m4)
 builtin(include, build/autoconf/linux.m4)dnl
 builtin(include, build/autoconf/winsdk.m4)dnl
 builtin(include, build/autoconf/icu.m4)dnl
 builtin(include, build/autoconf/ffi.m4)dnl
 builtin(include, build/autoconf/clang-plugin.m4)dnl
 builtin(include, build/autoconf/alloc.m4)dnl
 builtin(include, build/autoconf/ios.m4)dnl
 builtin(include, build/autoconf/jemalloc.m4)dnl
+builtin(include, build/autoconf/sanitize.m4)dnl
 
 MOZ_PROG_CHECKMSYS()
 
 # Read the user's .mozconfig script.  We can't do this in
 # configure.in: autoconf puts the argument parsing code above anything
 # expanded from configure.in, and we need to get the configure options
 # from .mozconfig in place before that argument parsing code.
 MOZ_READ_MOZCONFIG(.)
--- a/addon-sdk/source/lib/sdk/event/utils.js
+++ b/addon-sdk/source/lib/sdk/event/utils.js
@@ -239,19 +239,26 @@ Input.prototype[end] = Input.end;
 // while also allowing the objects to be reclaimed.  It means, however,
 // input.value cannot be accessed long after the event was dispatched.
 const WeakValueGetterSetter = {
   get: function() {
     return this._weakValue ? this._weakValue.get() : this._simpleValue
   },
   set: function(v) {
     if (v && typeof v === "object") {
-      this._weakValue = Cu.getWeakReference(v)
-      this._simpleValue = undefined;
-      return;
+      try {
+        // Try to set a weak reference.  This can throw for some values.
+        // For example, if the value is a native object that does not
+        // implement nsISupportsWeakReference.
+        this._weakValue = Cu.getWeakReference(v)
+        this._simpleValue = undefined;
+        return;
+      } catch (e) {
+        // Do nothing.  Fall through to setting _simpleValue below.
+      }
     }
     this._simpleValue = v;
     this._weakValue = undefined;
   },
 }
 Object.defineProperty(Input.prototype, "value", WeakValueGetterSetter);
 
 exports.Input = Input;
--- a/b2g/chrome/content/content.css
+++ b/b2g/chrome/content/content.css
@@ -292,17 +292,17 @@ input[type="checkbox"][disabled]:hover:a
   border:1px solid rgba(125,125,125,0.4) !important;
 }
 
 select[disabled] > button {
   opacity: 0.6;
   padding: 1px 7px 1px 7px;
 }
 
-*:-moz-any-link:active,
+*:any-link:active,
 *[role=button]:active,
 button:active,
 option:active,
 select:active,
 label:active {
   background-color: rgba(141, 184, 216, 0.5);
 }
 
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1366,18 +1366,20 @@ pref("privacy.trackingprotection.ui.enab
 pref("privacy.trackingprotection.ui.enabled", false);
 #endif
 pref("privacy.trackingprotection.introCount", 0);
 pref("privacy.trackingprotection.introURL", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tracking-protection/start/");
 
 // Enable Contextual Identity Containers
 #ifdef NIGHTLY_BUILD
 pref("privacy.userContext.enabled", true);
+pref("privacy.userContext.ui.enabled", true);
 #else
 pref("privacy.userContext.enabled", false);
+pref("privacy.userContext.ui.enabled", false);
 #endif
 
 #ifndef RELEASE_BUILD
 // At the moment, autostart.2 is used, while autostart.1 is unused.
 // We leave it here set to false to reset users' defaults and allow
 // us to change everybody to true in the future, when desired.
 pref("browser.tabs.remote.autostart.1", false);
 pref("browser.tabs.remote.autostart.2", true);
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3780,21 +3780,16 @@
              * are hidden). This checks to make sure all conditions are
              * satisfied, and then records the tab switch as finished.
              */
             maybeFinishTabSwitch: function () {
               if (this.switchInProgress && this.requestedTab &&
                   this.getTabState(this.requestedTab) == this.STATE_LOADED) {
                 // After this point the tab has switched from the content thread's point of view.
                 // The changes will be visible after the next refresh driver tick + composite.
-                let event = new CustomEvent("TabSwitched", {
-                  bubbles: true,
-                  cancelable: true
-                });
-                this.tabbrowser.dispatchEvent(event);
                 let time = TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
                 if (time != -1) {
                   TelemetryStopwatch.finish("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
                   this.log("DEBUG: tab switch time = " + time);
                   this.addMarker("AsyncTabSwitch:Finish");
                 }
                 this.switchInProgress = false;
               }
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -499,54 +499,51 @@ const CustomizableWidgets = [
       });
       return item;
     },
   }, {
     id: "privatebrowsing-button",
     shortcutId: "key_privatebrowsing",
     defaultArea: CustomizableUI.AREA_PANEL,
     onCommand: function(e) {
-      let win = e.target && e.target.ownerGlobal;
-      if (win && typeof win.OpenBrowserWindow == "function") {
+      let win = e.target.ownerGlobal;
+      if (typeof win.OpenBrowserWindow == "function") {
         win.OpenBrowserWindow({private: true});
       }
     }
   }, {
     id: "save-page-button",
     shortcutId: "key_savePage",
     tooltiptext: "save-page-button.tooltiptext3",
     defaultArea: CustomizableUI.AREA_PANEL,
     onCommand: function(aEvent) {
-      let win = aEvent.target &&
-                aEvent.target.ownerGlobal;
-      if (win && typeof win.saveBrowser == "function") {
+      let win = aEvent.target.ownerGlobal;
+      if (typeof win.saveBrowser == "function") {
         win.saveBrowser(win.gBrowser.selectedBrowser);
       }
     }
   }, {
     id: "find-button",
     shortcutId: "key_find",
     tooltiptext: "find-button.tooltiptext3",
     defaultArea: CustomizableUI.AREA_PANEL,
     onCommand: function(aEvent) {
-      let win = aEvent.target &&
-                aEvent.target.ownerGlobal;
-      if (win && win.gFindBar) {
+      let win = aEvent.target.ownerGlobal;
+      if (win.gFindBar) {
         win.gFindBar.onFindCommand();
       }
     }
   }, {
     id: "open-file-button",
     shortcutId: "openFileKb",
     tooltiptext: "open-file-button.tooltiptext3",
     defaultArea: CustomizableUI.AREA_PANEL,
     onCommand: function(aEvent) {
-      let win = aEvent.target
-                && aEvent.target.ownerGlobal;
-      if (win && typeof win.BrowserOpenFileWindow == "function") {
+      let win = aEvent.target.ownerGlobal;
+      if (typeof win.BrowserOpenFileWindow == "function") {
         win.BrowserOpenFileWindow();
       }
     }
   }, {
     id: "sidebar-button",
     type: "view",
     viewId: "PanelUI-sidebar",
     tooltiptext: "sidebar-button.tooltiptext2",
@@ -612,19 +609,18 @@ const CustomizableWidgets = [
       return node;
     }
   }, {
     id: "add-ons-button",
     shortcutId: "key_openAddons",
     tooltiptext: "add-ons-button.tooltiptext3",
     defaultArea: CustomizableUI.AREA_PANEL,
     onCommand: function(aEvent) {
-      let win = aEvent.target &&
-                aEvent.target.ownerGlobal;
-      if (win && typeof win.BrowserOpenAddonsMgr == "function") {
+      let win = aEvent.target.ownerGlobal;
+      if (typeof win.BrowserOpenAddonsMgr == "function") {
         win.BrowserOpenAddonsMgr();
       }
     }
   }, {
     id: "zoom-controls",
     type: "custom",
     tooltiptext: "zoom-controls.tooltiptext2",
     defaultArea: CustomizableUI.AREA_PANEL,
@@ -1149,19 +1145,18 @@ if (Services.prefs.getBoolPref("privacy.
     }
   });
 }
 
 let preferencesButton = {
   id: "preferences-button",
   defaultArea: CustomizableUI.AREA_PANEL,
   onCommand: function(aEvent) {
-    let win = aEvent.target &&
-              aEvent.target.ownerGlobal;
-    if (win && typeof win.openPreferences == "function") {
+    let win = aEvent.target.ownerGlobal;
+    if (typeof win.openPreferences == "function") {
       win.openPreferences();
     }
   }
 };
 if (AppConstants.platform == "win") {
   preferencesButton.label = "preferences-button.labelWin";
   preferencesButton.tooltiptext = "preferences-button.tooltipWin2";
 } else if (AppConstants.platform == "macosx") {
--- a/browser/components/downloads/content/allDownloadsViewOverlay.js
+++ b/browser/components/downloads/content/allDownloadsViewOverlay.js
@@ -297,18 +297,21 @@ HistoryDownloadElementShell.prototype = 
     return status;
   },
 
   onStateChanged() {
     this._updateState();
 
     if (this.element.selected) {
       goUpdateDownloadCommands();
+    } else {
+      // If a state change occurs in an item that is not currently selected,
+      // this is the only command that may be affected.
+      goUpdateCommand("downloadsCmd_clearDownloads");
     }
-    goUpdateCommand("downloadsCmd_clearDownloads");
   },
 
   onChanged() {
     // This cannot be placed within onStateChanged because
     // when a download goes from hasBlockedData to !hasBlockedData
     // it will still remain in the same state.
     this.element.classList.toggle("temporary-block",
                                   !!this.download.hasBlockedData);
@@ -1131,18 +1134,17 @@ DownloadsPlacesView.prototype = {
 
   onDownloadRemoved(download) {
     this._removeSessionDownloadFromView(download);
   },
 
   // nsIController
   supportsCommand(aCommand) {
     // Firstly, determine if this is a command that we can handle.
-    if (!aCommand.startsWith("cmd_") &&
-        !aCommand.startsWith("downloadsCmd_")) {
+    if (!DownloadsViewUI.isCommandName(aCommand)) {
       return false;
     }
     if (!(aCommand in this) &&
         !(aCommand in HistoryDownloadElementShell.prototype)) {
       return false;
     }
     // If this function returns true, other controllers won't get a chance to
     // process the command even if isCommandEnabled returns false, so it's
@@ -1413,16 +1415,16 @@ for (let methodName of ["load", "applyFi
     throw new Error("|" + methodName +
                     "| is not implemented by the downloads view.");
   }
 }
 
 function goUpdateDownloadCommands() {
   function updateCommandsForObject(object) {
     for (let name in object) {
-      if (name.startsWith("cmd_") || name.startsWith("downloadsCmd_")) {
+      if (DownloadsViewUI.isCommandName(name)) {
         goUpdateCommand(name);
       }
     }
   }
-  updateCommandsForObject(this);
+  updateCommandsForObject(DownloadsPlacesView.prototype);
   updateCommandsForObject(HistoryDownloadElementShell.prototype);
 }
--- a/browser/components/downloads/content/downloads.css
+++ b/browser/components/downloads/content/downloads.css
@@ -172,31 +172,40 @@ richlistitem.download button {
 #downloadsPanel-mainView .download-state[state="8"] .downloadConfirmBlock,
 #downloadsPanel-mainView .download-state[state="8"] .downloadChooseUnblock,
 #downloadsPanel-mainView .download-state[state="8"] .downloadChooseOpen,
 #downloadsPanel-mainView .download-state[state="8"] .downloadRetry,
 #downloadsPanel-mainView .download-state[state="8"] .downloadShow {
   display: none;
 }
 
+/* Make the panel wide enough to show the download list items without improperly
+   truncating them. */
+#downloadsPanel-multiView > .panel-viewcontainer,
+#downloadsPanel-multiView > .panel-viewcontainer > .panel-viewstack,
+#downloadsPanel-multiView > .panel-viewcontainer > .panel-viewstack > .panel-mainview {
+  overflow: visible;
+  max-width: unset;
+}
+
 /* Show the "show blocked info" button. */
 #downloadsPanel-mainView .download-state[state="8"] .downloadShowBlockedInfo {
   display: inline;
 }
 
 /** When the main view is showing... **/
 
 /* The subview should be off to the right and not visible at all. */
 #downloadsPanel-multiView > .panel-viewcontainer > .panel-viewstack[viewtype=main] > .panel-subviews {
-  transform: translateX(100%);
+  transform: translateX(101%);
   transition: transform var(--panelui-subview-transition-duration);
 }
 
 #downloadsPanel-multiView > .panel-viewcontainer > .panel-viewstack[viewtype=main] > .panel-subviews:-moz-locale-dir(rtl) {
-  transform: translateX(-100%);
+  transform: translateX(-101%);
 }
 
 /** When the subview is showing... **/
 
 /* Hide the buttons of all downloads except the one that triggered the
    subview. */
 #downloadsPanel-multiView > .panel-viewcontainer > .panel-viewstack[viewtype="subview"] .download-state:not([showingsubview]) .downloadButton {
   display: none;
--- a/browser/components/downloads/content/downloadsOverlay.xul
+++ b/browser/components/downloads/content/downloadsOverlay.xul
@@ -129,17 +129,17 @@
           <spacer flex="1"/>
           <vbox id="downloadsFooter">
             <hbox id="downloadsSummary"
                   align="center"
                   orient="horizontal"
                   onkeydown="DownloadsSummary.onKeyDown(event);"
                   onclick="DownloadsSummary.onClick(event);">
               <image class="downloadTypeIcon" />
-              <vbox>
+              <vbox id="downloadsSummaryChildBox">
                 <description id="downloadsSummaryDescription"
                              style="min-width: &downloadsSummary.minWidth2;"/>
                 <progressmeter id="downloadsSummaryProgress"
                                class="downloadProgress"
                                min="0"
                                max="100"
                                mode="normal" />
                 <description id="downloadsSummaryDetails"
--- a/browser/components/extensions/ext-commands.js
+++ b/browser/components/extensions/ext-commands.js
@@ -72,20 +72,22 @@ CommandList.prototype = {
   loadCommandsFromManifest(manifest) {
     let commands = new Map();
     // For Windows, chrome.runtime expects 'win' while chrome.commands
     // expects 'windows'.  We can special case this for now.
     let os = PlatformInfo.os == "win" ? "windows" : PlatformInfo.os;
     for (let name of Object.keys(manifest.commands)) {
       let command = manifest.commands[name];
       let shortcut = command.suggested_key[os] || command.suggested_key.default;
-      commands.set(name, {
-        description: command.description,
-        shortcut: shortcut.replace(/\s+/g, ""),
-      });
+      if (shortcut) {
+        commands.set(name, {
+          description: command.description,
+          shortcut: shortcut.replace(/\s+/g, ""),
+        });
+      }
     }
     return commands;
   },
 
   /**
    * Registers the commands to a document.
    * @param {ChromeWindow} window The XUL window to insert the Keyset.
    */
@@ -119,17 +121,17 @@ CommandList.prototype = {
     // and it is currently ignored when set to the empty string.
     keyElement.setAttribute("oncommand", "//");
 
     /* eslint-disable mozilla/balanced-listeners */
     // We remove all references to the key elements when the extension is shutdown,
     // therefore the listeners for these elements will be garbage collected.
     keyElement.addEventListener("command", (event) => {
       if (name == "_execute_page_action") {
-        let win = event.target.ownerGlobal;
+        let win = event.target.ownerDocument.defaultView;
         pageActionFor(this.extension).triggerAction(win);
       } else {
         this.emit("command", name);
       }
     });
     /* eslint-enable mozilla/balanced-listeners */
 
     return keyElement;
--- a/browser/components/extensions/test/browser/browser_ext_commands_onCommand.js
+++ b/browser/components/extensions/test/browser/browser_ext_commands_onCommand.js
@@ -1,98 +1,254 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
+Cu.import("resource://gre/modules/AppConstants.jsm");
+
 add_task(function* test_user_defined_commands() {
+  const testCommands = [
+    // Ctrl Shortcuts
+    {
+      name: "toggle-ctrl-a",
+      shortcut: "Ctrl+A",
+      key: "A",
+      modifiers: {
+        accelKey: true,
+      },
+    },
+    {
+      name: "toggle-ctrl-up",
+      shortcut: "Ctrl+Up",
+      key: "VK_UP",
+      modifiers: {
+        accelKey: true,
+      },
+    },
+    // Alt Shortcuts
+    {
+      name: "toggle-alt-1",
+      shortcut: "Alt+1",
+      key: "1",
+      modifiers: {
+        altKey: true,
+      },
+    },
+    {
+      name: "toggle-alt-a",
+      shortcut: "Alt+A",
+      key: "A",
+      modifiers: {
+        altKey: true,
+      },
+    },
+    {
+      name: "toggle-alt-down",
+      shortcut: "Alt+Down",
+      key: "VK_DOWN",
+      modifiers: {
+        altKey: true,
+      },
+    },
+    // Mac Shortcuts
+    {
+      name: "toggle-command-shift-page-up",
+      shortcutMac: "Command+Shift+PageUp",
+      key: "VK_PAGE_UP",
+      modifiers: {
+        accelKey: true,
+        shiftKey: true,
+      },
+    },
+    {
+      name: "toggle-mac-control-b",
+      shortcut: "Ctrl+B",
+      shortcutMac: "MacCtrl+B",
+      key: "B",
+      modifiers: {
+        ctrlKey: true,
+      },
+    },
+    // Ctrl+Shift Shortcuts
+    {
+      name: "toggle-ctrl-shift-1",
+      shortcut: "Ctrl+Shift+1",
+      key: "1",
+      modifiers: {
+        accelKey: true,
+        shiftKey: true,
+      },
+    },
+    {
+      name: "toggle-ctrl-shift-i",
+      shortcut: "Ctrl+Shift+I",
+      key: "I",
+      modifiers: {
+        accelKey: true,
+        shiftKey: true,
+      },
+    },
+    {
+      name: "toggle-ctrl-shift-left",
+      shortcut: "Ctrl+Shift+Left",
+      key: "VK_LEFT",
+      modifiers: {
+        accelKey: true,
+        shiftKey: true,
+      },
+    },
+    // Alt+Shift Shortcuts
+    {
+      name: "toggle-alt-shift-1",
+      shortcut: "Alt+Shift+1",
+      key: "1",
+      modifiers: {
+        altKey: true,
+        shiftKey: true,
+      },
+    },
+    {
+      name: "toggle-alt-shift-a",
+      shortcut: "Alt+Shift+A",
+      key: "A",
+      modifiers: {
+        altKey: true,
+        shiftKey: true,
+      },
+    },
+    {
+      name: "toggle-alt-shift-right",
+      shortcut: "Alt+Shift+Right",
+      key: "VK_RIGHT",
+      modifiers: {
+        altKey: true,
+        shiftKey: true,
+      },
+    },
+    // Misc Shortcuts
+    {
+      name: "unrecognized-property-name",
+      shortcut: "Alt+Shift+3",
+      key: "3",
+      modifiers: {
+        altKey: true,
+        shiftKey: true,
+      },
+      unrecognized_property: "with-a-random-value",
+    },
+    {
+      name: "spaces-in-shortcut-name",
+      shortcut: "  Alt + Shift + 2  ",
+      key: "2",
+      modifiers: {
+        altKey: true,
+        shiftKey: true,
+      },
+    },
+  ];
+
   // Create a window before the extension is loaded.
   let win1 = yield BrowserTestUtils.openNewBrowserWindow();
   yield BrowserTestUtils.loadURI(win1.gBrowser.selectedBrowser, "about:robots");
   yield BrowserTestUtils.browserLoaded(win1.gBrowser.selectedBrowser);
 
+  let commands = {};
+  let isMac = AppConstants.platform == "macosx";
+  let totalMacOnlyCommands = 0;
+
+  for (let testCommand of testCommands) {
+    let command = {
+      suggested_key: {},
+    };
+
+    if (testCommand.shortcut) {
+      command.suggested_key.default = testCommand.shortcut;
+    }
+
+    if (testCommand.shortcutMac) {
+      command.suggested_key.mac = testCommand.shortcutMac;
+    }
+
+    if (testCommand.shortcutMac && !testCommand.shortcut) {
+      totalMacOnlyCommands++;
+    }
+
+    if (testCommand.unrecognized_property) {
+      command.unrecognized_property = testCommand.unrecognized_property;
+    }
+
+    commands[testCommand.name] = command;
+  }
+
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
-      "commands": {
-        "toggle-feature-using-alt-shift-3": {
-          "suggested_key": {
-            "default": "Alt+Shift+3",
-          },
-        },
-        "toggle-feature-using-alt-shift-comma": {
-          "suggested_key": {
-            "default": "Alt+Shift+Comma",
-          },
-          "unrecognized_property": "with-a-random-value",
-        },
-        "toggle-feature-with-whitespace-in-suggested-key": {
-          "suggested_key": {
-            "default": "  Alt + Shift + 2  ",
-          },
-        },
-      },
+      "commands": commands,
     },
 
     background: function() {
       browser.commands.onCommand.addListener(commandName => {
         browser.test.sendMessage("oncommand", commandName);
       });
       browser.test.sendMessage("ready");
     },
   });
 
-
   SimpleTest.waitForExplicitFinish();
   let waitForConsole = new Promise(resolve => {
     SimpleTest.monitorConsole(resolve, [{
       message: /Reading manifest: Error processing commands.*.unrecognized_property: An unexpected property was found/,
     }]);
   });
 
   yield extension.startup();
   yield extension.awaitMessage("ready");
 
+  function* runTest() {
+    for (let testCommand of testCommands) {
+      if (testCommand.shortcutMac && !isMac) {
+        continue;
+      }
+      EventUtils.synthesizeKey(testCommand.key, testCommand.modifiers);
+      let message = yield extension.awaitMessage("oncommand");
+      is(message, testCommand.name, "Expected onCommand listener to fire with the correct command name");
+    }
+  }
+
   // Create another window after the extension is loaded.
   let win2 = yield BrowserTestUtils.openNewBrowserWindow();
   yield BrowserTestUtils.loadURI(win2.gBrowser.selectedBrowser, "about:config");
   yield BrowserTestUtils.browserLoaded(win2.gBrowser.selectedBrowser);
 
+  let totalTestCommands = Object.keys(testCommands).length;
+  let expectedCommandsRegistered = isMac ? totalTestCommands : totalTestCommands - totalMacOnlyCommands;
+
   // Confirm the keysets have been added to both windows.
   let keysetID = `ext-keyset-id-${makeWidgetId(extension.id)}`;
   let keyset = win1.document.getElementById(keysetID);
   ok(keyset != null, "Expected keyset to exist");
-  is(keyset.childNodes.length, 3, "Expected keyset to have 3 children");
+  is(keyset.childNodes.length, expectedCommandsRegistered, "Expected keyset to have the correct number of children");
 
   keyset = win2.document.getElementById(keysetID);
   ok(keyset != null, "Expected keyset to exist");
-  is(keyset.childNodes.length, 3, "Expected keyset to have 3 children");
+  is(keyset.childNodes.length, expectedCommandsRegistered, "Expected keyset to have the correct number of children");
 
   // Confirm that the commands are registered to both windows.
   yield focusWindow(win1);
-  EventUtils.synthesizeKey("3", {altKey: true, shiftKey: true});
-  let message = yield extension.awaitMessage("oncommand");
-  is(message, "toggle-feature-using-alt-shift-3", "Expected onCommand listener to fire with correct message");
+  yield runTest();
 
   yield focusWindow(win2);
-  EventUtils.synthesizeKey("VK_COMMA", {altKey: true, shiftKey: true});
-  message = yield extension.awaitMessage("oncommand");
-  is(message, "toggle-feature-using-alt-shift-comma", "Expected onCommand listener to fire with correct message");
-
-  EventUtils.synthesizeKey("2", {altKey: true, shiftKey: true});
-  message = yield extension.awaitMessage("oncommand");
-  is(message, "toggle-feature-with-whitespace-in-suggested-key", "Expected onCommand listener to fire with correct message");
+  yield runTest();
 
   yield extension.unload();
 
   // Confirm that the keysets have been removed from both windows after the extension is unloaded.
   keyset = win1.document.getElementById(keysetID);
   is(keyset, null, "Expected keyset to be removed from the window");
 
   keyset = win2.document.getElementById(keysetID);
   is(keyset, null, "Expected keyset to be removed from the window");
 
   yield BrowserTestUtils.closeWindow(win1);
   yield BrowserTestUtils.closeWindow(win2);
 
   SimpleTest.endMonitorConsole();
   yield waitForConsole;
 });
-
-
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -120,24 +120,23 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "SimpleServiceDiscovery",
                                   "resource://gre/modules/SimpleServiceDiscovery.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
                                   "resource:///modules/ContentSearch.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "TabCrashHandler",
                                   "resource:///modules/ContentCrashHandlers.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+                                  "resource://gre/modules/PluralForm.jsm");
 if (AppConstants.MOZ_CRASHREPORTER) {
   XPCOMUtils.defineLazyModuleGetter(this, "PluginCrashReporter",
                                     "resource:///modules/ContentCrashHandlers.jsm");
   XPCOMUtils.defineLazyModuleGetter(this, "CrashSubmit",
                                     "resource://gre/modules/CrashSubmit.jsm");
-  XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
-                                    "resource://gre/modules/PluralForm.jsm");
-
 }
 
 XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
   return Services.strings.createBundle('chrome://branding/locale/brand.properties');
 });
 
 XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
   return Services.strings.createBundle('chrome://browser/locale/browser.properties');
@@ -2477,18 +2476,22 @@ BrowserGlue.prototype = {
       if (URIs.length == 1) {
         title = bundle.GetStringFromName("tabArrivingNotification.title");
         const pageTitle = URIs[0].title || firstTab.linkedBrowser.contentTitle
                           || URIs[0].uri;
         body = bundle.formatStringFromName("tabArrivingNotification.body", [pageTitle, deviceName], 2);
       } else {
         title = bundle.GetStringFromName("tabsArrivingNotification.title");
         const tabArrivingBody = URIs.every(URI => URI.clientId == URIs[0].clientId) ?
-                                "tabsArrivingNotification.body" : "tabsArrivingNotificationMultiple.body";
-        body = bundle.formatStringFromName(tabArrivingBody, [URIs.length, deviceName], 2);
+                                "unnamedTabsArrivingNotification.body" :
+                                "unnamedTabsArrivingNotificationMultiple.body";
+        body = bundle.GetStringFromName(tabArrivingBody);
+        body = PluralForm.get(URIs.length, body);
+        body = body.replace("#1", URIs.length);
+        body = body.replace("#2", deviceName);
       }
 
       const clickCallback = (subject, topic, data) => {
         if (topic == "alertclickcallback") {
           win.gBrowser.selectedTab = firstTab;
         }
       }
       AlertsService.showAlertNotification(null, title, body, true, null, clickCallback);
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -49,16 +49,27 @@ var gPrivacyPane = {
    * Initialize autocomplete to ensure prefs are in sync.
    */
   _initAutocomplete: function () {
     Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
               .getService(Components.interfaces.mozIPlacesAutoComplete);
   },
 
   /**
+   * Show the Containers UI depending on the privacy.userContext.ui.enabled pref.
+   */
+  _initBrowserContainers: function () {
+    if (!Services.prefs.getBoolPref("privacy.userContext.ui.enabled")) {
+      return;
+    }
+
+    document.getElementById("browserContainersbox").hidden = false;
+  },
+
+  /**
    * Sets up the UI for the number of days of history to keep, and updates the
    * label of the "Clear Now..." button.
    */
   init: function ()
   {
     function setEventListener(aId, aEventType, aCallback)
     {
       document.getElementById(aId)
@@ -68,16 +79,17 @@ var gPrivacyPane = {
     this._updateSanitizeSettingsButton();
     this.initializeHistoryMode();
     this.updateHistoryModePane();
     this.updatePrivacyMicroControls();
     this.initAutoStartPrivateBrowsingReverter();
     this._initTrackingProtection();
     this._initTrackingProtectionPBM();
     this._initAutocomplete();
+    this._initBrowserContainers();
 
     setEventListener("privacy.sanitize.sanitizeOnShutdown", "change",
                      gPrivacyPane._updateSanitizeSettingsButton);
     setEventListener("browser.privatebrowsing.autostart", "change",
                      gPrivacyPane.updatePrivacyMicroControls);
     setEventListener("historyMode", "command", function () {
       gPrivacyPane.updateHistoryModePane();
       gPrivacyPane.updateHistoryModePrefs();
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -69,16 +69,21 @@
   <preference id="privacy.sanitize.timeSpan"
               name="privacy.sanitize.timeSpan"
               type="int"/>
   <!-- Private Browsing -->
   <preference id="browser.privatebrowsing.autostart"
               name="browser.privatebrowsing.autostart"
               type="bool"/>
 
+  <!-- Containers -->
+  <preference id="privacy.userContext.enabled"
+              name="privacy.userContext.enabled"
+              type="bool"/>
+
 </preferences>
 
 <hbox id="header-privacy"
       class="header"
       hidden="true"
       data-category="panePrivacy">
   <label class="header-name" flex="1">&panePrivacy.title;</label>
   <button class="help-button"
@@ -278,8 +283,19 @@
             preference="browser.urlbar.suggest.bookmark"/>
   <checkbox id="openpageSuggestion" label="&locbar.openpage.label;"
             accesskey="&locbar.openpage.accesskey;"
             preference="browser.urlbar.suggest.openpage"/>
   <label class="text-link" onclick="if (event.button == 0) gotoPref('search')">
     &suggestionSettings.label;
   </label>
 </groupbox>
+
+<!-- Containers -->
+<groupbox id="browserContainersGroup" data-category="panePrivacy" hidden="true">
+  <vbox id="browserContainersbox" hidden="true">
+    <caption><label>&browserContainersHeader.label;</label></caption>
+    <checkbox id="browserContainersCheckbox"
+              label="&browserContainersEnabled.label;"
+              accesskey="&browserContainersEnabled.accesskey;"
+              preference="privacy.userContext.enabled"/>
+  </vbox>
+</groupbox>
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -365,21 +365,21 @@ var SessionHistoryListener = {
  */
 var ScrollPositionListener = {
   init: function () {
     addEventListener("scroll", this);
     gFrameTree.addObserver(this);
   },
 
   handleEvent: function (event) {
-    let frame = event.target && event.target.defaultView;
+    let frame = event.target.defaultView;
 
     // Don't collect scroll data for frames created at or after the load event
     // as SessionStore can't restore scroll data for those.
-    if (frame && gFrameTree.contains(frame)) {
+    if (gFrameTree.contains(frame)) {
       MessageQueue.push("scroll", () => this.collect());
     }
   },
 
   onFrameTreeCollected: function () {
     MessageQueue.push("scroll", () => this.collect());
   },
 
@@ -412,22 +412,21 @@ var ScrollPositionListener = {
 var FormDataListener = {
   init: function () {
     addEventListener("input", this, true);
     addEventListener("change", this, true);
     gFrameTree.addObserver(this);
   },
 
   handleEvent: function (event) {
-    let frame = event.target &&
-                event.target.ownerGlobal;
+    let frame = event.target.ownerGlobal;
 
     // Don't collect form data for frames created at or after the load event
     // as SessionStore can't restore form data for those.
-    if (frame && gFrameTree.contains(frame)) {
+    if (gFrameTree.contains(frame)) {
       MessageQueue.push("formdata", () => this.collect());
     }
   },
 
   onFrameTreeReset: function () {
     MessageQueue.push("formdata", () => null);
   },
 
copy from browser/config/tooltool-manifests/linux64/asan.manifest
copy to browser/config/tooltool-manifests/linux64/msan.manifest
--- a/browser/extensions/pocket/content/main.js
+++ b/browser/extensions/pocket/content/main.js
@@ -130,22 +130,17 @@ var pktUI = (function() {
     function showSignUp() {
         // AB test: Direct logged-out users to tab vs panel
         if (pktApi.getSignupPanelTabTestVariant() == 'tab')
         {
             let site = Services.prefs.getCharPref("extensions.pocket.site");
             openTabWithUrl('https://' + site + '/firefox_learnmore?src=ff_ext&s=ffi&t=buttonclick', true);
 
             // force the panel closed before it opens
-            // wrapped in setTimeout to avoid race condition after logging out
-            // if this test goes to 100%, we should move this logic up before
-            // the panel is actually opened
-            setTimeout(function() {
-                getPanel().hidePopup();
-            }, 0);
+            getPanel().hidePopup();
 
             return;
         }
 
         // Control: Show panel as normal
         getFirefoxAccountSignedInUser(function(userdata)
         {
             var fxasignedin = (typeof userdata == 'object' && userdata !== null) ? '1' : '0';
@@ -327,17 +322,19 @@ var pktUI = (function() {
           iframe.style.height = options.height + "px";
         }
     }
 
     /**
      * Called when the signup and saved panel was hidden
      */
     function panelDidHide() {
-
+        // clear the onShow and onHide values
+        _currentPanelDidShow = null;
+        _currentPanelDidHide = null;
     }
 
     /**
      * Register all of the messages needed for the panels
      */
     function registerEventMessages() {
         var iframe = getPanelFrame();
 
--- a/browser/locales/en-US/chrome/browser/accounts.properties
+++ b/browser/locales/en-US/chrome/browser/accounts.properties
@@ -42,14 +42,18 @@ sendTabToAllDevices.menuitem = All Devic
 # LOCALIZATION NOTE (tabArrivingNotification.title, tabArrivingNotification.body,
 # tabsArrivingNotification.title, tabsArrivingNotification.body)
 # These strings are used in a notification shown when we're opening tab(s) another device sent us to display.
 tabArrivingNotification.title = Tab received
 # LOCALIZATION NOTE (tabArrivingNotification.body) %1 is the title of the tab and %2 is the device name.
 tabArrivingNotification.body = “%1$S” has arrived from %2$S.
 
 tabsArrivingNotification.title = Multiple tabs received
-# LOCALIZATION NOTE (tabsArrivingNotification.body) %1 is the number of tabs received and %2 is the device name.
-tabsArrivingNotification.body = %1$S tabs have arrived from %2$S.
-# LOCALIZATION NOTE (tabsArrivingNotificationMultiple.body)
-# This string is used in a notification shown when we're opening tab(s) that several devices sent us to display.
-# %S is the number of tabs received
-tabsArrivingNotificationMultiple.body = %S tabs have arrived from your connected devices.
+# LOCALIZATION NOTE (unnamedTabsArrivingNotification.body):
+# Semi-colon list of plural forms.
+# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
+# #1 is the number of tabs received and #2 is the device name.
+unnamedTabsArrivingNotification.body = #1 tab has arrived from #2.;#1 tabs have arrived from #2.
+# LOCALIZATION NOTE (unnamedTabsArrivingNotificationMultiple.body):
+# Semi-colon list of plural forms.
+# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
+# #1 is the number of tabs received.
+unnamedTabsArrivingNotificationMultiple.body = #1 tab has arrived from your connected devices.;#1 tabs have arrived from your connected devices.
--- a/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
@@ -99,8 +99,12 @@
 <!ENTITY  rememberSearchForm.label       "Remember search and form history">
 <!ENTITY  rememberSearchForm.accesskey   "f">
 
 <!ENTITY  clearOnClose.label             "Clear history when &brandShortName; closes">
 <!ENTITY  clearOnClose.accesskey         "r">
 
 <!ENTITY  clearOnCloseSettings.label     "Settings…">
 <!ENTITY  clearOnCloseSettings.accesskey "t">
+
+<!ENTITY  browserContainersHeader.label         "Container Tabs">
+<!ENTITY  browserContainersEnabled.label        "Enable Container Tabs">
+<!ENTITY  browserContainersEnabled.accesskey    "a">
--- a/browser/themes/shared/addons/addon-install-anchor.svg
+++ b/browser/themes/shared/addons/addon-install-anchor.svg
@@ -1,19 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
      width="16" height="16" viewBox="0 0 16 16">
   <defs>
-    <style>
-      use:not(:target) {
-        display: none;
-      }
-      .style-icon-notification {
-        fill: #999;
-      }
-    </style>
     <path id="shape-notifications-addons" d="M10,15c0.5,0,1-0.4,1-1v-3c0,0,0-0.8,0.8-0.8c0.6,0,0.6,0.8,1.8,0.8c0.6,0,1.5-0.2,1.5-2c0-1.8-0.9-2-1.5-2 c-1.1,0-1.1,0.7-1.8,0.7C11,7.7,11,7,11,7V6c0-0.6-0.5-1-1-1H8c0,0-0.8,0-0.8-0.8C7.2,3.6,8,3.6,8,2.5C8,1.9,7.8,1,6,1 C4.2,1,4,1.9,4,2.5c0,1.1,0.8,1.1,0.8,1.8C4.8,5,4,5,4,5H2C1.5,5,1,5.4,1,6l0,1.5c0,0-0.1,1,1.1,1c0.8,0,0.9-1,1.9-1 C4.5,7.4,5,8,5,9c0,1-0.5,1.6-1,1.6c-1,0-1.1-1.1-1.9-1.1C0.9,9.5,1,10.8,1,10.8V14c0,0.6,0.5,1,1,1l2.6,0c0,0,1.1,0,1.1-1 c0-0.8-1-0.1-1-1.1c0-0.5,0.7-1.2,1.8-1.2s1.8,0.7,1.8,1.2c0,1-1.1,0.3-1.1,1.1c0,1,1.2,1,1.2,1H10z"/>
   </defs>
-  <use id="default" xlink:href="#shape-notifications-addons" class="style-icon-notification"/>
+  <use id="default" xlink:href="#shape-notifications-addons" />
 </svg>
--- a/browser/themes/shared/downloads/downloads.inc.css
+++ b/browser/themes/shared/downloads/downloads.inc.css
@@ -27,21 +27,33 @@
 #emptyDownloads {
   padding: 10px 20px;
   /* The panel can be wider than this description after the blocked subview is
      shown, so center the text. */
   text-align: center;
 }
 
 #downloadsSummary {
-  padding: 8px 38px 8px 12px;
+  --summary-padding-end: 38px;
+  --summary-padding-start: 12px;
+  padding: 8px var(--summary-padding-end) 8px var(--summary-padding-start);
   cursor: pointer;
   -moz-user-focus: normal;
 }
 
+#downloadsSummary:-moz-locale-dir(rtl) {
+  padding-right: var(--summary-padding-start);
+  padding-left: var(--summary-padding-end);
+}
+
+#downloadsSummaryChildBox {
+  -moz-margin-start: var(--summary-padding-start);
+  -moz-margin-end: var(--summary-padding-end);
+}
+
 #downloadsSummary > .downloadTypeIcon {
   list-style-image: url("chrome://browser/skin/downloads/download-summary.png");
 }
 
 %ifdef XP_MACOSX
 @media (min-resolution: 2dppx) {
   #downloadsSummary > .downloadTypeIcon {
     list-style-image: url("chrome://browser/skin/downloads/download-summary@2x.png");
@@ -82,17 +94,17 @@ richlistitem[type="download"] {
 richlistitem[type="download"]:first-child {
   border-top: 1px solid transparent;
 }
 
 richlistitem[type="download"]:last-child {
   border-bottom: 1px solid transparent;
 }
 
-.downloadStackIcon {
+.downloadTypeIcon {
   --inline-offset: 8px;
   --block-offset: 4px;
   --icon-size: 32px;
 }
 
 .downloadTypeIcon {
   margin-inline-end: 8px;
   /* Prevent flickering when changing states. */
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -61,17 +61,17 @@
   skin/classic/browser/heartbeat-star-lit.svg                  (../shared/heartbeat-star-lit.svg)
   skin/classic/browser/heartbeat-star-off.svg                  (../shared/heartbeat-star-off.svg)
   skin/classic/browser/identity-icon.svg                       (../shared/identity-block/identity-icon.svg)
   skin/classic/browser/identity-not-secure.svg                 (../shared/identity-block/identity-not-secure.svg)
   skin/classic/browser/identity-secure.svg                     (../shared/identity-block/identity-secure.svg)
   skin/classic/browser/identity-mixed-passive-loaded.svg       (../shared/identity-block/identity-mixed-passive-loaded.svg)
   skin/classic/browser/identity-mixed-active-loaded.svg        (../shared/identity-block/identity-mixed-active-loaded.svg)
   skin/classic/browser/info.svg                                (../shared/info.svg)
-  skin/classic/browser/permissions.svg                         (../shared/permissions.svg)
+  skin/classic/browser/notification-icons.svg                  (../shared/notification-icons.svg)
   skin/classic/browser/tracking-protection-16.svg              (../shared/identity-block/tracking-protection-16.svg)
   skin/classic/browser/tracking-protection-disabled-16.svg     (../shared/identity-block/tracking-protection-disabled-16.svg)
   skin/classic/browser/newtab/close.png                        (../shared/newtab/close.png)
   skin/classic/browser/newtab/controls.svg                     (../shared/newtab/controls.svg)
   skin/classic/browser/newtab/whimsycorn.png                   (../shared/newtab/whimsycorn.png)
   skin/classic/browser/preferences/in-content/favicon.ico      (../shared/incontentprefs/favicon.ico)
   skin/classic/browser/preferences/in-content/icons.svg        (../shared/incontentprefs/icons.svg)
   skin/classic/browser/preferences/in-content/search.css       (../shared/incontentprefs/search.css)
@@ -122,22 +122,16 @@
   skin/classic/browser/session-restore.svg                     (../shared/incontent-icons/session-restore.svg)
   skin/classic/browser/tab-crashed.svg                         (../shared/incontent-icons/tab-crashed.svg)
   skin/classic/browser/favicon-search-16.svg                   (../shared/favicon-search-16.svg)
   skin/classic/browser/icon-search-64.svg                      (../shared/incontent-icons/icon-search-64.svg)
   skin/classic/browser/welcome-back.svg                        (../shared/incontent-icons/welcome-back.svg)
   skin/classic/browser/reader-tour.png                         (../shared/reader/reader-tour.png)
   skin/classic/browser/reader-tour@2x.png                      (../shared/reader/reader-tour@2x.png)
   skin/classic/browser/readerMode.svg                          (../shared/reader/readerMode.svg)
-  skin/classic/browser/notification-pluginNormal.png           (../shared/plugins/notification-pluginNormal.png)
-  skin/classic/browser/notification-pluginNormal@2x.png        (../shared/plugins/notification-pluginNormal@2x.png)
-  skin/classic/browser/notification-pluginAlert.png            (../shared/plugins/notification-pluginAlert.png)
-  skin/classic/browser/notification-pluginAlert@2x.png         (../shared/plugins/notification-pluginAlert@2x.png)
-  skin/classic/browser/notification-pluginBlocked.png          (../shared/plugins/notification-pluginBlocked.png)
-  skin/classic/browser/notification-pluginBlocked@2x.png       (../shared/plugins/notification-pluginBlocked@2x.png)
   skin/classic/browser/webRTC-camera-white-16.png              (../shared/webrtc/camera-white-16.png)
   skin/classic/browser/webRTC-microphone-white-16.png          (../shared/webrtc/microphone-white-16.png)
   skin/classic/browser/webRTC-screen-white-16.png              (../shared/webrtc/screen-white-16.png)
   skin/classic/browser/panic-panel/header.png                  (../shared/panic-panel/header.png)
   skin/classic/browser/panic-panel/header@2x.png               (../shared/panic-panel/header@2x.png)
   skin/classic/browser/panic-panel/header-small.png            (../shared/panic-panel/header-small.png)
   skin/classic/browser/panic-panel/header-small@2x.png         (../shared/panic-panel/header-small@2x.png)
   skin/classic/browser/panic-panel/icons.png                   (../shared/panic-panel/icons.png)
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -36,27 +36,33 @@
 }
 
 .popup-notification-icon {
   width: 64px;
   height: 64px;
   margin-inline-end: 10px;
 }
 
+#notification-popup-box > .notification-anchor-icon:hover {
+  fill: #606060;
+}
+
 /* INDIVIDUAL NOTIFICATIONS */
 
 /* For the moment we apply the color filter only on the icons listed here.
    The first two selectors are used by socialchat.xml (bug 1275558). */
 .webRTC-sharingDevices-notification-icon,
 .webRTC-sharingMicrophone-notification-icon,
 .camera-icon,
 .geo-icon,
 .indexedDB-icon,
+.install-icon,
 .login-icon,
 .microphone-icon,
+.plugin-icon,
 .pointerLock-icon,
 .popup-icon,
 .screen-icon,
 .desktop-notification-icon,
 .popup-notification-icon[popupid="geolocation"],
 .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
 .popup-notification-icon[popupid="password"],
 .popup-notification-icon[popupid="pointerLock"],
@@ -76,124 +82,124 @@
 .webRTC-sharingDevices-notification-icon,
 .webRTC-sharingMicrophone-notification-icon,
 .in-use {
   fill: #fea01b;
 }
 
 .popup-notification-icon[popupid="web-notifications"],
 .desktop-notification-icon {
-  list-style-image: url(chrome://browser/skin/permissions.svg#desktop-notification);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#desktop-notification);
 }
 
 .desktop-notification-icon.blocked {
-  list-style-image: url(chrome://browser/skin/permissions.svg#desktop-notification-blocked);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#desktop-notification-blocked);
 }
 
 .geo-icon {
 %ifdef XP_MACOSX
-  list-style-image: url(chrome://browser/skin/permissions.svg#geo-osx);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-osx);
 %elif defined(MOZ_WIDGET_GTK)
-  list-style-image: url(chrome://browser/skin/permissions.svg#geo-linux);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-linux);
 %else
-  list-style-image: url(chrome://browser/skin/permissions.svg#geo-windows);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-windows);
 %endif
 }
 
 .geo-icon.blocked {
 %ifdef XP_MACOSX
-  list-style-image: url(chrome://browser/skin/permissions.svg#geo-osx-blocked);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-osx-blocked);
 %elif defined(MOZ_WIDGET_GTK)
-  list-style-image: url(chrome://browser/skin/permissions.svg#geo-linux-blocked);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-linux-blocked);
 %else
-  list-style-image: url(chrome://browser/skin/permissions.svg#geo-windows-blocked);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-windows-blocked);
 %endif
 }
 
 .popup-notification-icon[popupid="geolocation"] {
 %ifdef XP_MACOSX
-  list-style-image: url(chrome://browser/skin/permissions.svg#geo-osx);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-osx);
 %elif defined(MOZ_WIDGET_GTK)
-  list-style-image: url(chrome://browser/skin/permissions.svg#geo-linux-detailed);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-linux-detailed);
 %else
-  list-style-image: url(chrome://browser/skin/permissions.svg#geo-windows-detailed);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-windows-detailed);
 %endif
 }
 
 .popup-notification-icon[popupid="indexedDB-permissions-prompt"],
 .indexedDB-icon {
-  list-style-image: url(chrome://browser/skin/permissions.svg#indexedDB);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#indexedDB);
 }
 
 .indexedDB-icon.blocked {
-  list-style-image: url(chrome://browser/skin/permissions.svg#indexedDB-blocked);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#indexedDB-blocked);
 }
 
 .login-icon {
-  list-style-image: url(chrome://browser/skin/permissions.svg#login);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#login);
 }
 
 .popup-notification-icon[popupid="password"] {
-  list-style-image: url(chrome://browser/skin/permissions.svg#login-detailed);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#login-detailed);
 }
 
 #login-fill-notification-icon {
   /* Temporary solution until the capture and fill doorhangers are unified. */
   transform: scaleX(-1);
 }
 
 /* The first selector is used by socialchat.xml (bug 1275558). */
 .webRTC-sharingDevices-notification-icon,
 .camera-icon,
 .popup-notification-icon[popupid="webRTC-shareDevices"],
 .popup-notification-icon[popupid="webRTC-sharingDevices"] {
-  list-style-image: url(chrome://browser/skin/permissions.svg#camera);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#camera);
 }
 
 .camera-icon.blocked {
-  list-style-image: url(chrome://browser/skin/permissions.svg#camera-blocked);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#camera-blocked);
 }
 
 /* The first selector is used by socialchat.xml (bug 1275558). */
 .webRTC-sharingMicrophone-notification-icon,
 .microphone-icon {
-  list-style-image: url(chrome://browser/skin/permissions.svg#microphone);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#microphone);
 }
 
 .microphone-icon.blocked {
-  list-style-image: url(chrome://browser/skin/permissions.svg#microphone-blocked);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#microphone-blocked);
 }
 
 .popup-notification-icon[popupid="webRTC-shareMicrophone"],
 .popup-notification-icon[popupid="webRTC-sharingMicrophone"] {
-  list-style-image: url(chrome://browser/skin/permissions.svg#microphone-detailed);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#microphone-detailed);
 }
 
 .popup-notification-icon[popupid="webRTC-shareScreen"],
 .popup-notification-icon[popupid="webRTC-sharingScreen"],
 .screen-icon {
-  list-style-image: url(chrome://browser/skin/permissions.svg#screen);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#screen);
 }
 
 .screen-icon.blocked {
-  list-style-image: url(chrome://browser/skin/permissions.svg#screen-blocked);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#screen-blocked);
 }
 
 .popup-notification-icon[popupid="pointerLock"],
 .pointerLock-icon {
-  list-style-image: url(chrome://browser/skin/permissions.svg#pointerLock);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#pointerLock);
 }
 
 .pointerLock-icon.blocked {
-  list-style-image: url(chrome://browser/skin/permissions.svg#pointerLock-blocked);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#pointerLock-blocked);
 }
 
 /* This icon has a block sign in it, so we don't need a blocked version. */
 .popup-icon {
-  list-style-image: url("chrome://browser/skin/permissions.svg#popup");
+  list-style-image: url("chrome://browser/skin/notification-icons.svg#popup");
 }
 
 /* EME */
 
 .popup-notification-icon[popupid="drmContentPlaying"],
 .drm-icon {
   list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
 }
@@ -258,51 +264,24 @@
 .popup-notification-icon[popupid*="offline-app-requested"],
 .popup-notification-icon[popupid="offline-app-usage"] {
   list-style-image: url(chrome://global/skin/icons/question-64.png);
 }
 
 /* PLUGINS */
 
 .plugin-icon {
-  list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
-}
-
-.plugin-icon.plugin-hidden {
-  list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#plugin);
 }
 
 .plugin-icon.plugin-blocked {
-  list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
-}
-
-.plugin-icon {
-  -moz-image-region: rect(0, 16px, 16px, 0);
+  list-style-image: url(chrome://browser/skin/notification-icons.svg#plugin-blocked);
+  fill: #d92215;
 }
 
-%ifdef XP_MACOSX
-@media (min-resolution: 1.1dppx) {
-  .plugin-icon {
-    list-style-image: url(chrome://browser/skin/notification-pluginNormal@2x.png);
-  }
-
-  .plugin-icon.plugin-hidden {
-    list-style-image: url(chrome://browser/skin/notification-pluginAlert@2x.png);
-  }
-
-  .plugin-icon.plugin-blocked {
-    list-style-image: url(chrome://browser/skin/notification-pluginBlocked@2x.png);
-  }
-
-  .plugin-icon {
-    -moz-image-region: rect(0, 32px, 32px, 0);
-  }
-}
-%endif
-
 #notification-popup-box[hidden] {
   /* Override display:none to make the pluginBlockedNotification animation work
      when showing the notification repeatedly. */
   display: -moz-box;
   visibility: collapse;
 }
 
 #plugins-notification-icon.plugin-blocked[showing] {
rename from browser/themes/shared/permissions.svg
rename to browser/themes/shared/notification-icons.svg
--- a/browser/themes/shared/permissions.svg
+++ b/browser/themes/shared/notification-icons.svg
@@ -28,16 +28,17 @@
     <path id="geo-osx-icon" d="m 0,16 16,0 0,16 12,-28 z" />
     <path id="geo-windows-icon" d="m 2,14 0,4 2,0 a 12,12 0 0 0 10,10 l 0,2 4,0 0,-2 a 12,12 0 0 0 10,-10 l 2,0 0,-4 -2,0 a 12,12 0 0 0 -10,-10 l 0,-2 -4,0 0,2 a 12,12 0 0 0 -10,10 z m 4,1.9 a 10,10 0 1 1 0,0.2 z m 4,0 a 6,6 0 1 1 0,0.2 z" />
     <path id="geo-windows-detailed-icon" d="m 2,14.5 0,3 2,0.5 a 12,12 0 0 0 10,10 l 0.5,2 3,0 0.5,-2 a 12,12 0 0 0 10,-10 l 2,-0.5 0,-3 -2,-0.5 a 12,12 0 0 0 -10,-10 l -0.5,-2 -3,0 -0.5,2 a 12,12 0 0 0 -10,10 z m 4,1.4 a 10,10 0 1 1 0,0.2 z m 3,0 a 7,7 0 1 1 0,0.2 z" />
     <path id="indexedDB-icon" d="m 2,24 a 4,4 0 0 0 4,4 l 2,0 0,-4 -2,0 0,-16 20,0 0,16 -2,0 0,4 2,0 a 4,4 0 0 0 4,-4 l 0,-16 a 4,4 0 0 0 -4,-4 l -20,0 a 4,4 0 0 0 -4,4 z m 8,-2 6,7 6,-7 -4,0 0,-8 -4,0 0,8 z" />
     <path id="login-icon" d="m 2,26 0,4 6,0 0,-2 2,0 0,-2 1,0 0,-1 2,0 0,-3 2,0 2.5,-2.5 1.5,1.5 3,-3 a 8,8 0 1 0 -8,-8 l -3,3 2,2 z m 20,-18.1 a 2,2 0 1 1 0,0.2 z" />
     <path id="login-detailed-icon" d="m 1,27 0,3.5 a 0.5,0.5 0 0 0 0.5,0.5 l 5,0 a 0.5,0.5 0 0 0 0.5,-0.5 l 0,-1.5 1.5,0 a 0.5,0.5 0 0 0 0.5,-0.5 l 0,-1.5 1,0 a 0.5,0.5 0 0 0 0.5,-0.5 l 0,-1 1,0 a 0.5,0.5 0 0 0 0.5,-0.5 l 0,-2 2,0 2.5,-2.5 q 0.5,-0.5 1,0 l 1,1 c 0.5,0.5 1,0.5 1.5,-0.5 l 1,-2 a 9,9 0 1 0 -8,-8 l -2,1 c -1,0.5 -1,1 -0.5,1.5 l 1.5,1.5 q 0.5,0.5 0,1 z m 21,-19.1 a 2,2 0 1 1 0,0.2 z" />
     <path id="microphone-icon" d="m 8,14 0,4 a 8,8 0 0 0 6,7.7 l 0,2.3 -2,0 a 2,2 0 0 0 -2,2 l 12,0 a 2,2 0 0 0 -2,-2 l -2,0 0,-2.3 a 8,8 0 0 0 6,-7.7 l 0,-4 -2,0 0,4 a 6,6 0 0 1 -12,0 l 0,-4 z m 4,4 a 4,4 0 0 0 8,0 l 0,-12 a 4,4 0 0 0 -8,0 z" />
     <path id="microphone-detailed-icon" d="m 8,18 a 8,8 0 0 0 6,7.7 l 0,2.3 -1,0 a 3,2 0 0 0 -3,2 l 12,0 a 3,2 0 0 0 -3,-2 l -1,0 0,-2.3 a 8,8 0 0 0 6,-7.7 l 0,-4 a 1,1 0 0 0 -2,0 l 0,4 a 6,6 0 0 1 -12,0 l 0,-4 a 1,1 0 0 0 -2,0 z m 4,0 a 4,4 0 0 0 8,0 l 0,-12 a 4,4 0 0 0 -8,0 z" />
+    <path id="plugin-icon" d="m 2,26 a 2,2 0 0 0 2,2 l 24,0 a 2,2 0 0 0 2,-2 l 0,-16 a 2,2 0 0 0 -2,-2 l -24,0 a 2,2 0 0 0 -2,2 z m 2,-20 10,0 0,-2 a 2,2 0 0 0 -2,-2 l -6,0 a 2,2 0 0 0 -2,2 z m 14,0 10,0 0,-2 a 2,2 0 0 0 -2,-2 l -6,0 a 2,2 0 0 0 -2,2 z" />
     <path id="pointerLock-icon" d="m 8,24 6,-5 5,10 4,-2 -5,-10 7,-1 -17,-14 z" />
     <path id="popup-icon" d="m 2,24 a 4,4 0 0 0 4,4 l 8,0 a 10,10 0 0 1 -2,-4 l -4,0 a 2,2 0 0 1 -2,-2 l 0,-12 18,0 0,2 a 10,10 0 0 1 4,2 l 0,-8 a 4,4 0 0 0 -4,-4 l -18,0 a 4,4 0 0 0 -4,4 z m 12,-2.1 a 8,8 0 1 1 0,0.2 m 10.7,-4.3 a 5,5 0 0 0 -6.9,6.9 z m -5.4,8.4 a 5,5 0 0 0 6.9,-6.9 z" />
     <path id="screen-icon" d="m 2,18 a 2,2 0 0 0 2,2 l 2,0 0,-6 a 4,4 0 0 1 4,-4 l 14,0 0,-6 a 2,2 0 0 0 -2,-2 l -18,0 a 2,2 0 0 0 -2,2 z m 6,10 a 2,2 0 0 0 2,2 l 18,0 a 2,2 0 0 0 2,-2 l 0,-14 a 2,2 0 0 0 -2,-2 l -18,0 a 2,2 0 0 0 -2,2 z" />
 
     <clipPath id="clip">
       <path d="m 0,0 0,31 31,-31 z m 6,32 26,0 0,-26 z"/>
     </clipPath>
   </defs>
@@ -56,16 +57,18 @@
   <use id="geo-windows-detailed" xlink:href="#geo-windows-detailed-icon" />
   <use id="indexedDB" xlink:href="#indexedDB-icon" />
   <use id="indexedDB-blocked" class="blocked" xlink:href="#indexedDB-icon" />
   <use id="login" xlink:href="#login-icon" />
   <use id="login-detailed" xlink:href="#login-detailed-icon" />
   <use id="microphone" xlink:href="#microphone-icon" />
   <use id="microphone-blocked" class="blocked" xlink:href="#microphone-icon" />
   <use id="microphone-detailed" xlink:href="#microphone-detailed-icon" />
+  <use id="plugin" xlink:href="#plugin-icon" />
+  <use id="plugin-blocked" class="blocked" xlink:href="#plugin-icon" />
   <use id="pointerLock" xlink:href="#pointerLock-icon" />
   <use id="pointerLock-blocked" class="blocked" xlink:href="#pointerLock-icon" />
   <use id="popup" xlink:href="#popup-icon" />
   <use id="screen" xlink:href="#screen-icon" />
   <use id="screen-blocked" class="blocked" xlink:href="#screen-icon" />
 
   <path id="strikeout" d="m 2,28 2,2 26,-26 -2,-2 z"/>
 </svg>
deleted file mode 100644
index 7492fdd8670488b9b510d913424dcc46f5e1ab57..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index f3359969b6f30fb090f424961024a72435e01b49..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index e2e9489004eb7cd0661d6ebf8d3a7be4869fddca..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 5126be01f08bfd06884278f6527e0e43f9029534..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 979e92b7f51d98aebc1ce4b6255954e6ee8a12dd..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index c081bbb475f9b60070fcae3817967da05f1b533b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -109,25 +109,25 @@
 
 .tab-sharing-icon-overlay {
   /* 16px of the icon + 6px of margin-inline-end of .tab-icon-image */
   margin-inline-start: -22px;
   position: relative;
 }
 
 .tab-sharing-icon-overlay[sharing="camera"] {
-  list-style-image: url("chrome://browser/skin/permissions.svg#camera");
+  list-style-image: url("chrome://browser/skin/notification-icons.svg#camera");
 }
 
 .tab-sharing-icon-overlay[sharing="microphone"] {
-  list-style-image: url("chrome://browser/skin/permissions.svg#microphone");
+  list-style-image: url("chrome://browser/skin/notification-icons.svg#microphone");
 }
 
 .tab-sharing-icon-overlay[sharing="screen"] {
-  list-style-image: url("chrome://browser/skin/permissions.svg#screen");
+  list-style-image: url("chrome://browser/skin/notification-icons.svg#screen");
 }
 
 .tab-sharing-icon-overlay[sharing] {
   filter: url("chrome://browser/skin/filters.svg#fill");
   fill: rgb(224, 41, 29);
 }
 
 .tab-icon-overlay {
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1018,76 +1018,144 @@ toolbar[brighttext] .toolbarbutton-1 > .
    * padding (2 * 2px) + border (2 * 1px), but as a minimum because otherwise
    * increase in text sizes would break things...
    */
   min-height: 24px;
 }
 
 /* ::::: fullscreen window controls ::::: */
 
-#window-controls {
-  margin-inline-start: 4px;
-}
-
 #minimize-button,
 #restore-button,
 #close-button {
-  list-style-image: url("chrome://global/skin/icons/windowControls.png");
-  padding: 0;
+  -moz-appearance: none;
+  border: none;
+  margin: 0 !important;
+  padding: 6px 12px;
 }
 
 #minimize-button {
-  -moz-image-region: rect(0, 16px, 16px, 0);
+  list-style-image: url(chrome://browser/skin/caption-buttons.svg#minimize);
 }
-#minimize-button:hover {
-  -moz-image-region: rect(16px, 16px, 32px, 0);
+
+#restore-button {
+  list-style-image: url(chrome://browser/skin/caption-buttons.svg#restore);
 }
-#minimize-button:hover:active {
-  -moz-image-region: rect(32px, 16px, 48px, 0);
+
+#minimize-button:hover,
+#restore-button:hover {
+  background-color: hsla(0, 0%, 0%, .12);
 }
-#restore-button {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-#restore-button:hover {
-  -moz-image-region: rect(16px, 32px, 32px, 16px);
-}
+
+#minimize-button:hover:active,
 #restore-button:hover:active {
-  -moz-image-region: rect(32px, 32px, 48px, 16px);
+  background-color: hsla(0, 0%, 0%, .22);
 }
+
 #close-button {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-  -moz-appearance: none;
-  border-style: none;
-  margin: 2px;
+  list-style-image: url(chrome://browser/skin/caption-buttons.svg#close);
+}
+
+#close-button:hover {
+  background-color: hsl(355, 86%, 49%);
+  list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-white);
+}
+
+#close-button:hover:active {
+  background-color: hsl(355, 82%, 69%);
+}
+
+toolbar[brighttext] #minimize-button {
+  list-style-image: url(chrome://browser/skin/caption-buttons.svg#minimize-white);
+}
+
+toolbar[brighttext] #restore-button {
+  list-style-image: url(chrome://browser/skin/caption-buttons.svg#restore-white);
+}
+
+toolbar[brighttext] #close-button {
+  list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-white);
 }
-#close-button:hover {
-  -moz-image-region: rect(16px, 48px, 32px, 32px);
+
+@media (-moz-os-version: windows-xp),
+       (-moz-os-version: windows-vista),
+       (-moz-os-version: windows-win7) {
+  #window-controls {
+    margin-inline-start: 4px;
+  }
+
+  #minimize-button,
+  #restore-button,
+  #close-button {
+    list-style-image: url("chrome://global/skin/icons/windowControls.png");
+    padding: 0;
+  }
+
+  #minimize-button {
+    -moz-image-region: rect(0, 16px, 16px, 0);
+  }
+
+  #minimize-button:hover {
+    -moz-image-region: rect(16px, 16px, 32px, 0);
+  }
+
+  #minimize-button:hover:active {
+    -moz-image-region: rect(32px, 16px, 48px, 0);
+  }
+
+  #restore-button {
+    -moz-image-region: rect(0, 32px, 16px, 16px);
+  }
+
+  #restore-button:hover {
+    -moz-image-region: rect(16px, 32px, 32px, 16px);
+  }
+
+  #restore-button:hover:active {
+    -moz-image-region: rect(32px, 32px, 48px, 16px);
+  }
+
+  #close-button {
+    -moz-image-region: rect(0, 48px, 16px, 32px);
+    -moz-appearance: none;
+    border-style: none;
+    margin: 2px;
+  }
+
+  #close-button:hover {
+    -moz-image-region: rect(16px, 48px, 32px, 32px);
+  }
+
+  #close-button:hover:active {
+    -moz-image-region: rect(32px, 48px, 48px, 32px);
+  }
 }
-#close-button:hover:active {
-  -moz-image-region: rect(32px, 48px, 48px, 32px);
-}
-
-@media not all and (-moz-os-version: windows-xp) {
+
+@media (-moz-os-version: windows-vista),
+       (-moz-os-version: windows-win7) {
   #window-controls {
     -moz-box-align: start;
   }
 
   #minimize-button,
   #restore-button,
   #close-button {
     -moz-appearance: none;
     border-style: none;
     margin: 0;
   }
+
   #close-button {
     -moz-image-region: rect(0, 49px, 16px, 32px);
   }
+
   #close-button:hover {
     -moz-image-region: rect(16px, 49px, 32px, 32px);
   }
+
   #close-button:hover:active {
     -moz-image-region: rect(32px, 49px, 48px, 32px);
   }
 
   #minimize-button:-moz-locale-dir(rtl),
   #restore-button:-moz-locale-dir(rtl),
   #close-button:-moz-locale-dir(rtl) {
     transform: scaleX(-1);
--- a/build/autoconf/icu.m4
+++ b/build/autoconf/icu.m4
@@ -11,21 +11,20 @@ ICU_LIB_NAMES=
 MOZ_SYSTEM_ICU=
 MOZ_ARG_WITH_BOOL(system-icu,
 [  --with-system-icu
                           Use system ICU (located with pkgconfig)],
     MOZ_SYSTEM_ICU=1)
 
 if test -n "$MOZ_SYSTEM_ICU"; then
     PKG_CHECK_MODULES(MOZ_ICU, icu-i18n >= 50.1)
-else
-    MOZ_ICU_INCLUDES="/intl/icu/source/common /intl/icu/source/i18n"
+    CFLAGS="$CFLAGS $MOZ_ICU_CFLAGS"
+    CXXFLAGS="$CXXFLAGS $MOZ_ICU_CFLAGS"
 fi
 
-AC_SUBST_LIST(MOZ_ICU_INCLUDES)
 AC_SUBST(MOZ_SYSTEM_ICU)
 
 MOZ_ARG_WITH_STRING(intl-api,
 [  --with-intl-api, --with-intl-api=build, --without-intl-api
     Determine the status of the ECMAScript Internationalization API.  The first
     (or lack of any of these) builds and exposes the API.  The second builds it
     but doesn't use ICU or expose the API to script.  The third doesn't build
     ICU at all.],
new file mode 100644
--- /dev/null
+++ b/build/autoconf/sanitize.m4
@@ -0,0 +1,85 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+AC_DEFUN([MOZ_CONFIG_SANITIZE], [
+
+dnl ========================================================
+dnl = Use Address Sanitizer
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(address-sanitizer,
+[  --enable-address-sanitizer       Enable Address Sanitizer (default=no)],
+    MOZ_ASAN=1,
+    MOZ_ASAN= )
+if test -n "$MOZ_ASAN"; then
+    MOZ_LLVM_HACKS=1
+    if test -n "$CLANG_CL"; then
+        # Look for clang_rt.asan_dynamic-i386.dll
+        MOZ_CLANG_RT_ASAN_LIB=clang_rt.asan_dynamic-i386.dll
+        # We use MOZ_PATH_PROG in order to get a Windows style path.
+        MOZ_PATH_PROG(MOZ_CLANG_RT_ASAN_LIB_PATH, $MOZ_CLANG_RT_ASAN_LIB)
+        if test -z "$MOZ_CLANG_RT_ASAN_LIB_PATH"; then
+            AC_MSG_ERROR([Couldn't find $MOZ_CLANG_RT_ASAN_LIB.  It should be available in the same location as clang-cl.])
+        fi
+        AC_SUBST(MOZ_CLANG_RT_ASAN_LIB_PATH)
+    fi
+    CFLAGS="-fsanitize=address -Dxmalloc=myxmalloc -fPIC $CFLAGS"
+    CXXFLAGS="-fsanitize=address -Dxmalloc=myxmalloc -fPIC $CXXFLAGS"
+    LDFLAGS="-fsanitize=address $LDFLAGS"
+    AC_DEFINE(MOZ_ASAN)
+    MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
+fi
+AC_SUBST(MOZ_ASAN)
+
+dnl ========================================================
+dnl = Use Memory Sanitizer
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(memory-sanitizer,
+[  --enable-memory-sanitizer       Enable Memory Sanitizer (default=no)],
+    MOZ_MSAN=1,
+    MOZ_MSAN= )
+if test -n "$MOZ_MSAN"; then
+    MOZ_LLVM_HACKS=1
+    CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins $CFLAGS"
+    CXXFLAGS="-fsanitize=memory -fsanitize-memory-track-origins $CXXFLAGS"
+    LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins $LDFLAGS"
+    AC_DEFINE(MOZ_MSAN)
+    MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
+fi
+AC_SUBST(MOZ_MSAN)
+
+dnl ========================================================
+dnl = Use Thread Sanitizer
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(thread-sanitizer,
+[  --enable-thread-sanitizer       Enable Thread Sanitizer (default=no)],
+   MOZ_TSAN=1,
+   MOZ_TSAN= )
+if test -n "$MOZ_TSAN"; then
+    MOZ_LLVM_HACKS=1
+    CFLAGS="-fsanitize=thread $CFLAGS"
+    CXXFLAGS="-fsanitize=thread $CXXFLAGS"
+    LDFLAGS="-fsanitize=thread $LDFLAGS"
+    AC_DEFINE(MOZ_TSAN)
+    MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
+fi
+AC_SUBST(MOZ_TSAN)
+
+# The LLVM symbolizer is used by all sanitizers
+AC_SUBST(LLVM_SYMBOLIZER)
+
+dnl ========================================================
+dnl = Enable hacks required for LLVM instrumentations
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(llvm-hacks,
+[  --enable-llvm-hacks       Enable workarounds required for several LLVM instrumentations (default=no)],
+    MOZ_LLVM_HACKS=1,
+    MOZ_LLVM_HACKS= )
+if test -n "$MOZ_LLVM_HACKS"; then
+    MOZ_NO_WLZDEFS=1
+    MOZ_CFLAGS_NSS=1
+fi
+AC_SUBST(MOZ_NO_WLZDEFS)
+AC_SUBST(MOZ_CFLAGS_NSS)
+
+])
--- a/build/pgo/server-locations.txt
+++ b/build/pgo/server-locations.txt
@@ -176,16 +176,19 @@ http://itisatracker.org:80
 http://trackertest.org:80
 
 https://malware.example.com:443
 https://unwanted.example.com:443
 https://tracking.example.com:443
 https://not-tracking.example.com:443
 https://tracking.example.org:443
 
+# Bug 1281083
+http://bug1281083.example.com:80
+
 # Bug 483437, 484111
 https://www.bank1.com:443           privileged,cert=escapeattack1
 
 #
 # CONNECT for redirproxy results in a 302 redirect to
 # test1.example.com
 #
 https://redirproxy.example.com:443          privileged,redir=test1.example.com
--- a/build/unix/mozconfig.asan
+++ b/build/unix/mozconfig.asan
@@ -2,22 +2,16 @@ MOZ_AUTOMATION_L10N_CHECK=0
 
 . "$topsrcdir/build/mozconfig.common"
 
 # Use Clang as specified in manifest
 export CC="$topsrcdir/clang/bin/clang -fgnu89-inline"
 export CXX="$topsrcdir/clang/bin/clang++"
 export LLVM_SYMBOLIZER="$topsrcdir/clang/bin/llvm-symbolizer"
 
-# Mandatory flags for ASan
-export ASANFLAGS="-fsanitize=address -Dxmalloc=myxmalloc -fPIC"
-export CFLAGS="$ASANFLAGS"
-export CXXFLAGS="$ASANFLAGS"
-export LDFLAGS="-fsanitize=address"
-
 # Use a newer binutils, from the tooltool gcc package, if it's there
 if [ -e "$topsrcdir/gcc/bin/ld" ]; then
     export CC="$CC -B $topsrcdir/gcc/bin"
     export CXX="$CXX -B $topsrcdir/gcc/bin"
 fi
 
 # Enable ASan specific code and build workarounds
 ac_add_options --enable-address-sanitizer
--- a/build/unix/mozconfig.tsan
+++ b/build/unix/mozconfig.tsan
@@ -2,31 +2,26 @@ MOZ_AUTOMATION_L10N_CHECK=0
 
 . "$topsrcdir/build/mozconfig.common"
 
 # Use Clang as specified in manifest
 export CC="$topsrcdir/clang/bin/clang"
 export CXX="$topsrcdir/clang/bin/clang++"
 export LLVM_SYMBOLIZER="$topsrcdir/clang/bin/llvm-symbolizer"
 
-# Mandatory flag for TSan
-export CFLAGS="-fsanitize=thread"
-export CXXFLAGS="-fsanitize=thread"
-export LDFLAGS="-fsanitize=thread"
-
 # Use a newer binutils, from the tooltool gcc package, if it's there
 if [ -e "$topsrcdir/gcc/bin/ld" ]; then
     export CC="$CC -B $topsrcdir/gcc/bin"
     export CXX="$CXX -B $topsrcdir/gcc/bin"
 fi
 
 # Enable TSan specific code and build workarounds
 ac_add_options --enable-thread-sanitizer
 
-# The ThreadSanitizer is not compatible with sanboxing
+# The ThreadSanitizer is not compatible with sandboxing
 # (see bug 1182565)
 ac_add_options --disable-sandbox
 
 # These are required by TSan
 ac_add_options --disable-jemalloc
 ac_add_options --disable-crashreporter
 ac_add_options --disable-elf-hack
 ac_add_options --enable-pie
--- a/caps/moz.build
+++ b/caps/moz.build
@@ -1,16 +1,17 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini']
 MOCHITEST_CHROME_MANIFESTS += ['tests/mochitest/chrome.ini']
+BROWSER_CHROME_MANIFESTS += ['tests/mochitest/browser.ini']
 XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
 
 # Hack to make this file available as a resource:// URI.
 TESTING_JS_MODULES += [
     'tests/mochitest/resource_test_file.html',
 ]
 
 XPIDL_SOURCES += [
new file mode 100644
--- /dev/null
+++ b/caps/tests/mochitest/browser.ini
@@ -0,0 +1,1 @@
+[browser_checkloaduri.js]
new file mode 100644
--- /dev/null
+++ b/caps/tests/mochitest/browser_checkloaduri.js
@@ -0,0 +1,121 @@
+"use strict";
+
+let ssm = Services.scriptSecurityManager;
+
+const URLs = new Map([
+  ["http://www.example.com", [
+  // For each of these entries, the booleans represent whether the parent URI can:
+  // - load them
+  // - load them without principal inheritance
+  // - whether the URI can be created at all (some protocol handlers will
+  //   refuse to create certain variants)
+    ["http://www.example2.com", true, true, true],
+    ["feed:http://www.example2.com", false, false, true],
+    ["https://www.example2.com", true, true, true],
+    ["chrome://foo/content/bar.xul", false, false, true],
+    ["feed:chrome://foo/content/bar.xul", false, false, false],
+    ["view-source:http://www.example2.com", false, false, true],
+    ["view-source:feed:http://www.example2.com", false, false, true],
+    ["feed:view-source:http://www.example2.com", false, false, false],
+    ["data:text/html,Hi", true, false, true],
+    ["javascript:alert('hi')", true, false, true],
+  ]],
+  ["feed:http://www.example.com", [
+    ["http://www.example2.com", true, true, true],
+    ["feed:http://www.example2.com", true, true, true],
+    ["https://www.example2.com", true, true, true],
+    ["feed:https://www.example2.com", false, false, true],
+    ["chrome://foo/content/bar.xul", false, false, true],
+    ["feed:chrome://foo/content/bar.xul", false, false, false],
+    ["view-source:http://www.example2.com", false, false, true],
+    ["view-source:feed:http://www.example2.com", false, false, true],
+    ["feed:view-source:http://www.example2.com", false, false, false],
+    ["data:text/html,Hi", true, false, true],
+    ["javascript:alert('hi')", true, false, true],
+  ]],
+  ["view-source:http://www.example.com", [
+    ["http://www.example2.com", true, true, true],
+    ["feed:http://www.example2.com", false, false, true],
+    ["https://www.example2.com", true, true, true],
+    ["feed:https://www.example2.com", false, false, true],
+    ["chrome://foo/content/bar.xul", false, false, true],
+    ["feed:chrome://foo/content/bar.xul", false, false, false],
+    ["view-source:http://www.example2.com", true, true, true],
+    ["view-source:feed:http://www.example2.com", false, false, true],
+    ["feed:view-source:http://www.example2.com", false, false, false],
+    ["data:text/html,Hi", true, false, true],
+    ["javascript:alert('hi')", true, false, true],
+  ]],
+]);
+
+function testURL(source, target, canLoad, canLoadWithoutInherit, canCreate, flags) {
+  let threw = false;
+  let targetURI;
+  try {
+    targetURI = makeURI(target);
+  } catch (ex) {
+    ok(!canCreate, "Shouldn't be passing URIs that we can't create. Failed to create: " + target);
+    return;
+  }
+  ok(canCreate, "Created a URI for " + target + " which should " +
+     (canCreate ? "" : "not ") + "be possible.");
+  try {
+    ssm.checkLoadURIWithPrincipal(source, targetURI, flags);
+  } catch (ex) {
+    info(ex.message);
+    threw = true;
+  }
+  let inheritDisallowed = flags & ssm.DISALLOW_INHERIT_PRINCIPAL;
+  let shouldThrow = inheritDisallowed ? !canLoadWithoutInherit : !canLoad;
+  ok(threw == shouldThrow,
+     "Should " + (shouldThrow ? "" : "not ") + "throw an error when loading " +
+     target + " from " + source.URI.spec +
+     (inheritDisallowed ? " without" : " with") + " principal inheritance.");
+}
+
+add_task(function* () {
+  let baseFlags = ssm.STANDARD | ssm.DONT_REPORT_ERRORS;
+  for (let [sourceString, targetsAndExpectations] of URLs) {
+    let source = ssm.createCodebasePrincipal(makeURI(sourceString), {});
+    for (let [target, canLoad, canLoadWithoutInherit, canCreate] of targetsAndExpectations) {
+      testURL(source, target, canLoad, canLoadWithoutInherit, canCreate, baseFlags);
+      testURL(source, target, canLoad, canLoadWithoutInherit, canCreate,
+              baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL);
+    }
+  }
+
+  // Now test blob URIs, which we need to do in-content.
+  yield BrowserTestUtils.withNewTab("http://www.example.com/", function* (browser) {
+    yield ContentTask.spawn(
+      browser,
+      testURL.toString(),
+      function* (testURLFn) {
+        let testURL = eval("(" + testURLFn + ")");
+        let ssm = Services.scriptSecurityManager;
+        let baseFlags = ssm.STANDARD | ssm.DONT_REPORT_ERRORS;
+        let makeURI = Cu.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI;
+        let b = new content.Blob(["I am a blob"]);
+        let contentBlobURI = content.URL.createObjectURL(b);
+        let contentPrincipal = content.document.nodePrincipal;
+        // Loading this blob URI from the content page should work:
+        testURL(contentPrincipal, contentBlobURI, true, true, true, baseFlags);
+        testURL(contentPrincipal, contentBlobURI, true, true, true,
+                baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL);
+
+        testURL(contentPrincipal, "view-source:" + contentBlobURI, false, false, true,
+                baseFlags);
+        testURL(contentPrincipal, "view-source:" + contentBlobURI, false, false, true,
+                baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL);
+
+        // Feed URIs for blobs can't be created, so need to pass false as the fourth param.
+        for (let prefix of ["feed:", "view-source:feed:", "feed:view-source:"]) {
+          testURL(contentPrincipal, prefix + contentBlobURI, false, false, false,
+                  baseFlags);
+          testURL(contentPrincipal, prefix + contentBlobURI, false, false, false,
+                  baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL);
+        }
+      }
+    );
+
+  });
+});
--- a/config/external/icu/common/moz.build
+++ b/config/external/icu/common/moz.build
@@ -12,12 +12,12 @@ if CONFIG['OS_TARGET'] == 'Android' and 
         'gabi++'
     ]
 
 DEFINES['U_COMMON_IMPLEMENTATION'] = True
 # This normally gets defined in the SDK but our WINVER is too low.
 #FIXME: should probably stop including mozilla-config.h
 DEFINES['LOCALE_SNAME'] = 0x5c
 
-LOCAL_INCLUDES += CONFIG['MOZ_ICU_INCLUDES']
+LOCAL_INCLUDES += ['/intl/icu/source/i18n']
 
 include('../defs.mozbuild')
 include('sources.mozbuild')
--- a/config/external/icu/common/sources.mozbuild
+++ b/config/external/icu/common/sources.mozbuild
@@ -174,8 +174,97 @@ SOURCES += [
    '/intl/icu/source/common/utrie2_builder.cpp',
    '/intl/icu/source/common/uts46.cpp',
    '/intl/icu/source/common/utypes.c',
    '/intl/icu/source/common/uvector.cpp',
    '/intl/icu/source/common/uvectr32.cpp',
    '/intl/icu/source/common/uvectr64.cpp',
    '/intl/icu/source/common/wintz.c',
 ]
+
+EXPORTS.unicode += [
+   '/intl/icu/source/common/unicode/appendable.h',
+   '/intl/icu/source/common/unicode/brkiter.h',
+   '/intl/icu/source/common/unicode/bytestream.h',
+   '/intl/icu/source/common/unicode/bytestrie.h',
+   '/intl/icu/source/common/unicode/bytestriebuilder.h',
+   '/intl/icu/source/common/unicode/caniter.h',
+   '/intl/icu/source/common/unicode/chariter.h',
+   '/intl/icu/source/common/unicode/dbbi.h',
+   '/intl/icu/source/common/unicode/docmain.h',
+   '/intl/icu/source/common/unicode/dtintrv.h',
+   '/intl/icu/source/common/unicode/enumset.h',
+   '/intl/icu/source/common/unicode/errorcode.h',
+   '/intl/icu/source/common/unicode/filteredbrk.h',
+   '/intl/icu/source/common/unicode/icudataver.h',
+   '/intl/icu/source/common/unicode/icuplug.h',
+   '/intl/icu/source/common/unicode/idna.h',
+   '/intl/icu/source/common/unicode/listformatter.h',
+   '/intl/icu/source/common/unicode/localpointer.h',
+   '/intl/icu/source/common/unicode/locid.h',
+   '/intl/icu/source/common/unicode/messagepattern.h',
+   '/intl/icu/source/common/unicode/normalizer2.h',
+   '/intl/icu/source/common/unicode/normlzr.h',
+   '/intl/icu/source/common/unicode/parseerr.h',
+   '/intl/icu/source/common/unicode/parsepos.h',
+   '/intl/icu/source/common/unicode/platform.h',
+   '/intl/icu/source/common/unicode/ptypes.h',
+   '/intl/icu/source/common/unicode/putil.h',
+   '/intl/icu/source/common/unicode/rbbi.h',
+   '/intl/icu/source/common/unicode/rep.h',
+   '/intl/icu/source/common/unicode/resbund.h',
+   '/intl/icu/source/common/unicode/schriter.h',
+   '/intl/icu/source/common/unicode/std_string.h',
+   '/intl/icu/source/common/unicode/strenum.h',
+   '/intl/icu/source/common/unicode/stringpiece.h',
+   '/intl/icu/source/common/unicode/stringtriebuilder.h',
+   '/intl/icu/source/common/unicode/symtable.h',
+   '/intl/icu/source/common/unicode/ubidi.h',
+   '/intl/icu/source/common/unicode/ubrk.h',
+   '/intl/icu/source/common/unicode/ucasemap.h',
+   '/intl/icu/source/common/unicode/ucat.h',
+   '/intl/icu/source/common/unicode/uchar.h',
+   '/intl/icu/source/common/unicode/ucharstrie.h',
+   '/intl/icu/source/common/unicode/ucharstriebuilder.h',
+   '/intl/icu/source/common/unicode/uchriter.h',
+   '/intl/icu/source/common/unicode/uclean.h',
+   '/intl/icu/source/common/unicode/ucnv.h',
+   '/intl/icu/source/common/unicode/ucnv_cb.h',
+   '/intl/icu/source/common/unicode/ucnv_err.h',
+   '/intl/icu/source/common/unicode/ucnvsel.h',
+   '/intl/icu/source/common/unicode/uconfig.h',
+   '/intl/icu/source/common/unicode/udata.h',
+   '/intl/icu/source/common/unicode/uenum.h',
+   '/intl/icu/source/common/unicode/uidna.h',
+   '/intl/icu/source/common/unicode/uiter.h',
+   '/intl/icu/source/common/unicode/ulistformatter.h',
+   '/intl/icu/source/common/unicode/uloc.h',
+   '/intl/icu/source/common/unicode/umachine.h',
+   '/intl/icu/source/common/unicode/umisc.h',
+   '/intl/icu/source/common/unicode/unifilt.h',
+   '/intl/icu/source/common/unicode/unifunct.h',
+   '/intl/icu/source/common/unicode/unimatch.h',
+   '/intl/icu/source/common/unicode/uniset.h',
+   '/intl/icu/source/common/unicode/unistr.h',
+   '/intl/icu/source/common/unicode/unorm.h',
+   '/intl/icu/source/common/unicode/unorm2.h',
+   '/intl/icu/source/common/unicode/uobject.h',
+   '/intl/icu/source/common/unicode/urename.h',
+   '/intl/icu/source/common/unicode/urep.h',
+   '/intl/icu/source/common/unicode/ures.h',
+   '/intl/icu/source/common/unicode/uscript.h',
+   '/intl/icu/source/common/unicode/uset.h',
+   '/intl/icu/source/common/unicode/usetiter.h',
+   '/intl/icu/source/common/unicode/ushape.h',
+   '/intl/icu/source/common/unicode/usprep.h',
+   '/intl/icu/source/common/unicode/ustring.h',
+   '/intl/icu/source/common/unicode/ustringtrie.h',
+   '/intl/icu/source/common/unicode/utext.h',
+   '/intl/icu/source/common/unicode/utf.h',
+   '/intl/icu/source/common/unicode/utf16.h',
+   '/intl/icu/source/common/unicode/utf32.h',
+   '/intl/icu/source/common/unicode/utf8.h',
+   '/intl/icu/source/common/unicode/utf_old.h',
+   '/intl/icu/source/common/unicode/utrace.h',
+   '/intl/icu/source/common/unicode/utypes.h',
+   '/intl/icu/source/common/unicode/uvernum.h',
+   '/intl/icu/source/common/unicode/uversion.h',
+]
--- a/config/external/icu/i18n/moz.build
+++ b/config/external/icu/i18n/moz.build
@@ -4,12 +4,12 @@
 # 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/.
 
 Library('icui18n')
 FINAL_LIBRARY = 'icu'
 
 DEFINES['U_I18N_IMPLEMENTATION'] = True
 
-LOCAL_INCLUDES += CONFIG['MOZ_ICU_INCLUDES']
+LOCAL_INCLUDES += ['/intl/icu/source/common']
 
 include('../defs.mozbuild')
 include('sources.mozbuild')
--- a/config/external/icu/i18n/sources.mozbuild
+++ b/config/external/icu/i18n/sources.mozbuild
@@ -194,8 +194,92 @@ SOURCES += [
    '/intl/icu/source/i18n/vzone.cpp',
    '/intl/icu/source/i18n/windtfmt.cpp',
    '/intl/icu/source/i18n/winnmfmt.cpp',
    '/intl/icu/source/i18n/wintzimpl.cpp',
    '/intl/icu/source/i18n/zonemeta.cpp',
    '/intl/icu/source/i18n/zrule.cpp',
    '/intl/icu/source/i18n/ztrans.cpp',
 ]
+
+EXPORTS.unicode += [
+   '/intl/icu/source/i18n/unicode/alphaindex.h',
+   '/intl/icu/source/i18n/unicode/basictz.h',
+   '/intl/icu/source/i18n/unicode/calendar.h',
+   '/intl/icu/source/i18n/unicode/choicfmt.h',
+   '/intl/icu/source/i18n/unicode/coleitr.h',
+   '/intl/icu/source/i18n/unicode/coll.h',
+   '/intl/icu/source/i18n/unicode/compactdecimalformat.h',
+   '/intl/icu/source/i18n/unicode/curramt.h',
+   '/intl/icu/source/i18n/unicode/currpinf.h',
+   '/intl/icu/source/i18n/unicode/currunit.h',
+   '/intl/icu/source/i18n/unicode/datefmt.h',
+   '/intl/icu/source/i18n/unicode/dcfmtsym.h',
+   '/intl/icu/source/i18n/unicode/decimfmt.h',
+   '/intl/icu/source/i18n/unicode/dtfmtsym.h',
+   '/intl/icu/source/i18n/unicode/dtitvfmt.h',
+   '/intl/icu/source/i18n/unicode/dtitvinf.h',
+   '/intl/icu/source/i18n/unicode/dtptngen.h',
+   '/intl/icu/source/i18n/unicode/dtrule.h',
+   '/intl/icu/source/i18n/unicode/fieldpos.h',
+   '/intl/icu/source/i18n/unicode/fmtable.h',
+   '/intl/icu/source/i18n/unicode/format.h',
+   '/intl/icu/source/i18n/unicode/fpositer.h',
+   '/intl/icu/source/i18n/unicode/gender.h',
+   '/intl/icu/source/i18n/unicode/gregocal.h',
+   '/intl/icu/source/i18n/unicode/locdspnm.h',
+   '/intl/icu/source/i18n/unicode/measfmt.h',
+   '/intl/icu/source/i18n/unicode/measunit.h',
+   '/intl/icu/source/i18n/unicode/measure.h',
+   '/intl/icu/source/i18n/unicode/msgfmt.h',
+   '/intl/icu/source/i18n/unicode/numfmt.h',
+   '/intl/icu/source/i18n/unicode/numsys.h',
+   '/intl/icu/source/i18n/unicode/plurfmt.h',
+   '/intl/icu/source/i18n/unicode/plurrule.h',
+   '/intl/icu/source/i18n/unicode/rbnf.h',
+   '/intl/icu/source/i18n/unicode/rbtz.h',
+   '/intl/icu/source/i18n/unicode/regex.h',
+   '/intl/icu/source/i18n/unicode/region.h',
+   '/intl/icu/source/i18n/unicode/reldatefmt.h',
+   '/intl/icu/source/i18n/unicode/scientificnumberformatter.h',
+   '/intl/icu/source/i18n/unicode/search.h',
+   '/intl/icu/source/i18n/unicode/selfmt.h',
+   '/intl/icu/source/i18n/unicode/simpletz.h',
+   '/intl/icu/source/i18n/unicode/smpdtfmt.h',
+   '/intl/icu/source/i18n/unicode/sortkey.h',
+   '/intl/icu/source/i18n/unicode/stsearch.h',
+   '/intl/icu/source/i18n/unicode/tblcoll.h',
+   '/intl/icu/source/i18n/unicode/timezone.h',
+   '/intl/icu/source/i18n/unicode/tmunit.h',
+   '/intl/icu/source/i18n/unicode/tmutamt.h',
+   '/intl/icu/source/i18n/unicode/tmutfmt.h',
+   '/intl/icu/source/i18n/unicode/translit.h',
+   '/intl/icu/source/i18n/unicode/tzfmt.h',
+   '/intl/icu/source/i18n/unicode/tznames.h',
+   '/intl/icu/source/i18n/unicode/tzrule.h',
+   '/intl/icu/source/i18n/unicode/tztrans.h',
+   '/intl/icu/source/i18n/unicode/ucal.h',
+   '/intl/icu/source/i18n/unicode/ucol.h',
+   '/intl/icu/source/i18n/unicode/ucoleitr.h',
+   '/intl/icu/source/i18n/unicode/ucsdet.h',
+   '/intl/icu/source/i18n/unicode/ucurr.h',
+   '/intl/icu/source/i18n/unicode/udat.h',
+   '/intl/icu/source/i18n/unicode/udateintervalformat.h',
+   '/intl/icu/source/i18n/unicode/udatpg.h',
+   '/intl/icu/source/i18n/unicode/udisplaycontext.h',
+   '/intl/icu/source/i18n/unicode/ufieldpositer.h',
+   '/intl/icu/source/i18n/unicode/uformattable.h',
+   '/intl/icu/source/i18n/unicode/ugender.h',
+   '/intl/icu/source/i18n/unicode/uldnames.h',
+   '/intl/icu/source/i18n/unicode/ulocdata.h',
+   '/intl/icu/source/i18n/unicode/umsg.h',
+   '/intl/icu/source/i18n/unicode/unirepl.h',
+   '/intl/icu/source/i18n/unicode/unum.h',
+   '/intl/icu/source/i18n/unicode/unumsys.h',
+   '/intl/icu/source/i18n/unicode/upluralrules.h',
+   '/intl/icu/source/i18n/unicode/uregex.h',
+   '/intl/icu/source/i18n/unicode/uregion.h',
+   '/intl/icu/source/i18n/unicode/usearch.h',
+   '/intl/icu/source/i18n/unicode/uspoof.h',
+   '/intl/icu/source/i18n/unicode/utmscale.h',
+   '/intl/icu/source/i18n/unicode/utrans.h',
+   '/intl/icu/source/i18n/unicode/vtzone.h',
+]
--- a/config/external/icu/stubdata/moz.build
+++ b/config/external/icu/stubdata/moz.build
@@ -5,11 +5,9 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # This builds the ICU stubdata library, since we are shipping ICU
 # data in a separate data file. ICU needs a data symbol to link against
 # even if you're loading its data from a file.
 
 Library('icustubdata')
 
-LOCAL_INCLUDES += CONFIG['MOZ_ICU_INCLUDES']
-
 SOURCES += ['/intl/icu/source/stubdata/stubdata.c']
--- a/config/nsinstall.py
+++ b/config/nsinstall.py
@@ -6,16 +6,17 @@
 # It's intended to be used when there's no natively compile nsinstall
 # available, and doesn't intend to be fully equivalent.
 # Its major use is for l10n repackaging on systems that don't have
 # a full build environment set up.
 # The basic limitation is, it doesn't even try to link and ignores
 # all related options.
 from __future__ import print_function
 from optparse import OptionParser
+import mozfile
 import os
 import os.path
 import sys
 import shutil
 import stat
 
 def _nsinstall_internal(argv):
   usage = "usage: %prog [options] arg1 [arg2 ...] target-directory"
@@ -121,20 +122,20 @@ def _nsinstall_internal(argv):
           os.mkdir(targetpath)
         entries = [os.path.join(srcpath, e) for e in os.listdir(srcpath)]
         copy_all_entries(entries, targetpath)
         # options.t is not relevant for directories
         if options.m:
           os.chmod(targetpath, options.m)
       else:
         if os.path.exists(targetpath):
-          # On Windows, read-only files can't be deleted
           if sys.platform == "win32":
-            os.chmod(targetpath, stat.S_IWUSR)
-          os.remove(targetpath)
+            mozfile.remove(targetpath)
+          else:
+            os.remove(targetpath)
         if options.t:
           shutil.copy2(srcpath, targetpath)
         else:
           shutil.copy(srcpath, targetpath)
 
   # the last argument is the target directory
   target = args.pop()
   # ensure target directory (importantly, we do not apply a mode to the directory
--- a/config/system-headers
+++ b/config/system-headers
@@ -552,16 +552,20 @@ intshcut.h
 inttypes.h
 iodef.h
 io.h
 IOKit/IOKitLib.h
 IOKit/IOMessage.h
 IOKit/pwr_mgt/IOPMLib.h
 iomanip
 iostream.h
+#if MOZ_JACK==1
+jack/jack.h
+jack/statistics.h
+#endif
 JavaControl.h
 JavaEmbedding/JavaControl.h
 JavaVM/jni.h
 JManager.h
 JNIEnvTests.h
 jni.h
 #if MOZ_SYSTEM_JPEG==1
 jpeglib.h
--- a/devtools/client/definitions.js
+++ b/devtools/client/definitions.js
@@ -1,18 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const {Cc, Ci} = require("chrome");
 const Services = require("Services");
-
-loader.lazyGetter(this, "osString", () => Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS);
+const osString = Services.appinfo.OS;
 
 // Panels
 loader.lazyGetter(this, "OptionsPanel", () => require("devtools/client/framework/toolbox-options").OptionsPanel);
 loader.lazyGetter(this, "InspectorPanel", () => require("devtools/client/inspector/inspector-panel").InspectorPanel);
 loader.lazyGetter(this, "WebConsolePanel", () => require("devtools/client/webconsole/panel").WebConsolePanel);
 loader.lazyGetter(this, "DebuggerPanel", () => require("devtools/client/debugger/panel").DebuggerPanel);
 loader.lazyGetter(this, "StyleEditorPanel", () => require("devtools/client/styleeditor/styleeditor-panel").StyleEditorPanel);
 loader.lazyGetter(this, "ShaderEditorPanel", () => require("devtools/client/shadereditor/panel").ShaderEditorPanel);
--- a/devtools/client/eyedropper/eyedropper.js
+++ b/devtools/client/eyedropper/eyedropper.js
@@ -27,20 +27,16 @@ loader.lazyGetter(this, "ioService", fun
   return Cc["@mozilla.org/network/io-service;1"]
     .getService(Ci.nsIIOService);
 });
 
 loader.lazyGetter(this, "DOMUtils", function () {
   return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
 });
 
-loader.lazyGetter(this, "XULRuntime", function () {
-  return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
-});
-
 loader.lazyGetter(this, "l10n", () => Services.strings
   .createBundle("chrome://devtools/locale/eyedropper.properties"));
 
 const EYEDROPPER_URL = "chrome://devtools/content/eyedropper/eyedropper.xul";
 const CROSSHAIRS_URL = "chrome://devtools/content/eyedropper/crosshairs.css";
 const NOCURSOR_URL = "chrome://devtools/content/eyedropper/nocursor.css";
 
 const ZOOM_PREF = "devtools.eyedropper.zoom";
@@ -112,17 +108,17 @@ function Eyedropper(chromeWindow, opts =
   this._onMouseMove = this._onMouseMove.bind(this);
   this._onMouseDown = this._onMouseDown.bind(this);
   this._onKeyDown = this._onKeyDown.bind(this);
   this._onFrameLoaded = this._onFrameLoaded.bind(this);
 
   this._chromeWindow = chromeWindow;
   this._chromeDocument = chromeWindow.document;
 
-  this._OS = XULRuntime.OS;
+  this._OS = Services.appinfo.OS;
 
   this._dragging = true;
   this.loaded = false;
 
   this._mouseMoveCounter = 0;
 
   this.format = Services.prefs.getCharPref(FORMAT_PREF); // color value format
   this.zoom = Services.prefs.getIntPref(ZOOM_PREF);      // zoom level - integer
--- a/devtools/client/framework/test/shared-head.js
+++ b/devtools/client/framework/test/shared-head.js
@@ -1,12 +1,13 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
+/* eslint no-unused-vars: [2, {"vars": "local"}] */
 
 "use strict";
 
 // This shared-head.js file is used for multiple mochitest test directories in
 // devtools.
 // It contains various common helper functions.
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr, Constructor: CC}
@@ -469,8 +470,22 @@ function waitForContextMenu(popup, butto
  * @return {Promise} resolves when the preferences have been updated
  */
 function pushPref(preferenceName, value) {
   return new Promise(resolve => {
     let options = {"set": [[preferenceName, value]]};
     SpecialPowers.pushPrefEnv(options, resolve);
   });
 }
+
+/**
+ * Lookup the provided dotted path ("prop1.subprop2.myProp") in the provided object.
+ *
+ * @param {Object} obj
+ *        Object to expand.
+ * @param {String} path
+ *        Dotted path to use to expand the object.
+ * @return {?} anything that is found at the provided path in the object.
+ */
+function lookupPath(obj, path) {
+  let segments = path.split(".");
+  return segments.reduce((prev, current) => prev[current], obj);
+}
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -65,19 +65,16 @@ loader.lazyRequireGetter(this, "system",
   "devtools/shared/system");
 loader.lazyRequireGetter(this, "getPreferenceFront",
   "devtools/shared/fronts/preference", true);
 loader.lazyRequireGetter(this, "KeyShortcuts",
   "devtools/client/shared/key-shortcuts", true);
 loader.lazyRequireGetter(this, "ZoomKeys",
   "devtools/client/shared/zoom-keys");
 
-loader.lazyGetter(this, "osString", () => {
-  return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
-});
 loader.lazyGetter(this, "registerHarOverlay", () => {
   return require("devtools/client/netmonitor/har/toolbox-overlay").register;
 });
 
 // White-list buttons that can be toggled to prevent adding prefs for
 // addons that have manually inserted toolbarbuttons into DOM.
 // (By default, supported target is only local tab)
 const ToolboxButtons = exports.ToolboxButtons = [
@@ -490,17 +487,18 @@ Toolbox.prototype = {
   get ReactDOM() {
     return this.browserRequire("devtools/client/shared/vendor/react-dom");
   },
 
   _pingTelemetry: function () {
     this._telemetry.toolOpened("toolbox");
 
     this._telemetry.logOncePerBrowserVersion(OS_HISTOGRAM, system.getOSCPU());
-    this._telemetry.logOncePerBrowserVersion(OS_IS_64_BITS, system.is64Bit ? 1 : 0);
+    this._telemetry.logOncePerBrowserVersion(OS_IS_64_BITS,
+                                             Services.appinfo.is64Bit ? 1 : 0);
     this._telemetry.logOncePerBrowserVersion(SCREENSIZE_HISTOGRAM, system.getScreenDimensions());
   },
 
   /**
    * Because our panels are lazy loaded this is a good place to watch for
    * "pref-changed" events.
    * @param  {String} event
    *         The event type, "pref-changed".
--- a/devtools/client/inspector/computed/computed.js
+++ b/devtools/client/inspector/computed/computed.js
@@ -24,16 +24,18 @@ const {XPCOMUtils} = require("resource:/
 const {getCssProperties} = require("devtools/shared/fronts/css-properties");
 
 loader.lazyRequireGetter(this, "overlays",
   "devtools/client/inspector/shared/style-inspector-overlays");
 loader.lazyRequireGetter(this, "StyleInspectorMenu",
   "devtools/client/inspector/shared/style-inspector-menu");
 loader.lazyRequireGetter(this, "KeyShortcuts",
   "devtools/client/shared/key-shortcuts", true);
+loader.lazyRequireGetter(this, "LayoutView",
+  "devtools/client/inspector/layout/layout", true);
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
                                   "resource://gre/modules/PluralForm.jsm");
 
 XPCOMUtils.defineLazyGetter(CssComputedView, "_strings", function () {
   return Services.strings.createBundle(
     "chrome://devtools-shared/locale/styleinspector.properties");
 });
@@ -164,17 +166,16 @@ function CssComputedView(inspector, docu
   this._onCopy = this._onCopy.bind(this);
   this._onFilterStyles = this._onFilterStyles.bind(this);
   this._onClearSearch = this._onClearSearch.bind(this);
   this._onIncludeBrowserStyles = this._onIncludeBrowserStyles.bind(this);
   this._onFilterTextboxContextMenu =
     this._onFilterTextboxContextMenu.bind(this);
 
   let doc = this.styleDocument;
-  this.root = doc.getElementById("root");
   this.element = doc.getElementById("propertyContainer");
   this.searchField = doc.getElementById("computedview-searchbox");
   this.searchClearButton = doc.getElementById("computedview-searchinput-clear");
   this.includeBrowserStylesCheckbox =
     doc.getElementById("browser-style-checkbox");
 
   this.shortcuts = new KeyShortcuts({ window: this.styleWindow });
   this._onShortcut = this._onShortcut.bind(this);
@@ -772,17 +773,16 @@ CssComputedView.prototype = {
     this.searchField.removeEventListener("input", this._onFilterStyles);
     this.searchField.removeEventListener("contextmenu",
                                          this._onFilterTextboxContextMenu);
     this.searchClearButton.removeEventListener("click", this._onClearSearch);
     this.includeBrowserStylesCheckbox.removeEventListener("input",
       this._onIncludeBrowserStyles);
 
     // Nodes used in templating
-    this.root = null;
     this.element = null;
     this.panel = null;
     this.searchField = null;
     this.searchClearButton = null;
     this.includeBrowserStylesCheckbox = null;
 
     // Property views
     for (let propView of this.propertyViews) {
@@ -1402,85 +1402,86 @@ SelectorView.prototype = {
     });
   }
 };
 
 function ComputedViewTool(inspector, window) {
   this.inspector = inspector;
   this.document = window.document;
 
-  this.view = new CssComputedView(this.inspector, this.document,
+  this.computedView = new CssComputedView(this.inspector, this.document,
     this.inspector.pageStyle);
+  this.layoutView = new LayoutView(this.inspector, this.document);
 
   this.onSelected = this.onSelected.bind(this);
   this.refresh = this.refresh.bind(this);
   this.onPanelSelected = this.onPanelSelected.bind(this);
   this.onMutations = this.onMutations.bind(this);
   this.onResized = this.onResized.bind(this);
 
   this.inspector.selection.on("detached", this.onSelected);
   this.inspector.selection.on("new-node-front", this.onSelected);
   this.inspector.selection.on("pseudoclass", this.refresh);
   this.inspector.sidebar.on("computedview-selected", this.onPanelSelected);
   this.inspector.pageStyle.on("stylesheet-updated", this.refresh);
   this.inspector.walker.on("mutations", this.onMutations);
   this.inspector.walker.on("resize", this.onResized);
 
-  this.view.selectElement(null);
+  this.computedView.selectElement(null);
 
   this.onSelected();
 }
 
 ComputedViewTool.prototype = {
   isSidebarActive: function () {
-    if (!this.view) {
+    if (!this.computedView) {
       return false;
     }
     return this.inspector.sidebar.getCurrentTabID() == "computedview";
   },
 
   onSelected: function (event) {
     // Ignore the event if the view has been destroyed, or if it's inactive.
     // But only if the current selection isn't null. If it's been set to null,
     // let the update go through as this is needed to empty the view on
     // navigation.
-    if (!this.view) {
+    if (!this.computedView) {
       return;
     }
 
     let isInactive = !this.isSidebarActive() &&
                      this.inspector.selection.nodeFront;
     if (isInactive) {
       return;
     }
 
-    this.view.setPageStyle(this.inspector.pageStyle);
+    this.computedView.setPageStyle(this.inspector.pageStyle);
 
     if (!this.inspector.selection.isConnected() ||
         !this.inspector.selection.isElementNode()) {
-      this.view.selectElement(null);
+      this.computedView.selectElement(null);
       return;
     }
 
     if (!event || event == "new-node-front") {
       let done = this.inspector.updating("computed-view");
-      this.view.selectElement(this.inspector.selection.nodeFront).then(() => {
+      this.computedView.selectElement(this.inspector.selection.nodeFront).then(() => {
         done();
       });
     }
   },
 
   refresh: function () {
     if (this.isSidebarActive()) {
-      this.view.refreshPanel();
+      this.computedView.refreshPanel();
     }
   },
 
   onPanelSelected: function () {
-    if (this.inspector.selection.nodeFront === this.view._viewedElement) {
+    if (this.inspector.selection.nodeFront === this.computedView._viewedElement) {
       this.refresh();
     } else {
       this.onSelected();
     }
   },
 
   /**
    * When markup mutations occur, if an attribute of the selected node changes,
@@ -1511,17 +1512,18 @@ ComputedViewTool.prototype = {
     this.inspector.selection.off("pseudoclass", this.refresh);
     this.inspector.selection.off("new-node-front", this.onSelected);
     this.inspector.selection.off("detached", this.onSelected);
     this.inspector.sidebar.off("computedview-selected", this.onPanelSelected);
     if (this.inspector.pageStyle) {
       this.inspector.pageStyle.off("stylesheet-updated", this.refresh);
     }
 
-    this.view.destroy();
+    this.computedView.destroy();
+    this.layoutView.destroy();
 
-    this.view = this.document = this.inspector = null;
+    this.computedView = this.layoutView = this.document = this.inspector = null;
   }
 };
 
 exports.CssComputedView = CssComputedView;
 exports.ComputedViewTool = ComputedViewTool;
 exports.PropertyView = PropertyView;
--- a/devtools/client/inspector/computed/test/browser_computed_cycle_color.js
+++ b/devtools/client/inspector/computed/test/browser_computed_cycle_color.js
@@ -54,16 +54,17 @@ function* checkColorCycling(container, v
   for (let test of tests) {
     yield checkSwatchShiftClick(container, win, test.value, test.comment);
   }
 }
 
 function* checkSwatchShiftClick(container, win, expectedValue, comment) {
   let swatch = container.querySelector(".computedview-colorswatch");
   let valueNode = container.querySelector(".computedview-color");
+  swatch.scrollIntoView();
 
   let onUnitChange = swatch.once("unit-change");
   EventUtils.synthesizeMouseAtCenter(swatch, {
     type: "mousedown",
     shiftKey: true
   }, win);
   yield onUnitChange;
   is(valueNode.textContent, expectedValue, comment);
--- a/devtools/client/inspector/computed/test/browser_computed_keybindings_01.js
+++ b/devtools/client/inspector/computed/test/browser_computed_keybindings_01.js
@@ -20,16 +20,17 @@ add_task(function* () {
   let {inspector, view} = yield openComputedView();
   yield selectNode(".matches", inspector);
 
   let propView = getFirstVisiblePropertyView(view);
   let rulesTable = propView.matchedSelectorsContainer;
   let matchedExpander = propView.element;
 
   info("Focusing the property");
+  matchedExpander.scrollIntoView();
   let onMatchedExpanderFocus = once(matchedExpander, "focus", true);
   EventUtils.synthesizeMouseAtCenter(matchedExpander, {}, view.styleWindow);
   yield onMatchedExpanderFocus;
 
   yield checkToggleKeyBinding(view.styleWindow, "VK_SPACE", rulesTable,
                               inspector);
   yield checkToggleKeyBinding(view.styleWindow, "VK_RETURN", rulesTable,
                               inspector);
--- a/devtools/client/inspector/computed/test/browser_computed_matched-selectors-toggle.js
+++ b/devtools/client/inspector/computed/test/browser_computed_matched-selectors-toggle.js
@@ -25,17 +25,17 @@ add_task(function* () {
   yield testExpandOnDblClick(view, inspector);
   yield testCollapseOnDblClick(view, inspector);
 });
 
 function* testExpandOnTwistyClick({styleDocument, styleWindow}, inspector) {
   info("Testing that a property expands on twisty click");
 
   info("Getting twisty element");
-  let twisty = styleDocument.querySelector(".expandable");
+  let twisty = styleDocument.querySelector("#propertyContainer .expandable");
   ok(twisty, "Twisty found");
 
   let onExpand = inspector.once("computed-view-property-expanded");
   info("Clicking on the twisty element");
   twisty.click();
 
   yield onExpand;
 
@@ -44,17 +44,17 @@ function* testExpandOnTwistyClick({style
   ok(div.childNodes.length > 0,
     "Matched selectors are expanded on twisty click");
 }
 
 function* testCollapseOnTwistyClick({styleDocument, styleWindow}, inspector) {
   info("Testing that a property collapses on twisty click");
 
   info("Getting twisty element");
-  let twisty = styleDocument.querySelector(".expandable");
+  let twisty = styleDocument.querySelector("#propertyContainer .expandable");
   ok(twisty, "Twisty found");
 
   let onCollapse = inspector.once("computed-view-property-collapsed");
   info("Clicking on the twisty element");
   twisty.click();
 
   yield onCollapse;
 
@@ -66,16 +66,18 @@ function* testCollapseOnTwistyClick({sty
 
 function* testExpandOnDblClick({styleDocument, styleWindow}, inspector) {
   info("Testing that a property expands on container dbl-click");
 
   info("Getting computed property container");
   let container = styleDocument.querySelector(".property-view");
   ok(container, "Container found");
 
+  container.scrollIntoView();
+
   let onExpand = inspector.once("computed-view-property-expanded");
   info("Dbl-clicking on the container");
   EventUtils.synthesizeMouseAtCenter(container, {clickCount: 2}, styleWindow);
 
   yield onExpand;
 
   // Expanded means the matchedselectors div is not empty
   let div = styleDocument.querySelector(".property-content .matchedselectors");
--- a/devtools/client/inspector/computed/test/browser_computed_select-and-copy-styles.js
+++ b/devtools/client/inspector/computed/test/browser_computed_select-and-copy-styles.js
@@ -1,19 +1,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Tests that properties can be selected and copied from the computed view.
 
-XPCOMUtils.defineLazyGetter(this, "osString", function () {
-  return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
-});
+const osString = Services.appinfo.OS;
 
 const TEST_URI = `
   <style type="text/css">
     span {
       font-variant-caps: small-caps;
       color: #000000;
     }
     .nomatches {
--- a/devtools/client/inspector/computed/test/head.js
+++ b/devtools/client/inspector/computed/test/head.js
@@ -127,17 +127,17 @@ function getComputedViewPropertyValue(vi
  *        The instance of the computed view panel
  * @param {Number} index
  *        The index of the property to be expanded
  * @return a promise that resolves when the property has been expanded, or
  * rejects if the property was not found
  */
 function expandComputedViewPropertyByIndex(view, index) {
   info("Expanding property " + index + " in the computed view");
-  let expandos = view.styleDocument.querySelectorAll(".expandable");
+  let expandos = view.styleDocument.querySelectorAll("#propertyContainer .expandable");
   if (!expandos.length || !expandos[index]) {
     return promise.reject();
   }
 
   let onExpand = view.inspector.once("computed-view-property-expanded");
   expandos[index].click();
   return onExpand;
 }
--- a/devtools/client/inspector/inspector-panel.js
+++ b/devtools/client/inspector/inspector-panel.js
@@ -26,17 +26,16 @@ const MenuItem = require("devtools/clien
 
 loader.lazyRequireGetter(this, "CSS", "CSS");
 
 loader.lazyRequireGetter(this, "CommandUtils", "devtools/client/shared/developer-toolbar", true);
 loader.lazyRequireGetter(this, "ComputedViewTool", "devtools/client/inspector/computed/computed", true);
 loader.lazyRequireGetter(this, "FontInspector", "devtools/client/inspector/fonts/fonts", true);
 loader.lazyRequireGetter(this, "HTMLBreadcrumbs", "devtools/client/inspector/breadcrumbs", true);
 loader.lazyRequireGetter(this, "InspectorSearch", "devtools/client/inspector/inspector-search", true);
-loader.lazyRequireGetter(this, "LayoutView", "devtools/client/inspector/layout/layout", true);
 loader.lazyRequireGetter(this, "MarkupView", "devtools/client/inspector/markup/markup", true);
 loader.lazyRequireGetter(this, "RuleViewTool", "devtools/client/inspector/rules/rules", true);
 loader.lazyRequireGetter(this, "ToolSidebar", "devtools/client/inspector/toolsidebar", true);
 loader.lazyRequireGetter(this, "ViewHelpers", "devtools/client/shared/widgets/view-helpers", true);
 
 loader.lazyGetter(this, "strings", () => {
   return Services.strings.createBundle("chrome://devtools/locale/inspector.properties");
 });
@@ -418,30 +417,24 @@ InspectorPanel.prototype = {
       strings.GetStringFromName("inspector.sidebar.ruleViewTitle"),
       defaultTab == "ruleview");
 
     this.sidebar.addExistingTab(
       "computedview",
       strings.GetStringFromName("inspector.sidebar.computedViewTitle"),
       defaultTab == "computedview");
 
-    this.sidebar.addExistingTab(
-      "layoutview",
-      strings.GetStringFromName("inspector.sidebar.layoutViewTitle"),
-      defaultTab == "layoutview");
-
     this._setDefaultSidebar = (event, toolId) => {
       Services.prefs.setCharPref("devtools.inspector.activeSidebar", toolId);
     };
 
     this.sidebar.on("select", this._setDefaultSidebar);
 
     this.ruleview = new RuleViewTool(this, this.panelWin);
     this.computedview = new ComputedViewTool(this, this.panelWin);
-    this.layoutview = new LayoutView(this, this.panelWin);
 
     if (this.target.form.animationsActor) {
       this.sidebar.addFrameTab(
         "animationinspector",
         strings.GetStringFromName("inspector.sidebar.animationInspectorTitle"),
         "chrome://devtools/content/animationinspector/animation-inspector.xhtml",
         defaultTab == "animationinspector");
     }
@@ -747,20 +740,16 @@ InspectorPanel.prototype = {
     if (this.computedview) {
       this.computedview.destroy();
     }
 
     if (this.fontInspector) {
       this.fontInspector.destroy();
     }
 
-    if (this.layoutview) {
-      this.layoutview.destroy();
-    }
-
     let cssPropertiesDestroyer = this._cssPropertiesLoaded.then(({front}) => {
       if (front) {
         front.destroy();
       }
     });
 
     this.sidebar.off("select", this._setDefaultSidebar);
     let sidebarDestroyer = this.sidebar.destroy();
--- a/devtools/client/inspector/inspector.xul
+++ b/devtools/client/inspector/inspector.xul
@@ -102,69 +102,74 @@
           </html:div>
           <html:label id="browser-style-checkbox-label" for="browser-style-checkbox">
             <html:input id="browser-style-checkbox"
                         type="checkbox"
                         class="includebrowserstyles"
                         label="&browserStylesLabel;"/>&browserStylesLabel;</html:label>
         </html:div>
 
-        <html:div id="propertyContainer">
-        </html:div>
-
-        <html:div id="computedview-no-results" hidden="">
-          &noPropertiesFound;
-        </html:div>
-      </html:div>
+        <html:div id="computedview-container">
+          <html:div id="layout-wrapper" class="theme-separator" tabindex="0">
+            <html:div id="layout-header">
+              <html:div id="layout-expander" class="expander theme-twisty expandable" open=""></html:div>
+              <html:span>&layoutViewTitle;</html:span>
+              <html:button class="devtools-button" id="layout-geometry-editor" title="&geometry.button.tooltip;"></html:button>
+            </html:div>
 
-      <html:div id="sidebar-panel-layoutview" class="devtools-monospace theme-sidebar inspector-tabpanel">
-        <html:div id="layout-wrapper">
-          <html:div id="layout-container">
-            <html:p id="layout-header">
-              <html:span id="layout-element-size"></html:span>
-              <html:section id="layout-position-group">
-                <html:button class="devtools-button" id="layout-geometry-editor" title="&geometry.button.tooltip;"></html:button>
-                <html:span id="layout-element-position"></html:span>
-              </html:section>
-            </html:p>
-
-            <html:div id="layout-main">
-              <html:span class="layout-legend" data-box="margin" title="&margin.tooltip;">&margin.tooltip;</html:span>
-              <html:div id="layout-margins" data-box="margin" title="&margin.tooltip;">
-                <html:span class="layout-legend" data-box="border" title="&border.tooltip;">&border.tooltip;</html:span>
-                <html:div id="layout-borders" data-box="border" title="&border.tooltip;">
-                  <html:span class="layout-legend" data-box="padding" title="&padding.tooltip;">&padding.tooltip;</html:span>
-                  <html:div id="layout-padding" data-box="padding" title="&padding.tooltip;">
-                    <html:div id="layout-content" data-box="content" title="&content.tooltip;">
+            <html:div id="layout-container">
+              <html:div id="layout-main">
+                <html:span class="layout-legend" data-box="margin" title="&margin.tooltip;">&margin.tooltip;</html:span>
+                <html:div id="layout-margins" data-box="margin" title="&margin.tooltip;">
+                  <html:span class="layout-legend" data-box="border" title="&border.tooltip;">&border.tooltip;</html:span>
+                  <html:div id="layout-borders" data-box="border" title="&border.tooltip;">
+                    <html:span class="layout-legend" data-box="padding" title="&padding.tooltip;">&padding.tooltip;</html:span>
+                    <html:div id="layout-padding" data-box="padding" title="&padding.tooltip;">
+                      <html:div id="layout-content" data-box="content" title="&content.tooltip;">
+                      </html:div>
                     </html:div>
                   </html:div>
                 </html:div>
+
+                <html:p class="layout-margin layout-top"><html:span data-box="margin" class="layout-editable" title="margin-top"></html:span></html:p>
+                <html:p class="layout-margin layout-right"><html:span data-box="margin" class="layout-editable" title="margin-right"></html:span></html:p>
+                <html:p class="layout-margin layout-bottom"><html:span data-box="margin" class="layout-editable" title="margin-bottom"></html:span></html:p>
+                <html:p class="layout-margin layout-left"><html:span data-box="margin" class="layout-editable" title="margin-left"></html:span></html:p>
+
+                <html:p class="layout-border layout-top"><html:span data-box="border" class="layout-editable" title="border-top"></html:span></html:p>
+                <html:p class="layout-border layout-right"><html:span data-box="border" class="layout-editable" title="border-right"></html:span></html:p>
+                <html:p class="layout-border layout-bottom"><html:span data-box="border" class="layout-editable" title="border-bottom"></html:span></html:p>
+                <html:p class="layout-border layout-left"><html:span data-box="border" class="layout-editable" title="border-left"></html:span></html:p>
+
+                <html:p class="layout-padding layout-top"><html:span data-box="padding" class="layout-editable" title="padding-top"></html:span></html:p>
+                <html:p class="layout-padding layout-right"><html:span data-box="padding" class="layout-editable" title="padding-right"></html:span></html:p>
+                <html:p class="layout-padding layout-bottom"><html:span data-box="padding" class="layout-editable" title="padding-bottom"></html:span></html:p>
+                <html:p class="layout-padding layout-left"><html:span data-box="padding" class="layout-editable" title="padding-left"></html:span></html:p>
+
+                <html:p class="layout-size"><html:span data-box="content" title="&content.tooltip;"></html:span></html:p>
               </html:div>
 
-              <html:p class="layout-border layout-top"><html:span data-box="border" class="layout-editable" title="border-top"></html:span></html:p>
-              <html:p class="layout-border layout-right"><html:span data-box="border" class="layout-editable" title="border-right"></html:span></html:p>
-              <html:p class="layout-border layout-bottom"><html:span data-box="border" class="layout-editable" title="border-bottom"></html:span></html:p>
-              <html:p class="layout-border layout-left"><html:span data-box="border" class="layout-editable" title="border-left"></html:span></html:p>
-
-              <html:p class="layout-margin layout-top"><html:span data-box="margin" class="layout-editable" title="margin-top"></html:span></html:p>
-              <html:p class="layout-margin layout-right"><html:span data-box="margin" class="layout-editable" title="margin-right"></html:span></html:p>
-              <html:p class="layout-margin layout-bottom"><html:span data-box="margin" class="layout-editable" title="margin-bottom"></html:span></html:p>
-              <html:p class="layout-margin layout-left"><html:span data-box="margin" class="layout-editable" title="margin-left"></html:span></html:p>
+              <html:div id="layout-info">
+                <html:span id="layout-element-size"></html:span>
+                <html:section id="layout-position-group">
+                  <html:span id="layout-element-position"></html:span>
+                </html:section>
+              </html:div>
 
-              <html:p class="layout-padding layout-top"><html:span data-box="padding" class="layout-editable" title="padding-top"></html:span></html:p>
-              <html:p class="layout-padding layout-right"><html:span data-box="padding" class="layout-editable" title="padding-right"></html:span></html:p>
-              <html:p class="layout-padding layout-bottom"><html:span data-box="padding" class="layout-editable" title="padding-bottom"></html:span></html:p>
-              <html:p class="layout-padding layout-left"><html:span data-box="padding" class="layout-editable" title="padding-left"></html:span></html:p>
+              <html:div style="display: none">
+                <html:p id="layout-dummy"></html:p>
+              </html:div>
+            </html:div>
+          </html:div>
 
-              <html:p class="layout-size"><html:span data-box="content" title="&content.tooltip;"></html:span></html:p>
-            </html:div>
+          <html:div id="propertyContainer" class="theme-separator" tabindex="0">
+          </html:div>
 
-            <html:div style="display: none">
-              <html:p id="layout-dummy"></html:p>
-            </html:div>
+          <html:div id="computedview-no-results" hidden="">
+            &noPropertiesFound;
           </html:div>
         </html:div>
       </html:div>
 
       <html:div id="sidebar-panel-fontinspector" class="devtools-monospace theme-sidebar inspector-tabpanel">
         <html:div class="devtools-toolbar">
           <html:div class="devtools-searchbox">
             <html:input id="font-preview-text-input"
--- a/devtools/client/inspector/layout/layout.js
+++ b/devtools/client/inspector/layout/layout.js
@@ -63,17 +63,17 @@ EditingSession.prototype = {
    * no style rules affect the property.
    *
    * @param property  The name of the property as a string
    */
   getProperty: function (property) {
     // Create a hidden element for getPropertyFromRule to use
     let div = this._doc.createElement("div");
     div.setAttribute("style", "display: none");
-    this._doc.getElementById("sidebar-panel-layoutview").appendChild(div);
+    this._doc.getElementById("sidebar-panel-computedview").appendChild(div);
     this._element = this._doc.createElement("p");
     div.appendChild(this._element);
 
     // As the rules are in order of priority we can just iterate until we find
     // the first that defines a value for the property and return that.
     for (let rule of this._rules) {
       let value = this.getPropertyFromRule(rule, property);
       if (value !== "") {
@@ -178,43 +178,52 @@ EditingSession.prototype = {
     this._doc = null;
     this._rules = null;
     this._modifications.clear();
   }
 };
 
 /**
  * The layout-view panel
- * @param {InspectorPanel} inspector An instance of the inspector-panel
- * currently loaded in the toolbox
- * @param {Window} win The window containing the panel
+ * @param {InspectorPanel} inspector
+ *        An instance of the inspector-panel currently loaded in the toolbox
+ * @param {Document} document
+ *        The document that will contain the layout view.
  */
-function LayoutView(inspector, win) {
+function LayoutView(inspector, document) {
   this.inspector = inspector;
-  this.doc = win.document;
+  this.doc = document;
+  this.wrapper = this.doc.getElementById("layout-wrapper");
+  this.container = this.doc.getElementById("layout-container");
+  this.expander = this.doc.getElementById("layout-expander");
   this.sizeLabel = this.doc.querySelector(".layout-size > span");
   this.sizeHeadingLabel = this.doc.getElementById("layout-element-size");
   this._geometryEditorHighlighter = null;
 
   this.init();
 }
 
 LayoutView.prototype = {
   init: function () {
     this.update = this.update.bind(this);
 
     this.onNewSelection = this.onNewSelection.bind(this);
     this.inspector.selection.on("new-node-front", this.onNewSelection);
 
     this.onNewNode = this.onNewNode.bind(this);
-    this.inspector.sidebar.on("layoutview-selected", this.onNewNode);
+    this.inspector.sidebar.on("computedview-selected", this.onNewNode);
 
     this.onSidebarSelect = this.onSidebarSelect.bind(this);
     this.inspector.sidebar.on("select", this.onSidebarSelect);
 
+    this.onToggleExpander = this.onToggleExpander.bind(this);
+    this.expander.addEventListener("click", this.onToggleExpander);
+    let header = this.doc.getElementById("layout-header");
+    header.addEventListener("dblclick", this.onToggleExpander);
+
     this.onPickerStarted = this.onPickerStarted.bind(this);
     this.onMarkupViewLeave = this.onMarkupViewLeave.bind(this);
     this.onMarkupViewNodeHover = this.onMarkupViewNodeHover.bind(this);
     this.onWillNavigate = this.onWillNavigate.bind(this);
 
     this.initBoxModelHighlighter();
 
     // Store for the different dimensions of the node.
@@ -308,17 +317,16 @@ LayoutView.prototype = {
     // Mark document as RTL or LTR:
     let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
                     .getService(Ci.nsIXULChromeRegistry);
     let dir = chromeReg.isLocaleRTL("global");
     let container = this.doc.getElementById("layout-container");
     container.setAttribute("dir", dir ? "rtl" : "ltr");
 
     let nodeGeometry = this.doc.getElementById("layout-geometry-editor");
-
     this.onGeometryButtonClick = this.onGeometryButtonClick.bind(this);
     nodeGeometry.addEventListener("click", this.onGeometryButtonClick);
   },
 
   initBoxModelHighlighter: function () {
     let highlightElts = this.doc.querySelectorAll("#layout-container *[title]");
     this.onHighlightMouseOver = this.onHighlightMouseOver.bind(this);
     this.onHighlightMouseOut = this.onHighlightMouseOut.bind(this);
@@ -410,17 +418,17 @@ LayoutView.prototype = {
   },
 
   /**
    * Is the layoutview visible in the sidebar.
    * @return {Boolean}
    */
   isViewVisible: function () {
     return this.inspector &&
-           this.inspector.sidebar.getCurrentTabID() == "layoutview";
+           this.inspector.sidebar.getCurrentTabID() == "computedview";
   },
 
   /**
    * Is the layoutview visible in the sidebar and is the current node valid to
    * be displayed in the view.
    * @return {Boolean}
    */
   isViewVisibleAndNodeValid: function () {
@@ -435,55 +443,62 @@ LayoutView.prototype = {
   destroy: function () {
     let highlightElts = this.doc.querySelectorAll("#layout-container *[title]");
 
     for (let element of highlightElts) {
       element.removeEventListener("mouseover", this.onHighlightMouseOver, true);
       element.removeEventListener("mouseout", this.onHighlightMouseOut, true);
     }
 
+    this.expander.removeEventListener("click", this.onToggleExpander);
+    let header = this.doc.getElementById("layout-header");
+    header.removeEventListener("dblclick", this.onToggleExpander);
+
     let nodeGeometry = this.doc.getElementById("layout-geometry-editor");
     nodeGeometry.removeEventListener("click", this.onGeometryButtonClick);
 
     this.inspector.off("picker-started", this.onPickerStarted);
 
     // Inspector Panel will destroy `markup` object on "will-navigate" event,
     // therefore we have to check if it's still available in case LayoutView
     // is destroyed immediately after.
     if (this.inspector.markup) {
       this.inspector.markup.off("leave", this.onMarkupViewLeave);
       this.inspector.markup.off("node-hover", this.onMarkupViewNodeHover);
     }
 
-    this.inspector.sidebar.off("layoutview-selected", this.onNewNode);
+    this.inspector.sidebar.off("computedview-selected", this.onNewNode);
     this.inspector.selection.off("new-node-front", this.onNewSelection);
     this.inspector.sidebar.off("select", this.onSidebarSelect);
     this.inspector._target.off("will-navigate", this.onWillNavigate);
 
-    this.sizeHeadingLabel = null;
-    this.sizeLabel = null;
     this.inspector = null;
     this.doc = null;
+    this.wrapper = null;
+    this.container = null;
+    this.expander = null;
+    this.sizeLabel = null;
+    this.sizeHeadingLabel = null;
 
     if (this.reflowFront) {
       this.untrackReflows();
       this.reflowFront.destroy();
       this.reflowFront = null;
     }
   },
 
   onSidebarSelect: function (e, sidebar) {
-    this.setActive(sidebar === "layoutview");
+    this.setActive(sidebar === "computedview");
   },
 
   /**
    * Selection 'new-node-front' event handler.
    */
   onNewSelection: function () {
-    let done = this.inspector.updating("layoutview");
+    let done = this.inspector.updating("computed-view");
     this.onNewNode()
       .then(() => this.hideGeometryEditor())
       .then(done, (err) => {
         console.error(err);
         done();
       }).catch(console.error);
   },
 
@@ -521,16 +536,28 @@ LayoutView.prototype = {
       this.showGeometryEditor();
     }
   },
 
   onPickerStarted: function () {
     this.hideGeometryEditor();
   },
 
+  onToggleExpander: function () {
+    let isOpen = this.expander.hasAttribute("open");
+
+    if (isOpen) {
+      this.container.hidden = true;
+      this.expander.removeAttribute("open");
+    } else {
+      this.container.hidden = false;
+      this.expander.setAttribute("open", "");
+    }
+  },
+
   onMarkupViewLeave: function () {
     this.showGeometryEditor(true);
   },
 
   onMarkupViewNodeHover: function () {
     this.hideGeometryEditor(false);
   },
 
@@ -545,34 +572,33 @@ LayoutView.prototype = {
    * @param {Boolean} isActive
    */
   setActive: function (isActive) {
     if (isActive === this.isActive) {
       return;
     }
     this.isActive = isActive;
 
-    let panel = this.doc.getElementById("sidebar-panel-layoutview");
-    panel.classList.toggle("inactive", !isActive);
-
     if (isActive) {
       this.trackReflows();
     } else {
       this.untrackReflows();
     }
   },
 
   /**
    * Compute the dimensions of the node and update the values in
-   * the layoutview/view.xhtml document.
+   * the inspector.xul document.
    * @return a promise that will be resolved when complete.
    */
   update: function () {
     let lastRequest = Task.spawn((function* () {
       if (!this.isViewVisibleAndNodeValid()) {
+        this.wrapper.hidden = true;
+        this.inspector.emit("layoutview-updated");
         return null;
       }
 
       let node = this.inspector.selection.nodeFront;
       let layout = yield this.inspector.pageStyle.getLayout(node, {
         autoMargins: this.isActive
       });
       let styleEntries = yield this.inspector.pageStyle.getApplied(node, {});
@@ -588,22 +614,16 @@ LayoutView.prototype = {
       let width = layout.width;
       let height = layout.height;
       let newLabel = SHARED_L10N.getFormatStr("dimensions", width, height);
 
       if (this.sizeHeadingLabel.textContent != newLabel) {
         this.sizeHeadingLabel.textContent = newLabel;
       }
 
-      // If the view isn't active, no need to do anything more.
-      if (!this.isActive) {
-        this.inspector.emit("layoutview-updated");
-        return null;
-      }
-
       for (let i in this.map) {
         let property = this.map[i].property;
         if (!(property in layout)) {
           // Depending on the actor version, some properties
           // might be missing.
           continue;
         }
         let parsedValue = parseFloat(layout[property]);
@@ -651,18 +671,20 @@ LayoutView.prototype = {
 
       let newValue = width + "\u00D7" + height;
       if (this.sizeLabel.textContent != newValue) {
         this.sizeLabel.textContent = newValue;
       }
 
       this.elementRules = styleEntries.map(e => e.rule);
 
+      this.wrapper.hidden = false;
+
       this.inspector.emit("layoutview-updated");
-      return undefined;
+      return null;
     }).bind(this)).catch(console.error);
 
     this._lastRequest = lastRequest;
     return this._lastRequest;
   },
 
   /**
    * Update the text in the tooltip shown when hovering over a value to provide
--- a/devtools/client/inspector/layout/test/head.js
+++ b/devtools/client/inspector/layout/test/head.js
@@ -50,33 +50,33 @@ function selectAndHighlightNode(nodeOrSe
 
 /**
  * Open the toolbox, with the inspector tool visible, and the layout-view
  * sidebar tab selected.
  * @return a promise that resolves when the inspector is ready and the layout
  * view is visible and ready
  */
 function openLayoutView() {
-  return openInspectorSidebarTab("layoutview").then(data => {
+  return openInspectorSidebarTab("computedview").then(data => {
     // The actual highligher show/hide methods are mocked in layoutview tests.
     // The highlighter is tested in devtools/inspector/test.
     function mockHighlighter({highlighter}) {
       highlighter.showBoxModel = function () {
         return promise.resolve();
       };
       highlighter.hideBoxModel = function () {
         return promise.resolve();
       };
     }
     mockHighlighter(data.toolbox);
 
     return {
       toolbox: data.toolbox,
       inspector: data.inspector,
-      view: data.inspector.layoutview,
+      view: data.inspector.computedview.layoutView,
       testActor: data.testActor
     };
   });
 }
 
 /**
  * Wait for the layoutview-updated event.
  * @return a promise
--- a/devtools/client/inspector/markup/markup.js
+++ b/devtools/client/inspector/markup/markup.js
@@ -48,16 +48,17 @@ const Heritage = require("sdk/core/herit
 const {parseAttribute} =
       require("devtools/client/shared/node-attribute-parser");
 const {Task} = require("devtools/shared/task");
 const {scrollIntoViewIfNeeded} = require("devtools/shared/layout/utils");
 const {PrefObserver} = require("devtools/client/styleeditor/utils");
 const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
 const {template} = require("devtools/shared/gcli/templater");
 const nodeConstants = require("devtools/shared/dom-node-constants");
+const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
 const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
 
 loader.lazyRequireGetter(this, "CSS", "CSS");
 loader.lazyGetter(this, "AutocompletePopup", () => {
   return require("devtools/client/shared/autocomplete-popup").AutocompletePopup;
 });
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
@@ -627,24 +628,24 @@ MarkupView.prototype = {
 
   /**
    * Create a TreeWalker to find the next/previous
    * node for selection.
    */
   _selectionWalker: function (start) {
     let walker = this.doc.createTreeWalker(
       start || this._elt,
-      Ci.nsIDOMNodeFilter.SHOW_ELEMENT,
+      nodeFilterConstants.SHOW_ELEMENT,
       function (element) {
         if (element.container &&
             element.container.elt === element &&
             element.container.visible) {
-          return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
+          return nodeFilterConstants.FILTER_ACCEPT;
         }
-        return Ci.nsIDOMNodeFilter.FILTER_SKIP;
+        return nodeFilterConstants.FILTER_SKIP;
       }
     );
     walker.currentNode = this._selectedContainer.elt;
     return walker;
   },
 
   _onCopy: function (evt) {
     // Ignore copy events from editors
@@ -3188,16 +3189,17 @@ ElementEditor.prototype = {
       attr.remove();
     }
   },
 
   _createAttribute: function (attribute, before = null) {
     // Create the template editor, which will save some variables here.
     let data = {
       attrName: attribute.name,
+      tabindex: this.container.canFocus ? "0" : "-1",
     };
     this.template("attribute", data);
     let {attr, inner, name, val} = data;
 
     // Double quotes need to be handled specially to prevent DOMParser failing.
     // name="v"a"l"u"e" when editing -> name='v"a"l"u"e"'
     // name="v'a"l'u"e" when editing -> name="v'a&quot;l'u&quot;e"
     let editValueDisplayed = attribute.value || "";
--- a/devtools/client/inspector/markup/markup.xhtml
+++ b/devtools/client/inspector/markup/markup.xhtml
@@ -71,17 +71,17 @@
  --></span>
 
     <span id="template-attribute"
           save="${attr}"
           data-attr="${attrName}"
           data-value="${attrValue}"
           class="attreditor"
           style="display:none"> <!--
-   --><span class="editable" save="${inner}" tabindex="-1"><!--
+   --><span class="editable" save="${inner}" tabindex="${tabindex}"><!--
      --><span save="${name}" class="attr-name theme-fg-color2"></span><!--
      -->=&quot;<!--
      --><span save="${val}" class="attr-value theme-fg-color6"></span><!--
      -->&quot;<!--
    --></span><!--
  --></span>
 
     <span id="template-text" save="${elt}" class="editor text"><!--
--- a/devtools/client/inspector/markup/test/browser.ini
+++ b/devtools/client/inspector/markup/test/browser.ini
@@ -29,16 +29,17 @@ support-files =
   doc_markup_toggle.html
   doc_markup_tooltip.png
   doc_markup_void_elements.html
   doc_markup_void_elements.xhtml
   doc_markup_xul.xul
   head.js
   helper_attributes_test_runner.js
   helper_events_test_runner.js
+  helper_markup_accessibility_navigation.js
   helper_outerhtml_test_runner.js
   helper_style_attr_test_runner.js
   lib_jquery_1.0.js
   lib_jquery_1.1.js
   lib_jquery_1.2_min.js
   lib_jquery_1.3_min.js
   lib_jquery_1.4_min.js
   lib_jquery_1.6_min.js
@@ -50,16 +51,18 @@ support-files =
   !/devtools/client/framework/test/shared-head.js
   !/devtools/client/shared/test/test-actor.js
   !/devtools/client/shared/test/test-actor-registry.js
 
 [browser_markup_accessibility_focus_blur.js]
 skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
 [browser_markup_accessibility_navigation.js]
 skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
+[browser_markup_accessibility_navigation_after_edit.js]
+skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
 [browser_markup_accessibility_semantics.js]
 [browser_markup_anonymous_01.js]
 [browser_markup_anonymous_02.js]
 skip-if = e10s # scratchpad.xul is not loading in e10s window
 [browser_markup_anonymous_03.js]
 [browser_markup_anonymous_04.js]
 [browser_markup_copy_image_data.js]
 subsuite = clipboard
@@ -85,16 +88,17 @@ subsuite = clipboard
 [browser_markup_events_jquery_1.3.js]
 [browser_markup_events_jquery_1.4.js]
 [browser_markup_events_jquery_1.6.js]
 [browser_markup_events_jquery_1.7.js]
 [browser_markup_events_jquery_1.11.1.js]
 [browser_markup_events_jquery_2.1.1.js]
 [browser_markup_events-overflow.js]
 skip-if = true # Bug 1177550
+[browser_markup_events-windowed-host.js]
 [browser_markup_links_01.js]
 [browser_markup_links_02.js]
 [browser_markup_links_03.js]
 [browser_markup_links_04.js]
 subsuite = clipboard
 [browser_markup_links_05.js]
 [browser_markup_links_06.js]
 [browser_markup_links_07.js]
--- a/devtools/client/inspector/markup/test/browser_markup_accessibility_navigation.js
+++ b/devtools/client/inspector/markup/test/browser_markup_accessibility_navigation.js
@@ -1,17 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* import-globals-from helper_markup_accessibility_navigation.js */
 
 "use strict";
 
-/* global getContainerForSelector, openInspectorForURL */
+// Test keyboard navigation accessibility of inspector's markup view.
 
-// Test keyboard navigation accessibility of inspector's markup view.
+loadHelperScript("helper_markup_accessibility_navigation.js");
 
 /**
  * Test data has the format of:
  * {
  *   desc              {String}   description for better logging
  *   key               {String}   key event's key
  *   options           {?Object}  optional event data such as shiftKey, etc
  *   focused           {String}   path to expected focused element relative to
@@ -232,70 +233,45 @@ const TESTS = [
     focused: "docBody",
     activedescendant: "body.tagLine",
     key: "VK_UP",
     options: { },
     waitFor: "inspector-updated"
   },
 ];
 
+let containerID = 0;
 let elms = {};
-let containerID = 0;
 
 add_task(function* () {
   let { inspector } = yield openInspectorForURL(`data:text/html;charset=utf-8,
     <h1 id="some-id" class="some-class">foo<span>Child span<span></h1>`);
-  let markup = inspector.markup;
-  let doc = markup.doc;
-  let win = doc.defaultView;
 
   // Record containers that are created after inspector is initialized to be
   // useful in testing.
   inspector.on("container-created", memorizeContainer);
   registerCleanupFunction(() => {
     inspector.off("container-created", memorizeContainer);
   });
 
-  elms.docBody = doc.body;
-  elms.root = markup.getContainer(markup._rootNode);
+  elms.docBody = inspector.markup.doc.body;
+  elms.root = inspector.markup.getContainer(inspector.markup._rootNode);
   elms.header = yield getContainerForSelector("h1", inspector);
   elms.body = yield getContainerForSelector("body", inspector);
 
   // Initial focus is on root element and active descendant should be set on
   // body tag line.
-  testNavigationState(doc, elms.docBody, elms.body.tagLine);
+  testNavigationState(inspector, elms, elms.docBody, elms.body.tagLine);
 
   // Focus on the tree element.
   elms.root.elt.focus();
 
-  for (let {desc, waitFor, focused, activedescendant, key, options} of TESTS) {
-    info(desc);
-    let updated;
-    if (waitFor) {
-      updated = waitFor === "inspector-updated" ?
-        inspector.once(waitFor) : markup.once(waitFor);
-    } else {
-      updated = Promise.resolve();
-    }
+  for (let testData of TESTS) {
+    yield runAccessibilityNavigationTest(inspector, elms, testData);
+  }
 
-    EventUtils.synthesizeKey(key, options, win);
-    yield updated;
-    testNavigationState(doc, getElm(focused), getElm(activedescendant));
-  }
+  elms = null;
 });
 
 // Record all containers that are created dynamically into elms object.
 function memorizeContainer(event, container) {
   elms[`container-${containerID++}`] = container;
 }
-
-// Parse and lookup an element from elms object based on dotted path.
-function getElm(path) {
-  let segments = path.split(".");
-  return segments.reduce((prev, current) => prev[current], elms);
-}
-
-function testNavigationState(doc, focused, activedescendant) {
-  let id = activedescendant.getAttribute("id");
-  is(doc.activeElement, focused, `Keyboard focus should be set to ${focused}`);
-  is(elms.root.elt.getAttribute("aria-activedescendant"), id,
-    `Active descendant should be set to ${id}`);
-}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_accessibility_navigation_after_edit.js
@@ -0,0 +1,126 @@
+/* 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/. */
+/* import-globals-from helper_markup_accessibility_navigation.js */
+
+"use strict";
+
+// Test keyboard navigation accessibility is preserved after editing attributes.
+
+loadHelperScript("helper_markup_accessibility_navigation.js");
+
+const TEST_URI = '<div id="some-id" class="some-class"></div>';
+
+/**
+ * Test data has the format of:
+ * {
+ *   desc              {String}   description for better logging
+ *   key               {String}   key event's key
+ *   options           {?Object}  optional event data such as shiftKey, etc
+ *   focused           {String}   path to expected focused element relative to
+ *                                its container
+ *   activedescendant  {String}   path to expected aria-activedescendant element
+ *                                relative to its container
+ *   waitFor           {String}   optional event to wait for if keyboard actions
+ *                                result in asynchronous updates
+ * }
+ */
+const TESTS = [
+  {
+    desc: "Select header container",
+    focused: "root.elt",
+    activedescendant: "div.tagLine",
+    key: "VK_DOWN",
+    options: { },
+    waitFor: "inspector-updated"
+  },
+  {
+    desc: "Focus on header tag",
+    focused: "div.focusableElms.0",
+    activedescendant: "div.tagLine",
+    key: "VK_RETURN",
+    options: { }
+  },
+  {
+    desc: "Activate header tag editor",
+    focused: "div.editor.tag.inplaceEditor.input",
+    activedescendant: "div.tagLine",
+    key: "VK_RETURN",
+    options: { }
+  },
+  {
+    desc: "Activate header id attribute editor",
+    focused: "div.editor.attrList.children.0.children.1.inplaceEditor.input",
+    activedescendant: "div.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+  {
+    desc: "Deselect text in header id attribute editor",
+    focused: "div.editor.attrList.children.0.children.1.inplaceEditor.input",
+    activedescendant: "div.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+  {
+    desc: "Move the cursor to the left",
+    focused: "div.editor.attrList.children.0.children.1.inplaceEditor.input",
+    activedescendant: "div.tagLine",
+    key: "VK_LEFT",
+    options: { }
+  },
+  {
+    desc: "Modify the attribute",
+    focused: "div.editor.attrList.children.0.children.1.inplaceEditor.input",
+    activedescendant: "div.tagLine",
+    key: "A",
+    options: { }
+  },
+  {
+    desc: "Commit the attribute change",
+    focused: "div.focusableElms.1",
+    activedescendant: "div.tagLine",
+    key: "VK_RETURN",
+    options: { },
+    waitFor: "inspector-updated"
+  },
+  {
+    desc: "Tab and focus on header class attribute",
+    focused: "div.focusableElms.2",
+    activedescendant: "div.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+  {
+    desc: "Tab and focus on header new attribute node",
+    focused: "div.focusableElms.3",
+    activedescendant: "div.tagLine",
+    key: "VK_TAB",
+    options: { }
+  },
+];
+
+let elms = {};
+
+add_task(function* () {
+  let url = `data:text/html;charset=utf-8,${TEST_URI}`;
+  let { inspector } = yield openInspectorForURL(url);
+
+  elms.docBody = inspector.markup.doc.body;
+  elms.root = inspector.markup.getContainer(inspector.markup._rootNode);
+  elms.div = yield getContainerForSelector("div", inspector);
+  elms.body = yield getContainerForSelector("body", inspector);
+
+  // Initial focus is on root element and active descendant should be set on
+  // body tag line.
+  testNavigationState(inspector, elms, elms.docBody, elms.body.tagLine);
+
+  // Focus on the tree element.
+  elms.root.elt.focus();
+
+  for (let testData of TESTS) {
+    yield runAccessibilityNavigationTest(inspector, elms, testData);
+  }
+
+  elms = null;
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/browser_markup_events-windowed-host.js
@@ -0,0 +1,61 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/*
+ * Test that the event details tooltip can be hidden by clicking outside of the tooltip
+ * after switching hosts.
+ */
+
+const TEST_URL = URL_ROOT + "doc_markup_events-overflow.html";
+
+registerCleanupFunction(() => {
+  // Restore the default Toolbox host position after the test.
+  Services.prefs.clearUserPref("devtools.toolbox.host");
+});
+
+add_task(function* () {
+  let { inspector, toolbox } = yield openInspectorForURL(TEST_URL);
+  yield runTests(inspector);
+
+  yield toolbox.switchHost("window");
+  yield runTests(inspector);
+
+  yield toolbox.switchHost("bottom");
+  yield runTests(inspector);
+
+  yield toolbox.destroy();
+});
+
+function* runTests(inspector) {
+  let markupContainer = yield getContainerForSelector("#events", inspector);
+  let evHolder = markupContainer.elt.querySelector(".markupview-events");
+  let tooltip = inspector.markup.eventDetailsTooltip;
+
+  info("Clicking to open event tooltip.");
+
+  let onInspectorUpdated = inspector.once("inspector-updated");
+  let onTooltipShown = tooltip.once("shown");
+  EventUtils.synthesizeMouseAtCenter(evHolder, {}, inspector.markup.doc.defaultView);
+
+  yield onTooltipShown;
+  // New node is selected when clicking on the events bubble, wait for inspector-updated.
+  yield onInspectorUpdated;
+
+  ok(tooltip.isVisible(), "EventTooltip visible.");
+
+  onInspectorUpdated = inspector.once("inspector-updated");
+  let onTooltipHidden = tooltip.once("hidden");
+
+  info("Click on another tag to hide the event tooltip");
+  let h1 = yield getContainerForSelector("h1", inspector);
+  let tag = h1.elt.querySelector(".tag");
+  EventUtils.synthesizeMouseAtCenter(tag, {}, inspector.markup.doc.defaultView);
+
+  yield onTooltipHidden;
+  // New node is selected, wait for inspector-updated.
+  yield onInspectorUpdated;
+
+  ok(!tooltip.isVisible(), "EventTooltip hidden.");
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/markup/test/helper_markup_accessibility_navigation.js
@@ -0,0 +1,70 @@
+/* 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/. */
+/* eslint no-unused-vars: [2, {"vars": "local"}] */
+/* import-globals-from head.js */
+"use strict";
+
+/**
+ * Execute a keyboard event and check that the state is as expected (focused element, aria
+ * attribute etc...).
+ *
+ * @param {InspectorPanel} inspector
+ *        Current instance of the inspector being tested.
+ * @param {Object} elms
+ *        Map of elements that will be used to retrieve live references to children
+ *        elements
+ * @param {Element} focused
+ *        Element expected to be focused
+ * @param {Element} activedescendant
+ *        Element expected to be the aria activedescendant of the root node
+ */
+function testNavigationState(inspector, elms, focused, activedescendant) {
+  let doc = inspector.markup.doc;
+  let id = activedescendant.getAttribute("id");
+  is(doc.activeElement, focused, `Keyboard focus should be set to ${focused}`);
+  is(elms.root.elt.getAttribute("aria-activedescendant"), id,
+    `Active descendant should be set to ${id}`);
+}
+
+/**
+ * Execute a keyboard event and check that the state is as expected (focused element, aria
+ * attribute etc...).
+ *
+ * @param {InspectorPanel} inspector
+ *        Current instance of the inspector being tested.
+ * @param {Object} elms
+ *        MarkupContainers/Elements that will be used to retrieve references to other
+ *        elements based on objects' paths.
+ * @param {Object} testData
+ *        - {String} desc: description for better logging.
+ *        - {String} key: keyboard event's key.
+ *        - {Object} options, optional: event data such as shiftKey, etc.
+ *        - {String} focused: path to expected focused element in elms map.
+ *        - {String} activedescendant: path to expected aria-activedescendant element in
+ *          elms map.
+ *        - {String} waitFor, optional: markupview event to wait for if keyboard actions
+ *          result in async updates. Also accepts the inspector event "inspector-updated".
+ */
+function* runAccessibilityNavigationTest(inspector, elms,
+  {desc, key, options, focused, activedescendant, waitFor}) {
+  info(desc);
+
+  let markup = inspector.markup;
+  let doc = markup.doc;
+  let win = doc.defaultView;
+
+  let updated;
+  if (waitFor) {
+    updated = waitFor === "inspector-updated" ?
+      inspector.once(waitFor) : markup.once(waitFor);
+  } else {
+    updated = Promise.resolve();
+  }
+  EventUtils.synthesizeKey(key, options, win);
+  yield updated;
+
+  let focusedElement = lookupPath(elms, focused);
+  let activeDescendantElement = lookupPath(elms, activedescendant);
+  testNavigationState(inspector, elms, focusedElement, activeDescendantElement);
+}
--- a/devtools/client/inspector/rules/models/rule.js
+++ b/devtools/client/inspector/rules/models/rule.js
@@ -1,29 +1,25 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const {Cc, Ci} = require("chrome");
+const {Ci} = require("chrome");
 const promise = require("promise");
 const CssLogic = require("devtools/shared/inspector/css-logic");
 const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
 const {TextProperty} =
       require("devtools/client/inspector/rules/models/text-property");
 const {promiseWarn} = require("devtools/client/inspector/shared/utils");
 const {parseDeclarations} = require("devtools/shared/css-parsing-utils");
-const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "osString", function () {
-  return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
-});
+const Services = require("Services");
 
 /**
  * Rule is responsible for the following:
  *   Manages a single style declaration or rule.
  *   Applies changes to the properties in a rule.
  *   Maintains a list of TextProperty objects.
  *
  * @param {ElementStyle} elementStyle
@@ -655,17 +651,17 @@ Rule.prototype = {
   },
 
   /**
    * Return a string representation of the rule.
    */
   stringifyRule: function () {
     let selectorText = this.selectorText;
     let cssText = "";
-    let terminator = osString === "WINNT" ? "\r\n" : "\n";
+    let terminator = Services.appinfo.OS === "WINNT" ? "\r\n" : "\n";
 
     for (let textProp of this.textProps) {
       if (!textProp.invisible) {
         cssText += "\t" + textProp.stringifyProperty() + terminator;
       }
     }
 
     return selectorText + " {" + terminator + cssText + "}";
--- a/devtools/client/inspector/rules/test/browser_rules_copy_styles.js
+++ b/devtools/client/inspector/rules/test/browser_rules_copy_styles.js
@@ -4,19 +4,17 @@
 
 "use strict";
 
 /**
  * Tests the behaviour of the copy styles context menu items in the rule
  * view.
  */
 
-XPCOMUtils.defineLazyGetter(this, "osString", function () {
-  return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
-});
+const osString = Services.appinfo.OS;
 
 const TEST_URI = URL_ROOT + "doc_copystyles.html";
 
 add_task(function* () {
   yield addTab(TEST_URI);
   let { inspector, view } = yield openRuleView();
   yield selectNode("#testid", inspector);
 
--- a/devtools/client/inspector/rules/test/browser_rules_select-and-copy-styles.js
+++ b/devtools/client/inspector/rules/test/browser_rules_select-and-copy-styles.js
@@ -1,19 +1,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Tests that properties can be selected and copied from the rule view
 
-XPCOMUtils.defineLazyGetter(this, "osString", function () {
-  return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
-});
+const osString = Services.appinfo.OS;
 
 const TEST_URI = `
   <style type="text/css">
     html {
       color: #000000;
     }
     span {
       font-variant: small-caps; color: #000000;
--- a/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js
+++ b/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js
@@ -111,18 +111,18 @@ function* userAgentStylesVisible(inspect
   }
 
   ok(userRules.some(rule => rule.matchedSelectors.length === 1),
     "There is an inline style for element in user styles");
 
   // These tests rely on the "a" selector being the last test in
   // TEST_DATA.
   ok(uaRules.some(rule => {
-    return rule.matchedSelectors.indexOf(":-moz-any-link") !== -1;
-  }), "There is a rule for :-moz-any-link");
+    return rule.matchedSelectors.indexOf(":any-link") !== -1;
+  }), "There is a rule for :any-link");
   ok(uaRules.some(rule => {
     return rule.matchedSelectors.indexOf("*|*:link") !== -1;
   }), "There is a rule for *|*:link");
   ok(uaRules.some(rule => {
     return rule.matchedSelectors.length === 1;
   }), "Inline styles for ua styles");
 }
 
--- a/devtools/client/inspector/shared/test/browser_styleinspector_context-menu-copy-color_01.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_context-menu-copy-color_01.js
@@ -19,17 +19,17 @@ add_task(function* () {
   yield testView("ruleview", inspector);
   yield testView("computedview", inspector);
 });
 
 function* testView(viewId, inspector) {
   info("Testing " + viewId);
 
   yield inspector.sidebar.select(viewId);
-  let view = inspector[viewId].view;
+  let view = inspector[viewId].view || inspector[viewId].computedView;
   yield selectNode("div", inspector);
 
   testIsColorValueNode(view);
   testIsColorPopupOnAllNodes(view);
   yield clearCurrentNodeSelection(inspector);
 }
 
 /**
--- a/devtools/client/inspector/shared/test/browser_styleinspector_refresh_when_active.js
+++ b/devtools/client/inspector/shared/test/browser_styleinspector_refresh_when_active.js
@@ -15,17 +15,17 @@ add_task(function* () {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   let {inspector, view} = yield openRuleView();
 
   yield selectNode("#one", inspector);
 
   is(getRuleViewPropertyValue(view, "element", "color"), "red",
     "The rule-view shows the properties for test node one");
 
-  let cView = inspector.computedview.view;
+  let cView = inspector.computedview.computedView;
   let prop = getComputedViewProperty(cView, "color");
   ok(!prop, "The computed-view doesn't show the properties for test node one");
 
   info("Switching to the computed-view");
   let onComputedViewReady = inspector.once("computed-view-refreshed");
   selectComputedView(inspector);
   yield onComputedViewReady;
 
--- a/devtools/client/inspector/test/head.js
+++ b/devtools/client/inspector/test/head.js
@@ -292,17 +292,17 @@ function openRuleView() {
  * view is visible and ready
  */
 function openComputedView() {
   return openInspectorSidebarTab("computedview").then(data => {
     return {
       toolbox: data.toolbox,
       inspector: data.inspector,
       testActor: data.testActor,
-      view: data.inspector.computedview.view
+      view: data.inspector.computedview.computedView
     };
   });
 }
 
 /**
  * Select the rule view sidebar tab on an already opened inspector panel.
  *
  * @param {InspectorPanel} inspector
@@ -318,17 +318,17 @@ function selectRuleView(inspector) {
  * Select the computed view sidebar tab on an already opened inspector panel.
  *
  * @param {InspectorPanel} inspector
  *        The opened inspector panel
  * @return {CssComputedView} the computed view
  */
 function selectComputedView(inspector) {
   inspector.sidebar.select("computedview");
-  return inspector.computedview.view;
+  return inspector.computedview.computedView;
 }
 
 /**
  * Get the NodeFront for a node that matches a given css selector, via the
  * protocol.
  * @param {String|NodeFront} selector
  * @param {InspectorPanel} inspector The instance of InspectorPanel currently
  * loaded in the toolbox
--- a/devtools/client/locales/en-US/layoutview.dtd
+++ b/devtools/client/locales/en-US/layoutview.dtd
@@ -11,16 +11,17 @@
   - You want to make that choice consistent across the developer tools.
   - A good criteria is the language in which you'd find the best
   - documentation on web development on the web. -->
 
 <!-- LOCALIZATION NOTE (*.tooltip): These tooltips are not regular tooltips.
   -  The text appears on the bottom right corner of the layout view when
   -  the corresponding box is hovered. -->
 
+<!ENTITY layoutViewTitle          "Box Model">
 <!ENTITY margin.tooltip           "margin">
 <!ENTITY border.tooltip           "border">
 <!ENTITY padding.tooltip          "padding">
 <!ENTITY content.tooltip          "content">
 
 <!-- LOCALIZATION NOTE: This label is displayed as a tooltip that appears when
   -  hovering over the button that allows users to edit the position of an
   -  element in the page. -->
--- a/devtools/client/netmonitor/har/har-builder.js
+++ b/devtools/client/netmonitor/har/har-builder.js
@@ -1,23 +1,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/. */
 "use strict";
 
-const { Ci, Cc } = require("chrome");
 const { defer, all } = require("promise");
 const { LocalizationHelper } = require("devtools/client/shared/l10n");
+const Services = require("Services");
+const appInfo = Services.appinfo;
 
 loader.lazyRequireGetter(this, "NetworkHelper", "devtools/shared/webconsole/network-helper");
 
-loader.lazyGetter(this, "appInfo", () => {
-  return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
-});
-
 loader.lazyGetter(this, "L10N", () => {
   return new LocalizationHelper("chrome://devtools/locale/har.properties");
 });
 
 const HAR_VERSION = "1.1";
 
 /**
  * This object is responsible for building HAR file. See HAR spec:
--- a/devtools/client/performance/test/browser.ini
+++ b/devtools/client/performance/test/browser.ini
@@ -97,16 +97,17 @@ support-files =
 [browser_perf-telemetry-02.js]
 [browser_perf-telemetry-03.js]
 [browser_perf-telemetry-04.js]
 # [browser_perf-theme-toggle.js] TODO bug 1256350
 [browser_perf-tree-abstract-01.js]
 [browser_perf-tree-abstract-02.js]
 [browser_perf-tree-abstract-03.js]
 [browser_perf-tree-abstract-04.js]
+[browser_perf-tree-abstract-05.js]
 [browser_perf-tree-view-01.js]
 [browser_perf-tree-view-02.js]
 [browser_perf-tree-view-03.js]
 [browser_perf-tree-view-04.js]
 [browser_perf-tree-view-05.js]
 [browser_perf-tree-view-06.js]
 [browser_perf-tree-view-07.js]
 [browser_perf-tree-view-08.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/performance/test/browser_perf-tree-abstract-05.js
@@ -0,0 +1,104 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/**
+ * Tests if the abstract tree base class for the profiler's tree view
+ * supports PageUp/PageDown/Home/End keys.
+ */
+
+const { appendAndWaitForPaint } = require("devtools/client/performance/test/helpers/dom-utils");
+const { synthesizeCustomTreeClass } = require("devtools/client/performance/test/helpers/synth-utils");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function* () {
+  let { MyCustomTreeItem } = synthesizeCustomTreeClass();
+
+  let container = document.createElement("vbox");
+  container.style.height = '100%';
+  container.style.overflow = 'scroll';
+  yield appendAndWaitForPaint(gBrowser.selectedBrowser.parentNode, container);
+
+  let myDataSrc = {
+    label: "root",
+    children: []
+  };
+
+  for (let i = 0; i < 1000; i++) {
+    myDataSrc.children.push({
+      label: "child-" + i,
+      children: []
+    });
+  }
+
+  let treeRoot = new MyCustomTreeItem(myDataSrc, { parent: null });
+  treeRoot.attachTo(container);
+  treeRoot.focus();
+  treeRoot.expand();
+
+  is(document.commandDispatcher.focusedElement, treeRoot.target,
+    "The root node is focused.");
+
+  // Test HOME and END
+
+  key("VK_END");
+  is(document.commandDispatcher.focusedElement,
+    treeRoot.getChild(myDataSrc.children.length - 1).target,
+    "The last node is focused.");
+
+  key("VK_HOME");
+  is(document.commandDispatcher.focusedElement, treeRoot.target,
+    "The first (root) node is focused.");
+
+  // Test PageUp and PageDown
+
+  let nodesPerPageSize = treeRoot._getNodesPerPageSize();
+
+  key("VK_PAGE_DOWN");
+  is(document.commandDispatcher.focusedElement,
+    treeRoot.getChild(nodesPerPageSize - 1).target,
+    "The first node in the second page is focused.");
+
+  key("VK_PAGE_DOWN");
+  is(document.commandDispatcher.focusedElement,
+    treeRoot.getChild(nodesPerPageSize * 2 - 1).target,
+    "The first node in the third page is focused.");
+
+  key("VK_PAGE_UP");
+  is(document.commandDispatcher.focusedElement,
+    treeRoot.getChild(nodesPerPageSize - 1).target,
+    "The first node in the second page is focused.");
+
+  key("VK_PAGE_UP");
+  is(document.commandDispatcher.focusedElement, treeRoot.target,
+    "The first (root) node is focused.");
+
+  // Test PageUp in the middle of the first page
+
+  let middleIndex = Math.floor(nodesPerPageSize / 2);
+
+  treeRoot.getChild(middleIndex).target.focus();
+  is(document.commandDispatcher.focusedElement,
+    treeRoot.getChild(middleIndex).target,
+    "The middle node in the first page is focused.");
+
+  key("VK_PAGE_UP");
+  is(document.commandDispatcher.focusedElement, treeRoot.target,
+    "The first (root) node is focused.");
+
+  // Test PageDown in the middle of the last page
+
+  middleIndex = Math.ceil(myDataSrc.children.length - middleIndex);
+
+  treeRoot.getChild(middleIndex).target.focus();
+  is(document.commandDispatcher.focusedElement,
+    treeRoot.getChild(middleIndex).target,
+    "The middle node in the last page is focused.");
+
+  key("VK_PAGE_DOWN");
+  is(document.commandDispatcher.focusedElement,
+    treeRoot.getChild(myDataSrc.children.length - 1).target,
+    "The last node is focused.");
+
+  container.remove();
+});
--- a/devtools/client/responsive.html/components/device-modal.js
+++ b/devtools/client/responsive.html/components/device-modal.js
@@ -1,12 +1,14 @@
 /* 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/. */
 
+/* eslint-env browser */
+
 "use strict";
 
 const { DOM: dom, createClass, PropTypes, addons } =
   require("devtools/client/shared/vendor/react");
 const { getStr } = require("../utils/l10n");
 const Types = require("../types");
 
 module.exports = createClass({
@@ -20,30 +22,38 @@ module.exports = createClass({
   },
 
   mixins: [ addons.PureRenderMixin ],
 
   getInitialState() {
     return {};
   },
 
+  componentDidMount() {
+    window.addEventListener("keydown", this.onKeyDown, true);
+  },
+
   componentWillReceiveProps(nextProps) {
     let {
       devices,
     } = nextProps;
 
     for (let type of devices.types) {
       for (let device of devices[type]) {
         this.setState({
           [device.name]: device.displayed,
         });
       }
     }
   },
 
+  componentWillUnmount() {
+    window.removeEventListener("keydown", this.onKeyDown, true);
+  },
+
   onDeviceCheckboxClick({ target }) {
     this.setState({
       [target.value]: !this.state[target.value]
     });
   },
 
   onDeviceModalSubmit() {
     let {
@@ -73,80 +83,99 @@ module.exports = createClass({
         }
       }
     }
 
     onDeviceListUpdate(preferredDevices);
     onUpdateDeviceModalOpen(false);
   },
 
+  onKeyDown(event) {
+    if (!this.props.devices.isModalOpen) {
+      return;
+    }
+    // Escape keycode
+    if (event.keyCode === 27) {
+      let {
+        onUpdateDeviceModalOpen
+      } = this.props;
+      onUpdateDeviceModalOpen(false);
+    }
+  },
+
   render() {
     let {
       devices,
       onUpdateDeviceModalOpen,
     } = this.props;
 
-    let modalClass = "device-modal container";
-
-    if (!devices.isModalOpen) {
-      modalClass += " hidden";
-    }
-
     const sortedDevices = {};
     for (let type of devices.types) {
       sortedDevices[type] = Object.assign([], devices[type])
         .sort((a, b) => a.name.localeCompare(b.name));
     }
 
     return dom.div(
       {
-        className: modalClass,
+        id: "device-modal-wrapper",
+        className: this.props.devices.isModalOpen ? "opened" : "closed",
       },
-      dom.button({
-        id: "device-close-button",
-        className: "toolbar-button devtools-button",
-        onClick: () => onUpdateDeviceModalOpen(false),
-      }),
       dom.div(
         {
-          className: "device-modal-content",
+          className: "device-modal container",
         },
-        devices.types.map(type => {
-          return dom.div(
-            {
-              className: "device-type",
-              key: type,
-            },
-            dom.header(
+        dom.button({
+          id: "device-close-button",
+          className: "toolbar-button devtools-button",
+          onClick: () => onUpdateDeviceModalOpen(false),
+        }),
+        dom.div(
+          {
+            className: "device-modal-content",
+          },
+          devices.types.map(type => {
+            return dom.div(
               {
-                className: "device-header",
+                className: "device-type",
+                key: type,
               },
-              type
-            ),
-            sortedDevices[type].map(device => {
-              return dom.label(
+              dom.header(
                 {
-                  className: "device-label",
-                  key: device.name,
+                  className: "device-header",
                 },
-                dom.input({
-                  className: "device-input-checkbox",
-                  type: "checkbox",
-                  value: device.name,
-                  checked: this.state[device.name],
-                  onChange: this.onDeviceCheckboxClick,
-                }),
-                device.name
-              );
-            })
-          );
-        })
+                type
+              ),
+              sortedDevices[type].map(device => {
+                return dom.label(
+                  {
+                    className: "device-label",
+                    key: device.name,
+                  },
+                  dom.input({
+                    className: "device-input-checkbox",
+                    type: "checkbox",
+                    value: device.name,
+                    checked: this.state[device.name],
+                    onChange: this.onDeviceCheckboxClick,
+                  }),
+                  device.name
+                );
+              })
+            );
+          })
+        ),
+        dom.button(
+          {
+            id: "device-submit-button",
+            onClick: this.onDeviceModalSubmit,
+          },
+          getStr("responsive.done")
+        )
       ),
-      dom.button(
+      dom.div(
         {
-          id: "device-submit-button",
-          onClick: this.onDeviceModalSubmit,
-        },
-        getStr("responsive.done")
+          className: "modal-overlay",
+          onClick: () => onUpdateDeviceModalOpen(false),
+        }
       )
     );
   },
 });
--- a/devtools/client/responsive.html/index.css
+++ b/devtools/client/responsive.html/index.css
@@ -34,30 +34,29 @@
 }
 
 * {
   box-sizing: border-box;
 }
 
 #root,
 html, body {
+  height: 100%;
   margin: 0;
 }
 
 #app {
   /* Center the viewports container */
   display: flex;
   align-items: center;
   flex-direction: column;
-  height: 100vh;
-
-  /* Snap to the top of the app when there isn't enough vertical space anymore
-     to center the viewports (so we don't lose the global toolbar) */
-  position: sticky;
-  top: 0;
+  padding-top: 15px;
+  padding-bottom: 1%;
+  position: relative;
+  height: 100%;
 }
 
 /**
  * Common style for containers and toolbar buttons
  */
 
 .container {
   background-color: var(--theme-toolbar-background);
@@ -81,17 +80,17 @@ html, body {
 /**
  * Global Toolbar
  */
 
 #global-toolbar {
   color: var(--theme-body-color-alt);
   border-radius: 2px;
   box-shadow: var(--rdm-box-shadow);
-  margin: 10% 0 30px 0;
+  margin: 0 0 15px 0;
   padding: 4px 5px;
   display: inline-flex;
   -moz-user-select: none;
 }
 
 #global-toolbar > .title {
   border-right: 1px solid var(--theme-splitter-color);
   padding: 1px 6px 0 2px;
@@ -331,31 +330,76 @@ html, body {
 .viewport-dimension-separator {
   -moz-user-select: none;
 }
 
 /**
  * Device Modal
  */
 
+@keyframes fade-in-and-up {
+  0% {
+    opacity: 0;
+    transform: translateY(5px);
+  }
+  100% {
+    opacity: 1;
+    transform: translateY(0px);
+  }
+}
+
+@keyframes fade-down-and-out {
+  0% {
+    opacity: 1;
+    transform: translateY(0px);
+  }
+  100% {
+    opacity: 0;
+    transform: translateY(5px);
+    visibility: hidden;
+  }
+}
+
 .device-modal {
   border-radius: 2px;
   box-shadow: var(--rdm-box-shadow);
+  display: none;
   position: absolute;
   margin: auto;
   top: 0;
   bottom: 0;
   left: 0;
   right: 0;
   width: 642px;
   height: 612px;
+  z-index: 1;
+}
+
+/* Handles the opening/closing of the modal */
+#device-modal-wrapper.opened .device-modal {
+  animation: fade-in-and-up 0.3s ease;
+  animation-fill-mode: forwards;
+  display: block;
 }
 
-.device-modal.hidden {
-  display: none;
+#device-modal-wrapper.closed .device-modal {
+  animation: fade-down-and-out 0.3s ease;
+  animation-fill-mode: forwards;
+  display: block;
+}
+
+#device-modal-wrapper.opened .modal-overlay {
+  background-color: var(--theme-splitter-color);
+  position: absolute;
+  top: 0;
+  left: 0;
+  height: 100%;
+  width: 100%;
+  z-index: 0;
+  opacity: 0.5;
 }
 
 .device-modal-content {
   display: flex;
   flex-direction: column;
   flex-wrap: wrap;
   overflow: auto;
   height: 550px;
--- a/devtools/client/responsive.html/test/browser/browser_device_modal_exit.js
+++ b/devtools/client/responsive.html/test/browser/browser_device_modal_exit.js
@@ -5,17 +5,17 @@ http://creativecommons.org/publicdomain/
 
 // Test submitting display device changes on the device modal
 
 const TEST_URL = "data:text/html;charset=utf-8,";
 const Types = require("devtools/client/responsive.html/types");
 
 addRDMTask(TEST_URL, function* ({ ui }) {
   let { store, document } = ui.toolWindow;
-  let modal = document.querySelector(".device-modal");
+  let modal = document.querySelector("#device-modal-wrapper");
   let closeButton = document.querySelector("#device-close-button");
 
   // Wait until the viewport has been added and the device list has been loaded
   yield waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   openDeviceModal(ui);
 
@@ -23,18 +23,18 @@ addRDMTask(TEST_URL, function* ({ ui }) 
 
   info("Check the first unchecked device and exit the modal.");
   let uncheckedCb = [...document.querySelectorAll(".device-input-checkbox")]
     .filter(cb => !cb.checked)[0];
   let value = uncheckedCb.value;
   uncheckedCb.click();
   closeButton.click();
 
-  ok(modal.classList.contains("hidden"),
-    "The device modal is hidden on exit.");
+  ok(modal.classList.contains("closed") && !modal.classList.contains("opened"),
+    "The device modal is closed on exit.");
 
   info("Check that the device list remains unchanged after exitting.");
   let preferredDevicesAfter = _loadPreferredDevices();
 
   is(preferredDevicesBefore.added.size, preferredDevicesAfter.added.size,
     "Got expected number of added devices.");
 
   is(preferredDevicesBefore.removed.size, preferredDevicesAfter.removed.size,
--- a/devtools/client/responsive.html/test/browser/browser_device_modal_submit.js
+++ b/devtools/client/responsive.html/test/browser/browser_device_modal_submit.js
@@ -18,17 +18,17 @@ const addedDevice = {
   "featured": true,
 };
 
 const TEST_URL = "data:text/html;charset=utf-8,";
 const Types = require("devtools/client/responsive.html/types");
 
 addRDMTask(TEST_URL, function* ({ ui }) {
   let { store, document } = ui.toolWindow;
-  let modal = document.querySelector(".device-modal");
+  let modal = document.querySelector("#device-modal-wrapper");
   let select = document.querySelector(".viewport-device-selector");
   let submitButton = document.querySelector("#device-submit-button");
 
   // Wait until the viewport has been added and the device list has been loaded
   yield waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   openDeviceModal(ui);
@@ -56,18 +56,18 @@ addRDMTask(TEST_URL, function* ({ ui }) 
   // Tests where the user adds a non-featured device
   info("Check the first unchecked device and submit new device list.");
   let uncheckedCb = [...document.querySelectorAll(".device-input-checkbox")]
     .filter(cb => !cb.checked)[0];
   let value = uncheckedCb.value;
   uncheckedCb.click();
   submitButton.click();
 
-  ok(modal.classList.contains("hidden"),
-    "The device modal is hidden on submit.");
+  ok(modal.classList.contains("closed") && !modal.classList.contains("opened"),
+    "The device modal is closed on submit.");
 
   info("Checking that the new device is added to the user preference list.");
   let preferredDevices = _loadPreferredDevices();
   ok(preferredDevices.added.has(value), value + " in user added list.");
 
   info("Checking new device is added to the device selector.");
   let options = [...select.options];
   is(options.length - 2, featuredCount + 1,
--- a/devtools/client/responsive.html/test/browser/head.js
+++ b/devtools/client/responsive.html/test/browser/head.js
@@ -130,32 +130,32 @@ var setViewportSize = Task.async(functio
     ui.setViewportSize(width, height);
     yield resized;
   }
 });
 
 function openDeviceModal(ui) {
   let { document } = ui.toolWindow;
   let select = document.querySelector(".viewport-device-selector");
-  let modal = document.querySelector(".device-modal");
+  let modal = document.querySelector("#device-modal-wrapper");
   let editDeviceOption = [...select.options].filter(o => {
     return o.value === OPEN_DEVICE_MODAL_VALUE;
   })[0];
 
   info("Checking initial device modal state");
-  ok(modal.classList.contains("hidden"),
-    "The device modal is hidden by default.");
+  ok(modal.classList.contains("closed") && !modal.classList.contains("opened"),
+    "The device modal is closed by default.");
 
   info("Opening device modal through device selector.");
   EventUtils.synthesizeMouseAtCenter(select, {type: "mousedown"},
     ui.toolWindow);
   EventUtils.synthesizeMouseAtCenter(editDeviceOption, {type: "mouseup"},
     ui.toolWindow);
 
-  ok(!modal.classList.contains("hidden"),
+  ok(modal.classList.contains("opened") && !modal.classList.contains("closed"),
     "The device modal is displayed.");
 }
 
 function getSessionHistory(browser) {
   return ContentTask.spawn(browser, {}, function* () {
     /* eslint-disable no-undef */
     let { interfaces: Ci } = Components;
     let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
--- a/devtools/client/responsivedesign/test/head.js
+++ b/devtools/client/responsivedesign/test/head.js
@@ -142,17 +142,17 @@ var openInspectorSideBar = Task.async(fu
   let {toolbox, inspector} = yield openInspector();
 
   info("Selecting the " + id + " sidebar");
   inspector.sidebar.select(id);
 
   return {
     toolbox: toolbox,
     inspector: inspector,
-    view: inspector[id].view
+    view: inspector[id].view || inspector[id].computedView
   };
 });
 
 /**
  * Checks whether the inspector's sidebar corresponding to the given id already
  * exists
  * @param {InspectorPanel}
  * @param {String}
--- a/devtools/client/shared/DOMHelpers.jsm
+++ b/devtools/client/shared/DOMHelpers.jsm
@@ -2,16 +2,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/. */
 
 "use strict";
 
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
+const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
+const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
 
 this.EXPORTED_SYMBOLS = ["DOMHelpers"];
 
 /**
  * DOMHelpers
  * Makes DOM traversal easier. Goes through iframes.
  *
  * @constructor
@@ -98,17 +100,17 @@ DOMHelpers.prototype = {
         return child;
     }
 
     return null;  // we have no children worth showing.
   },
 
   getFirstChild: function Helpers_getFirstChild(node)
   {
-    let SHOW_ALL = Components.interfaces.nsIDOMNodeFilter.SHOW_ALL;
+    let SHOW_ALL = nodeFilterConstants.SHOW_ALL;
     this.treeWalker = node.ownerDocument.createTreeWalker(node,
       SHOW_ALL, null);
     return this.treeWalker.firstChild();
   },
 
   getNextSibling: function Helpers_getNextSibling(node)
   {
     let next = this.treeWalker.nextSibling();
--- a/devtools/client/shared/components/reps/array.js
+++ b/devtools/client/shared/components/reps/array.js
@@ -55,17 +55,17 @@ define(function (require, exports, modul
           items.push(ItemRep({
             object: exc,
             delim: delim,
             key: i
           }));
         }
       }
 
-      if (array.length > max + 1) {
+      if (array.length > max) {
         items.pop();
 
         let objectLink = this.props.objectLink || DOM.span;
         items.push(Caption({
           key: "more",
           object: objectLink({
             object: this.props.object
           }, "more…")
--- a/devtools/client/shared/components/reps/grip-array.js
+++ b/devtools/client/shared/components/reps/grip-array.js
@@ -82,17 +82,17 @@ define(function (require, exports, modul
           items.push(GripArrayItem(Object.assign({}, this.props, {
             object: exc,
             delim: delim,
             key: i}
           )));
         }
       }
 
-      if (array.length > max + 1) {
+      if (array.length > max) {
         items.pop();
         let objectLink = this.props.objectLink || span;
         items.push(Caption({
           key: "more",
           object: objectLink({
             object: this.props.object
           }, "more…")
         }));
--- a/devtools/client/shared/components/test/mochitest/test_reps_array.html
+++ b/devtools/client/shared/components/test/mochitest/test_reps_array.html
@@ -14,23 +14,28 @@ Test ArrayRep rep
 <pre id="test">
 <script src="head.js" type="application/javascript;version=1.8"></script>
 <script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
   let { ArrayRep } = browserRequire("devtools/client/shared/components/reps/array");
 
   let componentUnderTest = ArrayRep;
+  const maxLength = {
+    short: 3,
+    long: 300
+  };
 
   try {
     yield testBasic();
 
     // Test property iterator
     yield testMaxProps();
-    yield testMoreThanMaxProps();
+    yield testMoreThanShortMaxProps();
+    yield testMoreThanLongMaxProps();
     yield testRecursiveArray();
 
     // Test that properties are rendered as expected by ItemRep
     yield testNested();
   } catch(e) {
     ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
   } finally {
     SimpleTest.finish();
@@ -88,36 +93,63 @@ window.onload = Task.async(function* () 
         mode: "long",
         expectedOutput: defaultOutput,
       }
     ];
 
     testRepRenderModes(modeTests, "testMaxProps", componentUnderTest, stub);
   }
 
-  function testMoreThanMaxProps() {
-    const stub = Array(302).fill("foo");
-    const defaultOutput = `["foo", "foo", "foo", more…]`;
+  function testMoreThanShortMaxProps() {
+    const stub = Array(maxLength.short + 1).fill("foo");
+    const defaultShortOutput = `[${Array(maxLength.short).fill("\"foo\"").join(", ")}, more…]`;
 
     const modeTests = [
       {
         mode: undefined,
-        expectedOutput: defaultOutput,
+        expectedOutput: defaultShortOutput,
       },
       {
         mode: "tiny",
-        expectedOutput: `[302]`,
+        expectedOutput: `[${maxLength.short + 1}]`,
       },
       {
         mode: "short",
-        expectedOutput: defaultOutput,
+        expectedOutput: defaultShortOutput,
       },
       {
         mode: "long",
-        expectedOutput: `[${Array(300).fill("\"foo\"").join(", ")}, more…]`,
+        expectedOutput: `[${Array(maxLength.short + 1).fill("\"foo\"").join(", ")}]`,
+      }
+    ];
+
+    testRepRenderModes(modeTests, "testMoreThanMaxProps", componentUnderTest, stub);
+  }
+
+  function testMoreThanLongMaxProps() {
+    const stub = Array(maxLength.long + 1).fill("foo");
+    const defaultShortOutput = `[${Array(maxLength.short).fill("\"foo\"").join(", ")}, more…]`;
+    const defaultLongOutput = `[${Array(maxLength.long).fill("\"foo\"").join(", ")}, more…]`;
+
+    const modeTests = [
+      {
+        mode: undefined,
+        expectedOutput: defaultShortOutput,
+      },
+      {
+        mode: "tiny",
+        expectedOutput: `[${maxLength.long + 1}]`,
+      },
+      {
+        mode: "short",
+        expectedOutput: defaultShortOutput,
+      },
+      {
+        mode: "long",
+        expectedOutput: defaultLongOutput,
       }
     ];
 
     testRepRenderModes(modeTests, "testMoreThanMaxProps", componentUnderTest, stub);
   }
 
   function testRecursiveArray() {
     let stub = [1];
--- a/devtools/client/shared/components/test/mochitest/test_reps_grip-array.html
+++ b/devtools/client/shared/components/test/mochitest/test_reps_grip-array.html
@@ -14,23 +14,28 @@ Test GripArray rep
 <pre id="test">
 <script src="head.js" type="application/javascript;version=1.8"></script>
 <script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
   let { GripArray } = browserRequire("devtools/client/shared/components/reps/grip-array");
 
   let componentUnderTest = GripArray;
+  const maxLength = {
+    short: 3,
+    long: 300
+  };
 
   try {
     yield testBasic();
 
     // Test property iterator
     yield testMaxProps();
-    yield testMoreThanMaxProps();
+    yield testMoreThanShortMaxProps();
+    yield testMoreThanLongMaxProps();
     yield testRecursiveArray();
   } catch(e) {
     ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
   } finally {
     SimpleTest.finish();
   }
 
   function testBasic() {
@@ -90,38 +95,67 @@ window.onload = Task.async(function* () 
         mode: "long",
         expectedOutput: defaultOutput,
       }
     ];
 
     testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
   }
 
-  function testMoreThanMaxProps() {
-    // Test array = `["test string"…] //301 items`
-    const testName = "testMoreThanMaxProps";
+  function testMoreThanShortMaxProps() {
+    // Test array = `["test string"…] //4 items`
+    const testName = "testMoreThanShortMaxProps";
 
-    const defaultOutput = `[${Array(3).fill("\"test string\"").join(", ")}, more…]`;
+    const defaultOutput = `[${Array(maxLength.short).fill("\"test string\"").join(", ")}, more…]`;
 
     const modeTests = [
       {
         mode: undefined,
         expectedOutput: defaultOutput,
       },
       {
         mode: "tiny",
-        expectedOutput: `[302]`,
+        expectedOutput: `[${maxLength.short + 1}]`,
       },
       {
         mode: "short",
         expectedOutput: defaultOutput,
       },
       {
         mode: "long",
-        expectedOutput: `[${Array(300).fill("\"test string\"").join(", ")}, more…]`,
+        expectedOutput: `[${Array(maxLength.short + 1).fill("\"test string\"").join(", ")}]`,
+      }
+    ];
+
+    testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
+  }
+
+  function testMoreThanLongMaxProps() {
+    // Test array = `["test string"…] //301 items`
+    const testName = "testMoreThanLongMaxProps";
+
+    const defaultShortOutput = `[${Array(maxLength.short).fill("\"test string\"").join(", ")}, more…]`;
+    const defaultLongOutput = `[${Array(maxLength.long).fill("\"test string\"").join(", ")}, more…]`;
+
+    const modeTests = [
+      {
+        mode: undefined,
+        expectedOutput: defaultShortOutput,
+      },
+      {
+        mode: "tiny",
+        expectedOutput: `[${maxLength.long + 1}]`,
+      },
+      {
+        mode: "short",
+        expectedOutput: defaultShortOutput,
+      },
+      {
+        mode: "long",
+        expectedOutput: defaultLongOutput
       }
     ];
 
     testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
   }
 
   function testRecursiveArray() {
     // @TODO This is not how this feature should actually work
@@ -195,39 +229,63 @@ window.onload = Task.async(function* () 
                 "frozen": false,
                 "sealed": false,
                 "ownPropertyLength": 0
               }
             ]
           }
         };
 
-      case "testMoreThanMaxProps":
-        let grip = {
+      case "testMoreThanShortMaxProps":
+        let shortArrayGrip = {
           "type": "object",
           "class": "Array",
           "actor": "server1.conn1.obj35",
           "extensible": true,
           "frozen": false,
           "sealed": false,
           "ownPropertyLength": 4,
           "preview": {
             "kind": "ArrayLike",
-            "length": 302,
+            "length": maxLength.short + 1,
             "items": []
           }
         };
 
-        // Generate 101 properties, which is more that the maximum
-        // limit in case of the 'long' mode.
-        for (let i = 0; i < 302; i++) {
-          grip.preview.items.push("test string");
+        // Generate array grip with length 4, which is more that the maximum
+        // limit in case of the 'short' mode.
+        for (let i = 0; i < maxLength.short + 1; i++) {
+          shortArrayGrip.preview.items.push("test string");
         }
 
-        return grip;
+        return shortArrayGrip;
+
+      case "testMoreThanLongMaxProps":
+        let longArrayGrip = {
+          "type": "object",
+          "class": "Array",
+          "actor": "server1.conn1.obj35",
+          "extensible": true,
+          "frozen": false,
+          "sealed": false,
+          "ownPropertyLength": 4,
+          "preview": {
+            "kind": "ArrayLike",
+            "length": maxLength.long + 1,
+            "items": []
+          }
+        };
+
+        // Generate array grip with length 301, which is more that the maximum
+        // limit in case of the 'long' mode.
+        for (let i = 0; i < maxLength.long + 1; i++) {
+          longArrayGrip.preview.items.push("test string");
+        }
+
+        return longArrayGrip;
 
       case "testRecursiveArray":
         return {
           "type": "object",
           "class": "Array",
           "actor": "server1.conn3.obj42",
           "extensible": true,
           "frozen": false,
--- a/devtools/client/shared/developer-toolbar.js
+++ b/devtools/client/shared/developer-toolbar.js
@@ -218,25 +218,20 @@ exports.CommandUtils = CommandUtils;
 /**
  * Due to a number of panel bugs we need a way to check if we are running on
  * Linux. See the comments for TooltipPanel and OutputPanel for further details.
  *
  * When bug 780102 is fixed all isLinux checks can be removed and we can revert
  * to using panels.
  */
 loader.lazyGetter(this, "isLinux", function () {
-  return OS == "Linux";
+  return Services.appinfo.OS == "Linux";
 });
 loader.lazyGetter(this, "isMac", function () {
-  return OS == "Darwin";
-});
-
-loader.lazyGetter(this, "OS", function () {
-  let os = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
-  return os;
+  return Services.appinfo.OS == "Darwin";
 });
 
 /**
  * A component to manage the global developer toolbar, which contains a GCLI
  * and buttons for various developer tools.
  * @param aChromeWindow The browser window to which this toolbar is attached
  */
 function DeveloperToolbar(aChromeWindow)
@@ -1005,17 +1000,17 @@ OutputPanel.prototype._resize = function
   // Set max panel width to match any content with a max of the width of the
   // browser window.
   let maxWidth = this._panel.ownerDocument.documentElement.clientWidth;
 
   // Adjust max width according to OS.
   // We'd like to put this in CSS but we can't:
   //   body { width: calc(min(-5px, max-content)); }
   //   #_panel { max-width: -5px; }
-  switch (OS) {
+  switch (Services.appinfo.OS) {
     case "Linux":
       maxWidth -= 5;
       break;
     case "Darwin":
       maxWidth -= 25;
       break;
     case "WINNT":
       maxWidth -= 5;
--- a/devtools/client/shared/shim/Services.js
+++ b/devtools/client/shared/shim/Services.js
@@ -460,16 +460,52 @@ PrefBranch.prototype = {
 
 const Services = {
   /**
    * An implementation of nsIPrefService that is based on local
    * storage.  Only the subset of nsIPrefService that is actually used
    * by devtools is implemented here.
    */
   prefs: new PrefBranch(null, "", ""),
+
+  /**
+   * An implementation of Services.appinfo that holds just the
+   * properties needed by devtools.
+   */
+  appinfo: {
+    get OS() {
+      const os = window.navigator.userAgent;
+      if (os) {
+        if (os.includes("Linux")) {
+          return "Linux";
+        } else if (os.includes("Windows")) {
+          return "WINNT";
+        } else if (os.includes("Mac")) {
+          return "Darwin";
+        }
+      }
+      return "Unknown";
+    },
+
+    // It's fine for this to be an approximation.
+    get name() {
+      return window.navigator.userAgent;
+    },
+
+    // It's fine for this to be an approximation.
+    get version() {
+      return window.navigator.appVersion;
+    },
+
+    // This is only used by telemetry, which is disabled for the
+    // content case.  So, being totally wrong is ok.
+    get is64Bit() {
+      return true;
+    },
+  },
 };
 
 /**
  * Create a new preference.  This is used during startup (see
  * devtools/client/preferences/devtools.js) to install the
  * default preferences.
  *
  * @param {String} name the name of the preference
--- a/devtools/client/shared/shim/test/mochitest.ini
+++ b/devtools/client/shared/shim/test/mochitest.ini
@@ -1,5 +1,6 @@
 [DEFAULT]
 support-files =
   prefs-wrapper.js
 
+[test_service_appinfo.html]
 [test_service_prefs.html]
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/shim/test/test_service_appinfo.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1265802
+-->
+<head>
+  <title>Test for Bug 1265802 - replace Services.appinfo</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css">
+
+  <script type="application/javascript;version=1.8">
+  "use strict";
+  var exports = {};
+  </script>
+
+  <script type="application/javascript;version=1.8"
+	  src="resource://devtools/client/shared/shim/Services.js"></script>
+</head>
+<body>
+<script type="application/javascript;version=1.8">
+"use strict";
+
+is(Services.appinfo.OS, SpecialPowers.Services.appinfo.OS,
+   "check that Services.appinfo.OS shim matches platform");
+</script>
+</body>
--- a/devtools/client/shared/telemetry.js
+++ b/devtools/client/shared/telemetry.js
@@ -51,19 +51,17 @@ this.Telemetry = function () {
   this.logOncePerBrowserVersion = this.logOncePerBrowserVersion.bind(this);
   this.destroy = this.destroy.bind(this);
 
   this._timers = new Map();
 };
 
 module.exports = Telemetry;
 
-var {Cc, Ci, Cu} = require("chrome");
 var Services = require("Services");
-var {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
 
 Telemetry.prototype = {
   _histograms: {
     toolbox: {
       histogram: "DEVTOOLS_TOOLBOX_OPENED_COUNT",
       userHistogram: "DEVTOOLS_TOOLBOX_OPENED_PER_USER_FLAG",
       timerHistogram: "DEVTOOLS_TOOLBOX_TIME_ACTIVE_SECONDS"
     },
@@ -92,21 +90,16 @@ Telemetry.prototype = {
       userHistogram: "DEVTOOLS_RULEVIEW_OPENED_PER_USER_FLAG",
       timerHistogram: "DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS"
     },
     computedview: {
       histogram: "DEVTOOLS_COMPUTEDVIEW_OPENED_COUNT",
       userHistogram: "DEVTOOLS_COMPUTEDVIEW_OPENED_PER_USER_FLAG",
       timerHistogram: "DEVTOOLS_COMPUTEDVIEW_TIME_ACTIVE_SECONDS"
     },
-    layoutview: {
-      histogram: "DEVTOOLS_LAYOUTVIEW_OPENED_COUNT",
-      userHistogram: "DEVTOOLS_LAYOUTVIEW_OPENED_PER_USER_FLAG",
-      timerHistogram: "DEVTOOLS_LAYOUTVIEW_TIME_ACTIVE_SECONDS"
-    },
     fontinspector: {
       histogram: "DEVTOOLS_FONTINSPECTOR_OPENED_COUNT",
       userHistogram: "DEVTOOLS_FONTINSPECTOR_OPENED_PER_USER_FLAG",
       timerHistogram: "DEVTOOLS_FONTINSPECTOR_TIME_ACTIVE_SECONDS"
     },
     animationinspector: {
       histogram: "DEVTOOLS_ANIMATIONINSPECTOR_OPENED_COUNT",
       userHistogram: "DEVTOOLS_ANIMATIONINSPECTOR_OPENED_PER_USER_FLAG",
@@ -357,17 +350,17 @@ Telemetry.prototype = {
   /**
    * Log info about usage once per browser version. This allows us to discover
    * how many individual users are using our tools for each browser version.
    *
    * @param  {String} perUserHistogram
    *         Histogram in which the data is to be stored.
    */
   logOncePerBrowserVersion: function (perUserHistogram, value) {
-    let currentVersion = appInfo.version;
+    let currentVersion = Services.appinfo.version;
     let latest = Services.prefs.getCharPref(TOOLS_OPENED_PREF);
     let latestObj = JSON.parse(latest);
 
     let lastVersionHistogramUpdated = latestObj[perUserHistogram];
 
     if (typeof lastVersionHistogramUpdated == "undefined" ||
         lastVersionHistogramUpdated !== currentVersion) {
       latestObj[perUserHistogram] = currentVersion;
@@ -378,12 +371,8 @@ Telemetry.prototype = {
   },
 
   destroy: function () {
     for (let histogramId of this._timers.keys()) {
       this.stopTimer(histogramId);
     }
   }
 };
-
-XPCOMUtils.defineLazyGetter(this, "appInfo", function () {
-  return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
-});
--- a/devtools/client/shared/test/browser_telemetry_sidebar.js
+++ b/devtools/client/shared/test/browser_telemetry_sidebar.js
@@ -23,17 +23,17 @@ add_task(function* () {
   gBrowser.removeCurrentTab();
 });
 
 function* testSidebar(toolbox) {
   info("Testing sidebar");
 
   let inspector = toolbox.getCurrentPanel();
   let sidebarTools = ["ruleview", "computedview", "fontinspector",
-                      "layoutview", "animationinspector"];
+                      "animationinspector"];
 
   // Concatenate the array with itself so that we can open each tool twice.
   sidebarTools.push.apply(sidebarTools, sidebarTools);
 
   return new Promise(resolve => {
     // See TOOL_DELAY for why we need setTimeout here
     setTimeout(function selectSidebarTab() {
       let tool = sidebarTools.pop();
--- a/devtools/client/shared/widgets/AbstractTreeItem.jsm
+++ b/devtools/client/shared/widgets/AbstractTreeItem.jsm
@@ -473,17 +473,58 @@ AbstractTreeItem.prototype = {
    * @param number delta
    *        The offset from this item to the target item.
    * @return nsIDOMNode
    *         The element displaying the target item at the specified offset.
    */
   _getSiblingAtDelta: function (delta) {
     let childNodes = this._containerNode.childNodes;
     let indexOfSelf = Array.indexOf(childNodes, this._targetNode);
-    return childNodes[indexOfSelf + delta];
+    if (indexOfSelf + delta >= 0) {
+      return childNodes[indexOfSelf + delta];
+    }
+    return undefined;
+  },
+
+  _getNodesPerPageSize: function() {
+    let childNodes = this._containerNode.childNodes;
+    let nodeHeight = this._getHeight(childNodes[childNodes.length - 1]);
+    let containerHeight = this.bounds.height;
+    return Math.ceil(containerHeight / nodeHeight);
+  },
+
+  _getHeight: function(elem) {
+    let win = this.document.defaultView;
+    let utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                   .getInterface(Ci.nsIDOMWindowUtils);
+    return utils.getBoundsWithoutFlushing(elem).height;
+  },
+
+  /**
+   * Focuses the first item in this tree.
+   */
+  _focusFirstNode: function () {
+    let childNodes = this._containerNode.childNodes;
+    // The root node of the tree may be hidden in practice, so uses for-loop
+    // here to find the next visible node.
+    for (let i = 0; i < childNodes.length; i++) {
+      // The height will be 0 if an element is invisible.
+      if (this._getHeight(childNodes[i])) {
+        childNodes[i].focus();
+        return;
+      }
+    }
+  },
+
+  /**
+   * Focuses the last item in this tree.
+   */
+  _focusLastNode: function () {
+    let childNodes = this._containerNode.childNodes;
+    childNodes[childNodes.length - 1].focus();
   },
 
   /**
    * Focuses the next item in this tree.
    */
   _focusNextNode: function () {
     let nextElement = this._getSiblingAtDelta(1);
     if (nextElement) nextElement.focus(); // nsIDOMNode
@@ -565,16 +606,46 @@ AbstractTreeItem.prototype = {
 
       case e.DOM_VK_RIGHT:
         if (!this._expanded) {
           this.expand();
         } else {
           this._focusNextNode();
         }
         return;
+
+      case e.DOM_VK_PAGE_UP:
+        let pageUpElement =
+          this._getSiblingAtDelta(-this._getNodesPerPageSize());
+        // There's a chance that the root node is hidden. In this case, its
+        // height will be 0.
+        if (pageUpElement && this._getHeight(pageUpElement)) {
+          pageUpElement.focus();
+        } else {
+          this._focusFirstNode();
+        }
+        return;
+
+      case e.DOM_VK_PAGE_DOWN:
+        let pageDownElement =
+          this._getSiblingAtDelta(this._getNodesPerPageSize());
+        if (pageDownElement) {
+          pageDownElement.focus();
+        } else {
+          this._focusLastNode();
+        }
+        return;
+
+      case e.DOM_VK_HOME:
+        this._focusFirstNode();
+        return;
+
+      case e.DOM_VK_END:
+        this._focusLastNode();
+        return;
     }
   },
 
   /**
    * Handler for the "focus" event on the element displaying this tree item.
    */
   _onFocus: function (e) {
     this._rootItem.emit("focus", this);
--- a/devtools/client/shared/widgets/FlameGraph.js
+++ b/devtools/client/shared/widgets/FlameGraph.js
@@ -922,17 +922,19 @@ FlameGraph.prototype = {
   },
 
   /**
    * Listener for the "keydown" event on the graph's container.
    */
   _onKeyDown: function (e) {
     ViewHelpers.preventScrolling(e);
 
-    if (!this._keysPressed[e.keyCode]) {
+    const hasModifier = e.ctrlKey || e.shiftKey || e.altKey || e.metaKey;
+
+    if (!hasModifier && !this._keysPressed[e.keyCode]) {
       this._keysPressed[e.keyCode] = true;
       this._userInputStack++;
       this._shouldRedraw = true;
     }
   },
 
   /**
    * Listener for the "keyup" event on the graph's container.
--- a/devtools/client/shared/widgets/HTMLTooltip.js
+++ b/devtools/client/shared/widgets/HTMLTooltip.js
@@ -217,20 +217,21 @@ function HTMLTooltip(toolbox, {
   EventEmitter.decorate(this);
 
   this.doc = toolbox.doc;
   this.type = type;
   this.autofocus = autofocus;
   this.consumeOutsideClicks = consumeOutsideClicks;
   this.useXulWrapper = this._isXUL() && useXulWrapper;
 
-  this._position = null;
+  // The top window is used to attach click event listeners to close the tooltip if the
+  // user clicks on the content page.
+  this.topWindow = this._getTopWindow();
 
-  // Use the topmost window to listen for click events to close the tooltip
-  this.topWindow = this.doc.defaultView.top;
+  this._position = null;
 
   this._onClick = this._onClick.bind(this);
 
   this._toggle = new TooltipToggle(this);
   this.startTogglingOnHover = this._toggle.start.bind(this._toggle);
   this.stopTogglingOnHover = this._toggle.stop.bind(this._toggle);
 
   this.container = this._createContainer();
@@ -377,16 +378,18 @@ HTMLTooltip.prototype = {
     this.container.classList.add("tooltip-visible");
 
     // Keep a pointer on the focused element to refocus it when hiding the tooltip.
     this._focusedElement = this.doc.activeElement;
 
     this.doc.defaultView.clearTimeout(this.attachEventsTimer);
     this.attachEventsTimer = this.doc.defaultView.setTimeout(() => {
       this._maybeFocusTooltip();
+      // Updated the top window reference each time in case the host changes.
+      this.topWindow = this._getTopWindow();
       this.topWindow.addEventListener("click", this._onClick, true);
       this.emit("shown");
     }, 0);
   }),
 
   /**
    * Calculate the rect of the viewport that limits the tooltip dimensions. When using a
    * XUL panel wrapper, the viewport will be able to use the whole screen (excluding space
@@ -545,16 +548,20 @@ HTMLTooltip.prototype = {
     // http://stackoverflow.com/questions/1599660/which-html-elements-can-receive-focus .
     let focusableSelector = "a, button, iframe, input, select, textarea";
     let focusableElement = this.panel.querySelector(focusableSelector);
     if (this.autofocus && focusableElement) {
       focusableElement.focus();
     }
   },
 
+  _getTopWindow: function () {
+    return this.doc.defaultView.top;
+  },
+
   /**
    * Check if the tooltip's owner document is a XUL document.
    */
   _isXUL: function () {
     return this.doc.documentElement.namespaceURI === XUL_NS;
   },
 
   _createXulPanelWrapper: function () {
@@ -565,17 +572,17 @@ HTMLTooltip.prototype = {
     panel.setAttribute("animate", false);
     panel.setAttribute("consumeoutsideclicks", false);
     panel.setAttribute("noautofocus", true);
     panel.setAttribute("ignorekeys", true);
 
     // Use type="arrow" to prevent side effects (see Bug 1285206)
     panel.setAttribute("type", "arrow");
 
-    panel.setAttribute("level", "float");
+    panel.setAttribute("level", "top");
     panel.setAttribute("class", "tooltip-xul-wrapper");
 
     return panel;
   },
 
   _showXulWrapperAt: function (left, top) {
     let onPanelShown = listenOnce(this.xulPanelWrapper, "popupshown");
     this.xulPanelWrapper.openPopupAtScreen(left, top, false);
--- a/devtools/client/themes/computed.css
+++ b/devtools/client/themes/computed.css
@@ -27,21 +27,27 @@
   margin-right: 5px;
 
   /* Vertically center the 'Browser styles' checkbox in the
      Computed panel with its label. */
   display: flex;
   align-items: center;
 }
 
+#computedview-container {
+  overflow: auto;
+}
+
 #propertyContainer {
   -moz-user-select: text;
   overflow-y: auto;
   overflow-x: hidden;
   flex: auto;
+  border-top-width: 1px;
+  border-top-style: dotted;
 }
 
 .row-striped {
   background: var(--theme-body-background);
 }
 
 .property-view-hidden,
 .property-content-hidden {
@@ -54,17 +60,19 @@
   flex-wrap: wrap;
 }
 
 .property-name-container {
   width: 202px;
 }
 
 .property-value-container {
-  width: 168px;
+  display: flex;
+  flex: 1 1 168px;
+  overflow: hidden;
 }
 
 .property-name-container > *,
 .property-value-container > * {
   display: inline-block;
   vertical-align: middle;
 }
 
--- a/devtools/client/themes/firebug-theme.css
+++ b/devtools/client/themes/firebug-theme.css
@@ -15,18 +15,20 @@
 /* Remove filters on firebug specific images */
 
 .theme-firebug .devtools-tabbar .devtools-button::before,
 .theme-firebug .devtools-option-toolbarbutton > image,
 .theme-firebug .command-button-invertable::before,
 .theme-firebug #sources-toolbar image,
 .theme-firebug [id$="pane-toggle"] > image,
 .theme-firebug [id$="pane-toggle"]::before,
-.theme-firebug #global-toolbar .devtools-button::before,
+.theme-firebug .sidebar-toggle::before,
 .theme-firebug #element-picker::before,
+.theme-firebug #rewind-timeline::before,
+.theme-firebug #pause-resume-timeline::before,
 .theme-firebug #debugger-controls .toolbarbutton-icon,
 .theme-firebug #filter-button .toolbarbutton-icon {
   filter: none !important;
 }
 
 /* CodeMirror Color Syntax */
 
 .theme-firebug .cm-keyword {color: BlueViolet; font-weight: bold;}
--- a/devtools/client/themes/layout.css
+++ b/devtools/client/themes/layout.css
@@ -1,72 +1,40 @@
 /* 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/ */
 
-#sidebar-panel-layoutview {
-  display: block;
-  overflow: auto;
-  height: 100%;
-}
-
-#layout-wrapper {
-  /* The sidebar-panel is not focusable, this wrapper will catch click events in
-     all the empty area around the layout-container */
-  height: 100%;
-}
-
 #layout-container {
   /* The view will grow bigger as the window gets resized, until 400px */
   max-width: 400px;
   margin: 0px auto;
   padding: 0;
-  /* "Contain" the absolutely positioned #layout-main element */
-  position: relative;
-}
-
-/* Header: contains the position and size of the element */
-
-#layout-header {
-  box-sizing: border-box;
-  width: 100%;
-  padding: 4px 14px;
-  display: -moz-box;
-  vertical-align: top;
-}
-
-#layout-header:dir(rtl) {
-  -moz-box-direction: reverse;
 }
 
-#layout-header > span {
-  display: -moz-box;
-}
+/* Header */
 
-#layout-element-size {
-  -moz-box-flex: 1;
+#layout-header,
+#layout-info {
+  display: flex;
+  align-items: center;
+  padding: 4px 17px;
 }
 
-#layout-element-size:dir(rtl) {
-  -moz-box-pack: end;
+#layout-geometry-editor {
+  visibility: hidden;
 }
 
-@media (max-height: 250px) {
-  #layout-header {
-    padding-top: 0;
-    padding-bottom: 0;
-    margin-top: 10px;
-    margin-bottom: 8px;
-  }
+#layout-geometry-editor::before {
+  background: url(images/geometry-editor.svg) no-repeat center center / 16px 16px;
 }
 
 /* Main: contains the box-model regions */
 
 #layout-main {
-  position: absolute;
+  position: relative;
   box-sizing: border-box;
   /* The regions are semi-transparent, so the white background is partly
      visible */
   background-color: white;
   color: var(--theme-selection-color);
   /* Make sure there is some space between the window's edges and the regions */
   margin: 0 14px 10px 14px;
   width: calc(100% - 2 * 14px);
@@ -311,17 +279,17 @@
     left: 16px;
   }
 
   .layout-border.layout-right {
     right: 17px;
   }
 }
 
-/* Legend, displayed inside regions */
+/* Legend: displayed inside regions */
 
 .layout-legend {
   position: absolute;
   margin: 5px 6px;
   z-index: 1;
 }
 
 .layout-legend[data-box="margin"] {
@@ -351,28 +319,18 @@
 }
 
 /* Make sure the content size doesn't appear as editable like the other sizes */
 
 .layout-size > span {
   cursor: default;
 }
 
-/* Hide all values when the view is inactive */
+/* Layout info: contains the position and size of the element */
 
-#layout-container.inactive > #layout-header > #layout-element-position,
-#layout-container.inactive > #layout-header > #layout-element-size,
-#layout-container.inactive > #layout-main > p {
-   visibility: hidden;
+#layout-element-size {
+  flex: 1;
 }
 
 #layout-position-group {
   display: flex;
   align-items: center;
 }
-
-#layout-geometry-editor {
-  visibility: hidden;
-}
-
-#layout-geometry-editor::before {
-  background: url(images/geometry-editor.svg) no-repeat center center / 16px 16px;
-}
--- a/devtools/client/themes/rules.css
+++ b/devtools/client/themes/rules.css
@@ -40,17 +40,16 @@
 #ruleview-toolbar-container {
   display: flex;
   flex-direction: column;
   height: auto;
 }
 
 #ruleview-toolbar {
   display: flex;
-  height: 23px;
 }
 
 #ruleview-toolbar > .devtools-searchbox:first-child {
   padding-inline-start: 0px;
 }
 
 #ruleview-command-toolbar {
   display: flex;
@@ -251,21 +250,19 @@
 .theme-firebug .ruleview-overridden .ruleview-propertyname,
 .theme-firebug .ruleview-overridden .ruleview-propertyvalue {
   text-decoration: line-through;
 }
 
 .theme-firebug .ruleview-enableproperty:not([checked]) ~ .ruleview-namecontainer,
 .theme-firebug .ruleview-enableproperty:not([checked]) ~ .ruleview-namecontainer *,
 .theme-firebug .ruleview-enableproperty:not([checked]) ~ .ruleview-propertyvaluecontainer,
-.theme-firebug .ruleview-enableproperty:not([checked]) ~ .ruleview-propertyvaluecontainer * {
-  color: #CCCCCC;
-}
-
-.theme-firebug .ruleview-enableproperty:not([checked]) ~ .ruleview-computedlist * {
+.theme-firebug .ruleview-enableproperty:not([checked]) ~ .ruleview-propertyvaluecontainer *,
+.theme-firebug .ruleview-overridden > * > .ruleview-computed:not(.ruleview-overridden),
+.theme-firebug .ruleview-overridden > * > .ruleview-computed:not(.ruleview-overridden) * {
   color: #CCCCCC;
 }
 
 .ruleview-rule + .ruleview-rule {
   border-top-width: 1px;
   border-top-style: dotted;
 }
 
--- a/devtools/client/themes/toolbars.css
+++ b/devtools/client/themes/toolbars.css
@@ -385,16 +385,17 @@
 .devtools-filterinput .textbox-input::-moz-placeholder {
   font-style: normal;
 }
 
 /* Searchbox is a div container element for a search input element */
 .devtools-searchbox {
   display: flex;
   flex: 1;
+  height: 23px;
   position: relative;
   padding: 0 3px;
 }
 
 /* The spacing is accomplished with a padding on the searchbox */
 .devtools-searchbox > .devtools-textinput,
 .devtools-searchbox > .devtools-searchinput,
 .devtools-searchbox > .devtools-filterinput {
--- a/devtools/server/actors/inspector.js
+++ b/devtools/server/actors/inspector.js
@@ -71,16 +71,17 @@ const {
   isAnonymous,
   isNativeAnonymous,
   isXBLAnonymous,
   isShadowAnonymous,
   getFrameElement
 } = require("devtools/shared/layout/utils");
 const {getLayoutChangesObserver, releaseLayoutChangesObserver} =
   require("devtools/server/actors/layout");
+const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
 
 loader.lazyRequireGetter(this, "CSS", "CSS");
 
 const {EventParsers} = require("devtools/shared/event-parsers");
 const {nodeSpec, nodeListSpec, walkerSpec, inspectorSpec} = require("devtools/shared/specs/inspector");
 
 const FONT_FAMILY_PREVIEW_TEXT = "The quick brown fox jumps over the lazy dog";
 const FONT_FAMILY_PREVIEW_TEXT_SIZE = 20;
@@ -2763,23 +2764,23 @@ function isNodeDead(node) {
 }
 
 /**
  * Wrapper for inDeepTreeWalker.  Adds filtering to the traversal methods.
  * See inDeepTreeWalker for more information about the methods.
  *
  * @param {DOMNode} node
  * @param {Window} rootWin
- * @param {Int} whatToShow See Ci.nsIDOMNodeFilter / inIDeepTreeWalker for
+ * @param {Int} whatToShow See nodeFilterConstants / inIDeepTreeWalker for
  * options.
  * @param {Function} filter A custom filter function Taking in a DOMNode
  *        and returning an Int. See WalkerActor.nodeFilter for an example.
  */
 function DocumentWalker(node, rootWin,
-    whatToShow = Ci.nsIDOMNodeFilter.SHOW_ALL,
+    whatToShow = nodeFilterConstants.SHOW_ALL,
     filter = standardTreeWalkerFilter) {
   if (!rootWin.location) {
     throw new Error("Got an invalid root window in DocumentWalker");
   }
 
   this.walker = Cc["@mozilla.org/inspector/deep-tree-walker;1"]
     .createInstance(Ci.inIDeepTreeWalker);
   this.walker.showAnonymousContent = true;
@@ -2788,17 +2789,17 @@ function DocumentWalker(node, rootWin,
   this.walker.init(rootWin.document, whatToShow);
   this.filter = filter;
 
   // Make sure that the walker knows about the initial node (which could
   // be skipped due to a filter).  Note that simply calling parentNode()
   // causes currentNode to be updated.
   this.walker.currentNode = node;
   while (node &&
-         this.filter(node) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
+         this.filter(node) === nodeFilterConstants.FILTER_SKIP) {
     node = this.walker.parentNode();
   }
 }
 
 DocumentWalker.prototype = {
   get node() {
     return this.walker.node;
   },
@@ -2819,64 +2820,64 @@ DocumentWalker.prototype = {
   nextNode: function () {
     let node = this.walker.currentNode;
     if (!node) {
       return null;
     }
 
     let nextNode = this.walker.nextNode();
     while (nextNode &&
-           this.filter(nextNode) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
+           this.filter(nextNode) === nodeFilterConstants.FILTER_SKIP) {
       nextNode = this.walker.nextNode();
     }
 
     return nextNode;
   },
 
   firstChild: function () {
     let node = this.walker.currentNode;
     if (!node) {
       return null;
     }
 
     let firstChild = this.walker.firstChild();
     while (firstChild &&
-           this.filter(firstChild) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
+           this.filter(firstChild) === nodeFilterConstants.FILTER_SKIP) {
       firstChild = this.walker.nextSibling();
     }
 
     return firstChild;
   },
 
   lastChild: function () {
     let node = this.walker.currentNode;
     if (!node) {
       return null;
     }
 
     let lastChild = this.walker.lastChild();
     while (lastChild &&
-           this.filter(lastChild) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
+           this.filter(lastChild) === nodeFilterConstants.FILTER_SKIP) {
       lastChild = this.walker.previousSibling();
     }
 
     return lastChild;
   },
 
   previousSibling: function () {
     let node = this.walker.previousSibling();
-    while (node && this.filter(node) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
+    while (node && this.filter(node) === nodeFilterConstants.FILTER_SKIP) {
       node = this.walker.previousSibling();
     }
     return node;
   },
 
   nextSibling: function () {
     let node = this.walker.nextSibling();
-    while (node && this.filter(node) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
+    while (node && this.filter(node) === nodeFilterConstants.FILTER_SKIP) {
       node = this.walker.nextSibling();
     }
     return node;
   }
 };
 
 function isInXULDocument(el) {
   let doc = nodeDocument(el);
@@ -2890,49 +2891,49 @@ function isInXULDocument(el) {
  * content with the exception of ::before and ::after and anonymous content
  * in XUL document (needed to show all elements in the browser toolbox).
  */
 function standardTreeWalkerFilter(node) {
   // ::before and ::after are native anonymous content, but we always
   // want to show them
   if (node.nodeName === "_moz_generated_content_before" ||
       node.nodeName === "_moz_generated_content_after") {
-    return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
+    return nodeFilterConstants.FILTER_ACCEPT;
   }
 
   // Ignore empty whitespace text nodes.
   if (node.nodeType == Ci.nsIDOMNode.TEXT_NODE &&
       !/[^\s]/.exec(node.nodeValue)) {
-    return Ci.nsIDOMNodeFilter.FILTER_SKIP;
+    return nodeFilterConstants.FILTER_SKIP;
   }
 
   // Ignore all native and XBL anonymous content inside a non-XUL document
   if (!isInXULDocument(node) && (isXBLAnonymous(node) ||
                                   isNativeAnonymous(node))) {
     // Note: this will skip inspecting the contents of feedSubscribeLine since
     // that's XUL content injected in an HTML document, but we need to because
     // this also skips many other elements that need to be skipped - like form
     // controls, scrollbars, video controls, etc (see bug 1187482).
-    return Ci.nsIDOMNodeFilter.FILTER_SKIP;
+    return nodeFilterConstants.FILTER_SKIP;
   }
 
-  return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
+  return nodeFilterConstants.FILTER_ACCEPT;
 }
 
 /**
  * This DeepTreeWalker filter is like standardTreeWalkerFilter except that
  * it also includes all anonymous content (like internal form controls).
  */
 function allAnonymousContentTreeWalkerFilter(node) {
   // Ignore empty whitespace text nodes.
   if (node.nodeType == Ci.nsIDOMNode.TEXT_NODE &&
       !/[^\s]/.exec(node.nodeValue)) {
-    return Ci.nsIDOMNodeFilter.FILTER_SKIP;
+    return nodeFilterConstants.FILTER_SKIP;
   }
-  return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
+  return nodeFilterConstants.FILTER_ACCEPT;
 }
 
 /**
  * Returns a promise that is settled once the given HTMLImageElement has
  * finished loading.
  *
  * @param {HTMLImageElement} image - The image element.
  * @param {Number} timeout - Maximum amount of time the image is allowed to load
--- a/devtools/server/tests/mochitest/test_inspector-anonymous.html
+++ b/devtools/server/tests/mochitest/test_inspector-anonymous.html
@@ -7,21 +7,22 @@ https://bugzilla.mozilla.org/show_bug.cg
   <meta charset="utf-8">
   <title>Test for Bug 777674</title>
 
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   <script type="application/javascript;version=1.8" src="inspector-helpers.js"></script>
   <script type="application/javascript;version=1.8">
 window.onload = function() {
-  const Ci = Components.interfaces;
   const {InspectorFront} =
     require("devtools/shared/fronts/inspector");
   const {_documentWalker} =
     require("devtools/server/actors/inspector");
+  const nodeFilterConstants =
+    require("devtools/shared/dom-node-filter-constants");
   const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
   SpecialPowers.pushPrefEnv({"set": [
     ["dom.webcomponents.enabled", true]
   ]});
   SimpleTest.waitForExplicitFinish();
 
   let gWalker = null;
@@ -71,19 +72,19 @@ window.onload = function() {
   addAsyncTest(function* testNativeAnonymousStartingNode() {
     info ("Tests attaching an element that a walker can't see.");
 
     let serverConnection = gWalker.conn._transport._serverConnection;
     let serverWalker = serverConnection.getActor(gWalker.actorID);
     let docwalker = new _documentWalker(
       gInspectee.querySelector("select"),
       gInspectee.defaultView,
-      Ci.nsIDOMNodeFilter.SHOW_ALL,
+      nodeFilterConstants.SHOW_ALL,
       () => {
-        return Ci.nsIDOMNodeFilter.FILTER_ACCEPT
+        return nodeFilterConstants.FILTER_ACCEPT
       }
     );
     let scrollbar = docwalker.lastChild();
     is (scrollbar.tagName, "scrollbar", "An anonymous child has been fetched");
 
     let node = yield serverWalker.attachElement(scrollbar);
 
     ok (node, "A response has arrived");
new file mode 100644
--- /dev/null
+++ b/devtools/shared/dom-node-filter-constants.js
@@ -0,0 +1,21 @@
+"use strict";
+
+module.exports = {
+  FILTER_ACCEPT: 1,
+  FILTER_REJECT: 2,
+  FILTER_SKIP: 3,
+
+  SHOW_ALL: 0xFFFFFFFF,
+  SHOW_ELEMENT: 0x00000001,
+  SHOW_ATTRIBUTE: 0x00000002,
+  SHOW_TEXT: 0x00000004,
+  SHOW_CDATA_SECTION: 0x00000008,
+  SHOW_ENTITY_REFERENCE: 0x00000010,
+  SHOW_ENTITY: 0x00000020,
+  SHOW_PROCESSING_INSTRUCTION: 0x00000040,
+  SHOW_COMMENT: 0x00000080,
+  SHOW_DOCUMENT: 0x00000100,
+  SHOW_DOCUMENT_TYPE: 0x00000200,
+  SHOW_DOCUMENT_FRAGMENT: 0x00000400,
+  SHOW_NOTATION: 0x00000800
+};
--- a/devtools/shared/inspector/css-logic.js
+++ b/devtools/shared/inspector/css-logic.js
@@ -35,17 +35,16 @@
  * CssLogic uses the standard DOM API, and the Gecko inIDOMUtils API to access
  * styling information in the page, and present this to the user in a way that
  * helps them understand:
  * - why their expectations may not have been fulfilled
  * - how browsers process CSS
  * @constructor
  */
 
-const { Cc, Ci } = require("chrome");
 const Services = require("Services");
 
 // This should be ok because none of the functions that use this should be used
 // on the worker thread, where Cu is not available.
 loader.lazyRequireGetter(this, "CSS", "CSS");
 
 loader.lazyRequireGetter(this, "CSSLexer", "devtools/shared/css-lexer");
 
@@ -139,17 +138,17 @@ const TAB_CHARS = "\t";
  * Prettify minified CSS text.
  * This prettifies CSS code where there is no indentation in usual places while
  * keeping original indentation as-is elsewhere.
  * @param string text The CSS source to prettify.
  * @return string Prettified CSS source
  */
 function prettifyCSS(text, ruleCount) {
   if (prettifyCSS.LINE_SEPARATOR == null) {
-    let os = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
+    let os = Services.appinfo.OS;
     prettifyCSS.LINE_SEPARATOR = (os === "WINNT" ? "\r\n" : "\n");
   }
 
   // remove initial and terminating HTML comments and surrounding whitespace
   text = text.replace(/(?:^\s*<!--[\r\n]*)|(?:\s*-->\s*$)/g, "");
   let originalText = text;
   text = text.trim();
 
--- a/devtools/shared/layout/utils.js
+++ b/devtools/shared/layout/utils.js
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Ci, Cc } = require("chrome");
 const { memoize } = require("sdk/lang/functional");
+const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
 
 loader.lazyRequireGetter(this, "setIgnoreLayoutChanges", "devtools/server/actors/layout", true);
 exports.setIgnoreLayoutChanges = (...args) =>
   this.setIgnoreLayoutChanges(...args);
 
 /**
  * Returns the `DOMWindowUtils` for the window given.
  *
@@ -372,17 +373,17 @@ function safelyGetContentWindow(frame) {
   if (frame.contentWindow) {
     return frame.contentWindow;
   }
 
   let walker = Cc["@mozilla.org/inspector/deep-tree-walker;1"]
                .createInstance(Ci.inIDeepTreeWalker);
   walker.showSubDocuments = true;
   walker.showDocumentsAsNodes = true;
-  walker.init(frame, Ci.nsIDOMNodeFilter.SHOW_ALL);
+  walker.init(frame, nodeFilterConstants.SHOW_ALL);
   walker.currentNode = frame;
 
   let document = walker.nextNode();
   if (!document || !document.defaultView) {
     throw new Error("Couldn't get the content window inside frame " + frame);
   }
 
   return document.defaultView;
--- a/devtools/shared/moz.build
+++ b/devtools/shared/moz.build
@@ -44,16 +44,17 @@ DevToolsModules(
     'content-observer.js',
     'css-lexer.js',
     'css-parsing-utils.js',
     'css-properties-db.js',
     'defer.js',
     'deprecated-sync-thenables.js',
     'DevToolsUtils.js',
     'dom-node-constants.js',
+    'dom-node-filter-constants.js',
     'event-emitter.js',
     'event-parsers.js',
     'indentation.js',
     'Loader.jsm',
     'Parser.jsm',
     'path.js',
     'protocol.js',
     'system.js',
--- a/devtools/shared/system.js
+++ b/devtools/shared/system.js
@@ -326,15 +326,14 @@ function getSetting(name) {
       handleError: (error) => deferred.reject(error),
     });
   } else {
     deferred.reject(new Error("No settings service"));
   }
   return deferred.promise;
 }
 
-exports.is64Bit = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).is64Bit;
 exports.getSystemInfo = Task.async(getSystemInfo);
 exports.getAppIniString = getAppIniString;
 exports.getSetting = getSetting;
 exports.getScreenDimensions = getScreenDimensions;
 exports.getOSCPU = getOSCPU;
 exports.constants = AppConstants;
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -810,16 +810,17 @@ nsDocShell::nsDocShell()
 #ifdef DEBUG
   , mInEnsureScriptEnv(false)
 #endif
   , mDefaultLoadFlags(nsIRequest::LOAD_NORMAL)
   , mFrameType(FRAME_TYPE_REGULAR)
   , mPrivateBrowsingId(0)
   , mParentCharsetSource(0)
   , mJSRunToCompletionDepth(0)
+  , mTouchEventsOverride(nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE)
 {
   AssertOriginAttributesMatchPrivateBrowsing();
   mHistoryID = ++gDocshellIDCounter;
   if (gDocShellCount++ == 0) {
     NS_ASSERTION(sURIFixup == nullptr,
                  "Huh, sURIFixup not null in first nsDocShell ctor!");
 
     CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
@@ -3175,16 +3176,46 @@ nsDocShell::SetCustomUserAgent(const nsA
     nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i));
     if (childShell) {
       childShell->SetCustomUserAgent(aCustomUserAgent);
     }
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDocShell::GetTouchEventsOverride(uint32_t* aTouchEventsOverride)
+{
+  NS_ENSURE_ARG_POINTER(aTouchEventsOverride);
+
+  *aTouchEventsOverride = mTouchEventsOverride;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetTouchEventsOverride(uint32_t aTouchEventsOverride)
+{
+  if (!(aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE ||
+        aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_ENABLED ||
+        aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_DISABLED)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  mTouchEventsOverride = aTouchEventsOverride;
+
+  uint32_t childCount = mChildList.Length();
+  for (uint32_t i = 0; i < childCount; ++i) {
+    nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i));
+    if (childShell) {
+      childShell->SetTouchEventsOverride(aTouchEventsOverride);
+    }
+  }
+  return NS_OK;
+}
+
 /* virtual */ int32_t
 nsDocShell::ItemType()
 {
   return mItemType;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetItemType(int32_t* aItemType)
@@ -3347,16 +3378,20 @@ nsDocShell::SetDocLoaderParent(nsDocLoad
     }
     SetAllowDNSPrefetch(mAllowDNSPrefetch && value);
     value = parentAsDocShell->GetAffectPrivateSessionLifetime();
     SetAffectPrivateSessionLifetime(value);
     uint32_t flags;
     if (NS_SUCCEEDED(parentAsDocShell->GetDefaultLoadFlags(&flags))) {
       SetDefaultLoadFlags(flags);
     }
+    uint32_t touchEventsOverride;
+    if (NS_SUCCEEDED(parentAsDocShell->GetTouchEventsOverride(&touchEventsOverride))) {
+      SetTouchEventsOverride(touchEventsOverride);
+    }
   }
 
   nsCOMPtr<nsILoadContext> parentAsLoadContext(do_QueryInterface(parent));
   if (parentAsLoadContext &&
       NS_SUCCEEDED(parentAsLoadContext->GetUsePrivateBrowsing(&value))) {
     SetPrivateBrowsing(value);
   }
 
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -1033,16 +1033,20 @@ private:
   nsCString mOriginalUriString;
   nsWeakPtr mOpener;
   mozilla::DocShellOriginAttributes mOriginAttributes;
 
   // A depth count of how many times NotifyRunToCompletionStart
   // has been called without a matching NotifyRunToCompletionStop.
   uint32_t mJSRunToCompletionDepth;
 
+  // Whether or not touch events are overridden. Possible values are defined
+  // as constants in the nsIDocShell.idl file.
+  uint32_t mTouchEventsOverride;
+
   // Separate function to do the actual name (i.e. not _top, _self etc.)
   // searching for FindItemWithName.
   nsresult DoFindItemWithName(const char16_t* aName,
                               nsISupports* aRequestor,
                               nsIDocShellTreeItem* aOriginalRequestor,
                               nsIDocShellTreeItem** aResult);
 
   // Helper assertion to enforce that mInPrivateBrowsing is in sync with
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -1109,9 +1109,27 @@ interface nsIDocShell : nsIDocShellTreeI
 
   /**
    * The tab child for this docshell.
    */
   [binaryname(ScriptableTabChild)] readonly attribute nsITabChild tabChild;
   [noscript,notxpcom,nostdcall] TabChildRef GetTabChild();
 
   [noscript,nostdcall,notxpcom] nsICommandManager GetCommandManager();
+
+  /**
+   * This allows chrome to override the default choice of whether touch events
+   * are available on a specific docshell. Possible values are listed below.
+   */
+  attribute unsigned long touchEventsOverride;
+  /**
+   * Override platform/pref default behaviour and force-disable touch events.
+   */
+  const unsigned long TOUCHEVENTS_OVERRIDE_DISABLED = 0;
+  /**
+   * Override platform/pref default behaviour and force-enable touch events.
+   */
+  const unsigned long TOUCHEVENTS_OVERRIDE_ENABLED = 1;
+  /**
+   * Don't override the platform/pref default behaviour for touch events.
+   */
+  const unsigned long TOUCHEVENTS_OVERRIDE_NONE = 2;
 };
--- a/docshell/test/browser/browser.ini
+++ b/docshell/test/browser/browser.ini
@@ -79,15 +79,16 @@ skip-if = buildapp == 'mulet'
 [browser_uriFixupAlternateRedirects.js]
 support-files =
   redirect_to_example.sjs
 [browser_loadDisallowInherit.js]
 [browser_loadURI.js]
 [browser_multiple_pushState.js]
 [browser_onbeforeunload_navigation.js]
 [browser_search_notification.js]
-[browser_ua_emulation.js]
+[browser_tab_touch_events.js]
 [browser_timelineMarkers-01.js]
 [browser_timelineMarkers-02.js]
 skip-if = true # Bug 1220415
 [browser_timelineMarkers-03.js]
 [browser_timelineMarkers-04.js]
 [browser_timelineMarkers-05.js]
+[browser_ua_emulation.js]
new file mode 100644
--- /dev/null
+++ b/docshell/test/browser/browser_tab_touch_events.js
@@ -0,0 +1,64 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(function*() {
+  yield openUrl("data:text/html;charset=utf-8,<iframe id='test-iframe'></iframe>");
+
+  let docshell = content.QueryInterface(Ci.nsIInterfaceRequestor)
+                        .getInterface(Ci.nsIWebNavigation)
+                        .QueryInterface(Ci.nsIDocShell);
+
+  is(docshell.touchEventsOverride, Ci.nsIDocShell.TOUCHEVENTS_OVERRIDE_NONE,
+    "touchEventsOverride flag should be initially set to NONE");
+
+  docshell.touchEventsOverride = Ci.nsIDocShell.TOUCHEVENTS_OVERRIDE_DISABLED;
+  is(docshell.touchEventsOverride, Ci.nsIDocShell.TOUCHEVENTS_OVERRIDE_DISABLED,
+    "touchEventsOverride flag should be changed to DISABLED");
+
+  let frameWin = content.document.querySelector("#test-iframe").contentWindow;
+  docshell = frameWin.QueryInterface(Ci.nsIInterfaceRequestor)
+                     .getInterface(Ci.nsIWebNavigation)
+                     .QueryInterface(Ci.nsIDocShell);
+  is(docshell.touchEventsOverride, Ci.nsIDocShell.TOUCHEVENTS_OVERRIDE_DISABLED,
+    "touchEventsOverride flag should be passed on to frames.");
+
+  let newFrame = content.document.createElement("iframe");
+  content.document.body.appendChild(newFrame);
+
+  let newFrameWin = newFrame.contentWindow;
+  docshell = newFrameWin.QueryInterface(Ci.nsIInterfaceRequestor)
+                        .getInterface(Ci.nsIWebNavigation)
+                        .QueryInterface(Ci.nsIDocShell);
+  is(docshell.touchEventsOverride, Ci.nsIDocShell.TOUCHEVENTS_OVERRIDE_DISABLED,
+    "Newly created frames should use the new touchEventsOverride flag");
+
+  newFrameWin.location.reload();
+  yield waitForEvent(newFrameWin, "load");
+
+  is(docshell.touchEventsOverride, Ci.nsIDocShell.TOUCHEVENTS_OVERRIDE_DISABLED,
+    "New touchEventsOverride flag should persist across reloads");
+
+  gBrowser.removeCurrentTab();
+});
+
+function waitForEvent(target, event) {
+  return new Promise(function(resolve) {
+    target.addEventListener(event, resolve);
+  });
+}
+
+function openUrl(url) {
+  return new Promise(function(resolve, reject) {
+    window.focus();
+
+    let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
+    let linkedBrowser = tab.linkedBrowser;
+
+    linkedBrowser.addEventListener("load", function onload() {
+      linkedBrowser.removeEventListener("load", onload, true);
+      resolve(tab);
+    }, true);
+  });
+}
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -8342,16 +8342,35 @@ nsContentUtils::SetFetchReferrerURIWithP
   net::ReferrerPolicy referrerPolicy = aReferrerPolicy;
   if (referrerPolicy == net::RP_Default) {
     referrerPolicy = aDoc->GetReferrerPolicy();
   }
   return aChannel->SetReferrerWithPolicy(referrerURI, referrerPolicy);
 }
 
 // static
+net::ReferrerPolicy
+nsContentUtils::GetReferrerPolicyFromHeader(const nsAString& aHeader)
+{
+  // Multiple headers could be concatenated into one comma-separated
+  // list of policies. Need to tokenize the multiple headers.
+  nsCharSeparatedTokenizer tokenizer(aHeader, ',');
+  nsAutoString token;
+  net::ReferrerPolicy referrerPolicy = mozilla::net::RP_Unset;
+  while (tokenizer.hasMoreTokens()) {
+    token = tokenizer.nextToken();
+    net::ReferrerPolicy policy = net::ReferrerPolicyFromString(token);
+    if (policy != net::RP_Unset) {
+      referrerPolicy = policy;
+    }
+  }
+  return referrerPolicy;
+}
+
+// static
 bool
 nsContentUtils::PushEnabled(JSContext* aCx, JSObject* aObj)
 {
   if (NS_IsMainThread()) {
     return Preferences::GetBool("dom.push.enabled", false);
   }
 
   using namespace workers;
@@ -9207,8 +9226,48 @@ nsContentUtils::GetPresentationURL(nsIDo
   nsCOMPtr<nsIDOMElement> topFrameElement;
   loadContext->GetTopFrameElement(getter_AddRefs(topFrameElement));
   if (!topFrameElement) {
     return;
   }
 
   topFrameElement->GetAttribute(NS_LITERAL_STRING("mozpresentation"), aPresentationUrl);
 }
+
+/* static */ nsIDocShell*
+nsContentUtils::GetDocShellForEventTarget(EventTarget* aTarget)
+{
+  nsCOMPtr<nsINode> node(do_QueryInterface(aTarget));
+  nsIDocument* doc = nullptr;
+  nsIDocShell* docShell = nullptr;
+
+  if (node) {
+    doc = node->OwnerDoc();
+    if (!doc->GetDocShell()) {
+      bool ignore;
+      nsCOMPtr<nsPIDOMWindowInner> window =
+        do_QueryInterface(doc->GetScriptHandlingObject(ignore));
+      if (window) {
+        doc = window->GetExtantDoc();
+      }
+    }
+  } else {
+    nsCOMPtr<nsPIDOMWindowInner> window(do_QueryInterface(aTarget));
+    if (window) {
+      doc = window->GetExtantDoc();
+    }
+  }
+
+  if (!doc) {
+    nsCOMPtr<DOMEventTargetHelper> helper(do_QueryInterface(aTarget));
+    if (helper) {
+      if (nsPIDOMWindowInner* window = helper->GetOwner()) {
+        doc = window->GetExtantDoc();
+      }
+    }
+  }
+
+  if (doc) {
+    docShell = doc->GetDocShell();
+  }
+
+  return docShell;
+}
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2573,16 +2573,25 @@ public:
    *
    * https://w3c.github.io/webappsec/specs/referrer-policy/#determine-requests-referrer
    */
   static nsresult SetFetchReferrerURIWithPolicy(nsIPrincipal* aPrincipal,
                                                 nsIDocument* aDoc,
                                                 nsIHttpChannel* aChannel,
                                                 mozilla::net::ReferrerPolicy aReferrerPolicy);
 
+    /*
+   * Parse a referrer policy from a Referrer-Policy header
+   * https://www.w3.org/TR/referrer-policy/#parse-referrer-policy-from-header
+   *
+   * @param aHeader the response's Referrer-Policy header to parse
+   * @return referrer policy from the response header.
+   */
+  static mozilla::net::ReferrerPolicy GetReferrerPolicyFromHeader(const nsAString& aHeader);
+
   static bool PushEnabled(JSContext* aCx, JSObject* aObj);
 
   static bool IsNonSubresourceRequest(nsIChannel* aChannel);
 
   static uint32_t CookiesBehavior()
   {
     return sCookiesBehavior;
   }
@@ -2637,16 +2646,21 @@ public:
   static void SetScrollbarsVisibility(nsIDocShell* aDocShell, bool aVisible);
 
   /*
    * Return the associated presentation URL of the presented content.
    * Will return empty string if the docshell is not in a presented content.
    */
   static void GetPresentationURL(nsIDocShell* aDocShell, nsAString& aPresentationUrl);
 
+  /*
+   * Try to find the docshell corresponding to the given event target.
+   */
+  static nsIDocShell* GetDocShellForEventTarget(mozilla::dom::EventTarget* aTarget);
+
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3780,16 +3780,25 @@ nsDocument::SetHeaderData(nsIAtom* aHead
     // referrer policy to policy
     if (policy != mozilla::net::RP_Unset) {
       // Referrer policy spec (section 6.1) says that we always use the newest
       // referrer policy we find
       mReferrerPolicy = policy;
       mReferrerPolicySet = true;
     }
   }
+
+  if (aHeaderField == nsGkAtoms::headerReferrerPolicy && !aData.IsEmpty()) {
+     ReferrerPolicy policy = nsContentUtils::GetReferrerPolicyFromHeader(aData);
+    if (policy != mozilla::net::RP_Unset) {
+      mReferrerPolicy = policy;
+      mReferrerPolicySet = true;
+    }
+  }
+
 }
 void
 nsDocument::TryChannelCharset(nsIChannel *aChannel,
                               int32_t& aCharsetSource,
                               nsACString& aCharset,
                               nsHtml5TreeOpExecutor* aExecutor)
 {
   if (aChannel) {
@@ -8721,16 +8730,17 @@ nsDocument::RetrieveRelevantHeaders(nsIC
     static const char *const headers[] = {
       "default-style",
       "content-style-type",
       "content-language",
       "content-disposition",
       "refresh",
       "x-dns-prefetch-control",
       "x-frame-options",
+      "referrer-policy",
       // add more http headers if you need
       // XXXbz don't add content-location support without reading bug
       // 238654 and its dependencies/dups first.
       0
     };
 
     nsAutoCString headerVal;
     const char *const *name = headers;
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -1730,17 +1730,18 @@ nsMessageManagerScriptExecutor::LoadScri
   }
 
   JS::Rooted<JSObject*> global(rt, mGlobal->GetJSObject());
   if (global) {
     AutoEntryScript aes(global, "message manager script load");
     JSContext* cx = aes.cx();
     if (script) {
       if (aRunInGlobalScope) {
-        JS::CloneAndExecuteScript(cx, script);
+        JS::RootedValue rval(cx);
+        JS::CloneAndExecuteScript(cx, script, &rval);
       } else {
         JS::Rooted<JSObject*> scope(cx);
         bool ok = js::ExecuteInGlobalAndReturnScope(cx, global, script, &scope);
         if (ok) {
           // Force the scope to stay alive.
           mAnonymousGlobalScopes.AppendElement(scope);
         }
       }
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -594,16 +594,17 @@ GK_ATOM(menugroup, "menugroup")
 GK_ATOM(menuitem, "menuitem")
 GK_ATOM(menulist, "menulist")
 GK_ATOM(menupopup, "menupopup")
 GK_ATOM(menuseparator, "menuseparator")
 GK_ATOM(message, "message")
 GK_ATOM(meta, "meta")
 GK_ATOM(referrer, "referrer")
 GK_ATOM(referrerpolicy, "referrerpolicy")
+GK_ATOM(headerReferrerPolicy, "referrer-policy")
 GK_ATOM(meter, "meter")
 GK_ATOM(method, "method")
 GK_ATOM(middle, "middle")
 GK_ATOM(min, "min")
 GK_ATOM(minheight, "minheight")
 GK_ATOM(minimum_scale, "minimum-scale")
 GK_ATOM(minpos, "minpos")
 GK_ATOM(minusSign, "minus-sign")
--- a/dom/base/nsIScriptElement.h
+++ b/dom/base/nsIScriptElement.h
@@ -46,29 +46,30 @@ public:
                      // behave like script-created scripts.
       mCreatorParser(nullptr)
   {
   }
 
   /**
    * Content type identifying the scripting language. Can be empty, in
    * which case javascript will be assumed.
+   * Return false if type attribute is not found.
    */
-  virtual void GetScriptType(nsAString& type) = 0;
-    
+  virtual bool GetScriptType(nsAString& type) = 0;
+
   /**
    * Location of script source text. Can return null, in which case
    * this is assumed to be an inline script element.
    */
   nsIURI* GetScriptURI()
   {
     NS_PRECONDITION(mFrozen, "Not ready for this call yet!");
     return mUri;
   }
-  
+
   /**
    * Script source text for inline script elements.
    */
   virtual void GetScriptText(nsAString& text) = 0;
 
   virtual void GetScriptCharset(nsAString& charset) = 0;
 
   /**
@@ -88,17 +89,17 @@ public:
   }
 
   /**
    * Is the script async. Currently only supported by HTML scripts.
    */
   bool GetScriptAsync()
   {
     NS_PRECONDITION(mFrozen, "Not ready for this call yet!");
-    return mAsync;  
+    return mAsync;
   }
 
   /**
    * Is the script an external script?
    */
   bool GetScriptExternal()
   {
     NS_PRECONDITION(mFrozen, "Not ready for this call yet!");
@@ -193,17 +194,17 @@ public:
    */
   void EndEvaluating()
   {
     nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
     if (parser) {
       parser->EndEvaluatingParserInsertedScript();
     }
   }
-  
+
   /**
    * Retrieves a pointer to the creator parser if this has one or null if not
    */
   already_AddRefed<nsIParser> GetCreatorParser()
   {
     nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
     return parser.forget();
   }
@@ -259,69 +260,69 @@ protected:
    *         loaded
    */
   virtual bool MaybeProcessScript() = 0;
 
   /**
    * The start line number of the script.
    */
   uint32_t mLineNumber;
-  
+
   /**
    * The "already started" flag per HTML5.
    */
   bool mAlreadyStarted;
-  
+
   /**
    * The script didn't have an end tag.
    */
   bool mMalformed;
-  
+
   /**
    * False if parser-inserted but the parser hasn't triggered running yet.
    */
   bool mDoneAddingChildren;
 
   /**
    * If true, the .async property returns true instead of reflecting the
    * content attribute.
    */
   bool mForceAsync;
 
   /**
    * Whether src, defer and async are frozen.
    */
   bool mFrozen;
-  
+
   /**
    * The effective deferredness.
    */
   bool mDefer;
-  
+
   /**
    * The effective asyncness.
    */
   bool mAsync;
-  
+
   /**
    * The effective externalness. A script can be external with mUri being null
    * if the src attribute contained an invalid URL string.
    */
   bool mExternal;
 
   /**
    * Whether this element was parser-created.
    */
   mozilla::dom::FromParser mParserCreated;
 
   /**
    * The effective src (or null if no src).
    */
   nsCOMPtr<nsIURI> mUri;
-  
+
   /**
    * The creator parser of a non-defer, non-async parser-inserted script.
    */
   nsWeakPtr mCreatorParser;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptElement, NS_ISCRIPTELEMENT_IID)
 
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -190,17 +190,17 @@ nsJSUtils::EvaluateString(JSContext* aCx
       if (!JS_WrapObject(aCx, scopeChain[i])) {
         ok = false;
         break;
       }
     }
 
     if (ok && aOffThreadToken) {
       JS::Rooted<JSScript*>
-        script(aCx, JS::FinishOffThreadScript(aCx, JS_GetRuntime(aCx), *aOffThreadToken));
+        script(aCx, JS::FinishOffThreadScript(aCx, *aOffThreadToken));
       *aOffThreadToken = nullptr; // Mark the token as having been finished.
       if (script) {
         ok = JS_ExecuteScript(aCx, scopeChain, script);
       } else {
         ok = false;
       }
     } else if (ok) {
       ok = JS::Evaluate(aCx, scopeChain, aCompileOptions, aSrcBuf, aRetValue);
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -703,18 +703,17 @@ nsScriptLoader::CreateModuleScript(nsMod
       masterScriptUpdater.emplace(master->ScriptLoader(),
                                   aRequest->mElement);
     }
 
     JSContext* cx = aes.cx();
     JS::Rooted<JSObject*> module(cx);
 
     if (aRequest->mWasCompiledOMT) {
-      module = JS::FinishOffThreadModule(cx, xpc::GetJSRuntime(),
-                                         aRequest->mOffThreadToken);
+      module = JS::FinishOffThreadModule(cx, aRequest->mOffThreadToken);
       aRequest->mOffThreadToken = nullptr;
       rv = module ? NS_OK : NS_ERROR_FAILURE;
     } else {
       JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
 
       JS::CompileOptions options(cx);
       FillCompileOptionsForRequest(aes, aRequest, global, &options);
 
@@ -1272,26 +1271,27 @@ nsScriptLoader::ProcessScriptElement(nsI
     return false;
   }
 
   JSVersion version = JSVERSION_DEFAULT;
 
   // Check the type attribute to determine language and version.
   // If type exists, it trumps the deprecated 'language='
   nsAutoString type;
-  aElement->GetScriptType(type);
+  bool hasType = aElement->GetScriptType(type);
+
   nsScriptKind scriptKind = nsScriptKind::Classic;
   if (!type.IsEmpty()) {
     // Support type="module" only for chrome documents.
     if (nsContentUtils::IsChromeDoc(mDocument) && type.LowerCaseEqualsASCII("module")) {
       scriptKind = nsScriptKind::Module;
     } else {
       NS_ENSURE_TRUE(ParseTypeAttribute(type, &version), false);
     }
-  } else {
+  } else if (!hasType) {
     // no 'type=' element
     // "language" is a deprecated attribute of HTML, so we check it only for
     // HTML script elements.
     if (scriptContent->IsHTMLElement()) {
       nsAutoString language;
       scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::language, language);
       if (!language.IsEmpty()) {
         if (!nsContentUtils::IsJavaScriptLanguage(language)) {
@@ -1824,17 +1824,18 @@ nsScriptLoader::ProcessRequest(nsScriptL
   }
 
   if (aRequest->mOffThreadToken) {
     // The request was parsed off-main-thread, but the result of the off
     // thread parse was not actually needed to process the request
     // (disappearing window, some other error, ...). Finish the
     // request to avoid leaks in the JS engine.
     MOZ_ASSERT(!aRequest->IsModuleRequest());
-    JS::FinishOffThreadScript(nullptr, xpc::GetJSRuntime(), aRequest->mOffThreadToken);
+    JSContext* cx = JS_GetContext(xpc::GetJSRuntime());
+    JS::CancelOffThreadScript(cx, aRequest->mOffThreadToken);
     aRequest->mOffThreadToken = nullptr;
   }
 
   // Free any source data.
   free(aRequest->mScriptTextBuf);
   aRequest->mScriptTextBuf = nullptr;
   aRequest->mScriptTextLength = 0;
 
--- a/dom/base/test/TestGetURL.cpp
+++ b/dom/base/test/TestGetURL.cpp
@@ -39,17 +39,17 @@ nsresult TestGetURL(const nsCString& aUR
   nsCOMPtr<nsIScriptSecurityManager> secman =
     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
   TEST_ENSURE_SUCCESS(rv, "Couldn't get script security manager!");
 
   nsCOMPtr<nsIPrincipal> systemPrincipal;
   rv = secman->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
   TEST_ENSURE_SUCCESS(rv, "Couldn't get system principal!");
 
-  rv = xhr->Init(systemPrincipal, nullptr, nullptr, nullptr, nullptr);
+  rv = xhr->Init(systemPrincipal, nullptr, nullptr, nullptr);
   TEST_ENSURE_SUCCESS(rv, "Couldn't initialize the XHR!");
 
   rv = xhr->Open(getString, aURL, false, empty, empty);
   TEST_ENSURE_SUCCESS(rv, "OpenRequest failed!");
 
   rv = xhr->Send(nullptr);
   TEST_ENSURE_SUCCESS(rv, "Send failed!");
 
--- a/dom/base/test/TestNativeXMLHttpRequest.cpp
+++ b/dom/base/test/TestNativeXMLHttpRequest.cpp
@@ -49,17 +49,17 @@ nsresult TestNativeXMLHttpRequest()
   nsCOMPtr<nsIScriptSecurityManager> secman =
     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
   TEST_ENSURE_SUCCESS(rv, "Couldn't get script security manager!");
 
   nsCOMPtr<nsIPrincipal> systemPrincipal;
   rv = secman->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
   TEST_ENSURE_SUCCESS(rv, "Couldn't get system principal!");
 
-  rv = xhr->Init(systemPrincipal, nullptr, nullptr, nullptr, nullptr);
+  rv = xhr->Init(systemPrincipal, nullptr, nullptr, nullptr);
   TEST_ENSURE_SUCCESS(rv, "Couldn't initialize the XHR!");
 
   rv = xhr->Open(getString, testURL, false, empty, empty);
   TEST_ENSURE_SUCCESS(rv, "Open failed!");
 
   rv = xhr->Send(nullptr);
   TEST_ENSURE_SUCCESS(rv, "Send failed!");
 
--- a/dom/bindings/AtomList.h
+++ b/dom/bindings/AtomList.h
@@ -11,19 +11,17 @@
 #include "mozilla/dom/GeneratedAtomList.h"
 
 namespace mozilla {
 namespace dom {
 
 template<class T>
 T* GetAtomCache(JSContext* aCx)
 {
-  JSRuntime* rt = JS_GetRuntime(aCx);
-
-  auto atomCache = static_cast<PerThreadAtomCache*>(JS_GetRuntimePrivate(rt));
+  auto atomCache = static_cast<PerThreadAtomCache*>(JS_GetContextPrivate(aCx));
 
   return static_cast<T*>(atomCache);
 }
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_AtomList_h
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -3905,38 +3905,37 @@ CanvasRenderingContext2D::DrawOrMeasureT
                                             float aX,
                                             float aY,
                                             const Optional<double>& aMaxWidth,
                                             TextDrawOperation aOp,
                                             float* aWidth)
 {
   nsresult rv;
 
-  // spec isn't clear on what should happen if aMaxWidth <= 0, so
-  // treat it as an invalid argument
-  // technically, 0 should be an invalid value as well, but 0 is the default
-  // arg, and there is no way to tell if the default was used
-  if (aMaxWidth.WasPassed() && aMaxWidth.Value() < 0)
-    return NS_ERROR_INVALID_ARG;
-
   if (!mCanvasElement && !mDocShell) {
     NS_WARNING("Canvas element must be non-null or a docshell must be provided");
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   if (!presShell)
     return NS_ERROR_FAILURE;
 
   nsIDocument* document = presShell->GetDocument();
 
   // replace all the whitespace characters with U+0020 SPACE
   nsAutoString textToDraw(aRawText);
   TextReplaceWhitespaceCharacters(textToDraw);
 
+  // According to spec, the API should return an empty array if maxWidth was provided
+  // but is less than or equal to zero or equal to NaN.
+  if (aMaxWidth.WasPassed() && (aMaxWidth.Value() <= 0 || IsNaN(aMaxWidth.Value()))) {
+    textToDraw.Truncate();
+  }
+
   // for now, default to ltr if not in doc
   bool isRTL = false;
 
   RefPtr<nsStyleContext> canvasStyle;
   if (mCanvasElement && mCanvasElement->IsInUncomposedDoc()) {
     // try to find the closest context
     canvasStyle =
       nsComputedDOMStyle::GetStyleContextForElement(mCanvasElement,
--- a/dom/canvas/TexUnpackBlob.cpp
+++ b/dom/canvas/TexUnpackBlob.cpp
@@ -15,22 +15,22 @@
 #include "WebGLContext.h"
 #include "WebGLTexelConversions.h"
 #include "WebGLTexture.h"
 
 namespace mozilla {
 namespace webgl {
 
 static bool
-UnpackFormatHasAlpha(GLenum unpackFormat)
+UnpackFormatHasColorAndAlpha(GLenum unpackFormat)
 {
     switch (unpackFormat) {
-    case LOCAL_GL_ALPHA:
     case LOCAL_GL_LUMINANCE_ALPHA:
     case LOCAL_GL_RGBA:
+    case LOCAL_GL_SRGB_ALPHA:
         return true;
 
     default:
         return false;
     }
 }
 
 static WebGLTexelFormat
@@ -211,17 +211,17 @@ TexUnpackBlob::ConvertIfNeeded(WebGLCont
         return false;
     }
 
     //////
 
     const auto dstFormat = FormatForPackingInfo(pi);
 
     bool premultMatches = (mIsSrcPremult == isDstPremult);
-    if (!UnpackFormatHasAlpha(dstDUI->unpackFormat)) {
+    if (!UnpackFormatHasColorAndAlpha(dstDUI->unpackFormat)) {
         premultMatches = true;
     }
 
     const bool needsPixelConversion = (srcFormat != dstFormat || !premultMatches);
     const bool originsMatch = (srcOrigin == dstOrigin);
 
     MOZ_ASSERT_IF(!needsPixelConversion, srcBPP == dstBPP);
 
--- a/dom/canvas/WebGLExtensionVertexArray.cpp
+++ b/dom/canvas/WebGLExtensionVertexArray.cpp
@@ -20,56 +20,44 @@ WebGLExtensionVertexArray::WebGLExtensio
 
 WebGLExtensionVertexArray::~WebGLExtensionVertexArray()
 {
 }
 
 already_AddRefed<WebGLVertexArray>
 WebGLExtensionVertexArray::CreateVertexArrayOES()
 {
-    if (mIsLost) {
-        mContext->ErrorInvalidOperation("%s: Extension is lost.",
-                                        "createVertexArrayOES");
+    if (mIsLost)
         return nullptr;
-    }
 
     return mContext->CreateVertexArray();
 }
 
 void
 WebGLExtensionVertexArray::DeleteVertexArrayOES(WebGLVertexArray* array)
 {
-    if (mIsLost) {
-        mContext->ErrorInvalidOperation("%s: Extension is lost.",
-                                        "deleteVertexArrayOES");
+    if (mIsLost)
         return;
-    }
 
     mContext->DeleteVertexArray(array);
 }
 
 bool
 WebGLExtensionVertexArray::IsVertexArrayOES(WebGLVertexArray* array)
 {
-    if (mIsLost) {
-        mContext->ErrorInvalidOperation("%s: Extension is lost.",
-                                        "isVertexArrayOES");
+    if (mIsLost)
         return false;
-    }
 
     return mContext->IsVertexArray(array);
 }
 
 void
 WebGLExtensionVertexArray::BindVertexArrayOES(WebGLVertexArray* array)
 {
-    if (mIsLost) {
-        mContext->ErrorInvalidOperation("%s: Extension is lost.",
-                                        "bindVertexArrayOES");
+    if (mIsLost)
         return;
-    }
 
     mContext->BindVertexArray(array);
 }
 
 IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionVertexArray, OES_vertex_array_object)
 
 } // namespace mozilla
--- a/dom/canvas/WebGLProgram.cpp
+++ b/dom/canvas/WebGLProgram.cpp
@@ -391,16 +391,20 @@ QueryProgramInfo(WebGLProgram* prog, gl:
                                                                            elemType,
                                                                            isArray,
                                                                            baseUserName,
                                                                            mappedName);
             info->transformFeedbackVaryings.push_back(activeInfo);
         }
     }
 
+    // Frag outputs
+
+    prog->EnumerateFragOutputs(info->fragDataMap);
+
     return info.forget();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* prog)
     : prog(prog)
 { }
@@ -627,19 +631,19 @@ WebGLProgram::GetFragDataLocation(const 
         return -1;
 
     if (!IsLinked()) {
         mContext->ErrorInvalidOperation("getFragDataLocation: `program` must be linked.");
         return -1;
     }
 
     const NS_LossyConvertUTF16toASCII userName(userName_wide);
+    nsCString mappedName;
 
-    nsCString mappedName;
-    if (!FindActiveOutputMappedNameByUserName(userName, &mappedName)) {
+    if (!LinkInfo()->FindFragData(userName, &mappedName)) {
         mappedName = userName;
     }
 
     gl::GLContext* gl = mContext->GL();
     gl->MakeCurrent();
 
     return gl->fGetFragDataLocation(mGLName, mappedName.BeginReading());
 }
@@ -1185,27 +1189,16 @@ WebGLProgram::LinkAndUpdate()
     if (!ok)
         return;
 
     mMostRecentLinkInfo = QueryProgramInfo(this, gl);
     MOZ_RELEASE_ASSERT(mMostRecentLinkInfo, "GFX: most recent link info not set.");
 }
 
 bool
-WebGLProgram::FindActiveOutputMappedNameByUserName(const nsACString& userName,
-                                                   nsCString* const out_mappedName) const
-{
-    if (mFragShader->FindActiveOutputMappedNameByUserName(userName, out_mappedName)) {
-        return true;
-    }
-
-    return false;
-}
-
-bool
 WebGLProgram::FindAttribUserNameByMappedName(const nsACString& mappedName,
                                              nsDependentCString* const out_userName) const
 {
     if (mVertShader->FindAttribUserNameByMappedName(mappedName, out_userName))
         return true;
 
     return false;
 }
@@ -1304,16 +1297,24 @@ WebGLProgram::FindUniformBlockByMappedNa
         return true;
 
     if (mFragShader->FindUniformBlockByMappedName(mappedName, out_userName, out_isArray))
         return true;
 
     return false;
 }
 
+void
+WebGLProgram::EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const
+{
+    MOZ_ASSERT(mFragShader);
+
+    mFragShader->EnumerateFragOutputs(out_FragOutputs);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 bool
 webgl::LinkedProgramInfo::FindAttrib(const nsCString& baseUserName,
                                      const webgl::AttribInfo** const out) const
 {
     for (const auto& attrib : attribs) {
         if (attrib.mActiveInfo->mBaseUserName == baseUserName) {
--- a/dom/canvas/WebGLProgram.h
+++ b/dom/canvas/WebGLProgram.h
@@ -85,23 +85,39 @@ struct LinkedProgramInfo final
     std::vector<const UniformBlockInfo*> uniformBlocks; // Owns its contents.
     std::vector<RefPtr<WebGLActiveInfo>> transformFeedbackVaryings;
 
     // Needed for draw call validation.
     std::vector<UniformInfo*> uniformSamplers;
 
     //////
 
+    // The maps for the frag data names to the translated names.
+    std::map<nsCString, const nsCString> fragDataMap;
+
     explicit LinkedProgramInfo(WebGLProgram* prog);
     ~LinkedProgramInfo();
 
     bool FindAttrib(const nsCString& baseUserName, const AttribInfo** const out) const;
     bool FindUniform(const nsCString& baseUserName, UniformInfo** const out) const;
     bool FindUniformBlock(const nsCString& baseUserName,
                           const UniformBlockInfo** const out) const;
+
+    bool
+    FindFragData(const nsCString& baseUserName,
+                 nsCString* const out_baseMappedName) const
+    {
+        const auto itr = fragDataMap.find(baseUserName);
+        if (itr == fragDataMap.end()) {
+            return false;
+        }
+
+        *out_baseMappedName = itr->second;
+        return true;
+    }
 };
 
 } // namespace webgl
 
 class WebGLProgram final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLProgram>
     , public LinkedListElement<WebGLProgram>
@@ -139,34 +155,34 @@ public:
     void UniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) const;
 
     void LinkProgram();
     bool UseProgram() const;
     void ValidateProgram() const;
 
     ////////////////
 
-    bool FindActiveOutputMappedNameByUserName(const nsACString& userName,
-                                              nsCString* const out_mappedName) const;
     bool FindAttribUserNameByMappedName(const nsACString& mappedName,
                                         nsDependentCString* const out_userName) const;
     bool FindVaryingByMappedName(const nsACString& mappedName,
                                  nsCString* const out_userName,
                                  bool* const out_isArray) const;
     bool FindUniformByMappedName(const nsACString& mappedName,
                                  nsCString* const out_userName,
                                  bool* const out_isArray) const;
     bool FindUniformBlockByMappedName(const nsACString& mappedName,
                                       nsCString* const out_userName,
                                       bool* const out_isArray) const;
 
     void TransformFeedbackVaryings(const dom::Sequence<nsString>& varyings,
                                    GLenum bufferMode);
     already_AddRefed<WebGLActiveInfo> GetTransformFeedbackVarying(GLuint index);
 
+    void EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const;
+
     bool IsLinked() const { return mMostRecentLinkInfo; }
 
     const webgl::LinkedProgramInfo* LinkInfo() const {
         return mMostRecentLinkInfo.get();
     }
 
     WebGLContext* GetParentObject() const {
         return mContext;
--- a/dom/canvas/WebGLShader.cpp
+++ b/dom/canvas/WebGLShader.cpp
@@ -325,32 +325,16 @@ WebGLShader::BindAttribLocation(GLuint p
     const std::string* mappedNameStr = &userNameStr;
     if (mValidator)
         mValidator->FindAttribMappedNameByUserName(userNameStr, &mappedNameStr);
 
     mContext->gl->fBindAttribLocation(prog, index, mappedNameStr->c_str());
 }
 
 bool
-WebGLShader::FindActiveOutputMappedNameByUserName(const nsACString& userName,
-                                                  nsCString* const out_mappedName) const
-{
-    if (!mValidator)
-        return false;
-
-    const std::string userNameStr(userName.BeginReading());
-    const std::string* mappedNameStr;
-    if (!mValidator->FindActiveOutputMappedNameByUserName(userNameStr, &mappedNameStr))
-        return false;
-
-    *out_mappedName = mappedNameStr->c_str();
-    return true;
-}
-
-bool
 WebGLShader::FindAttribUserNameByMappedName(const nsACString& mappedName,
                                             nsDependentCString* const out_userName) const
 {
     if (!mValidator)
         return false;
 
     const std::string mappedNameStr(mappedName.BeginReading());
     const std::string* userNameStr;
@@ -408,16 +392,27 @@ WebGLShader::FindUniformBlockByMappedNam
     if (!mValidator->FindUniformBlockByMappedName(mappedNameStr, &userNameStr))
         return false;
 
     *out_userName = userNameStr.c_str();
     return true;
 }
 
 void
+WebGLShader::EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const
+{
+    out_FragOutputs.clear();
+
+    if (!mValidator) {
+        return;
+    }
+    mValidator->EnumerateFragOutputs(out_FragOutputs);
+}
+
+void
 WebGLShader::ApplyTransformFeedbackVaryings(GLuint prog,
                                             const std::vector<nsCString>& varyings,
                                             GLenum bufferMode,
                                             std::vector<std::string>* out_mappedVaryings) const
 {
     MOZ_ASSERT(mType == LOCAL_GL_VERTEX_SHADER);
     MOZ_ASSERT(!varyings.empty());
     MOZ_ASSERT(out_mappedVaryings);
--- a/dom/canvas/WebGLShader.h
+++ b/dom/canvas/WebGLShader.h
@@ -47,30 +47,30 @@ public:
     void GetShaderTranslatedSource(nsAString* out) const;
     void ShaderSource(const nsAString& source);
 
     // Util funcs
     bool CanLinkTo(const WebGLShader* prev, nsCString* const out_log) const;
     size_t CalcNumSamplerUniforms() const;
     size_t NumAttributes() const;
     void BindAttribLocation(GLuint prog, const nsCString& userName, GLuint index) const;
-    bool FindActiveOutputMappedNameByUserName(const nsACString& userName,
-                                              nsCString* const out_mappedName) const;
     bool FindAttribUserNameByMappedName(const nsACString& mappedName,
                                         nsDependentCString* const out_userName) const;
     bool FindVaryingByMappedName(const nsACString& mappedName,
                                  nsCString* const out_userName,
                                  bool* const out_isArray) const;
     bool FindUniformByMappedName(const nsACString& mappedName,
                                  nsCString* const out_userName,
                                  bool* const out_isArray) const;
     bool FindUniformBlockByMappedName(const nsACString& mappedName,
                                       nsCString* const out_userName,
                                       bool* const out_isArray) const;
 
+    void EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const;
+
     bool IsCompiled() const {
         return mTranslationSuccessful && mCompilationSuccessful;
     }
 
     void ApplyTransformFeedbackVaryings(GLuint prog,
                                         const std::vector<nsCString>& varyings,
                                         GLenum bufferMode,
                                         std::vector<std::string>* out_mappedVaryings) const;
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ b/dom/canvas/WebGLShaderValidator.cpp
@@ -6,17 +6,16 @@
 #include "WebGLShaderValidator.h"
 
 #include "angle/ShaderLang.h"
 #include "gfxPrefs.h"
 #include "GLContext.h"
 #include "mozilla/Preferences.h"
 #include "MurmurHash3.h"
 #include "nsPrintfCString.h"
-#include "nsTArray.h"
 #include <string>
 #include <vector>
 #include "WebGLContext.h"
 
 namespace mozilla {
 namespace webgl {
 
 uint64_t
@@ -284,81 +283,127 @@ ShaderValidator::CanLinkTo(const ShaderV
                     *out_log = error;
                     return false;
                 }
 
                 break;
             }
         }
     }
+
+    const auto& vertVaryings = ShGetVaryings(prev->mHandle);
+    const auto& fragVaryings = ShGetVaryings(mHandle);
+    if (!vertVaryings || !fragVaryings) {
+        nsPrintfCString error("Could not create varying list.");
+        *out_log = error;
+        return false;
+    }
+
     {
-        const std::vector<sh::Varying>* vertPtr = ShGetVaryings(prev->mHandle);
-        const std::vector<sh::Varying>* fragPtr = ShGetVaryings(mHandle);
-        if (!vertPtr || !fragPtr) {
-            nsPrintfCString error("Could not create varying list.");
-            *out_log = error;
-            return false;
-        }
+        std::vector<ShVariableInfo> staticUseVaryingList;
 
-        nsTArray<ShVariableInfo> staticUseVaryingList;
-
-        for (auto itrFrag = fragPtr->begin(); itrFrag != fragPtr->end(); ++itrFrag) {
-            const ShVariableInfo varInfo = { itrFrag->type,
-                                             (int)itrFrag->elementCount() };
+        for (const auto& fragVarying : *fragVaryings) {
+            const ShVariableInfo varInfo = { fragVarying.type,
+                                             (int)fragVarying.elementCount() };
 
             static const char prefix[] = "gl_";
-            if (StartsWith(itrFrag->name, prefix)) {
-                if (itrFrag->staticUse)
-                    staticUseVaryingList.AppendElement(varInfo);
-
+            if (StartsWith(fragVarying.name, prefix)) {
+                if (fragVarying.staticUse) {
+                    staticUseVaryingList.push_back(varInfo);
+                }
                 continue;
             }
 
             bool definedInVertShader = false;
             bool staticVertUse = false;
 
-            for (auto itrVert = vertPtr->begin(); itrVert != vertPtr->end(); ++itrVert) {
-                if (itrVert->name != itrFrag->name)
+            for (const auto& vertVarying : *vertVaryings) {
+                if (vertVarying.name != fragVarying.name)
                     continue;
 
-                if (!itrVert->isSameVaryingAtLinkTime(*itrFrag)) {
+                if (!vertVarying.isSameVaryingAtLinkTime(fragVarying)) {
                     nsPrintfCString error("Varying `%s`is not linkable between"
                                           " attached shaders.",
-                                          itrFrag->name.c_str());
+                                          fragVarying.name.c_str());
                     *out_log = error;
                     return false;
                 }
 
                 definedInVertShader = true;
-                staticVertUse = itrVert->staticUse;
+                staticVertUse = vertVarying.staticUse;
                 break;
             }
 
-            if (!definedInVertShader && itrFrag->staticUse) {
+            if (!definedInVertShader && fragVarying.staticUse) {
                 nsPrintfCString error("Varying `%s` has static-use in the frag"
                                       " shader, but is undeclared in the vert"
-                                      " shader.", itrFrag->name.c_str());
+                                      " shader.", fragVarying.name.c_str());
                 *out_log = error;
                 return false;
             }
 
-            if (staticVertUse && itrFrag->staticUse)
-                staticUseVaryingList.AppendElement(varInfo);
+            if (staticVertUse && fragVarying.staticUse) {
+                staticUseVaryingList.push_back(varInfo);
+            }
         }
 
         if (!ShCheckVariablesWithinPackingLimits(mMaxVaryingVectors,
-                                                 staticUseVaryingList.Elements(),
-                                                 staticUseVaryingList.Length()))
+                                                 staticUseVaryingList.data(),
+                                                 staticUseVaryingList.size()))
         {
             *out_log = "Statically used varyings do not fit within packing limits. (see"
                        " GLSL ES Specification 1.0.17, p111)";
             return false;
         }
     }
 
+    {
+        bool isInvariant_Position = false;
+        bool isInvariant_PointSize = false;
+        bool isInvariant_FragCoord = false;
+        bool isInvariant_PointCoord = false;
+
+        for (const auto& varying : *vertVaryings) {
+            if (varying.name == "gl_Position") {
+                isInvariant_Position = varying.isInvariant;
+            } else if (varying.name == "gl_PointSize") {
+                isInvariant_PointSize = varying.isInvariant;
+            }
+        }
+
+        for (const auto& varying : *fragVaryings) {
+            if (varying.name == "gl_FragCoord") {
+                isInvariant_FragCoord = varying.isInvariant;
+            } else if (varying.name == "gl_PointCoord") {
+                isInvariant_PointCoord = varying.isInvariant;
+            }
+        }
+
+        ////
+
+        const auto fnCanBuiltInsLink = [](bool vertIsInvariant, bool fragIsInvariant) {
+            if (vertIsInvariant)
+                return true;
+
+            return !fragIsInvariant;
+        };
+
+        if (!fnCanBuiltInsLink(isInvariant_Position, isInvariant_FragCoord)) {
+            *out_log = "gl_Position must be invariant if gl_FragCoord is. (see GLSL ES"
+                       " Specification 1.0.17, p39)";
+            return false;
+        }
+
+        if (!fnCanBuiltInsLink(isInvariant_PointSize, isInvariant_PointCoord)) {
+            *out_log = "gl_PointSize must be invariant if gl_PointCoord is. (see GLSL ES"
+                       " Specification 1.0.17, p39)";
+            return false;
+        }
+    }
+
     return true;
 }
 
 size_t
 ShaderValidator::CalcNumSamplerUniforms() const
 {
     size_t accum = 0;
 
@@ -395,31 +440,16 @@ ShaderValidator::FindAttribUserNameByMap
             return true;
         }
     }
 
     return false;
 }
 
 bool
-ShaderValidator::FindActiveOutputMappedNameByUserName(const std::string& userName,
-                                                      const std::string** const out_mappedName) const
-{
-    const std::vector<sh::OutputVariable>& varibles = *ShGetOutputVariables(mHandle);
-    for (auto itr = varibles.begin(); itr != varibles.end(); ++itr) {
-        if (itr->name == userName) {
-            *out_mappedName = &(itr->mappedName);
-            return true;
-        }
-    }
-
-    return false;
-}
-
-bool
 ShaderValidator::FindAttribMappedNameByUserName(const std::string& userName,
                                                 const std::string** const out_mappedName) const
 {
     const std::vector<sh::Attribute>& attribs = *ShGetAttributes(mHandle);
     for (auto itr = attribs.begin(); itr != attribs.end(); ++itr) {
         if (itr->name == userName) {
             *out_mappedName = &(itr->mappedName);
             return true;
@@ -533,10 +563,23 @@ ShaderValidator::FindUniformBlockByMappe
             *out_userName = interface.name;
             return true;
         }
     }
 
     return false;
 }
 
+void
+ShaderValidator::EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const
+{
+    const auto* fragOutputs = ShGetOutputVariables(mHandle);
+
+    if (fragOutputs) {
+        for (const auto& fragOutput : *fragOutputs) {
+            out_FragOutputs.insert({nsCString(fragOutput.name.c_str()),
+                                    nsCString(fragOutput.mappedName.c_str())});
+        }
+    }
+}
+
 } // namespace webgl
 } // namespace mozilla
--- a/dom/canvas/WebGLShaderValidator.h
+++ b/dom/canvas/WebGLShaderValidator.h
@@ -43,32 +43,30 @@ public:
     void GetOutput(nsACString* out) const;
     bool CanLinkTo(const ShaderValidator* prev, nsCString* const out_log) const;
     size_t CalcNumSamplerUniforms() const;
     size_t NumAttributes() const;
 
     bool FindAttribUserNameByMappedName(const std::string& mappedName,
                                         const std::string** const out_userName) const;
 
-    bool FindActiveOutputMappedNameByUserName(const std::string& userName,
-                                              const std::string** const out_mappedName) const;
-
     bool FindAttribMappedNameByUserName(const std::string& userName,
                                         const std::string** const out_mappedName) const;
 
     bool FindVaryingMappedNameByUserName(const std::string& userName,
                                          const std::string** const out_mappedName) const;
 
     bool FindVaryingByMappedName(const std::string& mappedName,
                                  std::string* const out_userName,
                                  bool* const out_isArray) const;
     bool FindUniformByMappedName(const std::string& mappedName,
                                  std::string* const out_userName,
                                  bool* const out_isArray) const;
     bool FindUniformBlockByMappedName(const std::string& mappedName,
                                       std::string* const out_userName) const;
 
+    void EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const;
 };
 
 } // namespace webgl
 } // namespace mozilla
 
 #endif // WEBGL_SHADER_VALIDATOR_H_
--- a/dom/canvas/test/imagebitmap_extensions.js
+++ b/dom/canvas/test/imagebitmap_extensions.js
@@ -118,33 +118,33 @@ function testColorConversions() {
   return Promise.all([// From RGBA32
                       testColorConversion("RGBA32", "RGBA32"),
                       testColorConversion("RGBA32", "BGRA32"),
                       testColorConversion("RGBA32", "RGB24"),
                       testColorConversion("RGBA32", "BGR24"),
                       testColorConversion("RGBA32", "GRAY8"),
                       testColorConversion("RGBA32", "YUV444P"),
                       testColorConversion("RGBA32", "YUV422P"),
-                      testColorConversion("RGBA32", "YUV420P", 2),
+                      testColorConversion("RGBA32", "YUV420P"),
                       testColorConversion("RGBA32", "YUV420SP_NV12"),
                       testColorConversion("RGBA32", "YUV420SP_NV21"),
                       testColorConversion("RGBA32", "HSV", 0.01),
                       testColorConversion("RGBA32", "Lab", 0.5),
 
                       // From BGRA32
                       testColorConversion("BGRA32", "RGBA32"),
                       testColorConversion("BGRA32", "BGRA32"),
                       testColorConversion("BGRA32", "RGB24"),
                       testColorConversion("BGRA32", "BGR24"),
                       testColorConversion("BGRA32", "GRAY8"),
                       testColorConversion("BGRA32", "YUV444P", 3),
-                      testColorConversion("BGRA32", "YUV422P", 2),
-                      testColorConversion("BGRA32", "YUV420P", 2),
-                      testColorConversion("BGRA32", "YUV420SP_NV12", 2),
-                      testColorConversion("BGRA32", "YUV420SP_NV21", 2),
+                      testColorConversion("BGRA32", "YUV422P"),
+                      testColorConversion("BGRA32", "YUV420P"),
+                      testColorConversion("BGRA32", "YUV420SP_NV12"),
+                      testColorConversion("BGRA32", "YUV420SP_NV21"),
                       testColorConversion("BGRA32", "HSV", 0.01),
                       testColorConversion("BGRA32", "Lab", 0.5),
 
                       // From RGB24
                       testColorConversion("RGB24", "RGBA32"),
                       testColorConversion("RGB24", "BGRA32"),
                       testColorConversion("RGB24", "RGB24"),
                       testColorConversion("RGB24", "BGR24"),
@@ -173,73 +173,73 @@ function testColorConversions() {
 
                       // From YUV444P
                       testColorConversion("YUV444P", "RGBA32"),
                       testColorConversion("YUV444P", "BGRA32"),
                       testColorConversion("YUV444P", "RGB24"),
                       testColorConversion("YUV444P", "BGR24"),
                       testColorConversion("YUV444P", "GRAY8"),
                       testColorConversion("YUV444P", "YUV444P"),
-                      testColorConversion("YUV444P", "YUV422P", 4),
+                      testColorConversion("YUV444P", "YUV422P", 3),
                       testColorConversion("YUV444P", "YUV420P", 3),
                       testColorConversion("YUV444P", "YUV420SP_NV12", 3),
                       testColorConversion("YUV444P", "YUV420SP_NV21", 3),
                       testColorConversion("YUV444P", "HSV", 0.01),
                       testColorConversion("YUV444P", "Lab", 0.01),
 
                       // From YUV422P
                       testColorConversion("YUV422P", "RGBA32"),
-                      testColorConversion("YUV422P", "BGRA32", 2),
+                      testColorConversion("YUV422P", "BGRA32"),
                       testColorConversion("YUV422P", "RGB24"),
                       testColorConversion("YUV422P", "BGR24"),
                       testColorConversion("YUV422P", "GRAY8"),
                       testColorConversion("YUV422P", "YUV444P", 3),
                       testColorConversion("YUV422P", "YUV422P"),
                       testColorConversion("YUV422P", "YUV420P"),
                       testColorConversion("YUV422P", "YUV420SP_NV12"),
                       testColorConversion("YUV422P", "YUV420SP_NV21"),
                       testColorConversion("YUV422P", "HSV", 0.01),
                       testColorConversion("YUV422P", "Lab", 0.01),
 
                       // From YUV420P
-                      testColorConversion("YUV420P", "RGBA32", 2),
-                      testColorConversion("YUV420P", "BGRA32", 2),
+                      testColorConversion("YUV420P", "RGBA32"),
+                      testColorConversion("YUV420P", "BGRA32"),
                       testColorConversion("YUV420P", "RGB24"),
                       testColorConversion("YUV420P", "BGR24"),
                       testColorConversion("YUV420P", "GRAY8"),
                       testColorConversion("YUV420P", "YUV444P", 3),
-                      testColorConversion("YUV420P", "YUV422P", 1),
+                      testColorConversion("YUV420P", "YUV422P"),
                       testColorConversion("YUV420P", "YUV420P"),
                       testColorConversion("YUV420P", "YUV420SP_NV12"),
                       testColorConversion("YUV420P", "YUV420SP_NV21"),
                       testColorConversion("YUV420P", "HSV", 0.01),
                       testColorConversion("YUV420P", "Lab", 0.01),
 
                       // From NV12
                       testColorConversion("YUV420SP_NV12", "RGBA32"),
-                      testColorConversion("YUV420SP_NV12", "BGRA32", 2),
+                      testColorConversion("YUV420SP_NV12", "BGRA32"),
                       testColorConversion("YUV420SP_NV12", "RGB24"),
                       testColorConversion("YUV420SP_NV12", "BGR24"),
                       testColorConversion("YUV420SP_NV12", "GRAY8"),
                       testColorConversion("YUV420SP_NV12", "YUV444P", 3),
-                      testColorConversion("YUV420SP_NV12", "YUV422P", 1),
+                      testColorConversion("YUV420SP_NV12", "YUV422P"),
                       testColorConversion("YUV420SP_NV12", "YUV420P"),
                       testColorConversion("YUV420SP_NV12", "YUV420SP_NV12"),
                       testColorConversion("YUV420SP_NV12", "YUV420SP_NV21"),
                       testColorConversion("YUV420SP_NV12", "HSV", 0.01),
                       testColorConversion("YUV420SP_NV12", "Lab", 0.01),
 
                       // From NV21
                       testColorConversion("YUV420SP_NV21", "RGBA32"),
-                      testColorConversion("YUV420SP_NV21", "BGRA32", 2),
+                      testColorConversion("YUV420SP_NV21", "BGRA32"),
                       testColorConversion("YUV420SP_NV21", "RGB24"),
                       testColorConversion("YUV420SP_NV21", "BGR24"),
                       testColorConversion("YUV420SP_NV21", "GRAY8"),
                       testColorConversion("YUV420SP_NV21", "YUV444P", 3),
-                      testColorConversion("YUV420SP_NV21", "YUV422P", 1),
+                      testColorConversion("YUV420SP_NV21", "YUV422P"),
                       testColorConversion("YUV420SP_NV21", "YUV420P"),
                       testColorConversion("YUV420SP_NV21", "YUV420SP_NV12"),
                       testColorConversion("YUV420SP_NV21", "YUV420SP_NV21"),
                       testColorConversion("YUV420SP_NV21", "HSV", 0.01),
                       testColorConversion("YUV420SP_NV21", "Lab", 0.01),
 
                       // From HSV
                       testColorConversion("HSV", "RGBA32"),
--- a/dom/canvas/test/webgl-conf/generated-mochitest.ini
+++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini
@@ -5209,17 +5209,17 @@ skip-if = (os == 'android' || os == 'lin
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__glsl__misc__shader-with-while-loop.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__glsl__misc__shader-without-precision.frag.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__glsl__misc__shaders-with-constant-expression-loop-conditions.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__glsl__misc__shaders-with-invariance.html]
-fail-if = (os == 'mac') || (os == 'win')
+fail-if = (os == 'mac')
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__glsl__misc__shaders-with-mis-matching-uniforms.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__glsl__misc__shaders-with-mis-matching-varyings.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__glsl__misc__shaders-with-missing-varyings.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
 [generated/test_2_conformance__glsl__misc__shaders-with-name-conflicts.html]
@@ -5986,17 +5986,16 @@ fail-if = (os == 'mac' && os_version == 
 [generated/test_conformance__context__context-creation-and-destruction.html]
 [generated/test_conformance__context__context-creation.html]
 skip-if = (os == 'android')
 [generated/test_conformance__context__context-eviction-with-garbage-collection.html]
 skip-if = (os == 'android')
 [generated/test_conformance__context__context-hidden-alpha.html]
 [generated/test_conformance__context__context-lost-restored.html]
 [generated/test_conformance__context__context-lost.html]
-fail-if = 1
 [generated/test_conformance__context__context-release-upon-reload.html]
 skip-if = (os == 'android')
 [generated/test_conformance__context__context-release-with-workers.html]
 skip-if = (os == 'android')
 [generated/test_conformance__context__context-size-change.html]
 [generated/test_conformance__context__context-type-test.html]
 [generated/test_conformance__context__incorrect-context-object-behaviour.html]
 [generated/test_conformance__context__methods.html]
@@ -6344,17 +6343,17 @@ fail-if = (os == 'android')
 [generated/test_conformance__glsl__misc__shader-with-version-100.vert.html]
 [generated/test_conformance__glsl__misc__shader-with-version-120.vert.html]
 [generated/test_conformance__glsl__misc__shader-with-version-130.vert.html]
 [generated/test_conformance__glsl__misc__shader-with-webgl-identifier.vert.html]
 [generated/test_conformance__glsl__misc__shader-with-while-loop.html]
 [generated/test_conformance__glsl__misc__shader-without-precision.frag.html]
 [generated/test_conformance__glsl__misc__shaders-with-constant-expression-loop-conditions.html]
 [generated/test_conformance__glsl__misc__shaders-with-invariance.html]
-fail-if = 1
+fail-if = (os == 'mac')
 [generated/test_conformance__glsl__misc__shaders-with-mis-matching-uniforms.html]
 [generated/test_conformance__glsl__misc__shaders-with-mis-matching-varyings.html]
 [generated/test_conformance__glsl__misc__shaders-with-missing-varyings.html]
 [generated/test_conformance__glsl__misc__shaders-with-name-conflicts.html]
 [generated/test_conformance__glsl__misc__shaders-with-uniform-structs.html]
 [generated/test_conformance__glsl__misc__shaders-with-varyings.html]
 [generated/test_conformance__glsl__misc__shared.html]
 [generated/test_conformance__glsl__misc__struct-assign.html]
--- a/dom/canvas/test/webgl-conf/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini
@@ -27,20 +27,16 @@
 [DEFAULT]
 subsuite = webgl
 # Skip B2G for now, until we get a handle on the longer tail of emulator bugs.
 # Bug 1136181 disabled on Mulet for intermittent failures
 skip-if = os == 'b2g' || ((os == 'linux') && (buildapp == 'mulet'))
 
 [generated/test_..__always-fail.html]
 fail-if = 1
-[generated/test_conformance__context__context-lost.html]
-fail-if = 1
-[generated/test_conformance__glsl__misc__shaders-with-invariance.html]
-fail-if = 1
 
 ####################
 # Tests requesting non-local network connections.
 
 [generated/test_conformance__more__functions__readPixelsBadArgs.html]
 # (TODO) FATAL ERROR: Non-local network connections are disabled and a connection attempt to www.opengl.org (45.55.206.190) was made.
 skip-if = 1
 [generated/test_2_conformance__more__functions__readPixelsBadArgs.html]
@@ -170,18 +166,16 @@ fail-if = (os == 'mac') || (os == 'win')
 [generated/test_2_conformance2__buffers__buffer-copying-contents.html]
 fail-if = (os == 'mac') || (os == 'win')
 [generated/test_2_conformance2__reading__read-pixels-pack-parameters.html]
 fail-if = (os == 'mac') || (os == 'win')
 [generated/test_conformance__attribs__gl-vertexattribpointer.html]
 fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux')
 [generated/test_conformance__buffers__buffer-data-and-buffer-sub-data.html]
 fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux')
-[generated/test_2_conformance__glsl__misc__shaders-with-invariance.html]
-fail-if = (os == 'mac') || (os == 'win')
 [generated/test_2_conformance__textures__misc__tex-sub-image-2d-bad-args.html]
 fail-if = (os == 'mac') || (os == 'win')
 [generated/test_2_conformance2__misc__expando-loss-2.html]
 fail-if = (os == 'mac') || (os == 'win')
 [generated/test_conformance__ogles__GL__biuDepthRange__biuDepthRange_001_to_002.html]
 fail-if = (os == 'android') || (os == 'linux')
 [generated/test_conformance__ogles__GL__gl_FragCoord__gl_FragCoord_001_to_003.html]
 fail-if = (os == 'android') || (os == 'linux')
@@ -565,16 +559,20 @@ fail-if = (os == 'mac')
 [generated/test_2_conformance__glsl__variables__gl-pointcoord.html]
 fail-if = (os == 'mac')
 [generated/test_2_conformance2__state__gl-get-calls.html]
 fail-if = (os == 'mac')
 [generated/test_conformance__extensions__angle-instanced-arrays.html]
 fail-if = (os == 'mac')
 [generated/test_2_conformance__rendering__point-size.html]
 fail-if = (os == 'mac')
+[generated/test_conformance__glsl__misc__shaders-with-invariance.html]
+fail-if = (os == 'mac')
+[generated/test_2_conformance__glsl__misc__shaders-with-invariance.html]
+fail-if = (os == 'mac')
 
 [generated/test_2_conformance2__extensions__ext-color-buffer-float.html]
 skip-if = (os == 'mac' && debug)
 [generated/test_2_conformance__limits__gl-line-width.html]
 skip-if = (os == 'mac')
 [generated/test_2_conformance__misc__type-conversion-test.html]
 skip-if = (os == 'mac' && debug)
 [generated/test_2_conformance__state__gl-get-calls.html]
--- a/dom/canvas/test/webgl-mochitest/test_fuzzing_bugs.html
+++ b/dom/canvas/test/webgl-mochitest/test_fuzzing_bugs.html
@@ -77,20 +77,72 @@ function getFramebufferAttachmentParamet
   // The gl call should still work even though we use another gl context before.
   gl1.getFramebufferAttachmentParameter(gl1.FRAMEBUFFER,
                                         gl1.COLOR_ATTACHMENT0,
                                         gl1.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
 
   ok(true, 'WebGL test getFramebufferAttachmentParameter');
 }
 
+// Test to call getFragDataLocation() when the fragment shader is detatched.
+function getFragDataLocation_bug1259702() {
+  var canvas = document.createElement('canvas');
+
+  var gl = canvas.getContext('webgl2');
+
+  if (!gl) {
+    todo(false, 'WebGL2 is not supported');
+    return;
+  }
+
+  var program = gl.createProgram();
+
+  var vertexShaderSrc =
+    "void main(void) { \
+       gl_Position = vec4(1.0, 1.0, 1.0, 1.0); \
+    }";
+  var fragmentShaderSrc =
+    "void main(void) { \
+       gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); \
+    }";
+
+  var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+  var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+
+  gl.shaderSource(vertexShader, vertexShaderSrc);
+  gl.compileShader(vertexShader);
+  gl.attachShader(program, vertexShader);
+
+  gl.shaderSource(fragmentShader, fragmentShaderSrc);
+  gl.compileShader(fragmentShader);
+  gl.attachShader(program, fragmentShader);
+
+  gl.linkProgram(program);
+  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+    var lastError = gl.getProgramInfoLog(program);
+    ok(false, 'WebGL getFragDataLocation() test, error in linking:' +
+        lastError);
+    return;
+  }
+
+  gl.useProgram(program);
+
+  gl.detachShader(program, fragmentShader);
+  // Test the getFragDataLocation() call after detatch the shader.
+  // This call should not hit crash.
+  gl.getFragDataLocation(program, "foobar");
+
+  ok(true, 'WebGL getFragDataLocation() call after detatch fragment shader');
+}
+
 function run() {
   webGL2ClearBufferXXX_bug1252414();
   framebufferTexture2D_bug1257593();
   getFramebufferAttachmentParameter_bug1267100();
+  getFragDataLocation_bug1259702();
 
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 
 try {
   var prefArrArr = [
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -926,17 +926,17 @@ EventDispatcher::CreateEvent(EventTarget
   // initPopStateEvent method.  This is nuts ... but copying it is unlikely to
   // break the web.
   if (aEventType.LowerCaseEqualsLiteral("popstateevent")) {
     AutoJSContext cx;
     RootedDictionary<PopStateEventInit> init(cx);
     return PopStateEvent::Constructor(aOwner, EmptyString(), init);
   }
   if (aEventType.LowerCaseEqualsLiteral("touchevent") &&
-      TouchEvent::PrefEnabled())
+      TouchEvent::PrefEnabled(nsContentUtils::GetDocShellForEventTarget(aOwner)))
     return NS_NewDOMTouchEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("hashchangeevent")) {
     HashChangeEventInit init;
     return HashChangeEvent::Constructor(aOwner, EmptyString(), init);
   }
   if (aEventType.LowerCaseEqualsLiteral("customevent"))
     return NS_NewDOMCustomEvent(aOwner, aPresContext, nullptr);
   if (aEventType.LowerCaseEqualsLiteral("storageevent")) {
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -1149,55 +1149,16 @@ EventListenerManager::GetLegacyEventMess
       return eMozFullscreenChange;
     case eFullscreenError:
       return eMozFullscreenError;
     default:
       return aEventMessage;
   }
 }
 
-nsIDocShell*
-EventListenerManager::GetDocShellForTarget()
-{
-  nsCOMPtr<nsINode> node(do_QueryInterface(mTarget));
-  nsIDocument* doc = nullptr;
-  nsIDocShell* docShell = nullptr;
-
-  if (node) {
-    doc = node->OwnerDoc();
-    if (!doc->GetDocShell()) {
-      bool ignore;
-      nsCOMPtr<nsPIDOMWindowInner> window =
-        do_QueryInterface(doc->GetScriptHandlingObject(ignore));
-      if (window) {
-        doc = window->GetExtantDoc();
-      }
-    }
-  } else {
-    if (nsCOMPtr<nsPIDOMWindowInner> window = GetTargetAsInnerWindow()) {
-      doc = window->GetExtantDoc();
-    }
-  }
-
-  if (!doc) {
-    nsCOMPtr<DOMEventTargetHelper> helper(do_QueryInterface(mTarget));