Merge inbound to mozilla-central. a=merge
authorCsoregi Natalia <ncsoregi@mozilla.com>
Wed, 08 Aug 2018 12:58:36 +0300
changeset 430521 17116905bc072c37d74226ccc46c93f0bd45d516
parent 430460 c65991f3fa1080fdd9eca4bda0a3f218a7aeeeda (current diff)
parent 430520 c54958b74fd29e0d262c3b5a37328ae26cd80a6e (diff)
child 430527 ac5832da0ca8002ad5910c566b737e74d286a989
child 430607 28c6e1e00992b6e6a9741c60b412bcc967e60af6
push id34406
push userncsoregi@mozilla.com
push dateWed, 08 Aug 2018 09:58:58 +0000
treeherdermozilla-central@17116905bc07 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
17116905bc07 / 63.0a1 / 20180808100114 / files
nightly linux64
17116905bc07 / 63.0a1 / 20180808100114 / files
nightly mac
17116905bc07 / 63.0a1 / 20180808100114 / files
nightly win32
17116905bc07 / 63.0a1 / 20180808100114 / files
nightly win64
17116905bc07 / 63.0a1 / 20180808100114 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
docshell/base/nsIClipboardCommands.idl
docshell/base/nsITextScroll.idl
docshell/base/nsIWebShellServices.h
dom/base/Element.cpp
dom/base/Element.h
dom/base/nsAttrAndChildArray.cpp
dom/base/nsAttrAndChildArray.h
dom/base/test/test_bug614583.html
dom/html/HTMLMediaElement.cpp
layout/style/nsStyleStruct.h
testing/web-platform/meta/css/css-filter/filtered-inline-is-container.html.ini
testing/web-platform/meta/media-source/mediasource-changetype-play.html.ini
third_party/rust/app_units-0.6.0/.cargo-checksum.json
third_party/rust/app_units-0.6.0/.travis.yml
third_party/rust/app_units-0.6.0/Cargo.toml
third_party/rust/app_units-0.6.0/README.md
third_party/rust/app_units-0.6.0/src/app_unit.rs
third_party/rust/app_units-0.6.0/src/lib.rs
third_party/rust/euclid-0.18.1/.cargo-checksum.json
third_party/rust/euclid-0.18.1/.travis.yml
third_party/rust/euclid-0.18.1/COPYRIGHT
third_party/rust/euclid-0.18.1/Cargo.toml
third_party/rust/euclid-0.18.1/LICENSE-APACHE
third_party/rust/euclid-0.18.1/LICENSE-MIT
third_party/rust/euclid-0.18.1/README.md
third_party/rust/euclid-0.18.1/src/approxeq.rs
third_party/rust/euclid-0.18.1/src/homogen.rs
third_party/rust/euclid-0.18.1/src/length.rs
third_party/rust/euclid-0.18.1/src/lib.rs
third_party/rust/euclid-0.18.1/src/macros.rs
third_party/rust/euclid-0.18.1/src/num.rs
third_party/rust/euclid-0.18.1/src/point.rs
third_party/rust/euclid-0.18.1/src/rect.rs
third_party/rust/euclid-0.18.1/src/rotation.rs
third_party/rust/euclid-0.18.1/src/scale.rs
third_party/rust/euclid-0.18.1/src/side_offsets.rs
third_party/rust/euclid-0.18.1/src/size.rs
third_party/rust/euclid-0.18.1/src/transform2d.rs
third_party/rust/euclid-0.18.1/src/transform3d.rs
third_party/rust/euclid-0.18.1/src/trig.rs
third_party/rust/euclid-0.18.1/src/vector.rs
toolkit/components/browser/nsIWebBrowserFocus.idl
toolkit/components/browser/nsIWebBrowserSetup.idl
widget/android/nsScreenManagerAndroid.cpp
widget/android/nsScreenManagerAndroid.h
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -25,25 +25,16 @@ name = "ansi_term"
 version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "app_units"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "app_units"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -673,24 +664,16 @@ dependencies = [
 
 [[package]]
 name = "error-chain"
 version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "euclid"
-version = "0.18.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "euclid"
 version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1147,19 +1130,19 @@ source = "registry+https://github.com/ru
 dependencies = [
  "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "malloc_size_of"
 version = "0.0.1"
 dependencies = [
- "app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.24.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "hashglobe 0.1.0",
  "selectors 0.19.0",
  "servo_arc 0.1.1",
  "smallbitvec 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1576,17 +1559,17 @@ dependencies = [
 
 [[package]]
 name = "pkg-config"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "plane-split"
-version = "0.12.0"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1957,25 +1940,25 @@ source = "registry+https://github.com/ru
 name = "strsim"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "style"
 version = "0.0.1"
 dependencies = [
- "app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bindgen 0.37.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.24.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fallible 0.0.1",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "hashglobe 0.1.0",
  "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1987,17 +1970,17 @@ dependencies = [
  "nsstring 0.1.0",
  "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.19.0",
  "servo_arc 0.1.1",
  "smallbitvec 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "style_derive 0.0.1",
  "style_traits 0.0.1",
  "thin-slice 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2018,40 +2001,39 @@ dependencies = [
  "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "synstructure 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "style_traits"
 version = "0.0.1"
 dependencies = [
- "app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.24.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of 0.0.1",
  "malloc_size_of_derive 0.0.1",
  "selectors 0.19.0",
  "servo_arc 0.1.1",
 ]
 
 [[package]]
 name = "stylo_tests"
 version = "0.0.1"
 dependencies = [
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cssparser 0.24.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "euclid 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "geckoservo 0.0.1",
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of 0.0.1",
- "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.19.0",
  "size_of_test 0.0.1",
  "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
 ]
 
 [[package]]
@@ -2382,17 +2364,17 @@ dependencies = [
  "dwrote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "plane-split 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "plane-split 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_api 0.57.2",
 ]
@@ -2554,17 +2536,16 @@ dependencies = [
  "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [metadata]
 "checksum Inflector 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1b33cd9b653730fc539c53c7b3c672d2f47108fa20c6df571fa5817178f5a14c"
 "checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45"
 "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
-"checksum app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29069a9b483f7780aebb55dafb360c6225eefdc1f98c8d336a65148fd10c37b1"
 "checksum app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9dadc668390b373e73e4abbfc1f07238b09a25858f2f39c06cebc6d8e141d774"
 "checksum arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0ef4a9820019a0c91d918918c93dc71d469f581a49b47ddc1d285d4270bbe2"
 "checksum ascii-canvas 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b385d69402821a1c254533a011a312531cbcc0e3e24f19bbb4747a5a2daf37e2"
 "checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21"
 "checksum atty 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d0fd4c0631f06448cc45a6bbb3b710ebb7ff8ccb96a0800c994afe23a70d5df2"
 "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
 "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"
 "checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff"
@@ -2618,17 +2599,16 @@ dependencies = [
 "checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d"
 "checksum dwrote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b26e30aaa6bf31ec830db15fec14ed04f0f2ecfcc486ecfce88c55d3389b237f"
 "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
 "checksum ena 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe5a5078ac8c506d3e4430763b1ba9b609b1286913e7d08e581d1c2de9b7e5"
 "checksum encoding_c 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "769ecb8b33323998e482b218c0d13cd64c267609023b4b7ec3ee740714c318ee"
 "checksum encoding_rs 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88a1b66a0d28af4b03a8c8278c6dcb90e6e600d89c14500a9e7a02e64b9ee3ac"
 "checksum env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0561146661ae44c579e993456bc76d11ce1e0c7d745e57b2fa7146b6e49fa2ad"
 "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
-"checksum euclid 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "47d5eb6310c8dd3e79f973952ddcb180bf6a98c01d341add49126a094b5598cc"
 "checksum euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70a2ebdf55fb9d6329046e026329a55ef8fbaae5ea833f56e170beb3125a8a5f"
 "checksum fixedbitset 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "85cb8fec437468d86dc7c83ca7cfc933341d561873275f22dd5eedefa63a6478"
 "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909"
 "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
 "checksum foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ebc04f19019fff1f2d627b5581574ead502f80c48c88900575a46e0840fe5d0"
 "checksum freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b659e75b7a7338fe75afd7f909fc2b71937845cffb6ebe54ba2e50f13d8e903d"
 "checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866"
 "checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159"
@@ -2699,17 +2679,17 @@ dependencies = [
 "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
 "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
 "checksum petgraph 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "7a7e5234c228fbfa874c86a77f685886127f82e0aef602ad1d48333fcac6ad61"
 "checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
 "checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f"
 "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
 "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
 "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
-"checksum plane-split 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f0a0766225cf828672e97948dfa035bb2eae75110757359ae12fbb46509c8b66"
+"checksum plane-split 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3a4fc9e31d70eb6828e9a2d7a401a824d9f281686a39a8fc06f08796edb1bb"
 "checksum podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e5422a1ee1bc57cc47ae717b0137314258138f38fd5f3cea083f43a9725383a0"
 "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 "checksum proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "77997c53ae6edd6d187fec07ec41b207063b5ee6f33680e9fa86d405cdd313d4"
 "checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6"
 "checksum procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f566249236c6ca4340f7ca78968271f0ed2b0f234007a61b66f9ecd0af09260"
 "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
 "checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
--- a/browser/base/content/browser-ctrlTab.js
+++ b/browser/base/content/browser-ctrlTab.js
@@ -4,25 +4,16 @@
 
 // This file is loaded into the browser window scope.
 /* eslint-env mozilla/browser-window */
 
 /**
  * Tab previews utility, produces thumbnails
  */
 var tabPreviews = {
-  init: function tabPreviews_init() {
-    if (this._selectedTab)
-      return;
-    this._selectedTab = gBrowser.selectedTab;
-
-    gBrowser.tabContainer.addEventListener("TabSelect", this);
-    gBrowser.tabContainer.addEventListener("SSTabRestored", this);
-  },
-
   get aspectRatio() {
     let { PageThumbUtils } = ChromeUtils.import("resource://gre/modules/PageThumbUtils.jsm", {});
     let [ width, height ] = PageThumbUtils.getThumbnailSize(window);
     delete this.aspectRatio;
     return this.aspectRatio = height / width;
   },
 
   get: function tabPreviews_get(aTab) {
@@ -65,43 +56,16 @@ var tabPreviews = {
             aTab.__thumbnail = canvas;
             aTab.__thumbnail_lastURI = uri;
           }
         });
       }
     });
     return canvas;
   },
-
-  handleEvent: function tabPreviews_handleEvent(event) {
-    switch (event.type) {
-      case "TabSelect":
-        if (this._selectedTab &&
-            this._selectedTab.parentNode &&
-            !this._pendingUpdate) {
-          // Generate a thumbnail for the tab that was selected.
-          // The timeout keeps the UI snappy and prevents us from generating thumbnails
-          // for tabs that will be closed. During that timeout, don't generate other
-          // thumbnails in case multiple TabSelect events occur fast in succession.
-          this._pendingUpdate = true;
-          setTimeout(function(self, aTab) {
-            self._pendingUpdate = false;
-            if (aTab.parentNode &&
-                !aTab.hasAttribute("busy") &&
-                !aTab.hasAttribute("pending"))
-              self.capture(aTab, true);
-          }, 2000, this, this._selectedTab);
-        }
-        this._selectedTab = event.target;
-        break;
-      case "SSTabRestored":
-        this.capture(event.target, true);
-        break;
-    }
-  }
 };
 
 var tabPreviewPanelHelper = {
   opening(host) {
     host.panel.hidden = false;
 
     var handler = this._generateHandler(host);
     host.panel.addEventListener("popupshown", handler);
@@ -201,18 +165,16 @@ var ctrlTab = {
   },
 
   get tabList() {
     return this._recentlyUsedTabs;
   },
 
   init: function ctrlTab_init() {
     if (!this._recentlyUsedTabs) {
-      tabPreviews.init();
-
       this._initRecentlyUsedTabs();
       this._init(true);
     }
   },
 
   uninit: function ctrlTab_uninit() {
     if (this._recentlyUsedTabs) {
       this._recentlyUsedTabs = null;
--- a/browser/base/content/test/general/browser_gZipOfflineChild.js
+++ b/browser/base/content/test/general/browser_gZipOfflineChild.js
@@ -13,16 +13,18 @@ registerCleanupFunction(function() {
   Services.prefs.clearUserPref("offline-apps.allow_by_default");
 });
 
 //
 // Handle "message" events which are posted from the iframe upon
 // offline cache events.
 //
 function contentTask() {
+  ChromeUtils.import("resource://gre/modules/Timer.jsm");
+
   let resolve;
   let promise = new Promise(r => { resolve = r; });
 
   var cacheCount = 0;
   var intervalID = 0;
 
   function handleMessageEvents(event) {
     cacheCount++;
--- a/browser/base/content/test/performance/browser_startup_content.js
+++ b/browser/base/content/test/performance/browser_startup_content.js
@@ -19,16 +19,18 @@ const kDumpAllStacks = false;
 
 const whitelist = {
   components: new Set([
     "ContentProcessSingleton.js",
     "extension-process-script.js",
   ]),
   modules: new Set([
     "chrome://mochikit/content/ShutdownLeaksCollector.jsm",
+    "resource://specialpowers/specialpowers.js",
+    "resource://specialpowers/specialpowersAPI.js",
 
     // General utilities
     "resource://gre/modules/AppConstants.jsm",
     "resource://gre/modules/AsyncShutdown.jsm",
     "resource://gre/modules/DeferredTask.jsm",
     "resource://gre/modules/PromiseUtils.jsm",
     "resource://gre/modules/Services.jsm", // bug 1464542
     "resource://gre/modules/Timer.jsm",
--- a/browser/base/content/test/popupNotifications/browser_displayURI.js
+++ b/browser/base/content/test/popupNotifications/browser_displayURI.js
@@ -87,24 +87,26 @@ add_task(async function test_displayURI_
 add_task(async function test_displayURI_camera() {
   await check(async function() {
     content.navigator.mediaDevices.getUserMedia({video: true, fake: true});
   });
 });
 
 add_task(async function test_displayURI_geo_blob() {
   await check(async function() {
+    Cu.importGlobalProperties(["Blob"]);
     let text = "<script>navigator.geolocation.getCurrentPosition(() => {})</script>";
     let blob = new Blob([text], {type: "text/html"});
     let url = content.URL.createObjectURL(blob);
     content.location.href = url;
   }, {skipOnExtension: true});
 });
 
 add_task(async function test_displayURI_camera_blob() {
   await check(async function() {
+    Cu.importGlobalProperties(["Blob"]);
     let text = "<script>navigator.mediaDevices.getUserMedia({video: true, fake: true})</script>";
     let blob = new Blob([text], {type: "text/html"});
     let url = content.URL.createObjectURL(blob);
     content.location.href = url;
   }, {skipOnExtension: true});
 });
 
--- a/browser/base/content/test/webrtc/get_user_media_content_script.js
+++ b/browser/base/content/test/webrtc/get_user_media_content_script.js
@@ -1,13 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /* eslint-env mozilla/frame-script */
 
+ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "MediaManagerService",
                                    "@mozilla.org/mediaManagerService;1",
                                    "nsIMediaManagerService");
 
 const kObservedTopics = [
   "getUserMedia:response:allow",
   "getUserMedia:revoke",
--- a/browser/components/newtab/test/browser/browser_topsites_section.js
+++ b/browser/components/newtab/test/browser/browser_topsites_section.js
@@ -60,17 +60,17 @@ test_newtab({
   }
 });
 
 // Check Topsites add
 test_newtab({
   // it should be able to click the topsites edit button to reveal the edit topsites modal and overlay.
   test: async function topsites_add() {
     let nativeInputValueSetter = Object.getOwnPropertyDescriptor(content.window.HTMLInputElement.prototype, "value").set;
-    let event = new Event("input", {bubbles: true});
+    let event = new content.Event("input", {bubbles: true});
 
     // Find the add topsites button
     content.document.querySelector(".top-sites .section-top-bar .context-menu-button").click();
     let contextMenu = content.document.querySelector(".top-sites .section-top-bar .context-menu");
     ok(contextMenu, "Should find a visible topsite context menu");
 
     const topsitesAddBtn = content.document.querySelector(".top-sites .context-menu-item a");
     topsitesAddBtn.click();
--- a/browser/components/payments/content/paymentDialogFrameScript.js
+++ b/browser/components/payments/content/paymentDialogFrameScript.js
@@ -85,22 +85,22 @@ let PaymentFrameScript = {
       },
 
       getFormFormat(country) {
         let format = FormAutofillUtils.getFormFormat(country);
         return Cu.cloneInto(format, waivedContent);
       },
 
       getDefaultPreferences() {
-        let prefValues = {
+        let prefValues = Cu.cloneInto({
           saveCreditCardDefaultChecked:
             Services.prefs.getBoolPref(SAVE_CREDITCARD_DEFAULT_PREF, false),
           saveAddressDefaultChecked:
             Services.prefs.getBoolPref(SAVE_ADDRESS_DEFAULT_PREF, false),
-        };
+        }, waivedContent);
         return prefValues;
       },
     };
     waivedContent.PaymentDialogUtils = Cu.cloneInto(PaymentDialogUtils, waivedContent, {
       cloneFunctions: true,
     });
   },
 
--- a/browser/components/uitour/test/head.js
+++ b/browser/components/uitour/test/head.js
@@ -318,30 +318,30 @@ function loadUITourTestPage(callback, ho
               args,
               fnIndices,
             };
             return ContentTask.spawn(browser, taskArgs, async function(contentArgs) {
               let contentWin = Cu.waiveXrays(content);
               let callbacksCalled = 0;
               let resolveCallbackPromise;
               let allCallbacksCalledPromise = new Promise(resolve => resolveCallbackPromise = resolve);
-              let argumentsWithFunctions = contentArgs.args.map((arg, index) => {
+              let argumentsWithFunctions = Cu.cloneInto(contentArgs.args.map((arg, index) => {
                 if (arg === "" && contentArgs.fnIndices.includes(index)) {
                   return function() {
                     callbacksCalled++;
                     sendAsyncMessage("UITourHandler:proxiedfunction-" + index, Array.from(arguments));
                     if (callbacksCalled >= contentArgs.fnIndices.length) {
                       resolveCallbackPromise();
                     }
                   };
                 }
                 return arg;
-              });
+              }), content, {cloneFunctions: true});
               let rv = contentWin.Mozilla.UITour[contentArgs.methodName].apply(contentWin.Mozilla.UITour,
-                                                                        argumentsWithFunctions);
+                                                                               argumentsWithFunctions);
               if (contentArgs.fnIndices.length) {
                 await allCallbacksCalledPromise;
               }
               return rv;
             });
           };
         },
       };
--- a/config/external/nspr/pr/moz.build
+++ b/config/external/nspr/pr/moz.build
@@ -88,18 +88,22 @@ elif CONFIG['OS_TARGET'] == 'WINNT':
         WIN95=True,
         WINNT=False,
         _PR_GLOBAL_THREADS_ONLY=True,
     )
     if not CONFIG['DEBUG']:
       DEFINES['DO_NOT_WAIT_FOR_CONNECT_OVERLAPPED_OPERATIONS'] = True
     if CONFIG['CPU_ARCH'] == 'x86_64':
         DEFINES['_AMD64_'] = True
+    elif CONFIG['CPU_ARCH'] == 'x86':
+        DEFINES['_X86_'] = True
+    elif CONFIG['CPU_ARCH'] == 'aarch64':
+        DEFINES['_ARM64_'] = True
     else:
-        DEFINES['_X86_'] = True
+        error('Unsupported CPU_ARCH value: %s' % CONFIG['CPU_ARCH'])
 else:
     error('Not a supported OS_TARGET for NSPR in moz.build: "%s". Use --with-system-nspr' % CONFIG['OS_TARGET'])
 
 
 LOCAL_INCLUDES += [
     '/config/external/nspr',
     '/nsprpub/pr/include',
     '/nsprpub/pr/include/private',
--- a/devtools/client/debugger/new/README.mozilla
+++ b/devtools/client/debugger/new/README.mozilla
@@ -1,13 +1,13 @@
 This is the debugger.html project output.
 See https://github.com/devtools-html/debugger.html
 
-Version 78
+Version 79
 
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-77...release-78
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-78...release-79
 
 Packages:
 - babel-plugin-transform-es2015-modules-commonjs @6.26.2
 - babel-preset-react @6.24.1
 - react @16.4.1
 - react-dom @16.4.1
 - webpack @3.12.0
--- a/devtools/client/debugger/new/dist/debugger.css
+++ b/devtools/client/debugger/new/dist/debugger.css
@@ -1,8 +1,11 @@
+.A11y-mouse :focus {
+  outline: 0;
+}
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 .modal-wrapper {
   position: fixed;
   display: flex;
   flex-direction: column;
@@ -119,17 +122,16 @@
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 * {
   box-sizing: border-box;
 }
 
 button {
   background: transparent;
-  outline: none;
   border: none;
 }
 
 button:hover,
 button:focus {
   background-color: var(--theme-toolbar-background-hover);
 }
 
@@ -905,20 +907,16 @@ html[dir="rtl"] .tree-node img.arrow {
   border-radius: 2px;
   display: flex;
   flex-direction: row;
   justify-content: center;
   align-items: center;
   padding: 0;
 }
 
-.close-btn:focus {
-  outline: none;
-}
-
 .close-btn .close {
   mask: url("chrome://devtools/skin/images/debugger/close.svg") no-repeat;
   mask-size: 100%;
   background-color: var(--theme-comment);
   width: 8px;
   height: 8px;
   transition: all 0.15s ease-in-out;
   padding: 0;
@@ -961,20 +959,16 @@ img.close::before {
   border: none;
   display: inline-block;
   text-align: center;
   position: relative;
   padding: 0px 5px;
   fill: currentColor;
 }
 
-.command-bar-button:focus {
-  outline: none;
-}
-
 .command-bar-button:disabled {
   opacity: 0.8;
   cursor: default;
 }
 
 .command-bar-button:not(.disabled):hover {
   background: var(--theme-toolbar-background-hover);
 }
@@ -1088,20 +1082,16 @@ html .toggle-button.end.vertical svg {
 
 .search-field.big input {
   position: relative;
   margin-left: 30px;
   font-size: 14px;
   line-height: 40px;
 }
 
-.search-field input:focus {
-  outline: none;
-}
-
 .theme-dark .search-field input {
   color: var(--theme-body-color-inactive);
 }
 
 .search-field i.magnifying-glass,
 .search-field i.sad-face {
   padding-top: 5px;
   padding-bottom: 5px;
@@ -1390,20 +1380,16 @@ html .toggle-button.end.vertical svg {
 }
 
 .sources-list {
   flex: 1;
   display: flex;
   overflow: hidden;
 }
 
-.sources-list .tree:focus {
-  outline: none;
-}
-
 .sources-list .managed-tree {
   flex: 1;
   display: flex;
   overflow-x: hidden;
   overflow-y: auto;
 }
 
 .sources-list .managed-tree .tree .node {
@@ -1884,20 +1870,16 @@ menuseparator {
   flex-direction: column;
   justify-content: center;
 }
 
 .source-footer > .commands > button.action:hover {
   background: var(--theme-toolbar-background-hover);
 }
 
-.source-footer > .commands > button.action:focus {
-  outline: none;
-}
-
 :root.theme-dark .source-footer > .commands > .action {
   fill: var(--theme-body-color);
 }
 
 :root.theme-dark .source-footer > .commands > .action:hover {
   fill: var(--theme-selection-color);
 }
 
@@ -1969,20 +1951,16 @@ menuseparator {
   justify-content: flex-end;
   width: calc(100% - 1px);
   height: var(--editor-second-searchbar-height);
   background-color: var(--theme-toolbar-background);
   border-bottom: 1px solid var(--theme-splitter-color);
   padding: 0 13px;
 }
 
-.search-bottom-bar button:focus {
-  outline: none;
-}
-
 .search-bottom-bar .search-modifiers {
   display: flex;
   align-items: center;
 }
 
 .search-bottom-bar .search-modifiers button {
   padding: 0 3px;
   margin: 0 3px;
@@ -2006,20 +1984,16 @@ menuseparator {
   height: 16px;
   width: 16px;
 }
 
 .search-bottom-bar .search-modifiers button:hover {
   background: var(--theme-toolbar-background-hover);
 }
 
-.search-bottom-bar .search-modifiers button:active {
-  outline: none;
-}
-
 .search-bottom-bar .search-modifiers button.active svg {
   fill: var(--theme-selection-background);
 }
 
 .theme-dark .search-bottom-bar .search-modifiers button.active svg {
   fill: white;
 }
 
@@ -2032,20 +2006,16 @@ menuseparator {
 .search-bottom-bar .search-type-name {
   padding: 1px 0 0 0;
   margin: 0 0 0 6px;
   border: none;
   background: transparent;
   color: var(--theme-comment);
 }
 
-.search-bottom-bar .search-type-toggles .search-type-btn:active {
-  outline: none;
-}
-
 .search-bottom-bar .search-type-toggles .search-type-btn.active {
   color: var(--theme-selection-background);
 }
 
 .theme-dark .search-bottom-bar .search-type-toggles .search-type-btn.active {
   color: white;
 }
 
@@ -3259,17 +3229,16 @@ html[dir="rtl"] .breakpoints-list .break
 }
 
 .input-expression::placeholder {
   font-style: italic;
   color: var(--theme-comment);
 }
 
 .input-expression:focus {
-  outline: none;
   cursor: text;
 }
 
 .expressions-list {
   /* TODO: add normalize */
   margin: 0;
   padding: 0;
 }
@@ -3340,20 +3309,16 @@ html[dir="rtl"] .breakpoints-list .break
 
 .expression-content .tree-node[data-expandable="false"][aria-level="1"] {
   padding-inline-start: 10px;
 }
 
 .expression-input {
   max-width: 50%;
 }
-
-.expressions-list .tree:focus {
-  outline: none;
-}
 /* 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/>. */
 
 .frames ul .frames-group .group,
 .frames ul .frames-group .group .location {
   font-weight: 500;
   cursor: default;
@@ -3481,17 +3446,16 @@ html[dir="rtl"] .breakpoints-list .break
   text-overflow: ellipsis;
   overflow: hidden;
   margin: 7px 0.5em 7px 0;
 }
 
 .frames ul li:hover,
 .frames ul li:focus {
   background-color: var(--theme-toolbar-background-alt);
-  outline: none;
 }
 
 .theme-dark .frames ul li:focus {
   background-color: var(--theme-tab-toolbar-background);
 }
 
 .frames ul li.selected {
   background-color: var(--theme-selection-background);
@@ -3666,30 +3630,28 @@ html[dir="rtl"] .breakpoints-list .break
 .accordion div:last-child ._content {
   border-bottom: none;
 }
 
 .accordion ._header .header-buttons {
   display: flex;
   margin-left: auto;
   padding-right: 5px;
-  outline: 0;
 }
 
 .accordion .header-buttons .add-button {
   font-size: 180%;
   text-align: center;
   line-height: 16px;
 }
 
 .accordion .header-buttons button {
   color: var(--theme-body-color);
   border: none;
   background: none;
-  outline: 0;
   padding: 0;
   width: 16px;
   height: 16px;
 }
 
 .accordion .header-buttons button::-moz-focus-inner {
   border: none;
 }
@@ -3881,20 +3843,16 @@ html[dir="rtl"] .object-node {
 .theme-light .objectBox-object {
   white-space: nowrap;
 }
 
 .scopes-pane {
   overflow: auto;
 }
 
-.scopes-list .tree:focus {
-  outline: none;
-}
-
 .scopes-list .function-signature {
   display: inline-block;
 }
 
 .scopes-list .scope-type-toggle {
   text-align: center;
   padding-top: 10px;
   padding-bottom: 10px;
--- a/devtools/client/debugger/new/dist/vendors.js
+++ b/devtools/client/debugger/new/dist/vendors.js
@@ -1215,201 +1215,16 @@ process.cwd = function () { return '/' }
 process.chdir = function (dir) {
     throw new Error('process.chdir is not supported');
 };
 process.umask = function() { return 0; };
 
 
 /***/ }),
 
-/***/ 121:
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-
-// If obj.hasOwnProperty has been overridden, then calling
-// obj.hasOwnProperty(prop) will break.
-// See: https://github.com/joyent/node/issues/1707
-function hasOwnProperty(obj, prop) {
-  return Object.prototype.hasOwnProperty.call(obj, prop);
-}
-
-module.exports = function(qs, sep, eq, options) {
-  sep = sep || '&';
-  eq = eq || '=';
-  var obj = {};
-
-  if (typeof qs !== 'string' || qs.length === 0) {
-    return obj;
-  }
-
-  var regexp = /\+/g;
-  qs = qs.split(sep);
-
-  var maxKeys = 1000;
-  if (options && typeof options.maxKeys === 'number') {
-    maxKeys = options.maxKeys;
-  }
-
-  var len = qs.length;
-  // maxKeys <= 0 means that we should not limit keys count
-  if (maxKeys > 0 && len > maxKeys) {
-    len = maxKeys;
-  }
-
-  for (var i = 0; i < len; ++i) {
-    var x = qs[i].replace(regexp, '%20'),
-        idx = x.indexOf(eq),
-        kstr, vstr, k, v;
-
-    if (idx >= 0) {
-      kstr = x.substr(0, idx);
-      vstr = x.substr(idx + 1);
-    } else {
-      kstr = x;
-      vstr = '';
-    }
-
-    k = decodeURIComponent(kstr);
-    v = decodeURIComponent(vstr);
-
-    if (!hasOwnProperty(obj, k)) {
-      obj[k] = v;
-    } else if (isArray(obj[k])) {
-      obj[k].push(v);
-    } else {
-      obj[k] = [obj[k], v];
-    }
-  }
-
-  return obj;
-};
-
-var isArray = Array.isArray || function (xs) {
-  return Object.prototype.toString.call(xs) === '[object Array]';
-};
-
-
-/***/ }),
-
-/***/ 122:
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-
-var stringifyPrimitive = function(v) {
-  switch (typeof v) {
-    case 'string':
-      return v;
-
-    case 'boolean':
-      return v ? 'true' : 'false';
-
-    case 'number':
-      return isFinite(v) ? v : '';
-
-    default:
-      return '';
-  }
-};
-
-module.exports = function(obj, sep, eq, name) {
-  sep = sep || '&';
-  eq = eq || '=';
-  if (obj === null) {
-    obj = undefined;
-  }
-
-  if (typeof obj === 'object') {
-    return map(objectKeys(obj), function(k) {
-      var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
-      if (isArray(obj[k])) {
-        return map(obj[k], function(v) {
-          return ks + encodeURIComponent(stringifyPrimitive(v));
-        }).join(sep);
-      } else {
-        return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
-      }
-    }).join(sep);
-
-  }
-
-  if (!name) return '';
-  return encodeURIComponent(stringifyPrimitive(name)) + eq +
-         encodeURIComponent(stringifyPrimitive(obj));
-};
-
-var isArray = Array.isArray || function (xs) {
-  return Object.prototype.toString.call(xs) === '[object Array]';
-};
-
-function map (xs, f) {
-  if (xs.map) return xs.map(f);
-  var res = [];
-  for (var i = 0; i < xs.length; i++) {
-    res.push(f(xs[i], i));
-  }
-  return res;
-}
-
-var objectKeys = Object.keys || function (obj) {
-  var res = [];
-  for (var key in obj) {
-    if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key);
-  }
-  return res;
-};
-
-
-/***/ }),
-
 /***/ 1233:
 /***/ (function(module, exports) {
 
 module.exports = "<!-- 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 viewBox=\"0 0 256 296\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" preserveAspectRatio=\"xMidYMid\"><g><polygon fill=\"#673AB8\" points=\"128 0 256 73.8999491 256 221.699847 128 295.599796 0 221.699847 0 73.8999491\"></polygon><path d=\"M34.8647584,220.478469 C51.8814262,242.25881 105.959701,225.662965 157.014868,185.774297 C208.070035,145.885628 237.255632,97.428608 220.238964,75.6482664 C203.222296,53.8679249 149.144022,70.4637701 98.0888543,110.352439 C47.0336869,150.241107 17.8480906,198.698127 34.8647584,220.478469 Z M42.1343351,214.798853 C36.4908625,207.575537 38.9565723,193.395881 49.7081913,175.544904 C61.0297348,156.747677 80.2490923,135.997367 103.76847,117.622015 C127.287848,99.2466634 152.071368,85.6181573 173.049166,79.1803727 C192.970945,73.066665 207.325915,74.1045667 212.969387,81.3278822 C218.61286,88.5511977 216.14715,102.730854 205.395531,120.581832 C194.073987,139.379058 174.85463,160.129368 151.335252,178.50472 C127.815874,196.880072 103.032354,210.508578 82.054556,216.946362 C62.1327769,223.06007 47.7778077,222.022168 42.1343351,214.798853 Z\" fill=\"#FFFFFF\"></path><path d=\"M220.238964,220.478469 C237.255632,198.698127 208.070035,150.241107 157.014868,110.352439 C105.959701,70.4637701 51.8814262,53.8679249 34.8647584,75.6482664 C17.8480906,97.428608 47.0336869,145.885628 98.0888543,185.774297 C149.144022,225.662965 203.222296,242.25881 220.238964,220.478469 Z M212.969387,214.798853 C207.325915,222.022168 192.970945,223.06007 173.049166,216.946362 C152.071368,210.508578 127.287848,196.880072 103.76847,178.50472 C80.2490923,160.129368 61.0297348,139.379058 49.7081913,120.581832 C38.9565723,102.730854 36.4908625,88.5511977 42.1343351,81.3278822 C47.7778077,74.1045667 62.1327769,73.066665 82.054556,79.1803727 C103.032354,85.6181573 127.815874,99.2466634 151.335252,117.622015 C174.85463,135.997367 194.073987,156.747677 205.395531,175.544904 C216.14715,193.395881 218.61286,207.575537 212.969387,214.798853 Z\" fill=\"#FFFFFF\"></path><path d=\"M127.551861,167.666971 C138.378632,167.666971 147.155465,158.890139 147.155465,148.063368 C147.155465,137.236596 138.378632,128.459764 127.551861,128.459764 C116.72509,128.459764 107.948257,137.236596 107.948257,148.063368 C107.948257,158.890139 116.72509,167.666971 127.551861,167.666971 L127.551861,167.666971 Z\" fill=\"#FFFFFF\"></path></g></svg>"
 
 /***/ }),
 
 /***/ 1290:
@@ -4979,756 +4794,16 @@ Transition.EXITED = 1;
 Transition.ENTERING = 2;
 Transition.ENTERED = 3;
 Transition.EXITING = 4;
 
 exports.default = (0, _reactLifecyclesCompat.polyfill)(Transition);
 
 /***/ }),
 
-/***/ 334:
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-
-var punycode = __webpack_require__(916);
-var util = __webpack_require__(336);
-
-exports.parse = urlParse;
-exports.resolve = urlResolve;
-exports.resolveObject = urlResolveObject;
-exports.format = urlFormat;
-
-exports.Url = Url;
-
-function Url() {
-  this.protocol = null;
-  this.slashes = null;
-  this.auth = null;
-  this.host = null;
-  this.port = null;
-  this.hostname = null;
-  this.hash = null;
-  this.search = null;
-  this.query = null;
-  this.pathname = null;
-  this.path = null;
-  this.href = null;
-}
-
-// Reference: RFC 3986, RFC 1808, RFC 2396
-
-// define these here so at least they only have to be
-// compiled once on the first module load.
-var protocolPattern = /^([a-z0-9.+-]+:)/i,
-    portPattern = /:[0-9]*$/,
-
-    // Special case for a simple path URL
-    simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,
-
-    // RFC 2396: characters reserved for delimiting URLs.
-    // We actually just auto-escape these.
-    delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],
-
-    // RFC 2396: characters not allowed for various reasons.
-    unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims),
-
-    // Allowed by RFCs, but cause of XSS attacks.  Always escape these.
-    autoEscape = ['\''].concat(unwise),
-    // Characters that are never ever allowed in a hostname.
-    // Note that any invalid chars are also handled, but these
-    // are the ones that are *expected* to be seen, so we fast-path
-    // them.
-    nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape),
-    hostEndingChars = ['/', '?', '#'],
-    hostnameMaxLen = 255,
-    hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,
-    hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
-    // protocols that can allow "unsafe" and "unwise" chars.
-    unsafeProtocol = {
-      'javascript': true,
-      'javascript:': true
-    },
-    // protocols that never have a hostname.
-    hostlessProtocol = {
-      'javascript': true,
-      'javascript:': true
-    },
-    // protocols that always contain a // bit.
-    slashedProtocol = {
-      'http': true,
-      'https': true,
-      'ftp': true,
-      'gopher': true,
-      'file': true,
-      'http:': true,
-      'https:': true,
-      'ftp:': true,
-      'gopher:': true,
-      'file:': true
-    },
-    querystring = __webpack_require__(66);
-
-function urlParse(url, parseQueryString, slashesDenoteHost) {
-  if (url && util.isObject(url) && url instanceof Url) return url;
-
-  var u = new Url;
-  u.parse(url, parseQueryString, slashesDenoteHost);
-  return u;
-}
-
-Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
-  if (!util.isString(url)) {
-    throw new TypeError("Parameter 'url' must be a string, not " + typeof url);
-  }
-
-  // Copy chrome, IE, opera backslash-handling behavior.
-  // Back slashes before the query string get converted to forward slashes
-  // See: https://code.google.com/p/chromium/issues/detail?id=25916
-  var queryIndex = url.indexOf('?'),
-      splitter =
-          (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#',
-      uSplit = url.split(splitter),
-      slashRegex = /\\/g;
-  uSplit[0] = uSplit[0].replace(slashRegex, '/');
-  url = uSplit.join(splitter);
-
-  var rest = url;
-
-  // trim before proceeding.
-  // This is to support parse stuff like "  http://foo.com  \n"
-  rest = rest.trim();
-
-  if (!slashesDenoteHost && url.split('#').length === 1) {
-    // Try fast path regexp
-    var simplePath = simplePathPattern.exec(rest);
-    if (simplePath) {
-      this.path = rest;
-      this.href = rest;
-      this.pathname = simplePath[1];
-      if (simplePath[2]) {
-        this.search = simplePath[2];
-        if (parseQueryString) {
-          this.query = querystring.parse(this.search.substr(1));
-        } else {
-          this.query = this.search.substr(1);
-        }
-      } else if (parseQueryString) {
-        this.search = '';
-        this.query = {};
-      }
-      return this;
-    }
-  }
-
-  var proto = protocolPattern.exec(rest);
-  if (proto) {
-    proto = proto[0];
-    var lowerProto = proto.toLowerCase();
-    this.protocol = lowerProto;
-    rest = rest.substr(proto.length);
-  }
-
-  // figure out if it's got a host
-  // user@server is *always* interpreted as a hostname, and url
-  // resolution will treat //foo/bar as host=foo,path=bar because that's
-  // how the browser resolves relative URLs.
-  if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
-    var slashes = rest.substr(0, 2) === '//';
-    if (slashes && !(proto && hostlessProtocol[proto])) {
-      rest = rest.substr(2);
-      this.slashes = true;
-    }
-  }
-
-  if (!hostlessProtocol[proto] &&
-      (slashes || (proto && !slashedProtocol[proto]))) {
-
-    // there's a hostname.
-    // the first instance of /, ?, ;, or # ends the host.
-    //
-    // If there is an @ in the hostname, then non-host chars *are* allowed
-    // to the left of the last @ sign, unless some host-ending character
-    // comes *before* the @-sign.
-    // URLs are obnoxious.
-    //
-    // ex:
-    // http://a@b@c/ => user:a@b host:c
-    // http://a@b?@c => user:a host:c path:/?@c
-
-    // v0.12 TODO(isaacs): This is not quite how Chrome does things.
-    // Review our test case against browsers more comprehensively.
-
-    // find the first instance of any hostEndingChars
-    var hostEnd = -1;
-    for (var i = 0; i < hostEndingChars.length; i++) {
-      var hec = rest.indexOf(hostEndingChars[i]);
-      if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
-        hostEnd = hec;
-    }
-
-    // at this point, either we have an explicit point where the
-    // auth portion cannot go past, or the last @ char is the decider.
-    var auth, atSign;
-    if (hostEnd === -1) {
-      // atSign can be anywhere.
-      atSign = rest.lastIndexOf('@');
-    } else {
-      // atSign must be in auth portion.
-      // http://a@b/c@d => host:b auth:a path:/c@d
-      atSign = rest.lastIndexOf('@', hostEnd);
-    }
-
-    // Now we have a portion which is definitely the auth.
-    // Pull that off.
-    if (atSign !== -1) {
-      auth = rest.slice(0, atSign);
-      rest = rest.slice(atSign + 1);
-      this.auth = decodeURIComponent(auth);
-    }
-
-    // the host is the remaining to the left of the first non-host char
-    hostEnd = -1;
-    for (var i = 0; i < nonHostChars.length; i++) {
-      var hec = rest.indexOf(nonHostChars[i]);
-      if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
-        hostEnd = hec;
-    }
-    // if we still have not hit it, then the entire thing is a host.
-    if (hostEnd === -1)
-      hostEnd = rest.length;
-
-    this.host = rest.slice(0, hostEnd);
-    rest = rest.slice(hostEnd);
-
-    // pull out port.
-    this.parseHost();
-
-    // we've indicated that there is a hostname,
-    // so even if it's empty, it has to be present.
-    this.hostname = this.hostname || '';
-
-    // if hostname begins with [ and ends with ]
-    // assume that it's an IPv6 address.
-    var ipv6Hostname = this.hostname[0] === '[' &&
-        this.hostname[this.hostname.length - 1] === ']';
-
-    // validate a little.
-    if (!ipv6Hostname) {
-      var hostparts = this.hostname.split(/\./);
-      for (var i = 0, l = hostparts.length; i < l; i++) {
-        var part = hostparts[i];
-        if (!part) continue;
-        if (!part.match(hostnamePartPattern)) {
-          var newpart = '';
-          for (var j = 0, k = part.length; j < k; j++) {
-            if (part.charCodeAt(j) > 127) {
-              // we replace non-ASCII char with a temporary placeholder
-              // we need this to make sure size of hostname is not
-              // broken by replacing non-ASCII by nothing
-              newpart += 'x';
-            } else {
-              newpart += part[j];
-            }
-          }
-          // we test again with ASCII char only
-          if (!newpart.match(hostnamePartPattern)) {
-            var validParts = hostparts.slice(0, i);
-            var notHost = hostparts.slice(i + 1);
-            var bit = part.match(hostnamePartStart);
-            if (bit) {
-              validParts.push(bit[1]);
-              notHost.unshift(bit[2]);
-            }
-            if (notHost.length) {
-              rest = '/' + notHost.join('.') + rest;
-            }
-            this.hostname = validParts.join('.');
-            break;
-          }
-        }
-      }
-    }
-
-    if (this.hostname.length > hostnameMaxLen) {
-      this.hostname = '';
-    } else {
-      // hostnames are always lower case.
-      this.hostname = this.hostname.toLowerCase();
-    }
-
-    if (!ipv6Hostname) {
-      // IDNA Support: Returns a punycoded representation of "domain".
-      // It only converts parts of the domain name that
-      // have non-ASCII characters, i.e. it doesn't matter if
-      // you call it with a domain that already is ASCII-only.
-      this.hostname = punycode.toASCII(this.hostname);
-    }
-
-    var p = this.port ? ':' + this.port : '';
-    var h = this.hostname || '';
-    this.host = h + p;
-    this.href += this.host;
-
-    // strip [ and ] from the hostname
-    // the host field still retains them, though
-    if (ipv6Hostname) {
-      this.hostname = this.hostname.substr(1, this.hostname.length - 2);
-      if (rest[0] !== '/') {
-        rest = '/' + rest;
-      }
-    }
-  }
-
-  // now rest is set to the post-host stuff.
-  // chop off any delim chars.
-  if (!unsafeProtocol[lowerProto]) {
-
-    // First, make 100% sure that any "autoEscape" chars get
-    // escaped, even if encodeURIComponent doesn't think they
-    // need to be.
-    for (var i = 0, l = autoEscape.length; i < l; i++) {
-      var ae = autoEscape[i];
-      if (rest.indexOf(ae) === -1)
-        continue;
-      var esc = encodeURIComponent(ae);
-      if (esc === ae) {
-        esc = escape(ae);
-      }
-      rest = rest.split(ae).join(esc);
-    }
-  }
-
-
-  // chop off from the tail first.
-  var hash = rest.indexOf('#');
-  if (hash !== -1) {
-    // got a fragment string.
-    this.hash = rest.substr(hash);
-    rest = rest.slice(0, hash);
-  }
-  var qm = rest.indexOf('?');
-  if (qm !== -1) {
-    this.search = rest.substr(qm);
-    this.query = rest.substr(qm + 1);
-    if (parseQueryString) {
-      this.query = querystring.parse(this.query);
-    }
-    rest = rest.slice(0, qm);
-  } else if (parseQueryString) {
-    // no query string, but parseQueryString still requested
-    this.search = '';
-    this.query = {};
-  }
-  if (rest) this.pathname = rest;
-  if (slashedProtocol[lowerProto] &&
-      this.hostname && !this.pathname) {
-    this.pathname = '/';
-  }
-
-  //to support http.request
-  if (this.pathname || this.search) {
-    var p = this.pathname || '';
-    var s = this.search || '';
-    this.path = p + s;
-  }
-
-  // finally, reconstruct the href based on what has been validated.
-  this.href = this.format();
-  return this;
-};
-
-// format a parsed object into a url string
-function urlFormat(obj) {
-  // ensure it's an object, and not a string url.
-  // If it's an obj, this is a no-op.
-  // this way, you can call url_format() on strings
-  // to clean up potentially wonky urls.
-  if (util.isString(obj)) obj = urlParse(obj);
-  if (!(obj instanceof Url)) return Url.prototype.format.call(obj);
-  return obj.format();
-}
-
-Url.prototype.format = function() {
-  var auth = this.auth || '';
-  if (auth) {
-    auth = encodeURIComponent(auth);
-    auth = auth.replace(/%3A/i, ':');
-    auth += '@';
-  }
-
-  var protocol = this.protocol || '',
-      pathname = this.pathname || '',
-      hash = this.hash || '',
-      host = false,
-      query = '';
-
-  if (this.host) {
-    host = auth + this.host;
-  } else if (this.hostname) {
-    host = auth + (this.hostname.indexOf(':') === -1 ?
-        this.hostname :
-        '[' + this.hostname + ']');
-    if (this.port) {
-      host += ':' + this.port;
-    }
-  }
-
-  if (this.query &&
-      util.isObject(this.query) &&
-      Object.keys(this.query).length) {
-    query = querystring.stringify(this.query);
-  }
-
-  var search = this.search || (query && ('?' + query)) || '';
-
-  if (protocol && protocol.substr(-1) !== ':') protocol += ':';
-
-  // only the slashedProtocols get the //.  Not mailto:, xmpp:, etc.
-  // unless they had them to begin with.
-  if (this.slashes ||
-      (!protocol || slashedProtocol[protocol]) && host !== false) {
-    host = '//' + (host || '');
-    if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname;
-  } else if (!host) {
-    host = '';
-  }
-
-  if (hash && hash.charAt(0) !== '#') hash = '#' + hash;
-  if (search && search.charAt(0) !== '?') search = '?' + search;
-
-  pathname = pathname.replace(/[?#]/g, function(match) {
-    return encodeURIComponent(match);
-  });
-  search = search.replace('#', '%23');
-
-  return protocol + host + pathname + search + hash;
-};
-
-function urlResolve(source, relative) {
-  return urlParse(source, false, true).resolve(relative);
-}
-
-Url.prototype.resolve = function(relative) {
-  return this.resolveObject(urlParse(relative, false, true)).format();
-};
-
-function urlResolveObject(source, relative) {
-  if (!source) return relative;
-  return urlParse(source, false, true).resolveObject(relative);
-}
-
-Url.prototype.resolveObject = function(relative) {
-  if (util.isString(relative)) {
-    var rel = new Url();
-    rel.parse(relative, false, true);
-    relative = rel;
-  }
-
-  var result = new Url();
-  var tkeys = Object.keys(this);
-  for (var tk = 0; tk < tkeys.length; tk++) {
-    var tkey = tkeys[tk];
-    result[tkey] = this[tkey];
-  }
-
-  // hash is always overridden, no matter what.
-  // even href="" will remove it.
-  result.hash = relative.hash;
-
-  // if the relative url is empty, then there's nothing left to do here.
-  if (relative.href === '') {
-    result.href = result.format();
-    return result;
-  }
-
-  // hrefs like //foo/bar always cut to the protocol.
-  if (relative.slashes && !relative.protocol) {
-    // take everything except the protocol from relative
-    var rkeys = Object.keys(relative);
-    for (var rk = 0; rk < rkeys.length; rk++) {
-      var rkey = rkeys[rk];
-      if (rkey !== 'protocol')
-        result[rkey] = relative[rkey];
-    }
-
-    //urlParse appends trailing / to urls like http://www.example.com
-    if (slashedProtocol[result.protocol] &&
-        result.hostname && !result.pathname) {
-      result.path = result.pathname = '/';
-    }
-
-    result.href = result.format();
-    return result;
-  }
-
-  if (relative.protocol && relative.protocol !== result.protocol) {
-    // if it's a known url protocol, then changing
-    // the protocol does weird things
-    // first, if it's not file:, then we MUST have a host,
-    // and if there was a path
-    // to begin with, then we MUST have a path.
-    // if it is file:, then the host is dropped,
-    // because that's known to be hostless.
-    // anything else is assumed to be absolute.
-    if (!slashedProtocol[relative.protocol]) {
-      var keys = Object.keys(relative);
-      for (var v = 0; v < keys.length; v++) {
-        var k = keys[v];
-        result[k] = relative[k];
-      }
-      result.href = result.format();
-      return result;
-    }
-
-    result.protocol = relative.protocol;
-    if (!relative.host && !hostlessProtocol[relative.protocol]) {
-      var relPath = (relative.pathname || '').split('/');
-      while (relPath.length && !(relative.host = relPath.shift()));
-      if (!relative.host) relative.host = '';
-      if (!relative.hostname) relative.hostname = '';
-      if (relPath[0] !== '') relPath.unshift('');
-      if (relPath.length < 2) relPath.unshift('');
-      result.pathname = relPath.join('/');
-    } else {
-      result.pathname = relative.pathname;
-    }
-    result.search = relative.search;
-    result.query = relative.query;
-    result.host = relative.host || '';
-    result.auth = relative.auth;
-    result.hostname = relative.hostname || relative.host;
-    result.port = relative.port;
-    // to support http.request
-    if (result.pathname || result.search) {
-      var p = result.pathname || '';
-      var s = result.search || '';
-      result.path = p + s;
-    }
-    result.slashes = result.slashes || relative.slashes;
-    result.href = result.format();
-    return result;
-  }
-
-  var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'),
-      isRelAbs = (
-          relative.host ||
-          relative.pathname && relative.pathname.charAt(0) === '/'
-      ),
-      mustEndAbs = (isRelAbs || isSourceAbs ||
-                    (result.host && relative.pathname)),
-      removeAllDots = mustEndAbs,
-      srcPath = result.pathname && result.pathname.split('/') || [],
-      relPath = relative.pathname && relative.pathname.split('/') || [],
-      psychotic = result.protocol && !slashedProtocol[result.protocol];
-
-  // if the url is a non-slashed url, then relative
-  // links like ../.. should be able
-  // to crawl up to the hostname, as well.  This is strange.
-  // result.protocol has already been set by now.
-  // Later on, put the first path part into the host field.
-  if (psychotic) {
-    result.hostname = '';
-    result.port = null;
-    if (result.host) {
-      if (srcPath[0] === '') srcPath[0] = result.host;
-      else srcPath.unshift(result.host);
-    }
-    result.host = '';
-    if (relative.protocol) {
-      relative.hostname = null;
-      relative.port = null;
-      if (relative.host) {
-        if (relPath[0] === '') relPath[0] = relative.host;
-        else relPath.unshift(relative.host);
-      }
-      relative.host = null;
-    }
-    mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === '');
-  }
-
-  if (isRelAbs) {
-    // it's absolute.
-    result.host = (relative.host || relative.host === '') ?
-                  relative.host : result.host;
-    result.hostname = (relative.hostname || relative.hostname === '') ?
-                      relative.hostname : result.hostname;
-    result.search = relative.search;
-    result.query = relative.query;
-    srcPath = relPath;
-    // fall through to the dot-handling below.
-  } else if (relPath.length) {
-    // it's relative
-    // throw away the existing file, and take the new path instead.
-    if (!srcPath) srcPath = [];
-    srcPath.pop();
-    srcPath = srcPath.concat(relPath);
-    result.search = relative.search;
-    result.query = relative.query;
-  } else if (!util.isNullOrUndefined(relative.search)) {
-    // just pull out the search.
-    // like href='?foo'.
-    // Put this after the other two cases because it simplifies the booleans
-    if (psychotic) {
-      result.hostname = result.host = srcPath.shift();
-      //occationaly the auth can get stuck only in host
-      //this especially happens in cases like
-      //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
-      var authInHost = result.host && result.host.indexOf('@') > 0 ?
-                       result.host.split('@') : false;
-      if (authInHost) {
-        result.auth = authInHost.shift();
-        result.host = result.hostname = authInHost.shift();
-      }
-    }
-    result.search = relative.search;
-    result.query = relative.query;
-    //to support http.request
-    if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
-      result.path = (result.pathname ? result.pathname : '') +
-                    (result.search ? result.search : '');
-    }
-    result.href = result.format();
-    return result;
-  }
-
-  if (!srcPath.length) {
-    // no path at all.  easy.
-    // we've already handled the other stuff above.
-    result.pathname = null;
-    //to support http.request
-    if (result.search) {
-      result.path = '/' + result.search;
-    } else {
-      result.path = null;
-    }
-    result.href = result.format();
-    return result;
-  }
-
-  // if a url ENDs in . or .., then it must get a trailing slash.
-  // however, if it ends in anything else non-slashy,
-  // then it must NOT get a trailing slash.
-  var last = srcPath.slice(-1)[0];
-  var hasTrailingSlash = (
-      (result.host || relative.host || srcPath.length > 1) &&
-      (last === '.' || last === '..') || last === '');
-
-  // strip single dots, resolve double dots to parent dir
-  // if the path tries to go above the root, `up` ends up > 0
-  var up = 0;
-  for (var i = srcPath.length; i >= 0; i--) {
-    last = srcPath[i];
-    if (last === '.') {
-      srcPath.splice(i, 1);
-    } else if (last === '..') {
-      srcPath.splice(i, 1);
-      up++;
-    } else if (up) {
-      srcPath.splice(i, 1);
-      up--;
-    }
-  }
-
-  // if the path is allowed to go above the root, restore leading ..s
-  if (!mustEndAbs && !removeAllDots) {
-    for (; up--; up) {
-      srcPath.unshift('..');
-    }
-  }
-
-  if (mustEndAbs && srcPath[0] !== '' &&
-      (!srcPath[0] || srcPath[0].charAt(0) !== '/')) {
-    srcPath.unshift('');
-  }
-
-  if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) {
-    srcPath.push('');
-  }
-
-  var isAbsolute = srcPath[0] === '' ||
-      (srcPath[0] && srcPath[0].charAt(0) === '/');
-
-  // put the host back
-  if (psychotic) {
-    result.hostname = result.host = isAbsolute ? '' :
-                                    srcPath.length ? srcPath.shift() : '';
-    //occationaly the auth can get stuck only in host
-    //this especially happens in cases like
-    //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
-    var authInHost = result.host && result.host.indexOf('@') > 0 ?
-                     result.host.split('@') : false;
-    if (authInHost) {
-      result.auth = authInHost.shift();
-      result.host = result.hostname = authInHost.shift();
-    }
-  }
-
-  mustEndAbs = mustEndAbs || (result.host && srcPath.length);
-
-  if (mustEndAbs && !isAbsolute) {
-    srcPath.unshift('');
-  }
-
-  if (!srcPath.length) {
-    result.pathname = null;
-    result.path = null;
-  } else {
-    result.pathname = srcPath.join('/');
-  }
-
-  //to support request.http
-  if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
-    result.path = (result.pathname ? result.pathname : '') +
-                  (result.search ? result.search : '');
-  }
-  result.auth = relative.auth || result.auth;
-  result.slashes = result.slashes || relative.slashes;
-  result.href = result.format();
-  return result;
-};
-
-Url.prototype.parseHost = function() {
-  var host = this.host;
-  var port = portPattern.exec(host);
-  if (port) {
-    port = port[0];
-    if (port !== ':') {
-      this.port = port.substr(1);
-    }
-    host = host.substr(0, host.length - port.length);
-  }
-  if (host) this.hostname = host;
-};
-
-
-/***/ }),
-
 /***/ 335:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 exports.__esModule = true;
 exports.classNamesShape = exports.timeoutsShape = undefined;
@@ -5776,40 +4851,16 @@ var classNamesShape = exports.classNames
   enterActive: _propTypes2.default.string,
   exit: _propTypes2.default.string,
   exitDone: _propTypes2.default.string,
   exitActive: _propTypes2.default.string
 })]);
 
 /***/ }),
 
-/***/ 336:
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-module.exports = {
-  isString: function(arg) {
-    return typeof(arg) === 'string';
-  },
-  isObject: function(arg) {
-    return typeof(arg) === 'object' && arg !== null;
-  },
-  isNull: function(arg) {
-    return arg === null;
-  },
-  isNullOrUndefined: function(arg) {
-    return arg == null;
-  }
-};
-
-
-/***/ }),
-
 /***/ 347:
 /***/ (function(module, exports) {
 
 module.exports = "<!-- 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 viewBox=\"-1 73 16 11\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"><g id=\"Shape-Copy-3-+-Shape-Copy-4\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(0.000000, 74.000000)\"><path d=\"M0.749321284,4.16081709 L4.43130681,0.242526751 C4.66815444,-0.00952143591 5.06030999,-0.0211407611 5.30721074,0.216574262 C5.55411149,0.454289284 5.56226116,0.851320812 5.32541353,1.103369 L1.95384971,4.69131519 L5.48809879,8.09407556 C5.73499955,8.33179058 5.74314922,8.72882211 5.50630159,8.9808703 C5.26945396,9.23291849 4.87729841,9.24453781 4.63039766,9.00682279 L0.827097345,5.34502101 C0.749816996,5.31670099 0.677016974,5.27216098 0.613753508,5.21125118 C0.427367989,5.03179997 0.377040713,4.7615583 0.465458792,4.53143559 C0.492371834,4.43667624 0.541703274,4.34676528 0.613628034,4.27022448 C0.654709457,4.22650651 0.70046335,4.19002189 0.749321284,4.16081709 Z\" id=\"Shape-Copy-3\" stroke=\"#FFFFFF\" stroke-width=\"0.05\" fill=\"#DDE1E4\"></path><path d=\"M13.7119065,5.44453032 L9.77062746,9.09174784 C9.51677479,9.3266604 9.12476399,9.31089603 8.89504684,9.05653714 C8.66532968,8.80217826 8.68489539,8.40554539 8.93874806,8.17063283 L12.5546008,4.82456128 L9.26827469,1.18571135 C9.03855754,0.931352463 9.05812324,0.534719593 9.31197591,0.299807038 C9.56582858,0.0648944831 9.95783938,0.0806588502 10.1875565,0.335017737 L13.72891,4.25625178 C13.8013755,4.28980469 13.8684335,4.3382578 13.9254821,4.40142604 C14.0883019,4.58171146 14.1258883,4.83347168 14.0435812,5.04846202 C14.0126705,5.15680232 13.9526426,5.2583679 13.8641331,5.34027361 C13.8174417,5.38348136 13.7660763,5.41820853 13.7119065,5.44453032 Z\" id=\"Shape-Copy-4\" stroke=\"#FFFFFF\" stroke-width=\"0.05\" fill=\"#DDE1E4\"></path></g></svg>"
 
 /***/ }),
 
 /***/ 348:
@@ -7645,20 +6696,16 @@ var transition = _interopRequireWildcard
 var _tabs = __webpack_require__(3762);
 
 var reactAriaComponentsTabs = _interopRequireWildcard(_tabs);
 
 var _reselect = __webpack_require__(993);
 
 var reselect = _interopRequireWildcard(_reselect);
 
-var _url = __webpack_require__(334);
-
-var url = _interopRequireWildcard(_url);
-
 var _classnames = __webpack_require__(175);
 
 var _classnames2 = _interopRequireDefault(_classnames);
 
 var _devtoolsSplitter = __webpack_require__(1440);
 
 var _devtoolsSplitter2 = _interopRequireDefault(_devtoolsSplitter);
 
@@ -7676,51 +6723,51 @@ function _interopRequireWildcard(obj) { 
 
 // We cannot directly export literals containing special characters
 // (eg. "my-module/Test") which is why they are nested in "vendored".
 // The keys of the vendored object should match the module names
 // !!! Should remain synchronized with .babel/transform-mc.js !!!
 
 
 // Modules imported without destructuring
+/* 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/>. */
+
+/**
+ * Vendors.js is a file used to bundle and expose all dependencies needed to run
+ * the transpiled debugger modules when running in Firefox.
+ *
+ * To make transpilation easier, a vendored module should always be imported in
+ * same way:
+ * - always with destructuring (import { a } from "modA";)
+ * - always without destructuring (import modB from "modB")
+ *
+ * Both are fine, but cannot be mixed for the same module.
+ */
+
+// Modules imported with destructuring
 const vendored = exports.vendored = {
   classnames: _classnames2.default,
   "devtools-components": devtoolsComponents,
   "devtools-config": devtoolsConfig,
   "devtools-contextmenu": devtoolsContextmenu,
   "devtools-environment": devtoolsEnvironment,
   "devtools-modules": devtoolsModules,
   "devtools-splitter": _devtoolsSplitter2.default,
   "devtools-utils": devtoolsUtils,
   "fuzzaldrin-plus": fuzzaldrinPlus,
   "lodash-move": _lodashMove2.default,
   "react-aria-components/src/tabs": reactAriaComponentsTabs,
   "react-transition-group/Transition": transition,
   reselect,
   // Svg is required via relative paths, so the key is not imported path.
   // See .babel/transform-mc.js
-  Svg: _Svg2.default,
-  url
-}; /* 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/>. */
-
-/**
- * Vendors.js is a file used to bundle and expose all dependencies needed to run
- * the transpiled debugger modules when running in Firefox.
- *
- * To make transpilation easier, a vendored module should always be imported in
- * same way:
- * - always with destructuring (import { a } from "modA";)
- * - always without destructuring (import modB from "modB")
- *
- * Both are fine, but cannot be mixed for the same module.
- */
-
-// Modules imported with destructuring
+  Svg: _Svg2.default
+};
 
 /***/ }),
 
 /***/ 3750:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
@@ -8915,28 +7962,16 @@ function baseGetTag(value) {
     : objectToString(value);
 }
 
 module.exports = baseGetTag;
 
 
 /***/ }),
 
-/***/ 66:
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-exports.decode = exports.parse = __webpack_require__(121);
-exports.encode = exports.stringify = __webpack_require__(122);
-
-
-/***/ }),
-
 /***/ 67:
 /***/ (function(module, exports, __webpack_require__) {
 
 var baseGet = __webpack_require__(68);
 
 /**
  * Gets the value at `path` of `object`. If the resolved value is
  * `undefined`, the `defaultValue` is returned in its place.
--- a/devtools/client/debugger/new/src/client/index.js
+++ b/devtools/client/debugger/new/src/client/index.js
@@ -26,34 +26,42 @@ function loadFromPrefs(actions) {
     pauseOnCaughtExceptions
   } = _prefs.prefs;
 
   if (pauseOnExceptions || pauseOnCaughtExceptions) {
     return actions.pauseOnExceptions(pauseOnExceptions, pauseOnCaughtExceptions);
   }
 }
 
+async function loadInitialState() {
+  const pendingBreakpoints = await _prefs.asyncStore.pendingBreakpoints;
+  return {
+    pendingBreakpoints
+  };
+}
+
 async function onConnect(connection, {
   services,
   toolboxActions
 }) {
   // NOTE: the landing page does not connect to a JS process
   if (!connection) {
     return;
   }
 
   const commands = firefox.clientCommands;
+  const initialState = await loadInitialState();
   const {
     store,
     actions,
     selectors
   } = (0, _bootstrap.bootstrapStore)(commands, {
     services,
     toolboxActions
-  });
+  }, initialState);
   const workers = (0, _bootstrap.bootstrapWorkers)();
   await firefox.onConnect(connection, actions);
   await loadFromPrefs(actions);
   (0, _dbg.setupHelper)({
     store,
     actions,
     selectors,
     workers: { ...workers,
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/src/components/A11yIntention.js
@@ -0,0 +1,43 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+
+var _react = require("devtools/client/shared/vendor/react");
+
+var _react2 = _interopRequireDefault(_react);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/* 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/>. */
+class A11yIntention extends _react2.default.Component {
+  constructor(...args) {
+    var _temp;
+
+    return _temp = super(...args), this.state = {
+      keyboard: false
+    }, this.handleKeyDown = () => {
+      this.setState({
+        keyboard: true
+      });
+    }, this.handleMouseDown = () => {
+      this.setState({
+        keyboard: false
+      });
+    }, _temp;
+  }
+
+  render() {
+    return _react2.default.createElement("div", {
+      className: this.state.keyboard ? "A11y-keyboard" : "A11y-mouse",
+      onKeyDown: this.handleKeyDown,
+      onMouseDown: this.handleMouseDown
+    }, this.props.children);
+  }
+
+}
+
+exports.default = A11yIntention;
\ No newline at end of file
--- a/devtools/client/debugger/new/src/components/App.js
+++ b/devtools/client/debugger/new/src/components/App.js
@@ -15,16 +15,20 @@ var _react2 = _interopRequireDefault(_re
 var _reactRedux = require("devtools/client/shared/vendor/react-redux");
 
 var _prefs = require("../utils/prefs");
 
 var _actions = require("../actions/index");
 
 var _actions2 = _interopRequireDefault(_actions);
 
+var _A11yIntention = require("./A11yIntention");
+
+var _A11yIntention2 = _interopRequireDefault(_A11yIntention);
+
 var _ShortcutsModal = require("./ShortcutsModal");
 
 var _selectors = require("../selectors/index");
 
 var _devtoolsModules = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-modules"];
 
 var _devtoolsServices = require("Services");
 
@@ -272,20 +276,20 @@ class App extends _react.Component {
   }
 
   render() {
     const {
       quickOpenEnabled
     } = this.props;
     return _react2.default.createElement("div", {
       className: "debugger"
-    }, this.renderLayout(), quickOpenEnabled === true && _react2.default.createElement(_QuickOpenModal2.default, {
+    }, _react2.default.createElement(_A11yIntention2.default, null, this.renderLayout(), quickOpenEnabled === true && _react2.default.createElement(_QuickOpenModal2.default, {
       shortcutsModalEnabled: this.state.shortcutsModalEnabled,
       toggleShortcutsModal: () => this.toggleShortcutsModal()
-    }), this.renderShortcutsModal());
+    }), this.renderShortcutsModal()));
   }
 
 }
 
 App.childContextTypes = {
   shortcuts: _propTypes2.default.object
 };
 
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/ExceptionOption.js
@@ -0,0 +1,33 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.default = ExceptionOption;
+
+var _react = require("devtools/client/shared/vendor/react");
+
+var _react2 = _interopRequireDefault(_react);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
+function ExceptionOption({
+  className,
+  isChecked = false,
+  label,
+  onChange
+}) {
+  return _react2.default.createElement("div", {
+    className: className,
+    onClick: onChange
+  }, _react2.default.createElement("input", {
+    type: "checkbox",
+    checked: isChecked ? "checked" : "",
+    onChange: e => e.stopPropagation() && onChange()
+  }), _react2.default.createElement("div", {
+    className: "breakpoint-exceptions-label"
+  }, label));
+}
\ No newline at end of file
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/index.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/index.js
@@ -9,16 +9,20 @@ var _react = require("devtools/client/sh
 var _react2 = _interopRequireDefault(_react);
 
 var _classnames = require("devtools/client/debugger/new/dist/vendors").vendored["classnames"];
 
 var _classnames2 = _interopRequireDefault(_classnames);
 
 var _reactRedux = require("devtools/client/shared/vendor/react-redux");
 
+var _ExceptionOption = require("./ExceptionOption");
+
+var _ExceptionOption2 = _interopRequireDefault(_ExceptionOption);
+
 var _Breakpoint = require("./Breakpoint");
 
 var _Breakpoint2 = _interopRequireDefault(_Breakpoint);
 
 var _SourceIcon = require("../../shared/SourceIcon");
 
 var _SourceIcon2 = _interopRequireDefault(_SourceIcon);
 
@@ -32,45 +36,40 @@ var _breakpoint = require("../../../util
 
 var _selectors = require("../../../selectors/index");
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
-function createExceptionOption(label, value, onChange, className) {
-  return _react2.default.createElement("div", {
-    className: className,
-    onClick: onChange
-  }, _react2.default.createElement("input", {
-    type: "checkbox",
-    checked: value ? "checked" : "",
-    onChange: e => e.stopPropagation() && onChange()
-  }), _react2.default.createElement("div", {
-    className: "breakpoint-exceptions-label"
-  }, label));
-}
-
 class Breakpoints extends _react.Component {
   renderExceptionsOptions() {
     const {
       breakpointSources,
       shouldPauseOnExceptions,
       shouldPauseOnCaughtExceptions,
       pauseOnExceptions
     } = this.props;
     const isEmpty = breakpointSources.length == 0;
-    const exceptionsBox = createExceptionOption(L10N.getStr("pauseOnExceptionsItem2"), shouldPauseOnExceptions, () => pauseOnExceptions(!shouldPauseOnExceptions, false), "breakpoints-exceptions");
-    const ignoreCaughtBox = createExceptionOption(L10N.getStr("pauseOnCaughtExceptionsItem"), shouldPauseOnCaughtExceptions, () => pauseOnExceptions(true, !shouldPauseOnCaughtExceptions), "breakpoints-exceptions-caught");
     return _react2.default.createElement("div", {
       className: (0, _classnames2.default)("breakpoints-exceptions-options", {
         empty: isEmpty
       })
-    }, exceptionsBox, shouldPauseOnExceptions ? ignoreCaughtBox : null);
+    }, _react2.default.createElement(_ExceptionOption2.default, {
+      className: "breakpoints-exceptions",
+      label: L10N.getStr("pauseOnExceptionsItem2"),
+      isChecked: shouldPauseOnExceptions,
+      onChange: () => pauseOnExceptions(!shouldPauseOnExceptions, false)
+    }), shouldPauseOnExceptions && _react2.default.createElement(_ExceptionOption2.default, {
+      className: "breakpoints-exceptions-caught",
+      label: L10N.getStr("pauseOnCaughtExceptionsItem"),
+      isChecked: shouldPauseOnCaughtExceptions,
+      onChange: () => pauseOnExceptions(true, !shouldPauseOnCaughtExceptions)
+    }));
   }
 
   renderBreakpoints() {
     const {
       breakpointSources
     } = this.props;
     const sources = [...breakpointSources.map(({
       source,
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/moz.build
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/moz.build
@@ -5,10 +5,11 @@
 
 DIRS += [
 
 ]
 
 DevToolsModules(
     'Breakpoint.js',
     'BreakpointsContextMenu.js',
+    'ExceptionOption.js',
     'index.js',
 )
--- a/devtools/client/debugger/new/src/components/moz.build
+++ b/devtools/client/debugger/new/src/components/moz.build
@@ -6,14 +6,15 @@
 DIRS += [
     'Editor',
     'PrimaryPanes',
     'SecondaryPanes',
     'shared',
 ]
 
 DevToolsModules(
+    'A11yIntention.js',
     'App.js',
     'ProjectSearch.js',
     'QuickOpenModal.js',
     'ShortcutsModal.js',
     'WelcomeBox.js',
 )
--- a/devtools/client/debugger/new/src/reducers/pause.js
+++ b/devtools/client/debugger/new/src/reducers/pause.js
@@ -395,19 +395,22 @@ function getSelectedFrameBindings(state)
   if (!frameScope || frameScope.pending) {
     return;
   }
 
   let currentScope = frameScope.scope;
   let frameBindings = [];
 
   while (currentScope && currentScope.type != "object") {
-    const bindings = Object.keys(currentScope.bindings.variables);
-    const args = [].concat(...currentScope.bindings.arguments.map(argument => Object.keys(argument)));
-    frameBindings = [...frameBindings, ...bindings, ...args];
+    if (currentScope.bindings) {
+      const bindings = Object.keys(currentScope.bindings.variables);
+      const args = [].concat(...currentScope.bindings.arguments.map(argument => Object.keys(argument)));
+      frameBindings = [...frameBindings, ...bindings, ...args];
+    }
+
     currentScope = currentScope.parent;
   }
 
   return frameBindings;
 }
 
 function getFrameScope(state, sourceId, frameId) {
   return getOriginalFrameScope(state, sourceId, frameId) || getGeneratedFrameScope(state, frameId);
--- a/devtools/client/debugger/new/src/reducers/pending-breakpoints.js
+++ b/devtools/client/debugger/new/src/reducers/pending-breakpoints.js
@@ -1,35 +1,28 @@
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-exports.initialPendingBreakpointsState = initialPendingBreakpointsState;
 exports.getPendingBreakpoints = getPendingBreakpoints;
 exports.getPendingBreakpointList = getPendingBreakpointList;
 exports.getPendingBreakpointsForSource = getPendingBreakpointsForSource;
 
 var _breakpoint = require("../utils/breakpoint/index");
 
-var _prefs = require("../utils/prefs");
-
 /* 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/>. */
 
 /**
  * Pending breakpoints reducer
  * @module reducers/pending-breakpoints
  */
-function initialPendingBreakpointsState() {
-  return restorePendingBreakpoints();
-}
-
-function update(state = initialPendingBreakpointsState(), action) {
+function update(state = {}, action) {
   switch (action.type) {
     case "ADD_BREAKPOINT":
       {
         return addBreakpoint(state, action);
       }
 
     case "SYNC_BREAKPOINT":
       {
@@ -167,14 +160,9 @@ function getPendingBreakpoints(state) {
 function getPendingBreakpointList(state) {
   return Object.values(getPendingBreakpoints(state));
 }
 
 function getPendingBreakpointsForSource(state, sourceUrl) {
   return getPendingBreakpointList(state).filter(pendingBreakpoint => pendingBreakpoint.location.sourceUrl === sourceUrl);
 }
 
-function restorePendingBreakpoints() {
-  return { ..._prefs.prefs.pendingBreakpoints
-  };
-}
-
 exports.default = update;
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/src/utils/asyncStoreHelper.js
@@ -0,0 +1,60 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.asyncStoreHelper = asyncStoreHelper;
+
+var _asyncStorage = require("devtools/shared/async-storage");
+
+var _asyncStorage2 = _interopRequireDefault(_asyncStorage);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/* 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/>. */
+
+/*
+ * asyncStoreHelper wraps asyncStorage so that it is easy to define project
+ * specific properties. It is similar to PrefsHelper.
+ *
+ * e.g.
+ *   const asyncStore = asyncStoreHelper("r", {a: "_a"})
+ *   asyncStore.a         // => asyncStorage.getItem("r._a")
+ *   asyncStore.a = 2     // => asyncStorage.setItem("r._a", 2)
+ */
+function asyncStoreHelper(root, mappings) {
+  let store = {};
+
+  function getMappingKey(key) {
+    return Array.isArray(mappings[key]) ? mappings[key][0] : mappings[key];
+  }
+
+  function getMappingDefaultValue(key) {
+    return Array.isArray(mappings[key]) ? mappings[key][1] : null;
+  }
+
+  Object.keys(mappings).map(key => Object.defineProperty(store, key, {
+    async get() {
+      const value = await _asyncStorage2.default.getItem(`${root}.${getMappingKey(key)}`);
+      return value || getMappingDefaultValue(key);
+    },
+
+    set(value) {
+      return _asyncStorage2.default.setItem(`${root}.${getMappingKey(key)}`, value);
+    }
+
+  }));
+  store = new Proxy(store, {
+    set: function (target, property, value, receiver) {
+      if (!mappings.hasOwnProperty(property)) {
+        throw new Error(`AsyncStore: ${property} is not defined in mappings`);
+      }
+
+      Reflect.set(...arguments);
+      return true;
+    }
+  });
+  return store;
+}
\ No newline at end of file
--- a/devtools/client/debugger/new/src/utils/bootstrap.js
+++ b/devtools/client/debugger/new/src/utils/bootstrap.js
@@ -78,29 +78,29 @@ function renderPanel(component, store) {
   _reactDom2.default.render(_react2.default.createElement(Provider, {
     store
   }, _react2.default.createElement(component)), root);
 }
 
 function bootstrapStore(client, {
   services,
   toolboxActions
-}) {
+}, initialState) {
   const createStore = (0, _createStore2.default)({
     log: (0, _devtoolsEnvironment.isTesting)(),
     timing: (0, _devtoolsEnvironment.isDevelopment)(),
     makeThunkArgs: (args, state) => {
       return { ...args,
         client,
         ...services,
         ...toolboxActions
       };
     }
   });
-  const store = createStore((0, _redux.combineReducers)(_reducers2.default));
+  const store = createStore((0, _redux.combineReducers)(_reducers2.default), initialState);
   store.subscribe(() => updatePrefs(store.getState()));
   const actions = (0, _redux.bindActionCreators)(require("../actions/index").default, store.dispatch);
   return {
     store,
     actions,
     selectors
   };
 }
@@ -148,11 +148,11 @@ function bootstrapApp(store) {
 
 let currentPendingBreakpoints;
 
 function updatePrefs(state) {
   const previousPendingBreakpoints = currentPendingBreakpoints;
   currentPendingBreakpoints = selectors.getPendingBreakpoints(state);
 
   if (previousPendingBreakpoints && currentPendingBreakpoints !== previousPendingBreakpoints) {
-    _prefs.prefs.pendingBreakpoints = currentPendingBreakpoints;
+    _prefs.asyncStore.pendingBreakpoints = currentPendingBreakpoints;
   }
 }
\ No newline at end of file
--- a/devtools/client/debugger/new/src/utils/dbg.js
+++ b/devtools/client/debugger/new/src/utils/dbg.js
@@ -65,16 +65,17 @@ function _formatPausePoints(dbg, url) {
   console.log((0, _pausePoints.formatPausePoints)(source.text, pausePoints));
 }
 
 function setupHelper(obj) {
   const selectors = bindSelectors(obj);
   const dbg = { ...obj,
     selectors,
     prefs: _prefs.prefs,
+    asyncStore: _prefs.asyncStore,
     features: _prefs.features,
     timings,
     getCM,
     helpers: {
       findSource: url => findSource(dbg, url),
       evaluate: (expression, cbk) => evaluate(dbg, expression, cbk),
       sendPacketToThread: (packet, cbk) => sendPacketToThread(dbg, packet, cbk),
       sendPacket: (packet, cbk) => sendPacket(dbg, packet, cbk)
--- a/devtools/client/debugger/new/src/utils/moz.build
+++ b/devtools/client/debugger/new/src/utils/moz.build
@@ -8,16 +8,17 @@ DIRS += [
     'editor',
     'pause',
     'sources-tree',
 ]
 
 DevToolsModules(
     'assert.js',
     'ast.js',
+    'asyncStoreHelper.js',
     'bootstrap.js',
     'build-query.js',
     'clipboard.js',
     'dbg.js',
     'defer.js',
     'DevToolsUtils.js',
     'expressions.js',
     'fromJS.js',
--- a/devtools/client/debugger/new/src/utils/pause/mapScopes/index.js
+++ b/devtools/client/debugger/new/src/utils/pause/mapScopes/index.js
@@ -203,17 +203,17 @@ function generateClientScope(scopes, ori
       } : null)
     };
   }, globalLexicalScope); // The rendering logic in getScope 'this' bindings only runs on the current
   // selected frame scope, so we pluck out the 'this' binding that was mapped,
   // and put it in a special location
 
   const thisScope = originalScopes.find(scope => scope.bindings.this);
 
-  if (thisScope) {
+  if (result.bindings && thisScope) {
     result.bindings.this = thisScope.generatedBindings.this || null;
   }
 
   return result;
 }
 
 function hasValidIdent(range, pos) {
   return range.type === "match" || // For declarations, we allow the range on the identifier to be a
--- a/devtools/client/debugger/new/src/utils/pause/scopes/getScope.js
+++ b/devtools/client/debugger/new/src/utils/pause/scopes/getScope.js
@@ -39,17 +39,17 @@ function getScope(scope, selectedFrame, 
   if (type === "function" || type === "block") {
     const bindings = scope.bindings;
     let vars = (0, _getVariables.getBindingVariables)(bindings, key); // show exception, return, and this variables in innermost scope
 
     if (isLocalScope) {
       vars = vars.concat((0, _utils.getFramePopVariables)(why, key));
       let thisDesc_ = selectedFrame.this;
 
-      if ("this" in bindings) {
+      if (bindings && "this" in bindings) {
         // The presence of "this" means we're rendering a "this" binding
         // generated from mapScopes and this can override the binding
         // provided by the current frame.
         thisDesc_ = bindings.this ? bindings.this.value : null;
       }
 
       const this_ = (0, _utils.getThisVariable)(thisDesc_, key);
 
--- a/devtools/client/debugger/new/src/utils/pause/scopes/getVariables.js
+++ b/devtools/client/debugger/new/src/utils/pause/scopes/getVariables.js
@@ -10,16 +10,20 @@ var _lodash = require("devtools/client/s
 /* eslint max-nested-callbacks: ["error", 4] */
 
 /* 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/>. */
 // Create the tree nodes representing all the variables and arguments
 // for the bindings from a scope.
 function getBindingVariables(bindings, parentName) {
+  if (!bindings) {
+    return [];
+  }
+
   const args = bindings.arguments.map(arg => (0, _lodash.toPairs)(arg)[0]);
   const variables = (0, _lodash.toPairs)(bindings.variables);
   return args.concat(variables).map(binding => {
     const name = binding[0];
     const contents = binding[1];
     return {
       name,
       path: `${parentName}/${name}`,
--- a/devtools/client/debugger/new/src/utils/prefs.js
+++ b/devtools/client/debugger/new/src/utils/prefs.js
@@ -1,31 +1,34 @@
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
+exports.asyncStore = exports.features = exports.prefs = undefined;
+
+var _devtoolsModules = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-modules"];
+
+var _devtoolsEnvironment = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-environment"];
+
+var _devtoolsServices = require("Services");
+
+var _devtoolsServices2 = _interopRequireDefault(_devtoolsServices);
+
+var _asyncStoreHelper = require("./asyncStoreHelper");
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
-const {
-  isDevelopment
-} = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-environment"];
+const prefsSchemaVersion = "1.0.3";
+const pref = _devtoolsServices2.default.pref;
 
-const {
-  PrefsHelper
-} = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-modules"];
-
-const Services = require("Services");
-
-const prefsSchemaVersion = "1.0.3";
-const pref = Services.pref;
-
-if (isDevelopment()) {
+if ((0, _devtoolsEnvironment.isDevelopment)()) {
   pref("devtools.debugger.alphabetize-outline", false);
   pref("devtools.debugger.auto-pretty-print", false);
   pref("devtools.source-map.client-service.enabled", true);
   pref("devtools.debugger.pause-on-exceptions", false);
   pref("devtools.debugger.pause-on-caught-exceptions", false);
   pref("devtools.debugger.ignore-caught-exceptions", true);
   pref("devtools.debugger.call-stack-visible", true);
   pref("devtools.debugger.scopes-visible", true);
@@ -63,17 +66,17 @@ if (isDevelopment()) {
   pref("devtools.debugger.features.replay", true);
   pref("devtools.debugger.features.pause-points", true);
   pref("devtools.debugger.features.skip-pausing", true);
   pref("devtools.debugger.features.component-pane", false);
   pref("devtools.debugger.features.autocomplete-expressions", false);
   pref("devtools.debugger.features.map-expression-bindings", true);
 }
 
-const prefs = exports.prefs = new PrefsHelper("devtools", {
+const prefs = exports.prefs = new _devtoolsModules.PrefsHelper("devtools", {
   alphabetizeOutline: ["Bool", "debugger.alphabetize-outline"],
   autoPrettyPrint: ["Bool", "debugger.auto-pretty-print"],
   clientSourceMapsEnabled: ["Bool", "source-map.client-service.enabled"],
   pauseOnExceptions: ["Bool", "debugger.pause-on-exceptions"],
   pauseOnCaughtExceptions: ["Bool", "debugger.pause-on-caught-exceptions"],
   ignoreCaughtExceptions: ["Bool", "debugger.ignore-caught-exceptions"],
   callStackVisible: ["Bool", "debugger.call-stack-visible"],
   scopesVisible: ["Bool", "debugger.scopes-visible"],
@@ -91,17 +94,17 @@ const prefs = exports.prefs = new PrefsH
   expressions: ["Json", "debugger.expressions", []],
   fileSearchCaseSensitive: ["Bool", "debugger.file-search-case-sensitive"],
   fileSearchWholeWord: ["Bool", "debugger.file-search-whole-word"],
   fileSearchRegexMatch: ["Bool", "debugger.file-search-regex-match"],
   debuggerPrefsSchemaVersion: ["Char", "debugger.prefs-schema-version"],
   projectDirectoryRoot: ["Char", "debugger.project-directory-root", ""],
   skipPausing: ["Bool", "debugger.skip-pausing"]
 });
-const features = exports.features = new PrefsHelper("devtools.debugger.features", {
+const features = exports.features = new _devtoolsModules.PrefsHelper("devtools.debugger.features", {
   asyncStepping: ["Bool", "async-stepping"],
   wasm: ["Bool", "wasm"],
   shortcuts: ["Bool", "shortcuts"],
   root: ["Bool", "root"],
   columnBreakpoints: ["Bool", "column-breakpoints"],
   mapScopes: ["Bool", "map-scopes"],
   removeCommandBarOptions: ["Bool", "remove-command-bar-options"],
   workers: ["Bool", "workers"],
@@ -111,14 +114,17 @@ const features = exports.features = new 
   codeFolding: ["Bool", "code-folding"],
   replay: ["Bool", "replay"],
   pausePoints: ["Bool", "pause-points"],
   skipPausing: ["Bool", "skip-pausing"],
   autocompleteExpression: ["Bool", "autocomplete-expressions"],
   mapExpressionBindings: ["Bool", "map-expression-bindings"],
   componentPane: ["Bool", "component-pane"]
 });
+const asyncStore = exports.asyncStore = (0, _asyncStoreHelper.asyncStoreHelper)("debugger", {
+  pendingBreakpoints: ["pending-breakpoints", {}]
+});
 
 if (prefs.debuggerPrefsSchemaVersion !== prefsSchemaVersion) {
   // clear pending Breakpoints
   prefs.pendingBreakpoints = {};
   prefs.debuggerPrefsSchemaVersion = prefsSchemaVersion;
 }
\ No newline at end of file
--- a/devtools/client/debugger/new/test/mochitest/helpers.js
+++ b/devtools/client/debugger/new/test/mochitest/helpers.js
@@ -3,16 +3,17 @@
 
 /**
  * Helper methods to drive with the debugger during mochitests. This file can be safely
  * required from other panel test files.
  */
 
 var { Toolbox } = require("devtools/client/framework/toolbox");
 var { Task } = require("devtools/shared/task");
+var asyncStorage = require("devtools/shared/async-storage");
 
 const sourceUtils = {
   isLoaded: source => source.loadedState === "loaded"
 };
 
 function log(msg, data) {
   info(`${msg} ${!data ? "" : JSON.stringify(data)}`);
 }
@@ -476,16 +477,18 @@ function createDebuggerContext(toolbox) 
     panel: panel
   };
 }
 
 /**
  * Clear all the debugger related preferences.
  */
 function clearDebuggerPreferences() {
+  asyncStorage.clear();
+  Services.prefs.clearUserPref("devtools.recordreplay.enabled");
   Services.prefs.clearUserPref("devtools.debugger.pause-on-exceptions");
   Services.prefs.clearUserPref("devtools.debugger.pause-on-caught-exceptions");
   Services.prefs.clearUserPref("devtools.debugger.ignore-caught-exceptions");
   Services.prefs.clearUserPref("devtools.debugger.tabs");
   Services.prefs.clearUserPref("devtools.debugger.pending-selected-location");
   Services.prefs.clearUserPref("devtools.debugger.pending-breakpoints");
   Services.prefs.clearUserPref("devtools.debugger.expressions");
   Services.prefs.clearUserPref("devtools.debugger.call-stack-visible");
--- a/devtools/client/debugger/test/mochitest/code_frame-script.js
+++ b/devtools/client/debugger/test/mochitest/code_frame-script.js
@@ -18,17 +18,17 @@ loadSubScript("chrome://mochikit/content
 dump("Frame script loaded.\n");
 
 var workers = {};
 
 this.call = function (name, args) {
   dump("Calling function with name " + name + ".\n");
 
   dump("args " + JSON.stringify(args) + "\n");
-  return XPCNativeWrapper.unwrap(content)[name].apply(undefined, args);
+  return XPCNativeWrapper.unwrap(content)[name].apply(undefined, Cu.cloneInto(args, content));
 };
 
 this._eval = function (string) {
   dump("Evalling string.\n");
 
   return content.eval(string);
 };
 
--- a/devtools/client/shared/components/menu/MenuButton.js
+++ b/devtools/client/shared/components/menu/MenuButton.js
@@ -192,16 +192,20 @@ class MenuButton extends PureComponent {
       if (this.buttonRef) {
         this.buttonRef.style.pointerEvents = "auto";
       }
     }, 0);
   }
 
   async onClick(e) {
     if (e.target === this.buttonRef) {
+      // On Mac, even after clicking the button it doesn't get focus.
+      // Force focus to the button so that our keydown handlers get called.
+      this.buttonRef.focus();
+
       if (this.props.onClick) {
         this.props.onClick(e);
       }
 
       if (!e.defaultPrevented) {
         const wasKeyboardEvent = e.screenX === 0 && e.screenY === 0;
         // If the popup menu will be shown, disable this button in order to
         // prevent reopening the popup menu. See extended comment in onHidden().
--- a/devtools/client/shared/test/unit/test_parseDeclarations.js
+++ b/devtools/client/shared/test/unit/test_parseDeclarations.js
@@ -369,25 +369,25 @@ const TEST_DATA = [
   // A comment-in-a-comment should yield the correct offsets.
   {
     parseComments: true,
     input: "/* color: /\\* comment *\\/ red; */",
     expected: [{name: "color", value: "red", priority: "",
                 offsets: [3, 30], commentOffsets: [0, 33]}]
   },
 
-  // HTML comments are ignored.
+  // HTML comments are not special -- they are just ordinary tokens.
   {
     parseComments: true,
     input: "<!-- color: red; --> color: blue;",
     expected: [
-      {name: "color", value: "red", priority: "",
-       offsets: [5, 16]},
-      {name: "color", value: "blue", priority: "",
-       offsets: [21, 33]}]
+      {name: "<!-- color", value: "red", priority: "",
+       offsets: [0, 16]},
+      {name: "--> color", value: "blue", priority: "",
+       offsets: [17, 33]}]
   },
 
   // Don't error on an empty comment.
   {
     parseComments: true,
     input: "/**/",
     expected: []
   },
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_split_persist.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_split_persist.js
@@ -28,25 +28,22 @@ add_task(async function() {
      "Panel height matches the pref");
   toolbox.webconsolePanel.height = 200;
 
   await toolbox.destroy();
 
   info("Opening a tab while there is a true user setting on split console pref");
   toolbox = await openNewTabAndToolbox(TEST_URI, "inspector");
   ok(toolbox.splitConsole, "Split console is visible by default.");
-
+  ok(isJstermFocused(toolbox.getPanel("webconsole").hud.jsterm),
+     "Split console input is focused by default");
   ok(await doesMenuSayHide(toolbox),
      "Split console menu item initially says hide");
   is(getHeightPrefValue(), 200, "Height is set based on panel height after closing");
 
-  const activeElement = getActiveElement(toolbox.doc);
-  const inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
-  is(activeElement, inputNode, "Split console input is focused by default");
-
   toolbox.webconsolePanel.height = 1;
   ok(toolbox.webconsolePanel.clientHeight > 1,
      "The actual height of the console is bound with a min height");
 
   toolbox.webconsolePanel.height = 10000;
   ok(toolbox.webconsolePanel.clientHeight < 10000,
      "The actual height of the console is bound with a max height");
 
@@ -65,36 +62,29 @@ add_task(async function() {
   toolbox = await openNewTabAndToolbox(TEST_URI, "inspector");
 
   ok(!toolbox.splitConsole, "Split console is hidden by default.");
   ok(!getVisiblePrefValue(), "Visibility pref is false");
 
   await toolbox.destroy();
 });
 
-function getActiveElement(doc) {
-  let activeElement = doc.activeElement;
-  while (activeElement && activeElement.contentDocument) {
-    activeElement = activeElement.contentDocument.activeElement;
-  }
-  return activeElement;
-}
-
 function getVisiblePrefValue() {
   return Services.prefs.getBoolPref("devtools.toolbox.splitconsoleEnabled");
 }
 
 function getHeightPrefValue() {
   return Services.prefs.getIntPref("devtools.toolbox.splitconsoleHeight");
 }
 
-function doesMenuSayHide(toolbox) {
+async function doesMenuSayHide(toolbox) {
+  const button = toolbox.doc.getElementById("toolbox-meatball-menu-button");
+  await waitUntil(() => toolbox.win.getComputedStyle(button).pointerEvents === "auto");
   return new Promise(resolve => {
-    const button = toolbox.doc.getElementById("toolbox-meatball-menu-button");
-    EventUtils.sendMouseEvent({ type: "click" }, button);
+    EventUtils.synthesizeMouseAtCenter(button, {}, toolbox.win);
 
     toolbox.doc.addEventListener("popupshown", () => {
       const menuItem =
         toolbox.doc.getElementById("toolbox-meatball-menu-splitconsole");
 
       const result =
         menuItem &&
         menuItem.querySelector(".label") &&
--- a/devtools/shared/css/parsing-utils.js
+++ b/devtools/shared/css/parsing-utils.js
@@ -313,22 +313,16 @@ function parseDeclarationsInternal(isCss
   let importantWS = false;
   let current = "";
   while (true) {
     const token = lexer.nextToken();
     if (!token) {
       break;
     }
 
-    // Ignore HTML comment tokens (but parse anything they might
-    // happen to surround).
-    if (token.tokenType === "htmlcomment") {
-      continue;
-    }
-
     // Update the start and end offsets of the declaration, but only
     // when we see a significant token.
     if (token.tokenType !== "whitespace" && token.tokenType !== "comment") {
       if (lastProp.offsets[0] === undefined) {
         lastProp.offsets[0] = token.startOffset;
       }
       lastProp.offsets[1] = token.endOffset;
     } else if (lastProp.name && !current && !importantState &&
--- a/docshell/base/moz.build
+++ b/docshell/base/moz.build
@@ -32,47 +32,45 @@ with Files('nsIScrollObserver.*'):
     BUG_COMPONENT = ('Core', 'Panning and Zooming')
 
 DIRS += [
     'timeline',
 ]
 
 XPIDL_SOURCES += [
     'nsCDefaultURIFixup.idl',
-    'nsIClipboardCommands.idl',
     'nsIContentViewer.idl',
     'nsIContentViewerEdit.idl',
     'nsIDocShell.idl',
     'nsIDocShellTreeItem.idl',
     'nsIDocShellTreeOwner.idl',
     'nsIDocumentLoaderFactory.idl',
     'nsILoadContext.idl',
     'nsIPrivacyTransitionObserver.idl',
     'nsIReflowObserver.idl',
     'nsIRefreshURI.idl',
     'nsIScrollable.idl',
-    'nsITextScroll.idl',
     'nsITooltipListener.idl',
     'nsITooltipTextProvider.idl',
     'nsIURIFixup.idl',
     'nsIWebNavigation.idl',
     'nsIWebNavigationInfo.idl',
     'nsIWebPageDescriptor.idl',
 ]
 
 XPIDL_MODULE = 'docshell'
 
 EXPORTS += [
     'nsCTooltipTextProvider.h',
+    'nsDocShell.h',
     'nsDocShellLoadInfo.h',
     'nsDocShellLoadTypes.h',
     'nsDocShellTreeOwner.h',
     'nsILinkHandler.h',
     'nsIScrollObserver.h',
-    'nsIWebShellServices.h',
     'SerializedLoadContext.h',
 ]
 
 EXPORTS.mozilla += [
     'IHistory.h',
     'LoadContext.h',
 ]
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -515,26 +515,23 @@ NS_IMPL_ADDREF_INHERITED(nsDocShell, nsD
 NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocShell)
   NS_INTERFACE_MAP_ENTRY(nsIDocShell)
   NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
   NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
   NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
   NS_INTERFACE_MAP_ENTRY(nsIScrollable)
-  NS_INTERFACE_MAP_ENTRY(nsITextScroll)
   NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
   NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
   NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
   NS_INTERFACE_MAP_ENTRY(nsILoadContext)
-  NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
   NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
-  NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
   NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsINetworkInterceptController,
                                      mInterceptController)
   NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner)
 NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
 
 NS_IMETHODIMP
 nsDocShell::GetInterface(const nsIID& aIID, void** aSink)
@@ -6085,42 +6082,16 @@ nsDocShell::GetScrollbarVisibility(bool*
     *aHorizontalVisible =
       (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) != 0;
   }
 
   return NS_OK;
 }
 
 //*****************************************************************************
-// nsDocShell::nsITextScroll
-//*****************************************************************************
-
-NS_IMETHODIMP
-nsDocShell::ScrollByLines(int32_t aNumLines)
-{
-  nsIScrollableFrame* sf = GetRootScrollFrame();
-  NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
-
-  sf->ScrollBy(nsIntPoint(0, aNumLines), nsIScrollableFrame::LINES,
-               nsIScrollableFrame::SMOOTH);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDocShell::ScrollByPages(int32_t aNumPages)
-{
-  nsIScrollableFrame* sf = GetRootScrollFrame();
-  NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
-
-  sf->ScrollBy(nsIntPoint(0, aNumPages), nsIScrollableFrame::PAGES,
-               nsIScrollableFrame::SMOOTH);
-  return NS_OK;
-}
-
-//*****************************************************************************
 // nsDocShell::nsIRefreshURI
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsDocShell::RefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal,
                        int32_t aDelay, bool aRepeat,
                        bool aMetaRefresh)
 {
@@ -9038,87 +9009,92 @@ nsDocShell::CopyFavicon(nsIURI* aOldURI,
   if (favSvc) {
     favSvc->CopyFavicons(aOldURI, aNewURI,
       aInPrivateBrowsing ? nsIFaviconService::FAVICON_LOAD_PRIVATE
                          : nsIFaviconService::FAVICON_LOAD_NON_PRIVATE, nullptr);
   }
 #endif
 }
 
-class InternalLoadEvent : public Runnable
+struct InternalLoadData 
 {
 public:
-  InternalLoadEvent(nsDocShell* aDocShell,
-                    nsIURI* aURI,
-                    nsIURI* aOriginalURI,
-                    Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
-                    bool aKeepResultPrincipalURIIfSet,
-                    bool aLoadReplace,
-                    nsIURI* aReferrer, uint32_t aReferrerPolicy,
-                    nsIPrincipal* aTriggeringPrincipal,
-                    nsIPrincipal* aPrincipalToInherit,
-                    uint32_t aFlags,
-                    const char* aTypeHint,
-                    nsIInputStream* aPostData,
-                    nsIInputStream* aHeadersData,
-                    uint32_t aLoadType,
-                    nsISHEntry* aSHEntry,
-                    bool aFirstParty,
-                    const nsAString& aSrcdoc,
-                    nsIDocShell* aSourceDocShell,
-                    nsIURI* aBaseURI)
-    : mozilla::Runnable("InternalLoadEvent")
-    , mSrcdoc(aSrcdoc)
+  InternalLoadData(nsDocShell* aDocShell,
+                   nsIURI* aURI,
+                   nsIURI* aOriginalURI,
+                   Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
+                   bool aKeepResultPrincipalURIIfSet,
+                   bool aLoadReplace,
+                   nsIURI* aReferrer, uint32_t aReferrerPolicy,
+                   nsIPrincipal* aTriggeringPrincipal,
+                   nsIPrincipal* aPrincipalToInherit,
+                   uint32_t aFlags,
+                   const nsAString& aWindowTarget,
+                   const char* aTypeHint,
+                   const nsAString& aFileName,
+                   nsIInputStream* aPostData,
+                   nsIInputStream* aHeadersData,
+                   uint32_t aLoadType,
+                   nsISHEntry* aSHEntry,
+                   bool aFirstParty,
+                   const nsAString& aSrcdoc,
+                   nsIDocShell* aSourceDocShell,
+                   nsIURI* aBaseURI,
+                   nsIDocShell** aDocShell2,
+                   nsIRequest** aRequest)
+    : mSrcdoc(aSrcdoc)
     , mDocShell(aDocShell)
     , mURI(aURI)
     , mOriginalURI(aOriginalURI)
     , mResultPrincipalURI(aResultPrincipalURI)
     , mKeepResultPrincipalURIIfSet(aKeepResultPrincipalURIIfSet)
     , mLoadReplace(aLoadReplace)
     , mReferrer(aReferrer)
     , mReferrerPolicy(aReferrerPolicy)
     , mTriggeringPrincipal(aTriggeringPrincipal)
     , mPrincipalToInherit(aPrincipalToInherit)
     , mPostData(aPostData)
     , mHeadersData(aHeadersData)
     , mSHEntry(aSHEntry)
     , mFlags(aFlags)
+    , mWindowTarget(aWindowTarget)
+    , mFileName(aFileName)
     , mLoadType(aLoadType)
     , mFirstParty(aFirstParty)
     , mSourceDocShell(aSourceDocShell)
     , mBaseURI(aBaseURI)
+    , mDocShell2(aDocShell2)
+    , mRequest(aRequest)
   {
     // Make sure to keep null things null as needed
     if (aTypeHint) {
       mTypeHint = aTypeHint;
     } else {
       mTypeHint.SetIsVoid(true);
     }
   }
 
-  NS_IMETHOD
-  Run() override
+  nsresult Run()
   {
     return mDocShell->InternalLoad(mURI, mOriginalURI, mResultPrincipalURI,
                                    mKeepResultPrincipalURIIfSet,
                                    mLoadReplace,
                                    mReferrer,
                                    mReferrerPolicy,
                                    mTriggeringPrincipal, mPrincipalToInherit,
-                                   mFlags, EmptyString(),
+                                   mFlags, mWindowTarget,
                                    mTypeHint.IsVoid() ? nullptr
                                                       : mTypeHint.get(),
-                                   VoidString(), mPostData,
+                                   mFileName, mPostData,
                                    mHeadersData, mLoadType, mSHEntry,
                                    mFirstParty, mSrcdoc, mSourceDocShell,
-                                   mBaseURI, nullptr,
-                                   nullptr);
-  }
-
-private:
+                                   mBaseURI, mDocShell2,
+                                   mRequest);
+  }
+
   nsCString mTypeHint;
   nsString mSrcdoc;
 
   RefPtr<nsDocShell> mDocShell;
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIURI> mOriginalURI;
   Maybe<nsCOMPtr<nsIURI>> mResultPrincipalURI;
   bool mKeepResultPrincipalURIIfSet;
@@ -9126,22 +9102,184 @@ private:
   nsCOMPtr<nsIURI> mReferrer;
   uint32_t mReferrerPolicy;
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
   nsCOMPtr<nsIInputStream> mPostData;
   nsCOMPtr<nsIInputStream> mHeadersData;
   nsCOMPtr<nsISHEntry> mSHEntry;
   uint32_t mFlags;
+  nsString mWindowTarget;
+  nsString mFileName;
   uint32_t mLoadType;
   bool mFirstParty;
   nsCOMPtr<nsIDocShell> mSourceDocShell;
   nsCOMPtr<nsIURI> mBaseURI;
+  nsIDocShell** mDocShell2;
+  nsIRequest** mRequest;
 };
 
+class InternalLoadEvent : public Runnable
+{
+public:
+  InternalLoadEvent(nsDocShell* aDocShell,
+                    nsIURI* aURI,
+                    nsIURI* aOriginalURI,
+                    Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
+                    bool aKeepResultPrincipalURIIfSet,
+                    bool aLoadReplace,
+                    nsIURI* aReferrer,
+                    uint32_t aReferrerPolicy,
+                    nsIPrincipal* aTriggeringPrincipal,
+                    nsIPrincipal* aPrincipalToInherit,
+                    uint32_t aFlags,
+                    const char* aTypeHint,
+                    nsIInputStream* aPostData,
+                    nsIInputStream* aHeadersData,
+                    uint32_t aLoadType,
+                    nsISHEntry* aSHEntry,
+                    bool aFirstParty,
+                    const nsAString& aSrcdoc,
+                    nsIDocShell* aSourceDocShell,
+                    nsIURI* aBaseURI)
+    : mozilla::Runnable("InternalLoadEvent")
+    , mLoadData(aDocShell,
+                aURI,
+                aOriginalURI,
+                aResultPrincipalURI,
+                aKeepResultPrincipalURIIfSet,
+                aLoadReplace,
+                aReferrer,
+                aReferrerPolicy,
+                aTriggeringPrincipal,
+                aPrincipalToInherit,
+                aFlags,
+                EmptyString(),
+                aTypeHint,
+                VoidString(),
+                aPostData,
+                aHeadersData,
+                aLoadType,
+                aSHEntry,
+                aFirstParty,
+                aSrcdoc,
+                aSourceDocShell,
+                aBaseURI,
+                nullptr,
+                nullptr) 
+  {}
+
+  NS_IMETHOD
+  Run() override
+  {
+    return mLoadData.Run();
+  }
+
+private:
+  InternalLoadData mLoadData;
+};
+
+class LoadURIDelegateHandler final : public PromiseNativeHandler
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(LoadURIDelegateHandler)
+
+  LoadURIDelegateHandler(nsDocShell* aDocShell,
+                         nsIURI* aURI,
+                         nsIURI* aOriginalURI,
+                         Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
+                         bool aKeepResultPrincipalURIIfSet,
+                         bool aLoadReplace,
+                         nsIURI* aReferrer,
+                         uint32_t aReferrerPolicy,
+                         nsIPrincipal* aTriggeringPrincipal,
+                         nsIPrincipal* aPrincipalToInherit,
+                         uint32_t aFlags,
+                         const nsAString& aWindowTarget,
+                         const char* aTypeHint,
+                         const nsAString& aFileName,
+                         nsIInputStream* aPostData,
+                         nsIInputStream* aHeadersData,
+                         uint32_t aLoadType,
+                         nsISHEntry* aSHEntry,
+                         bool aFirstParty,
+                         const nsAString& aSrcdoc,
+                         nsIDocShell* aSourceDocShell,
+                         nsIURI* aBaseURI,
+                         nsIDocShell** aDocShell2,
+                         nsIRequest** aRequest)
+    : mLoadData(aDocShell,
+                aURI,
+                aOriginalURI,
+                aResultPrincipalURI,
+                aKeepResultPrincipalURIIfSet,
+                aLoadReplace,
+                aReferrer,
+                aReferrerPolicy,
+                aTriggeringPrincipal,
+                aPrincipalToInherit,
+                aFlags,
+                aWindowTarget,
+                aTypeHint,
+                aFileName,
+                aPostData,
+                aHeadersData,
+                aLoadType,
+                aSHEntry,
+                aFirstParty,
+                aSrcdoc,
+                aSourceDocShell,
+                aBaseURI,
+                aDocShell2,
+                aRequest)
+  {}
+
+  void
+  ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
+  {
+    if (aValue.isBoolean() && !aValue.toBoolean()) {
+      // Things went fine, not handled by app, let Gecko do its thing
+      mLoadData.Run();
+    } else if (!aValue.isBoolean()) {
+      // If the promise resolves to a non-boolean, let Gecko handle the load
+      mLoadData.Run();
+    }
+  }
+
+  void
+  RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
+  {
+    // In the event of a rejected callback, let Gecko handle the load
+    mLoadData.Run();
+  }
+
+private:
+  ~LoadURIDelegateHandler()
+  {}
+
+  InternalLoadData mLoadData;
+};
+
+NS_IMPL_CYCLE_COLLECTION(LoadURIDelegateHandler, mLoadData.mDocShell,
+                         mLoadData.mURI, mLoadData.mOriginalURI,
+                         mLoadData.mResultPrincipalURI, mLoadData.mReferrer,
+                         mLoadData.mTriggeringPrincipal,
+                         mLoadData.mPrincipalToInherit, 
+                         mLoadData.mPostData, mLoadData.mHeadersData,
+                         mLoadData.mSHEntry, mLoadData.mSourceDocShell,
+                         mLoadData.mBaseURI)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LoadURIDelegateHandler)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(LoadURIDelegateHandler)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(LoadURIDelegateHandler)
+
 /**
  * Returns true if we started an asynchronous load (i.e., from the network), but
  * the document we're loading there hasn't yet become this docshell's active
  * document.
  *
  * When JustStartedNetworkLoad is true, you should be careful about modifying
  * mLoadType and mLSHE.  These are both set when the asynchronous load first
  * starts, and the load expects that, when it eventually runs InternalLoad,
@@ -9379,34 +9517,50 @@ nsDocShell::InternalLoad(nsIURI* aURI,
   }
 
   nsIDocument* doc = mContentViewer ? mContentViewer->GetDocument()
                                     : nullptr;
 
   const bool isDocumentAuxSandboxed = doc &&
     (doc->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION);
 
-  if (aURI && mLoadURIDelegate &&
+  const bool checkLoadDelegates = !(aFlags & INTERNAL_LOAD_FLAGS_DELEGATES_CHECKED);
+  aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_DELEGATES_CHECKED;
+
+  if (aURI && mLoadURIDelegate && checkLoadDelegates &&
       (!targetDocShell || targetDocShell == static_cast<nsIDocShell*>(this))) {
     // Dispatch only load requests for the current or a new window to the
     // delegate, e.g., to allow for GeckoView apps to handle the load event
     // outside of Gecko.
     const int where = (aWindowTarget.IsEmpty() || targetDocShell)
                       ? nsIBrowserDOMWindow::OPEN_CURRENTWINDOW
                       : nsIBrowserDOMWindow::OPEN_NEWWINDOW;
 
     if (where == nsIBrowserDOMWindow::OPEN_NEWWINDOW && isDocumentAuxSandboxed) {
       return NS_ERROR_DOM_INVALID_ACCESS_ERR;
     }
 
-    bool loadURIHandled = false;
+    RefPtr<dom::Promise> promise;
     rv = mLoadURIDelegate->LoadURI(aURI, where, aFlags, aTriggeringPrincipal,
-                                   &loadURIHandled);
-    if (NS_SUCCEEDED(rv) && loadURIHandled) {
-      // The request has been handled, nothing to do here.
+                                   getter_AddRefs(promise));
+    if (NS_SUCCEEDED(rv) && promise) {
+      const uint32_t flags = aFlags | INTERNAL_LOAD_FLAGS_DELEGATES_CHECKED;
+
+      RefPtr<LoadURIDelegateHandler> handler = 
+        new LoadURIDelegateHandler(this, aURI, aOriginalURI, aResultPrincipalURI,
+                                   aKeepResultPrincipalURIIfSet,
+                                   aLoadReplace, aReferrer, aReferrerPolicy,
+                                   aTriggeringPrincipal, aPrincipalToInherit,
+                                   flags, aWindowTarget, aTypeHint, aFileName, aPostData,
+                                   aHeadersData, aLoadType, aSHEntry, aFirstParty,
+                                   aSrcdoc, aSourceDocShell, aBaseURI, nullptr, nullptr);
+
+      promise->AppendNativeHandler(handler);
+
+      // Checking for load delegates; InternalLoad will be re-called if needed.
       return NS_OK;
     }
   }
 
   //
   // Resolve the window target before going any further...
   // If the load has been targeted to another DocShell, then transfer the
   // load to it...
@@ -13102,106 +13256,16 @@ nsDocShell::EnsureCommandHandler()
     if (NS_SUCCEEDED(rv)) {
       mCommandManager = do_QueryInterface(commandUpdater);
     }
   }
 
   return mCommandManager ? NS_OK : NS_ERROR_FAILURE;
 }
 
-NS_IMETHODIMP
-nsDocShell::CanCutSelection(bool* aResult)
-{
-  return IsCommandEnabled("cmd_cut", aResult);
-}
-
-NS_IMETHODIMP
-nsDocShell::CanCopySelection(bool* aResult)
-{
-  return IsCommandEnabled("cmd_copy", aResult);
-}
-
-NS_IMETHODIMP
-nsDocShell::CanCopyLinkLocation(bool* aResult)
-{
-  return IsCommandEnabled("cmd_copyLink", aResult);
-}
-
-NS_IMETHODIMP
-nsDocShell::CanCopyImageLocation(bool* aResult)
-{
-  return IsCommandEnabled("cmd_copyImageLocation", aResult);
-}
-
-NS_IMETHODIMP
-nsDocShell::CanCopyImageContents(bool* aResult)
-{
-  return IsCommandEnabled("cmd_copyImageContents", aResult);
-}
-
-NS_IMETHODIMP
-nsDocShell::CanPaste(bool* aResult)
-{
-  return IsCommandEnabled("cmd_paste", aResult);
-}
-
-NS_IMETHODIMP
-nsDocShell::CutSelection(void)
-{
-  return DoCommand("cmd_cut");
-}
-
-NS_IMETHODIMP
-nsDocShell::CopySelection(void)
-{
-  return DoCommand("cmd_copy");
-}
-
-NS_IMETHODIMP
-nsDocShell::CopyLinkLocation(void)
-{
-  return DoCommand("cmd_copyLink");
-}
-
-NS_IMETHODIMP
-nsDocShell::CopyImageLocation(void)
-{
-  return DoCommand("cmd_copyImageLocation");
-}
-
-NS_IMETHODIMP
-nsDocShell::CopyImageContents(void)
-{
-  return DoCommand("cmd_copyImageContents");
-}
-
-NS_IMETHODIMP
-nsDocShell::Paste(void)
-{
-  return DoCommand("cmd_paste");
-}
-
-NS_IMETHODIMP
-nsDocShell::SelectAll(void)
-{
-  return DoCommand("cmd_selectAll");
-}
-
-//
-// SelectNone
-//
-// Collapses the current selection, insertion point ends up at beginning
-// of previous selection.
-//
-NS_IMETHODIMP
-nsDocShell::SelectNone(void)
-{
-  return DoCommand("cmd_selectNone");
-}
-
 // link handling
 
 class OnLinkClickEvent : public Runnable
 {
 public:
   OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
                    nsIURI* aURI,
                    const char16_t* aTargetSpec,
@@ -13596,19 +13660,19 @@ nsDocShell::PluginsAllowedInCurrentDoc()
 
   return doc->GetAllowPlugins();
 }
 
 //----------------------------------------------------------------------
 // Web Shell Services API
 
 // This functions is only called when a new charset is detected in loading a
-// document. Its name should be changed to "CharsetReloadDocument"
-NS_IMETHODIMP
-nsDocShell::ReloadDocument(const char* aCharset, int32_t aSource)
+// document.
+nsresult
+nsDocShell::CharsetChangeReloadDocument(const char* aCharset, int32_t aSource)
 {
   // XXX hack. keep the aCharset and aSource wait to pick it up
   nsCOMPtr<nsIContentViewer> cv;
   NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE);
   if (cv) {
     int32_t hint;
     cv->GetHintCharacterSetSource(&hint);
     if (aSource > hint) {
@@ -13630,18 +13694,18 @@ nsDocShell::ReloadDocument(const char* a
         }
       }
     }
   }
   // return failure if this request is not accepted due to mCharsetReloadState
   return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
 }
 
-NS_IMETHODIMP
-nsDocShell::StopDocumentLoad(void)
+nsresult
+nsDocShell::CharsetChangeStopDocumentLoad()
 {
   if (eCharsetReloadRequested != mCharsetReloadState) {
     Stop(nsIWebNavigation::STOP_ALL);
     return NS_OK;
   }
   // return failer if this request is not accepted due to mCharsetReloadState
   return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
 }
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -17,54 +17,52 @@
 
 #include "mozilla/dom/BrowsingContext.h"
 #include "mozilla/dom/ProfileTimelineMarkerBinding.h"
 #include "mozilla/gfx/Matrix.h"
 #include "mozilla/dom/ChildSHistory.h"
 
 #include "nsIAuthPromptProvider.h"
 #include "nsIBaseWindow.h"
-#include "nsIClipboardCommands.h"
 #include "nsIDeprecationWarner.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDOMStorageManager.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsILinkHandler.h"
 #include "nsILoadContext.h"
 #include "nsILoadURIDelegate.h"
 #include "nsINetworkInterceptController.h"
 #include "nsIRefreshURI.h"
 #include "nsIScrollable.h"
 #include "nsITabParent.h"
-#include "nsITextScroll.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebPageDescriptor.h"
 #include "nsIWebProgressListener.h"
-#include "nsIWebShellServices.h"
 
 #include "nsAutoPtr.h"
+#include "nsCharsetSource.h"
 #include "nsCOMPtr.h"
 #include "nsContentPolicyUtils.h"
 #include "nsContentUtils.h"
 #include "nsCRT.h"
 #include "nsDocLoader.h"
 #include "nsPoint.h" // mCurrent/mDefaultScrollbarPreferences
 #include "nsRect.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 
 #include "GeckoProfiler.h"
 #include "jsapi.h"
 #include "prtime.h"
 #include "Units.h"
 
-#include "timeline/ObservedDocShell.h"
-#include "timeline/TimelineConsumers.h"
-#include "timeline/TimelineMarker.h"
+#include "mozilla/ObservedDocShell.h"
+#include "mozilla/TimelineConsumers.h"
+#include "mozilla/TimelineMarker.h"
 
 // Interfaces Needed
 
 namespace mozilla {
 class Encoding;
 class HTMLEditor;
 enum class TaskCategory;
 namespace dom {
@@ -117,25 +115,22 @@ enum eCharsetReloadState
 };
 
 class nsDocShell final
   : public nsDocLoader
   , public nsIDocShell
   , public nsIWebNavigation
   , public nsIBaseWindow
   , public nsIScrollable
-  , public nsITextScroll
   , public nsIRefreshURI
   , public nsIWebProgressListener
   , public nsIWebPageDescriptor
   , public nsIAuthPromptProvider
   , public nsILoadContext
-  , public nsIWebShellServices
   , public nsILinkHandler
-  , public nsIClipboardCommands
   , public nsIDOMStorageManager
   , public nsINetworkInterceptController
   , public nsIDeprecationWarner
   , public mozilla::SupportsWeakPtr<nsDocShell>
 {
 public:
   // Event type dispatched by RestorePresentation
   class RestorePresentationEvent : public mozilla::Runnable
@@ -168,24 +163,21 @@ public:
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsDocShell)
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDocShell, nsDocLoader)
   NS_DECL_NSIDOCSHELL
   NS_DECL_NSIDOCSHELLTREEITEM
   NS_DECL_NSIWEBNAVIGATION
   NS_DECL_NSIBASEWINDOW
   NS_DECL_NSISCROLLABLE
-  NS_DECL_NSITEXTSCROLL
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIWEBPROGRESSLISTENER
   NS_DECL_NSIREFRESHURI
   NS_DECL_NSIWEBPAGEDESCRIPTOR
   NS_DECL_NSIAUTHPROMPTPROVIDER
-  NS_DECL_NSICLIPBOARDCOMMANDS
-  NS_DECL_NSIWEBSHELLSERVICES
   NS_DECL_NSINETWORKINTERCEPTCONTROLLER
   NS_DECL_NSIDEPRECATIONWARNER
 
   NS_FORWARD_SAFE_NSIDOMSTORAGEMANAGER(TopSessionStorageManager())
 
   // Need to implement (and forward) nsISecurityEventSink, because
   // nsIWebProgressListener has methods with identical names...
   NS_FORWARD_NSISECURITYEVENTSINK(nsDocLoader::)
@@ -278,16 +270,21 @@ public:
   }
   bool InFrameSwap();
 
   const mozilla::Encoding* GetForcedCharset() { return mForcedCharset; }
 
   mozilla::HTMLEditor* GetHTMLEditorInternal();
   nsresult SetHTMLEditorInternal(mozilla::HTMLEditor* aHTMLEditor);
 
+  // Handle page navigation due to charset changes
+  nsresult CharsetChangeReloadDocument(const char* aCharset = nullptr,
+                                               int32_t aSource = kCharsetUninitialized);
+  nsresult CharsetChangeStopDocumentLoad();
+
   nsDOMNavigationTiming* GetNavigationTiming() const;
 
   nsresult SetOriginAttributes(const mozilla::OriginAttributes& aAttrs);
 
   /**
    * Get the list of ancestor principals for this docshell.  The list is meant
    * to be the list of principals of the documents this docshell is "nested
    * through" in the sense of
deleted file mode 100644
--- a/docshell/base/nsIClipboardCommands.idl
+++ /dev/null
@@ -1,111 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-/**
- * An interface for embedding clients who wish to interact with
- * the system-wide OS clipboard. Mozilla does not use a private
- * clipboard, instead it places its data directly onto the system 
- * clipboard. The webshell implements this interface.
- */
-
-[scriptable, uuid(b8100c90-73be-11d2-92a5-00105a1b0d64)]
-interface nsIClipboardCommands : nsISupports {
-
-  /**
-   * Returns whether there is a selection and it is not read-only.
-   *
-   * @return <code>true</code> if the current selection can be cut,
-   *          <code>false</code> otherwise.
-   */
-  boolean canCutSelection();
-
-  /**
-   * Returns whether there is a selection and it is copyable.
-   *
-   * @return <code>true</code> if there is a selection,
-   *          <code>false</code> otherwise.
-   */
-  boolean canCopySelection();
-
-  /**
-   * Returns whether we can copy a link location.
-   *
-   * @return <code>true</code> if a link is selected,
-   *           <code>false</code> otherwise.
-   */
-  boolean canCopyLinkLocation();
-
-  /**
-   * Returns whether we can copy an image location.
-   *
-   * @return <code>true</code> if an image is selected,
-              <code>false</code> otherwise.
-   */
-  boolean canCopyImageLocation();
-
-  /**
-   * Returns whether we can copy an image's contents.
-   *
-   * @return <code>true</code> if an image is selected,
-   *          <code>false</code> otherwise
-   */
-  boolean canCopyImageContents();
-
-  /**
-   * Returns whether the current contents of the clipboard can be
-   * pasted and if the current selection is not read-only.
-   *
-   * @return <code>true</code> there is data to paste on the clipboard
-   *          and the current selection is not read-only,
-   *          <code>false</code> otherwise
-   */
-  boolean canPaste();
-
-  /**
-   * Cut the current selection onto the clipboard.
-   */
-  void cutSelection();
-
-  /**
-   * Copy the current selection onto the clipboard.
-   */
-  void copySelection();
-
-  /**
-   * Copy the link location of the current selection (e.g.,
-   * the |href| attribute of a selected |a| tag).
-   */
-  void copyLinkLocation();
-
-  /**
-   * Copy the location of the selected image.
-   */
-  void copyImageLocation();
-
-  /**
-   * Copy the contents of the selected image.
-   */
-  void copyImageContents();
-
-  /**
-   * Paste the contents of the clipboard into the current selection.
-   */
-  void paste();
-
-  /**
-   * Select the entire contents.
-   */
-  void selectAll();
-
-  /**
-   * Clear the current selection (if any). Insertion point ends up
-   * at beginning of current selection.
-   */
-  void selectNone();
-
-};
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -113,16 +113,19 @@ interface nsIDocShell : nsIDocShellTreeI
   // Whether this is the load of a frame's original src attribute
   const long INTERNAL_LOAD_FLAGS_ORIGINAL_FRAME_SRC      = 0x80;
 
   const long INTERNAL_LOAD_FLAGS_NO_OPENER               = 0x100;
 
   // Whether a top-level data URI navigation is allowed for that load
   const long INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI    = 0x200;
 
+  // Whether load delegates have already been checked for this load
+  const long INTERNAL_LOAD_FLAGS_DELEGATES_CHECKED       = 0x400;
+
   // Whether the load was triggered by user interaction.
   const long INTERNAL_LOAD_FLAGS_IS_USER_TRIGGERED       = 0x1000;
 
   /**
    * Loads the given URI.  This method is identical to loadURI(...) except
    * that its parameter list is broken out instead of being packaged inside
    * of an nsIDocShellLoadInfo object...
    *
deleted file mode 100644
--- a/docshell/base/nsITextScroll.idl
+++ /dev/null
@@ -1,33 +0,0 @@
-/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-/**
- * The nsITextScroll is an interface that can be implemented by a control that
- * supports text scrolling. 
- */
-
-[scriptable, uuid(067B28A0-877F-11d3-AF7E-00A024FFC08C)]
-interface nsITextScroll : nsISupports
-{
-  /**
-   * Scroll the view up or down by aNumLines lines. positive
-   * values move down in the view. Prevents scrolling off the
-   * end of the view.
-   * @param numLines number of lines to scroll the view by
-   */
-	void scrollByLines(in long numLines);
-
-	/**
-   * Scroll the view up or down by numPages pages. a page
-   * is considered to be the amount displayed by the clip view.
-   * positive values move down in the view. Prevents scrolling
-   * off the end of the view.
-   * @param numPages number of pages to scroll the view by
-   */
-	void scrollByPages(in long numPages);
-};
\ No newline at end of file
deleted file mode 100644
--- a/docshell/base/nsIWebShellServices.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#ifndef nsIWebShellServices_h___
-#define nsIWebShellServices_h___
-
-#include "nsISupports.h"
-#include "nsCharsetSource.h"
-
-/* 0c628af0-5638-4703-8f99-ed6134c9de18 */
-#define NS_IWEB_SHELL_SERVICES_IID \
-{ 0x0c628af0, 0x5638, 0x4703, {0x8f, 0x99, 0xed, 0x61, 0x34, 0xc9, 0xde, 0x18} }
-
-class nsIWebShellServices : public nsISupports
-{
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWEB_SHELL_SERVICES_IID)
-
-  NS_IMETHOD ReloadDocument(const char* aCharset = nullptr,
-                            int32_t aSource = kCharsetUninitialized) = 0;
-  NS_IMETHOD StopDocumentLoad(void) = 0;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIWebShellServices, NS_IWEB_SHELL_SERVICES_IID)
-
-/* Use this macro when declaring classes that implement this interface. */
-#define NS_DECL_NSIWEBSHELLSERVICES \
-  NS_IMETHOD ReloadDocument(const char* aCharset = nullptr, \
-                            int32_t aSource = kCharsetUninitialized) override; \
-  NS_IMETHOD StopDocumentLoad(void) override;
-
-#endif /* nsIWebShellServices_h___ */
--- a/docshell/test/chrome/bug89419_window.xul
+++ b/docshell/test/chrome/bug89419_window.xul
@@ -5,18 +5,16 @@
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         width="600"
         height="600"
         onload="setTimeout(nextTest,0);"
         title="bug 89419 test">
 
   <script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
   <script type="text/javascript"
-          src="chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js"/>
-  <script type="text/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js"/>
   <script type="text/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/specialpowers.js"/>
   <script type="application/javascript" src="docshell_helpers.js" />
   <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
 
   <script type="application/javascript"><![CDATA[
     // Define the generator-iterator for the tests.
rename from dom/base/nsAttrAndChildArray.cpp
rename to dom/base/AttrArray.cpp
--- a/dom/base/nsAttrAndChildArray.cpp
+++ b/dom/base/AttrArray.cpp
@@ -4,122 +4,69 @@
  * 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/. */
 
 /*
  * Storage of the children and attributes of a DOM node; storage for
  * the two is unified to minimize footprint.
  */
 
-#include "nsAttrAndChildArray.h"
+#include "AttrArray.h"
 
 #include "mozilla/CheckedInt.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/MemoryReporting.h"
 
 #include "nsMappedAttributeElement.h"
 #include "nsString.h"
 #include "nsHTMLStyleSheet.h"
 #include "nsMappedAttributes.h"
 #include "nsUnicharUtils.h"
 #include "nsContentUtils.h" // nsAutoScriptBlocker
 
 using mozilla::CheckedUint32;
 
-/*
-CACHE_POINTER_SHIFT indicates how many steps to downshift the |this| pointer.
-It should be small enough to not cause collisions between adjecent arrays, and
-large enough to make sure that all indexes are used. The size below is based
-on the size of the smallest possible element (currently 20[*] bytes) which is
-the smallest distance between two nsAttrAndChildArray. 20/(2^_5_) is 0.625.
-This means that two adjacent nsAttrAndChildArrays will overlap one in 2.7 times.
-However not all elements will have enough children to get cached. And any
-allocator that doesn't return addresses aligned to 64 bytes will ensure that
-any index will get used.
-
-[*] sizeof(Element).  Except is that really 20 bytes?  Seems dubious!
-*/
-
-#define CACHE_POINTER_SHIFT 5
-#define CACHE_NUM_SLOTS 128
-#define CACHE_CHILD_LIMIT 10
-
-#define CACHE_GET_INDEX(_array) \
-  ((NS_PTR_TO_INT32(_array) >> CACHE_POINTER_SHIFT) & \
-   (CACHE_NUM_SLOTS - 1))
-
-struct IndexCacheSlot
-{
-  const nsAttrAndChildArray* array;
-  int32_t index;
-};
-
-// This is inited to all zeroes since it's static. Though even if it wasn't
-// the worst thing that'd happen is a small inefficency if you'd get a false
-// positive cachehit.
-static IndexCacheSlot indexCache[CACHE_NUM_SLOTS];
-
-static
-inline
-void
-AddIndexToCache(const nsAttrAndChildArray* aArray, int32_t aIndex)
-{
-  uint32_t ix = CACHE_GET_INDEX(aArray);
-  indexCache[ix].array = aArray;
-  indexCache[ix].index = aIndex;
-}
-
-static
-inline
-int32_t
-GetIndexFromCache(const nsAttrAndChildArray* aArray)
-{
-  uint32_t ix = CACHE_GET_INDEX(aArray);
-  return indexCache[ix].array == aArray ? indexCache[ix].index : -1;
-}
-
-
 /**
  * Due to a compiler bug in VisualAge C++ for AIX, we need to return the
  * address of the first index into mBuffer here, instead of simply returning
  * mBuffer itself.
  *
  * See Bug 231104 for more information.
  */
 #define ATTRS(_impl) \
   reinterpret_cast<InternalAttr*>(&((_impl)->mBuffer[0]))
 
 
 #define NS_IMPL_EXTRA_SIZE \
   ((sizeof(Impl) - sizeof(mImpl->mBuffer)) / sizeof(void*))
 
-nsAttrAndChildArray::nsAttrAndChildArray()
+AttrArray::AttrArray()
   : mImpl(nullptr)
 {
 }
 
-nsAttrAndChildArray::~nsAttrAndChildArray()
+AttrArray::~AttrArray()
 {
   if (!mImpl) {
     return;
   }
 
   Clear();
 
   free(mImpl);
 }
 
 uint32_t
-nsAttrAndChildArray::AttrCount() const
+AttrArray::AttrCount() const
 {
   return NonMappedAttrCount() + MappedAttrCount();
 }
 
 const nsAttrValue*
-nsAttrAndChildArray::GetAttr(nsAtom* aLocalName, int32_t aNamespaceID) const
+AttrArray::GetAttr(nsAtom* aLocalName, int32_t aNamespaceID) const
 {
   uint32_t i, slotCount = AttrSlotCount();
   if (aNamespaceID == kNameSpaceID_None) {
     // This should be the common case so lets make an optimized loop
     for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
       if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
         return &ATTRS(mImpl)[i].mValue;
       }
@@ -136,35 +83,35 @@ nsAttrAndChildArray::GetAttr(nsAtom* aLo
       }
     }
   }
 
   return nullptr;
 }
 
 const nsAttrValue*
-nsAttrAndChildArray::GetAttr(const nsAString& aLocalName) const
+AttrArray::GetAttr(const nsAString& aLocalName) const
 {
   uint32_t i, slotCount = AttrSlotCount();
   for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
       return &ATTRS(mImpl)[i].mValue;
     }
   }
 
   if (mImpl && mImpl->mMappedAttrs) {
     return mImpl->mMappedAttrs->GetAttr(aLocalName);
   }
 
   return nullptr;
 }
 
 const nsAttrValue*
-nsAttrAndChildArray::GetAttr(const nsAString& aName,
-                             nsCaseTreatment aCaseSensitive) const
+AttrArray::GetAttr(const nsAString& aName,
+                   nsCaseTreatment aCaseSensitive) const
 {
   // Check whether someone is being silly and passing non-lowercase
   // attr names.
   if (aCaseSensitive == eIgnoreCase &&
       nsContentUtils::StringContainsASCIIUpper(aName)) {
     // Try again with a lowercased name, but make sure we can't reenter this
     // block by passing eCaseSensitive for aCaseSensitive.
     nsAutoString lowercase;
@@ -186,60 +133,57 @@ nsAttrAndChildArray::GetAttr(const nsASt
       return val;
     }
   }
 
   return nullptr;
 }
 
 const nsAttrValue*
-nsAttrAndChildArray::AttrAt(uint32_t aPos) const
+AttrArray::AttrAt(uint32_t aPos) const
 {
   NS_ASSERTION(aPos < AttrCount(),
-               "out-of-bounds access in nsAttrAndChildArray");
+               "out-of-bounds access in AttrArray");
 
   uint32_t nonmapped = NonMappedAttrCount();
   if (aPos < nonmapped) {
     return &ATTRS(mImpl)[aPos].mValue;
   }
 
   return mImpl->mMappedAttrs->AttrAt(aPos - nonmapped);
 }
 
 nsresult
-nsAttrAndChildArray::SetAndSwapAttr(nsAtom* aLocalName, nsAttrValue& aValue,
-                                    bool* aHadValue)
+AttrArray::SetAndSwapAttr(nsAtom* aLocalName, nsAttrValue& aValue,
+                          bool* aHadValue)
 {
   *aHadValue = false;
   uint32_t i, slotCount = AttrSlotCount();
   for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
       ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
       *aHadValue = true;
       return NS_OK;
     }
   }
 
-  NS_ENSURE_TRUE(i < ATTRCHILD_ARRAY_MAX_ATTR_COUNT,
-                 NS_ERROR_FAILURE);
-
   if (i == slotCount && !AddAttrSlot()) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   new (&ATTRS(mImpl)[i].mName) nsAttrName(aLocalName);
   new (&ATTRS(mImpl)[i].mValue) nsAttrValue();
   ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
 
   return NS_OK;
 }
 
 nsresult
-nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName,
-                                    nsAttrValue& aValue, bool* aHadValue)
+AttrArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName,
+                          nsAttrValue& aValue, bool* aHadValue)
 {
   int32_t namespaceID = aName->NamespaceID();
   nsAtom* localName = aName->NameAtom();
   if (namespaceID == kNameSpaceID_None) {
     return SetAndSwapAttr(localName, aValue, aHadValue);
   }
 
   *aHadValue = false;
@@ -248,33 +192,29 @@ nsAttrAndChildArray::SetAndSwapAttr(mozi
     if (ATTRS(mImpl)[i].mName.Equals(localName, namespaceID)) {
       ATTRS(mImpl)[i].mName.SetTo(aName);
       ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
       *aHadValue = true;
       return NS_OK;
     }
   }
 
-  NS_ENSURE_TRUE(i < ATTRCHILD_ARRAY_MAX_ATTR_COUNT,
-                 NS_ERROR_FAILURE);
-
   if (i == slotCount && !AddAttrSlot()) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   new (&ATTRS(mImpl)[i].mName) nsAttrName(aName);
   new (&ATTRS(mImpl)[i].mValue) nsAttrValue();
   ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
 
   return NS_OK;
 }
 
-
 nsresult
-nsAttrAndChildArray::RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue)
+AttrArray::RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue)
 {
   NS_ASSERTION(aPos < AttrCount(), "out-of-bounds");
 
   uint32_t nonmapped = NonMappedAttrCount();
   if (aPos < nonmapped) {
     ATTRS(mImpl)[aPos].mValue.SwapValueWith(aValue);
     ATTRS(mImpl)[aPos].~InternalAttr();
 
@@ -300,46 +240,46 @@ nsAttrAndChildArray::RemoveAttrAt(uint32
     GetModifiableMapped(nullptr, nullptr, false);
 
   mapped->RemoveAttrAt(aPos - nonmapped, aValue);
 
   return MakeMappedUnique(mapped);
 }
 
 mozilla::dom::BorrowedAttrInfo
-nsAttrAndChildArray::AttrInfoAt(uint32_t aPos) const
+AttrArray::AttrInfoAt(uint32_t aPos) const
 {
   NS_ASSERTION(aPos < AttrCount(),
-               "out-of-bounds access in nsAttrAndChildArray");
+               "out-of-bounds access in AttrArray");
 
   uint32_t nonmapped = NonMappedAttrCount();
   if (aPos < nonmapped) {
     return BorrowedAttrInfo(&ATTRS(mImpl)[aPos].mName, &ATTRS(mImpl)[aPos].mValue);
   }
 
   return BorrowedAttrInfo(mImpl->mMappedAttrs->NameAt(aPos - nonmapped),
                     mImpl->mMappedAttrs->AttrAt(aPos - nonmapped));
 }
 
 const nsAttrName*
-nsAttrAndChildArray::AttrNameAt(uint32_t aPos) const
+AttrArray::AttrNameAt(uint32_t aPos) const
 {
   NS_ASSERTION(aPos < AttrCount(),
-               "out-of-bounds access in nsAttrAndChildArray");
+               "out-of-bounds access in AttrArray");
 
   uint32_t nonmapped = NonMappedAttrCount();
   if (aPos < nonmapped) {
     return &ATTRS(mImpl)[aPos].mName;
   }
 
   return mImpl->mMappedAttrs->NameAt(aPos - nonmapped);
 }
 
 const nsAttrName*
-nsAttrAndChildArray::GetSafeAttrNameAt(uint32_t aPos) const
+AttrArray::GetSafeAttrNameAt(uint32_t aPos) const
 {
   uint32_t nonmapped = NonMappedAttrCount();
   if (aPos < nonmapped) {
     void** pos = mImpl->mBuffer + aPos * ATTRSIZE;
     if (!*pos) {
       return nullptr;
     }
 
@@ -349,34 +289,34 @@ nsAttrAndChildArray::GetSafeAttrNameAt(u
   if (aPos >= AttrCount()) {
     return nullptr;
   }
 
   return mImpl->mMappedAttrs->NameAt(aPos - nonmapped);
 }
 
 const nsAttrName*
-nsAttrAndChildArray::GetExistingAttrNameFromQName(const nsAString& aName) const
+AttrArray::GetExistingAttrNameFromQName(const nsAString& aName) const
 {
   uint32_t i, slotCount = AttrSlotCount();
   for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     if (ATTRS(mImpl)[i].mName.QualifiedNameEquals(aName)) {
       return &ATTRS(mImpl)[i].mName;
     }
   }
 
   if (mImpl && mImpl->mMappedAttrs) {
     return mImpl->mMappedAttrs->GetExistingAttrNameFromQName(aName);
   }
 
   return nullptr;
 }
 
 int32_t
-nsAttrAndChildArray::IndexOfAttr(nsAtom* aLocalName, int32_t aNamespaceID) const
+AttrArray::IndexOfAttr(nsAtom* aLocalName, int32_t aNamespaceID) const
 {
   int32_t idx;
   if (mImpl && mImpl->mMappedAttrs && aNamespaceID == kNameSpaceID_None) {
     idx = mImpl->mMappedAttrs->IndexOfAttr(aLocalName);
     if (idx >= 0) {
       return NonMappedAttrCount() + idx;
     }
   }
@@ -404,68 +344,68 @@ nsAttrAndChildArray::IndexOfAttr(nsAtom*
       }
     }
   }
 
   return -1;
 }
 
 nsresult
-nsAttrAndChildArray::SetAndSwapMappedAttr(nsAtom* aLocalName,
-                                          nsAttrValue& aValue,
-                                          nsMappedAttributeElement* aContent,
-                                          nsHTMLStyleSheet* aSheet,
-                                          bool* aHadValue)
+AttrArray::SetAndSwapMappedAttr(nsAtom* aLocalName,
+                                nsAttrValue& aValue,
+                                nsMappedAttributeElement* aContent,
+                                nsHTMLStyleSheet* aSheet,
+                                bool* aHadValue)
 {
   bool willAdd = true;
   if (mImpl && mImpl->mMappedAttrs) {
     willAdd = !mImpl->mMappedAttrs->GetAttr(aLocalName);
   }
 
   RefPtr<nsMappedAttributes> mapped =
     GetModifiableMapped(aContent, aSheet, willAdd);
 
   mapped->SetAndSwapAttr(aLocalName, aValue, aHadValue);
 
   return MakeMappedUnique(mapped);
 }
 
 nsresult
-nsAttrAndChildArray::DoSetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet)
+AttrArray::DoSetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet)
 {
   MOZ_ASSERT(mImpl && mImpl->mMappedAttrs,
                   "Should have mapped attrs here!");
   if (aSheet == mImpl->mMappedAttrs->GetStyleSheet()) {
     return NS_OK;
   }
 
   RefPtr<nsMappedAttributes> mapped =
     GetModifiableMapped(nullptr, nullptr, false);
 
   mapped->SetStyleSheet(aSheet);
 
   return MakeMappedUnique(mapped);
 }
 
 nsresult
-nsAttrAndChildArray::DoUpdateMappedAttrRuleMapper(nsMappedAttributeElement& aElement)
+AttrArray::DoUpdateMappedAttrRuleMapper(nsMappedAttributeElement& aElement)
 {
   MOZ_ASSERT(mImpl && mImpl->mMappedAttrs, "Should have mapped attrs here!");
 
   // First two args don't matter if the assert holds.
   RefPtr<nsMappedAttributes> mapped =
     GetModifiableMapped(nullptr, nullptr, false);
 
   mapped->SetRuleMapper(aElement.GetAttributeMappingFunction());
 
   return MakeMappedUnique(mapped);
 }
 
 void
-nsAttrAndChildArray::Compact()
+AttrArray::Compact()
 {
   if (!mImpl) {
     return;
   }
 
   // First compress away empty attrslots
   uint32_t slotCount = AttrSlotCount();
   uint32_t attrCount = NonMappedAttrCount();
@@ -484,89 +424,90 @@ nsAttrAndChildArray::Compact()
     mImpl = static_cast<Impl*>(realloc(mImpl, (newSize + NS_IMPL_EXTRA_SIZE) * sizeof(nsIContent*)));
     NS_ASSERTION(mImpl, "failed to reallocate to smaller buffer");
 
     mImpl->mBufferSize = newSize;
   }
 }
 
 void
-nsAttrAndChildArray::Clear()
+AttrArray::Clear()
 {
   if (!mImpl) {
     return;
   }
 
   if (mImpl->mMappedAttrs) {
     NS_RELEASE(mImpl->mMappedAttrs);
   }
 
   uint32_t i, slotCount = AttrSlotCount();
   for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     ATTRS(mImpl)[i].~InternalAttr();
   }
 
-  SetAttrSlotAndChildCount(0, 0);
+  SetAttrSlotCount(0);
 }
 
 uint32_t
-nsAttrAndChildArray::NonMappedAttrCount() const
+AttrArray::NonMappedAttrCount() const
 {
   if (!mImpl) {
     return 0;
   }
 
   uint32_t count = AttrSlotCount();
   while (count > 0 && !mImpl->mBuffer[(count - 1) * ATTRSIZE]) {
     --count;
   }
 
   return count;
 }
 
 uint32_t
-nsAttrAndChildArray::MappedAttrCount() const
+AttrArray::MappedAttrCount() const
 {
   return mImpl && mImpl->mMappedAttrs ? (uint32_t)mImpl->mMappedAttrs->Count() : 0;
 }
 
 nsresult
-nsAttrAndChildArray::ForceMapped(nsMappedAttributeElement* aContent, nsIDocument* aDocument)
+AttrArray::ForceMapped(nsMappedAttributeElement* aContent, nsIDocument* aDocument)
 {
   nsHTMLStyleSheet* sheet = aDocument->GetAttributeStyleSheet();
   RefPtr<nsMappedAttributes> mapped = GetModifiableMapped(aContent, sheet, false, 0);
   return MakeMappedUnique(mapped);
 }
 
 void
-nsAttrAndChildArray::ClearMappedServoStyle() {
+AttrArray::ClearMappedServoStyle()
+{
   if (mImpl && mImpl->mMappedAttrs) {
     mImpl->mMappedAttrs->ClearServoStyle();
   }
 }
 
 nsMappedAttributes*
-nsAttrAndChildArray::GetModifiableMapped(nsMappedAttributeElement* aContent,
-                                         nsHTMLStyleSheet* aSheet,
-                                         bool aWillAddAttr,
-                                         int32_t aAttrCount)
+AttrArray::GetModifiableMapped(nsMappedAttributeElement* aContent,
+                               nsHTMLStyleSheet* aSheet,
+                               bool aWillAddAttr,
+                               int32_t aAttrCount)
 {
   if (mImpl && mImpl->mMappedAttrs) {
     return mImpl->mMappedAttrs->Clone(aWillAddAttr);
   }
 
   MOZ_ASSERT(aContent, "Trying to create modifiable without content");
 
   nsMapRuleToAttributesFunc mapRuleFunc =
     aContent->GetAttributeMappingFunction();
   return new (aAttrCount) nsMappedAttributes(aSheet, mapRuleFunc);
 }
 
 nsresult
-nsAttrAndChildArray::MakeMappedUnique(nsMappedAttributes* aAttributes)
+AttrArray::MakeMappedUnique(nsMappedAttributes* aAttributes)
 {
   NS_ASSERTION(aAttributes, "missing attributes");
 
   if (!mImpl && !GrowBy(1)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (!aAttributes->GetStyleSheet()) {
@@ -591,56 +532,57 @@ nsAttrAndChildArray::MakeMappedUnique(ns
     aAttributes->DropStyleSheetReference();
   }
   mapped.swap(mImpl->mMappedAttrs);
 
   return NS_OK;
 }
 
 const nsMappedAttributes*
-nsAttrAndChildArray::GetMapped() const
+AttrArray::GetMapped() const
 {
   return mImpl ? mImpl->mMappedAttrs : nullptr;
 }
 
-nsresult nsAttrAndChildArray::EnsureCapacityToClone(const nsAttrAndChildArray& aOther,
-                                                    bool aAllocateChildren)
+nsresult
+AttrArray::EnsureCapacityToClone(const AttrArray& aOther,
+                                 bool aAllocateChildren)
 {
-  MOZ_ASSERT(!mImpl, "nsAttrAndChildArray::EnsureCapacityToClone requires the array be empty when called");
+  MOZ_ASSERT(!mImpl, "AttrArray::EnsureCapacityToClone requires the array be empty when called");
 
   uint32_t attrCount = aOther.NonMappedAttrCount();
 
   if (attrCount == 0) {
     return NS_OK;
   }
 
   // No need to use a CheckedUint32 because we are cloning. We know that we
-  // have already allocated an nsAttrAndChildArray of this size.
+  // have already allocated an AttrArray of this size.
   uint32_t size = attrCount;
   size *= ATTRSIZE;
   uint32_t totalSize = size;
   totalSize += NS_IMPL_EXTRA_SIZE;
 
   mImpl = static_cast<Impl*>(malloc(totalSize * sizeof(void*)));
   NS_ENSURE_TRUE(mImpl, NS_ERROR_OUT_OF_MEMORY);
 
   mImpl->mMappedAttrs = nullptr;
   mImpl->mBufferSize = size;
 
   // The array is now the right size, but we should reserve the correct
   // number of slots for attributes so that children don't get written into
   // that part of the array (which will then need to be moved later).
   memset(static_cast<void*>(mImpl->mBuffer), 0, sizeof(InternalAttr) * attrCount);
-  SetAttrSlotAndChildCount(attrCount, 0);
+  SetAttrSlotCount(attrCount);
 
   return NS_OK;
 }
 
 bool
-nsAttrAndChildArray::GrowBy(uint32_t aGrowSize)
+AttrArray::GrowBy(uint32_t aGrowSize)
 {
   CheckedUint32 size = 0;
   if (mImpl) {
     size += mImpl->mBufferSize;
     size += NS_IMPL_EXTRA_SIZE;
     if (!size.isValid()) {
       return false;
     }
@@ -679,26 +621,26 @@ nsAttrAndChildArray::GrowBy(uint32_t aGr
   Impl* newImpl = static_cast<Impl*>(realloc(mImpl, neededSize.value()));
   NS_ENSURE_TRUE(newImpl, false);
 
   mImpl = newImpl;
 
   // Set initial counts if we didn't have a buffer before
   if (needToInitialize) {
     mImpl->mMappedAttrs = nullptr;
-    SetAttrSlotAndChildCount(0, 0);
+    SetAttrSlotCount(0);
   }
 
   mImpl->mBufferSize = size.value() - NS_IMPL_EXTRA_SIZE;
 
   return true;
 }
 
 bool
-nsAttrAndChildArray::AddAttrSlot()
+AttrArray::AddAttrSlot()
 {
   uint32_t slotCount = AttrSlotCount();
 
   CheckedUint32 size = slotCount;
   size += 1;
   size *= ATTRSIZE;
   if (!size.isValid()) {
     return false;
@@ -714,17 +656,17 @@ nsAttrAndChildArray::AddAttrSlot()
 
   SetAttrSlotCount(slotCount + 1);
   memset(static_cast<void*>(offset), 0, sizeof(InternalAttr));
 
   return true;
 }
 
 size_t
-nsAttrAndChildArray::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+AttrArray::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   size_t n = 0;
   if (mImpl) {
     // Don't add the size taken by *mMappedAttrs because it's shared.
 
     n += aMallocSizeOf(mImpl);
 
     uint32_t slotCount = AttrSlotCount();
rename from dom/base/nsAttrAndChildArray.h
rename to dom/base/AttrArray.h
--- a/dom/base/nsAttrAndChildArray.h
+++ b/dom/base/AttrArray.h
@@ -1,21 +1,20 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
- * Storage of the children and attributes of a DOM node; storage for
- * the two is unified to minimize footprint.
+ * Storage of the attributes of a DOM node.
  */
 
-#ifndef nsAttrAndChildArray_h___
-#define nsAttrAndChildArray_h___
+#ifndef AttrArray_h___
+#define AttrArray_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/BorrowedAttrInfo.h"
 
 #include "nscore.h"
 #include "nsAttrName.h"
 #include "nsAttrValue.h"
@@ -26,36 +25,24 @@ class nsIContent;
 class nsMappedAttributes;
 class nsHTMLStyleSheet;
 class nsRuleWalker;
 class nsMappedAttributeElement;
 
 #define ATTRCHILD_ARRAY_GROWSIZE 8
 #define ATTRCHILD_ARRAY_LINEAR_THRESHOLD 32
 
-#define ATTRCHILD_ARRAY_ATTR_SLOTS_BITS 10
-
-#define ATTRCHILD_ARRAY_MAX_ATTR_COUNT \
-    ((1 << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS) - 1)
-
-#define ATTRCHILD_ARRAY_MAX_CHILD_COUNT \
-    (~uint32_t(0) >> ATTRCHILD_ARRAY_ATTR_SLOTS_BITS)
-
-#define ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK \
-    ((1 << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS) - 1)
-
-
 #define ATTRSIZE (sizeof(InternalAttr) / sizeof(void*))
 
-class nsAttrAndChildArray
+class AttrArray
 {
   typedef mozilla::dom::BorrowedAttrInfo BorrowedAttrInfo;
 public:
-  nsAttrAndChildArray();
-  ~nsAttrAndChildArray();
+  AttrArray();
+  ~AttrArray();
 
   bool HasAttrs() const
   {
     return MappedAttrCount() || (AttrSlotCount() && AttrSlotIsTaken(0));
   }
 
   uint32_t AttrCount() const;
   const nsAttrValue* GetAttr(nsAtom* aLocalName,
@@ -116,22 +103,16 @@ public:
     if (!mImpl || !mImpl->mMappedAttrs) {
       return NS_OK;
     }
     return DoUpdateMappedAttrRuleMapper(aElement);
   }
 
   void Compact();
 
-  bool CanFitMoreAttrs() const
-  {
-    return AttrSlotCount() < ATTRCHILD_ARRAY_MAX_ATTR_COUNT ||
-           !AttrSlotIsTaken(ATTRCHILD_ARRAY_MAX_ATTR_COUNT - 1);
-  }
-
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   bool HasMappedAttrs() const
   {
     return MappedAttrCount();
   }
   const nsMappedAttributes* GetMapped() const;
 
   // Force this to have mapped attributes, even if those attributes are empty.
@@ -140,22 +121,22 @@ public:
   // Clear the servo declaration block on the mapped attributes, if any
   // Will assert off main thread
   void ClearMappedServoStyle();
 
   // Increases capacity (if necessary) to have enough space to accomodate the
   // unmapped attributes and children of |aOther|. If |aAllocateChildren| is not
   // true, only enough space for unmapped attributes will be reserved.
   // It is REQUIRED that this function be called ONLY when the array is empty.
-  nsresult EnsureCapacityToClone(const nsAttrAndChildArray& aOther,
+  nsresult EnsureCapacityToClone(const AttrArray& aOther,
                                  bool aAllocateChildren);
 
 private:
-  nsAttrAndChildArray(const nsAttrAndChildArray& aOther) = delete;
-  nsAttrAndChildArray& operator=(const nsAttrAndChildArray& aOther) = delete;
+  AttrArray(const AttrArray& aOther) = delete;
+  AttrArray& operator=(const AttrArray& aOther) = delete;
 
   void Clear();
 
   uint32_t NonMappedAttrCount() const;
   uint32_t MappedAttrCount() const;
 
   // Returns a non-null zero-refcount object.
   nsMappedAttributes*
@@ -167,43 +148,28 @@ private:
 
   uint32_t AttrSlotsSize() const
   {
     return AttrSlotCount() * ATTRSIZE;
   }
 
   uint32_t AttrSlotCount() const
   {
-    return mImpl ? mImpl->mAttrAndChildCount & ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK : 0;
+    return mImpl ? mImpl->mAttrCount : 0;
   }
 
   bool AttrSlotIsTaken(uint32_t aSlot) const
   {
     MOZ_ASSERT(aSlot < AttrSlotCount(), "out-of-bounds");
     return mImpl->mBuffer[aSlot * ATTRSIZE];
   }
 
-  void SetChildCount(uint32_t aCount)
-  {
-    mImpl->mAttrAndChildCount =
-        (mImpl->mAttrAndChildCount & ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK) |
-        (aCount << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS);
-  }
-
   void SetAttrSlotCount(uint32_t aCount)
   {
-    mImpl->mAttrAndChildCount =
-        (mImpl->mAttrAndChildCount & ~ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK) |
-        aCount;
-  }
-
-  void SetAttrSlotAndChildCount(uint32_t aSlotCount, uint32_t aChildCount)
-  {
-    mImpl->mAttrAndChildCount = aSlotCount |
-      (aChildCount << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS);
+    mImpl->mAttrCount = aCount;
   }
 
   bool GrowBy(uint32_t aGrowSize);
   bool AddAttrSlot();
 
   /**
    * Guts of SetMappedAttrStyleSheet for the rare case when we have mapped attrs
    */
@@ -216,17 +182,17 @@ private:
 
   struct InternalAttr
   {
     nsAttrName mName;
     nsAttrValue mValue;
   };
 
   struct Impl {
-    uint32_t mAttrAndChildCount;
+    uint32_t mAttrCount;
     uint32_t mBufferSize;
     nsMappedAttributes* mMappedAttrs;
     void* mBuffer[1];
   };
 
   Impl* mImpl;
 };
 
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -322,17 +322,17 @@ Element::UpdateEditableState(bool aNotif
       AddStatesSilently(NS_EVENT_STATE_MOZ_READONLY);
     }
   }
 }
 
 int32_t
 Element::TabIndex()
 {
-  const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsGkAtoms::tabindex);
+  const nsAttrValue* attrVal = mAttrs.GetAttr(nsGkAtoms::tabindex);
   if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
     return attrVal->GetIntegerValue();
   }
 
   return TabIndexDefault();
 }
 
 void
@@ -640,19 +640,19 @@ Element::ClassList()
   }
 
   return slots->mClassList;
 }
 
 void
 Element::GetAttributeNames(nsTArray<nsString>& aResult)
 {
-  uint32_t count = mAttrsAndChildren.AttrCount();
+  uint32_t count = mAttrs.AttrCount();
   for (uint32_t i = 0; i < count; ++i) {
-    const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i);
+    const nsAttrName* name = mAttrs.AttrNameAt(i);
     name->GetQualifiedName(*aResult.AppendElement());
   }
 }
 
 already_AddRefed<nsIHTMLCollection>
 Element::GetElementsByTagName(const nsAString& aLocalName)
 {
   return NS_GetContentList(this, kNameSpaceID_Unknown, aLocalName);
@@ -1292,19 +1292,19 @@ Element::UnattachShadow()
   MOZ_ASSERT(!GetShadowRoot()->HasSlots(), "Won't work when shadow root has slots!");
   SetShadowRoot(nullptr);
 }
 
 void
 Element::GetAttribute(const nsAString& aName, DOMString& aReturn)
 {
   const nsAttrValue* val =
-    mAttrsAndChildren.GetAttr(aName,
-                              IsHTMLElement() && IsInHTMLDocument() ?
-                                eIgnoreCase : eCaseMatters);
+    mAttrs.GetAttr(aName,
+                   IsHTMLElement() && IsInHTMLDocument() ?
+                     eIgnoreCase : eCaseMatters);
   if (val) {
     val->ToString(aReturn);
   } else {
     if (IsXULElement()) {
       // XXX should be SetDOMStringToNull(aReturn);
       // See bug 232598
       // aReturn is already empty
     } else {
@@ -2151,29 +2151,29 @@ Element::IsInteractiveHTMLContent(bool a
 }
 
 DeclarationBlock*
 Element::GetInlineStyleDeclaration() const
 {
   if (!MayHaveStyle()) {
     return nullptr;
   }
-  const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
+  const nsAttrValue* attrVal = mAttrs.GetAttr(nsGkAtoms::style);
 
   if (attrVal && attrVal->Type() == nsAttrValue::eCSSDeclaration) {
     return attrVal->GetCSSDeclarationValue();
   }
 
   return nullptr;
 }
 
 const nsMappedAttributes*
 Element::GetMappedAttributes() const
 {
-  return mAttrsAndChildren.GetMapped();
+  return mAttrs.GetMapped();
 }
 
 void
 Element::InlineStyleDeclarationWillChange(MutationClosureData& aData)
 {
   MOZ_ASSERT_UNREACHABLE("Element::InlineStyleDeclarationWillChange");
 }
 
@@ -2403,22 +2403,22 @@ Element::InternalGetAttrNameFromQName(co
                                       nsAutoString* aNameToUse) const
 {
   MOZ_ASSERT(!aNameToUse || aNameToUse->IsEmpty());
   const nsAttrName* val = nullptr;
   if (IsHTMLElement() && IsInHTMLDocument()) {
     nsAutoString lower;
     nsAutoString& outStr = aNameToUse ? *aNameToUse : lower;
     nsContentUtils::ASCIIToLower(aStr, outStr);
-    val = mAttrsAndChildren.GetExistingAttrNameFromQName(outStr);
+    val = mAttrs.GetExistingAttrNameFromQName(outStr);
     if (val) {
       outStr.Truncate();
     }
   } else {
-    val = mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
+    val = mAttrs.GetExistingAttrNameFromQName(aStr);
     if (!val && aNameToUse) {
       *aNameToUse = aStr;
     }
   }
 
   return val;
 }
 
@@ -2497,20 +2497,16 @@ Element::OnlyNotifySameValueSet(int32_t 
   return true;
 }
 
 nsresult
 Element::SetSingleClassFromParser(nsAtom* aSingleClassName)
 {
   // Keep this in sync with SetAttr and SetParsedAttr below.
 
-  if (!mAttrsAndChildren.CanFitMoreAttrs()) {
-    return NS_ERROR_FAILURE;
-  }
-
   nsAttrValue value(aSingleClassName);
 
   nsIDocument* document = GetComposedDoc();
   mozAutoDocUpdate updateBatch(document, false);
 
   // In principle, BeforeSetAttr should be called here if a node type
   // existed that wanted to do something special for class, but there
   // is no such node type, so calling SetMayHaveClass() directly.
@@ -2538,20 +2534,16 @@ Element::SetAttr(int32_t aNamespaceID, n
 {
   // Keep this in sync with SetParsedAttr below and SetSingleClassFromParser
   // above.
 
   NS_ENSURE_ARG_POINTER(aName);
   NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
                "Don't call SetAttr with unknown namespace");
 
-  if (!mAttrsAndChildren.CanFitMoreAttrs()) {
-    return NS_ERROR_FAILURE;
-  }
-
   uint8_t modType;
   bool hasListeners;
   // We don't want to spend time preparsing class attributes if the value is not
   // changing, so just init our nsAttrValueOrString with aValue for the
   // OnlyNotifySameValueSet call.
   nsAttrValueOrString value(aValue);
   nsAttrValue oldValue;
   bool oldValueSet;
@@ -2605,21 +2597,16 @@ Element::SetParsedAttr(int32_t aNamespac
                        bool aNotify)
 {
   // Keep this in sync with SetAttr and SetSingleClassFromParser above
 
   NS_ENSURE_ARG_POINTER(aName);
   NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
                "Don't call SetAttr with unknown namespace");
 
-  if (!mAttrsAndChildren.CanFitMoreAttrs()) {
-    return NS_ERROR_FAILURE;
-  }
-
-
   uint8_t modType;
   bool hasListeners;
   nsAttrValueOrString value(aParsedValue);
   nsAttrValue oldValue;
   bool oldValueSet;
 
   if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
                              oldValue, &modType, &hasListeners, &oldValueSet)) {
@@ -2677,26 +2664,26 @@ Element::SetAttrAndNotify(int32_t aNames
       hadValidDir = HasValidDir() || IsHTMLElement(nsGkAtoms::bdi);
       hadDirAuto = HasDirAuto(); // already takes bdi into account
     }
 
     // XXXbz Perhaps we should push up the attribute mapping function
     // stuff to Element?
     if (!IsAttributeMapped(aName) ||
         !SetAndSwapMappedAttribute(aName, aParsedValue, &oldValueSet, &rv)) {
-      rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue, &oldValueSet);
+      rv = mAttrs.SetAndSwapAttr(aName, aParsedValue, &oldValueSet);
     }
   }
   else {
     RefPtr<mozilla::dom::NodeInfo> ni;
     ni = mNodeInfo->NodeInfoManager()->GetNodeInfo(aName, aPrefix,
                                                    aNamespaceID,
                                                    ATTRIBUTE_NODE);
 
-    rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue, &oldValueSet);
+    rv = mAttrs.SetAndSwapAttr(ni, aParsedValue, &oldValueSet);
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   PostIdMaybeChange(aNamespaceID, aName, &valueForAfterSetAttr);
 
   // If the old value owns its own data, we know it is OK to keep using it.
   // oldValue will be null if there was no previously set value
   const nsAttrValue* oldValue;
@@ -2940,17 +2927,17 @@ Element::FindAttrValueIn(int32_t aNameSp
                          nsAtom* aName,
                          AttrValuesArray* aValues,
                          nsCaseTreatment aCaseSensitive) const
 {
   NS_ASSERTION(aName, "Must have attr name");
   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
   NS_ASSERTION(aValues, "Null value array");
 
-  const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
+  const nsAttrValue* val = mAttrs.GetAttr(aName, aNameSpaceID);
   if (val) {
     for (int32_t i = 0; aValues[i]; ++i) {
       if (val->Equals(*aValues[i], aCaseSensitive)) {
         return i;
       }
     }
     return ATTR_VALUE_NO_MATCH;
   }
@@ -2958,17 +2945,17 @@ Element::FindAttrValueIn(int32_t aNameSp
 }
 
 nsresult
 Element::UnsetAttr(int32_t aNameSpaceID, nsAtom* aName,
                    bool aNotify)
 {
   NS_ASSERTION(nullptr != aName, "must have attribute name");
 
-  int32_t index = mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID);
+  int32_t index = mAttrs.IndexOfAttr(aName, aNameSpaceID);
   if (index < 0) {
     return NS_OK;
   }
 
   nsIDocument *document = GetComposedDoc();
   mozAutoDocUpdate updateBatch(document, aNotify);
 
   if (aNotify) {
@@ -3009,17 +2996,17 @@ Element::UnsetAttr(int32_t aNameSpaceID,
   bool hadDirAuto = false;
 
   if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
     hadValidDir = HasValidDir() || IsHTMLElement(nsGkAtoms::bdi);
     hadDirAuto = HasDirAuto(); // already takes bdi into account
   }
 
   nsAttrValue oldValue;
-  rv = mAttrsAndChildren.RemoveAttrAt(index, oldValue);
+  rv = mAttrs.RemoveAttrAt(index, oldValue);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PostIdMaybeChange(aNameSpaceID, aName, nullptr);
 
   if (document) {
     RefPtr<nsXBLBinding> binding = GetXBLBinding();
     if (binding) {
       binding->AttributeChanged(aName, aNameSpaceID, true, aNotify);
@@ -3081,35 +3068,35 @@ Element::UnsetAttr(int32_t aNameSpaceID,
 
   return NS_OK;
 }
 
 void
 Element::DescribeAttribute(uint32_t index, nsAString& aOutDescription) const
 {
   // name
-  mAttrsAndChildren.AttrNameAt(index)->GetQualifiedName(aOutDescription);
+  mAttrs.AttrNameAt(index)->GetQualifiedName(aOutDescription);
 
   // value
   aOutDescription.AppendLiteral("=\"");
   nsAutoString value;
-  mAttrsAndChildren.AttrAt(index)->ToString(value);
+  mAttrs.AttrAt(index)->ToString(value);
   for (uint32_t i = value.Length(); i > 0; --i) {
     if (value[i - 1] == char16_t('"'))
       value.Insert(char16_t('\\'), i - 1);
   }
   aOutDescription.Append(value);
   aOutDescription.Append('"');
 }
 
 #ifdef DEBUG
 void
 Element::ListAttributes(FILE* out) const
 {
-  uint32_t index, count = mAttrsAndChildren.AttrCount();
+  uint32_t index, count = mAttrs.AttrCount();
   for (index = 0; index < count; index++) {
     nsAutoString attributeDescription;
     DescribeAttribute(index, attributeDescription);
 
     fputs(" ", out);
     fputs(NS_LossyConvertUTF16toASCII(attributeDescription).get(), out);
   }
 }
@@ -3237,17 +3224,17 @@ Element::DumpContent(FILE* out, int32_t 
 #endif
 
 void
 Element::Describe(nsAString& aOutDescription) const
 {
   aOutDescription.Append(mNodeInfo->QualifiedName());
   aOutDescription.AppendPrintf("@%p", (void *)this);
 
-  uint32_t index, count = mAttrsAndChildren.AttrCount();
+  uint32_t index, count = mAttrs.AttrCount();
   for (index = 0; index < count; index++) {
     aOutDescription.Append(' ');
     nsAutoString attributeDescription;
     DescribeAttribute(index, attributeDescription);
     aOutDescription.Append(attributeDescription);
   }
 }
 
@@ -4102,17 +4089,17 @@ Element::GetEnumAttr(nsAtom* aAttr,
 }
 
 void
 Element::GetEnumAttr(nsAtom* aAttr,
                      const char* aDefaultMissing,
                      const char* aDefaultInvalid,
                      nsAString& aResult) const
 {
-  const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
+  const nsAttrValue* attrVal = mAttrs.GetAttr(aAttr);
 
   aResult.Truncate();
 
   if (!attrVal) {
     if (aDefaultMissing) {
       AppendASCIItoUTF16(nsDependentCString(aDefaultMissing), aResult);
     } else {
       SetDOMStringToNull(aResult);
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -16,17 +16,17 @@
 #include "mozilla/dom/FragmentOrElement.h" // for base class
 #include "nsChangeHint.h"                  // for enum
 #include "mozilla/EventStates.h"           // for member
 #include "mozilla/ServoTypes.h"
 #include "mozilla/dom/DirectionalityUtils.h"
 #include "nsILinkHandler.h"
 #include "nsINodeList.h"
 #include "nsNodeUtils.h"
-#include "nsAttrAndChildArray.h"
+#include "AttrArray.h"
 #include "mozilla/FlushType.h"
 #include "nsDOMAttributeMap.h"
 #include "nsPresContext.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/Attributes.h"
 #include "nsIScrollableFrame.h"
 #include "mozilla/dom/Attr.h"
 #include "nsISMILAttr.h"
@@ -315,18 +315,19 @@ public:
    */
   DeclarationBlock* GetInlineStyleDeclaration() const;
 
   /**
    * Get the mapped attributes, if any, for this element.
    */
   const nsMappedAttributes* GetMappedAttributes() const;
 
-  void ClearMappedServoStyle() {
-    mAttrsAndChildren.ClearMappedServoStyle();
+  void ClearMappedServoStyle()
+  {
+    mAttrs.ClearMappedServoStyle();
   }
 
   /**
    * InlineStyleDeclarationWillChange is called before SetInlineStyleDeclaration
    * so that the element implementation can access the old style attribute
    * value.
    */
   virtual void InlineStyleDeclarationWillChange(MutationClosureData& aData);
@@ -911,39 +912,39 @@ public:
    *          out-of-bounds.
    * @note    The document returned by NodeInfo()->GetDocument() (if one is
    *          present) is *not* necessarily the owner document of the element.
    * @note    The pointer returned by this function is only valid until the
    *          next call of either GetAttrNameAt or SetAttr on the element.
    */
   const nsAttrName* GetAttrNameAt(uint32_t aIndex) const
   {
-    return mAttrsAndChildren.GetSafeAttrNameAt(aIndex);
+    return mAttrs.GetSafeAttrNameAt(aIndex);
   }
 
   /**
    * Gets the attribute info (name and value) for this element at a given index.
    */
   BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const
   {
-    if (aIndex >= mAttrsAndChildren.AttrCount()) {
+    if (aIndex >= mAttrs.AttrCount()) {
       return BorrowedAttrInfo(nullptr, nullptr);
     }
 
-    return mAttrsAndChildren.AttrInfoAt(aIndex);
+    return mAttrs.AttrInfoAt(aIndex);
   }
 
   /**
    * Get the number of all specified attributes.
    *
    * @return the number of attributes
    */
   uint32_t GetAttrCount() const
   {
-    return mAttrsAndChildren.AttrCount();
+    return mAttrs.AttrCount();
   }
 
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
 
   /**
    * Get the class list of this element (this corresponds to the value of the
    * class attribute).  This may be null if there are no classes, but that's not
    * guaranteed (e.g. we could have class="").
@@ -1024,32 +1025,32 @@ private:
 protected:
   inline bool GetAttr(int32_t aNameSpaceID, nsAtom* aName,
                       DOMString& aResult) const
   {
     NS_ASSERTION(nullptr != aName, "must have attribute name");
     NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
                  "must have a real namespace ID!");
     MOZ_ASSERT(aResult.IsEmpty(), "Should have empty string coming in");
-    const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
+    const nsAttrValue* val = mAttrs.GetAttr(aName, aNameSpaceID);
     if (val) {
       val->ToString(aResult);
       return true;
     }
     // else DOMString comes pre-emptied.
     return false;
   }
 
 public:
-  bool HasAttrs() const { return mAttrsAndChildren.HasAttrs(); }
+  bool HasAttrs() const { return mAttrs.HasAttrs(); }
 
   inline bool GetAttr(const nsAString& aName, DOMString& aResult) const
   {
     MOZ_ASSERT(aResult.IsEmpty(), "Should have empty string coming in");
-    const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName);
+    const nsAttrValue* val = mAttrs.GetAttr(aName);
     if (val) {
       val->ToString(aResult);
       return true;
     }
     // else DOMString comes pre-emptied.
     return false;
   }
 
@@ -1457,22 +1458,22 @@ public:
 
   bool IsDisplayContents() const
   {
     return HasServoData() && Servo_Element_IsDisplayContents(this);
   }
 
   const nsAttrValue* GetParsedAttr(nsAtom* aAttr) const
   {
-    return mAttrsAndChildren.GetAttr(aAttr);
+    return mAttrs.GetAttr(aAttr);
   }
 
   const nsAttrValue* GetParsedAttr(nsAtom* aAttr, int32_t aNameSpaceID) const
   {
-    return mAttrsAndChildren.GetAttr(aAttr, aNameSpaceID);
+    return mAttrs.GetAttr(aAttr, aNameSpaceID);
   }
 
   /**
    * Returns the attribute map, if there is one.
    *
    * @return existing attribute map or nullptr.
    */
   nsDOMAttributeMap* GetAttributeMap()
@@ -1487,30 +1488,30 @@ public:
   }
 
   /**
    * Get the attr info for the given namespace ID and attribute name.  The
    * namespace ID must not be kNameSpaceID_Unknown and the name must not be
    * null.  Note that this can only return info on attributes that actually
    * live on this element (and is only virtual to handle XUL prototypes).  That
    * is, this should only be called from methods that only care about attrs
-   * that effectively live in mAttrsAndChildren.
+   * that effectively live in mAttrs.
    */
   BorrowedAttrInfo GetAttrInfo(int32_t aNamespaceID, nsAtom* aName) const
   {
     NS_ASSERTION(aName, "must have attribute name");
     NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
                  "must have a real namespace ID!");
 
-    int32_t index = mAttrsAndChildren.IndexOfAttr(aName, aNamespaceID);
+    int32_t index = mAttrs.IndexOfAttr(aName, aNamespaceID);
     if (index < 0) {
       return BorrowedAttrInfo(nullptr, nullptr);
     }
 
-    return mAttrsAndChildren.AttrInfoAt(index);
+    return mAttrs.AttrInfoAt(index);
   }
 
   /**
    * Called when we have been adopted, and the information of the
    * node has been changed.
    *
    * The new document can be reached via OwnerDoc().
    *
@@ -2016,43 +2017,43 @@ NS_DEFINE_STATIC_IID_ACCESSOR(Element, N
 
 inline bool
 Element::HasAttr(int32_t aNameSpaceID, nsAtom* aName) const
 {
   NS_ASSERTION(nullptr != aName, "must have attribute name");
   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
                "must have a real namespace ID!");
 
-  return mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID) >= 0;
+  return mAttrs.IndexOfAttr(aName, aNameSpaceID) >= 0;
 }
 
 inline bool
 Element::AttrValueIs(int32_t aNameSpaceID,
                      nsAtom* aName,
                      const nsAString& aValue,
                      nsCaseTreatment aCaseSensitive) const
 {
   NS_ASSERTION(aName, "Must have attr name");
   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
 
-  const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
+  const nsAttrValue* val = mAttrs.GetAttr(aName, aNameSpaceID);
   return val && val->Equals(aValue, aCaseSensitive);
 }
 
 inline bool
 Element::AttrValueIs(int32_t aNameSpaceID,
                      nsAtom* aName,
                      nsAtom* aValue,
                      nsCaseTreatment aCaseSensitive) const
 {
   NS_ASSERTION(aName, "Must have attr name");
   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
   NS_ASSERTION(aValue, "Null value atom");
 
-  const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
+  const nsAttrValue* val = mAttrs.GetAttr(aName, aNameSpaceID);
   return val && val->Equals(aValue, aCaseSensitive);
 }
 
 } // namespace dom
 } // namespace mozilla
 
 inline mozilla::dom::Element* nsINode::AsElement()
 {
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -2014,22 +2014,22 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
         }
       }
     }
   }
 
   // Traverse attribute names.
   {
     uint32_t i;
-    uint32_t attrs = tmp->mAttrsAndChildren.AttrCount();
+    uint32_t attrs = tmp->mAttrs.AttrCount();
     for (i = 0; i < attrs; i++) {
-      const nsAttrName* name = tmp->mAttrsAndChildren.AttrNameAt(i);
+      const nsAttrName* name = tmp->mAttrs.AttrNameAt(i);
       if (!name->IsAtom()) {
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
-                                           "mAttrsAndChildren[i]->NodeInfo()");
+                                           "mAttrs[i]->NodeInfo()");
         cb.NoteNativeChild(name->NodeInfo(),
                            NS_CYCLE_COLLECTION_PARTICIPANT(NodeInfo));
       }
     }
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 
@@ -2038,24 +2038,24 @@ NS_INTERFACE_MAP_BEGIN(FragmentOrElement
 NS_INTERFACE_MAP_END_INHERITING(nsIContent)
 
 //----------------------------------------------------------------------
 
 nsresult
 FragmentOrElement::CopyInnerTo(FragmentOrElement* aDst,
                                bool aPreallocateChildren)
 {
-  nsresult rv = aDst->mAttrsAndChildren.EnsureCapacityToClone(mAttrsAndChildren,
-                                                              aPreallocateChildren);
+  nsresult rv = aDst->mAttrs.EnsureCapacityToClone(mAttrs,
+                                                   aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  uint32_t i, count = mAttrsAndChildren.AttrCount();
+  uint32_t i, count = mAttrs.AttrCount();
   for (i = 0; i < count; ++i) {
-    const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i);
-    const nsAttrValue* value = mAttrsAndChildren.AttrAt(i);
+    const nsAttrName* name = mAttrs.AttrNameAt(i);
+    const nsAttrValue* value = mAttrs.AttrAt(i);
     nsAutoString valStr;
     value->ToString(valStr);
     rv = aDst->AsElement()->SetAttr(name->NamespaceID(), name->LocalName(),
                                     name->GetPrefix(), valStr, false);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
@@ -2318,15 +2318,15 @@ FragmentOrElement::FireNodeRemovedForChi
 }
 
 void
 FragmentOrElement::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
                                           size_t* aNodeSize) const
 {
   nsIContent::AddSizeOfExcludingThis(aSizes, aNodeSize);
   *aNodeSize +=
-    mAttrsAndChildren.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
+    mAttrs.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
 
   nsDOMSlots* slots = GetExistingDOMSlots();
   if (slots) {
     *aNodeSize += slots->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
   }
 }
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -11,17 +11,17 @@
  */
 
 #ifndef FragmentOrElement_h___
 #define FragmentOrElement_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/UniquePtr.h"
-#include "nsAttrAndChildArray.h"          // member
+#include "AttrArray.h"                    // member
 #include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
 #include "nsIContent.h"                   // base class
 #include "nsNodeUtils.h"                  // class member nsNodeUtils::CloneNodeImpl
 #include "nsIHTMLCollection.h"
 #include "nsDataHashtable.h"
 #include "nsXBLBinding.h"
 
 class ContentUnbinder;
@@ -323,19 +323,19 @@ protected:
 
   nsExtendedDOMSlots* GetExistingExtendedDOMSlots()
   {
     return static_cast<nsExtendedDOMSlots*>(GetExistingExtendedContentSlots());
   }
 
   friend class ::ContentUnbinder;
   /**
-   * Array containing all attributes and children for this element
+   * Array containing all attributes for this element
    */
-  nsAttrAndChildArray mAttrsAndChildren;
+  AttrArray mAttrs;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #define NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE                               \
     if (NS_SUCCEEDED(rv))                                                     \
       return rv;                                                              \
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -28,23 +28,23 @@ XPIDL_SOURCES += [
     'nsISelectionDisplay.idl',
     'nsISelectionListener.idl',
     'nsISlowScriptDebug.idl',
 ]
 
 XPIDL_MODULE = 'dom'
 
 EXPORTS += [
+    'AttrArray.h',
     'AutocompleteFieldList.h',
     'Crypto.h',
     'HTMLSplitOnSpacesTokenizer.h',
     'IframeSandboxKeywordList.h',
     'mozAutoDocUpdate.h',
     'NodeUbiReporting.h',
-    'nsAttrAndChildArray.h',
     'nsAttrName.h',
     'nsAttrValue.h',
     'nsAttrValueInlines.h',
     'nsCaseTreatment.h',
     'nsChildContentList.h',
     'nsContentCID.h',
     'nsContentCreatorFunctions.h',
     'nsContentList.h',
@@ -233,16 +233,17 @@ EXPORTS.mozilla.dom += [
 if CONFIG['FUZZING']:
     EXPORTS.mozilla.dom += [
         'FuzzingFunctions.h',
     ]
 
 UNIFIED_SOURCES += [
     'AnonymousContent.cpp',
     'Attr.cpp',
+    'AttrArray.cpp',
     'BarProps.cpp',
     'BodyUtil.cpp',
     'BorrowedAttrInfo.cpp',
     'CharacterData.cpp',
     'ChildIterator.cpp',
     'ChromeMessageBroadcaster.cpp',
     'ChromeMessageSender.cpp',
     'ChromeNodeList.cpp',
@@ -284,17 +285,16 @@ UNIFIED_SOURCES += [
     'MessageListenerManager.cpp',
     'MessageManagerGlobal.cpp',
     'MessageSender.cpp',
     'MozQueryInterface.cpp',
     'Navigator.cpp',
     'NodeInfo.cpp',
     'NodeIterator.cpp',
     'NodeUbiReporting.cpp',
-    'nsAttrAndChildArray.cpp',
     'nsAttrValue.cpp',
     'nsAttrValueOrString.cpp',
     'nsCCUncollectableMarker.cpp',
     'nsContentAreaDragDrop.cpp',
     'nsContentIterator.cpp',
     'nsContentList.cpp',
     'nsContentPermissionHelper.cpp',
     'nsContentPolicy.cpp',
--- a/dom/base/nsAttrName.h
+++ b/dom/base/nsAttrName.h
@@ -96,17 +96,17 @@ public:
   }
 
   bool Equals(const nsAttrName& aOther) const
   {
     return mBits == aOther.mBits;
   }
 
   // Faster comparison in the case we know the namespace is null
-  // Note that some callers such as nsAttrAndChildArray::IndexOfAttr() will
+  // Note that some callers such as AttrArray::IndexOfAttr() will
   // call this function on nsAttrName structs with 0 mBits, so no attempt
   // must be made to do anything with mBits besides comparing it with the
   // incoming aAtom argument.
   bool Equals(nsAtom* aAtom) const
   {
     return reinterpret_cast<uintptr_t>(aAtom) == mBits;
   }
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1954,17 +1954,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCSSLoader)
 
   // We own only the items in mDOMMediaQueryLists that have listeners;
   // this reference is managed by their AddListener and RemoveListener
   // methods.
   for (MediaQueryList* mql = tmp->mDOMMediaQueryLists.getFirst(); mql;
        mql = static_cast<LinkedListElement<MediaQueryList>*>(mql)->getNext()) {
-    if (mql->HasListeners()) {
+    if (mql->HasListeners() &&
+        NS_SUCCEEDED(mql->CheckInnerWindowCorrectness())) {
       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDOMMediaQueryLists item");
       cb.NoteXPCOMChild(mql);
     }
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument)
 
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2,17 +2,16 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsIDocument_h___
 #define nsIDocument_h___
 
 #include "mozilla/FlushType.h"           // for enum
-#include "nsAttrAndChildArray.h"
 #include "nsAutoPtr.h"                   // for member
 #include "nsCOMArray.h"                  // for member
 #include "nsCompatibility.h"             // for member
 #include "nsCOMPtr.h"                    // for member
 #include "nsGkAtoms.h"                   // for static class members
 #include "nsIApplicationCache.h"
 #include "nsIApplicationCacheContainer.h"
 #include "nsIContentViewer.h"
@@ -4415,19 +4414,16 @@ protected:
   RefPtr<nsContentList> mImageMaps;
 
   // A set of responsive images keyed by address pointer.
   nsTHashtable<nsPtrHashKey<mozilla::dom::HTMLImageElement>> mResponsiveContent;
 
   // Tracking for plugins in the document.
   nsTHashtable<nsPtrHashKey<nsIObjectLoadingContent>> mPlugins;
 
-  // Array of owning references to all children
-  nsAttrAndChildArray mChildren;
-
   RefPtr<mozilla::dom::DocumentTimeline> mDocumentTimeline;
   mozilla::LinkedList<mozilla::dom::DocumentTimeline> mTimelines;
 
   RefPtr<mozilla::dom::ScriptLoader> mScriptLoader;
 
   nsRefPtrHashtable<nsPtrHashKey<nsIContent>, mozilla::dom::BoxObject>*
     mBoxObjectTable;
 
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -30,17 +30,17 @@
 
 // Including 'windows.h' will #define GetClassInfo to something else.
 #ifdef XP_WIN
 #ifdef GetClassInfo
 #undef GetClassInfo
 #endif
 #endif
 
-class nsAttrAndChildArray;
+class AttrArray;
 class nsAttrChildContentList;
 class nsDOMAttributeMap;
 class nsIAnimationObserver;
 class nsIContent;
 class nsIDocument;
 class nsIFrame;
 class nsIHTMLCollection;
 class nsIMutationObserver;
@@ -362,17 +362,17 @@ public:
   // way that |this| points to the start of the allocated object, even in
   // methods of nsINode's sub-classes, so aSizes.mState.mMallocSizeOf(this) is
   // always safe to call no matter which object it was invoked on.
   void AddSizeOfIncludingThis(nsWindowSizes& aSizes, size_t* aNodeSize) const;
 
   friend class nsNodeUtils;
   friend class nsNodeWeakReference;
   friend class nsNodeSupportsWeakRefTearoff;
-  friend class nsAttrAndChildArray;
+  friend class AttrArray;
 
 #ifdef MOZILLA_INTERNAL_API
   explicit nsINode(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 #endif
 
   virtual ~nsINode();
 
   /**
--- a/dom/base/nsMappedAttributeElement.cpp
+++ b/dom/base/nsMappedAttributeElement.cpp
@@ -10,18 +10,18 @@
 
 bool
 nsMappedAttributeElement::SetAndSwapMappedAttribute(nsAtom* aName,
                                                     nsAttrValue& aValue,
                                                     bool* aValueWasSet,
                                                     nsresult* aRetval)
 {
   nsHTMLStyleSheet* sheet = OwnerDoc()->GetAttributeStyleSheet();
-  *aRetval = mAttrsAndChildren.SetAndSwapMappedAttr(aName, aValue,
-                                                    this, sheet, aValueWasSet);
+  *aRetval = mAttrs.SetAndSwapMappedAttr(aName, aValue,
+                                         this, sheet, aValueWasSet);
   return true;
 }
 
 nsMapRuleToAttributesFunc
 nsMappedAttributeElement::GetAttributeMappingFunction() const
 {
   return &MapNoAttributesInto;
 }
@@ -31,11 +31,11 @@ nsMappedAttributeElement::MapNoAttribute
                                               mozilla::MappedDeclarations&)
 {
 }
 
 void
 nsMappedAttributeElement::NodeInfoChanged(nsIDocument* aOldDoc)
 {
   nsHTMLStyleSheet* sheet = OwnerDoc()->GetAttributeStyleSheet();
-  mAttrsAndChildren.SetMappedAttrStyleSheet(sheet);
+  mAttrs.SetMappedAttrStyleSheet(sheet);
   nsMappedAttributeElementBase::NodeInfoChanged(aOldDoc);
 }
--- a/dom/base/nsMappedAttributes.h
+++ b/dom/base/nsMappedAttributes.h
@@ -7,17 +7,17 @@
 /*
  * A unique per-element set of attributes that is used as an
  * nsIStyleRule; used to implement presentational attributes.
  */
 
 #ifndef nsMappedAttributes_h___
 #define nsMappedAttributes_h___
 
-#include "nsAttrAndChildArray.h"
+#include "AttrArray.h"
 #include "nsMappedAttributeElement.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ServoBindingTypes.h"
 #include "mozilla/MemoryReporting.h"
 
 class nsAtom;
 class nsHTMLStyleSheet;
 
--- a/dom/base/nsStyledElement.cpp
+++ b/dom/base/nsStyledElement.cpp
@@ -159,27 +159,27 @@ nsStyledElement::Style()
 }
 
 nsresult
 nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc, bool aForceIfAlreadyParsed)
 {
   if (!MayHaveStyle()) {
     return NS_OK;
   }
-  const nsAttrValue* oldVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
+  const nsAttrValue* oldVal = mAttrs.GetAttr(nsGkAtoms::style);
   if (oldVal && (aForceIfAlreadyParsed || oldVal->Type() != nsAttrValue::eCSSDeclaration)) {
     nsAttrValue attrValue;
     nsAutoString stringValue;
     oldVal->ToString(stringValue);
     ParseStyleAttribute(stringValue, nullptr, attrValue, aForceInDataDoc);
     // Don't bother going through SetInlineStyleDeclaration; we don't
     // want to fire off mutation events or document notifications anyway
     bool oldValueSet;
-    nsresult rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue,
-                                                   &oldValueSet);
+    nsresult rv = mAttrs.SetAndSwapAttr(nsGkAtoms::style, attrValue,
+                                        &oldValueSet);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 void
 nsStyledElement::NodeInfoChanged(nsIDocument* aOldDoc)
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -482,17 +482,16 @@ skip-if = toolkit == 'android' || (verif
 [test_bug599588.html]
 [test_bug601803.html]
 [test_bug602838.html]
 [test_bug604592.html]
 [test_bug604660.html]
 [test_bug605982.html]
 [test_bug606729.html]
 [test_bug614058.html]
-[test_bug614583.html]
 [test_bug622088.html]
 [test_bug622117.html]
 [test_bug622246.html]
 [test_bug625722.html]
 [test_bug626262.html]
 [test_bug628938.html]
 [test_bug631615.html]
 [test_bug638112.html]
deleted file mode 100644
--- a/dom/base/test/test_bug614583.html
+++ /dev/null
@@ -1,261 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=614583
--->
-<head>
-  <title>Test for Bug 614583</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=614583">Mozilla Bug 614583</a>
-<span id="crash1"
-attr0 attr1 attr2 attr3 attr4 attr5 attr6 attr7 attr8 attr9
-attr10 attr11 attr12 attr13 attr14 attr15 attr16 attr17 attr18 attr19
-attr20 attr21 attr22 attr23 attr24 attr25 attr26 attr27 attr28 attr29
-attr30 attr31 attr32 attr33 attr34 attr35 attr36 attr37 attr38 attr39
-attr40 attr41 attr42 attr43 attr44 attr45 attr46 attr47 attr48 attr49
-attr50 attr51 attr52 attr53 attr54 attr55 attr56 attr57 attr58 attr59
-attr60 attr61 attr62 attr63 attr64 attr65 attr66 attr67 attr68 attr69
-attr70 attr71 attr72 attr73 attr74 attr75 attr76 attr77 attr78 attr79
-attr80 attr81 attr82 attr83 attr84 attr85 attr86 attr87 attr88 attr89
-attr90 attr91 attr92 attr93 attr94 attr95 attr96 attr97 attr98 attr99
-attr100 attr101 attr102 attr103 attr104 attr105 attr106 attr107 attr108 attr109
-attr110 attr111 attr112 attr113 attr114 attr115 attr116 attr117 attr118 attr119
-attr120 attr121 attr122 attr123 attr124 attr125 attr126 attr127 attr128 attr129
-attr130 attr131 attr132 attr133 attr134 attr135 attr136 attr137 attr138 attr139
-attr140 attr141 attr142 attr143 attr144 attr145 attr146 attr147 attr148 attr149
-attr150 attr151 attr152 attr153 attr154 attr155 attr156 attr157 attr158 attr159
-attr160 attr161 attr162 attr163 attr164 attr165 attr166 attr167 attr168 attr169
-attr170 attr171 attr172 attr173 attr174 attr175 attr176 attr177 attr178 attr179
-attr180 attr181 attr182 attr183 attr184 attr185 attr186 attr187 attr188 attr189
-attr190 attr191 attr192 attr193 attr194 attr195 attr196 attr197 attr198 attr199
-attr200 attr201 attr202 attr203 attr204 attr205 attr206 attr207 attr208 attr209
-attr210 attr211 attr212 attr213 attr214 attr215 attr216 attr217 attr218 attr219
-attr220 attr221 attr222 attr223 attr224 attr225 attr226 attr227 attr228 attr229
-attr230 attr231 attr232 attr233 attr234 attr235 attr236 attr237 attr238 attr239
-attr240 attr241 attr242 attr243 attr244 attr245 attr246 attr247 attr248 attr249
-attr250 attr251 attr252 attr253 attr254 attr255 attr256 attr257 attr258 attr259
-attr260 attr261 attr262 attr263 attr264 attr265 attr266 attr267 attr268 attr269
-attr270 attr271 attr272 attr273 attr274 attr275 attr276 attr277 attr278 attr279
-attr280 attr281 attr282 attr283 attr284 attr285 attr286 attr287 attr288 attr289
-attr290 attr291 attr292 attr293 attr294 attr295 attr296 attr297 attr298 attr299
-attr300 attr301 attr302 attr303 attr304 attr305 attr306 attr307 attr308 attr309
-attr310 attr311 attr312 attr313 attr314 attr315 attr316 attr317 attr318 attr319
-attr320 attr321 attr322 attr323 attr324 attr325 attr326 attr327 attr328 attr329
-attr330 attr331 attr332 attr333 attr334 attr335 attr336 attr337 attr338 attr339
-attr340 attr341 attr342 attr343 attr344 attr345 attr346 attr347 attr348 attr349
-attr350 attr351 attr352 attr353 attr354 attr355 attr356 attr357 attr358 attr359
-attr360 attr361 attr362 attr363 attr364 attr365 attr366 attr367 attr368 attr369
-attr370 attr371 attr372 attr373 attr374 attr375 attr376 attr377 attr378 attr379
-attr380 attr381 attr382 attr383 attr384 attr385 attr386 attr387 attr388 attr389
-attr390 attr391 attr392 attr393 attr394 attr395 attr396 attr397 attr398 attr399
-attr400 attr401 attr402 attr403 attr404 attr405 attr406 attr407 attr408 attr409
-attr410 attr411 attr412 attr413 attr414 attr415 attr416 attr417 attr418 attr419
-attr420 attr421 attr422 attr423 attr424 attr425 attr426 attr427 attr428 attr429
-attr430 attr431 attr432 attr433 attr434 attr435 attr436 attr437 attr438 attr439
-attr440 attr441 attr442 attr443 attr444 attr445 attr446 attr447 attr448 attr449
-attr450 attr451 attr452 attr453 attr454 attr455 attr456 attr457 attr458 attr459
-attr460 attr461 attr462 attr463 attr464 attr465 attr466 attr467 attr468 attr469
-attr470 attr471 attr472 attr473 attr474 attr475 attr476 attr477 attr478 attr479
-attr480 attr481 attr482 attr483 attr484 attr485 attr486 attr487 attr488 attr489
-attr490 attr491 attr492 attr493 attr494 attr495 attr496 attr497 attr498 attr499
-attr500 attr501 attr502 attr503 attr504 attr505 attr506 attr507 attr508 attr509
-attr510 attr511 attr512 attr513 attr514 attr515 attr516 attr517 attr518 attr519
-attr520 attr521 attr522 attr523 attr524 attr525 attr526 attr527 attr528 attr529
-attr530 attr531 attr532 attr533 attr534 attr535 attr536 attr537 attr538 attr539
-attr540 attr541 attr542 attr543 attr544 attr545 attr546 attr547 attr548 attr549
-attr550 attr551 attr552 attr553 attr554 attr555 attr556 attr557 attr558 attr559
-attr560 attr561 attr562 attr563 attr564 attr565 attr566 attr567 attr568 attr569
-attr570 attr571 attr572 attr573 attr574 attr575 attr576 attr577 attr578 attr579
-attr580 attr581 attr582 attr583 attr584 attr585 attr586 attr587 attr588 attr589
-attr590 attr591 attr592 attr593 attr594 attr595 attr596 attr597 attr598 attr599
-attr600 attr601 attr602 attr603 attr604 attr605 attr606 attr607 attr608 attr609
-attr610 attr611 attr612 attr613 attr614 attr615 attr616 attr617 attr618 attr619
-attr620 attr621 attr622 attr623 attr624 attr625 attr626 attr627 attr628 attr629
-attr630 attr631 attr632 attr633 attr634 attr635 attr636 attr637 attr638 attr639
-attr640 attr641 attr642 attr643 attr644 attr645 attr646 attr647 attr648 attr649
-attr650 attr651 attr652 attr653 attr654 attr655 attr656 attr657 attr658 attr659
-attr660 attr661 attr662 attr663 attr664 attr665 attr666 attr667 attr668 attr669
-attr670 attr671 attr672 attr673 attr674 attr675 attr676 attr677 attr678 attr679
-attr680 attr681 attr682 attr683 attr684 attr685 attr686 attr687 attr688 attr689
-attr690 attr691 attr692 attr693 attr694 attr695 attr696 attr697 attr698 attr699
-attr700 attr701 attr702 attr703 attr704 attr705 attr706 attr707 attr708 attr709
-attr710 attr711 attr712 attr713 attr714 attr715 attr716 attr717 attr718 attr719
-attr720 attr721 attr722 attr723 attr724 attr725 attr726 attr727 attr728 attr729
-attr730 attr731 attr732 attr733 attr734 attr735 attr736 attr737 attr738 attr739
-attr740 attr741 attr742 attr743 attr744 attr745 attr746 attr747 attr748 attr749
-attr750 attr751 attr752 attr753 attr754 attr755 attr756 attr757 attr758 attr759
-attr760 attr761 attr762 attr763 attr764 attr765 attr766 attr767 attr768 attr769
-attr770 attr771 attr772 attr773 attr774 attr775 attr776 attr777 attr778 attr779
-attr780 attr781 attr782 attr783 attr784 attr785 attr786 attr787 attr788 attr789
-attr790 attr791 attr792 attr793 attr794 attr795 attr796 attr797 attr798 attr799
-attr800 attr801 attr802 attr803 attr804 attr805 attr806 attr807 attr808 attr809
-attr810 attr811 attr812 attr813 attr814 attr815 attr816 attr817 attr818 attr819
-attr820 attr821 attr822 attr823 attr824 attr825 attr826 attr827 attr828 attr829
-attr830 attr831 attr832 attr833 attr834 attr835 attr836 attr837 attr838 attr839
-attr840 attr841 attr842 attr843 attr844 attr845 attr846 attr847 attr848 attr849
-attr850 attr851 attr852 attr853 attr854 attr855 attr856 attr857 attr858 attr859
-attr860 attr861 attr862 attr863 attr864 attr865 attr866 attr867 attr868 attr869
-attr870 attr871 attr872 attr873 attr874 attr875 attr876 attr877 attr878 attr879
-attr880 attr881 attr882 attr883 attr884 attr885 attr886 attr887 attr888 attr889
-attr890 attr891 attr892 attr893 attr894 attr895 attr896 attr897 attr898 attr899
-attr900 attr901 attr902 attr903 attr904 attr905 attr906 attr907 attr908 attr909
-attr910 attr911 attr912 attr913 attr914 attr915 attr916 attr917 attr918 attr919
-attr920 attr921 attr922 attr923 attr924 attr925 attr926 attr927 attr928 attr929
-attr930 attr931 attr932 attr933 attr934 attr935 attr936 attr937 attr938 attr939
-attr940 attr941 attr942 attr943 attr944 attr945 attr946 attr947 attr948 attr949
-attr950 attr951 attr952 attr953 attr954 attr955 attr956 attr957 attr958 attr959
-attr960 attr961 attr962 attr963 attr964 attr965 attr966 attr967 attr968 attr969
-attr970 attr971 attr972 attr973 attr974 attr975 attr976 attr977 attr978 attr979
-attr980 attr981 attr982 attr983 attr984 attr985 attr986 attr987 attr988 attr989
-attr990 attr991 attr992 attr993 attr994 attr995 attr996 attr997 attr998 attr999
-attr1000 attr1001 attr1002 attr1003 attr1004 attr1005 attr1006 attr1007 attr1008 attr1009
-attr1010 attr1011 attr1012 attr1013 attr1014 attr1015 attr1016 attr1017 attr1018 attr1019
-attr1020 attr1021 attr1022 attr1023 attr1024 attr1025 attr1026 attr1027 attr1028 attr1029
-attr1030 attr1031 attr1032 attr1033 attr1034 attr1035 attr1036 attr1037 attr1038 attr1039
-attr1040 attr1041 attr1042 attr1043 attr1044 attr1045 attr1046 attr1047 attr1048 attr1049
-attr1050 attr1051 attr1052 attr1053 attr1054 attr1055 attr1056 attr1057 attr1058 attr1059
-attr1060 attr1061 attr1062 attr1063 attr1064 attr1065 attr1066 attr1067 attr1068 attr1069
-attr1070 attr1071 attr1072 attr1073 attr1074 attr1075 attr1076 attr1077 attr1078 attr1079
-attr1080 attr1081 attr1082 attr1083 attr1084 attr1085 attr1086 attr1087 attr1088 attr1089
-attr1090 attr1091 attr1092 attr1093 attr1094 attr1095 attr1096 attr1097 attr1098 attr1099
->I'm on a boat</span>
-<span
-attr0 attr1 attr2 attr3 attr4 attr5 attr6 attr7 attr8 attr9
-attr10 attr11 attr12 attr13 attr14 attr15 attr16 attr17 attr18 attr19
-attr20 attr21 attr22 attr23 attr24 attr25 attr26 attr27 attr28 attr29
-attr30 attr31 attr32 attr33 attr34 attr35 attr36 attr37 attr38 attr39
-attr40 attr41 attr42 attr43 attr44 attr45 attr46 attr47 attr48 attr49
-attr50 attr51 attr52 attr53 attr54 attr55 attr56 attr57 attr58 attr59
-attr60 attr61 attr62 attr63 attr64 attr65 attr66 attr67 attr68 attr69
-attr70 attr71 attr72 attr73 attr74 attr75 attr76 attr77 attr78 attr79
-attr80 attr81 attr82 attr83 attr84 attr85 attr86 attr87 attr88 attr89
-attr90 attr91 attr92 attr93 attr94 attr95 attr96 attr97 attr98 attr99
-attr100 attr101 attr102 attr103 attr104 attr105 attr106 attr107 attr108 attr109
-attr110 attr111 attr112 attr113 attr114 attr115 attr116 attr117 attr118 attr119
-attr120 attr121 attr122 attr123 attr124 attr125 attr126 attr127 attr128 attr129
-attr130 attr131 attr132 attr133 attr134 attr135 attr136 attr137 attr138 attr139
-attr140 attr141 attr142 attr143 attr144 attr145 attr146 attr147 attr148 attr149
-attr150 attr151 attr152 attr153 attr154 attr155 attr156 attr157 attr158 attr159
-attr160 attr161 attr162 attr163 attr164 attr165 attr166 attr167 attr168 attr169
-attr170 attr171 attr172 attr173 attr174 attr175 attr176 attr177 attr178 attr179
-attr180 attr181 attr182 attr183 attr184 attr185 attr186 attr187 attr188 attr189
-attr190 attr191 attr192 attr193 attr194 attr195 attr196 attr197 attr198 attr199
-attr200 attr201 attr202 attr203 attr204 attr205 attr206 attr207 attr208 attr209
-attr210 attr211 attr212 attr213 attr214 attr215 attr216 attr217 attr218 attr219
-attr220 attr221 attr222 attr223 attr224 attr225 attr226 attr227 attr228 attr229
-attr230 attr231 attr232 attr233 attr234 attr235 attr236 attr237 attr238 attr239
-attr240 attr241 attr242 attr243 attr244 attr245 attr246 attr247 attr248 attr249
-attr250 attr251 attr252 attr253 attr254 attr255 attr256 attr257 attr258 attr259
-attr260 attr261 attr262 attr263 attr264 attr265 attr266 attr267 attr268 attr269
-attr270 attr271 attr272 attr273 attr274 attr275 attr276 attr277 attr278 attr279
-attr280 attr281 attr282 attr283 attr284 attr285 attr286 attr287 attr288 attr289
-attr290 attr291 attr292 attr293 attr294 attr295 attr296 attr297 attr298 attr299
-attr300 attr301 attr302 attr303 attr304 attr305 attr306 attr307 attr308 attr309
-attr310 attr311 attr312 attr313 attr314 attr315 attr316 attr317 attr318 attr319
-attr320 attr321 attr322 attr323 attr324 attr325 attr326 attr327 attr328 attr329
-attr330 attr331 attr332 attr333 attr334 attr335 attr336 attr337 attr338 attr339
-attr340 attr341 attr342 attr343 attr344 attr345 attr346 attr347 attr348 attr349
-attr350 attr351 attr352 attr353 attr354 attr355 attr356 attr357 attr358 attr359
-attr360 attr361 attr362 attr363 attr364 attr365 attr366 attr367 attr368 attr369
-attr370 attr371 attr372 attr373 attr374 attr375 attr376 attr377 attr378 attr379
-attr380 attr381 attr382 attr383 attr384 attr385 attr386 attr387 attr388 attr389
-attr390 attr391 attr392 attr393 attr394 attr395 attr396 attr397 attr398 attr399
-attr400 attr401 attr402 attr403 attr404 attr405 attr406 attr407 attr408 attr409
-attr410 attr411 attr412 attr413 attr414 attr415 attr416 attr417 attr418 attr419
-attr420 attr421 attr422 attr423 attr424 attr425 attr426 attr427 attr428 attr429
-attr430 attr431 attr432 attr433 attr434 attr435 attr436 attr437 attr438 attr439
-attr440 attr441 attr442 attr443 attr444 attr445 attr446 attr447 attr448 attr449
-attr450 attr451 attr452 attr453 attr454 attr455 attr456 attr457 attr458 attr459
-attr460 attr461 attr462 attr463 attr464 attr465 attr466 attr467 attr468 attr469
-attr470 attr471 attr472 attr473 attr474 attr475 attr476 attr477 attr478 attr479
-attr480 attr481 attr482 attr483 attr484 attr485 attr486 attr487 attr488 attr489
-attr490 attr491 attr492 attr493 attr494 attr495 attr496 attr497 attr498 attr499
-attr500 attr501 attr502 attr503 attr504 attr505 attr506 attr507 attr508 attr509
-attr510 attr511 attr512 attr513 attr514 attr515 attr516 attr517 attr518 attr519
-attr520 attr521 attr522 attr523 attr524 attr525 attr526 attr527 attr528 attr529
-attr530 attr531 attr532 attr533 attr534 attr535 attr536 attr537 attr538 attr539
-attr540 attr541 attr542 attr543 attr544 attr545 attr546 attr547 attr548 attr549
-attr550 attr551 attr552 attr553 attr554 attr555 attr556 attr557 attr558 attr559
-attr560 attr561 attr562 attr563 attr564 attr565 attr566 attr567 attr568 attr569
-attr570 attr571 attr572 attr573 attr574 attr575 attr576 attr577 attr578 attr579
-attr580 attr581 attr582 attr583 attr584 attr585 attr586 attr587 attr588 attr589
-attr590 attr591 attr592 attr593 attr594 attr595 attr596 attr597 attr598 attr599
-attr600 attr601 attr602 attr603 attr604 attr605 attr606 attr607 attr608 attr609
-attr610 attr611 attr612 attr613 attr614 attr615 attr616 attr617 attr618 attr619
-attr620 attr621 attr622 attr623 attr624 attr625 attr626 attr627 attr628 attr629
-attr630 attr631 attr632 attr633 attr634 attr635 attr636 attr637 attr638 attr639
-attr640 attr641 attr642 attr643 attr644 attr645 attr646 attr647 attr648 attr649
-attr650 attr651 attr652 attr653 attr654 attr655 attr656 attr657 attr658 attr659
-attr660 attr661 attr662 attr663 attr664 attr665 attr666 attr667 attr668 attr669
-attr670 attr671 attr672 attr673 attr674 attr675 attr676 attr677 attr678 attr679
-attr680 attr681 attr682 attr683 attr684 attr685 attr686 attr687 attr688 attr689
-attr690 attr691 attr692 attr693 attr694 attr695 attr696 attr697 attr698 attr699
-attr700 attr701 attr702 attr703 attr704 attr705 attr706 attr707 attr708 attr709
-attr710 attr711 attr712 attr713 attr714 attr715 attr716 attr717 attr718 attr719
-attr720 attr721 attr722 attr723 attr724 attr725 attr726 attr727 attr728 attr729
-attr730 attr731 attr732 attr733 attr734 attr735 attr736 attr737 attr738 attr739
-attr740 attr741 attr742 attr743 attr744 attr745 attr746 attr747 attr748 attr749
-attr750 attr751 attr752 attr753 attr754 attr755 attr756 attr757 attr758 attr759
-attr760 attr761 attr762 attr763 attr764 attr765 attr766 attr767 attr768 attr769
-attr770 attr771 attr772 attr773 attr774 attr775 attr776 attr777 attr778 attr779
-attr780 attr781 attr782 attr783 attr784 attr785 attr786 attr787 attr788 attr789
-attr790 attr791 attr792 attr793 attr794 attr795 attr796 attr797 attr798 attr799
-attr800 attr801 attr802 attr803 attr804 attr805 attr806 attr807 attr808 attr809
-attr810 attr811 attr812 attr813 attr814 attr815 attr816 attr817 attr818 attr819
-attr820 attr821 attr822 attr823 attr824 attr825 attr826 attr827 attr828 attr829
-attr830 attr831 attr832 attr833 attr834 attr835 attr836 attr837 attr838 attr839
-attr840 attr841 attr842 attr843 attr844 attr845 attr846 attr847 attr848 attr849
-attr850 attr851 attr852 attr853 attr854 attr855 attr856 attr857 attr858 attr859
-attr860 attr861 attr862 attr863 attr864 attr865 attr866 attr867 attr868 attr869
-attr870 attr871 attr872 attr873 attr874 attr875 attr876 attr877 attr878 attr879
-attr880 attr881 attr882 attr883 attr884 attr885 attr886 attr887 attr888 attr889
-attr890 attr891 attr892 attr893 attr894 attr895 attr896 attr897 attr898 attr899
-attr900 attr901 attr902 attr903 attr904 attr905 attr906 attr907 attr908 attr909
-attr910 attr911 attr912 attr913 attr914 attr915 attr916 attr917 attr918 attr919
-attr920 attr921 attr922 attr923 attr924 attr925 attr926 attr927 attr928 attr929
-attr930 attr931 attr932 attr933 attr934 attr935 attr936 attr937 attr938 attr939
-attr940 attr941 attr942 attr943 attr944 attr945 attr946 attr947 attr948 attr949
-attr950 attr951 attr952 attr953 attr954 attr955 attr956 attr957 attr958 attr959
-attr960 attr961 attr962 attr963 attr964 attr965 attr966 attr967 attr968 attr969
-attr970 attr971 attr972 attr973 attr974 attr975 attr976 attr977 attr978 attr979
-attr980 attr981 attr982 attr983 attr984 attr985 attr986 attr987 attr988 attr989
-attr990 attr991 attr992 attr993 attr994 attr995 attr996 attr997 attr998 attr999
-attr1000 attr1001 attr1002 attr1003 attr1004 attr1005 attr1006 attr1007 attr1008 attr1009
-attr1010 attr1011 attr1012 attr1013 attr1014 attr1015 attr1016 attr1017 attr1018 attr1019
-attr1020 attr1021 attr1022 attr1023 attr1024 attr1025 attr1026 attr1027 attr1028 attr1029
-attr1030 attr1031 attr1032 attr1033 attr1034 attr1035 attr1036 attr1037 attr1038 attr1039
-attr1040 attr1041 attr1042 attr1043 attr1044 attr1045 attr1046 attr1047 attr1048 attr1049
-attr1050 attr1051 attr1052 attr1053 attr1054 attr1055 attr1056 attr1057 attr1058 attr1059
-attr1060 attr1061 attr1062 attr1063 attr1064 attr1065 attr1066 attr1067 attr1068 attr1069
-attr1070 attr1071 attr1072 attr1073 attr1074 attr1075 attr1076 attr1077 attr1078 attr1079
-attr1080 attr1081 attr1082 attr1083 attr1084 attr1085 attr1086 attr1087 attr1088 attr1089
-attr1090 attr1091 attr1092 attr1093 attr1094 attr1095 attr1096 attr1097 attr1098 attr1099
-id="crash2"
->I'm on a boat</span>
-<pre id="test">
-<script>
-span = document.createElement("span");
-try {
-  var i = 0;
-  while(1) {
-    span.setAttribute("attr" + (++i), "foo");
-  }
-}
-catch (ex) {}
-span.id = "crash3";
-document.body.appendChild(span);
-var attrCount = span.attributes.length;
-var spans = document.getElementsByTagName("span");
-for (i = 0; i < spans.length; ++i) {
-  is(spans[i].attributes.length, attrCount, "didn't have maxed out attrs");
-}
-while (spans.length) {
-  spans[0].remove();
-}
-</script>
-</pre>
-</body>
-</html>
--- a/dom/cache/test/mochitest/browser_cache_pb_window.js
+++ b/dom/cache/test/mochitest/browser_cache_pb_window.js
@@ -67,16 +67,18 @@ function testKeys(browser) {
         resolve();
       });
     });
   });
 }
 
 function testOpen_worker(browser) {
   return ContentTask.spawn(browser, {}, function() {
+    Cu.importGlobalProperties(["Blob"]);
+
     let workerFunctionString = function () {
       caches.open("pb-worker-cache").then(function(cacheObject) {
         postMessage(cacheObject.toString());
       }, function (reason) {
         postMessage(reason.name);
       });
     }.toString();
     let workerBlobURL = content.URL.createObjectURL(
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -292,16 +292,17 @@ class WebGLContext
     friend class WebGLExtensionCompressedTextureETC1;
     friend class WebGLExtensionCompressedTexturePVRTC;
     friend class WebGLExtensionCompressedTextureS3TC;
     friend class WebGLExtensionCompressedTextureS3TC_SRGB;
     friend class WebGLExtensionDepthTexture;
     friend class WebGLExtensionDisjointTimerQuery;
     friend class WebGLExtensionDrawBuffers;
     friend class WebGLExtensionLoseContext;
+    friend class WebGLExtensionMOZDebug;
     friend class WebGLExtensionVertexArray;
     friend class WebGLMemoryTracker;
     friend class webgl::AvailabilityRunnable;
     friend struct webgl::LinkedProgramInfo;
     friend struct webgl::UniformBlockInfo;
 
     friend const webgl::CachedDrawFetchLimits*
         ValidateDraw(WebGLContext*, const char*, GLenum, uint32_t);
--- a/dom/canvas/WebGLExtensionMOZDebug.cpp
+++ b/dom/canvas/WebGLExtensionMOZDebug.cpp
@@ -54,24 +54,28 @@ WebGLExtensionMOZDebug::GetParameter(JSC
     case LOCAL_GL_VENDOR:
     case LOCAL_GL_VERSION:
         {
             const auto raw = (const char*)gl->fGetString(pname);
             retval.set(StringValue(cx, NS_ConvertUTF8toUTF16(raw), er));
             return;
         }
 
-    case 0x10000: // "WSI_INFO"
+    case dom::MOZ_debug_Binding::WSI_INFO:
         {
             nsCString info;
             gl->GetWSIInfo(&info);
             retval.set(StringValue(cx, NS_ConvertUTF8toUTF16(info), er));
             return;
         }
 
+    case dom::MOZ_debug_Binding::DOES_INDEX_VALIDATION:
+        retval.set(JS::BooleanValue(mContext->mNeedsIndexValidation));
+        return;
+
     default:
         mContext->ErrorInvalidEnumArg("MOZ_debug.getParameter", "pname", pname);
         retval.set(JS::NullValue());
         return;
     }
 }
 
 IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionMOZDebug, MOZ_debug)
--- a/dom/canvas/test/webgl-mochitest/mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest/mochitest.ini
@@ -61,16 +61,18 @@ skip-if = os == 'win' && debug # Bug 138
 support-files = ../captureStream_common.js
 # Even though we use ../ here, in the test HTML, we need to omit this. Sub-CWD relative
 # paths are fine, but they locate the file and dump it in the current directory.
 [test_cubemap_must_be_square.html]
 [test_depth_tex_lazy_clear.html]
 [test_draw.html]
 [test_fb_param.html]
 [test_fb_param_crash.html]
+[test_has_rbab.html]
+fail-if = (os == 'linux') || (os == 'mac')
 [test_hidden_alpha.html]
 [test_hidden_depth_stencil.html]
 [test_implicit_color_buffer_float.html]
 [test_highp_fs.html]
 [test_no_arr_points.html]
 skip-if = android_version == '18' #Android 4.3 aws only; bug 1030942
 [test_noprog_draw.html]
 [test_pixel_pack_buffer.html]
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-mochitest/test_has_rbab.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset='UTF-8'>
+  <title>Fail without robust_buffer_access_behavior</title>
+  <script src='/tests/SimpleTest/SimpleTest.js'></script>
+  <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
+</head>
+<body>
+<script>
+
+function AssertRBAB() {
+  const c = document.createElement('canvas');
+  const g = c.getContext('webgl');
+  const e = g.getExtension('MOZ_debug');
+  ok(e, 'Should have MOZ_debug.');
+
+  const does_index_validation = e.getParameter(e.DOES_INDEX_VALIDATION);
+  ok(!does_index_validation,
+     "Should have RBAB. Mark this test as failing on platforms that can't support it.");
+
+  SimpleTest.finish();
+}
+
+// -
+
+SimpleTest.waitForExplicitFinish();
+
+const prefPairList = [
+  ['webgl.force-enabled', true],
+  ['webgl.enable-privileged-extensions', true],
+];
+const prefEnv = {'set': prefPairList};
+SpecialPowers.pushPrefEnv(prefEnv, AssertRBAB);
+
+</script>
+</body>
+</html>
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -2012,32 +2012,31 @@ EventStateManager::DetermineDragTargetAn
   // drag instead of the node that was clicked on. If a draggable node wasn't
   // found, just use the clicked node.
   if (!*aSelection) {
     while (dragContent) {
       if (auto htmlElement = nsGenericHTMLElement::FromNode(dragContent)) {
         if (htmlElement->Draggable()) {
           break;
         }
-      }
-      else {
+      } else {
         if (dragContent->IsXULElement()) {
           // All XUL elements are draggable, so if a XUL element is
           // encountered, stop looking for draggable nodes and just use the
           // original clicked node instead.
           // XXXndeakin
           // In the future, we will want to improve this so that XUL has a
           // better way to specify whether something is draggable than just
           // on/off.
           dragContent = mGestureDownContent;
           break;
         }
         // otherwise, it's not an HTML or XUL element, so just keep looking
       }
-      dragContent = dragContent->GetParent();
+      dragContent = dragContent->GetFlattenedTreeParent();
     }
   }
 
   // if no node in the hierarchy was found to drag, but the GetDragData method
   // returned a node, use that returned node. Otherwise, nothing is draggable.
   if (!dragContent && dragDataNode)
     dragContent = dragDataNode;
 
@@ -2446,17 +2445,17 @@ EventStateManager::SendLineScrollEvent(n
 {
   nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
   if (!targetContent)
     targetContent = GetFocusedContent();
   if (!targetContent)
     return;
 
   while (targetContent->IsText()) {
-    targetContent = targetContent->GetParent();
+    targetContent = targetContent->GetFlattenedTreeParent();
   }
 
   WidgetMouseScrollEvent event(aEvent->IsTrusted(),
                                eLegacyMouseLineOrPageScroll, aEvent->mWidget);
   event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
   event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
   event.mRefPoint = aEvent->mRefPoint;
   event.mTime = aEvent->mTime;
@@ -2485,17 +2484,17 @@ EventStateManager::SendPixelScrollEvent(
   nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
   if (!targetContent) {
     targetContent = GetFocusedContent();
     if (!targetContent)
       return;
   }
 
   while (targetContent->IsText()) {
-    targetContent = targetContent->GetParent();
+    targetContent = targetContent->GetFlattenedTreeParent();
   }
 
   WidgetMouseScrollEvent event(aEvent->IsTrusted(),
                                eLegacyMousePixelScroll, aEvent->mWidget);
   event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
   event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
   event.mRefPoint = aEvent->mRefPoint;
   event.mTime = aEvent->mTime;
@@ -3336,24 +3335,22 @@ EventStateManager::PostHandleEvent(nsPre
           }
         }
 
         // The rest is left button-specific.
         if (mouseEvent->button != WidgetMouseEvent::eLeftButton) {
           break;
         }
 
-        if (activeContent) {
-          // The nearest enclosing element goes into the :active state.  If
-          // we're not an element (so we're text or something) we need to obtain
-          // our parent element and put it into :active instead.
-          if (!activeContent->IsElement()) {
-            nsIContent* par = activeContent->GetParent();
-            if (par)
-              activeContent = par;
+        // The nearest enclosing element goes into the :active state.  If we're
+        // not an element (so we're text or something) we need to obtain
+        // our parent element and put it into :active instead.
+        if (activeContent && !activeContent->IsElement()) {
+          if (nsIContent* par = activeContent->GetFlattenedTreeParent()) {
+            activeContent = par;
           }
         }
       }
       else {
         // if we're here, the event handler returned false, so stop
         // any of our own processing of a drag. Workaround for bug 43258.
         StopTrackingDragGesture();
 
@@ -4292,16 +4289,25 @@ EventStateManager::DispatchMouseOrPointe
   }
 
   mCurrentTargetContent = nullptr;
   mCurrentTarget = previousTarget;
 
   return targetFrame;
 }
 
+static nsIContent*
+FindCommonAncestor(nsIContent* aNode1, nsIContent* aNode2)
+{
+  if (!aNode1 || !aNode2) {
+    return nullptr;
+  }
+  return nsContentUtils::GetCommonFlattenedTreeAncestor(aNode1, aNode2);
+}
+
 class EnterLeaveDispatcher
 {
 public:
   EnterLeaveDispatcher(EventStateManager* aESM,
                        nsIContent* aTarget, nsIContent* aRelatedTarget,
                        WidgetMouseEvent* aMouseEvent,
                        EventMessage aEventMessage)
     : mESM(aESM)
@@ -4309,29 +4315,25 @@ public:
     , mEventMessage(aEventMessage)
   {
     nsPIDOMWindowInner* win =
       aTarget ? aTarget->OwnerDoc()->GetInnerWindow() : nullptr;
     if (aMouseEvent->AsPointerEvent() ? win && win->HasPointerEnterLeaveEventListeners() :
                                         win && win->HasMouseEnterLeaveEventListeners()) {
       mRelatedTarget = aRelatedTarget ?
         aRelatedTarget->FindFirstNonChromeOnlyAccessContent() : nullptr;
-      nsINode* commonParent = nullptr;
-      if (aTarget && aRelatedTarget) {
-        commonParent =
-          nsContentUtils::GetCommonAncestor(aTarget, aRelatedTarget);
-      }
+      nsINode* commonParent = FindCommonAncestor(aTarget, aRelatedTarget);
       nsIContent* current = aTarget;
       // Note, it is ok if commonParent is null!
       while (current && current != commonParent) {
         if (!current->ChromeOnlyAccess()) {
           mTargets.AppendObject(current);
         }
         // mouseenter/leave is fired only on elements.
-        current = current->GetParent();
+        current = current->GetFlattenedTreeParent();
       }
     }
   }
 
   void Dispatch()
   {
     if (mEventMessage == eMouseEnter || mEventMessage == ePointerEnter) {
       for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
@@ -4908,17 +4910,17 @@ EventStateManager::SetClickCount(WidgetM
 {
   nsCOMPtr<nsIContent> mouseContent = aOverrideClickTarget;
   nsIContent* mouseContentParent = nullptr;
   if (!mouseContent && mCurrentTarget) {
     mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
   }
   if (mouseContent) {
     if (mouseContent->IsText()) {
-      mouseContent = mouseContent->GetParent();
+      mouseContent = mouseContent->GetFlattenedTreeParent();
     }
     if (mouseContent && mouseContent->IsRootOfNativeAnonymousSubtree()) {
       mouseContentParent = mouseContent->GetParent();
     }
   }
 
   switch (aEvent->button) {
   case WidgetMouseEvent::eLeftButton:
@@ -5038,17 +5040,17 @@ EventStateManager::CheckForAndDispatchCl
     nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
     if (presShell) {
       nsCOMPtr<nsIContent> mouseContent = GetEventTargetContent(aEvent);
       // Click events apply to *elements* not nodes. At this point the target
       // content may have been reset to some non-element content, and so we need
       // to walk up the closest ancestor element, just like we do in
       // nsPresShell::HandleEvent.
       while (mouseContent && !mouseContent->IsElement()) {
-        mouseContent = mouseContent->GetParent();
+        mouseContent = mouseContent->GetFlattenedTreeParent();
       }
 
       if (!mouseContent && !mCurrentTarget && !aOverrideClickTarget) {
         return NS_OK;
       }
 
       // HandleEvent clears out mCurrentTarget which we might need again
       AutoWeakFrame currentTarget = mCurrentTarget;
@@ -5133,25 +5135,16 @@ GetLabelTarget(nsIContent* aPossibleLabe
   mozilla::dom::HTMLLabelElement* label =
     mozilla::dom::HTMLLabelElement::FromNode(aPossibleLabel);
   if (!label)
     return nullptr;
 
   return label->GetLabeledElement();
 }
 
-static nsIContent*
-FindCommonAncestor(nsIContent* aNode1, nsIContent* aNode2)
-{
-  if (!aNode1 || !aNode2) {
-    return nullptr;
-  }
-  return nsContentUtils::GetCommonFlattenedTreeAncestor(aNode1, aNode2);
-}
-
 /* static */
 void
 EventStateManager::SetFullScreenState(Element* aElement, bool aIsFullScreen)
 {
   DoStateChange(aElement, NS_EVENT_STATE_FULL_SCREEN, aIsFullScreen);
 }
 
 /* static */
@@ -5358,18 +5351,18 @@ EventStateManager::SetContentState(nsICo
 
 void
 EventStateManager::ResetLastOverForContent(
                      const uint32_t& aIdx,
                      RefPtr<OverOutElementsWrapper>& aElemWrapper,
                      nsIContent* aContent)
 {
   if (aElemWrapper && aElemWrapper->mLastOverElement &&
-      nsContentUtils::ContentIsDescendantOf(aElemWrapper->mLastOverElement,
-                                            aContent)) {
+      nsContentUtils::ContentIsFlattenedTreeDescendantOf(
+        aElemWrapper->mLastOverElement, aContent)) {
     aElemWrapper->mLastOverElement = nullptr;
   }
 }
 
 void
 EventStateManager::RemoveNodeFromChainIfNeeded(EventStates aState,
                                                nsIContent* aContentRemoved,
                                                bool aNotify)
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -202,8 +202,10 @@ skip-if = toolkit == 'android'
 support-files = window_bug1429572.html
 [test_bug1446834.html]
 support-files = file_bug1446834.html
 [test_bug1447993.html]
 support-files = window_bug1447993.html
 skip-if = toolkit == 'android'
 [test_dnd_with_modifiers.html]
 [test_hover_mouseleave.html]
+[test_slotted_mouse_event.html]
+[test_slotted_text_click.html]
new file mode 100644
--- /dev/null
+++ b/dom/events/test/test_slotted_mouse_event.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Bug 1481500: mouse enter / leave events in slotted content</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script>
+function runTests() {
+  let iframe = document.createElement('iframe');
+  document.body.appendChild(iframe);
+  iframe.onload = () => frameLoaded(iframe);
+  iframe.srcdoc =
+    `<div id="host"><div id="target"></div></div>`
+}
+
+function frameLoaded(iframe) {
+  let host = iframe.contentDocument.getElementById('host');
+  let target = iframe.contentDocument.getElementById('target');
+  let finished = false;
+
+  host.attachShadow({ mode: 'open' }).innerHTML = `
+    <style>
+      :host {
+        width: 300px;
+        height: 300px;
+        background: purple;
+      }
+      ::slotted(div) {
+        width: 100px;
+        height: 100px;
+        background: green;
+      }
+    </style>
+    <slot></slot>
+  `;
+
+  host.addEventListener("mouseleave", e => {
+    if (finished)
+      return;
+    ok(false, "Should not fire mouseleave when moving the cursor to the slotted target");
+  });
+
+  target.addEventListener("mouseenter", () => {
+    if (finished)
+      return;
+    ok(true, "Moving the mouse into the target should trigger a mouseenter there");
+    setTimeout(() => {
+      finished = true;
+      SimpleTest.finish()
+    }, 0);
+  });
+
+  synthesizeMouseAtCenter(host, { type: "mousemove" });
+  synthesizeMouseAtCenter(target, { type: "mousemove" });
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(() => {
+  SpecialPowers.pushPrefEnv({
+    set: [
+      ["dom.webcomponents.shadowdom.enabled", true]
+    ]
+  }, runTests);
+});
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/test_slotted_text_click.html
@@ -0,0 +1,76 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Bug 1481500: click / activation on text activates the slot it's assigned to</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script>
+function generateLotsOfText() {
+  let text = "Some text. ";
+  for (let i = 0; i < 10; ++i)
+    text += text;
+  return text;
+}
+
+function runTests() {
+  let iframe = document.createElement('iframe');
+  document.body.appendChild(iframe);
+  iframe.onload = () => frameLoaded(iframe);
+  iframe.width = "350"
+  iframe.height = "350"
+  iframe.srcdoc =
+    `<div id="host">${generateLotsOfText()}</div>`
+}
+
+function frameLoaded(iframe) {
+  let host = iframe.contentDocument.getElementById('host');
+
+  host.attachShadow({ mode: 'open' }).innerHTML = `
+    <style>
+      :host {
+        width: 300px;
+        height: 300px;
+        overflow: hidden;
+      }
+    </style>
+    <slot></slot>
+  `;
+
+  let slot = host.shadowRoot.querySelector('slot');
+  let mousedownFired = false;
+  let mouseupFired = false;
+  slot.addEventListener('mousedown', function() {
+    ok(true, "Mousedown should fire on the slot when clicking on text");
+    mousedownFired = true;
+  });
+
+  slot.addEventListener('click', function() {
+    ok(true, "Click should target the slot");
+    ok(mousedownFired, "mousedown should've fired");
+    ok(mouseupFired, "click should've fired");
+    SimpleTest.finish();
+  });
+
+  slot.addEventListener('mouseup', function() {
+    // FIXME: When we fix bug 1481517, this check should move to the mousedown listener.
+    ok(this.matches(":active"), "Slot should become active");
+    mouseupFired = true;
+  });
+
+  requestAnimationFrame(() => {
+    requestAnimationFrame(() => {
+      synthesizeMouseAtPoint(150, 150, { type: "mousedown" });
+      synthesizeMouseAtPoint(150, 150, { type: "mouseup" });
+    });
+  });
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(() => {
+  SpecialPowers.pushPrefEnv({
+    set: [
+      ["dom.webcomponents.shadowdom.enabled", true]
+    ]
+  }, runTests);
+});
+</script>
--- a/dom/file/ipc/tests/browser_ipcBlob.js
+++ b/dom/file/ipc/tests/browser_ipcBlob.js
@@ -6,16 +6,17 @@ requestLongerTimeout(3);
 const BASE_URI = "http://mochi.test:8888/browser/dom/file/ipc/tests/empty.html";
 
 // More than 1mb memory blob childA-parent-childB.
 add_task(async function test_CtoPtoC_big() {
   let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
   let browser1 = gBrowser.getBrowserForTab(tab1);
 
   let blob = await ContentTask.spawn(browser1, null, function() {
+    Cu.importGlobalProperties(["Blob"]);
     let blob = new Blob([new Array(1024*1024).join('123456789ABCDEF')]);
     return blob;
   });
 
   ok(blob, "CtoPtoC-big: We have a blob!");
   is(blob.size, new Array(1024*1024).join('123456789ABCDEF').length, "CtoPtoC-big: The size matches");
 
   let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
@@ -38,16 +39,17 @@ add_task(async function test_CtoPtoC_big
 });
 
 // Less than 1mb memory blob childA-parent-childB.
 add_task(async function test_CtoPtoC_small() {
   let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
   let browser1 = gBrowser.getBrowserForTab(tab1);
 
   let blob = await ContentTask.spawn(browser1, null, function() {
+    Cu.importGlobalProperties(["Blob"]);
     let blob = new Blob(["hello world!"]);
     return blob;
   });
 
   ok(blob, "CtoPtoC-small: We have a blob!");
   is(blob.size, "hello world!".length, "CtoPtoC-small: The size matches");
 
   let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
@@ -70,16 +72,17 @@ add_task(async function test_CtoPtoC_sma
 });
 
 // More than 1mb memory blob childA-parent-childB: BroadcastChannel
 add_task(async function test_CtoPtoC_bc_big() {
   let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
   let browser1 = gBrowser.getBrowserForTab(tab1);
 
   await ContentTask.spawn(browser1, null, function() {
+    Cu.importGlobalProperties(["Blob"]);
     var bc = new content.BroadcastChannel('test');
     bc.onmessage = function() {
       bc.postMessage(new Blob([new Array(1024*1024).join('123456789ABCDEF')]));
     }
   });
 
   let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
   let browser2 = gBrowser.getBrowserForTab(tab2);
@@ -106,16 +109,17 @@ add_task(async function test_CtoPtoC_bc_
 });
 
 // Less than 1mb memory blob childA-parent-childB: BroadcastChannel
 add_task(async function test_CtoPtoC_bc_small() {
   let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
   let browser1 = gBrowser.getBrowserForTab(tab1);
 
   await ContentTask.spawn(browser1, null, function() {
+    Cu.importGlobalProperties(["Blob"]);
     var bc = new content.BroadcastChannel('test');
     bc.onmessage = function() {
       bc.postMessage(new Blob(["hello world!"]));
     }
   });
 
   let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
   let browser2 = gBrowser.getBrowserForTab(tab2);
@@ -142,16 +146,17 @@ add_task(async function test_CtoPtoC_bc_
 });
 
 // blob URL childA-parent-childB
 add_task(async function test_CtoPtoC_bc_small() {
   let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
   let browser1 = gBrowser.getBrowserForTab(tab1);
 
   let blobURL = await ContentTask.spawn(browser1, null, function() {
+    Cu.importGlobalProperties(["Blob"]);
     return content.URL.createObjectURL(new content.Blob(["hello world!"]));
   });
 
   let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
   let browser2 = gBrowser.getBrowserForTab(tab2);
 
   let status = await ContentTask.spawn(browser2, blobURL, function(blobURL) {
     return new Promise(resolve => {
@@ -172,28 +177,30 @@ add_task(async function test_CtoPtoC_bc_
 });
 
 // Multipart Blob childA-parent-childB.
 add_task(async function test_CtoPtoC_multipart() {
   let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
   let browser1 = gBrowser.getBrowserForTab(tab1);
 
   let blob = await ContentTask.spawn(browser1, null, function() {
+    Cu.importGlobalProperties(["Blob"]);
     return new Blob(["!"]);
   });
 
   ok(blob, "CtoPtoC-,ultipart: We have a blob!");
   is(blob.size, "!".length, "CtoPtoC-multipart: The size matches");
 
   let newBlob = new Blob(["world", blob]);
 
   let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, BASE_URI);
   let browser2 = gBrowser.getBrowserForTab(tab2);
 
   let status = await ContentTask.spawn(browser2, newBlob, function(blob) {
+    Cu.importGlobalProperties(["Blob"]);
     return new Promise(resolve => {
       let fr = new content.FileReader();
       fr.readAsText(new Blob(["hello ", blob]));
       fr.onloadend = function() {
         resolve(fr.result == "hello world!");
       }
     });
   });
--- a/dom/html/HTMLBodyElement.cpp
+++ b/dom/html/HTMLBodyElement.cpp
@@ -292,34 +292,34 @@ HTMLBodyElement::IsEventAttributeNameInt
 
 nsresult
 HTMLBodyElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                             nsIContent* aBindingParent)
 {
   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
                                                  aBindingParent);
   NS_ENSURE_SUCCESS(rv, rv);
-  return mAttrsAndChildren.ForceMapped(this, OwnerDoc());
+  return mAttrs.ForceMapped(this, OwnerDoc());
 }
 
 nsresult
 HTMLBodyElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                               const nsAttrValue* aValue,
                               const nsAttrValue* aOldValue,
                               nsIPrincipal* aSubjectPrincipal,
                               bool aNotify)
 {
   nsresult rv = nsGenericHTMLElement::AfterSetAttr(aNameSpaceID,
                                                    aName, aValue, aOldValue,
                                                    aSubjectPrincipal, aNotify);
   NS_ENSURE_SUCCESS(rv, rv);
   // if the last mapped attribute was removed, don't clear the
   // nsMappedAttributes, our style can still depend on the containing frame element
   if (!aValue && IsAttributeMapped(aName)) {
-    nsresult rv = mAttrsAndChildren.ForceMapped(this, OwnerDoc());
+    nsresult rv = mAttrs.ForceMapped(this, OwnerDoc());
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 #define EVENT(name_, id_, type_, struct_) /* nothing; handled by the superclass */
 // nsGenericHTMLElement::GetOnError returns
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -4826,34 +4826,34 @@ HTMLInputElement::HandleTypeChange(uint8
   UpdateBarredFromConstraintValidation();
 
   if (oldType == NS_FORM_INPUT_IMAGE) {
     // We're no longer an image input.  Cancel our image requests, if we have
     // any.
     CancelImageRequests(aNotify);
 
     // And we should update our mapped attribute mapping function.
-    mAttrsAndChildren.UpdateMappedAttrRuleMapper(*this);
+    mAttrs.UpdateMappedAttrRuleMapper(*this);
   } else if (mType == NS_FORM_INPUT_IMAGE) {
     if (aNotify) {
       // We just got switched to be an image input; we should see
       // whether we have an image to load;
       nsAutoString src;
       if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
         // Mark channel as urgent-start before load image if the image load is
         // initaiated by a user interaction.
         mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
 
         LoadImage(src, false, aNotify, eImageLoadType_Normal,
                   mSrcTriggeringPrincipal);
       }
     }
 
     // And we should update our mapped attribute mapping function.
-    mAttrsAndChildren.UpdateMappedAttrRuleMapper(*this);
+    mAttrs.UpdateMappedAttrRuleMapper(*this);
   }
 
   if (mType == NS_FORM_INPUT_PASSWORD && IsInComposedDoc()) {
     AsyncEventDispatcher* dispatcher =
       new AsyncEventDispatcher(this,
                                NS_LITERAL_STRING("DOMInputPasswordAdded"),
                                CanBubble::eYes,
                                ChromeOnlyDispatch::eYes);
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -2540,17 +2540,17 @@ HTMLMediaElement::UpdatePreloadAction()
   // as we'll need it to play.
   if ((AutoplayPolicy::IsAllowedToPlay(*this) == nsIAutoplay::ALLOWED &&
        HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay)) ||
       !mPaused) {
     nextAction = HTMLMediaElement::PRELOAD_ENOUGH;
   } else {
     // Find the appropriate preload action by looking at the attribute.
     const nsAttrValue* val =
-      mAttrsAndChildren.GetAttr(nsGkAtoms::preload, kNameSpaceID_None);
+      mAttrs.GetAttr(nsGkAtoms::preload, kNameSpaceID_None);
     // MSE doesn't work if preload is none, so it ignores the pref when src is
     // from MSE.
     uint32_t preloadDefault =
       mMediaSource
         ? HTMLMediaElement::PRELOAD_ATTR_METADATA
         : Preferences::GetInt("media.preload.default",
                               HTMLMediaElement::PRELOAD_ATTR_METADATA);
     uint32_t preloadAuto = Preferences::GetInt(
--- a/dom/html/HTMLMeterElement.cpp
+++ b/dom/html/HTMLMeterElement.cpp
@@ -67,17 +67,17 @@ HTMLMeterElement::ParseAttribute(int32_t
 
 double
 HTMLMeterElement::Min() const
 {
   /**
    * If the attribute min is defined, the minimum is this value.
    * Otherwise, the minimum is the default value.
    */
-  const nsAttrValue* attrMin = mAttrsAndChildren.GetAttr(nsGkAtoms::min);
+  const nsAttrValue* attrMin = mAttrs.GetAttr(nsGkAtoms::min);
   if (attrMin && attrMin->Type() == nsAttrValue::eDoubleValue) {
     return attrMin->GetDoubleValue();
   }
   return kDefaultMin;
 }
 
 double
 HTMLMeterElement::Max() const
@@ -85,17 +85,17 @@ HTMLMeterElement::Max() const
   /**
    * If the attribute max is defined, the maximum is this value.
    * Otherwise, the maximum is the default value.
    * If the maximum value is less than the minimum value,
    * the maximum value is the same as the minimum value.
    */
   double max;
 
-  const nsAttrValue* attrMax = mAttrsAndChildren.GetAttr(nsGkAtoms::max);
+  const nsAttrValue* attrMax = mAttrs.GetAttr(nsGkAtoms::max);
   if (attrMax && attrMax->Type() == nsAttrValue::eDoubleValue) {
     max = attrMax->GetDoubleValue();
   } else {
     max = kDefaultMax;
   }
 
   return std::max(max, Min());
 }
@@ -108,17 +108,17 @@ HTMLMeterElement::Value() const
    * Otherwise, the actual value is the default value.
    * If the actual value is less than the minimum value,
    * the actual value is the same as the minimum value.
    * If the actual value is greater than the maximum value,
    * the actual value is the same as the maximum value.
    */
   double value;
 
-  const nsAttrValue* attrValue = mAttrsAndChildren.GetAttr(nsGkAtoms::value);
+  const nsAttrValue* attrValue = mAttrs.GetAttr(nsGkAtoms::value);
   if (attrValue && attrValue->Type() == nsAttrValue::eDoubleValue) {
     value = attrValue->GetDoubleValue();
   } else {
     value = kDefaultValue;
   }
 
   double min = Min();
 
@@ -138,17 +138,17 @@ HTMLMeterElement::Low() const
    * If the low value is less than the minimum value,
    * the low value is the same as the minimum value.
    * If the low value is greater than the maximum value,
    * the low value is the same as the maximum value.
    */
 
   double min = Min();
 
-  const nsAttrValue* attrLow = mAttrsAndChildren.GetAttr(nsGkAtoms::low);
+  const nsAttrValue* attrLow = mAttrs.GetAttr(nsGkAtoms::low);
   if (!attrLow || attrLow->Type() != nsAttrValue::eDoubleValue) {
     return min;
   }
 
   double low = attrLow->GetDoubleValue();
 
   if (low <= min) {
     return min;
@@ -166,17 +166,17 @@ HTMLMeterElement::High() const
    * If the high value is less than the low value,
    * the high value is the same as the low value.
    * If the high value is greater than the maximum value,
    * the high value is the same as the maximum value.
    */
 
   double max = Max();
 
-  const nsAttrValue* attrHigh = mAttrsAndChildren.GetAttr(nsGkAtoms::high);
+  const nsAttrValue* attrHigh = mAttrs.GetAttr(nsGkAtoms::high);
   if (!attrHigh || attrHigh->Type() != nsAttrValue::eDoubleValue) {
     return max;
   }
 
   double high = attrHigh->GetDoubleValue();
 
   if (high >= max) {
     return max;
@@ -199,17 +199,17 @@ HTMLMeterElement::Optimum() const
    * the optimum value is the same as the maximum value.
    */
 
   double max = Max();
 
   double min = Min();
 
   const nsAttrValue* attrOptimum =
-              mAttrsAndChildren.GetAttr(nsGkAtoms::optimum);
+              mAttrs.GetAttr(nsGkAtoms::optimum);
   if (!attrOptimum || attrOptimum->Type() != nsAttrValue::eDoubleValue) {
     return (min + max) / 2.0;
   }
 
   double optimum = attrOptimum->GetDoubleValue();
 
   if (optimum <= min) {
     return min;
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -361,17 +361,17 @@ HTMLObjectElement::IsHTMLFocusable(bool 
 
     *aIsFocusable = true;
 
     return false;
   }
 
   // TODO: this should probably be managed directly by IsHTMLFocusable.
   // See bug 597242.
-  const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsGkAtoms::tabindex);
+  const nsAttrValue* attrVal = mAttrs.GetAttr(nsGkAtoms::tabindex);
 
   *aIsFocusable = attrVal && attrVal->Type() == nsAttrValue::eInteger;
 
   if (aTabIndex && *aIsFocusable) {
     *aTabIndex = attrVal->GetIntegerValue();
   }
 
   return false;
--- a/dom/html/HTMLProgressElement.cpp
+++ b/dom/html/HTMLProgressElement.cpp
@@ -61,29 +61,29 @@ HTMLProgressElement::ParseAttribute(int3
                                               aValue,
                                               aMaybeScriptedPrincipal,
                                               aResult);
 }
 
 double
 HTMLProgressElement::Value() const
 {
-  const nsAttrValue* attrValue = mAttrsAndChildren.GetAttr(nsGkAtoms::value);
+  const nsAttrValue* attrValue = mAttrs.GetAttr(nsGkAtoms::value);
   if (!attrValue || attrValue->Type() != nsAttrValue::eDoubleValue ||
       attrValue->GetDoubleValue() < 0.0) {
     return kDefaultValue;
   }
 
   return std::min(attrValue->GetDoubleValue(), Max());
 }
 
 double
 HTMLProgressElement::Max() const
 {
-  const nsAttrValue* attrMax = mAttrsAndChildren.GetAttr(nsGkAtoms::max);
+  const nsAttrValue* attrMax = mAttrs.GetAttr(nsGkAtoms::max);
   if (!attrMax || attrMax->Type() != nsAttrValue::eDoubleValue ||
       attrMax->GetDoubleValue() <= 0.0) {
     return kDefaultMax;
   }
 
   return attrMax->GetDoubleValue();
 }
 
@@ -95,17 +95,17 @@ HTMLProgressElement::Position() const
   }
 
   return Value() / Max();
 }
 
 bool
 HTMLProgressElement::IsIndeterminate() const
 {
-  const nsAttrValue* attrValue = mAttrsAndChildren.GetAttr(nsGkAtoms::value);
+  const nsAttrValue* attrValue = mAttrs.GetAttr(nsGkAtoms::value);
   return !attrValue || attrValue->Type() != nsAttrValue::eDoubleValue;
 }
 
 JSObject*
 HTMLProgressElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return HTMLProgressElement_Binding::Wrap(aCx, this, aGivenProto);
 }
--- a/dom/html/HTMLTableElement.cpp
+++ b/dom/html/HTMLTableElement.cpp
@@ -1074,17 +1074,17 @@ HTMLTableElement::BuildInheritedAttribut
   NS_ASSERTION(!mTableInheritedAttributes,
                "potential leak, plus waste of work");
   MOZ_ASSERT(NS_IsMainThread());
   nsIDocument *document = GetComposedDoc();
   nsHTMLStyleSheet* sheet = document ?
                               document->GetAttributeStyleSheet() : nullptr;
   RefPtr<nsMappedAttributes> newAttrs;
   if (sheet) {
-    const nsAttrValue* value = mAttrsAndChildren.GetAttr(nsGkAtoms::cellpadding);
+    const nsAttrValue* value = mAttrs.GetAttr(nsGkAtoms::cellpadding);
     if (value) {
       RefPtr<nsMappedAttributes> modifiableMapped = new
       nsMappedAttributes(sheet, MapInheritedTableAttributesIntoRule);
 
       if (modifiableMapped) {
         nsAttrValue val(*value);
         bool oldValueSet;
         modifiableMapped->SetAndSwapAttr(nsGkAtoms::cellpadding, val,
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -108,24 +108,24 @@ nsresult
 nsGenericHTMLElement::CopyInnerTo(Element* aDst, bool aPreallocateChildren)
 {
   MOZ_ASSERT(!aDst->GetUncomposedDoc(),
              "Should not CopyInnerTo an Element in a document");
   nsresult rv;
 
   bool reparse = (aDst->OwnerDoc() != OwnerDoc());
 
-  rv = static_cast<nsGenericHTMLElement*>(aDst)->mAttrsAndChildren.
-       EnsureCapacityToClone(mAttrsAndChildren, aPreallocateChildren);
+  rv = static_cast<nsGenericHTMLElement*>(aDst)->mAttrs.
+         EnsureCapacityToClone(mAttrs, aPreallocateChildren);
   NS_ENSURE_SUCCESS(rv, rv);
 
   int32_t i, count = GetAttrCount();
   for (i = 0; i < count; ++i) {
-    const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
-    const nsAttrValue *value = mAttrsAndChildren.AttrAt(i);
+    const nsAttrName *name = mAttrs.AttrNameAt(i);
+    const nsAttrValue *value = mAttrs.AttrAt(i);
 
     if (name->Equals(nsGkAtoms::style, kNameSpaceID_None) &&
         value->Type() == nsAttrValue::eCSSDeclaration) {
       // We still clone CSS attributes, even in the cross-document case.
       // https://github.com/w3c/webappsec-csp/issues/212
 
       // We can't just set this as a string, because that will fail
       // to reparse the string into style data until the node is
@@ -1469,17 +1469,17 @@ nsGenericHTMLElement::MapBackgroundAttri
   MapBGColorInto(aAttributes, aDecls);
 }
 
 //----------------------------------------------------------------------
 
 int32_t
 nsGenericHTMLElement::GetIntAttr(nsAtom* aAttr, int32_t aDefault) const
 {
-  const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
+  const nsAttrValue* attrVal = mAttrs.GetAttr(aAttr);
   if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
     return attrVal->GetIntegerValue();
   }
   return aDefault;
 }
 
 nsresult
 nsGenericHTMLElement::SetIntAttr(nsAtom* aAttr, int32_t aValue)
@@ -1489,17 +1489,17 @@ nsGenericHTMLElement::SetIntAttr(nsAtom*
 
   return SetAttr(kNameSpaceID_None, aAttr, value, true);
 }
 
 uint32_t
 nsGenericHTMLElement::GetUnsignedIntAttr(nsAtom* aAttr,
                                          uint32_t aDefault) const
 {
-  const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
+  const nsAttrValue* attrVal = mAttrs.GetAttr(aAttr);
   if (!attrVal || attrVal->Type() != nsAttrValue::eInteger) {
     return aDefault;
   }
 
   return attrVal->GetIntegerValue();
 }
 
 void
@@ -1524,17 +1524,17 @@ nsGenericHTMLElement::GetURIAttr(nsAtom*
   CopyUTF8toUTF16(spec, aResult);
 }
 
 bool
 nsGenericHTMLElement::GetURIAttr(nsAtom* aAttr, nsAtom* aBaseAttr, nsIURI** aURI) const
 {
   *aURI = nullptr;
 
-  const nsAttrValue* attr = mAttrsAndChildren.GetAttr(aAttr);
+  const nsAttrValue* attr = mAttrs.GetAttr(aAttr);
   if (!attr) {
     return false;
   }
 
   nsCOMPtr<nsIURI> baseURI = GetBaseURI();
 
   if (aBaseAttr) {
     nsAutoString baseAttrValue;
@@ -2591,19 +2591,19 @@ nsGenericHTMLElement::SyncEditorsOnSubtr
        child = child->GetNextSibling()) {
     SyncEditorsOnSubtree(child);
   }
 }
 
 void
 nsGenericHTMLElement::RecompileScriptEventListeners()
 {
-    int32_t i, count = mAttrsAndChildren.AttrCount();
+    int32_t i, count = mAttrs.AttrCount();
     for (i = 0; i < count; ++i) {
-        const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
+        const nsAttrName *name = mAttrs.AttrNameAt(i);
 
         // Eventlistenener-attributes are always in the null namespace
         if (!name->IsAtom()) {
             continue;
         }
 
         nsAtom *attr = name->Atom();
         if (!IsEventAttributeName(attr)) {
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -298,17 +298,17 @@ public:
    */
   bool CheckHandleEventForAnchorsPreconditions(
          mozilla::EventChainVisitor& aVisitor);
   void GetEventTargetParentForAnchors(mozilla::EventChainPreVisitor& aVisitor);
   nsresult PostHandleEventForAnchors(mozilla::EventChainPostVisitor& aVisitor);
   bool IsHTMLLink(nsIURI** aURI) const;
 
   // HTML element methods
-  void Compact() { mAttrsAndChildren.Compact(); }
+  void Compact() { mAttrs.Compact(); }
 
   virtual void UpdateEditableState(bool aNotify) override;
 
   virtual mozilla::EventStates IntrinsicState() const override;
 
   // Helper for setting our editable flag and notifying
   void DoSetEditableFlag(bool aEditable, bool aNotify) {
     SetEditableFlag(aEditable);
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -30,17 +30,16 @@
 #include "nsIIOService.h"
 #include "nsNetUtil.h"
 #include "nsIPrivateBrowsingChannel.h"
 #include "nsIContentViewer.h"
 #include "nsDocShell.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsIWebNavigation.h"
 #include "nsIBaseWindow.h"
-#include "nsIWebShellServices.h"
 #include "nsIScriptContext.h"
 #include "nsIXPConnect.h"
 #include "nsContentList.h"
 #include "nsError.h"
 #include "nsIPrincipal.h"
 #include "nsJSPrincipals.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsAttrName.h"
--- a/dom/html/test/browser_fullscreen-api-keys.js
+++ b/dom/html/test/browser_fullscreen-api-keys.js
@@ -13,17 +13,17 @@ const kStrictKeyPressEvents =
 
 function frameScript() {
   let doc = content.document;
   addMessageListener("Test:RequestFullscreen", () => {
     doc.body.requestFullscreen();
   });
   addMessageListener("Test:DispatchUntrustedKeyEvents", msg => {
     var evt = new content.CustomEvent("Test:DispatchKeyEvents", {
-      detail: { code: msg.data }
+      detail: Cu.cloneInto({ code: msg.data }, content),
     });
     content.dispatchEvent(evt);
   });
 
   doc.addEventListener("fullscreenchange", () => {
     sendAsyncMessage("Test:FullscreenChanged", !!doc.fullscreenElement);
   });
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -74,18 +74,16 @@
 #include "nsFocusManager.h"
 #include "EventStateManager.h"
 #include "nsIDocShell.h"
 #include "nsIFrame.h"
 #include "nsIURI.h"
 #include "nsIURIFixup.h"
 #include "nsCDefaultURIFixup.h"
 #include "nsIWebBrowser.h"
-#include "nsIWebBrowserFocus.h"
-#include "nsIWebBrowserSetup.h"
 #include "nsIWebProgress.h"
 #include "nsIXULRuntime.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
 #include "nsPointerHashKeys.h"
 #include "nsLayoutUtils.h"
 #include "nsPrintfCString.h"
 #include "nsTHashtable.h"
@@ -119,16 +117,17 @@
 #include "nsISHistory.h"
 #include "nsQueryObject.h"
 #include "nsIHttpChannel.h"
 #include "mozilla/dom/DocGroup.h"
 #include "nsString.h"
 #include "nsISupportsPrimitives.h"
 #include "mozilla/Telemetry.h"
 #include "nsDocShellLoadInfo.h"
+#include "nsWebBrowser.h"
 
 #ifdef XP_WIN
 #include "mozilla/plugins/PluginWidgetChild.h"
 #endif
 
 #ifdef NS_PRINTING
 #include "nsIPrintSession.h"
 #include "nsIPrintSettings.h"
@@ -544,21 +543,20 @@ TabChild::DoUpdateZoomConstraints(const 
 
 nsresult
 TabChild::Init()
 {
   if (!mTabGroup) {
     mTabGroup = TabGroup::GetFromActor(this);
   }
 
-  nsCOMPtr<nsIWebBrowser> webBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
-  if (!webBrowser) {
-    NS_ERROR("Couldn't create a nsWebBrowser?");
-    return NS_ERROR_FAILURE;
-  }
+  // Directly create our web browser object and store it, so we can start
+  // eliminating QIs.
+  mWebBrowser = new nsWebBrowser();
+  nsIWebBrowser* webBrowser = mWebBrowser;
 
   webBrowser->SetContainerWindow(this);
   webBrowser->SetOriginAttributes(OriginAttributesRef());
   mWebNav = do_QueryInterface(webBrowser);
   NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
 
   nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(WebNavigation()));
   docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
@@ -584,25 +582,17 @@ TabChild::Init()
   baseWindow->InitWindow(0, mPuppetWidget, 0, 0, 0, 0);
   baseWindow->Create();
 
   // Set the tab context attributes then pass to docShell
   NotifyTabContextUpdated(false);
 
   // IPC uses a WebBrowser object for which DNS prefetching is turned off
   // by default. But here we really want it, so enable it explicitly
-  nsCOMPtr<nsIWebBrowserSetup> webBrowserSetup =
-    do_QueryInterface(baseWindow);
-  if (webBrowserSetup) {
-    webBrowserSetup->SetProperty(nsIWebBrowserSetup::SETUP_ALLOW_DNS_PREFETCH,
-                                 true);
-  } else {
-    NS_WARNING("baseWindow doesn't QI to nsIWebBrowserSetup, skipping "
-               "DNS prefetching enable step.");
-  }
+  mWebBrowser->SetAllowDNSPrefetch(true);
 
   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
   MOZ_ASSERT(docShell);
 
   docShell->SetAffectPrivateSessionLifetime(
       mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME);
   nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(WebNavigation());
   MOZ_ASSERT(loadContext);
@@ -1481,32 +1471,32 @@ TabChild::ZoomToRect(const uint32_t& aPr
   if (mApzcTreeManager) {
     mApzcTreeManager->ZoomToRect(guid, aRect, aFlags);
   }
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvActivate()
 {
+  MOZ_ASSERT(mWebBrowser);
   // Ensure that the PresShell exists, otherwise focusing
   // is definitely not going to work. GetPresShell should
   // create a PresShell if one doesn't exist yet.
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   MOZ_ASSERT(presShell);
 
-  nsCOMPtr<nsIWebBrowserFocus> browser = do_QueryInterface(WebNavigation());
-  browser->Activate();
+  mWebBrowser->FocusActivate();
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvDeactivate()
 {
-  nsCOMPtr<nsIWebBrowserFocus> browser = do_QueryInterface(WebNavigation());
-  browser->Deactivate();
+  MOZ_ASSERT(mWebBrowser);
+  mWebBrowser->FocusDeactivate();
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvParentActivated(const bool& aActivated)
 {
   mParentIsActive = aActivated;
 
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -43,16 +43,17 @@
 #include "PuppetWidget.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "nsDeque.h"
 #include "nsISHistoryListener.h"
 
 class nsIDOMWindowUtils;
 class nsIHttpChannel;
 class nsISerialEventTarget;
+class nsWebBrowser;
 
 template<typename T> class nsTHashtable;
 template<typename T> class nsPtrHashKey;
 
 namespace mozilla {
 class AbstractThread;
 namespace layout {
 class RenderFrameChild;
@@ -817,16 +818,17 @@ private:
 
   void InternalSetDocShellIsActive(bool aIsActive);
 
   bool CreateRemoteLayerManager(mozilla::layers::PCompositorBridgeChild* aCompositorChild);
 
   class DelayedDeleteRunnable;
 
   TextureFactoryIdentifier mTextureFactoryIdentifier;
+  RefPtr<nsWebBrowser> mWebBrowser;
   nsCOMPtr<nsIWebNavigation> mWebNav;
   RefPtr<mozilla::dom::TabGroup> mTabGroup;
   RefPtr<PuppetWidget> mPuppetWidget;
   nsCOMPtr<nsIURI> mLastURI;
   RenderFrameChild* mRemoteFrame;
   RefPtr<nsIContentChild> mManager;
   uint32_t mChromeFlags;
   uint32_t mMaxTouchPoints;
--- a/dom/mathml/nsMathMLElement.cpp
+++ b/dom/mathml/nsMathMLElement.cpp
@@ -956,18 +956,18 @@ nsMathMLElement::IsLink(nsIURI** aURI) c
   // The REC says that the following elements should not be linking elements:
   if (IsAnyOfMathMLElements(nsGkAtoms::mprescripts_, nsGkAtoms::none,
                             nsGkAtoms::malignmark_, nsGkAtoms::maligngroup_)) {
     *aURI = nullptr;
     return false;
   }
 
   bool hasHref = false;
-  const nsAttrValue* href = mAttrsAndChildren.GetAttr(nsGkAtoms::href,
-                                                      kNameSpaceID_None);
+  const nsAttrValue* href = mAttrs.GetAttr(nsGkAtoms::href,
+                                           kNameSpaceID_None);
   if (href) {
     // MathML href
     // The REC says: "When user agents encounter MathML elements with both href
     // and xlink:href attributes, the href attribute should take precedence."
     hasHref = true;
   } else {
     // To be a clickable XLink for styling and interaction purposes, we require:
     //
@@ -984,18 +984,17 @@ nsMathMLElement::IsLink(nsIURI** aURI) c
 
     static Element::AttrValuesArray sShowVals[] =
       { &nsGkAtoms::_empty, &nsGkAtoms::_new, &nsGkAtoms::replace, nullptr };
 
     static Element::AttrValuesArray sActuateVals[] =
       { &nsGkAtoms::_empty, &nsGkAtoms::onRequest, nullptr };
 
     // Optimization: check for href first for early return
-    href = mAttrsAndChildren.GetAttr(nsGkAtoms::href,
-                                     kNameSpaceID_XLink);
+    href = mAttrs.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink);
     if (href &&
         FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::type,
                         sTypeVals, eCaseMatters) !=
         Element::ATTR_VALUE_NO_MATCH &&
         FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::show,
                         sShowVals, eCaseMatters) !=
         Element::ATTR_VALUE_NO_MATCH &&
         FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::actuate,
@@ -1018,18 +1017,18 @@ nsMathMLElement::IsLink(nsIURI** aURI) c
 
   *aURI = nullptr;
   return false;
 }
 
 void
 nsMathMLElement::GetLinkTarget(nsAString& aTarget)
 {
-  const nsAttrValue* target = mAttrsAndChildren.GetAttr(nsGkAtoms::target,
-                                                        kNameSpaceID_XLink);
+  const nsAttrValue* target = mAttrs.GetAttr(nsGkAtoms::target,
+                                             kNameSpaceID_XLink);
   if (target) {
     target->ToString(aTarget);
   }
 
   if (aTarget.IsEmpty()) {
 
     static Element::AttrValuesArray sShowVals[] =
       { &nsGkAtoms::_new, &nsGkAtoms::replace, nullptr };
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -320,17 +320,17 @@ class RTCStatsReport {
               //       if (stat.isRemote) continue;
               //       let rtcp = stats.get(stat.remoteId);
               //
               if (warnRemoteNullable.warn && stat.isRemote &&
                   key != "type" &&
                   key != "isRemote") {
                 // id is first prop, a sign of JSON.stringify(), cancel warnings.
                 if (key != "id") {
-                  warnRemoteNullable.warn();
+                  warnRemoteNullable.warn(key);
                 }
                 warnRemoteNullable.warn = null;
               }
               return stat[key];
             }, entry)
           });
         }
         Cu.unwaiveXrays(entry)._isRemote = stat.isRemote;
@@ -495,19 +495,19 @@ class RTCPeerConnection {
     this._warnDeprecatedStatsAccessNullable = { warn: () =>
       this.logWarning("non-maplike pc.getStats access is deprecated, and will be removed in the near future! " +
                       "See http://w3c.github.io/webrtc-pc/#getstats-example for usage.") };
 
     this._warnDeprecatedStatsCallbacksNullable = { warn: () =>
       this.logWarning("Callback-based pc.getStats is deprecated, and will be removed in the near future! Use promise-version! " +
                       "See http://w3c.github.io/webrtc-pc/#getstats-example for usage.") };
 
-    this._warnDeprecatedStatsRemoteAccessNullable = { warn: () =>
-      this.logWarning("Detected soon-to-break getStats() use! stat.isRemote goes away in Firefox 65, but won't warn there!\
- - See https://blog.mozilla.org/webrtc/getstats-isremote-65/") };
+    this._warnDeprecatedStatsRemoteAccessNullable = { warn: (key) =>
+      this.logWarning(`Detected soon-to-break getStats() use with key="${key}"! stat.isRemote goes away in Firefox 65, but won't warn there!\
+ - See https://blog.mozilla.org/webrtc/getstats-isremote-65/`) };
 
     // Add a reference to the PeerConnection to global list (before init).
     _globalPCList.addPC(this);
 
     this._impl.initialize(this._observer, this._win, rtcConfig,
                           Services.tm.currentThread);
 
     this._certificateReady = this._initCertificate(rtcConfig.certificates);
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -2100,17 +2100,18 @@ TrackBuffersManager::RemoveFrames(const 
 
   // Recalculate sanitized buffered ranges.
   aTrackData.mSanitizedBufferedRanges = aTrackData.mBufferedRanges;
   aTrackData.mSanitizedBufferedRanges.SetFuzz(maxSampleDuration/2);
 
   data.RemoveElementsAt(firstRemovedIndex.ref(),
                         lastRemovedIndex - firstRemovedIndex.ref() + 1);
 
-  if (aIntervals.GetEnd() >= aTrackData.mHighestStartTimestamp) {
+  if (removedIntervals.GetEnd() >= aTrackData.mHighestStartTimestamp &&
+      removedIntervals.GetStart() <= aTrackData.mHighestStartTimestamp) {
     // The sample with the highest presentation time got removed.
     // Rescan the trackbuffer to determine the new one.
     TimeUnit highestStartTime;
     for (const auto& sample : data) {
       if (sample->mTime > highestStartTime) {
         highestStartTime = sample->mTime;
       }
     }
--- a/dom/media/mediasource/test/test_ChangeType.html
+++ b/dom/media/mediasource/test/test_ChangeType.html
@@ -5,20 +5,16 @@
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="mediasource.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test"><script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
-async function setupTest() {
-  await SpecialPowers.pushPrefEnv({"set": [["media.mediasource.experimental.enabled", true]]});
-}
-setupTest();
 
 runWithMSE(function(ms, el) {
   el.controls = true;
   once(ms, "sourceopen").then(function() {
     // Log events for debugging.
     const events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
                     "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
                     "waiting", "pause", "durationchange", "seeking", "seeked"];
--- a/dom/svg/SVGAnimationElement.cpp
+++ b/dom/svg/SVGAnimationElement.cpp
@@ -77,18 +77,17 @@ SVGAnimationElement::GetTargetElementCon
   // allow <use><animate>, for example.
   return GetParentElement();
 }
 
 bool
 SVGAnimationElement::GetTargetAttributeName(int32_t *aNamespaceID,
                                             nsAtom **aLocalName) const
 {
-  const nsAttrValue* nameAttr
-    = mAttrsAndChildren.GetAttr(nsGkAtoms::attributeName);
+  const nsAttrValue* nameAttr = mAttrs.GetAttr(nsGkAtoms::attributeName);
 
   if (!nameAttr)
     return false;
 
   NS_ASSERTION(nameAttr->Type() == nsAttrValue::eAtom,
     "attributeName should have been parsed as an atom");
 
   return NS_SUCCEEDED(nsContentUtils::SplitQName(
@@ -172,18 +171,18 @@ SVGAnimationElement::BindToTree(nsIDocum
   // Add myself to the animation controller's master set of animation elements.
   if (nsIDocument* doc = GetComposedDoc()) {
     nsSMILAnimationController* controller = doc->GetAnimationController();
     if (controller) {
       controller->RegisterAnimationElement(this);
     }
     const nsAttrValue* href =
       HasAttr(kNameSpaceID_None, nsGkAtoms::href)
-      ? mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_None)
-      : mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink);
+        ? mAttrs.GetAttr(nsGkAtoms::href, kNameSpaceID_None)
+        : mAttrs.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink);
     if (href) {
       nsAutoString hrefStr;
       href->ToString(hrefStr);
 
       UpdateHrefTarget(hrefStr);
     }
 
     mTimedElement.BindToTree(aParent);
@@ -293,17 +292,17 @@ SVGAnimationElement::AfterSetAttr(int32_
   if (!aValue) {
     if (aNamespaceID == kNameSpaceID_None) {
       mHrefTarget.Unlink();
       AnimationTargetChanged();
 
       // After unsetting href, we may still have xlink:href, so we
       // should try to add it back.
       const nsAttrValue* xlinkHref =
-        mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink);
+        mAttrs.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink);
       if (xlinkHref) {
         UpdateHrefTarget(xlinkHref->GetStringValue());
       }
     } else if (!HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
       mHrefTarget.Unlink();
       AnimationTargetChanged();
     } // else: we unset xlink:href, but we still have href attribute, so keep
       // mHrefTarget linking to href.
--- a/dom/svg/SVGMPathElement.cpp
+++ b/dom/svg/SVGMPathElement.cpp
@@ -88,18 +88,18 @@ SVGMPathElement::BindToTree(nsIDocument*
              "Shouldn't have href-target yet (or it should've been cleared)");
   nsresult rv = SVGMPathElementBase::BindToTree(aDocument, aParent,
                                                 aBindingParent);
   NS_ENSURE_SUCCESS(rv,rv);
 
   if (aDocument) {
     const nsAttrValue* hrefAttrValue =
       HasAttr(kNameSpaceID_None, nsGkAtoms::href)
-      ? mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_None)
-      : mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink);
+        ? mAttrs.GetAttr(nsGkAtoms::href, kNameSpaceID_None)
+        : mAttrs.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink);
     if (hrefAttrValue) {
       UpdateHrefTarget(aParent, hrefAttrValue->GetStringValue());
     }
   }
 
   return NS_OK;
 }
 
@@ -149,17 +149,17 @@ SVGMPathElement::AfterSetAttr(int32_t aN
   if (!aValue && aName == nsGkAtoms::href) {
     // href attr being removed.
     if (aNamespaceID == kNameSpaceID_None) {
       UnlinkHrefTarget(true);
 
       // After unsetting href, we may still have xlink:href, so we should
       // try to add it back.
       const nsAttrValue* xlinkHref =
-        mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink);
+        mAttrs.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink);
       if (xlinkHref) {
         UpdateHrefTarget(GetParent(), xlinkHref->GetStringValue());
       }
     } else if (aNamespaceID == kNameSpaceID_XLink &&
                !HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
       UnlinkHrefTarget(true);
     } // else: we unset some random-namespace href attribute, or unset xlink:href
       // but still have href attribute, so keep the target linking to href.
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -239,35 +239,34 @@ nsSVGElement::BindToTree(nsIDocument* aD
 {
   nsresult rv = nsSVGElementBase::BindToTree(aDocument, aParent,
                                              aBindingParent);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!MayHaveStyle()) {
     return NS_OK;
   }
-  const nsAttrValue* oldVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
+  const nsAttrValue* oldVal = mAttrs.GetAttr(nsGkAtoms::style);
 
   if (oldVal && oldVal->Type() == nsAttrValue::eCSSDeclaration) {
     // we need to force a reparse because the baseURI of the document
     // may have changed, and in particular because we may be clones of
     // XBL anonymous content now being bound to the document we should
     // render in and due to the hacky way in which we implement the
     // interaction of XBL and SVG resources.  Once we have a sane
     // ownerDocument on XBL anonymous content, this can all go away.
     nsAttrValue attrValue;
     nsAutoString stringValue;
     oldVal->ToString(stringValue);
     // Force in data doc, since we already have a style rule
     ParseStyleAttribute(stringValue, nullptr, attrValue, true);
     // Don't bother going through SetInlineStyleDeclaration; we don't
     // want to fire off mutation events or document notifications anyway
     bool oldValueSet;
-    rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue,
-                                          &oldValueSet);
+    rv = mAttrs.SetAndSwapAttr(nsGkAtoms::style, attrValue, &oldValueSet);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsSVGElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
@@ -275,19 +274,19 @@ nsSVGElement::AfterSetAttr(int32_t aName
                            const nsAttrValue* aOldValue,
                            nsIPrincipal* aSubjectPrincipal,
                            bool aNotify)
 {
   // We don't currently use nsMappedAttributes within SVG. If this changes, we
   // need to be very careful because some nsAttrValues used by SVG point to
   // member data of SVG elements and if an nsAttrValue outlives the SVG element
   // whose data it points to (by virtue of being stored in
-  // mAttrsAndChildren->mMappedAttributes, meaning it's shared between
+  // mAttrs->mMappedAttributes, meaning it's shared between
   // elements), the pointer will dangle. See bug 724680.
-  MOZ_ASSERT(!mAttrsAndChildren.HasMappedAttrs(),
+  MOZ_ASSERT(!mAttrs.HasMappedAttrs(),
              "Unexpected use of nsMappedAttributes within SVG");
 
   // If this is an svg presentation attribute we need to map it into
   // the content declaration block.
   // XXX For some reason incremental mapping doesn't work, so for now
   // just delete the style rule and lazily reconstruct it as needed).
   if (aNamespaceID == kNameSpaceID_None && IsAttributeMapped(aName)) {
     mContentDeclarationBlock = nullptr;
@@ -1244,28 +1243,28 @@ MappedAttrParser::GetDeclarationBlock()
 // Implementation Helpers:
 
 void
 nsSVGElement::UpdateContentDeclarationBlock()
 {
   NS_ASSERTION(!mContentDeclarationBlock,
                "we already have a content declaration block");
 
-  uint32_t attrCount = mAttrsAndChildren.AttrCount();
+  uint32_t attrCount = mAttrs.AttrCount();
   if (!attrCount) {
     // nothing to do
     return;
   }
 
   nsIDocument* doc = OwnerDoc();
   MappedAttrParser mappedAttrParser(doc->CSSLoader(), doc->GetDocumentURI(),
                                     GetBaseURI(), this);
 
   for (uint32_t i = 0; i < attrCount; ++i) {
-    const nsAttrName* attrName = mAttrsAndChildren.AttrNameAt(i);
+    const nsAttrName* attrName = mAttrs.AttrNameAt(i);
     if (!attrName->IsAtom() || !IsAttributeMapped(attrName->Atom()))
       continue;
 
     if (attrName->NamespaceID() != kNameSpaceID_None &&
         !attrName->Equals(nsGkAtoms::lang, kNameSpaceID_XML)) {
       continue;
     }
 
@@ -1288,17 +1287,17 @@ nsSVGElement::UpdateContentDeclarationBl
       }
       if (attrName->Atom() == nsGkAtoms::height &&
           !GetAnimatedLength(nsGkAtoms::height)->HasBaseVal()) {
         continue;
       }
     }
 
     nsAutoString value;
-    mAttrsAndChildren.AttrAt(i)->ToString(value);
+    mAttrs.AttrAt(i)->ToString(value);
     mappedAttrParser.ParseMappedAttrValue(attrName->Atom(), value);
   }
   mContentDeclarationBlock = mappedAttrParser.GetDeclarationBlock();
 }
 
 const DeclarationBlock*
 nsSVGElement::GetContentDeclarationBlock() const
 {
@@ -1439,25 +1438,25 @@ nsSVGElement::MaybeSerializeAttrBeforeRe
 {
   if (!aNotify ||
       !nsContentUtils::HasMutationListeners(this,
                                             NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
                                             this)) {
     return;
   }
 
-  const nsAttrValue* attrValue = mAttrsAndChildren.GetAttr(aName);
+  const nsAttrValue* attrValue = mAttrs.GetAttr(aName);
   if (!attrValue)
     return;
 
   nsAutoString serializedValue;
   attrValue->ToString(serializedValue);
   nsAttrValue oldAttrValue(serializedValue);
   bool oldValueSet;
-  mAttrsAndChildren.SetAndSwapAttr(aName, oldAttrValue, &oldValueSet);
+  mAttrs.SetAndSwapAttr(aName, oldAttrValue, &oldValueSet);
 }
 
 /* static */
 nsAtom* nsSVGElement::GetEventNameForAttr(nsAtom* aAttr)
 {
   if (aAttr == nsGkAtoms::onload)
     return nsGkAtoms::onSVGLoad;
   if (aAttr == nsGkAtoms::onunload)
@@ -2452,19 +2451,19 @@ nsSVGElement::ReportAttributeParseFailur
   return SVGContentUtils::ReportToConsole(aDocument,
                                           "AttributeParseWarning",
                                           strings, ArrayLength(strings));
 }
 
 void
 nsSVGElement::RecompileScriptEventListeners()
 {
-  int32_t i, count = mAttrsAndChildren.AttrCount();
+  int32_t i, count = mAttrs.AttrCount();
   for (i = 0; i < count; ++i) {
-    const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
+    const nsAttrName *name = mAttrs.AttrNameAt(i);
 
     // Eventlistenener-attributes are always in the null namespace
     if (!name->IsAtom()) {
         continue;
     }
 
     nsAtom *attr = name->Atom();
     if (!IsEventAttributeName(attr)) {
--- a/dom/tests/browser/browser_localStorage_e10s.js
+++ b/dom/tests/browser/browser_localStorage_e10s.js
@@ -155,17 +155,17 @@ async function verifyTabPreload(knownTab
  * Instruct the given tab to execute the given series of mutations.  For
  * simplicity, the mutations representation matches the expected events rep.
  */
 async function mutateTabStorage(knownTab, mutations, sentinelValue) {
   await ContentTask.spawn(
     knownTab.tab.linkedBrowser,
     { mutations, sentinelValue },
     function(args) {
-      return content.wrappedJSObject.mutateStorage(args);
+      return content.wrappedJSObject.mutateStorage(Cu.cloneInto(args, content));
     });
 }
 
 /**
  * Instruct the given tab to add a "storage" event listener and record all
  * received events.  verifyTabStorageEvents is the corresponding method to
  * check and assert the recorded events.
  */
--- a/dom/webidl/SourceBuffer.webidl
+++ b/dom/webidl/SourceBuffer.webidl
@@ -53,11 +53,11 @@ interface SourceBuffer : EventTarget {
   [Throws]
   void remove(double start, unrestricted double end);
   // Experimental function as proposed in:
   // https://github.com/w3c/media-source/issues/100 for promise proposal.
   [Throws, Func="mozilla::dom::MediaSource::ExperimentalEnabled"]
   Promise<void> removeAsync(double start, unrestricted double end);
   // Experimental function as proposed in:
   // https://github.com/w3c/media-source/issues/155
-  [Throws, Func="mozilla::dom::MediaSource::ExperimentalEnabled"]
+  [Throws]
   void changeType(DOMString type);
 };
--- a/dom/webidl/WebGLRenderingContext.webidl
+++ b/dom/webidl/WebGLRenderingContext.webidl
@@ -1096,14 +1096,16 @@ interface EXT_disjoint_timer_query {
     void queryCounterEXT(WebGLQuery query, GLenum target);
     any getQueryEXT(GLenum target, GLenum pname);
     any getQueryObjectEXT(WebGLQuery query, GLenum pname);
 };
 
 [NoInterfaceObject]
 interface MOZ_debug {
     const GLenum EXTENSIONS = 0x1F03;
+
     const GLenum WSI_INFO   = 0x10000;
     const GLenum UNPACK_REQUIRE_FASTPATH = 0x10001;
+    const GLenum DOES_INDEX_VALIDATION   = 0x10002;
 
     [Throws]
     any getParameter(GLenum pname);
 };
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -311,27 +311,27 @@ nsresult
 nsXULElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
                     bool aPreallocateChildren) const
 {
     *aResult = nullptr;
 
     RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
     RefPtr<nsXULElement> element = Construct(ni.forget());
 
-    nsresult rv = element->mAttrsAndChildren.EnsureCapacityToClone(mAttrsAndChildren,
-                                                                   aPreallocateChildren);
+    nsresult rv = element->mAttrs.EnsureCapacityToClone(mAttrs,
+                                                        aPreallocateChildren);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Note that we're _not_ copying mControllers.
 
-    uint32_t count = mAttrsAndChildren.AttrCount();
+    uint32_t count = mAttrs.AttrCount();
     rv = NS_OK;
     for (uint32_t i = 0; i < count; ++i) {
-        const nsAttrName* originalName = mAttrsAndChildren.AttrNameAt(i);
-        const nsAttrValue* originalValue = mAttrsAndChildren.AttrAt(i);
+        const nsAttrName* originalName = mAttrs.AttrNameAt(i);
+        const nsAttrValue* originalValue = mAttrs.AttrAt(i);
         nsAttrValue attrValue;
 
         // Style rules need to be cloned.
         if (originalValue->Type() == nsAttrValue::eCSSDeclaration) {
             DeclarationBlock* decl = originalValue->GetCSSDeclarationValue();
             RefPtr<DeclarationBlock> declClone = decl->Clone();
 
             nsString stringValue;
@@ -339,23 +339,23 @@ nsXULElement::Clone(mozilla::dom::NodeIn
 
             attrValue.SetTo(declClone.forget(), &stringValue);
         } else {
             attrValue.SetTo(*originalValue);
         }
 
         bool oldValueSet;
         if (originalName->IsAtom()) {
-           rv = element->mAttrsAndChildren.SetAndSwapAttr(originalName->Atom(),
-                                                          attrValue,
-                                                          &oldValueSet);
+           rv = element->mAttrs.SetAndSwapAttr(originalName->Atom(),
+                                               attrValue,
+                                               &oldValueSet);
         } else {
-            rv = element->mAttrsAndChildren.SetAndSwapAttr(originalName->NodeInfo(),
-                                                           attrValue,
-                                                           &oldValueSet);
+            rv = element->mAttrs.SetAndSwapAttr(originalName->NodeInfo(),
+                                                attrValue,
+                                                &oldValueSet);
         }
         NS_ENSURE_SUCCESS(rv, rv);
         element->AddListenerFor(*originalName);
         if (originalName->Equals(nsGkAtoms::id) &&
             !originalValue->IsEmptyString()) {
             element->SetHasID();
         }
         if (originalName->Equals(nsGkAtoms::_class)) {
@@ -1312,21 +1312,21 @@ nsXULElement::MakeHeavyweight(nsXULProto
             attrValue.SetTo(declClone.forget(), &stringValue);
         } else {
             attrValue.SetTo(protoattr->mValue);
         }
 
         bool oldValueSet;
         // XXX we might wanna have a SetAndTakeAttr that takes an nsAttrName
         if (protoattr->mName.IsAtom()) {
-            rv = mAttrsAndChildren.SetAndSwapAttr(protoattr->mName.Atom(),
-                                                  attrValue, &oldValueSet);
+            rv = mAttrs.SetAndSwapAttr(protoattr->mName.Atom(),
+                                       attrValue, &oldValueSet);
         } else {
-            rv = mAttrsAndChildren.SetAndSwapAttr(protoattr->mName.NodeInfo(),
-                                                  attrValue, &oldValueSet);
+            rv = mAttrs.SetAndSwapAttr(protoattr->mName.NodeInfo(),
+                                       attrValue, &oldValueSet);
         }
         NS_ENSURE_SUCCESS(rv, rv);
     }
     return NS_OK;
 }
 
 nsresult
 nsXULElement::HideWindowChrome(bool aShouldHide)
@@ -1508,19 +1508,19 @@ nsXULElement::BoolAttrIsTrue(nsAtom* aNa
 
     return attr && attr->Type() == nsAttrValue::eAtom &&
            attr->GetAtomValue() == nsGkAtoms::_true;
 }
 
 void
 nsXULElement::RecompileScriptEventListeners()
 {
-    int32_t i, count = mAttrsAndChildren.AttrCount();
+    int32_t i, count = mAttrs.AttrCount();
     for (i = 0; i < count; ++i) {
-        const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
+        const nsAttrName *name = mAttrs.AttrNameAt(i);
 
         // Eventlistenener-attributes are always in the null namespace
         if (!name->IsAtom()) {
             continue;
         }
 
         nsAtom *attr = name->Atom();
         if (!nsContentUtils::IsEventAttributeName(attr, EventNameType_XUL)) {
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -16,17 +16,17 @@
 #include "mozilla/Attributes.h"
 #include "nsIServiceManager.h"
 #include "nsAtom.h"
 #include "mozilla/dom/NodeInfo.h"
 #include "nsIControllers.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIURI.h"
 #include "nsLayoutCID.h"
-#include "nsAttrAndChildArray.h"
+#include "AttrArray.h"
 #include "nsGkAtoms.h"
 #include "nsStringFwd.h"
 #include "nsStyledElement.h"
 #include "mozilla/dom/DOMRect.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/DOMString.h"
 #include "mozilla/dom/FromParser.h"
 
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -577,25 +577,26 @@ GLContextEGL::CreateGLContext(CreateCont
 
     std::vector<EGLint> robustness_attribs;
     std::vector<EGLint> rbab_attribs; // RBAB: Robust Buffer Access Behavior
     if (flags & CreateContextFlags::PREFER_ROBUSTNESS) {
         if (egl->IsExtensionSupported(GLLibraryEGL::EXT_create_context_robustness)) {
             robustness_attribs = required_attribs;
             robustness_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
             robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT);
-            // Skip EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, since it doesn't help us.
-        }
 
-        if (egl->IsExtensionSupported(GLLibraryEGL::KHR_create_context) &&
-            !egl->IsANGLE())
-        {
-            rbab_attribs = required_attribs;
-            rbab_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR);
-            rbab_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_KHR);
+            rbab_attribs = robustness_attribs;
+            rbab_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
+            rbab_attribs.push_back(LOCAL_EGL_TRUE);
+        } else if (egl->IsExtensionSupported(GLLibraryEGL::KHR_create_context)) {
+            robustness_attribs = required_attribs;
+            robustness_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR);
+            robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_KHR);
+
+            rbab_attribs = robustness_attribs;
             rbab_attribs.push_back(LOCAL_EGL_CONTEXT_FLAGS_KHR);
             rbab_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR);
         }
     }
 
     const auto fnCreate = [&](const std::vector<EGLint>& attribs) {
         auto terminated_attribs = attribs;
 
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -361,18 +361,18 @@ AsyncImagePipelineManager::ApplyAsyncIma
                            !!aPipeline->mCurrentTexture;
 
   if (!updateDisplayList) {
     // We don't need to update the display list, either because we can't or because
     // the previous one is still up to date.
     // We may, however, have updated some resources.
 
     // Use transaction of scene builder thread to notify epoch.
-    // It is for making epoc update consisitent.
-    aMaybeFastTxn.UpdateEpoch(aPipelineId, aEpoch);
+    // It is for making epoch update consistent.
+    aSceneBuilderTxn.UpdateEpoch(aPipelineId, aEpoch);
     if (aPipeline->mCurrentTexture) {
       HoldExternalImage(aPipelineId, aEpoch, aPipeline->mCurrentTexture->AsWebRenderTextureHost());
     }
     return;
   }
 
   aPipeline->mIsChanged = false;
 
--- a/gfx/webrender/Cargo.toml
+++ b/gfx/webrender/Cargo.toml
@@ -26,17 +26,17 @@ byteorder = "1.0"
 cfg-if = "0.1.2"
 euclid = "0.19"
 fxhash = "0.2.1"
 gleam = "0.6"
 image = { optional = true, version = "0.19" }
 lazy_static = "1"
 log = "0.4"
 num-traits = "0.2"
-plane-split = "0.12"
+plane-split = "0.12.1"
 png = { optional = true, version = "0.12" }
 rayon = "1"
 ron = { optional = true, version = "0.1.7" }
 serde = { optional = true, version = "1.0", features = ["serde_derive"] }
 serde_json = { optional = true, version = "1.0" }
 smallvec = "0.6"
 thread_profiler = "0.1.1"
 time = "0.1"
--- a/gfx/webrender/src/batch.rs
+++ b/gfx/webrender/src/batch.rs
@@ -1,38 +1,37 @@
 /* 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 api::{AlphaType, ClipMode, DeviceIntRect, DeviceIntSize};
-use api::{DeviceUintRect, DeviceUintPoint, ExternalImageType, FilterOp, ImageRendering, LayoutRect};
-use api::{DeviceIntPoint, YuvColorSpace, YuvFormat};
-use api::{LayoutToWorldTransform, WorldPixel};
+use api::{AlphaType, ClipMode, DeviceIntRect, DeviceIntSize, DeviceIntPoint};
+use api::{DeviceUintRect, DeviceUintPoint, ExternalImageType, FilterOp, ImageRendering};
+use api::{YuvColorSpace, YuvFormat, WorldPixel};
 use clip::{ClipSource, ClipStore, ClipWorkItem};
 use clip_scroll_tree::{CoordinateSystemId};
-use euclid::{TypedTransform3D, vec3};
+use euclid::vec3;
 use glyph_rasterizer::GlyphFormat;
 use gpu_cache::{GpuCache, GpuCacheHandle, GpuCacheAddress};
 use gpu_types::{BrushFlags, BrushInstance, PrimitiveHeaders};
 use gpu_types::{ClipMaskInstance, SplitCompositeInstance};
 use gpu_types::{PrimitiveInstance, RasterizationSpace, GlyphInstance};
 use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
 use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
 use picture::{PictureCompositeMode, PicturePrimitive, PictureSurface};
-use plane_split::{BspSplitter, Polygon, Splitter};
+use plane_split::{BspSplitter, Clipper, Polygon, Splitter};
 use prim_store::{BrushKind, BrushPrimitive, BrushSegmentTaskId, DeferredResolve};
 use prim_store::{EdgeAaSegmentMask, ImageSource, PictureIndex, PrimitiveIndex, PrimitiveKind};
 use prim_store::{PrimitiveMetadata, PrimitiveRun, PrimitiveStore, VisibleGradientTile};
 use prim_store::{BorderSource};
 use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree};
-use renderer::{BlendMode, ImageBufferKind};
-use renderer::{BLOCKS_PER_UV_RECT, ShaderColorMode};
+use renderer::{BlendMode, ImageBufferKind, ShaderColorMode};
+use renderer::BLOCKS_PER_UV_RECT;
 use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache};
 use scene::FilterOpHelpers;
-use std::{usize, f32, i32};
+use std::{f32, i32};
 use tiling::{RenderTargetContext};
 use util::{TransformedRectKind};
 
 // Special sentinel value recognized by the shader. It is considered to be
 // a dummy task that doesn't mask out anything.
 const OPAQUE_TASK_ADDRESS: RenderTaskAddress = RenderTaskAddress(0x7fff);
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -671,29 +670,40 @@ impl AlphaBatchBuilder {
                         let picture = &ctx.prim_store.pictures[pic_index.0];
 
                         // If this picture is participating in a 3D rendering context,
                         // then don't add it to any batches here. Instead, create a polygon
                         // for it and add it to the current plane splitter.
                         if picture.is_in_3d_context {
                             // Push into parent plane splitter.
                             debug_assert!(picture.surface.is_some());
-
-                            let real_xf = &ctx
-                                .transforms
+                            let transform = &ctx.transforms
                                 .get_transform(picture.reference_frame_index);
-                            match make_polygon(
-                                picture.real_local_rect,
-                                &real_xf.m,
-                                prim_index.0,
-                            ) {
-                                Some(polygon) => splitter.add(polygon),
-                                None => {
-                                    // this shouldn't happen, the path will ultimately be
-                                    // turned into `expect` when the splitting code is fixed
+
+                            match transform.transform_kind {
+                                TransformedRectKind::AxisAligned => {
+                                    let polygon = Polygon::from_transformed_rect(
+                                        picture.real_local_rect.cast(),
+                                        transform.m.cast(),
+                                        prim_index.0,
+                                    ).unwrap();
+                                    splitter.add(polygon);
+                                }
+                                TransformedRectKind::Complex => {
+                                    let mut clipper = Clipper::new();
+                                    let bounds = (screen_rect.clipped.to_f32() / ctx.device_pixel_scale).to_f64();
+                                    let matrix = transform.m.cast();
+                                    let results = clipper.clip_transformed(
+                                        Polygon::from_rect(picture.real_local_rect.cast(), prim_index.0),
+                                        &matrix,
+                                        Some(bounds),
+                                    );
+                                    for poly in results {
+                                        splitter.add(poly);
+                                    }
                                 }
                             }
 
                             return;
                         }
 
                         let add_to_parent_pic = match picture.composite_mode {
                             Some(PictureCompositeMode::Filter(filter)) => {
@@ -1704,43 +1714,16 @@ pub fn resolve_image(
             }
         }
         None => {
             CacheItem::invalid()
         }
     }
 }
 
-/// Construct a polygon from stacking context boundaries.
-/// `anchor` here is an index that's going to be preserved in all the
-/// splits of the polygon.
-fn make_polygon(
-    rect: LayoutRect,
-    transform: &LayoutToWorldTransform,
-    anchor: usize,
-) -> Option<Polygon<f64, WorldPixel>> {
-    let mat = TypedTransform3D::row_major(
-        transform.m11 as f64,
-        transform.m12 as f64,
-        transform.m13 as f64,
-        transform.m14 as f64,
-        transform.m21 as f64,
-        transform.m22 as f64,
-        transform.m23 as f64,
-        transform.m24 as f64,
-        transform.m31 as f64,
-        transform.m32 as f64,
-        transform.m33 as f64,
-        transform.m34 as f64,
-        transform.m41 as f64,
-        transform.m42 as f64,
-        transform.m43 as f64,
-        transform.m44 as f64);
-    Polygon::from_transformed_rect(rect.cast(), mat, anchor)
-}
 
 /// Batcher managing draw calls into the clip mask (in the RT cache).
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct ClipBatcher {
     /// Rectangle draws fill up the rectangles with rounded corners.
     pub rectangles: Vec<ClipMaskInstance>,
--- a/gfx/webrender/src/border.rs
+++ b/gfx/webrender/src/border.rs
@@ -4,29 +4,32 @@
 
 use api::{BorderRadius, BorderSide, BorderStyle, BorderWidths, ColorF};
 use api::{ColorU, DeviceRect, DeviceSize, LayoutSizeAu, LayoutPrimitiveInfo, LayoutToDeviceScale};
 use api::{DevicePixel, DeviceVector2D, DevicePoint, DeviceIntSize, LayoutRect, LayoutSize, NormalBorder};
 use app_units::Au;
 use ellipse::Ellipse;
 use display_list_flattener::DisplayListFlattener;
 use gpu_types::{BorderInstance, BorderSegment, BrushFlags};
-use prim_store::{BrushKind, BrushPrimitive, BrushSegment, VECS_PER_SEGMENT};
+use prim_store::{BrushKind, BrushPrimitive, BrushSegment};
 use prim_store::{BorderSource, EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain};
-use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
 use util::{lerp, RectHelpers};
 
 // Using 2048 as the maximum radius in device space before which we
 // start stretching is up for debate.
 // the value must be chosen so that the corners will not use an
 // unreasonable amount of memory but should allow crisp corners in the
 // common cases.
 
 /// Maximum resolution in device pixels at which borders are rasterized.
 pub const MAX_BORDER_RESOLUTION: u32 = 2048;
+/// Maximum number of dots or dashes per segment to avoid freezing and filling up
+/// memory with unreasonable inputs. It would be better to address this by not building
+/// a list of per-dot information in the first place.
+pub const MAX_DASH_COUNT: usize = 2048;
 
 trait AuSizeConverter {
     fn to_au(&self) -> LayoutSizeAu;
 }
 
 impl AuSizeConverter for LayoutSize {
     fn to_au(&self) -> LayoutSizeAu {
         LayoutSizeAu::new(
@@ -350,33 +353,30 @@ impl BorderCornerClipSource {
             outer_scale.x * self.radius.width,
             outer_scale.y * self.radius.height,
         );
         let clip_sign = DeviceVector2D::new(
             1.0 - 2.0 * outer_scale.x,
             1.0 - 2.0 * outer_scale.y,
         );
 
-        // No point in pushing more clips as it will blow up the maximum amount of
-        // segments per primitive later down the road.
-        // See #2915 for a better fix.
-        let clip_limit = MAX_VERTEX_TEXTURE_WIDTH / VECS_PER_SEGMENT;
-        let max_clip_count = self.max_clip_count.min(clip_limit);
+        let max_clip_count = self.max_clip_count.min(MAX_DASH_COUNT);
 
         match self.kind {
             BorderCornerClipKind::Dash => {
                 // Get the correct dash arc length.
                 let dash_arc_length =
                     0.5 * self.ellipse.total_arc_length / max_clip_count as f32;
                 // Start the first dash at one quarter the length of a single dash
                 // along the arc line. This is arbitrary but looks reasonable in
                 // most cases. We need to spend some time working on a more
                 // sophisticated dash placement algorithm that takes into account
                 // the offset of the dashes along edge segments.
                 let mut current_arc_length = 0.25 * dash_arc_length;
+                dot_dash_data.reserve(max_clip_count);
                 for _ in 0 .. max_clip_count {
                     let arc_length0 = current_arc_length;
                     current_arc_length += dash_arc_length;
 
                     let arc_length1 = current_arc_length;
                     current_arc_length += dash_arc_length;
 
                     let alpha = self.ellipse.find_angle_for_arc_length(arc_length0);
@@ -420,18 +420,18 @@ impl BorderCornerClipSource {
             BorderCornerClipKind::Dot if max_clip_count == 1 => {
                 let dot_diameter = lerp(self.widths.width, self.widths.height, 0.5);
                 dot_dash_data.push([
                     self.widths.width / 2.0, self.widths.height / 2.0, 0.5 * dot_diameter, 0.,
                     0., 0., 0., 0.,
                 ]);
             }
             BorderCornerClipKind::Dot => {
-                let mut forward_dots = Vec::new();
-                let mut back_dots = Vec::new();
+                let mut forward_dots = Vec::with_capacity(max_clip_count / 2 + 1);
+                let mut back_dots = Vec::with_capacity(max_clip_count / 2 + 1);
                 let mut leftover_arc_length = 0.0;
 
                 // Alternate between adding dots at the start and end of the
                 // ellipse arc. This ensures that we always end up with an exact
                 // half dot at each end of the arc, to match up with the edges.
                 forward_dots.push(DotInfo::new(self.widths.width, self.widths.width));
                 back_dots.push(DotInfo::new(
                     self.ellipse.total_arc_length - self.widths.height,
@@ -496,16 +496,18 @@ impl BorderCornerClipSource {
                     let center = DevicePoint::new(
                         outer.x + clip_sign.x * (self.radius.width - center.x),
                         outer.y + clip_sign.y * (self.radius.height - center.y),
                     );
 
                     [center.x, center.y, radius, 0.0, 0.0, 0.0, 0.0, 0.0]
                 };
 
+                dot_dash_data.reserve(forward_dots.len() + back_dots.len());
+
                 for (i, dot) in forward_dots.iter().enumerate() {
                     let extra_dist = i as f32 * extra_space_per_dot;
                     let dot_data = create_dot_data(&self.ellipse, dot.arc_pos + extra_dist, 0.5 * dot.diameter);
                     dot_dash_data.push(dot_data);
                 }
 
                 for (i, dot) in back_dots.iter().enumerate() {
                     let extra_dist = i as f32 * extra_space_per_dot;
--- a/gfx/webrender/src/device/gl.rs
+++ b/gfx/webrender/src/device/gl.rs
@@ -2308,58 +2308,70 @@ impl<'a, T> Drop for TextureUploader<'a,
 
 impl<'a, T> TextureUploader<'a, T> {
     pub fn upload(
         &mut self,
         rect: DeviceUintRect,
         layer_index: i32,
         stride: Option<u32>,
         data: &[T],
-    ) {
+    ) -> usize {
+        let bytes_pp = self.target.texture.format.bytes_per_pixel();
+        let upload_size = match stride {
+            Some(stride) => ((rect.size.height - 1) * stride + rect.size.width * bytes_pp) as usize,
+            None => (rect.size.area() * bytes_pp) as usize,
+        };
+        assert!(upload_size <= data.len() * mem::size_of::<T>());
+
         match self.buffer {
             Some(ref mut buffer) => {
-                let upload_size = mem::size_of::<T>() * data.len();
+                let elem_count = upload_size / mem::size_of::<T>();
+                assert_eq!(elem_count * mem::size_of::<T>(), upload_size);
+                let slice = &data[.. elem_count];
+
                 if buffer.size_used + upload_size > buffer.size_allocated {
                     // flush
                     for chunk in buffer.chunks.drain() {
                         self.target.update_impl(chunk);
                     }
                     buffer.size_used = 0;
                 }
 
                 if upload_size > buffer.size_allocated {
                     gl::buffer_data(
                         self.target.gl,
                         gl::PIXEL_UNPACK_BUFFER,
-                        data,
+                        slice,
                         buffer.usage,
                     );
                     buffer.size_allocated = upload_size;
                 } else {
                     gl::buffer_sub_data(
                         self.target.gl,
                         gl::PIXEL_UNPACK_BUFFER,
                         buffer.size_used as _,
-                        data,
+                        slice,
                     );
                 }
 
                 buffer.chunks.push(UploadChunk {
                     rect, layer_index, stride,
                     offset: buffer.size_used,
                 });
                 buffer.size_used += upload_size;
             }
             None => {
                 self.target.update_impl(UploadChunk {
                     rect, layer_index, stride,
                     offset: data.as_ptr() as _,
                 });
             }
         }
+
+        upload_size
     }
 }
 
 impl<'a> UploadTarget<'a> {
     fn update_impl(&mut self, chunk: UploadChunk) {
         let (gl_format, bpp, data_type) = match self.texture.format {
             ImageFormat::R8 => (gl::RED, 1, gl::UNSIGNED_BYTE),
             ImageFormat::BGRA8 => (self.bgra_format, 4, gl::UNSIGNED_BYTE),
--- a/gfx/webrender/src/device/query_gl.rs
+++ b/gfx/webrender/src/device/query_gl.rs
@@ -278,17 +278,17 @@ impl<T: NamedTag> GpuProfiler<T> {
 #[must_use]
 pub struct GpuMarker {
     gl: Option<Rc<gl::Gl>>
 }
 
 impl GpuMarker {
     fn new(gl: &Rc<gl::Gl>, message: &str, ext_debug_marker: bool) -> Self {
         let gl = if ext_debug_marker {
-            gl.push_group_marker_ext(message);            
+            gl.push_group_marker_ext(message);
             Some(Rc::clone(gl))
         } else {
             None
         };
         GpuMarker { gl }
     }
 
     fn fire(gl: &Rc<gl::Gl>, message: &str, ext_debug_marker: bool) {
--- a/gfx/webrender/src/glyph_rasterizer/no_pathfinder.rs
+++ b/gfx/webrender/src/glyph_rasterizer/no_pathfinder.rs
@@ -10,17 +10,17 @@ use device::TextureFilter;
 use euclid::size2;
 use gpu_types::UvRectKind;
 use rayon::prelude::*;
 use std::sync::{Arc, MutexGuard};
 use platform::font::FontContext;
 use glyph_rasterizer::{FontInstance, FontContexts, GlyphKey};
 use glyph_rasterizer::{GlyphRasterizer, GlyphRasterJob, GlyphRasterJobs, GlyphRasterResult};
 use glyph_cache::{GlyphCache, CachedGlyphInfo, GlyphCacheEntry};
-use texture_cache::{TextureCache, TextureCacheHandle};
+use texture_cache::{TextureCache, TextureCacheHandle, Eviction};
 use gpu_cache::GpuCache;
 use render_task::{RenderTaskTree, RenderTaskCache};
 use tiling::SpecialRenderPasses;
 use profiler::TextureCacheProfileCounters;
 use std::collections::hash_map::Entry;
 
 impl FontContexts {
     /// Get access to the font context associated to the current thread.
@@ -183,16 +183,17 @@ impl GlyphRasterizer {
                             },
                             TextureFilter::Linear,
                             Some(ImageData::Raw(Arc::new(glyph.bytes))),
                             [glyph.left, -glyph.top, glyph.scale],
                             None,
                             gpu_cache,
                             Some(glyph_key_cache.eviction_notice()),
                             UvRectKind::Rect,
+                            Eviction::Auto,
                         );
                         GlyphCacheEntry::Cached(CachedGlyphInfo {
                             texture_cache_handle,
                             format: glyph.format,
                         })
                     }
                 };
                 glyph_key_cache.insert(key, glyph_info);
--- a/gfx/webrender/src/profiler.rs
+++ b/gfx/webrender/src/profiler.rs
@@ -32,17 +32,17 @@ cfg_if! {
 
 const ONE_SECOND_NS: u64 = 1000000000;
 
 #[derive(Debug, Clone)]
 pub struct GpuProfileTag {
     pub label: &'static str,
     pub color: ColorF,
 }
- 
+
 impl NamedTag for GpuProfileTag {
     fn get_label(&self) -> &str {
         self.label
     }
 }
 
 trait ProfileCounter {
     fn description(&self) -> &'static str;
@@ -452,16 +452,17 @@ impl BackendProfileCounters {
 pub struct RendererProfileCounters {
     pub frame_counter: IntProfileCounter,
     pub frame_time: AverageTimeProfileCounter,
     pub draw_calls: IntProfileCounter,
     pub vertices: IntProfileCounter,
     pub vao_count_and_size: ResourceProfileCounter,
     pub color_targets: IntProfileCounter,
     pub alpha_targets: IntProfileCounter,
+    pub texture_data_uploaded: IntProfileCounter,
 }
 
 pub struct RendererProfileTimers {
     pub cpu_time: TimeProfileCounter,
     pub gpu_time: TimeProfileCounter,
     pub gpu_samples: Vec<GpuTimer<GpuProfileTag>>,
 }
 
@@ -470,24 +471,26 @@ impl RendererProfileCounters {
         RendererProfileCounters {
             frame_counter: IntProfileCounter::new("Frame"),
             frame_time: AverageTimeProfileCounter::new("FPS", true, ONE_SECOND_NS / 2),
             draw_calls: IntProfileCounter::new("Draw Calls"),
             vertices: IntProfileCounter::new("Vertices"),
             vao_count_and_size: ResourceProfileCounter::new("VAO"),
             color_targets: IntProfileCounter::new("Color Targets"),
             alpha_targets: IntProfileCounter::new("Alpha Targets"),
+            texture_data_uploaded: IntProfileCounter::new("Texture data, kb"),
         }
     }
 
     pub fn reset(&mut self) {
         self.draw_calls.reset();
         self.vertices.reset();
         self.color_targets.reset();
         self.alpha_targets.reset();
+        self.texture_data_uploaded.reset();
     }
 }
 
 impl RendererProfileTimers {
     pub fn new() -> Self {
         RendererProfileTimers {
             cpu_time: TimeProfileCounter::new("Compositor CPU Time", false),
             gpu_samples: Vec::new(),
@@ -787,17 +790,16 @@ pub struct Profiler {
     compositor_time: ProfileGraph,
     gpu_time: ProfileGraph,
     gpu_frames: GpuFrameCollection,
     ipc_time: ProfileGraph,
 }
 
 #[cfg(feature = "debug_renderer")]
 impl Profiler {
-
     pub fn new() -> Self {
         Profiler {
             draw_state: DrawState {
                 x_left: 0.0,
                 y_left: 0.0,
                 x_right: 0.0,
                 y_right: 0.0,
             },
@@ -1016,16 +1018,17 @@ impl Profiler {
     ) {
         Profiler::draw_counters(
             &[
                 &renderer_profile.frame_time as &ProfileCounter,
                 &renderer_profile.color_targets,
                 &renderer_profile.alpha_targets,
                 &renderer_profile.draw_calls,
                 &renderer_profile.vertices,
+                &renderer_profile.texture_data_uploaded,
                 &self.backend_time,
                 &self.compositor_time,
                 &self.gpu_time,
             ],
             debug_renderer,
             true,
             &mut self.draw_state,
         );
@@ -1042,16 +1045,17 @@ impl Profiler {
         debug_renderer: &mut DebugRenderer,
     ) {
         Profiler::draw_counters(
             &[
                 &renderer_profile.frame_time as &ProfileCounter,
                 &renderer_profile.frame_counter,
                 &renderer_profile.color_targets,
                 &renderer_profile.alpha_targets,
+                &renderer_profile.texture_data_uploaded,
             ],
             debug_renderer,
             true,
             &mut self.draw_state
         );
 
         self.draw_gpu_cache_bars(
             &backend_profile.resources.gpu_cache,
--- a/gfx/webrender/src/render_task.rs
+++ b/gfx/webrender/src/render_task.rs
@@ -21,17 +21,17 @@ use internal_types::{FastHashMap, SavedT
 use pathfinder_partitioner::mesh::Mesh;
 use picture::PictureCacheKey;
 use prim_store::{PrimitiveIndex, ImageCacheKey};
 #[cfg(feature = "debugger")]
 use print_tree::{PrintTreePrinter};
 use render_backend::FrameId;
 use resource_cache::{CacheItem, ResourceCache};
 use std::{cmp, ops, usize, f32, i32};
-use texture_cache::{TextureCache, TextureCacheHandle};
+use texture_cache::{TextureCache, TextureCacheHandle, Eviction};
 use tiling::{RenderPass, RenderTargetIndex};
 use tiling::{RenderTargetKind};
 #[cfg(feature = "pathfinder")]
 use webrender_api::DevicePixel;
 
 const FLOATS_PER_RENDER_TASK_INFO: usize = 8;
 pub const MAX_BLUR_STD_DEVIATION: f32 = 4.0;
 pub const MIN_DOWNSCALING_RT_SIZE: i32 = 128;
@@ -1099,16 +1099,17 @@ impl RenderTaskCache {
                     descriptor,
                     TextureFilter::Linear,
                     None,
                     entry.user_data.unwrap_or([0.0; 3]),
                     None,
                     gpu_cache,
                     None,
                     render_task.uv_rect_kind(),
+                    Eviction::Auto,
                 );
 
                 // Get the allocation details in the texture cache, and store
                 // this in the render task. The renderer will draw this
                 // task into the appropriate layer and rect of the texture
                 // cache on this frame.
                 let (texture_id, texture_layer, uv_rect) =
                     texture_cache.get_cache_location(&entry.handle);
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -2580,51 +2580,54 @@ impl Renderer {
                     } => {
                         let texture = &self.texture_resolver.cache_texture_map[update.id.0];
                         let mut uploader = self.device.upload_texture(
                             texture,
                             &self.texture_cache_upload_pbo,
                             0,
                         );
 
-                        match source {
+                        let bytes_uploaded = match source {
                             TextureUpdateSource::Bytes { data } => {
                                 uploader.upload(
                                     rect, layer_index, stride,
                                     &data[offset as usize ..],
-                                );
+                                )
                             }
                             TextureUpdateSource::External { id, channel_index } => {
                                 let handler = self.external_image_handler
                                     .as_mut()
                                     .expect("Found external image, but no handler set!");
-                                match handler.lock(id, channel_index).source {
+                                let size = match handler.lock(id, channel_index).source {
                                     ExternalImageSource::RawData(data) => {
                                         uploader.upload(
                                             rect, layer_index, stride,
                                             &data[offset as usize ..],
-                                        );
+                                        )
                                     }
                                     ExternalImageSource::Invalid => {
                                         // Create a local buffer to fill the pbo.
                                         let bpp = texture.get_format().bytes_per_pixel();
                                         let width = stride.unwrap_or(rect.size.width * bpp);
                                         let total_size = width * rect.size.height;
                                         // WR haven't support RGBAF32 format in texture_cache, so
                                         // we use u8 type here.
                                         let dummy_data: Vec<u8> = vec![255; total_size as usize];
-                                        uploader.upload(rect, layer_index, stride, &dummy_data);
+                                        uploader.upload(rect, layer_index, stride, &dummy_data)
                                     }
                                     ExternalImageSource::NativeTexture(eid) => {
                                         panic!("Unexpected external texture {:?} for the texture cache update of {:?}", eid, id);
                                     }
                                 };
                                 handler.unlock(id, channel_index);
+                                size
                             }
-                        }
+                        };
+
+                        self.profile_counters.texture_data_uploaded.add(bytes_uploaded >> 10);
                     }
                     TextureUpdateOp::Free => {
                         let texture = &mut self.texture_resolver.cache_texture_map[update.id.0];
                         self.device.free_texture_storage(texture);
                     }
                 }
             }
         }
--- a/gfx/webrender/src/resource_cache.rs
+++ b/gfx/webrender/src/resource_cache.rs
@@ -35,17 +35,17 @@ use render_task::{RenderTaskCacheEntry, 
 use std::collections::hash_map::Entry::{self, Occupied, Vacant};
 use std::collections::hash_map::ValuesMut;
 use std::{cmp, mem};
 use std::fmt::Debug;
 use std::hash::Hash;
 #[cfg(any(feature = "capture", feature = "replay"))]
 use std::path::PathBuf;
 use std::sync::{Arc, RwLock};
-use texture_cache::{TextureCache, TextureCacheHandle};
+use texture_cache::{TextureCache, TextureCacheHandle, Eviction};
 use tiling::SpecialRenderPasses;
 
 const DEFAULT_TILE_SIZE: TileSize = 512;
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct GlyphFetchResult {
     pub index_in_text_run: i32,
@@ -212,16 +212,20 @@ where
         }
     }
 
     pub fn get(&self, key: &K) -> &V {
         self.resources.get(key)
             .expect("Didn't find a cached resource with that ID!")
     }
 
+    pub fn try_get(&self, key: &K) -> Option<&V> {
+        self.resources.get(key)
+    }
+
     pub fn insert(&mut self, key: K, value: V) {
         self.resources.insert(key, value);
     }
 
     pub fn remove(&mut self, key: &K) {
         self.resources.remove(key);
     }
 
@@ -767,16 +771,28 @@ impl ResourceCache {
             },
             viewport_tiles: image.viewport_tiles,
         };
     }
 
     pub fn delete_image_template(&mut self, image_key: ImageKey) {
         let value = self.resources.image_templates.remove(image_key);
 
+        match self.cached_images.try_get(&image_key) {
+            Some(&ImageResult::UntiledAuto(ref entry)) => {
+                self.texture_cache.mark_unused(&entry.texture_cache_handle);
+            }
+            Some(&ImageResult::Multi(ref entries)) => {
+                for (_, entry) in &entries.resources {
+                    self.texture_cache.mark_unused(&entry.texture_cache_handle);
+                }
+            }
+            _ => {}
+        }
+
         self.cached_images.remove(&image_key);
 
         match value {
             Some(image) => if image.data.is_blob() {
                 self.blob_image_handler.as_mut().unwrap().delete(image_key);
                 self.blob_image_templates.remove(&image_key);
                 self.rasterized_blob_images.remove(&image_key);
             },
@@ -1004,48 +1020,57 @@ impl ResourceCache {
                         size: compute_tile_size(
                             &template.descriptor,
                             tile_size,
                             tile,
                         ),
                         format: template.descriptor.format,
                     };
 
+                    // TODO: We only track dirty rects for non-tiled blobs but we
+                    // should also do it with tiled ones unless we settle for a small
+                    // tile size.
                     blob_request_params.push(
                         BlobImageParams {
                             request: BlobImageRequest {
                                 key: *key,
                                 tile: Some(tile),
                             },
                             descriptor,
                             dirty_rect: None,
                         }
                     );
                 });
             } else {
-                // TODO: to support partial rendering of non-tiled blobs we
-                // need to know that the current version of the blob is uploaded
-                // to the texture cache and get the guarantee that it will not
-                // get evicted by the time the updated blob is rasterized and
-                // uploaded.
-                // Alternatively we could make it the responsibility of the blob
-                // renderer to always output the full image. This could be based
-                // a similar copy-on-write mechanism as gecko tiling.
+                let needs_upload = match self.cached_images.try_get(&key) {
+                    Some(&ImageResult::UntiledAuto(ref entry)) => {
+                        self.texture_cache.needs_upload(&entry.texture_cache_handle)
+                    }
+                    _ => true,
+                };
+
+                let dirty_rect = if needs_upload {
+                    // The texture cache entry has been evicted, treat it as all dirty.
+                    None
+                } else {
+                    template.dirty_rect
+                };
+
                 blob_request_params.push(
                     BlobImageParams {
                         request: BlobImageRequest {
                             key: *key,
                             tile: None,
                         },
                         descriptor: BlobImageDescriptor {
                             offset: DevicePoint::zero(),
                             size: template.descriptor.size,
                             format: template.descriptor.format,
                         },
-                        dirty_rect: None,
+                        dirty_rect,
                     }
                 );
             }
             template.dirty_rect = None;
         }
         let handler = self.blob_image_handler.as_mut().unwrap();
         handler.prepare_resources(&self.resources, &blob_request_params);
         (Some(handler.create_blob_rasterizer()), blob_request_params)
@@ -1348,47 +1373,58 @@ impl ResourceCache {
         self.missing_blob_images.clear();
     }
 
     fn update_texture_cache(&mut self, gpu_cache: &mut GpuCache) {
         for request in self.pending_image_requests.drain() {
             let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
             debug_assert!(image_template.data.uses_texture_cache());
 
+            let mut blob_rasterized_rect = None;
             let image_data = match image_template.data {
                 ImageData::Raw(..) | ImageData::External(..) => {
                     // Safe to clone here since the Raw image data is an
                     // Arc, and the external image data is small.
                     image_template.data.clone()
                 }
                 ImageData::Blob(..) => {
                     let blob_image = self.rasterized_blob_images.get(&request.key).unwrap();
                     match blob_image.data.get(&request.tile) {
                         Some(result) => {
                             let result = result
                                 .as_ref()
                                 .expect("Failed to render a blob image");
 
                             // TODO: we may want to not panic and show a placeholder instead.
 
+                            blob_rasterized_rect = Some(result.rasterized_rect);
+
                             ImageData::Raw(Arc::clone(&result.data))
                         }
                         None => {
                             debug_assert!(false, "invalid blob image request during frame building");
                             continue;
                         }
                     }
                 }
             };
 
             let entry = match *self.cached_images.get_mut(&request.key) {
                 ImageResult::UntiledAuto(ref mut entry) => entry,
                 ImageResult::Multi(ref mut entries) => entries.get_mut(&request.into()),
                 ImageResult::Err(_) => panic!("Update requested for invalid entry")
             };
+
+            match (blob_rasterized_rect, entry.dirty_rect) {
+                (Some(rasterized), Some(dirty)) => {
+                    debug_assert!(request.tile.is_some() || rasterized.contains_rect(&dirty));
+                }
+                _ => {}
+            }
+
             let mut descriptor = image_template.descriptor.clone();
             let local_dirty_rect;
 
             if let Some(tile) = request.tile {
                 let tile_size = image_template.tiling.unwrap();
                 let clipped_tile_size = compute_tile_size(&descriptor, tile_size, tile);
 
                 local_dirty_rect = if let Some(rect) = entry.dirty_rect.take() {
@@ -1441,27 +1477,34 @@ impl ResourceCache {
                     ) {
                         TextureFilter::Trilinear
                     } else {
                         TextureFilter::Linear
                     }
                 }
             };
 
+            let eviction = if image_template.data.is_blob() {
+                Eviction::Manual
+            } else {
+                Eviction::Auto
+            };
+
             //Note: at this point, the dirty rectangle is local to the descriptor space
             self.texture_cache.update(
                 &mut entry.texture_cache_handle,
                 descriptor,
                 filter,
                 Some(image_data),
                 [0.0; 3],
                 local_dirty_rect,
                 gpu_cache,
                 None,
                 UvRectKind::Rect,
+                eviction,
             );
         }
     }
 
     pub fn end_frame(&mut self) {
         debug_assert_eq!(self.state, State::QueryResources);
         self.state = State::Idle;
     }
@@ -1477,16 +1520,19 @@ impl ResourceCache {
             self.cached_glyph_dimensions.clear();
         }
         if what.contains(ClearCache::RENDER_TASKS) {
             self.cached_render_tasks.clear();
         }
         if what.contains(ClearCache::TEXTURE_CACHE) {
             self.texture_cache.clear();
         }
+        if what.contains(ClearCache::RASTERIZED_BLOBS) {
+            self.rasterized_blob_images.clear();
+        }
     }
 
     pub fn clear_namespace(&mut self, namespace: IdNamespace) {
         self.resources
             .image_templates
             .images
             .retain(|key, _| key.0 != namespace);
         self.cached_images
@@ -1705,17 +1751,17 @@ impl ResourceCache {
                     ];
 
                     let blob_handler = self.blob_image_handler.as_mut().unwrap();
                     blob_handler.prepare_resources(&self.resources, blob_request_params);
                     let mut rasterizer = blob_handler.create_blob_rasterizer();
                     let (_, result) = rasterizer.rasterize(blob_request_params).pop().unwrap();
                     let result = result.expect("Blob rasterization failed");
 
-                    assert_eq!(result.size, desc.size);
+                    assert_eq!(result.rasterized_rect.size, desc.size);
                     assert_eq!(result.data.len(), desc.compute_total_size() as usize);
 
                     num_blobs += 1;
                     #[cfg(feature = "png")]
                     CaptureConfig::save_png(
                         root.join(format!("blobs/{}.png", num_blobs)),
                         (desc.size.width, desc.size.height),
                         ReadPixelsFormat::Standard(desc.format),
--- a/gfx/webrender/src/texture_cache.rs
+++ b/gfx/webrender/src/texture_cache.rs
@@ -88,35 +88,37 @@ pub enum CacheEntryMarker {}
 
 // Stores information related to a single entry in the texture
 // cache. This is stored for each item whether it's in the shared
 // cache or a standalone texture.
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 struct CacheEntry {
-    // Size the requested item, in device pixels.
+    /// Size the requested item, in device pixels.
     size: DeviceUintSize,
-    // Details specific to standalone or shared items.
+    /// Details specific to standalone or shared items.
     kind: EntryKind,
-    // Arbitrary user data associated with this item.
+    /// Arbitrary user data associated with this item.
     user_data: [f32; 3],
-    // The last frame this item was requested for rendering.
+    /// The last frame this item was requested for rendering.
     last_access: FrameId,
-    // Handle to the resource rect in the GPU cache.
+    /// Handle to the resource rect in the GPU cache.
     uv_rect_handle: GpuCacheHandle,
-    // Image format of the item.
+    /// Image format of the item.
     format: ImageFormat,
     filter: TextureFilter,
-    // The actual device texture ID this is part of.
+    /// The actual device texture ID this is part of.
     texture_id: CacheTextureId,
-    // Optional notice when the entry is evicted from the cache.
+    /// Optional notice when the entry is evicted from the cache.
     eviction_notice: Option<EvictionNotice>,
-    // The type of UV rect this entry specifies.
+    /// The type of UV rect this entry specifies.
     uv_rect_kind: UvRectKind,
+    /// If set to `Auto` the cache entry may be evicted if unused for a number of frames.
+    eviction: Eviction,
 }
 
 impl CacheEntry {
     // Create a new entry for a standalone texture.
     fn new_standalone(
         texture_id: CacheTextureId,
         size: DeviceUintSize,
         format: ImageFormat,
@@ -131,16 +133,17 @@ impl CacheEntry {
             last_access,
             kind: EntryKind::Standalone,
             texture_id,
             format,
             filter,
             uv_rect_handle: GpuCacheHandle::new(),
             eviction_notice: None,
             uv_rect_kind,
+            eviction: Eviction::Auto,
         }
     }
 
     // Update the GPU cache for this texture cache entry.
     // This ensures that the UV rect, and texture layer index
     // are up to date in the GPU cache for vertex shaders
     // to fetch from.
     fn update_gpu_cache(&mut self, gpu_cache: &mut GpuCache) {
@@ -187,16 +190,24 @@ pub struct TextureCacheHandle {
 }
 
 impl TextureCacheHandle {
     pub fn new() -> Self {
         TextureCacheHandle { entry: None }
     }
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub enum Eviction {
+    Auto,
+    Manual,
+}
+
 // An eviction notice is a shared condition useful for detecting
 // when a TextureCacheHandle gets evicted from the TextureCache.
 // It is optionally installed to the TextureCache when an update()
 // is scheduled. A single notice may be shared among any number of
 // TextureCacheHandle updates. The notice may then be subsequently
 // checked to see if any of the updates using it have been evicted.
 #[derive(Clone, Debug, Default)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
@@ -405,16 +416,17 @@ impl TextureCache {
         descriptor: ImageDescriptor,
         filter: TextureFilter,
         data: Option<ImageData>,
         user_data: [f32; 3],
         mut dirty_rect: Option<DeviceUintRect>,
         gpu_cache: &mut GpuCache,
         eviction_notice: Option<&EvictionNotice>,
         uv_rect_kind: UvRectKind,
+        eviction: Eviction,
     ) {
         // Determine if we need to allocate texture cache memory
         // for this item. We need to reallocate if any of the following
         // is true:
         // - Never been in the cache
         // - Has been in the cache but was evicted.
         // - Exists in the cache but dimensions / format have changed.
         let realloc = match handle.entry {
@@ -458,16 +470,18 @@ impl TextureCache {
         // Invalidate the contents of the resource rect in the GPU cache.
         // This ensures that the update_gpu_cache below will add
         // the new information to the GPU cache.
         gpu_cache.invalidate(&entry.uv_rect_handle);
 
         // Upload the resource rect and texture array layer.
         entry.update_gpu_cache(gpu_cache);
 
+        entry.eviction = eviction;
+
         // Create an update command, which the render thread processes
         // to upload the new image data into the correct location
         // in GPU memory.
         if let Some(data) = data {
             let (layer_index, origin) = match entry.kind {
                 EntryKind::Standalone { .. } => (0, DeviceUintPoint::zero()),
                 EntryKind::Cache {
                     layer_index,
@@ -576,26 +590,37 @@ impl TextureCache {
                 ..
             } => (layer_index, origin),
         };
         (SourceTexture::TextureCache(entry.texture_id),
          layer_index as i32,
          DeviceUintRect::new(origin, entry.size))
     }
 
+    pub fn mark_unused(&mut self, handle: &TextureCacheHandle) {
+        if let Some(ref handle) = handle.entry {
+            if let Some(entry) = self.entries.get_opt_mut(handle) {
+                // Set a very low last accessed frame to make it very likely that this entry
+                // will get cleaned up next time we try to expire entries.
+                entry.last_access = FrameId(0);
+                entry.eviction = Eviction::Auto;
+            }
+        }
+    }
+
     // Expire old standalone textures.
     fn expire_old_standalone_entries(&mut self) {
         let mut eviction_candidates = Vec::new();
         let mut retained_entries = Vec::new();
 
         // Build a list of eviction candidates (which are
         // anything not used this frame).
         for handle in self.standalone_entry_handles.drain(..) {
             let entry = self.entries.get(&handle);
-            if entry.last_access == self.frame_id {
+            if entry.eviction == Eviction::Manual || entry.last_access == self.frame_id {
                 retained_entries.push(handle);
             } else {
                 eviction_candidates.push(handle);
             }
         }
 
         // Sort by access time so we remove the oldest ones first.
         eviction_candidates.sort_by_key(|handle| {
@@ -1200,16 +1225,17 @@ impl TextureArray {
                 last_access: frame_id,
                 kind,
                 uv_rect_handle: GpuCacheHandle::new(),
                 format: self.format,
                 filter: self.filter,
                 texture_id: self.texture_id.unwrap(),
                 eviction_notice: None,
                 uv_rect_kind,
+                eviction: Eviction::Auto,
             }
         })
     }
 }
 
 impl TextureUpdate {
     // Constructs a TextureUpdate operation to be passed to the
     // rendering thread in order to do an upload to the right
--- a/gfx/webrender/src/util.rs
+++ b/gfx/webrender/src/util.rs
@@ -1,20 +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 api::{BorderRadius, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale};
 use api::{DevicePoint, DeviceRect, DeviceSize, LayoutPixel, LayoutPoint, LayoutRect, LayoutSize};
-use api::{WorldPixel, WorldPoint, WorldRect};
+use api::{WorldPixel, WorldRect};
 use euclid::{Point2D, Rect, Size2D, TypedPoint2D, TypedRect, TypedSize2D};
-use euclid::{TypedTransform2D, TypedTransform3D, TypedVector2D, TypedVector3D};
+use euclid::{TypedTransform2D, TypedTransform3D, TypedVector2D};
 use euclid::{HomogeneousVector};
 use num_traits::Zero;
-use plane_split::{Clipper, Plane, Polygon};
+use plane_split::{Clipper, Polygon};
 use std::{i32, f32};
 use std::borrow::Cow;
 
 
 // Matches the definition of SK_ScalarNearlyZero in Skia.
 const NEARLY_ZERO: f32 = 1.0 / 4096.0;
 
 // TODO: Implement these in euclid!
@@ -170,170 +170,82 @@ pub fn lerp(a: f32, b: f32, t: f32) -> f
 }
 
 pub fn calculate_screen_bounding_rect(
     transform: &LayoutToWorldFastTransform,
     rect: &LayoutRect,
     device_pixel_scale: DevicePixelScale,
     screen_bounds: Option<&DeviceIntRect>,
 ) -> Option<DeviceIntRect> {
-    debug!("rect {:?}", rect);
-    debug!("transform {:?}", transform);
-    debug!("screen_bounds: {:?}", screen_bounds);
+    debug!("calculate_screen_bounding_rect for {:?}", rect);
     let homogens = [
         transform.transform_point2d_homogeneous(&rect.origin),
         transform.transform_point2d_homogeneous(&rect.top_right()),
         transform.transform_point2d_homogeneous(&rect.bottom_left()),
         transform.transform_point2d_homogeneous(&rect.bottom_right()),
     ];
-    debug!("homogeneous points {:?}", homogens);
     let max_rect = match screen_bounds {
         Some(bounds) => bounds.to_f32(),
         None => DeviceRect::max_rect(),
     };
 
     // Note: we only do the full frustum collision when the polygon approaches the camera plane.
     // Otherwise, it will be clamped to the screen bounds anyway.
     let world_rect = if homogens.iter().any(|h| h.w <= 0.0) {
-        let mut clipper = Clipper::new();
-        // using inverse-transpose of the inversed transform
-        let t = transform.to_transform();
-        // camera plane
-        {
-            let normal = TypedVector3D::new(t.m14, t.m24, t.m34);
-            let kf = 1.0 / normal.length();
-            clipper.add(Plane {
-                normal: normal * kf,
-                offset: t.m44 * kf,
-            });
-        }
-
-        // The equations for clip planes come from the following one:
-        // (v * M).x < right
-        // (v, Mx) < right
-        // (v, Mx) - right = 0;
+        debug!("transform {:?}", transform);
+        debug!("screen_bounds: {:?}", screen_bounds);
+        debug!("homogeneous points {:?}", homogens);
 
-        // left/right planes
-        if let Some(bounds) = screen_bounds {
-            let normal = TypedVector3D::new(t.m11, t.m21, t.m31);
-            let kf = 1.0 / normal.length();
-            clipper.add(Plane {
-                normal: normal * kf,
-                offset: t.m41 * kf - (bounds.origin.x) as f32 / device_pixel_scale.0,
-            });
-            clipper.add(Plane {
-                normal: normal * -kf,
-                offset: t.m41 * -kf + (bounds.origin.x + bounds.size.width) as f32 / device_pixel_scale.0,
-            });
-        }
-        // top/bottom planes
-        if let Some(bounds) = screen_bounds {
-            let normal = TypedVector3D::new(t.m12, t.m22, t.m32);
-            let kf = 1.0 / normal.length();
-            clipper.add(Plane {
-                normal: normal * kf,
-                offset: t.m42 * kf - (bounds.origin.y) as f32 / device_pixel_scale.0,
-            });
-            clipper.add(Plane {
-                normal: normal * -kf,
-                offset: t.m42 * -kf + (bounds.origin.y + bounds.size.height) as f32 / device_pixel_scale.0,
-            });
-        }
+        let mut clipper = Clipper::new();
+        clipper.add_frustum(
+            &transform.to_transform(),
+            screen_bounds.map(|b| b.to_f32() / device_pixel_scale),
+        );
 
-        let polygon = Polygon::from_points(
-            [
-                rect.origin.to_3d(),
-                rect.top_right().to_3d(),
-                rect.bottom_left().to_3d(),
-                rect.bottom_right().to_3d(),
-            ],
-            1,
-        );
+        let polygon = Polygon::from_rect(*rect, 1);
         debug!("crossing detected for poly {:?}", polygon);
         let results = clipper.clip(polygon);
         debug!("clip results: {:?}", results);
         if results.is_empty() {
             return None
         }
 
         debug!("points:");
         WorldRect::from_points(results
             .into_iter()
             // filter out parts behind the view plane
             .flat_map(|poly| &poly.points)
             .map(|p| {
-                debug!("\tpoint {:?} -> {:?} -> {:?}", p,
-                    transform.transform_point2d_homogeneous(&p.to_2d()),
-                    transform.transform_point2d(&p.to_2d())
-                );
-                //TODO: change to `expect` when the near splitting code is ready
-                transform
-                    .transform_point2d(&p.to_2d())
-                    .unwrap_or(WorldPoint::zero())
+                let mut homo = transform.transform_point2d_homogeneous(&p.to_2d());
+                homo.w = homo.w.max(0.00000001); // avoid infinite values
+                debug!("\tpoint {:?} -> {:?} -> {:?}", p, homo, homo.to_point2d());
+                homo.to_point2d().unwrap()
             })
         )
     } else {
         // we just checked for all the points to be in positive hemisphere, so `unwrap` is valid
         WorldRect::from_points(&[
             homogens[0].to_point2d().unwrap(),
             homogens[1].to_point2d().unwrap(),
             homogens[2].to_point2d().unwrap(),
             homogens[3].to_point2d().unwrap(),
         ])
     };
 
-    debug!("world rect {:?}", world_rect);
-    (world_rect * device_pixel_scale)
-        .round_out()
-        .intersection(&max_rect)
-        .map(|r| r.to_i32())
+    let result = (world_rect * device_pixel_scale)
+         .round_out()
+         .intersection(&max_rect)
+         .map(|r| r.to_i32());
+    if homogens.iter().any(|h| h.w <= 0.0) {
+        debug!("world rect {:?}", world_rect);
+        debug!("result {:?}", result);
+    }
+    result
 }
 
-pub fn _subtract_rect<U>(
-    rect: &TypedRect<f32, U>,
-    other: &TypedRect<f32, U>,
-    results: &mut Vec<TypedRect<f32, U>>,
-) {
-    results.clear();
-
-    let int = rect.intersection(other);
-    match int {
-        Some(int) => {
-            let rx0 = rect.origin.x;
-            let ry0 = rect.origin.y;
-            let rx1 = rx0 + rect.size.width;
-            let ry1 = ry0 + rect.size.height;
-
-            let ox0 = int.origin.x;
-            let oy0 = int.origin.y;
-            let ox1 = ox0 + int.size.width;
-            let oy1 = oy0 + int.size.height;
-
-            let r = TypedRect::from_untyped(&rect_from_points_f(rx0, ry0, ox0, ry1));
-            if r.size.width > 0.0 && r.size.height > 0.0 {
-                results.push(r);
-            }
-            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, ry0, ox1, oy0));
-            if r.size.width > 0.0 && r.size.height > 0.0 {
-                results.push(r);
-            }
-            let r = TypedRect::from_untyped(&rect_from_points_f(ox0, oy1, ox1, ry1));
-            if r.size.width > 0.0 && r.size.height > 0.0 {
-                results.push(r);
-            }
-            let r = TypedRect::from_untyped(&rect_from_points_f(ox1, ry0, rx1, ry1));
-            if r.size.width > 0.0 && r.size.height > 0.0 {
-                results.push(r);
-            }
-        }
-        None => {
-            results.push(*rect);
-        }
-    }
-}
 
 #[repr(u32)]
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub enum TransformedRectKind {
     AxisAligned = 0,
     Complex = 1,
--- a/gfx/webrender_api/src/api.rs
+++ b/gfx/webrender_api/src/api.rs
@@ -530,21 +530,22 @@ bitflags!{
         const FRAME = 0x2;
     }
 }
 
 bitflags!{
     /// Mask for clearing caches in debug commands.
     #[derive(Deserialize, Serialize)]
     pub struct ClearCache: u8 {
-        const IMAGES = 0x1;
-        const GLYPHS = 0x2;
-        const GLYPH_DIMENSIONS = 0x4;
-        const RENDER_TASKS = 0x8;
-        const TEXTURE_CACHE = 0x16;
+        const IMAGES = 0b1;
+        const GLYPHS = 0b01;
+        const GLYPH_DIMENSIONS = 0b001;
+        const RENDER_TASKS = 0b0001;
+        const TEXTURE_CACHE = 0b00001;
+        const RASTERIZED_BLOBS = 0b000001;
     }
 }
 
 /// Information about a loaded capture of each document
 /// that is returned by `RenderBackend`.
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct CapturedDocument {
     pub document_id: DocumentId,
--- a/gfx/webrender_api/src/image.rs
+++ b/gfx/webrender_api/src/image.rs
@@ -240,17 +240,17 @@ pub type BlobImageResult = Result<Raster
 #[derive(Copy, Clone, Debug)]
 pub struct BlobImageDescriptor {
     pub size: DeviceUintSize,
     pub offset: DevicePoint,
     pub format: ImageFormat,
 }
 
 pub struct RasterizedBlobImage {
-    pub size: DeviceUintSize,
+    pub rasterized_rect: DeviceUintRect,
     pub data: Arc<Vec<u8>>,
 }
 
 #[derive(Clone, Debug)]
 pub enum BlobImageError {
     Oom,
     InvalidKey,
     InvalidData,
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-7a1b919e37d6cd0155077aa90f98cfcdf9fa5bae
+c939a61b83bcc9dc10742977704793e9a85b3858
--- a/gfx/webrender_bindings/src/moz2d_renderer.rs
+++ b/gfx/webrender_bindings/src/moz2d_renderer.rs
@@ -378,17 +378,22 @@ impl AsyncBlobImageRasterizer for Moz2dB
                         descriptor.size.height,
                         descriptor.format,
                         option_to_nullable(&item.tile_size),
                         option_to_nullable(&item.request.tile),
                         option_to_nullable(&item.dirty_rect),
                         MutByteSlice::new(output.as_mut_slice()),
                     ) {
                         Ok(RasterizedBlobImage {
-                            size: descriptor.size,
+                            rasterized_rect: item.dirty_rect.unwrap_or(
+                                DeviceUintRect {
+                                    origin: DeviceUintPoint::origin(),
+                                    size: descriptor.size,
+                                }
+                            ),
                             data: Arc::new(output),
                         })
                     } else {
                         panic!("Moz2D replay problem");
                     }
                 };
 
                 (item.request, result)
--- a/gfx/wrench/src/blob.rs
+++ b/gfx/wrench/src/blob.rs
@@ -98,17 +98,17 @@ fn render_blob(
                     ));
                 }
             }
         }
     }
 
     Ok(RasterizedBlobImage {
         data: Arc::new(texels),
-        size: descriptor.size,
+        rasterized_rect: dirty_rect,
     })
 }
 
 /// See rawtest.rs. We use this to test that blob images are requested the right
 /// amount of times.
 pub struct BlobCallbacks {
     pub request: Box<Fn(&[BlobImageParams]) + Send + 'static>,
 }
--- a/js/src/doc/Debugger/Debugger.md
+++ b/js/src/doc/Debugger/Debugger.md
@@ -241,16 +241,22 @@ compartment.
     API observe activity in only those globals that are reachable by the
     API's user, thus imposing capability-based restrictions on a
     `Debugger`'s reach. However, the `onNewGlobalObject` method allows the
     API user to monitor all global object creation that occurs anywhere
     within the JavaScript system (the "JSRuntime", in SpiderMonkey terms),
     thereby escaping the capability-based limits. For this reason,
     `onNewGlobalObject` is only available to privileged code.
 
+    Note that, even though the presence of a `Debugger`'s `onNewGlobalObject`
+    hook can have arbitrary side effects, the garbage collector does not
+    consider the presence of the hook sufficient reason to keep the `Debugger`
+    alive. Thus, the behavior of code that uses `onNewGlobalObject` on unrooted,
+    enabled `Debugger`s may be affected by the garbage collector's activity, and
+    is not entirely deterministic.
 
 
 ## Function Properties of the Debugger Prototype Object
 
 The functions described below may only be called with a `this` value
 referring to a `Debugger` instance; they may not be used as methods of
 other kinds of objects.
 
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -832,16 +832,19 @@ Debugger::getHook(Hook hook) const
 }
 
 bool
 Debugger::hasAnyLiveHooks(JSRuntime* rt) const
 {
     if (!enabled)
         return false;
 
+    // A onNewGlobalObject hook does not hold its Debugger live, so its behavior
+    // is nondeterministic. This behavior is not satisfying, but it is at least
+    // documented.
     if (getHook(OnDebuggerStatement) ||
         getHook(OnExceptionUnwind) ||
         getHook(OnNewScript) ||
         getHook(OnEnterFrame))
     {
         return true;
     }
 
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -5877,20 +5877,17 @@ class BaseCompiler final : public BaseCo
     MOZ_MUST_USE RegI32 maybeLoadTlsForAccess(const AccessCheck& check);
     MOZ_MUST_USE RegI32 maybeLoadTlsForAccess(const AccessCheck& check, RegI32 specific);
     MOZ_MUST_USE bool emitLoad(ValType type, Scalar::Type viewType);
     MOZ_MUST_USE bool loadCommon(MemoryAccessDesc* access, ValType type);
     MOZ_MUST_USE bool emitStore(ValType resultType, Scalar::Type viewType);
     MOZ_MUST_USE bool storeCommon(MemoryAccessDesc* access, ValType resultType);
     MOZ_MUST_USE bool emitSelect();
 
-    // Mark these templates as inline to work around a compiler crash in
-    // gcc 4.8.5 when compiling for linux64-opt.
-
-    template<bool isSetLocal> MOZ_MUST_USE inline bool emitSetOrTeeLocal(uint32_t slot);
+    template<bool isSetLocal> MOZ_MUST_USE bool emitSetOrTeeLocal(uint32_t slot);
 
     void endBlock(ExprType type);
     void endLoop(ExprType type);
     void endIfThen();
     void endIfThenElse(ExprType type);
 
     void doReturn(ExprType returnType, bool popStack);
     void pushReturnedIfNonVoid(const FunctionCall& call, ExprType type);
--- a/js/xpconnect/tests/mochitest/test_bug628410.html
+++ b/js/xpconnect/tests/mochitest/test_bug628410.html
@@ -14,17 +14,27 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">
   
 </div>
 
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 628410 **/
-window.toSource();
+{
+  // window.toSource() will throw if SpecialPowers is defined on the window and
+  // permissive COWs are not enabled for the global that owns its frame message
+  // manager.
+  let sp = window.SpecialPowers;
+  window.SpecialPowers = null;
+
+  window.toSource();
+  window.SpecialPowers = sp;
+}
+
 window.toString();
 InstallTrigger + "";
 console + "";
 ok(true, "Things didn't throw");
 
 </script>
 </pre>
 </body>
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -6242,19 +6242,19 @@ nsCSSFrameConstructor::AppendFramesToPar
     FindFirstBlock(firstBlockEnumerator);
 
     nsFrameList inlineKids = aFrameList.ExtractHead(firstBlockEnumerator);
     if (!inlineKids.IsEmpty()) {
       AppendFrames(aParentFrame, kPrincipalList, inlineKids);
     }
 
     if (!aFrameList.IsEmpty()) {
-      bool positioned = aParentFrame->IsRelativelyPositioned();
       nsFrameItems ibSiblings;
-      CreateIBSiblings(aState, aParentFrame, positioned, aFrameList,
+      CreateIBSiblings(aState, aParentFrame,
+                       aParentFrame->IsAbsPosContainingBlock(), aFrameList,
                        ibSiblings);
 
       // Make sure to trigger reflow of the inline that used to be our
       // last one and now isn't anymore, since its GetSkipSides() has
       // changed.
       mPresShell->FrameNeedsReflow(aParentFrame,
                                    nsIPresShell::eTreeChange,
                                    NS_FRAME_HAS_DIRTY_CHILDREN);
@@ -11113,32 +11113,28 @@ nsCSSFrameConstructor::ConstructInline(n
   //   Block (div)
   //     Text("e")
   // Inline (outer span)
   //   Text("f")
 
   nsIContent* const content = aItem.mContent;
   ComputedStyle* const computedStyle = aItem.mComputedStyle;
 
-  bool positioned =
-    StyleDisplay::Inline == aDisplay->mDisplay &&
-    aDisplay->IsRelativelyPositionedStyle() &&
-    !nsSVGUtils::IsInSVGTextSubtree(aParentFrame);
-
   nsInlineFrame* newFrame = NS_NewInlineFrame(mPresShell, computedStyle);
 
   // Initialize the frame
   InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
 
   nsFrameConstructorSaveState absoluteSaveState;  // definition cannot be inside next block
                                                   // because the object's destructor is significant
                                                   // this is part of the fix for bug 42372
 
+  bool isAbsPosCB = newFrame->IsAbsPosContainingBlock();
   newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
-  if (positioned) {
+  if (isAbsPosCB) {
     // Relatively positioned frames becomes a container for child
     // frames that are positioned
     aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
   }
 
   // Process the child content
   nsFrameItems childItems;
   ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
@@ -11167,28 +11163,30 @@ nsCSSFrameConstructor::ConstructInline(n
 
   // Grab the first inline's kids
   nsFrameList firstInlineKids = childItems.ExtractHead(firstBlockEnumerator);
   newFrame->SetInitialChildList(kPrincipalList, firstInlineKids);
 
   aFrameItems.AddChild(newFrame);
 
   newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
-  CreateIBSiblings(aState, newFrame, positioned, childItems, aFrameItems);
+  CreateIBSiblings(aState, newFrame, isAbsPosCB, childItems, aFrameItems);
 
   return newFrame;
 }
 
 void
 nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState,
                                         nsContainerFrame* aInitialInline,
-                                        bool aIsPositioned,
+                                        bool aIsAbsPosCB,
                                         nsFrameItems& aChildItems,
                                         nsFrameItems& aSiblings)
 {
+  MOZ_ASSERT(aIsAbsPosCB == aInitialInline->IsAbsPosContainingBlock());
+
   nsIContent* content = aInitialInline->GetContent();
   ComputedStyle* computedStyle = aInitialInline->Style();
   nsContainerFrame* parentFrame = aInitialInline->GetParent();
 
   // Resolve the right style for our anonymous blocks.
   //
   // The distinction in styles is needed because of CSS 2.1, section
   // 9.2.1.1, which says:
@@ -11226,17 +11224,17 @@ nsCSSFrameConstructor::CreateIBSiblings(
     SetFrameIsIBSplit(lastNewInline, blockFrame);
     aSiblings.AddChild(blockFrame);
 
     // Now grab the initial inlines in aChildItems and put them into an inline
     // frame.
     nsInlineFrame* inlineFrame = NS_NewInlineFrame(mPresShell, computedStyle);
     InitAndRestoreFrame(aState, content, parentFrame, inlineFrame, false);
     inlineFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
-    if (aIsPositioned) {
+    if (aIsAbsPosCB) {
       inlineFrame->MarkAsAbsoluteContainingBlock();
     }
 
     if (aChildItems.NotEmpty()) {
       nsFrameList::FrameLinkEnumerator firstBlock(aChildItems);
       FindFirstBlock(firstBlock);
       nsFrameList inlineKids = aChildItems.ExtractHead(firstBlock);
 
--- a/layout/generic/nsBulletFrame.h
+++ b/layout/generic/nsBulletFrame.h
@@ -79,17 +79,17 @@ public:
   virtual nscoord GetPrefISize(gfxContext *aRenderingContext) override;
   void AddInlineMinISize(gfxContext* aRenderingContext,
                          nsIFrame::InlineMinISizeData* aData) override;
   void AddInlinePrefISize(gfxContext* aRenderingContext,
                           nsIFrame::InlinePrefISizeData* aData) override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    if (aFlags & eSupportsCSSTransforms) {
+    if (aFlags & (eSupportsCSSTransforms | eSupportsContainLayoutAndPaint)) {
       return false;
     }
     return nsFrame::IsFrameOfType(aFlags);
   }
 
   // nsBulletFrame
   int32_t SetListItemOrdinal(int32_t aNextOrdinal, bool* aChanged,
                              int32_t aIncrement);
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -2857,37 +2857,44 @@ public:
     eExcludesIgnorableWhitespace =      1 << 14,
     eSupportsCSSTransforms =            1 << 15,
 
     // A replaced element that has replaced-element sizing
     // characteristics (i.e., like images or iframes), as opposed to
     // inline-block sizing characteristics (like form controls).
     eReplacedSizing =                   1 << 16,
 
+    // Does this frame class support 'contain: layout' and
+    // 'contain:paint' (supporting one is equivalent to supporting the
+    // other).
+    eSupportsContainLayoutAndPaint =    1 << 17,
+
     // These are to allow nsFrame::Init to assert that IsFrameOfType
     // implementations all call the base class method.  They are only
     // meaningful in DEBUG builds.
     eDEBUGAllFrames =                   1 << 30,
     eDEBUGNoFrames =                    1 << 31
   };
 
   /**
    * API for doing a quick check if a frame is of a given
    * type. Returns true if the frame matches ALL flags passed in.
    *
    * Implementations should always override with inline virtual
    * functions that call the base class's IsFrameOfType method.
    */
   virtual bool IsFrameOfType(uint32_t aFlags) const
   {
+    return !(aFlags & ~(
 #ifdef DEBUG
-    return !(aFlags & ~(nsIFrame::eDEBUGAllFrames | nsIFrame::eSupportsCSSTransforms));
-#else
-    return !(aFlags & ~nsIFrame::eSupportsCSSTransforms);
+                        nsIFrame::eDEBUGAllFrames |
 #endif
+                        nsIFrame::eSupportsCSSTransforms |
+                        nsIFrame::eSupportsContainLayoutAndPaint
+                        ));
   }
 
   /**
    * Returns true if the frame is a block wrapper.
    */
   bool IsBlockWrapper() const;
 
   /**
--- a/layout/generic/nsInlineFrame.h
+++ b/layout/generic/nsInlineFrame.h
@@ -38,17 +38,17 @@ public:
 #endif
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    if (aFlags & eSupportsCSSTransforms) {
+    if (aFlags & (eSupportsCSSTransforms | eSupportsContainLayoutAndPaint)) {
       return false;
     }
     return nsContainerFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eBidiInlineContainer | nsIFrame::eLineParticipant));
   }
 
   virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0, bool aRebuildDisplayItems = true) override;
   virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0, bool aRebuildDisplayItems = true) override;
--- a/layout/generic/nsRubyBaseContainerFrame.cpp
+++ b/layout/generic/nsRubyBaseContainerFrame.cpp
@@ -245,17 +245,17 @@ nsRubyBaseContainerFrame::AddInlinePrefI
     }
   }
   aData->mCurrentLine += sum;
 }
 
 /* virtual */ bool
 nsRubyBaseContainerFrame::IsFrameOfType(uint32_t aFlags) const
 {
-  if (aFlags & eSupportsCSSTransforms) {
+  if (aFlags & (eSupportsCSSTransforms | eSupportsContainLayoutAndPaint)) {
     return false;
   }
   return nsContainerFrame::IsFrameOfType(aFlags &
          ~(nsIFrame::eLineParticipant));
 }
 
 /* virtual */ bool
 nsRubyBaseContainerFrame::CanContinueTextRun() const
--- a/layout/generic/nsRubyTextContainerFrame.cpp
+++ b/layout/generic/nsRubyTextContainerFrame.cpp
@@ -46,17 +46,17 @@ nsRubyTextContainerFrame::GetFrameName(n
 {
   return MakeFrameName(NS_LITERAL_STRING("RubyTextContainer"), aResult);
 }
 #endif
 
 /* virtual */ bool
 nsRubyTextContainerFrame::IsFrameOfType(uint32_t aFlags) const
 {
-  if (aFlags & eSupportsCSSTransforms) {
+  if (aFlags & (eSupportsCSSTransforms | eSupportsContainLayoutAndPaint)) {
     return false;
   }
   return nsContainerFrame::IsFrameOfType(aFlags);
 }
 
 /* virtual */ void
 nsRubyTextContainerFrame::SetInitialChildList(ChildListID aListID,
                                               nsFrameList& aChildList)
--- a/layout/mathml/nsMathMLContainerFrame.h
+++ b/layout/mathml/nsMathMLContainerFrame.h
@@ -63,19 +63,21 @@ public:
     return NS_OK;
   }
 
   // --------------------------------------------------------------------------
   // Overloaded nsContainerFrame methods -- see documentation in nsIFrame.h
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return !(aFlags & nsIFrame::eLineParticipant) &&
-      nsContainerFrame::IsFrameOfType(aFlags &
-              ~(nsIFrame::eMathML | nsIFrame::eExcludesIgnorableWhitespace));
+    if (aFlags & (eLineParticipant | eSupportsContainLayoutAndPaint)) {
+      return false;
+    }
+    return nsContainerFrame::IsFrameOfType(aFlags &
+      ~(eMathML | eExcludesIgnorableWhitespace));
   }
 
   virtual void
   AppendFrames(ChildListID     aListID,
                nsFrameList&    aFrameList) override;
 
   virtual void
   InsertFrames(ChildListID     aListID,
--- a/layout/reftests/transform-3d/reftest.list
+++ b/layout/reftests/transform-3d/reftest.list
@@ -57,17 +57,17 @@ fuzzy-if(winWidget&&!layersGPUAccelerate
 # Different, but equivalent (for the given transform) transform origins
 fuzzy-if(webrender,0-1,0-4) == rotatex-transformorigin-1a.html rotatex-transformorigin-1-ref.html
 fuzzy-if((gtkWidget&&layersOMTC)||(winWidget&&!layersGPUAccelerated),1,86) == overflow-hidden-1a.html overflow-hidden-1-ref.html
 fails-if(webrender) == transform-style-flat-1a.html transform-style-flat-1-ref.html
 == willchange-containing-block.html?willchange willchange-containing-block.html?ref
 != willchange-containing-block.html?willchange willchange-containing-block.html?noblock
 fuzzy-if(winWidget&&!layersGPUAccelerated,1,606) == scroll-perspective-1.html scroll-perspective-1-ref.html
 # Bugs
-fails-if(!layersGPUAccelerated) fails-if(webrender) == 1035611-1.html 1035611-1-ref.html # Bug 1072898 for !layersGPUAccelerated failures
+fails-if(!layersGPUAccelerated) == 1035611-1.html 1035611-1-ref.html # Bug 1072898 for !layersGPUAccelerated failures
 fails-if(webrender) != 1157984-1.html about:blank # Bug 1157984
 fuzzy(3,99) == animate-cube-radians.html animate-cube-radians-ref.html # subpixel AA
 fuzzy(3,99) fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated,16,6) == animate-cube-radians-zoom.html animate-cube-radians-zoom-ref.html
 != animate-cube-radians-ref.html animate-cube-radians-zoom-ref.html
 fuzzy(3,99) == animate-cube-degrees.html animate-cube-degrees-ref.html # subpixel AA
 == animate-cube-degrees-zoom.html animate-cube-degrees-zoom-ref.html
 != animate-cube-degrees-ref.html animate-cube-degrees-zoom-ref.html
 fuzzy-if(gtkWidget,128,100) fuzzy-if(Android||OSX==1010||(gtkWidget&&layersGPUAccelerated),143,100) fuzzy-if(winWidget||OSX<1010,141,100) == preserves3d-nested.html preserves3d-nested-ref.html
--- a/layout/style/ComputedStyle.cpp
+++ b/layout/style/ComputedStyle.cpp
@@ -234,24 +234,46 @@ ComputedStyle::CalcStyleDifference(Compu
 
     // This depends on data in nsStyleDisplay and nsStyleEffects, so we do it
     // here
 
     // Note that it's perhaps good for this test to be last because it
     // doesn't use Peek* functions to get the structs on the old
     // context.  But this isn't a big concern because these struct
     // getters should be called during frame construction anyway.
-    if (ThreadsafeStyleDisplay()->IsAbsPosContainingBlockForAppropriateFrame(*this) ==
-        aNewContext->ThreadsafeStyleDisplay()->
-          IsAbsPosContainingBlockForAppropriateFrame(*aNewContext) &&
-        ThreadsafeStyleDisplay()->IsFixedPosContainingBlockForAppropriateFrame(*this) ==
-        aNewContext->ThreadsafeStyleDisplay()->
-          IsFixedPosContainingBlockForAppropriateFrame(*aNewContext)) {
+    const nsStyleDisplay* oldDisp = ThreadsafeStyleDisplay();
+    const nsStyleDisplay* newDisp = aNewContext->ThreadsafeStyleDisplay();
+    bool isFixedCB;
+    if (oldDisp->IsAbsPosContainingBlockForNonSVGTextFrames() ==
+        newDisp->IsAbsPosContainingBlockForNonSVGTextFrames() &&
+        (isFixedCB =
+           oldDisp->IsFixedPosContainingBlockForNonSVGTextFrames(*this)) ==
+        newDisp->IsFixedPosContainingBlockForNonSVGTextFrames(*aNewContext) &&
+        // transform-supporting frames are a subcategory of non-SVG-text
+        // frames, so no need to test this if isFixedCB is true (both
+        // before and after the change)
+        (isFixedCB ||
+         oldDisp->IsFixedPosContainingBlockForTransformSupportingFrames() ==
+         newDisp->IsFixedPosContainingBlockForTransformSupportingFrames()) &&
+        // contain-layout-and-paint-supporting frames are a subset of
+        // non-SVG-text frames, so no need to test this if isFixedCB is true
+        // (both before and after the change).
+        //
+        // Note, however, that neither of these last two sets is a
+        // subset of the other, because table frames support contain:
+        // layout/paint but not transforms (which are instead inherited
+        // to the table wrapper), and quite a few frame types support
+        // transforms but not contain: layout/paint (e.g., table rows
+        // and row groups, many SVG frames).
+        (isFixedCB ||
+         oldDisp->IsFixedPosContainingBlockForContainLayoutAndPaintSupportingFrames() ==
+         newDisp->IsFixedPosContainingBlockForContainLayoutAndPaintSupportingFrames())) {
       // While some styles that cause the frame to be a containing block
-      // has changed, the overall result hasn't.
+      // has changed, the overall result cannot have changed (no matter
+      // what the frame type is).
       hint &= ~nsChangeHint_UpdateContainingBlock;
     }
   }
 
   MOZ_ASSERT(NS_IsHintSubset(hint, nsChangeHint_AllHints),
              "Added a new hint without bumping AllHints?");
   return hint & ~nsChangeHint_NeutralChange;
 }
--- a/layout/style/nsCSSPseudoElements.h
+++ b/layout/style/nsCSSPseudoElements.h
@@ -197,26 +197,16 @@ public:
 
     return false;
   }
 
   static nsString PseudoTypeAsString(Type aPseudoType);
 
 private:
   // Does the given pseudo-element have all of the flags given?
-
-  // Work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64037 ,
-  // which is a general gcc bug that we seem to have hit only on Android/x86.
-#if defined(ANDROID) && defined(__i386__) && defined(__GNUC__) && \
-    !defined(__clang__)
-#if (MOZ_GCC_VERSION_AT_LEAST(4,8,0) && MOZ_GCC_VERSION_AT_MOST(4,8,4)) || \
-    (MOZ_GCC_VERSION_AT_LEAST(4,9,0) && MOZ_GCC_VERSION_AT_MOST(4,9,2))
-   __attribute__((noinline))
-#endif
-#endif
   static bool PseudoElementHasFlags(const Type aType, uint32_t aFlags)
   {
     MOZ_ASSERT(aType < Type::Count);
     return (kPseudoElementFlags[size_t(aType)] & aFlags) == aFlags;
   }
 
   static bool PseudoElementHasAnyFlag(const Type aType, uint32_t aFlags)
   {
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2395,77 +2395,87 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   inline mozilla::StyleDisplay GetDisplay(const nsIFrame* aContextFrame) const;
   inline bool IsFloating(const nsIFrame* aContextFrame) const;
   inline bool IsRelativelyPositioned(const nsIFrame* aContextFrame) const;
   inline bool IsAbsolutelyPositioned(const nsIFrame* aContextFrame) const;
 
   // These methods are defined in nsStyleStructInlines.h.
 
   /**
-   * Returns whether the element is a containing block for its
-   * absolutely positioned descendants.
-   * aContextFrame is the frame for which this is the nsStyleDisplay.
-   */
-  inline bool IsAbsPosContainingBlock(const nsIFrame* aContextFrame) const;
-
-  /**
-   * The same as IsAbsPosContainingBlock, except skipping the tests that
-   * are based on the frame rather than the ComputedStyle (thus
-   * potentially returning a false positive).
-   */
-  inline bool IsAbsPosContainingBlockForAppropriateFrame(
-    mozilla::ComputedStyle&) const;
-
-  /**
    * Returns true when the element has the transform property
    * or a related property, and supports CSS transforms.
    * aContextFrame is the frame for which this is the nsStyleDisplay.
    */
   inline bool HasTransform(const nsIFrame* aContextFrame) const;
 
   /**
    * Returns true when the element has the perspective property,
    * and supports CSS transforms. aContextFrame is the frame for
    * which this is the nsStyleDisplay.
    */
   inline bool HasPerspective(const nsIFrame* aContextFrame) const;
 
   /**
+   * Returns whether the element is a containing block for its
+   * absolutely positioned descendants.
+   * aContextFrame is the frame for which this is the nsStyleDisplay.
+   */
+  inline bool IsAbsPosContainingBlock(const nsIFrame* aContextFrame) const;
+
+  /**
+   * Tests for only the sub-parts of IsAbsPosContainingBlock that apply
+   * to nearly all frames, except those that are SVG text frames.
+   *
+   * This should be used only when the caller has the style but not the
+   * frame (i.e., when calculating style changes).
+   *
+   * NOTE: This (unlike IsAbsPosContainingBlock) does not include
+   * IsFixPosContainingBlockForNonSVGTextFrames.
+   */
+  inline bool IsAbsPosContainingBlockForNonSVGTextFrames() const;
+
+  /**
    * Returns true when the element is a containing block for its fixed-pos
    * descendants.
    * aContextFrame is the frame for which this is the nsStyleDisplay.
    */
   inline bool IsFixedPosContainingBlock(const nsIFrame* aContextFrame) const;
 
   /**
-   * The same as IsFixedPosContainingBlock, except skipping the tests that
-   * are based on the frame rather than the ComputedStyle (thus
-   * potentially returning a false positive).
+   * Tests for only the sub-parts of IsFixedPosContainingBlock that apply
+   * to:
+   *  - nearly all frames, except those that are SVG text frames.
+   *  - frames that support CSS contain:layout and contain:paint and are not
+   *    SVG text frames.
+   *  - frames that support CSS transforms and are not SVG text frames.
+   *
+   * This should be used only when the caller has the style but not the
+   * frame (i.e., when calculating style changes).
    */
-  inline bool IsFixedPosContainingBlockForAppropriateFrame(
+  inline bool IsFixedPosContainingBlockForNonSVGTextFrames(
     mozilla::ComputedStyle&) const;
+  inline bool
+    IsFixedPosContainingBlockForContainLayoutAndPaintSupportingFrames() const;
+  inline bool IsFixedPosContainingBlockForTransformSupportingFrames() const;
 
   /**
    * Returns the final combined transform.
    **/
   already_AddRefed<nsCSSValueSharedList> GetCombinedTransform() const {
     if (mCombinedTransform) {
       return do_AddRef(mCombinedTransform);
     }
 
     // backward compatible to gecko-backed style system.
     return mSpecifiedTransform ? do_AddRef(mSpecifiedTransform) : nullptr;
   }
 
 private:
   // Helpers for above functions, which do some but not all of the tests
   // for them (since transform must be tested separately for each).
-  inline bool HasAbsPosContainingBlockStyleInternal() const;
-  inline bool HasFixedPosContainingBlockStyleInternal(
-    mozilla::ComputedStyle&) const;
   void GenerateCombinedTransform();
 };
 
 struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTable
 {
   explicit nsStyleTable(const nsPresContext* aContext);
   nsStyleTable(const nsStyleTable& aOther);
   ~nsStyleTable();
--- a/layout/style/nsStyleStructInlines.h
+++ b/layout/style/nsStyleStructInlines.h
@@ -149,88 +149,88 @@ nsStyleDisplay::HasTransform(const nsIFr
 bool
 nsStyleDisplay::HasPerspective(const nsIFrame* aContextFrame) const
 {
   MOZ_ASSERT(aContextFrame->StyleDisplay() == this, "unexpected aContextFrame");
   return HasPerspectiveStyle() && aContextFrame->IsFrameOfType(nsIFrame::eSupportsCSSTransforms);
 }
 
 bool
-nsStyleDisplay::HasFixedPosContainingBlockStyleInternal(
+nsStyleDisplay::IsFixedPosContainingBlockForNonSVGTextFrames(
   mozilla::ComputedStyle& aStyle) const
 {
   // NOTE: Any CSS properties that influence the output of this function
   // should have the FIXPOS_CB flag set on them.
   NS_ASSERTION(aStyle.ThreadsafeStyleDisplay() == this, "unexpected aStyle");
 
-  if (IsContainPaint()) {
-    return true;
-  }
-
   if (mWillChangeBitField & NS_STYLE_WILL_CHANGE_FIXPOS_CB) {
     return true;
   }
 
   return aStyle.ThreadsafeStyleEffects()->HasFilters();
 }
 
 bool
-nsStyleDisplay::IsFixedPosContainingBlockForAppropriateFrame(
-  mozilla::ComputedStyle& aStyle) const
+nsStyleDisplay::IsFixedPosContainingBlockForContainLayoutAndPaintSupportingFrames() const
+{
+  // FIXME (bug 1472919): 'contain: layout' should also establish a
+  // containing block for fixed and absolute positioned elements.
+  return IsContainPaint();
+}
+
+bool
+nsStyleDisplay::IsFixedPosContainingBlockForTransformSupportingFrames() const
 {
   // NOTE: Any CSS properties that influence the output of this function
   // should have the FIXPOS_CB flag set on them.
-  return HasFixedPosContainingBlockStyleInternal(aStyle) ||
-         HasTransformStyle() || HasPerspectiveStyle();
+  return HasTransformStyle() || HasPerspectiveStyle();
 }
 
 bool
 nsStyleDisplay::IsFixedPosContainingBlock(const nsIFrame* aContextFrame) const
 {
+  mozilla::ComputedStyle* style = aContextFrame->Style();
+  NS_ASSERTION(style->ThreadsafeStyleDisplay() == this,
+               "unexpected aContextFrame");
   // NOTE: Any CSS properties that influence the output of this function
   // should have the FIXPOS_CB flag set on them.
-  if (!HasFixedPosContainingBlockStyleInternal(*aContextFrame->Style()) &&
-      !HasTransform(aContextFrame) && !HasPerspective(aContextFrame)) {
+  if (!IsFixedPosContainingBlockForNonSVGTextFrames(*style) &&
+      (!IsFixedPosContainingBlockForContainLayoutAndPaintSupportingFrames() ||
+       !aContextFrame->IsFrameOfType(nsIFrame::eSupportsContainLayoutAndPaint)) &&
+      (!IsFixedPosContainingBlockForTransformSupportingFrames() ||
+       !aContextFrame->IsFrameOfType(nsIFrame::eSupportsCSSTransforms))) {
     return false;
   }
   return !nsSVGUtils::IsInSVGTextSubtree(aContextFrame);
 }
 
 bool
-nsStyleDisplay::HasAbsPosContainingBlockStyleInternal() const
+nsStyleDisplay::IsAbsPosContainingBlockForNonSVGTextFrames() const
 {
   // NOTE: Any CSS properties that influence the output of this function
   // should have the ABSPOS_CB set on them.
   return IsAbsolutelyPositionedStyle() ||
          IsRelativelyPositionedStyle() ||
          (mWillChangeBitField & NS_STYLE_WILL_CHANGE_ABSPOS_CB);
 }
 
 bool
-nsStyleDisplay::IsAbsPosContainingBlockForAppropriateFrame(
-  mozilla::ComputedStyle& aStyle) const
-{
-  NS_ASSERTION(aStyle.ThreadsafeStyleDisplay() == this, "unexpected aStyle");
-  // NOTE: Any CSS properties that influence the output of this function
-  // should have the ABSPOS_CB set on them.
-  return HasAbsPosContainingBlockStyleInternal() ||
-         IsFixedPosContainingBlockForAppropriateFrame(aStyle);
-}
-
-bool
 nsStyleDisplay::IsAbsPosContainingBlock(const nsIFrame* aContextFrame) const
 {
-  NS_ASSERTION(aContextFrame->Style()->ThreadsafeStyleDisplay() == this,
+  mozilla::ComputedStyle *style = aContextFrame->Style();
+  NS_ASSERTION(style->ThreadsafeStyleDisplay() == this,
                "unexpected aContextFrame");
   // NOTE: Any CSS properties that influence the output of this function
   // should have the ABSPOS_CB set on them.
-  if (!HasAbsPosContainingBlockStyleInternal() &&
-      !HasFixedPosContainingBlockStyleInternal(*aContextFrame->Style()) &&
-      !HasTransform(aContextFrame) &&
-      !HasPerspective(aContextFrame)) {
+  if (!IsAbsPosContainingBlockForNonSVGTextFrames() &&
+      !IsFixedPosContainingBlockForNonSVGTextFrames(*style) &&
+      (!IsFixedPosContainingBlockForContainLayoutAndPaintSupportingFrames() ||
+       !aContextFrame->IsFrameOfType(nsIFrame::eSupportsContainLayoutAndPaint)) &&
+      (!IsFixedPosContainingBlockForTransformSupportingFrames() ||
+       !aContextFrame->IsFrameOfType(nsIFrame::eSupportsCSSTransforms))) {
     return false;
   }
   return !nsSVGUtils::IsInSVGTextSubtree(aContextFrame);
 }
 
 bool
 nsStyleDisplay::IsRelativelyPositioned(const nsIFrame* aContextFrame) const
 {
--- a/layout/svg/SVGFEContainerFrame.cpp
+++ b/layout/svg/SVGFEContainerFrame.cpp
@@ -29,16 +29,20 @@ protected:
     AddStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY);
   }
 
 public:
   NS_DECL_FRAMEARENA_HELPERS(SVGFEContainerFrame)
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
+    if (aFlags & eSupportsContainLayoutAndPaint) {
+      return false;
+    }
+
     return nsContainerFrame::IsFrameOfType(
             aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGContainer));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGFEContainer"), aResult);
--- a/layout/svg/SVGFEImageFrame.cpp
+++ b/layout/svg/SVGFEImageFrame.cpp
@@ -40,16 +40,20 @@ public:
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
   virtual void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
+    if (aFlags & eSupportsContainLayoutAndPaint) {
+      return false;
+    }
+
     return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGFEImage"), aResult);
   }
--- a/layout/svg/SVGFELeafFrame.cpp
+++ b/layout/svg/SVGFELeafFrame.cpp
@@ -32,16 +32,20 @@ public:
 #ifdef DEBUG
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 #endif
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
+    if (aFlags & eSupportsContainLayoutAndPaint) {
+      return false;
+    }
+
     return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGFELeaf"), aResult);
   }
--- a/layout/svg/SVGFEUnstyledLeafFrame.cpp
+++ b/layout/svg/SVGFEUnstyledLeafFrame.cpp
@@ -25,16 +25,20 @@ protected:
 public:
   NS_DECL_FRAMEARENA_HELPERS(SVGFEUnstyledLeafFrame)
 
   virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
                                 const nsDisplayListSet& aLists) override {}
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
+    if (aFlags & eSupportsContainLayoutAndPaint) {
+      return false;
+    }
+
     return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGFEUnstyledLeaf"), aResult);
   }
--- a/layout/svg/SVGGeometryFrame.h
+++ b/layout/svg/SVGGeometryFrame.h
@@ -65,16 +65,20 @@ public:
 
   // nsIFrame interface:
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
+    if (aFlags & eSupportsContainLayoutAndPaint) {
+      return false;
+    }
+
     return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGGeometry));
   }
 
   virtual nsresult  AttributeChanged(int32_t         aNameSpaceID,
                                      nsAtom*        aAttribute,
                                      int32_t         aModType) override;
 
   virtual void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override;
--- a/layout/svg/SVGViewFrame.cpp
+++ b/layout/svg/SVGViewFrame.cpp
@@ -36,16 +36,20 @@ public:
 #ifdef DEBUG
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 #endif
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
+    if (aFlags & eSupportsContainLayoutAndPaint) {
+      return false;
+    }
+
     return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGView"), aResult);
   }
--- a/layout/svg/nsSVGContainerFrame.h
+++ b/layout/svg/nsSVGContainerFrame.h
@@ -72,16 +72,20 @@ public:
   virtual void InsertFrames(ChildListID     aListID,
                             nsIFrame*       aPrevFrame,
                             nsFrameList&    aFrameList) override;
   virtual void RemoveFrame(ChildListID     aListID,
                            nsIFrame*       aOldFrame) override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
+    if (aFlags & eSupportsContainLayoutAndPaint) {
+      return false;
+    }
+
     return nsContainerFrame::IsFrameOfType(
             aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGContainer));
   }
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsDisplayListSet& aLists) override {}
 
   virtual bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) override;
--- a/layout/svg/nsSVGForeignObjectFrame.h
+++ b/layout/svg/nsSVGForeignObjectFrame.h
@@ -47,16 +47,20 @@ public:
                       const ReflowInput& aReflowInput,
                       nsReflowStatus&          aStatus) override;
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsDisplayListSet& aLists) override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
+    if (aFlags & eSupportsContainLayoutAndPaint) {
+      return false;
+    }
+
     return nsContainerFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eSVG | nsIFrame::eSVGForeignObject));
   }
 
   virtual bool IsSVGTransformed(Matrix *aOwnTransform,
                                 Matrix *aFromParentTransform) const override;
 
 #ifdef DEBUG_FRAME_DUMP
--- a/layout/svg/nsSVGOuterSVGFrame.h
+++ b/layout/svg/nsSVGOuterSVGFrame.h
@@ -69,16 +69,22 @@ public:
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsDisplayListSet& aLists) override;
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
 
+  bool IsFrameOfType(uint32_t aFlags) const override
+  {
+    return nsSVGDisplayContainerFrame::IsFrameOfType(
+      aFlags & ~eSupportsContainLayoutAndPaint);
+  }
+
   virtual nsSplittableType GetSplittableType() const override;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGOuterSVG"), aResult);
   }
 #endif
--- a/layout/svg/nsSVGStopFrame.cpp
+++ b/layout/svg/nsSVGStopFrame.cpp
@@ -40,16 +40,20 @@ public:
                         const nsDisplayListSet& aLists) override {}
 
   virtual nsresult AttributeChanged(int32_t         aNameSpaceID,
                                     nsAtom*        aAttribute,
                                     int32_t         aModType) override;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
+    if (aFlags & eSupportsContainLayoutAndPaint) {
+      return false;
+    }
+
     return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGStop"), aResult);
   }
--- a/layout/tables/nsTableColFrame.h
+++ b/layout/tables/nsTableColFrame.h
@@ -269,16 +269,20 @@ public:
     mFinalISize = aFinalISize;
   }
   nscoord GetFinalISize() {
     return mFinalISize;
   }
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
+    if (aFlags & eSupportsContainLayoutAndPaint) {
+      return false;
+    }
+
     return nsSplittableFrame::IsFrameOfType(aFlags & ~(nsIFrame::eTablePart));
   }
 
   virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0, bool aRebuildDisplayItems = true) override;
   virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0, bool aRebuildDisplayItems = true) override;
   virtual void InvalidateFrameForRemoval() override { InvalidateFrameSubtree(); }
 
 protected:
--- a/layout/tables/nsTableColGroupFrame.h
+++ b/layout/tables/nsTableColGroupFrame.h
@@ -190,16 +190,20 @@ public:
    * Set full border widths before collapsing with cell borders
    * @param aForSide - side to set; only accepts bstart and bend
    */
   void SetContinuousBCBorderWidth(mozilla::LogicalSide aForSide,
                                   BCPixelSize aPixelValue);
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
+    if (aFlags & eSupportsContainLayoutAndPaint) {
+      return false;
+    }
+
     return nsContainerFrame::IsFrameOfType(aFlags & ~(nsIFrame::eTablePart));
   }
 
   virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0, bool aRebuildDisplayItems = true) override;
   virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0, bool aRebuildDisplayItems = true) override;
   virtual void InvalidateFrameForRemoval() override { InvalidateFrameSubtree(); }
 
 protected:
--- a/layout/tables/nsTableRowFrame.h
+++ b/layout/tables/nsTableRowFrame.h
@@ -234,16 +234,20 @@ publ