Merge autoland to mozilla-central. a=merge
authorNoemi Erli <nerli@mozilla.com>
Fri, 23 Mar 2018 00:51:42 +0200
changeset 409599 6c82708c26ee0e21142c78d9c031723f32fce3fd
parent 409598 8bf380faae74e4921be6000496ca09d4a2c44e8d (current diff)
parent 409596 e4304fffb4f0b9808dd8a29df7a1f6a0e692e79b (diff)
child 409600 e02bfb1c5596b8e82409c4f4ac74076d5b43ba1d
push id101247
push usernerli@mozilla.com
push dateThu, 22 Mar 2018 23:00:51 +0000
treeherdermozilla-inbound@02e384bdf97d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge autoland to mozilla-central. a=merge
gfx/webrender/res/cs_text_run.glsl
layout/style/ServoStyleContext.cpp
layout/style/ServoStyleContext.h
layout/style/ServoStyleContextInlines.h
layout/style/nsStyleContext.cpp
layout/style/nsStyleContext.h
layout/style/nsStyleContextInlines.h
testing/web-platform/meta/css/css-backgrounds/background-size/vector/wide--cover--nonpercent-width-nonpercent-height-viewbox.html.ini
testing/web-platform/meta/css/css-backgrounds/background-size/vector/wide--cover--nonpercent-width-nonpercent-height.html.ini
testing/web-platform/meta/webrtc/RTCDataChannelEvent-constructor.html.ini
third_party/rust/bincode/.travis.yml
third_party/rust/bincode/changelist.org
third_party/rust/bincode/examples/basic.rs
third_party/rust/bincode/logo.png
third_party/rust/bincode/readme.dev.md
third_party/rust/bincode/tests/test.rs
third_party/rust/num-traits-0.1.41/.cargo-checksum.json
third_party/rust/num-traits-0.1.41/Cargo.toml
third_party/rust/num-traits-0.1.41/LICENSE-APACHE
third_party/rust/num-traits-0.1.41/LICENSE-MIT
third_party/rust/num-traits-0.1.41/src/bounds.rs
third_party/rust/num-traits-0.1.41/src/cast.rs
third_party/rust/num-traits-0.1.41/src/float.rs
third_party/rust/num-traits-0.1.41/src/identities.rs
third_party/rust/num-traits-0.1.41/src/int.rs
third_party/rust/num-traits-0.1.41/src/lib.rs
third_party/rust/num-traits-0.1.41/src/ops/checked.rs
third_party/rust/num-traits-0.1.41/src/ops/mod.rs
third_party/rust/num-traits-0.1.41/src/ops/saturating.rs
third_party/rust/num-traits-0.1.41/src/ops/wrapping.rs
third_party/rust/num-traits-0.1.41/src/pow.rs
third_party/rust/num-traits-0.1.41/src/sign.rs
toolkit/components/places/tests/bookmarks/test_395593.js
toolkit/components/places/tests/unit/test_multi_queries.js
toolkit/components/resistfingerprinting/nsRFPService.cpp
toolkit/content/widgets/splitter.xml
toolkit/themes/osx/global/splitter/grip-bottom.gif
toolkit/themes/osx/global/splitter/grip-left.gif
toolkit/themes/osx/global/splitter/grip-right.gif
toolkit/themes/osx/global/splitter/grip-top.gif
toolkit/themes/windows/global/splitter/grip-bottom.gif
toolkit/themes/windows/global/splitter/grip-left.gif
toolkit/themes/windows/global/splitter/grip-right.gif
toolkit/themes/windows/global/splitter/grip-top.gif
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -16,17 +16,17 @@ name = "ansi_term"
 version = "0.10.2"
 source = "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.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "arrayvec"
 version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -45,19 +45,19 @@ source = "registry+https://github.com/ru
 dependencies = [
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "audioipc"
-version = "0.2.1"
+version = "0.2.2"
 dependencies = [
- "bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "cubeb 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -68,32 +68,32 @@ dependencies = [
  "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "audioipc-client"
 version = "0.3.0"
 dependencies = [
- "audioipc 0.2.1",
+ "audioipc 0.2.2",
  "cubeb-backend 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "audioipc-server"
 version = "0.2.2"
 dependencies = [
- "audioipc 0.2.1",
+ "audioipc 0.2.2",
  "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "cubeb 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -112,17 +112,17 @@ dependencies = [
 
 [[package]]
 name = "binary-space-partition"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "bincode"
-version = "0.9.1"
+version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "bindgen"
@@ -557,17 +557,17 @@ name = "error-chain"
 version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "euclid"
 version = "0.17.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "fallible"
 version = "0.0.1"
 dependencies = [
  "hashglobe 0.1.0",
@@ -844,17 +844,17 @@ dependencies = [
  "bindgen 0.33.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "mozjs_sys 0.0.0",
- "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "kernel32-sys"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1193,40 +1193,43 @@ dependencies = [
 
 [[package]]
 name = "num"
 version = "0.1.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "num-integer"
 version = "0.1.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "num-iter"
 version = "0.1.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "num-traits"
-version = "0.1.41"
+version = "0.1.43"
 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)",
+]
 
 [[package]]
 name = "num-traits"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "num_cpus"
@@ -1236,17 +1239,17 @@ dependencies = [
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "ordered-float"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "owning_ref"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -1326,17 +1329,17 @@ source = "registry+https://github.com/ru
 [[package]]
 name = "plane-split"
 version = "0.8.0"
 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.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "podio"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -1640,17 +1643,17 @@ dependencies = [
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of 0.0.1",
  "malloc_size_of_derive 0.0.1",
  "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "nsstring 0.1.0",
  "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.1.41 (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)",
  "ordered-float 0.4.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.5.4 (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)",
  "selectors 0.19.0",
@@ -2011,46 +2014,46 @@ dependencies = [
  "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender"
 version = "0.57.0"
 dependencies = [
  "app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bincode 1.0.0 (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)",
  "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 9.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.3.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.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "plane-split 0.8.0 (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.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.6.0 (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.38 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender_api 0.57.0",
 ]
 
 [[package]]
 name = "webrender_api"
 version = "0.57.0"
 dependencies = [
  "app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bincode 1.0.0 (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)",
  "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.27 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)",
@@ -2181,17 +2184,17 @@ dependencies = [
 "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
 "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455"
 "checksum app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29069a9b483f7780aebb55dafb360c6225eefdc1f98c8d336a65148fd10c37b1"
 "checksum arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0ef4a9820019a0c91d918918c93dc71d469f581a49b47ddc1d285d4270bbe2"
 "checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21"
 "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"
-"checksum bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3fb369af639822830328794eba2501b3479652fcd021b2aeb1ed4984202afd"
+"checksum bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bda13183df33055cbb84b847becce220d392df502ebe7a4a78d7021771ed94d0"
 "checksum bindgen 0.33.2 (registry+https://github.com/rust-lang/crates.io-index)" = "603ed8d8392ace9581e834e26bd09799bf1e989a79bd1aedbb893e72962bdc6e"
 "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
 "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
 "checksum bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80b13e2ab064ff3aa0bdbf1eff533f9822dc37899821f5f98c67f263eab51707"
 "checksum boxfnonce 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8380105befe91099e6f69206164072c05bc92427ff6aa8a5171388317346dd75"
 "checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9"
 "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
 "checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6"
@@ -2284,17 +2287,17 @@ dependencies = [
 "checksum mp4parse_fallible 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6626c2aef76eb8f984eef02e475883d3fe9112e114720446c5810fc5f045cd30"
 "checksum msdos_time 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "65ba9d75bcea84e07812618fedf284a64776c2f2ea0cad6bca7f69739695a958"
 "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"
 "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
 "checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
 "checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525"
 "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba"
 "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01"
-"checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070"
+"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
 "checksum num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7de20f146db9d920c45ee8ed8f71681fd9ade71909b48c3acbd766aa504cf10"
 "checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
 "checksum ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8"
 "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
 "checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd"
 "checksum parking_lot_core 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6c677d78851950b3aec390e681a411f78cc250cba277d4f578758a377f727970"
 "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"
--- a/accessible/base/StyleInfo.cpp
+++ b/accessible/base/StyleInfo.cpp
@@ -12,45 +12,45 @@
 #include "nsIFrame.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 StyleInfo::StyleInfo(dom::Element* aElement) :
   mElement(aElement)
 {
-  mStyleContext =
-    nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr);
+  mComputedStyle =
+    nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr);
 }
 
 void
 StyleInfo::Display(nsAString& aValue)
 {
   aValue.Truncate();
   AppendASCIItoUTF16(
-    nsCSSProps::ValueToKeyword(mStyleContext->StyleDisplay()->mDisplay,
+    nsCSSProps::ValueToKeyword(mComputedStyle->StyleDisplay()->mDisplay,
                                nsCSSProps::kDisplayKTable), aValue);
 }
 
 void
 StyleInfo::TextAlign(nsAString& aValue)
 {
   aValue.Truncate();
   AppendASCIItoUTF16(
-    nsCSSProps::ValueToKeyword(mStyleContext->StyleText()->mTextAlign,
+    nsCSSProps::ValueToKeyword(mComputedStyle->StyleText()->mTextAlign,
                                nsCSSProps::kTextAlignKTable), aValue);
 }
 
 void
 StyleInfo::TextIndent(nsAString& aValue)
 {
   aValue.Truncate();
 
   const nsStyleCoord& styleCoord =
-    mStyleContext->StyleText()->mTextIndent;
+    mComputedStyle->StyleText()->mTextIndent;
 
   nscoord coordVal = 0;
   switch (styleCoord.GetUnit()) {
     case eStyleUnit_Coord:
       coordVal = styleCoord.GetCoordValue();
       aValue.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(coordVal));
       aValue.AppendLiteral("px");
       break;
--- a/accessible/base/StyleInfo.h
+++ b/accessible/base/StyleInfo.h
@@ -3,17 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _mozilla_a11y_style_h_
 #define _mozilla_a11y_style_h_
 
 #include "mozilla/gfx/Types.h"
-#include "nsStyleContext.h"
+#include "mozilla/ComputedStyle.h"
 
 namespace mozilla {
 namespace a11y {
 
 class StyleInfo
 {
 public:
   explicit StyleInfo(dom::Element* aElement);
@@ -34,15 +34,15 @@ public:
 private:
   StyleInfo() = delete;
   StyleInfo(const StyleInfo&) = delete;
   StyleInfo& operator = (const StyleInfo&) = delete;
 
   void Margin(Side aSide, nsAString& aValue);
 
   dom::Element* mElement;
-  RefPtr<nsStyleContext> mStyleContext;
+  RefPtr<ComputedStyle> mComputedStyle;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/ipc/win/HandlerProvider.cpp
+++ b/accessible/ipc/win/HandlerProvider.cpp
@@ -214,22 +214,16 @@ HandlerProvider::BuildStaticIA2Data(
     // IA2 should always be present, so something has
     // gone very wrong if this fails.
     aOutData->mIA2 = nullptr;
     return;
   }
 
   // Some of these interfaces aren't present on all accessibles,
   // so it's not a failure if these interfaces can't be fetched.
-  hr = aInterceptor->GetInterceptorForIID(IID_IEnumVARIANT,
-                                          (void**)&aOutData->mIEnumVARIANT);
-  if (FAILED(hr)) {
-    aOutData->mIEnumVARIANT = nullptr;
-  }
-
   hr = aInterceptor->GetInterceptorForIID(IID_IAccessibleHypertext2,
                                           (void**)&aOutData->mIAHypertext);
   if (FAILED(hr)) {
     aOutData->mIAHypertext = nullptr;
   }
 
   hr = aInterceptor->GetInterceptorForIID(IID_IAccessibleHyperlink,
                                           (void**)&aOutData->mIAHyperlink);
@@ -756,11 +750,159 @@ HandlerProvider::get_RelationsInfo(IARel
                                  &HandlerProvider::GetRelationsInfoMainThread,
                                  aRelations, aNRelations, &hr)) {
     return E_FAIL;
   }
 
   return hr;
 }
 
+// Helper function for GetAllChildrenMainThread.
+static bool
+SetChildDataForTextLeaf(NEWEST_IA2_INTERFACE* acc, AccChildData& data)
+{
+  const VARIANT kChildIdSelf = {VT_I4};
+  VARIANT varVal;
+
+  // 1. Check whether this is a text leaf.
+
+  // 1.1. A text leaf always has ROLE_SYSTEM_TEXT or ROLE_SYSTEM_WHITESPACE.
+  HRESULT hr = acc->get_accRole(kChildIdSelf, &varVal);
+  if (FAILED(hr)) {
+    return false;
+  }
+  if (varVal.vt != VT_I4) {
+    return false;
+  }
+  long role = varVal.lVal;
+  if (role != ROLE_SYSTEM_TEXT && role != ROLE_SYSTEM_WHITESPACE) {
+    return false;
+  }
+
+  // 1.2. A text leaf doesn't support IAccessibleText.
+  RefPtr<IAccessibleText> iaText;
+  hr = acc->QueryInterface(IID_IAccessibleText, getter_AddRefs(iaText));
+  if (SUCCEEDED(hr)) {
+    return false;
+  }
+
+  // 1.3. A text leaf doesn't have children.
+  long count;
+  hr = acc->get_accChildCount(&count);
+  if (FAILED(hr) || count != 0) {
+    return false;
+  }
+
+  // 2. Update |data| with the data for this text leaf.
+  // Because marshaling objects is more expensive than marshaling other data,
+  // we just marshal the data we need for text leaf children, rather than
+  // marshaling the full accessible object.
+
+  // |data| has already been zeroed, so we don't need to do anything if these
+  // calls fail.
+  acc->get_accName(kChildIdSelf, &data.mText);
+  data.mTextRole = role;
+  acc->get_uniqueID(&data.mTextId);
+  acc->get_accState(kChildIdSelf, &varVal);
+  data.mTextState = varVal.lVal;
+  acc->accLocation(&data.mTextLeft, &data.mTextTop, &data.mTextWidth,
+                   &data.mTextHeight, kChildIdSelf);
+
+  return true;
+}
+
+void
+HandlerProvider::GetAllChildrenMainThread(AccChildData** aChildren,
+                                          ULONG* aNChildren,
+                                          HRESULT* hr)
+{
+  MOZ_ASSERT(aChildren);
+  MOZ_ASSERT(aNChildren);
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!mTargetUnk) {
+    *hr = CO_E_OBJNOTCONNECTED;
+    return;
+  }
+
+  RefPtr<NEWEST_IA2_INTERFACE> acc;
+  *hr = mTargetUnk.get()->QueryInterface(NEWEST_IA2_IID,
+    getter_AddRefs(acc));
+  if (FAILED(*hr)) {
+    return;
+  }
+
+  long count;
+  *hr = acc->get_accChildCount(&count);
+  if (FAILED(*hr)) {
+    return;
+  }
+  MOZ_ASSERT(count >= 0);
+
+  if (count == 0) {
+    *aChildren = nullptr;
+    *aNChildren = 0;
+    return;
+  }
+
+  RefPtr<IEnumVARIANT> enumVar;
+  *hr = mTargetUnk.get()->QueryInterface(IID_IEnumVARIANT,
+    getter_AddRefs(enumVar));
+  if (FAILED(*hr)) {
+    return;
+  }
+
+  auto rawChildren = MakeUnique<VARIANT[]>(count);
+  *hr = enumVar->Next((ULONG)count, rawChildren.get(), aNChildren);
+  if (FAILED(*hr)) {
+    *aChildren = nullptr;
+    *aNChildren = 0;
+    return;
+  }
+
+  *aChildren = static_cast<AccChildData*>(::CoTaskMemAlloc(
+    sizeof(AccChildData) * *aNChildren));
+  for (ULONG index = 0; index < *aNChildren; ++index) {
+    (*aChildren)[index] = {};
+    AccChildData& child = (*aChildren)[index];
+
+    MOZ_ASSERT(rawChildren[index].vt == VT_DISPATCH);
+    MOZ_ASSERT(rawChildren[index].pdispVal);
+    RefPtr<NEWEST_IA2_INTERFACE> childAcc;
+    *hr = rawChildren[index].pdispVal->QueryInterface(NEWEST_IA2_IID,
+      getter_AddRefs(childAcc));
+    rawChildren[index].pdispVal->Release();
+    MOZ_ASSERT(SUCCEEDED(*hr));
+    if (FAILED(*hr)) {
+      continue;
+    }
+
+    if (!SetChildDataForTextLeaf(childAcc, child)) {
+      // This isn't a text leaf. Marshal the accessible.
+      childAcc.forget(&child.mAccessible);
+      // We must wrap this accessible in an Interceptor.
+      ToWrappedObject(&child.mAccessible);
+    }
+  }
+
+  *hr = S_OK;
+}
+
+HRESULT
+HandlerProvider::get_AllChildren(AccChildData** aChildren,
+                                 ULONG* aNChildren)
+{
+  MOZ_ASSERT(mscom::IsCurrentThreadMTA());
+
+  HRESULT hr;
+  if (!mscom::InvokeOnMainThread("HandlerProvider::GetAllChildrenMainThread",
+                                 this,
+                                 &HandlerProvider::GetAllChildrenMainThread,
+                                 aChildren, aNChildren, &hr)) {
+    return E_FAIL;
+  }
+
+  return hr;
+}
+
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/ipc/win/HandlerProvider.h
+++ b/accessible/ipc/win/HandlerProvider.h
@@ -59,16 +59,18 @@ public:
   STDMETHODIMP Refresh(DynamicIA2Data* aOutData) override;
   STDMETHODIMP get_AllTextInfo(BSTR* aText,
                                IAccessibleHyperlink*** aHyperlinks,
                                long* aNHyperlinks,
                                IA2TextSegment** aAttribRuns,
                                long* aNAttribRuns) override;
   STDMETHODIMP get_RelationsInfo(IARelationData** aRelations,
                                  long* aNRelations) override;
+  STDMETHODIMP get_AllChildren(AccChildData** aChildren,
+                               ULONG* aNChildren) override;
 
 private:
   ~HandlerProvider() = default;
 
   void SetHandlerControlOnMainThread(DWORD aPid,
                                      mscom::ProxyUniquePtr<IHandlerControl> aCtrl);
   void GetAndSerializePayload(const MutexAutoLock&,
                               NotNull<mscom::IInterceptor*> aInterceptor);
@@ -90,16 +92,18 @@ private:
                                 IAccessibleHyperlink*** aHyperlinks,
                                 long* aNHyperlinks,
                                 IA2TextSegment** aAttribRuns,
                                 long* aNAttribRuns,
                                 HRESULT* result);
   void GetRelationsInfoMainThread(IARelationData** aRelations,
                                   long* aNRelations,
                                   HRESULT* result);
+  void GetAllChildrenMainThread(AccChildData** aChildren, ULONG* aNChildren,
+                                HRESULT* result);
 
   Atomic<uint32_t>                  mRefCnt;
   Mutex                             mMutex; // Protects mSerializer
   const IID                         mTargetUnkIid;
   mscom::InterceptorTargetPtr<IUnknown> mTargetUnk; // Constant, main thread only
   UniquePtr<mscom::StructToStream>  mSerializer;
   RefPtr<IUnknown>                  mFastMarshalUnk;
 };
--- a/accessible/ipc/win/handler/AccessibleHandler.cpp
+++ b/accessible/ipc/win/handler/AccessibleHandler.cpp
@@ -7,16 +7,17 @@
 #if defined(MOZILLA_INTERNAL_API)
 #error This code is NOT for internal Gecko use!
 #endif // defined(MOZILLA_INTERNAL_API)
 
 #define INITGUID
 
 #include "AccessibleHandler.h"
 #include "AccessibleHandlerControl.h"
+#include "HandlerChildEnumerator.h"
 #include "HandlerRelation.h"
 
 #include "Factory.h"
 #include "HandlerData.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/a11y/HandlerDataCleanup.h"
 #include "mozilla/mscom/Registration.h"
 #include "mozilla/UniquePtr.h"
@@ -352,19 +353,17 @@ AccessibleHandler::QueryHandlerInterface
     return S_OK;
   }
 
   if (HasPayload()) {
     // The proxy manager caches interfaces marshaled in the payload
     // and returns them on QI without a cross-process call.
     // However, it doesn't know about interfaces which don't exist.
     // We can determine this from the payload.
-    if ((aIid == IID_IEnumVARIANT &&
-         !mCachedData.mStaticData.mIEnumVARIANT) ||
-        ((aIid == IID_IAccessibleText || aIid == IID_IAccessibleHypertext ||
+    if (((aIid == IID_IAccessibleText || aIid == IID_IAccessibleHypertext ||
           aIid == IID_IAccessibleHypertext2) &&
          !mCachedData.mStaticData.mIAHypertext) ||
         ((aIid == IID_IAccessibleAction || aIid == IID_IAccessibleHyperlink) &&
          !mCachedData.mStaticData.mIAHyperlink) ||
         (aIid == IID_IAccessibleTable &&
          !mCachedData.mStaticData.mIATable) ||
         (aIid == IID_IAccessibleTable2 &&
          !mCachedData.mStaticData.mIATable2) ||
@@ -401,16 +400,26 @@ AccessibleHandler::QueryHandlerInterface
   }
 
   if (aIid == IID_IProvideClassInfo) {
     RefPtr<IProvideClassInfo> clsInfo(this);
     clsInfo.forget(aOutInterface);
     return S_OK;
   }
 
+  if (aIid == IID_IEnumVARIANT && mCachedData.mGeckoBackChannel) {
+    if (&mCachedData.mDynamicData.mChildCount == 0) {
+      return E_NOINTERFACE;
+    }
+    RefPtr<IEnumVARIANT> childEnum(
+      new HandlerChildEnumerator(this, mCachedData.mGeckoBackChannel));
+    childEnum.forget(aOutInterface);
+    return S_OK;
+  }
+
   return E_NOINTERFACE;
 }
 
 HRESULT
 AccessibleHandler::ReadHandlerPayload(IStream* aStream, REFIID aIid)
 {
   if (!aStream) {
     return E_INVALIDARG;
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/win/handler/HandlerChildEnumerator.cpp
@@ -0,0 +1,183 @@
+/* -*- 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/. */
+
+#if defined(MOZILLA_INTERNAL_API)
+#error This code is NOT for internal Gecko use!
+#endif // defined(MOZILLA_INTERNAL_API)
+
+#include "HandlerChildEnumerator.h"
+#include "HandlerTextLeaf.h"
+#include "mozilla/Assertions.h"
+
+namespace mozilla {
+namespace a11y {
+
+HandlerChildEnumerator::HandlerChildEnumerator(AccessibleHandler* aHandler,
+    IGeckoBackChannel* aGeckoBackChannel)
+  : mHandler(aHandler)
+  , mGeckoBackChannel(aGeckoBackChannel)
+  , mChildCount(0)
+  , mNextChild(0)
+{
+  MOZ_ASSERT(aHandler);
+  MOZ_ASSERT(aGeckoBackChannel);
+}
+
+HandlerChildEnumerator::HandlerChildEnumerator(
+    const HandlerChildEnumerator& aEnumerator)
+  : mHandler(aEnumerator.mHandler)
+  , mGeckoBackChannel(aEnumerator.mGeckoBackChannel)
+  , mChildCount(aEnumerator.mChildCount)
+  , mNextChild(aEnumerator.mNextChild)
+{
+  if (mChildCount == 0) {
+    return;
+  }
+  mChildren = MakeUnique<VARIANT[]>(mChildCount);
+  CopyMemory(mChildren.get(), aEnumerator.mChildren.get(),
+             sizeof(VARIANT) * mChildCount);
+  for (ULONG index = 0; index < mChildCount; ++index) {
+    mChildren[index].pdispVal->AddRef();
+  }
+}
+
+HandlerChildEnumerator::~HandlerChildEnumerator()
+{
+  ClearCache();
+}
+
+void
+HandlerChildEnumerator::ClearCache()
+{
+  if (!mChildren) {
+    return;
+  }
+
+  for (ULONG index = 0; index < mChildCount; ++index) {
+    mChildren[index].pdispVal->Release();
+  }
+
+  mChildren = nullptr;
+  mChildCount = 0;
+}
+
+HRESULT
+HandlerChildEnumerator::MaybeCacheChildren()
+{
+  if (mChildren) {
+    // Already cached.
+    return S_OK;
+  }
+
+  AccChildData* children;
+  HRESULT hr = mGeckoBackChannel->get_AllChildren(&children, &mChildCount);
+  if (FAILED(hr)) {
+    mChildCount = 0;
+    ClearCache();
+    return hr;
+  }
+
+  HWND hwnd = nullptr;
+  hr = mHandler->get_windowHandle(&hwnd);
+  MOZ_ASSERT(SUCCEEDED(hr));
+
+  RefPtr<IDispatch> parent;
+  hr = mHandler->QueryInterface(IID_IDispatch, getter_AddRefs(parent));
+  MOZ_ASSERT(SUCCEEDED(hr));
+
+  mChildren = MakeUnique<VARIANT[]>(mChildCount);
+  for (ULONG index = 0; index < mChildCount; ++index) {
+    AccChildData& data = children[index];
+    VARIANT& child = mChildren[index];
+    if (data.mAccessible) {
+      RefPtr<IDispatch> disp;
+      hr = data.mAccessible->QueryInterface(IID_IDispatch,
+                                            getter_AddRefs(disp));
+      data.mAccessible->Release();
+      MOZ_ASSERT(SUCCEEDED(hr));
+      if (FAILED(hr)) {
+        child.vt = VT_EMPTY;
+        continue;
+      }
+      child.vt = VT_DISPATCH;
+      disp.forget(&child.pdispVal);
+    } else {
+      // Text leaf.
+      RefPtr<IDispatch> leaf(
+        new HandlerTextLeaf(parent, index, hwnd, data));
+      child.vt = VT_DISPATCH;
+      leaf.forget(&child.pdispVal);
+    }
+  }
+
+  ::CoTaskMemFree(children);
+  return S_OK;
+}
+
+IMPL_IUNKNOWN_QUERY_HEAD(HandlerChildEnumerator)
+IMPL_IUNKNOWN_QUERY_IFACE(IEnumVARIANT)
+IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mHandler)
+
+/*** IEnumVARIANT ***/
+
+HRESULT
+HandlerChildEnumerator::Clone(IEnumVARIANT** aPpEnum)
+{
+  RefPtr<HandlerChildEnumerator> newEnum(new HandlerChildEnumerator(*this));
+  newEnum.forget(aPpEnum);
+  return S_OK;
+}
+
+HRESULT
+HandlerChildEnumerator::Next(ULONG aCelt, VARIANT* aRgVar,
+                             ULONG* aPCeltFetched)
+{
+  if (!aRgVar || aCelt == 0) {
+    return E_INVALIDARG;
+  }
+
+  HRESULT hr = MaybeCacheChildren();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  for (ULONG index = 0; index < aCelt; ++index) {
+    if (mNextChild >= mChildCount) {
+      // Less elements remaining than were requested.
+      if (aPCeltFetched) {
+        *aPCeltFetched = index;
+      }
+      return S_FALSE;
+    }
+    aRgVar[index] = mChildren[mNextChild];
+    aRgVar[index].pdispVal->AddRef();
+    ++mNextChild;
+  }
+  *aPCeltFetched = aCelt;
+  return S_OK;
+}
+
+HRESULT
+HandlerChildEnumerator::Reset()
+{
+  mNextChild = 0;
+  ClearCache();
+  return S_OK;
+}
+
+HRESULT
+HandlerChildEnumerator::Skip(ULONG aCelt)
+{
+  mNextChild += aCelt;
+  if (mNextChild > mChildCount) {
+    // Less elements remaining than the client requested to skip.
+    return S_FALSE;
+  }
+  return S_OK;
+}
+
+} // namespace a11y
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/win/handler/HandlerChildEnumerator.h
@@ -0,0 +1,52 @@
+/* -*- 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/. */
+
+#if defined(MOZILLA_INTERNAL_API)
+#error This code is NOT for internal Gecko use!
+#endif // defined(MOZILLA_INTERNAL_API)
+
+#ifndef mozilla_a11y_HandlerChildEnumerator_h
+#define mozilla_a11y_HandlerChildEnumerator_h
+
+#include "AccessibleHandler.h"
+#include "IUnknownImpl.h"
+#include "mozilla/RefPtr.h"
+
+namespace mozilla {
+namespace a11y {
+
+class HandlerChildEnumerator final : public IEnumVARIANT
+{
+public:
+  explicit HandlerChildEnumerator(AccessibleHandler* aHandler,
+                                  IGeckoBackChannel* aGeckoBackChannel);
+
+  DECL_IUNKNOWN
+
+  // IEnumVARIANT
+  STDMETHODIMP Clone(IEnumVARIANT** aPpEnum) override;
+  STDMETHODIMP Next(ULONG aCelt, VARIANT* aRgVar,
+                    ULONG* aPCeltFetched) override;
+  STDMETHODIMP Reset() override;
+  STDMETHODIMP Skip(ULONG aCelt) override;
+
+private:
+  explicit HandlerChildEnumerator(const HandlerChildEnumerator& aEnumerator);
+  ~HandlerChildEnumerator();
+  void ClearCache();
+  HRESULT MaybeCacheChildren();
+
+  RefPtr<AccessibleHandler> mHandler;
+  RefPtr<IGeckoBackChannel> mGeckoBackChannel;
+  UniquePtr<VARIANT[]> mChildren;
+  ULONG mChildCount;
+  ULONG mNextChild;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif // mozilla_a11y_HandlerChildEnumerator_h
--- a/accessible/ipc/win/handler/HandlerData.idl
+++ b/accessible/ipc/win/handler/HandlerData.idl
@@ -2,31 +2,29 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla-config.h"
 #include "AccessibleHandler.h"
 
-import "oaidl.idl";
 import "ocidl.idl";
 import "ServProv.idl";
 
 import "Accessible2_3.idl";
 import "AccessibleHypertext2.idl";
 import "AccessibleHyperlink.idl";
 import "AccessibleTable.idl";
 import "AccessibleTable2.idl";
 import "AccessibleTableCell.idl";
 
 typedef struct _StaticIA2Data
 {
   NEWEST_IA2_INTERFACE* mIA2;
-  IEnumVARIANT* mIEnumVARIANT;
   IAccessibleHypertext2* mIAHypertext;
   IAccessibleHyperlink* mIAHyperlink;
   IAccessibleTable* mIATable;
   IAccessibleTable2* mIATable2;
   IAccessibleTableCell* mIATableCell;
 } StaticIA2Data;
 
 typedef struct _DynamicIA2Data
@@ -146,31 +144,47 @@ interface IHandlerControl : IUnknown
 }
 
 typedef struct _IARelationData 
 {
   BSTR mType;
   long mNTargets;
 } IARelationData;
 
+typedef struct _AccChildData
+{
+  NEWEST_IA2_INTERFACE* mAccessible;
+  BSTR mText;
+  long mTextRole;
+  long mTextId;
+  long mTextState;
+  long mTextLeft;
+  long mTextTop;
+  long mTextWidth;
+  long mTextHeight;
+} AccChildData;
+
 [object,
  uuid(IGECKOBACKCHANNEL_IID),
  pointer_default(unique)]
 interface IGeckoBackChannel : IUnknown
 {
   [propput] HRESULT HandlerControl([in] long aPid, [in] IHandlerControl* aCtrl);
   HRESULT Refresh([out] DynamicIA2Data* aOutData);
   [propget] HRESULT AllTextInfo([out] BSTR* aText,
     [out, size_is(,*aNHyperlinks)] IAccessibleHyperlink*** aHyperlinks,
     [out] long* aNHyperlinks,
     [out, size_is(,*aNAttribRuns)] IA2TextSegment** aAttribRuns,
     [out] long* aNAttribRuns);
   [propget] HRESULT RelationsInfo(
     [out, size_is(,*aNRelations)] IARelationData** aRelations,
     [out] long* aNRelations);
+  [propget] HRESULT AllChildren(
+    [out, size_is(,*aNChildren)] AccChildData** aChildren,
+    [out] ULONG* aNChildren);
 }
 
 [uuid(1e545f07-f108-4912-9471-546827a80983)]
 library AccessibleHandlerTypeLib
 {
   /**
    * This definition is required in order for the handler implementation to
    * support IDispatch (aka Automation). This is used by interpreted language
--- a/accessible/ipc/win/handler/HandlerDataCleanup.h
+++ b/accessible/ipc/win/handler/HandlerDataCleanup.h
@@ -18,19 +18,16 @@ ReleaseStaticIA2DataInterfaces(StaticIA2
 {
   // Only interfaces of the proxied object wrapped by this handler should be
   // released here, never other objects!
   // For example, if StaticIA2Data were to include accParent in future,
   // that must not be released here.
   if (aData.mIA2) {
     aData.mIA2->Release();
   }
-  if (aData.mIEnumVARIANT) {
-    aData.mIEnumVARIANT->Release();
-  }
   if (aData.mIAHypertext) {
     aData.mIAHypertext->Release();
   }
   if (aData.mIAHyperlink) {
     aData.mIAHyperlink->Release();
   }
   if (aData.mIATable) {
     aData.mIATable->Release();
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/win/handler/HandlerTextLeaf.cpp
@@ -0,0 +1,402 @@
+/* -*- 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/. */
+
+#if defined(MOZILLA_INTERNAL_API)
+#error This code is NOT for internal Gecko use!
+#endif // defined(MOZILLA_INTERNAL_API)
+
+#include "HandlerTextLeaf.h"
+#include "mozilla/Assertions.h"
+
+namespace mozilla {
+namespace a11y {
+
+HandlerTextLeaf::HandlerTextLeaf(IDispatch* aParent,
+                                 long aIndexInParent, HWND aHwnd,
+                                 AccChildData& aData)
+: mParent(aParent)
+, mIndexInParent(aIndexInParent)
+, mHwnd(aHwnd)
+, mData(aData)
+{
+  MOZ_ASSERT(aParent);
+}
+
+HandlerTextLeaf::~HandlerTextLeaf()
+{
+  if (mData.mText) {
+    ::SysFreeString(mData.mText);
+  }
+}
+
+IMPL_IUNKNOWN_QUERY_HEAD(HandlerTextLeaf)
+IMPL_IUNKNOWN_QUERY_IFACE(IDispatch)
+IMPL_IUNKNOWN_QUERY_IFACE(IAccessible)
+IMPL_IUNKNOWN_QUERY_IFACE(IAccessible2)
+IMPL_IUNKNOWN_QUERY_IFACE(IServiceProvider)
+IMPL_IUNKNOWN_QUERY_TAIL
+
+/*** IDispatch ***/
+
+HRESULT
+HandlerTextLeaf::GetTypeInfoCount(UINT *pctinfo)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames,
+                               LCID lcid, DISPID *rgDispId)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
+                        WORD wFlags, DISPPARAMS *pDispParams,
+                        VARIANT *pVarResult, EXCEPINFO *pExcepInfo,
+                        UINT *puArgErr)
+{
+  return E_NOTIMPL;
+}
+
+/*** IAccessible ***/
+
+HRESULT
+HandlerTextLeaf::get_accParent(IDispatch **ppdispParent)
+{
+  if (!ppdispParent) {
+    return E_INVALIDARG;
+  }
+
+  RefPtr<IDispatch> parent(mParent);
+  parent.forget(ppdispParent);
+  return S_OK;
+}
+
+HRESULT
+HandlerTextLeaf::get_accChildCount(long *pcountChildren)
+{
+  if (!pcountChildren) {
+    return E_INVALIDARG;
+  }
+
+  *pcountChildren = 0;
+  return S_OK;
+}
+
+HRESULT
+HandlerTextLeaf::get_accChild(VARIANT varChild, IDispatch **ppdispChild)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_accName(VARIANT varChild, BSTR *pszName)
+{
+  if (varChild.lVal != CHILDID_SELF || !pszName) {
+    return E_INVALIDARG;
+  }
+
+  *pszName = CopyBSTR(mData.mText);
+  return S_OK;
+}
+
+HRESULT
+HandlerTextLeaf::get_accValue(VARIANT varChild, BSTR *pszValue)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_accDescription(VARIANT varChild, BSTR *pszDescription)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_accRole(VARIANT varChild, VARIANT *pvarRole)
+{
+  if (varChild.lVal != CHILDID_SELF || !pvarRole) {
+    return E_INVALIDARG;
+  }
+
+  pvarRole->vt = VT_I4;
+  pvarRole->lVal = mData.mTextRole;
+  return S_OK;
+}
+
+HRESULT
+HandlerTextLeaf::get_accState(VARIANT varChild, VARIANT *pvarState)
+{
+  if (varChild.lVal != CHILDID_SELF || !pvarState) {
+    return E_INVALIDARG;
+  }
+
+  pvarState->vt = VT_I4;
+  pvarState->lVal = mData.mTextState;
+  return S_OK;
+}
+
+HRESULT
+HandlerTextLeaf::get_accHelp(VARIANT varChild, BSTR *pszHelp)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild,
+                                  long *pidTopic)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_accKeyboardShortcut(VARIANT varChild,
+                                         BSTR *pszKeyboardShortcut)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_accFocus(VARIANT *pvarChild)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_accSelection(VARIANT *pvarChildren)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_accDefaultAction(VARIANT varChild,
+                                      BSTR *pszDefaultAction)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::accSelect(long flagsSelect, VARIANT varChild)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::accLocation(long *pxLeft, long *pyTop, long *pcxWidth,
+                             long *pcyHeight, VARIANT varChild)
+{
+  if (varChild.lVal != CHILDID_SELF || !pxLeft || !pyTop || !pcxWidth ||
+      !pcyHeight) {
+    return E_INVALIDARG;
+  }
+
+  *pxLeft = mData.mTextLeft;
+  *pyTop = mData.mTextTop;
+  *pcxWidth = mData.mTextWidth;
+  *pcyHeight = mData.mTextHeight;
+  return S_OK;
+}
+
+HRESULT
+HandlerTextLeaf::accNavigate(long navDir, VARIANT varStart,
+                             VARIANT *pvarEndUpAt)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::accHitTest( long xLeft, long yTop, VARIANT *pvarChild)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::accDoDefaultAction(VARIANT varChild)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::put_accName(VARIANT varChild, BSTR szName)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::put_accValue(VARIANT varChild, BSTR szValue)
+{
+  return E_NOTIMPL;
+}
+
+/*** IAccessible2 ***/
+
+HRESULT
+HandlerTextLeaf::get_nRelations(long* nRelations)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_relation(long relationIndex,
+                              IAccessibleRelation** relation)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_relations(long maxRelations,
+                               IAccessibleRelation** relations,
+                               long* nRelations)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::role(long* role)
+{
+  if (!role) {
+    return E_INVALIDARG;
+  }
+
+  *role = mData.mTextRole;
+  return S_OK;
+}
+
+HRESULT
+HandlerTextLeaf::scrollTo(IA2ScrollType scrollType)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::scrollToPoint(IA2CoordinateType coordinateType, long x,
+                               long y)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_groupPosition(long* groupLevel, long* similarItemsInGroup,
+                                   long* positionInGroup)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_states(AccessibleStates* states)
+{
+  if (!states) {
+    return E_INVALIDARG;
+  }
+
+  *states = 0;
+  return S_OK;
+}
+
+HRESULT
+HandlerTextLeaf::get_extendedRole(BSTR* extendedRole)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_localizedExtendedRole(BSTR* localizedExtendedRole)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_nExtendedStates(long* nExtendedStates)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_extendedStates(long maxExtendedStates,
+                                    BSTR** extendedStates,
+                                    long* nExtendedStates)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_localizedExtendedStates(long maxLocalizedExtendedStates,
+                                             BSTR** localizedExtendedStates,
+                                             long* nLocalizedExtendedStates)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_uniqueID(long* uniqueID)
+{
+  if (!uniqueID) {
+    return E_INVALIDARG;
+  }
+
+  *uniqueID = mData.mTextId;
+  return S_OK;
+}
+
+HRESULT
+HandlerTextLeaf::get_windowHandle(HWND* windowHandle)
+{
+  if (!windowHandle) {
+    return E_INVALIDARG;
+  }
+
+  *windowHandle = mHwnd;
+  return S_OK;
+}
+
+HRESULT
+HandlerTextLeaf::get_indexInParent(long* indexInParent)
+{
+  if (!indexInParent) {
+    return E_INVALIDARG;
+  }
+
+  *indexInParent = mIndexInParent;
+  return S_OK;
+}
+
+HRESULT
+HandlerTextLeaf::get_locale(IA2Locale* locale)
+{
+  return E_NOTIMPL;
+}
+
+HRESULT
+HandlerTextLeaf::get_attributes(BSTR* attributes)
+{
+  return E_NOTIMPL;
+}
+
+/*** IServiceProvider ***/
+
+HRESULT
+HandlerTextLeaf::QueryService(REFGUID aServiceId, REFIID aIid,
+                              void** aOutInterface)
+{
+  if (aIid == IID_IAccessible2) {
+    RefPtr<IAccessible2> ia2(this);
+    ia2.forget(aOutInterface);
+    return S_OK;
+  }
+
+  return E_INVALIDARG;
+}
+
+} // namespace a11y
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/accessible/ipc/win/handler/HandlerTextLeaf.h
@@ -0,0 +1,110 @@
+/* -*- 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/. */
+
+#if defined(MOZILLA_INTERNAL_API)
+#error This code is NOT for internal Gecko use!
+#endif // defined(MOZILLA_INTERNAL_API)
+
+#ifndef mozilla_a11y_HandlerTextLeaf_h
+#define mozilla_a11y_HandlerTextLeaf_h
+
+#include "AccessibleHandler.h"
+#include "IUnknownImpl.h"
+#include "mozilla/RefPtr.h"
+
+namespace mozilla {
+namespace a11y {
+
+class HandlerTextLeaf final : public IAccessible2
+                              , public IServiceProvider
+{
+public:
+  explicit HandlerTextLeaf(IDispatch* aParent, long aIndexInParent,
+                           HWND aHwnd, AccChildData& aData);
+
+  DECL_IUNKNOWN
+
+  // IDispatch
+  STDMETHODIMP GetTypeInfoCount(UINT *pctinfo) override;
+  STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) override;
+  STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames,
+                             LCID lcid, DISPID *rgDispId) override;
+  STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
+                      DISPPARAMS *pDispParams, VARIANT *pVarResult,
+                      EXCEPINFO *pExcepInfo, UINT *puArgErr) override;
+
+  // IAccessible
+  STDMETHODIMP get_accParent(IDispatch **ppdispParent) override;
+  STDMETHODIMP get_accChildCount(long *pcountChildren) override;
+  STDMETHODIMP get_accChild(VARIANT varChild, IDispatch **ppdispChild) override;
+  STDMETHODIMP get_accName(VARIANT varChild, BSTR *pszName) override;
+  STDMETHODIMP get_accValue(VARIANT varChild, BSTR *pszValue) override;
+  STDMETHODIMP get_accDescription(VARIANT varChild, BSTR *pszDescription) override;
+  STDMETHODIMP get_accRole(VARIANT varChild, VARIANT *pvarRole) override;
+  STDMETHODIMP get_accState(VARIANT varChild, VARIANT *pvarState) override;
+  STDMETHODIMP get_accHelp(VARIANT varChild, BSTR *pszHelp) override;
+  STDMETHODIMP get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild,
+                                long *pidTopic) override;
+  STDMETHODIMP get_accKeyboardShortcut(VARIANT varChild,
+                                       BSTR *pszKeyboardShortcut) override;
+  STDMETHODIMP get_accFocus(VARIANT *pvarChild) override;
+  STDMETHODIMP get_accSelection(VARIANT *pvarChildren) override;
+  STDMETHODIMP get_accDefaultAction(VARIANT varChild,
+                                    BSTR *pszDefaultAction) override;
+  STDMETHODIMP accSelect(long flagsSelect, VARIANT varChild) override;
+  STDMETHODIMP accLocation(long *pxLeft, long *pyTop, long *pcxWidth,
+                           long *pcyHeight, VARIANT varChild) override;
+  STDMETHODIMP accNavigate(long navDir, VARIANT varStart,
+                           VARIANT *pvarEndUpAt) override;
+  STDMETHODIMP accHitTest( long xLeft, long yTop, VARIANT *pvarChild) override;
+  STDMETHODIMP accDoDefaultAction(VARIANT varChild) override;
+  STDMETHODIMP put_accName(VARIANT varChild, BSTR szName) override;
+  STDMETHODIMP put_accValue(VARIANT varChild, BSTR szValue) override;
+
+  // IAccessible2
+  STDMETHODIMP get_nRelations(long* nRelations) override;
+  STDMETHODIMP get_relation(long relationIndex,
+                            IAccessibleRelation** relation) override;
+  STDMETHODIMP get_relations(long maxRelations, IAccessibleRelation** relations,
+                             long* nRelations) override;
+  STDMETHODIMP role(long* role) override;
+  STDMETHODIMP scrollTo(IA2ScrollType scrollType) override;
+  STDMETHODIMP scrollToPoint(IA2CoordinateType coordinateType, long x,
+                             long y) override;
+  STDMETHODIMP get_groupPosition(long* groupLevel, long* similarItemsInGroup,
+                                 long* positionInGroup) override;
+  STDMETHODIMP get_states(AccessibleStates* states) override;
+  STDMETHODIMP get_extendedRole(BSTR* extendedRole) override;
+  STDMETHODIMP get_localizedExtendedRole(BSTR* localizedExtendedRole) override;
+  STDMETHODIMP get_nExtendedStates(long* nExtendedStates) override;
+  STDMETHODIMP get_extendedStates(long maxExtendedStates, BSTR** extendedStates,
+                                  long* nExtendedStates) override;
+  STDMETHODIMP get_localizedExtendedStates(long maxLocalizedExtendedStates,
+                                           BSTR** localizedExtendedStates,
+                                           long* nLocalizedExtendedStates) override;
+  STDMETHODIMP get_uniqueID(long* uniqueID) override;
+  STDMETHODIMP get_windowHandle(HWND* windowHandle) override;
+  STDMETHODIMP get_indexInParent(long* indexInParent) override;
+  STDMETHODIMP get_locale(IA2Locale* locale) override;
+  STDMETHODIMP get_attributes(BSTR* attributes) override;
+
+  // IServiceProvider
+  STDMETHODIMP QueryService(REFGUID aServiceId, REFIID aIid,
+                            void** aOutInterface) override;
+
+private:
+  ~HandlerTextLeaf();
+
+  RefPtr<IDispatch> mParent;
+  long mIndexInParent;
+  HWND mHwnd;
+  AccChildData mData;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif // mozilla_a11y_HandlerTextLeaf_h
--- a/accessible/ipc/win/handler/moz.build
+++ b/accessible/ipc/win/handler/moz.build
@@ -18,17 +18,19 @@ LOCAL_INCLUDES += [
 
 SOURCES += [
     '!dlldata.c',
     '!HandlerData_c.c',
     '!HandlerData_i.c',
     '!HandlerData_p.c',
     'AccessibleHandler.cpp',
     'AccessibleHandlerControl.cpp',
+    'HandlerChildEnumerator.cpp',
     'HandlerRelation.cpp',
+    'HandlerTextLeaf.cpp',
 ]
 
 GENERATED_FILES += [
     'dlldata.c',
     'HandlerData.h',
     'HandlerData.tlb',
     'HandlerData_c.c',
     'HandlerData_i.c',
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1226,17 +1226,30 @@ var gBrowserInit = {
       document.documentElement.setAttribute("height", height);
 
       if (width < TARGET_WIDTH && height < TARGET_HEIGHT) {
         document.documentElement.setAttribute("sizemode", "maximized");
       }
     }
 
     new LightweightThemeConsumer(document);
+    CompactTheme.init();
+
     TabsInTitlebar.init();
+
+    if (window.matchMedia("(-moz-os-version: windows-win8)").matches &&
+        window.matchMedia("(-moz-windows-default-theme)").matches) {
+      let windowFrameColor = new Color(...ChromeUtils.import("resource:///modules/Windows8WindowFrameColor.jsm", {})
+                                            .Windows8WindowFrameColor.get());
+      // Default to black for foreground text.
+      if (!windowFrameColor.isContrastRatioAcceptable(new Color(0, 0, 0))) {
+        document.documentElement.setAttribute("darkwindowframe", "true");
+      }
+    }
+    ToolbarIconColor.init();
   },
 
   onDOMContentLoaded() {
     gBrowser = window._gBrowser;
     delete window._gBrowser;
     gBrowser.init();
 
     window.QueryInterface(Ci.nsIInterfaceRequestor)
@@ -1314,17 +1327,16 @@ var gBrowserInit = {
     // loading the frame script to ensure that we don't miss any
     // message sent between when the frame script is loaded and when
     // the listener is registered.
     DOMEventHandler.init();
     gPageStyleMenu.init();
     LanguageDetectionListener.init();
     BrowserOnClick.init();
     FeedHandler.init();
-    CompactTheme.init();
     AboutCapabilitiesListener.init();
     TrackingProtection.init();
     CaptivePortalWatcher.init();
     ZoomUI.init(window);
 
     let mm = window.getGroupMessageManager("browsers");
     mm.loadFrameScript("chrome://browser/content/tab-content.js", true);
     mm.loadFrameScript("chrome://browser/content/content.js", true);
@@ -1363,28 +1375,16 @@ var gBrowserInit = {
 
     // Misc. inits.
     TabletModeUpdater.init();
     CombinedStopReload.ensureInitialized();
     gPrivateBrowsingUI.init();
     BrowserPageActions.init();
     gAccessibilityServiceIndicator.init();
 
-    if (window.matchMedia("(-moz-os-version: windows-win8)").matches &&
-        window.matchMedia("(-moz-windows-default-theme)").matches) {
-      let windowFrameColor = new Color(...ChromeUtils.import("resource:///modules/Windows8WindowFrameColor.jsm", {})
-                                            .Windows8WindowFrameColor.get());
-      // Default to black for foreground text.
-      if (!windowFrameColor.isContrastRatioAcceptable(new Color(0, 0, 0))) {
-        document.documentElement.setAttribute("darkwindowframe", "true");
-      }
-    }
-
-    ToolbarIconColor.init();
-
     gRemoteControl.updateVisualCue(Marionette.running);
 
     // If we are given a tab to swap in, take care of it before first paint to
     // avoid an about:blank flash.
     let tabToOpen = window.arguments && window.arguments[0];
     if (tabToOpen instanceof XULElement) {
       // Clear the reference to the tab from the arguments array.
       window.arguments[0] = null;
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -54,25 +54,19 @@ window._gBrowser = {
 
     // To correctly handle keypresses for potential FindAsYouType, while
     // the tab's find bar is not yet initialized.
     this._findAsYouType = Services.prefs.getBoolPref("accessibility.typeaheadfind");
     Services.prefs.addObserver("accessibility.typeaheadfind", this);
     messageManager.addMessageListener("Findbar:Keypress", this);
 
     XPCOMUtils.defineLazyPreferenceGetter(this, "animationsEnabled",
-      "toolkit.cosmeticAnimations.enabled", true);
+      "toolkit.cosmeticAnimations.enabled");
     XPCOMUtils.defineLazyPreferenceGetter(this, "schedulePressureDefaultCount",
-      "browser.schedulePressure.defaultCount", 3);
-    XPCOMUtils.defineLazyPreferenceGetter(this, "tabWarmingEnabled",
-      "browser.tabs.remote.warmup.enabled", false);
-    XPCOMUtils.defineLazyPreferenceGetter(this, "tabWarmingMax",
-      "browser.tabs.remote.warmup.maxTabs", 3);
-    XPCOMUtils.defineLazyPreferenceGetter(this, "tabWarmingUnloadDelay" /* ms */,
-      "browser.tabs.remote.warmup.unloadDelayMs", 2000);
+      "browser.schedulePressure.defaultCount");
 
     this._setupEventListeners();
   },
 
   ownerGlobal: window,
 
   ownerDocument: document,
 
--- a/browser/base/content/test/performance/browser_toolbariconcolor_restyles.js
+++ b/browser/base/content/test/performance/browser_toolbariconcolor_restyles.js
@@ -12,16 +12,22 @@ add_task(async function test_toolbar_ele
   // create a window and snapshot the elementsStyled
   let win1 = await BrowserTestUtils.openNewBrowserWindow();
   await new Promise(resolve => waitForFocus(resolve, win1));
 
   // create a 2nd window and snapshot the elementsStyled
   let win2 = await BrowserTestUtils.openNewBrowserWindow();
   await new Promise(resolve => waitForFocus(resolve, win2));
 
+  // (De)-activate both windows once before we take a measurement. The first
+  // (de-)activation may flush styles, after that the style data should be
+  // cached.
+  Services.focus.activeWindow = win1;
+  Services.focus.activeWindow = win2;
+
   // Flush any pending styles before we take a measurement.
   win1.getComputedStyle(win1.document.firstElementChild);
   win2.getComputedStyle(win2.document.firstElementChild);
 
   // Clear the focused element from each window so that when
   // we raise them, the focus of the element doesn't cause an
   // unrelated style flush.
   Services.focus.clearFocus(win1);
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media_multi_process.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_multi_process.js
@@ -181,27 +181,26 @@ var gTests = [
 
     ok(webrtcUI.showGlobalIndicator, "webrtcUI wants the global indicator shown");
     ok(webrtcUI.showCameraIndicator, "webrtcUI wants the camera indicator shown");
     ok(!webrtcUI.showMicrophoneIndicator, "webrtcUI wants the mic indicator hidden");
     is(webrtcUI.getActiveStreams(true).length, 2, "2 active camera streams");
     is(webrtcUI.getActiveStreams(true, true, true).length, 2, "2 active streams");
 
     info("removing the second tab");
-    // FIXME: This should wait for indicator update instead (bug 1444007).
-    let sessionStorePromise = BrowserTestUtils.waitForSessionStoreUpdate(tab);
     BrowserTestUtils.removeTab(tab);
-    await sessionStorePromise;
 
     // Check that we still show the sharing indicators for the first tab's stream.
-    await TestUtils.waitForCondition(() => webrtcUI.showCameraIndicator);
+    await Promise.all([
+      TestUtils.waitForCondition(() => webrtcUI.showCameraIndicator),
+      TestUtils.waitForCondition(() => webrtcUI.getActiveStreams(true).length == 1),
+    ]);
     ok(webrtcUI.showGlobalIndicator, "webrtcUI wants the global indicator shown");
     ok(webrtcUI.showCameraIndicator, "webrtcUI wants the camera indicator shown");
     ok(!webrtcUI.showMicrophoneIndicator, "webrtcUI wants the mic indicator hidden");
-    is(webrtcUI.getActiveStreams(true).length, 1, "1 active camera stream");
     is(webrtcUI.getActiveStreams(true, true, true).length, 1, "1 active stream");
 
     await checkSharingUI({video: true});
 
     // When both tabs use the same content process, the frame script for the
     // first tab receives observer notifications for things happening in the
     // second tab, so let's clear the observer call counts before we cleanup
     // in the first tab.
--- a/browser/components/extensions/ext-bookmarks.js
+++ b/browser/components/extensions/ext-bookmarks.js
@@ -66,22 +66,17 @@ const getTree = (rootGuid, onlyChildren)
           ? node.children.map(child => convert(child, node))
           : [];
       }
     }
 
     return treenode;
   }
 
-  return PlacesUtils.promiseBookmarksTree(rootGuid, {
-    excludeItemsCallback: item => {
-      return item.annos &&
-             item.annos.find(a => a.name == PlacesUtils.EXCLUDE_FROM_BACKUP_ANNO);
-    },
-  }).then(root => {
+  return PlacesUtils.promiseBookmarksTree(rootGuid).then(root => {
     if (onlyChildren) {
       let children = root.children || [];
       return children.map(child => convert(child, root));
     }
     let treenode = convert(root, null);
     treenode.parentId = root.parentGuid;
     // It seems like the array always just contains the root node.
     return [treenode];
--- a/browser/components/extensions/ext-pageAction.js
+++ b/browser/components/extensions/ext-pageAction.js
@@ -227,19 +227,18 @@ this.pageAction = class extends Extensio
    * Triggers this page action for the given window, with the same effects as
    * if it were clicked by a user.
    *
    * This has no effect if the page action is hidden for the selected tab.
    *
    * @param {Window} window
    */
   triggerAction(window) {
-    let pageAction = pageActionMap.get(this.extension);
-    if (pageAction.getProperty(window.gBrowser.selectedTab, "show")) {
-      pageAction.handleClick(window);
+    if (this.isShown(window.gBrowser.selectedTab)) {
+      this.handleClick(window);
     }
   }
 
   handleEvent(event) {
     switch (event.type) {
       case "popupshowing":
         const menu = event.target;
         const trigger = menu.triggerNode;
--- a/browser/components/extensions/test/browser/browser_ext_commands_execute_page_action.js
+++ b/browser/components/extensions/test/browser/browser_ext_commands_execute_page_action.js
@@ -1,12 +1,14 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
+const scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head><body>Test Popup</body></html>`;
+
 add_task(async function test_execute_page_action_without_popup() {
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "commands": {
         "_execute_page_action": {
           "suggested_key": {
             "default": "Alt+Shift+J",
           },
@@ -54,34 +56,33 @@ add_task(async function test_execute_pag
   });
 
   await extension.startup();
   await extension.awaitFinish("page-action-without-popup");
   await extension.unload();
 });
 
 add_task(async function test_execute_page_action_with_popup() {
-  let scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head><body>Test Popup</body></html>`;
-
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "commands": {
         "_execute_page_action": {
           "suggested_key": {
             "default": "Alt+Shift+J",
           },
         },
         "send-keys-command": {
           "suggested_key": {
             "default": "Alt+Shift+3",
           },
         },
       },
       "page_action": {
         "default_popup": "popup.html",
+        "browser_style": true,
       },
     },
 
     files: {
       "popup.html": scriptPage("popup.js"),
       "popup.js": function() {
         browser.runtime.sendMessage("popup-opened");
       },
@@ -126,8 +127,43 @@ add_task(async function test_execute_pag
     EventUtils.synthesizeKey("j", {altKey: true, shiftKey: true});
     EventUtils.synthesizeKey("3", {altKey: true, shiftKey: true});
   });
 
   await extension.startup();
   await extension.awaitFinish("page-action-with-popup");
   await extension.unload();
 });
+
+add_task(async function test_execute_page_action_with_matching() {
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "commands": {
+        "_execute_page_action": {
+          "suggested_key": {
+            "default": "Alt+Shift+J",
+          },
+        },
+      },
+      "page_action": {
+        "default_popup": "popup.html",
+        "show_matches": ["<all_urls>"],
+        "browser_style": true,
+      },
+    },
+
+    files: {
+      "popup.html": scriptPage("popup.js"),
+      "popup.js": function() {
+        window.addEventListener("load", () => {
+          browser.test.notifyPass("page-action-with-popup");
+        }, {once: true});
+      },
+    },
+  });
+
+  await extension.startup();
+  let tab = await BrowserTestUtils.openNewForegroundTab(window.gBrowser, "http://example.com/");
+  EventUtils.synthesizeKey("j", {altKey: true, shiftKey: true});
+  await extension.awaitFinish("page-action-with-popup");
+  await extension.unload();
+  BrowserTestUtils.removeTab(tab);
+});
--- a/browser/components/migration/AutoMigrate.jsm
+++ b/browser/components/migration/AutoMigrate.jsm
@@ -605,27 +605,29 @@ const AutoMigrate = {
             this._errorMap.logins++;
           }
         }
       }
     }
   },
 
   async _removeSomeVisits(visits) {
+    // It is necessary to recreate URL and date objects because the data
+    // can be serialized through JSON that destroys those objects.
     for (let urlVisits of visits) {
       let urlObj;
       try {
         urlObj = new URL(urlVisits.url);
       } catch (ex) {
         continue;
       }
       let visitData = {
         url: urlObj,
-        beginDate: PlacesUtils.toDate(urlVisits.first),
-        endDate: PlacesUtils.toDate(urlVisits.last),
+        beginDate: new Date(urlVisits.first),
+        endDate: new Date(urlVisits.last),
         limit: urlVisits.visitCount,
       };
       try {
         await PlacesUtils.history.removeVisitsByFilter(visitData);
       } catch (ex) {
         this._errorMap.visits++;
         try {
           visitData.url = visitData.url.href;
--- a/browser/components/migration/ChromeProfileMigrator.js
+++ b/browser/components/migration/ChromeProfileMigrator.js
@@ -268,53 +268,39 @@ async function GetHistoryResource(aProfi
           query += " AND last_visit_time > " + maxAge;
         }
         if (LIMIT) {
           query += " ORDER BY last_visit_time DESC LIMIT " + LIMIT;
         }
 
         let rows =
           await MigrationUtils.getRowsFromDBWithoutLocks(historyPath, "Chrome history", query);
-        let places = [];
+        let pageInfos = [];
         for (let row of rows) {
           try {
             // if having typed_count, we changes transition type to typed.
-            let transType = PlacesUtils.history.TRANSITION_LINK;
+            let transition = PlacesUtils.history.TRANSITIONS.LINK;
             if (row.getResultByName("typed_count") > 0)
-              transType = PlacesUtils.history.TRANSITION_TYPED;
+              transition = PlacesUtils.history.TRANSITIONS.TYPED;
 
-            places.push({
-              uri: NetUtil.newURI(row.getResultByName("url")),
+            pageInfos.push({
               title: row.getResultByName("title"),
+              url: new URL(row.getResultByName("url")),
               visits: [{
-                transitionType: transType,
-                visitDate: chromeTimeToDate(
-                             row.getResultByName(
-                               "last_visit_time")) * 1000,
+                transition,
+                date: chromeTimeToDate(row.getResultByName("last_visit_time")),
               }],
             });
           } catch (e) {
             Cu.reportError(e);
           }
         }
 
-        if (places.length > 0) {
-          await new Promise((resolve, reject) => {
-            MigrationUtils.insertVisitsWrapper(places, {
-              ignoreErrors: true,
-              ignoreResults: true,
-              handleCompletion(updatedCount) {
-                if (updatedCount > 0) {
-                  resolve();
-                } else {
-                  reject(new Error("Couldn't add visits"));
-                }
-              },
-            });
-          });
+        if (pageInfos.length > 0) {
+          await MigrationUtils.insertVisitsWrapper(pageInfos);
         }
       })().then(() => { aCallback(true); },
               ex => {
                 Cu.reportError(ex);
                 aCallback(false);
               });
     },
   };
--- a/browser/components/migration/EdgeProfileMigrator.js
+++ b/browser/components/migration/EdgeProfileMigrator.js
@@ -104,52 +104,46 @@ EdgeTypedURLMigrator.prototype = {
   },
 
   get exists() {
     return this._typedURLs.size > 0;
   },
 
   migrate(aCallback) {
     let typedURLs = this._typedURLs;
-    let places = [];
+    let pageInfos = [];
     for (let [urlString, time] of typedURLs) {
-      let uri;
+      let url;
       try {
-        uri = Services.io.newURI(urlString);
-        if (!["http", "https", "ftp"].includes(uri.scheme)) {
+        url = new URL(urlString);
+        if (!["http", "https", "ftp"].includes(url.scheme)) {
           continue;
         }
       } catch (ex) {
         Cu.reportError(ex);
         continue;
       }
 
-      // Note that the time will be in microseconds (PRTime),
-      // and Date.now() returns milliseconds. Places expects PRTime,
-      // so we multiply the Date.now return value to make up the difference.
-      let visitDate = time || (Date.now() * 1000);
-      places.push({
-        uri,
-        visits: [{ transitionType: Ci.nsINavHistoryService.TRANSITION_TYPED,
-                   visitDate}],
+      pageInfos.push({
+        url,
+        visits: [{
+          transition: PlacesUtils.history.TRANSITIONS.TYPED,
+          date: time ? PlacesUtils.toDate(time) : new Date(),
+        }],
       });
     }
 
-    if (places.length == 0) {
+    if (pageInfos.length == 0) {
       aCallback(typedURLs.size == 0);
       return;
     }
 
-    MigrationUtils.insertVisitsWrapper(places, {
-      ignoreErrors: true,
-      ignoreResults: true,
-      handleCompletion(updatedCount) {
-        aCallback(updatedCount > 0);
-      },
-    });
+    MigrationUtils.insertVisitsWrapper(pageInfos).then(
+      () => aCallback(true),
+      () => aCallback(false));
   },
 };
 
 function EdgeReadingListMigrator(dbOverride) {
   this.dbOverride = dbOverride;
 }
 
 EdgeReadingListMigrator.prototype = {
--- a/browser/components/migration/IEProfileMigrator.js
+++ b/browser/components/migration/IEProfileMigrator.js
@@ -33,68 +33,62 @@ function History() {
 History.prototype = {
   type: MigrationUtils.resourceTypes.HISTORY,
 
   get exists() {
     return true;
   },
 
   migrate: function H_migrate(aCallback) {
-    let places = [];
+    let pageInfos = [];
     let typedURLs = MSMigrationUtils.getTypedURLs("Software\\Microsoft\\Internet Explorer");
     let historyEnumerator = Cc["@mozilla.org/profile/migrator/iehistoryenumerator;1"].
                             createInstance(Ci.nsISimpleEnumerator);
     while (historyEnumerator.hasMoreElements()) {
       let entry = historyEnumerator.getNext().QueryInterface(Ci.nsIPropertyBag2);
-      let uri = entry.get("uri").QueryInterface(Ci.nsIURI);
+      let url = entry.get("uri").QueryInterface(Ci.nsIURI);
       // MSIE stores some types of URLs in its history that we don't handle,
       // like HTMLHelp and others.  Since we don't properly map handling for
       // all of them we just avoid importing them.
-      if (!["http", "https", "ftp", "file"].includes(uri.scheme)) {
+      if (!["http", "https", "ftp", "file"].includes(url.scheme)) {
         continue;
       }
 
       let title = entry.get("title");
       // Embed visits have no title and don't need to be imported.
       if (title.length == 0) {
         continue;
       }
 
       // The typed urls are already fixed-up, so we can use them for comparison.
-      let transitionType = typedURLs.has(uri.spec) ?
-                             Ci.nsINavHistoryService.TRANSITION_TYPED :
-                             Ci.nsINavHistoryService.TRANSITION_LINK;
+      let transition = typedURLs.has(url.spec) ?
+        PlacesUtils.history.TRANSITIONS.LINK :
+        PlacesUtils.history.TRANSITIONS.TYPED;
       // use the current date if we have no visits for this entry.
-      // Note that the entry will have a time in microseconds (PRTime),
-      // and Date.now() returns milliseconds. Places expects PRTime,
-      // so we multiply the Date.now return value to make up the difference.
-      let lastVisitTime = entry.get("time") || (Date.now() * 1000);
+      let time = entry.get("time");
 
-      places.push(
-        { uri,
-          title,
-          visits: [{ transitionType,
-                     visitDate: lastVisitTime }],
-        }
-      );
+      pageInfos.push({
+        url,
+        title,
+        visits: [{
+          transition,
+          date: time ? PlacesUtils.toDate(entry.get("time")) : new Date(),
+        }],
+      });
     }
 
     // Check whether there is any history to import.
-    if (places.length == 0) {
+    if (pageInfos.length == 0) {
       aCallback(true);
       return;
     }
 
-    MigrationUtils.insertVisitsWrapper(places, {
-      ignoreErrors: true,
-      ignoreResults: true,
-      handleCompletion(updatedCount) {
-        aCallback(updatedCount > 0);
-      },
-    });
+    MigrationUtils.insertVisitsWrapper(pageInfos).then(
+      () => aCallback(true),
+      () => aCallback(false));
   },
 };
 
 // IE form password migrator supporting windows from XP until 7 and IE from 7 until 11
 function IE7FormPasswords() {
   // used to distinguish between this migrator and other passwords migrators in tests.
   this.name = "IE7FormPasswords";
 }
--- a/browser/components/migration/MigrationUtils.jsm
+++ b/browser/components/migration/MigrationUtils.jsm
@@ -1037,22 +1037,22 @@ var MigrationUtils = Object.freeze({
         for (let bm of insertedItems) {
           let {parentGuid, guid, lastModified, type} = bm;
           bmData.push({parentGuid, guid, lastModified, type});
         }
       }
     }, ex => Cu.reportError(ex));
   },
 
-  insertVisitsWrapper(places, options) {
-    this._importQuantities.history += places.length;
+  insertVisitsWrapper(pageInfos) {
+    this._importQuantities.history += pageInfos.length;
     if (gKeepUndoData) {
-      this._updateHistoryUndo(places);
+      this._updateHistoryUndo(pageInfos);
     }
-    return PlacesUtils.asyncHistory.updatePlaces(places, options, true);
+    return PlacesUtils.history.insertMany(pageInfos);
   },
 
   async insertLoginsWrapper(logins) {
     this._importQuantities.logins += logins.length;
     let inserted = await LoginHelper.maybeImportLogins(logins);
     // Note that this means that if we import a login that has a newer password
     // than we know about, we will update the login, and an undo of the import
     // will not revert this. This seems preferable over removing the login
@@ -1096,30 +1096,36 @@ var MigrationUtils = Object.freeze({
 
   stopAndRetrieveUndoData() {
     let undoData = gUndoData;
     gUndoData = null;
     gKeepUndoData = false;
     return this._postProcessUndoData(undoData);
   },
 
-  _updateHistoryUndo(places) {
+  _updateHistoryUndo(pageInfos) {
     let visits = gUndoData.get("visits");
     let visitMap = new Map(visits.map(v => [v.url, v]));
-    for (let place of places) {
-      let visitCount = place.visits.length;
+    for (let pageInfo of pageInfos) {
+      let visitCount = pageInfo.visits.length;
       let first, last;
       if (visitCount > 1) {
-        let visitDates = place.visits.map(v => v.visitDate);
-        first = Math.min.apply(Math, visitDates);
-        last = Math.max.apply(Math, visitDates);
+        let dates = pageInfo.visits.map(v => v.date);
+        first = Math.min.apply(Math, dates);
+        last = Math.max.apply(Math, dates);
       } else {
-        first = last = place.visits[0].visitDate;
+        first = last = pageInfo.visits[0].date;
       }
-      let url = place.uri.spec;
+      let url = pageInfo.url;
+      if (url instanceof Ci.nsIURI) {
+        url = pageInfo.url.spec;
+      } else if (typeof url != "string") {
+        pageInfo.url.href;
+      }
+
       try {
         new URL(url);
       } catch (ex) {
         // This won't save and we won't need to 'undo' it, so ignore this URL.
         continue;
       }
       if (!visitMap.has(url)) {
         visitMap.set(url, {url, visitCount, first, last});
--- a/browser/components/migration/SafariProfileMigrator.js
+++ b/browser/components/migration/SafariProfileMigrator.js
@@ -12,18 +12,16 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.import("resource:///modules/MigrationUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "Downloads",
                                "resource://gre/modules/Downloads.jsm");
 ChromeUtils.defineModuleGetter(this, "PropertyListUtils",
                                "resource://gre/modules/PropertyListUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "PlacesUtils",
                                "resource://gre/modules/PlacesUtils.jsm");
-ChromeUtils.defineModuleGetter(this, "NetUtil",
-                               "resource://gre/modules/NetUtil.jsm");
 ChromeUtils.defineModuleGetter(this, "FormHistory",
                                "resource://gre/modules/FormHistory.jsm");
 
 Cu.importGlobalProperties(["URL"]);
 
 function Bookmarks(aBookmarksFile) {
   this._file = aBookmarksFile;
 }
@@ -188,61 +186,65 @@ History.prototype = {
   // The visit date is stored as a string, so it's not read as a Date
   // object by PropertyListUtils.
   _parseCocoaDate: function H___parseCocoaDate(aCocoaDateStr) {
     let asDouble = parseFloat(aCocoaDateStr);
     if (!isNaN(asDouble)) {
       // reference date of NSDate.
       let date = new Date("1 January 2001, GMT");
       date.setMilliseconds(asDouble * 1000);
-      return date * 1000;
+      return date;
     }
-    return 0;
+    return new Date();
   },
 
   migrate: function H_migrate(aCallback) {
     PropertyListUtils.read(this._file, aDict => {
       try {
         if (!aDict)
           throw new Error("Could not read history property list");
         if (!aDict.has("WebHistoryDates"))
           throw new Error("Unexpected history-property list format");
 
-        // Safari's History file contains only top-level urls.  It does not
-        // distinguish between typed urls and linked urls.
-        let transType = PlacesUtils.history.TRANSITION_LINK;
-
-        let places = [];
+        let pageInfos = [];
         let entries = aDict.get("WebHistoryDates");
+        let failedOnce = false;
         for (let entry of entries) {
           if (entry.has("lastVisitedDate")) {
-            let visitDate = this._parseCocoaDate(entry.get("lastVisitedDate"));
+            let date = this._parseCocoaDate(entry.get("lastVisitedDate"));
             try {
-              places.push({ uri: NetUtil.newURI(entry.get("")),
-                            title: entry.get("title"),
-                            visits: [{ transitionType: transType,
-                                       visitDate }] });
+              pageInfos.push({
+                url: new URL(entry.get("")),
+                title: entry.get("title"),
+                visits: [{
+                  // Safari's History file contains only top-level urls.  It does not
+                  // distinguish between typed urls and linked urls.
+                  transition: PlacesUtils.history.TRANSITIONS.LINK,
+                  date,
+                }],
+              });
             } catch (ex) {
               // Safari's History file may contain malformed URIs which
               // will be ignored.
               Cu.reportError(ex);
+              failedOnce = true;
             }
           }
         }
-        if (places.length > 0) {
-          MigrationUtils.insertVisitsWrapper(places, {
-            ignoreErrors: true,
-            ignoreResults: true,
-            handleCompletion(updatedCount) {
-              aCallback(updatedCount > 0);
-            },
-          });
-        } else {
-          aCallback(false);
+        if (pageInfos.length == 0) {
+          // If we failed at least once, then we didn't succeed in importing,
+          // otherwise we didn't actually have anything to import, so we'll
+          // report it as a success.
+          aCallback(!failedOnce);
+          return;
         }
+
+        MigrationUtils.insertVisitsWrapper(pageInfos).then(
+          () => aCallback(true),
+          () => aCallback(false));
       } catch (ex) {
         Cu.reportError(ex);
         aCallback(false);
       }
     });
   },
 };
 
--- a/browser/components/migration/tests/unit/test_automigration.js
+++ b/browser/components/migration/tests/unit/test_automigration.js
@@ -1,16 +1,16 @@
 "use strict";
 
 ChromeUtils.import("resource:///modules/AutoMigrate.jsm", this);
 
 let gShimmedMigratorKeyPicker = null;
 let gShimmedMigrator = null;
 
-const kUsecPerMin = 60 * 1000000;
+const kMsecPerMin = 60 * 1000;
 
 // This is really a proxy on MigrationUtils, but if we specify that directly,
 // we get in trouble because the object itself is frozen, and Proxies can't
 // return a different value to an object when directly proxying a frozen
 // object.
 let AutoMigrateBackstage = ChromeUtils.import("resource:///modules/AutoMigrate.jsm", {});
 
 AutoMigrateBackstage.MigrationUtils = new Proxy({}, {
@@ -256,37 +256,37 @@ add_task(async function checkUndoRemoval
     title: "Some example bookmark",
   });
 
   let bookmark = await PlacesUtils.bookmarks.fetch({url: "http://www.example.org/"});
   Assert.ok(bookmark, "Should have a bookmark before undo");
   Assert.equal(bookmark.title, "Some example bookmark", "Should have correct bookmark before undo.");
 
   // Insert 2 history visits
-  let now_uSec = Date.now() * 1000;
+  let now = new Date();
   let visitedURI = Services.io.newURI("http://www.example.com/");
   let frecencyUpdatePromise = new Promise(resolve => {
     let observer = {
       onManyFrecenciesChanged() {
         PlacesUtils.history.removeObserver(observer);
         resolve();
       },
     };
     PlacesUtils.history.addObserver(observer);
   });
   await MigrationUtils.insertVisitsWrapper([{
-    uri: visitedURI,
+    url: visitedURI,
     visits: [
       {
-        transitionType: PlacesUtils.history.TRANSITION_LINK,
-        visitDate: now_uSec,
+        transition: PlacesUtils.history.TRANSITION_LINK,
+        date: now,
       },
       {
-        transitionType: PlacesUtils.history.TRANSITION_LINK,
-        visitDate: now_uSec - 100 * kUsecPerMin,
+        transition: PlacesUtils.history.TRANSITION_LINK,
+        date: new Date(now - 100 * kMsecPerMin),
       },
     ],
   }]);
   await frecencyUpdatePromise;
 
   // Verify that both visits get reported.
   let opts = PlacesUtils.history.getNewQueryOptions();
   opts.resultType = opts.RESULTS_AS_VISIT;
@@ -491,103 +491,103 @@ add_task(async function testLoginsRemova
   Assert.equal(1, LoginHelper.searchLoginsWithObject({hostname: "https://example.org", formSubmitURL: "https://example.org/"}).length,
                    "changed example.org entry should have persisted.");
   Services.logins.removeAllLogins();
 });
 
 add_task(async function checkUndoVisitsState() {
   MigrationUtils.initializeUndoData();
   await MigrationUtils.insertVisitsWrapper([{
-    uri: NetUtil.newURI("http://www.example.com/"),
+    url: NetUtil.newURI("http://www.example.com/"),
     title: "Example",
     visits: [{
-      visitDate: new Date("2015-07-10").getTime() * 1000,
-      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+      date: new Date("2015-07-10"),
+      transition: Ci.nsINavHistoryService.TRANSITION_LINK,
     }, {
-      visitDate: new Date("2015-09-10").getTime() * 1000,
-      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+      date: new Date("2015-09-10"),
+      transition: Ci.nsINavHistoryService.TRANSITION_LINK,
     }, {
-      visitDate: new Date("2015-08-10").getTime() * 1000,
-      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+      date: new Date("2015-08-10"),
+      transition: Ci.nsINavHistoryService.TRANSITION_LINK,
     }],
   }, {
-    uri: NetUtil.newURI("http://www.example.org/"),
+    url: Services.io.newURI("http://www.example.org/"),
     title: "Example",
     visits: [{
-      visitDate: new Date("2016-04-03").getTime() * 1000,
-      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+      date: new Date("2016-04-03"),
+      transition: Ci.nsINavHistoryService.TRANSITION_LINK,
     }, {
-      visitDate: new Date("2015-08-03").getTime() * 1000,
-      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+      date: new Date("2015-08-03"),
+      transition: Ci.nsINavHistoryService.TRANSITION_LINK,
     }],
   }, {
-    uri: NetUtil.newURI("http://www.example.com/"),
+    url: "http://www.example.com/",
     title: "Example",
     visits: [{
-      visitDate: new Date("2015-10-10").getTime() * 1000,
-      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+      date: new Date("2015-10-10"),
+      transition: Ci.nsINavHistoryService.TRANSITION_LINK,
     }],
   }]);
   let undoVisitData = (await MigrationUtils.stopAndRetrieveUndoData()).get("visits");
   Assert.deepEqual(Array.from(undoVisitData.map(v => v.url)).sort(),
                    ["http://www.example.com/", "http://www.example.org/"]);
   Assert.deepEqual(undoVisitData.find(v => v.url == "http://www.example.com/"), {
     url: "http://www.example.com/",
     visitCount: 4,
-    first: new Date("2015-07-10").getTime() * 1000,
-    last: new Date("2015-10-10").getTime() * 1000,
+    first: new Date("2015-07-10").getTime(),
+    last: new Date("2015-10-10").getTime(),
   });
   Assert.deepEqual(undoVisitData.find(v => v.url == "http://www.example.org/"), {
     url: "http://www.example.org/",
     visitCount: 2,
-    first: new Date("2015-08-03").getTime() * 1000,
-    last: new Date("2016-04-03").getTime() * 1000,
+    first: new Date("2015-08-03").getTime(),
+    last: new Date("2016-04-03").getTime(),
   });
 
   await PlacesUtils.history.clear();
 });
 
 add_task(async function checkUndoVisitsState() {
   MigrationUtils.initializeUndoData();
   await MigrationUtils.insertVisitsWrapper([{
-    uri: NetUtil.newURI("http://www.example.com/"),
+    url: NetUtil.newURI("http://www.example.com/"),
     title: "Example",
     visits: [{
-      visitDate: new Date("2015-07-10").getTime() * 1000,
-      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+      date: new Date("2015-07-10"),
+      transition: Ci.nsINavHistoryService.TRANSITION_LINK,
     }, {
-      visitDate: new Date("2015-09-10").getTime() * 1000,
-      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+      date: new Date("2015-09-10"),
+      transition: Ci.nsINavHistoryService.TRANSITION_LINK,
     }, {
-      visitDate: new Date("2015-08-10").getTime() * 1000,
-      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+      date: new Date("2015-08-10"),
+      transition: Ci.nsINavHistoryService.TRANSITION_LINK,
     }],
   }, {
-    uri: NetUtil.newURI("http://www.example.org/"),
+    url: NetUtil.newURI("http://www.example.org/"),
     title: "Example",
     visits: [{
-      visitDate: new Date("2016-04-03").getTime() * 1000,
-      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+      date: new Date("2016-04-03"),
+      transition: Ci.nsINavHistoryService.TRANSITION_LINK,
     }, {
-      visitDate: new Date("2015-08-03").getTime() * 1000,
-      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+      date: new Date("2015-08-03"),
+      transition: Ci.nsINavHistoryService.TRANSITION_LINK,
     }],
   }, {
-    uri: NetUtil.newURI("http://www.example.com/"),
+    url: NetUtil.newURI("http://www.example.com/"),
     title: "Example",
     visits: [{
-      visitDate: new Date("2015-10-10").getTime() * 1000,
-      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+      date: new Date("2015-10-10"),
+      transition: Ci.nsINavHistoryService.TRANSITION_LINK,
     }],
   }, {
-    uri: NetUtil.newURI("http://www.mozilla.org/"),
+    url: NetUtil.newURI("http://www.mozilla.org/"),
     title: "Example",
     visits: [{
-      visitDate: new Date("2015-01-01").getTime() * 1000,
-      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK,
+      date: new Date("2015-01-01"),
+      transition: Ci.nsINavHistoryService.TRANSITION_LINK,
     }],
   }]);
 
   // We have to wait until frecency updates have been handled in order
   // to accurately determine whether we're doing the right thing.
   let frecencyUpdatesHandled = new Promise(resolve => {
     PlacesUtils.history.addObserver({
       onManyFrecenciesChanged() {
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -816,33 +816,28 @@ var PlacesUIUtils = {
    * @param queryString
    *        the query string to check (a place: href)
    * @return whether or not queryString represents a folder shortcut.
    * @throws if queryString is malformed.
    */
   isFolderShortcutQueryString(queryString) {
     // Based on GetSimpleBookmarksQueryFolder in nsNavHistory.cpp.
 
-    let queriesParam = { }, optionsParam = { };
-    PlacesUtils.history.queryStringToQueries(queryString,
-                                             queriesParam,
-                                             { },
-                                             optionsParam);
-    let queries = queries.value;
-    if (queries.length == 0)
-      throw new Error(`Invalid place: uri: ${queryString}`);
-    return queries.length == 1 &&
-           queries[0].folderCount == 1 &&
-           !queries[0].hasBeginTime &&
-           !queries[0].hasEndTime &&
-           !queries[0].hasDomain &&
-           !queries[0].hasURI &&
-           !queries[0].hasSearchTerms &&
-           !queries[0].tags.length == 0 &&
-           optionsParam.value.maxResults == 0;
+    let query = {}, options = {};
+    PlacesUtils.history.queryStringToQuery(queryString, query, options);
+    query = query.value;
+    options = options.value;
+    return query.folderCount == 1 &&
+           !query.hasBeginTime &&
+           !query.hasEndTime &&
+           !query.hasDomain &&
+           !query.hasURI &&
+           !query.hasSearchTerms &&
+           !query.tags.length == 0 &&
+           options.maxResults == 0;
   },
 
   /**
    * Helpers for consumers of editBookmarkOverlay which don't have a node as their input.
    *
    * Given a bookmark object for either a url bookmark or a folder, returned by
    * Bookmarks.fetch (see Bookmark.jsm), this creates a node-like object suitable for
    * initialising the edit overlay with it.
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -48,23 +48,19 @@ PlacesViewBase.prototype = {
   _place: "",
   get place() {
     return this._place;
   },
   set place(val) {
     this._place = val;
 
     let history = PlacesUtils.history;
-    let queries = { }, options = { };
-    history.queryStringToQueries(val, queries, { }, options);
-    if (!queries.value.length)
-      queries.value = [history.getNewQuery()];
-
-    let result = history.executeQueries(queries.value, queries.value.length,
-                                        options.value);
+    let query = {}, options = {};
+    history.queryStringToQuery(val, query, options);
+    let result = history.executeQuery(query.value, options.value);
     result.addObserver(this);
     return val;
   },
 
   _result: null,
   get result() {
     return this._result;
   },
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -218,22 +218,22 @@ PlacesController.prototype = {
     case "placesCmd_paste":
       this.paste().catch(Cu.reportError);
       break;
     case "cmd_delete":
     case "placesCmd_delete":
       this.remove("Remove Selection").catch(Cu.reportError);
       break;
     case "placesCmd_deleteDataHost":
-      var host;
+      let host;
       if (PlacesUtils.nodeIsHost(this._view.selectedNode)) {
-        var queries = this._view.selectedNode.getQueries();
-        host = queries[0].domain;
-      } else
+        host = this._view.selectedNode.query.domain;
+      } else {
         host = Services.io.newURI(this._view.selectedNode.uri).host;
+      }
       let {ForgetAboutSite} = ChromeUtils.import("resource://gre/modules/ForgetAboutSite.jsm", {});
       ForgetAboutSite.removeDataFromDomain(host)
                      .catch(Cu.reportError);
       break;
     case "cmd_selectAll":
       this.selectAll();
       break;
     case "placesCmd_open":
@@ -905,17 +905,17 @@ PlacesController.prototype = {
    * @note history deletes are not undoable.
    */
   _removeHistoryContainer: function PC__removeHistoryContainer(aContainerNode) {
     if (PlacesUtils.nodeIsHost(aContainerNode)) {
       // Site container.
       PlacesUtils.history.removePagesFromHost(aContainerNode.title, true);
     } else if (PlacesUtils.nodeIsDay(aContainerNode)) {
       // Day container.
-      let query = aContainerNode.getQueries()[0];
+      let query = aContainerNode.query;
       let beginTime = query.beginTime;
       let endTime = query.endTime;
       if (!query || !beginTime || !endTime)
         throw new Error("A valid date container query should exist!");
       // We want to exclude beginTime from the removal because
       // removePagesByTimeframe includes both extremes, while date containers
       // exclude the lower extreme.  So, if we would not exclude it, we would
       // end up removing more history than requested.
--- a/browser/components/places/content/history-panel.js
+++ b/browser/components/places/content/history-panel.js
@@ -81,16 +81,16 @@ function searchHistory(aInput) {
   options.includeHidden = !!aInput;
 
   if (gHistoryGrouping == "lastvisited")
     this.TelemetryStopwatch.start("HISTORY_LASTVISITED_TREE_QUERY_TIME_MS");
 
   // call load() on the tree manually
   // instead of setting the place attribute in history-panel.xul
   // otherwise, we will end up calling load() twice
-  gHistoryTree.load([query], options);
+  gHistoryTree.load(query, options);
 
   if (gHistoryGrouping == "lastvisited")
     this.TelemetryStopwatch.finish("HISTORY_LASTVISITED_TREE_QUERY_TIME_MS");
 }
 
 window.addEventListener("SidebarFocused",
                         () => gSearchBox.focus());
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -390,23 +390,16 @@ var PlacesOrganizer = {
   /**
    * Returns the options associated with the query currently loaded in the
    * main places pane.
    */
   getCurrentOptions: function PO_getCurrentOptions() {
     return PlacesUtils.asQuery(ContentArea.currentView.result.root).queryOptions;
   },
 
-  /**
-   * Returns the queries associated with the query currently loaded in the
-   * main places pane.
-   */
-  getCurrentQueries: function PO_getCurrentQueries() {
-    return PlacesUtils.asQuery(ContentArea.currentView.result.root).getQueries();
-  },
 
   /**
    * Show the migration wizard for importing passwords,
    * cookies, history, preferences, and bookmarks.
    */
   importFromBrowser: function PO_importFromBrowser() {
     // We pass in the type of source we're using for use in telemetry:
     MigrationUtils.showMigrationWizard(window, [MigrationUtils.MIGRATION_ENTRYPOINT_PLACES]);
--- a/browser/components/places/content/tree.xml
+++ b/browser/components/places/content/tree.xml
@@ -93,27 +93,26 @@
 
           if (folderRestrict) {
             query.setFolders(folderRestrict, folderRestrict.length);
             options.queryType = options.QUERY_TYPE_BOOKMARKS;
           }
 
           options.includeHidden = !!includeHidden;
 
-          this.load([query], options);
+          this.load(query, options);
         ]]></body>
       </method>
 
       <method name="load">
-        <parameter name="queries"/>
+        <parameter name="query"/>
         <parameter name="options"/>
         <body><![CDATA[
           let result = PlacesUtils.history
-                                  .executeQueries(queries, queries.length,
-                                                  options);
+                                  .executeQuery(query, options);
           let callback;
           if (this.flatList) {
             let onOpenFlatContainer = this.onOpenFlatContainer;
             if (onOpenFlatContainer)
               callback = new Function("aContainer", onOpenFlatContainer);
           }
 
           if (!this._controller) {
@@ -283,26 +282,19 @@
       <!-- nsIPlacesView -->
       <property name="place">
         <getter><![CDATA[
           return this.getAttribute("place");
         ]]></getter>
         <setter><![CDATA[
           this.setAttribute("place", val);
 
-          var queriesRef = { };
-          var queryCountRef = { };
-          var optionsRef = { };
-          PlacesUtils.history.queryStringToQueries(val, queriesRef, queryCountRef, optionsRef);
-          if (queryCountRef.value == 0)
-            queriesRef.value = [PlacesUtils.history.getNewQuery()];
-          if (!optionsRef.value)
-            optionsRef.value = PlacesUtils.history.getNewQueryOptions();
-
-          this.load(queriesRef.value, optionsRef.value);
+          let query = {}, options = {};
+          PlacesUtils.history.queryStringToQuery(val, query, options);
+          this.load(query.value, options.value);
 
           return val;
         ]]></setter>
       </property>
 
       <!-- nsIPlacesView -->
       <property name="hasSelection">
         <getter><![CDATA[
--- a/browser/components/places/tests/browser/browser.ini
+++ b/browser/components/places/tests/browser/browser.ini
@@ -99,16 +99,17 @@ skip-if = os == "mac" && debug # bug 140
 [browser_toolbar_drop_text.js]
 [browser_toolbar_overflow.js]
 [browser_toolbarbutton_menu_context.js]
 [browser_views_iconsupdate.js]
 [browser_bug485100-change-case-loses-tag.js]
 [browser_editBookmark_tags_liveUpdate.js]
 [browser_bug427633_no_newfolder_if_noip.js]
 [browser_editBookmark_keywords.js]
+skip-if = (os == 'win' && ccov) # Bug 1423667
 [browser_bug631374_tags_selector_scroll.js]
 support-files =
   favicon-normal16.png
 [browser_views_liveupdate.js]
 [browser_bookmark_all_tabs.js]
 support-files =
   bookmark_dummy_1.html
   bookmark_dummy_2.html
--- a/browser/components/places/tests/browser/browser_library_middleclick.js
+++ b/browser/components/places/tests/browser/browser_library_middleclick.js
@@ -136,17 +136,17 @@ gTests.push({
     // Create a bookmarks query containing our bookmarks.
     var hs = PlacesUtils.history;
     var options = hs.getNewQueryOptions();
     options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
     var query = hs.getNewQuery();
     // The colon included in the terms selects only about: URIs. If not included
     // we also may get pages like about.html included in the query result.
     query.searchTerms = "about:";
-    var queryString = hs.queriesToQueryString([query], 1, options);
+    var queryString = hs.queryToQueryString(query, options);
     this._query = await PlacesUtils.bookmarks.insert({
       index: 0, // it must be the first
       parentGuid: PlacesUtils.bookmarks.unfiledGuid,
       title: "Query",
       url: queryString,
     });
 
     // Select unsorted bookmarks root in the left pane.
--- a/browser/components/places/tests/browser/browser_library_search.js
+++ b/browser/components/places/tests/browser/browser_library_search.js
@@ -61,23 +61,23 @@ async function search(aFolderGuid, aSear
     }
   }
 
   // Second, ensure that searching updates the content tree and search UI
   // properly.
   let searchBox = doc.getElementById("searchFilter");
   searchBox.value = aSearchStr;
   gLibrary.PlacesSearchBox.search(searchBox.value);
-  let queries = {};
-  PlacesUtils.history.queryStringToQueries(contentTree.result.root.uri, queries, {}, {});
+  let query = {};
+  PlacesUtils.history.queryStringToQuery(contentTree.result.root.uri, query, {});
   if (aSearchStr) {
-    Assert.equal(queries.value[0].searchTerms, aSearchStr,
+    Assert.equal(query.value.searchTerms, aSearchStr,
       "Content tree's searchTerms should be text in search box");
   } else {
-    Assert.equal(queries.value[0].hasSearchTerms, false,
+    Assert.equal(query.value.hasSearchTerms, false,
       "Content tree's searchTerms should not exist after search reset");
   }
 }
 
 add_task(async function test() {
   // Add visits, a bookmark and a tag.
   await PlacesTestUtils.addVisits(
     [{ uri: Services.io.newURI(TEST_URL), visitDate: Date.now() * 1000,
--- a/browser/components/places/tests/chrome/test_0_bug510634.xul
+++ b/browser/components/places/tests/chrome/test_0_bug510634.xul
@@ -49,18 +49,17 @@
 
       // The query-property is set on the title column for each row.
       let titleColumn = tree.treeBoxObject.columns.getColumnAt(0);
 
       // Open All Bookmarks
       tree.selectItems([PlacesUtils.virtualAllBookmarksGuid]);
       PlacesUtils.asContainer(tree.selectedNode).containerOpen = true;
       is(tree.selectedNode.uri,
-         "place:type=" + Ci.nsINavHistoryQueryOptions.RESULTS_AS_ROOTS_QUERY +
-         "&queryType=" + Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS,
+         "place:type=" + Ci.nsINavHistoryQueryOptions.RESULTS_AS_ROOTS_QUERY,
          "Opened All Bookmarks");
 
       const topLevelGuids = [
         PlacesUtils.virtualHistoryGuid,
         PlacesUtils.virtualDownloadsGuid,
         PlacesUtils.virtualTagsGuid,
         PlacesUtils.virtualAllBookmarksGuid
       ];
--- a/browser/components/places/tests/chrome/test_bug549192.xul
+++ b/browser/components/places/tests/chrome/test_bug549192.xul
@@ -85,17 +85,17 @@
              visitDate: newTimeInMicroseconds(), transition: ttype }];
 
         await PlacesTestUtils.addVisits(places);
 
         // Make a history query.
         let query = PlacesUtils.history.getNewQuery();
         let opts = PlacesUtils.history.getNewQueryOptions();
         opts.sortingMode = opts.SORT_BY_DATE_DESCENDING;
-        let queryURI = PlacesUtils.history.queriesToQueryString([query], 1, opts);
+        let queryURI = PlacesUtils.history.queryToQueryString(query, opts);
 
         // Setup the places tree contents.
         var tree = document.getElementById("tree");
         tree.place = queryURI;
 
         // loop through the rows and check them.
         let treeView = tree.view;
         let selection = treeView.selection;
--- a/browser/components/places/tests/chrome/test_bug549491.xul
+++ b/browser/components/places/tests/chrome/test_bug549491.xul
@@ -52,17 +52,17 @@
         await PlacesTestUtils.addVisits({
           uri: Services.io.newURI("http://example.tld/"),
           transition: PlacesUtils.history.TRANSITION_TYPED
         });
 
         // Make a history query.
         let query = PlacesUtils.history.getNewQuery();
         let opts = PlacesUtils.history.getNewQueryOptions();
-        let queryURI = PlacesUtils.history.queriesToQueryString([query], 1, opts);
+        let queryURI = PlacesUtils.history.queryToQueryString(query, opts);
 
         // Setup the places tree contents.
         let tree = document.getElementById("tree");
         tree.place = queryURI;
 
         let rootNode = tree.result.root;
         let obs = tree.view.QueryInterface(Ci.nsINavHistoryResultObserver);
         obs.nodeHistoryDetailsChanged(rootNode, rootNode.time, rootNode.accessCount);
--- a/browser/components/places/tests/chrome/test_treeview_date.xul
+++ b/browser/components/places/tests/chrome/test_treeview_date.xul
@@ -86,17 +86,17 @@
           url: "http://at.midnight.com/",
           title: "A bookmark at midnight",
           type: PlacesUtils.bookmarks.TYPE_BOOKMARK
         });
 
         // Make a history query.
         let query = PlacesUtils.history.getNewQuery();
         let opts = PlacesUtils.history.getNewQueryOptions();
-        let queryURI = PlacesUtils.history.queriesToQueryString([query], 1, opts);
+        let queryURI = PlacesUtils.history.queryToQueryString(query, opts);
 
         // Setup the places tree contents.
         let tree = document.getElementById("tree");
         tree.place = queryURI;
 
         // loop through the rows and check formatting
         let treeView = tree.view;
         let rc = treeView.rowCount;
--- a/browser/components/shell/nsGNOMEShellService.cpp
+++ b/browser/components/shell/nsGNOMEShellService.cpp
@@ -210,17 +210,17 @@ NS_IMETHODIMP
 nsGNOMEShellService::IsDefaultBrowser(bool aStartupCheck,
                                       bool aForAllTypes,
                                       bool* aIsDefaultBrowser)
 {
   *aIsDefaultBrowser = false;
 
   if (IsRunningAsASnap()) {
     const gchar *argv[] = { "xdg-settings", "check", "default-web-browser",
-                            "firefox_firefox.desktop", nullptr };
+                            "firefox.desktop", nullptr };
     GSpawnFlags flags = static_cast<GSpawnFlags>(G_SPAWN_SEARCH_PATH |
                                                  G_SPAWN_STDERR_TO_DEV_NULL);
     gchar *output = nullptr;
     gint exit_status = 0;
     if (!g_spawn_sync(nullptr, (gchar **) argv, nullptr, flags, nullptr,
                       nullptr, &output, nullptr, &exit_status, nullptr)) {
       return NS_OK;
     }
@@ -282,17 +282,17 @@ nsGNOMEShellService::SetDefaultBrowser(b
 {
 #ifdef DEBUG
   if (aForAllUsers)
     NS_WARNING("Setting the default browser for all users is not yet supported");
 #endif
 
   if (IsRunningAsASnap()) {
     const gchar *argv[] = { "xdg-settings", "set", "default-web-browser",
-                            "firefox_firefox.desktop", nullptr };
+                            "firefox.desktop", nullptr };
     GSpawnFlags flags = static_cast<GSpawnFlags>(G_SPAWN_SEARCH_PATH |
                                                  G_SPAWN_STDOUT_TO_DEV_NULL |
                                                  G_SPAWN_STDERR_TO_DEV_NULL);
     g_spawn_sync(nullptr, (gchar **) argv, nullptr, flags, nullptr, nullptr,
                  nullptr, nullptr, nullptr, nullptr);
     return NS_OK;
   }
 
--- a/browser/locales/en-US/browser/preferences/preferences.ftl
+++ b/browser/locales/en-US/browser/preferences/preferences.ftl
@@ -11,21 +11,16 @@ do-not-track-option-always =
 
 pref-page =
     .title =
         { PLATFORM() ->
             [windows] Options
            *[other] Preferences
         }
 
-# This string is currently used only in Firefox 60 and will be removed when not
-# needed for x-channel. See bug 1445686 for details.
-search-input =
-    .style = width: 15.4em
-
 # This is used to determine the width of the search field in about:preferences,
 # in order to make the entire placeholder string visible
 #
 # Please keep the placeholder string short to avoid truncation.
 #
 # Notice: The value of the `.style` attribute is a CSS string, and the `width`
 # is the name of the CSS property. It is intended only to adjust the element's width.
 # Do not translate.
--- a/browser/modules/AsyncTabSwitcher.jsm
+++ b/browser/modules/AsyncTabSwitcher.jsm
@@ -9,16 +9,23 @@ var EXPORTED_SYMBOLS = ["AsyncTabSwitche
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetters(this, {
   AppConstants: "resource://gre/modules/AppConstants.jsm",
   Services: "resource://gre/modules/Services.jsm",
   TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm",
 });
 
+XPCOMUtils.defineLazyPreferenceGetter(this, "gTabWarmingEnabled",
+  "browser.tabs.remote.warmup.enabled");
+XPCOMUtils.defineLazyPreferenceGetter(this, "gTabWarmingMax",
+  "browser.tabs.remote.warmup.maxTabs");
+XPCOMUtils.defineLazyPreferenceGetter(this, "gTabWarmingUnloadDelayMs",
+  "browser.tabs.remote.warmup.unloadDelayMs");
+
 /**
  * The tab switcher is responsible for asynchronously switching
  * tabs in e10s. It waits until the new tab is ready (i.e., the
  * layer tree is available) before switching to it. Then it
  * unloads the layer tree for the old tab.
  *
  * The tab switcher is a state machine. For each tab, it
  * maintains state about whether the layer tree for the tab is
@@ -596,17 +603,17 @@ class AsyncTabSwitcher {
     // handlers, which might cause finish() to already have been called.
     // Check for that before calling finish() again.
     if (!this.tabbrowser._switcher) {
       return;
     }
 
     this.maybeFinishTabSwitch();
 
-    if (numWarming > this.tabbrowser.tabWarmingMax) {
+    if (numWarming > gTabWarmingMax) {
       this.logState("Hit tabWarmingMax");
       if (this.unloadTimer) {
         this.clearTimer(this.unloadTimer);
       }
       this.unloadNonRequiredTabs();
     }
 
     if (numPending == 0) {
@@ -816,17 +823,17 @@ class AsyncTabSwitcher {
     if (state != this.STATE_LOADING &&
         state != this.STATE_LOADED) {
       this.setTabState(tab, this.STATE_LOADING);
       this.logState("Activated browser " + this.tinfo(tab) + " for print preview");
     }
   }
 
   canWarmTab(tab) {
-    if (!this.tabbrowser.tabWarmingEnabled) {
+    if (!gTabWarmingEnabled) {
       return false;
     }
 
     if (!tab) {
       return false;
     }
 
     // If the tab is not yet inserted, closing, not remote,
@@ -865,27 +872,26 @@ class AsyncTabSwitcher {
     if (!this.shouldWarmTab(tab)) {
       return;
     }
 
     this.logState("warmupTab " + this.tinfo(tab));
 
     this.warmingTabs.add(tab);
     this.setTabState(tab, this.STATE_LOADING);
-    this.suppressDisplayPortAndQueueUnload(tab,
-      this.tabbrowser.tabWarmingUnloadDelay);
+    this.suppressDisplayPortAndQueueUnload(tab, gTabWarmingUnloadDelayMs);
   }
 
   // Called when the user asks to switch to a given tab.
   requestTab(tab) {
     if (tab === this.requestedTab) {
       return;
     }
 
-    if (this.tabbrowser.tabWarmingEnabled) {
+    if (gTabWarmingEnabled) {
       let warmingState = "disqualified";
 
       if (this.canWarmTab(tab)) {
         let tabState = this.getTabState(tab);
         if (tabState == this.STATE_LOADING) {
           warmingState = "stillLoading";
         } else if (tabState == this.STATE_LOADED) {
           warmingState = "loaded";
--- a/browser/modules/WindowsJumpLists.jsm
+++ b/browser/modules/WindowsJumpLists.jsm
@@ -397,17 +397,17 @@ var WinTaskbarJumpList =
   function WTBLJL__getHistoryResults(aSortingMode, aLimit, aCallback, aScope) {
     var options = PlacesUtils.history.getNewQueryOptions();
     options.maxResults = aLimit;
     options.sortingMode = aSortingMode;
     var query = PlacesUtils.history.getNewQuery();
 
     // Return the pending statement to the caller, to allow cancelation.
     return PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                              .asyncExecuteLegacyQueries([query], 1, options, {
+                              .asyncExecuteLegacyQuery(query, options, {
       handleResult(aResultSet) {
         for (let row; (row = aResultSet.getNextRow());) {
           try {
             aCallback.call(aScope,
                            { uri: row.getResultByIndex(1),
                              title: row.getResultByIndex(2)
                            });
           } catch (e) {}
--- a/config/mozunit.py
+++ b/config/mozunit.py
@@ -227,14 +227,14 @@ def main(*args, **kwargs):
         unittest.main(testRunner=MozTestRunner(), *args, **kwargs)
     else:
         args = list(args)
         if os.environ.get('MACH_STDOUT_ISATTY') and not any(a.startswith('--color') for a in args):
             args.append('--color=yes')
 
         module = __import__('__main__')
         args.extend([
-            '--verbose',
+            '-vv',
             '-p', 'mozlog.pytest_mozlog.plugin',
             '-p', 'no:cacheprovider',
             module.__file__,
         ])
         sys.exit(pytest.main(args))
--- a/devtools/client/debugger/content/views/sources-view.js
+++ b/devtools/client/debugger/content/views/sources-view.js
@@ -1093,17 +1093,17 @@ SourcesView.prototype = extend(WidgetMet
   _onStopBlackBoxing: Task.async(function* () {
     this.actions.blackbox(getSelectedSource(this.getState()), false);
   }),
 
   /**
    * The source editor's contextmenu handler.
    * - Toggles "Add Conditional Breakpoint" and "Edit Conditional Breakpoint" items
    */
-  _onEditorContextMenuOpen: function (message, ev, popup) {
+  _onEditorContextMenuOpen: function (ev, popup) {
     let actor = this.selectedValue;
     let line = this.DebuggerView.editor.getCursor().line + 1;
     let location = { actor, line };
 
     let breakpoint = getBreakpoint(this.getState(), location);
     let addConditionalBreakpointMenuItem = popup.querySelector("#se-dbg-cMenu-addConditionalBreakpoint");
     let editConditionalBreakpointMenuItem = popup.querySelector("#se-dbg-cMenu-editConditionalBreakpoint");
 
--- a/devtools/client/debugger/debugger-view.js
+++ b/devtools/client/debugger/debugger-view.js
@@ -269,17 +269,17 @@ var DebuggerView = {
     });
 
     this.editor.appendTo(document.getElementById("editor")).then(() => {
       this.editor.extend(DebuggerEditor);
       this._loadingText = L10N.getStr("loadingText");
       callback();
     });
 
-    this.editor.on("gutterClick", (ev, line, button) => {
+    this.editor.on("gutterClick", (line, button) => {
       // A right-click shouldn't do anything but keep track of where
       // it was clicked.
       if (button == 2) {
         this.clickedLine = line;
       }
       else {
         const source = queries.getSelectedSource(this.controller.getState());
         if (source) {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-editor.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-editor.js
@@ -62,33 +62,31 @@ function test() {
     });
 
     callInTab(gTab, "firstCall");
 
     let breakpointsAdded = 0;
     let breakpointsRemoved = 0;
     let editorBreakpointChanges = 0;
 
-    function onEditorBreakpointAddFirst(aEvent, aLine) {
+    function onEditorBreakpointAddFirst(aLine) {
       editorBreakpointChanges++;
 
-      ok(aEvent,
-         "breakpoint1 added to the editor.");
+      info("breakpoint1 added to the editor.");
       is(aLine, 5,
          "Editor breakpoint line is correct.");
 
       is(gEditor.getBreakpoints().length, 1,
          "editor.getBreakpoints().length is correct.");
     }
 
-    function onEditorBreakpointRemoveFirst(aEvent, aLine) {
+    function onEditorBreakpointRemoveFirst(aLine) {
       editorBreakpointChanges++;
 
-      ok(aEvent,
-         "breakpoint1 removed from the editor.");
+      info("breakpoint1 removed from the editor.");
       is(aLine, 5,
          "Editor breakpoint line is correct.");
 
       is(gEditor.getBreakpoints().length, 0,
          "editor.getBreakpoints().length is correct.");
     }
 
     function checkFirstBreakpoint(location) {
@@ -154,21 +152,20 @@ function test() {
 
       is(queries.getSelectedSource(getState()).actor, gSources.values[1],
          "The second source should be currently selected.");
 
       // Remove the trap listener.
       gEditor.off("breakpointAdded", onEditorBreakpointAddBackgroundTrap);
     }
 
-    function onEditorBreakpointAddSwitch(aEvent, aLine) {
+    function onEditorBreakpointAddSwitch(aLine) {
       editorBreakpointChanges++;
 
-      ok(aEvent,
-        "breakpoint2 added to the editor.");
+      info("breakpoint2 added to the editor.");
       is(aLine, 4,
         "Editor breakpoint line is correct.");
 
       is(gEditor.getBreakpoints().length, 1,
         "editor.getBreakpoints().length is correct");
     }
 
     function onEditorTextChanged() {
@@ -202,21 +199,20 @@ function test() {
       let coords = gEditor.getCoordsFromPosition({ line: 4, ch: 0 });
       let rect = iframe.getBoundingClientRect();
       let left = rect.left + 10;
       let top = rect.top + coords.top + 4;
       utils.sendMouseEventToWindow("mousedown", left, top, 0, 1, 0, false, 0, 0);
       utils.sendMouseEventToWindow("mouseup", left, top, 0, 1, 0, false, 0, 0);
     }
 
-    function onEditorBreakpointRemoveSecond(aEvent, aLine) {
+    function onEditorBreakpointRemoveSecond(aLine) {
       editorBreakpointChanges++;
 
-      ok(aEvent,
-        "breakpoint2 removed from the editor.");
+      info("breakpoint2 removed from the editor.");
       is(aLine, 4,
         "Editor breakpoint line is correct.");
 
       is(gEditor.getBreakpoints().length, 0,
         "editor.getBreakpoints().length is correct.");
 
       waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED).then(() => {
         finalCheck();
--- a/devtools/client/netmonitor/src/connector/firefox-data-provider.js
+++ b/devtools/client/netmonitor/src/connector/firefox-data-provider.js
@@ -179,18 +179,20 @@ class FirefoxDataProvider {
 
       // Calculate total header size and don't forget to include
       // two new-line characters at the end.
       const headersSize = headers.reduce((acc, { name, value }) => {
         return acc + name.length + value.length + 2;
       }, 0);
 
       requestPostData.postData.text = postData;
-      payload.requestPostData = Object.assign({}, requestPostData);
-      payload.requestHeadersFromUploadStream = { headers, headersSize };
+      payload.requestPostData = {
+        ...requestPostData,
+        uploadHeaders: { headers, headersSize }
+      };
     }
     return payload;
   }
 
   async fetchRequestCookies(requestCookies) {
     let payload = {};
     if (requestCookies) {
       let reqCookies = [];
@@ -535,17 +537,17 @@ class FirefoxDataProvider {
    *
    * @param {object} response the message received from the server.
    */
   async onRequestPostData(response) {
     let payload = await this.updateRequest(response.from, {
       requestPostData: response
     });
     emit(EVENTS.RECEIVED_REQUEST_POST_DATA, response.from);
-    return payload;
+    return payload.requestPostData;
   }
 
   /**
    * Handles additional information received for a "securityInfo" packet.
    *
    * @param {object} response the message received from the server.
    */
   async onSecurityInfo(response) {
--- a/devtools/client/netmonitor/src/har/har-builder.js
+++ b/devtools/client/netmonitor/src/har/har-builder.js
@@ -263,19 +263,18 @@ HarBuilder.prototype = {
     // When using HarAutomation, HarCollector will automatically fetch requestPostData
     // and requestHeaders, but when we use it from netmonitor, FirefoxDataProvider
     // should fetch it itself lazily, via requestData.
     let requestPostData = file.requestPostData;
     let requestHeaders = file.requestHeaders;
     let requestHeadersFromUploadStream;
 
     if (!requestPostData && this._options.requestData) {
-      let payload = await this._options.requestData(file.id, "requestPostData");
-      requestPostData = payload.requestPostData;
-      requestHeadersFromUploadStream = payload.requestHeadersFromUploadStream;
+      requestPostData = await this._options.requestData(file.id, "requestPostData");
+      requestHeadersFromUploadStream = requestPostData.uploadHeaders;
     }
 
     if (!requestPostData.postData.text) {
       return undefined;
     }
 
     if (!requestHeaders && this._options.requestData) {
       requestHeaders = await this._options.requestData(file.id, "requestHeaders");
--- a/devtools/client/netmonitor/src/utils/request-utils.js
+++ b/devtools/client/netmonitor/src/utils/request-utils.js
@@ -471,20 +471,17 @@ function processNetworkUpdates(request =
       switch (key) {
         case "securityInfo":
           result.securityState = value.state;
           break;
         case "totalTime":
           result.totalTime = request.totalTime;
           break;
         case "requestPostData":
-          result.requestHeadersFromUploadStream = {
-            headers: [],
-            headersSize: 0,
-          };
+          result.requestHeadersFromUploadStream = value.uploadHeaders;
           break;
       }
     }
   }
   return result;
 }
 
 module.exports = {
--- a/devtools/client/netmonitor/src/widgets/RequestListContextMenu.js
+++ b/devtools/client/netmonitor/src/widgets/RequestListContextMenu.js
@@ -266,32 +266,35 @@ class RequestListContextMenu {
   }
 
   /**
    * Copy the request form data parameters (or raw payload) from
    * the currently selected item.
    */
   async copyPostData(id, formDataSections, requestPostData) {
     let params = [];
-    // Try to extract any form data parameters.
-    formDataSections.forEach(section => {
-      let paramsArray = parseQueryString(section);
-      if (paramsArray) {
-        params = [...params, ...paramsArray];
-      }
-    });
+    // Try to extract any form data parameters if formDataSections is already
+    // available, which is only true if ParamsPanel has ever been mounted before.
+    if (formDataSections) {
+      formDataSections.forEach(section => {
+        let paramsArray = parseQueryString(section);
+        if (paramsArray) {
+          params = [...params, ...paramsArray];
+        }
+      });
+    }
 
     let string = params
       .map(param => param.name + (param.value ? "=" + param.value : ""))
       .join(Services.appinfo.OS === "WINNT" ? "\r\n" : "\n");
 
     // Fall back to raw payload.
     if (!string) {
       requestPostData = requestPostData ||
-        await this.props.connector.requestData(id, "requestPostData").requestPostData;
+        await this.props.connector.requestData(id, "requestPostData");
 
       string = requestPostData.postData.text;
       if (Services.appinfo.OS !== "WINNT") {
         string = string.replace(/\r/g, "");
       }
     }
     copyString(string);
   }
@@ -299,17 +302,17 @@ class RequestListContextMenu {
   /**
    * Copy a cURL command from the currently selected item.
    */
   async copyAsCurl(id, url, method, httpVersion, requestHeaders, requestPostData) {
     requestHeaders = requestHeaders ||
       await this.props.connector.requestData(id, "requestHeaders");
 
     requestPostData = requestPostData ||
-      await this.props.connector.requestData(id, "requestPostData").requestPostData;
+      await this.props.connector.requestData(id, "requestPostData");
 
     // Create a sanitized object for the Curl command generator.
     let data = {
       url,
       method,
       headers: requestHeaders.headers,
       httpVersion,
       postDataText: requestPostData ? requestPostData.postData.text : "",
--- a/devtools/client/netmonitor/test/browser_net_copy_as_curl.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_as_curl.js
@@ -20,70 +20,104 @@ add_task(async function() {
   }
 
   // Header param is formatted as -H "Header: value" or -H 'Header: value'
   function header(h) {
     return "-H " + quote(h);
   }
 
   // Construct the expected command
-  const EXPECTED_RESULT = [
+  const BASE_RESULT = [
     "curl " + quote(SIMPLE_SJS),
     "--compressed",
     header("Host: example.com"),
     header("User-Agent: " + navigator.userAgent),
     header("Accept: */*"),
     header("Accept-Language: " + navigator.language),
     header("X-Custom-Header-1: Custom value"),
     header("X-Custom-Header-2: 8.8.8.8"),
     header("X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT"),
     header("Referer: " + CURL_URL),
     header("Connection: keep-alive"),
     header("Pragma: no-cache"),
     header("Cache-Control: no-cache")
   ];
 
-  let { document } = monitor.panelWin;
-
-  let wait = waitForNetworkEvents(monitor, 1);
-  await ContentTask.spawn(tab.linkedBrowser, SIMPLE_SJS, async function(url) {
-    content.wrappedJSObject.performRequest(url);
-  });
-  await wait;
+  const COOKIE_PARTIAL_RESULT = [
+    header("Cookie: bob=true; tom=cool")
+  ];
 
-  EventUtils.sendMouseEvent({ type: "mousedown" },
-    document.querySelectorAll(".request-list-item")[0]);
-  EventUtils.sendMouseEvent({ type: "contextmenu" },
-    document.querySelectorAll(".request-list-item")[0]);
+  const POST_PAYLOAD = "Plaintext value as a payload";
+  const POST_PARTIAL_RESULT = [
+    "--data " + quote(POST_PAYLOAD),
+    header("Content-Type: text/plain;charset=UTF-8")
+  ];
 
-  await waitForClipboardPromise(function setup() {
-    monitor.panelWin.parent.document
-      .querySelector("#request-list-context-copy-as-curl").click();
-  }, function validate(result) {
-    if (typeof result !== "string") {
-      return false;
-    }
+  // GET request, no cookies (first request)
+  await performRequest(null);
+  await testClipboardContent(BASE_RESULT);
 
-    // Different setups may produce the same command, but with the
-    // parameters in a different order in the commandline (which is fine).
-    // Here we confirm that the commands are the same even in that case.
-
-    // This monster regexp parses the command line into an array of arguments,
-    // recognizing quoted args with matching quotes and escaped quotes inside:
-    // [ "curl 'url'", "--standalone-arg", "-arg-with-quoted-string 'value\'s'" ]
-    let matchRe = /[-A-Za-z1-9]+(?: ([\"'])(?:\\\1|.)*?\1)?/g;
-
-    let actual = result.match(matchRe);
+  // GET request, cookies set by previous response
+  await performRequest(null);
+  await testClipboardContent([
+    ...BASE_RESULT,
+    ...COOKIE_PARTIAL_RESULT
+  ]);
 
-    // Must begin with the same "curl 'URL'" segment
-    if (!actual || EXPECTED_RESULT[0] != actual[0]) {
-      return false;
-    }
-
-    // Must match each of the params in the middle (headers and --compressed)
-    return EXPECTED_RESULT.length === actual.length &&
-      EXPECTED_RESULT.every(param => actual.includes(param));
-  });
-
-  info("Clipboard contains a cURL command for the currently selected item's url.");
+  // POST request
+  await performRequest(POST_PAYLOAD);
+  await testClipboardContent([
+    ...BASE_RESULT,
+    ...COOKIE_PARTIAL_RESULT,
+    ...POST_PARTIAL_RESULT
+  ]);
 
   await teardown(monitor);
+
+  async function performRequest(payload) {
+    let wait = waitForNetworkEvents(monitor, 1);
+    await ContentTask.spawn(tab.linkedBrowser, {
+      url: SIMPLE_SJS, payload_: payload
+    }, async function({url, payload_}) {
+      content.wrappedJSObject.performRequest(url, payload_);
+    });
+    await wait;
+  }
+
+  async function testClipboardContent(expectedResult) {
+    let { document } = monitor.panelWin;
+
+    const items = document.querySelectorAll(".request-list-item");
+    EventUtils.sendMouseEvent({ type: "mousedown" }, items[items.length - 1]);
+    EventUtils.sendMouseEvent({ type: "contextmenu" },
+      document.querySelectorAll(".request-list-item")[0]);
+
+    await waitForClipboardPromise(function setup() {
+      monitor.panelWin.parent.document
+        .querySelector("#request-list-context-copy-as-curl").click();
+    }, function validate(result) {
+      if (typeof result !== "string") {
+        return false;
+      }
+
+      // Different setups may produce the same command, but with the
+      // parameters in a different order in the commandline (which is fine).
+      // Here we confirm that the commands are the same even in that case.
+
+      // This monster regexp parses the command line into an array of arguments,
+      // recognizing quoted args with matching quotes and escaped quotes inside:
+      // [ "curl 'url'", "--standalone-arg", "-arg-with-quoted-string 'value\'s'" ]
+      let matchRe = /[-A-Za-z1-9]+(?: ([\"'])(?:\\\1|.)*?\1)?/g;
+
+      let actual = result.match(matchRe);
+      // Must begin with the same "curl 'URL'" segment
+      if (!actual || expectedResult[0] != actual[0]) {
+        return false;
+      }
+
+      // Must match each of the params in the middle (headers and --compressed)
+      return expectedResult.length === actual.length &&
+        expectedResult.every(param => actual.includes(param));
+    });
+
+    info("Clipboard contains a cURL command for the currently selected item's url.");
+  }
 });
--- a/devtools/client/netmonitor/test/browser_net_curl-utils.js
+++ b/devtools/client/netmonitor/test/browser_net_curl-utils.js
@@ -253,17 +253,17 @@ async function createCurlData(selected, 
 
   let requestHeaders = await requestData(id, "requestHeaders");
   // Fetch header values.
   for (let { name, value } of requestHeaders.headers) {
     let text = await getLongString(value);
     data.headers.push({ name: name, value: text });
   }
 
-  let { requestPostData } = await requestData(id, "requestPostData");
+  let requestPostData = await requestData(id, "requestPostData");
   // Fetch the request payload.
   if (requestPostData) {
     let postData = requestPostData.postData.text;
     data.postDataText = await getLongString(postData);
   }
 
   return data;
 }
--- a/devtools/client/netmonitor/test/html_copy-as-curl.html
+++ b/devtools/client/netmonitor/test/html_copy-as-curl.html
@@ -7,27 +7,28 @@
     <meta charset="utf-8"/>
     <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
     <meta http-equiv="Pragma" content="no-cache" />
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
-    <p>Performing a GET request</p>
+    <p>Performing a GET or POST request</p>
 
     <script type="text/javascript">
       /* exported performRequest */
       "use strict";
 
-      function performRequest(url) {
+      function performRequest(url, payload) {
         let xhr = new XMLHttpRequest();
-        xhr.open("GET", url, true);
+        let method = payload ? "POST" : "GET";
+        xhr.open(method, url, true);
         xhr.setRequestHeader("Accept-Language", window.navigator.language);
         xhr.setRequestHeader("X-Custom-Header-1", "Custom value");
         xhr.setRequestHeader("X-Custom-Header-2", "8.8.8.8");
         xhr.setRequestHeader("X-Custom-Header-3", "Mon, 3 Mar 2014 11:11:11 GMT");
-        xhr.send(null);
+        xhr.send(payload);
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/sourceeditor/editor.js
+++ b/devtools/client/sourceeditor/editor.js
@@ -25,17 +25,17 @@ const VALID_KEYMAPS = new Set(["emacs", 
 const MAX_VERTICAL_OFFSET = 3;
 
 // Match @Scratchpad/N:LINE[:COLUMN] or (LINE[:COLUMN]) anywhere at an end of
 // line in text selection.
 const RE_SCRATCHPAD_ERROR = /(?:@Scratchpad\/\d+:|\()(\d+):?(\d+)?(?:\)|\n)/;
 const RE_JUMP_TO_LINE = /^(\d+):?(\d+)?/;
 
 const Services = require("Services");
-const events = require("devtools/shared/old-event-emitter");
+const EventEmitter = require("devtools/shared/event-emitter");
 const { PrefObserver } = require("devtools/client/shared/prefs");
 const { getClientCssProperties } = require("devtools/shared/fronts/css-properties");
 const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
 
 const {LocalizationHelper} = require("devtools/shared/l10n");
 const L10N = new LocalizationHelper("devtools/client/locales/sourceeditor.properties");
 
 const {
@@ -203,17 +203,17 @@ function Editor(config) {
   if (this.config.cssProperties) {
     // Ensure that autocompletion has cssProperties if it's passed in via the options.
     this.config.autocompleteOpts.cssProperties = this.config.cssProperties;
   } else {
     // Use a static client-side database of CSS values if none is provided.
     this.config.cssProperties = getClientCssProperties();
   }
 
-  events.decorate(this);
+  EventEmitter.decorate(this);
 }
 
 Editor.prototype = {
   container: null,
   version: null,
   config: null,
   Doc: null,
 
--- a/devtools/server/actors/highlighters/css-grid.js
+++ b/devtools/server/actors/highlighters/css-grid.js
@@ -1062,16 +1062,23 @@ class CssGridHighlighter extends AutoRef
       } else {
         endPos = this._winDimensions.width;
         startPos = -endPos;
       }
       drawRect(this.ctx, startPos, linePos, endPos, linePos + breadth,
         this.currentMatrix);
     }
 
+    // Find current angle of grid by measuring the angle of two arbitrary points,
+    // then rotate canvas, so the hash pattern stays 45deg to the gridlines.
+    let p1 = apply(this.currentMatrix, [0, 0]);
+    let p2 = apply(this.currentMatrix, [1, 0]);
+    let angleRad = Math.atan2(p2[1] - p1[1], p2[0] - p1[0]);
+    this.ctx.rotate(angleRad);
+
     this.ctx.fill();
     this.ctx.restore();
   }
 
   /**
    * Render the grid line name highlight for the given grid fragment index, lineNumber,
    * and dimensionType.
    *
--- a/devtools/server/actors/highlighters/flexbox.js
+++ b/devtools/server/actors/highlighters/flexbox.js
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { AutoRefreshHighlighter } = require("./auto-refresh");
+const { apply } = require("devtools/shared/layout/dom-matrix-2d");
 const {
   CANVAS_SIZE,
   DEFAULT_COLOR,
   clearRect,
   drawLine,
   drawRect,
   getCurrentMatrix,
   updateCanvasElement,
@@ -359,16 +360,23 @@ class FlexboxHighlighter extends AutoRef
     this.ctx.setLineDash(FLEXBOX_LINES_PROPERTIES.edge.lineDash);
     this.ctx.lineWidth = 0;
     this.ctx.strokeStyle = DEFAULT_COLOR;
     this.ctx.fillStyle = this.getFlexContainerPattern(devicePixelRatio);
 
     let { bounds } = this.currentQuads.content[0];
     drawRect(this.ctx, 0, 0, bounds.width, bounds.height, this.currentMatrix);
 
+    // Find current angle of outer flex element by measuring the angle of two arbitrary
+    // points, then rotate canvas, so the hash pattern stays 45deg to the boundary.
+    let p1 = apply(this.currentMatrix, [0, 0]);
+    let p2 = apply(this.currentMatrix, [1, 0]);
+    let angleRad = Math.atan2(p2[1] - p1[1], p2[0] - p1[0]);
+    this.ctx.rotate(angleRad);
+
     this.ctx.fill();
     this.ctx.stroke();
     this.ctx.restore();
   }
 
   /**
    * Renders the flex basis for a given flex item.
    */
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -12,33 +12,33 @@
 #include "mozilla/dom/Animation.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/KeyframeEffectReadOnly.h"
 #include "mozilla/AnimationComparator.h"
 #include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/AnimationTarget.h"
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/AutoRestore.h"
+#include "mozilla/ComputedStyleInlines.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/LayerAnimationInfo.h"
 #include "mozilla/RestyleManager.h"
 #include "mozilla/RestyleManagerInlines.h"
 #include "mozilla/ServoBindings.h" // Servo_GetProperties_Overriding_Animation
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/TypeTraits.h" // For Forward<>
 #include "nsContentUtils.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSPropertyIDSet.h"
 #include "nsCSSProps.h"
 #include "nsAtom.h"
 #include "nsIPresShell.h"
 #include "nsIPresShellInlines.h"
 #include "nsLayoutUtils.h"
-#include "nsStyleContextInlines.h"
 #include "nsTArray.h"
 #include "PendingAnimationTracker.h"
 
 using mozilla::dom::Animation;
 using mozilla::dom::Element;
 using mozilla::dom::KeyframeEffectReadOnly;
 
 namespace mozilla {
@@ -162,24 +162,21 @@ FindAnimationsForCompositor(const nsIFra
   // from test control after seeking where it might not be the case.
   //
   // Those cases are probably not important but just to be safe, let's make
   // sure the cascade is up to date since if it *is* up to date, this is
   // basically a no-op.
   Maybe<NonOwningAnimationTarget> pseudoElement =
     EffectCompositor::GetAnimationElementAndPseudoForFrame(aFrame);
   if (pseudoElement) {
-    StyleBackendType backend =
-      aFrame->StyleContext()->IsServo()
-      ? StyleBackendType::Servo
-      : StyleBackendType::Gecko;
+    StyleBackendType backend = StyleBackendType::Servo;
     EffectCompositor::MaybeUpdateCascadeResults(backend,
                                                 pseudoElement->mElement,
                                                 pseudoElement->mPseudoType,
-                                                aFrame->StyleContext());
+                                                aFrame->Style());
   }
 
   if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
     if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
       nsCString message;
       message.AppendLiteral("Performance warning: Async animations are "
                             "disabled");
       AnimationUtils::LogAsyncAnimationFailure(message);
@@ -545,37 +542,37 @@ EffectCompositor::ClearIsRunningOnCompos
     effect->SetIsRunningOnCompositor(aProperty, false);
   }
 }
 
 /* static */ void
 EffectCompositor::MaybeUpdateCascadeResults(StyleBackendType aBackendType,
                                             Element* aElement,
                                             CSSPseudoElementType aPseudoType,
-                                            nsStyleContext* aStyleContext)
+                                            ComputedStyle* aComputedStyle)
 {
   EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
   if (!effects || !effects->CascadeNeedsUpdate()) {
     return;
   }
 
   UpdateCascadeResults(aBackendType, *effects, aElement, aPseudoType,
-                       aStyleContext);
+                       aComputedStyle);
 
   MOZ_ASSERT(!effects->CascadeNeedsUpdate(), "Failed to update cascade state");
 }
 
 /* static */ Maybe<NonOwningAnimationTarget>
 EffectCompositor::GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame)
 {
   // Always return the same object to benefit from return-value optimization.
   Maybe<NonOwningAnimationTarget> result;
 
   CSSPseudoElementType pseudoType =
-    aFrame->StyleContext()->GetPseudoType();
+    aFrame->Style()->GetPseudoType();
 
   if (pseudoType != CSSPseudoElementType::NotPseudo &&
       pseudoType != CSSPseudoElementType::before &&
       pseudoType != CSSPseudoElementType::after) {
     return result;
   }
 
   nsIContent* content = aFrame->GetContent();
@@ -601,26 +598,26 @@ EffectCompositor::GetAnimationElementAnd
 }
 
 
 /* static */ nsCSSPropertyIDSet
 EffectCompositor::GetOverriddenProperties(StyleBackendType aBackendType,
                                           EffectSet& aEffectSet,
                                           Element* aElement,
                                           CSSPseudoElementType aPseudoType,
-                                          nsStyleContext* aStyleContext)
+                                          ComputedStyle* aComputedStyle)
 {
   MOZ_ASSERT(aBackendType != StyleBackendType::Servo || aElement,
              "Should have an element to get style data from if we are using"
              " the Servo backend");
 
   nsCSSPropertyIDSet result;
 
   Element* elementToRestyle = GetElementToRestyle(aElement, aPseudoType);
-  if (aBackendType == StyleBackendType::Gecko && !aStyleContext) {
+  if (aBackendType == StyleBackendType::Gecko && !aComputedStyle) {
     MOZ_CRASH("old style system disabled");
   } else if (aBackendType == StyleBackendType::Servo && !elementToRestyle) {
     return result;
   }
 
   AutoTArray<nsCSSPropertyID, LayerAnimationInfo::kRecords> propertiesToTrack;
   {
     nsCSSPropertyIDSet propertiesToTrackAsSet;
@@ -662,17 +659,17 @@ EffectCompositor::GetOverriddenPropertie
   return result;
 }
 
 /* static */ void
 EffectCompositor::UpdateCascadeResults(StyleBackendType aBackendType,
                                        EffectSet& aEffectSet,
                                        Element* aElement,
                                        CSSPseudoElementType aPseudoType,
-                                       nsStyleContext* aStyleContext)
+                                       ComputedStyle* aComputedStyle)
 {
   MOZ_ASSERT(EffectSet::GetEffectSet(aElement, aPseudoType) == &aEffectSet,
              "Effect set should correspond to the specified (pseudo-)element");
   if (aEffectSet.IsEmpty()) {
     aEffectSet.MarkCascadeUpdated();
     return;
   }
 
@@ -687,17 +684,17 @@ EffectCompositor::UpdateCascadeResults(S
   //
   // We only do this for properties that we can animate on the compositor
   // since we will apply other properties on the main thread where the usual
   // cascade applies.
   nsCSSPropertyIDSet overriddenProperties =
     GetOverriddenProperties(aBackendType,
                             aEffectSet,
                             aElement, aPseudoType,
-                            aStyleContext);
+                            aComputedStyle);
 
   // Returns a bitset the represents which properties from
   // LayerAnimationInfo::sRecords are present in |aPropertySet|.
   auto compositorPropertiesInSet =
     [](nsCSSPropertyIDSet& aPropertySet) ->
       std::bitset<LayerAnimationInfo::kRecords> {
         std::bitset<LayerAnimationInfo::kRecords> result;
         for (size_t i = 0; i < LayerAnimationInfo::kRecords; i++) {
@@ -1027,13 +1024,13 @@ EffectCompositor::PreTraverse(dom::Eleme
   }
   return found;
 }
 
 
 template
 void
 EffectCompositor::UpdateEffectProperties(
-  const ServoStyleContext* aStyleContext,
+  const ComputedStyle* aComputedStyle,
   Element* aElement,
   CSSPseudoElementType aPseudoType);
 
 } // namespace mozilla
--- a/dom/animation/EffectCompositor.h
+++ b/dom/animation/EffectCompositor.h
@@ -17,22 +17,22 @@
 #include "nsCycleCollectionParticipant.h"
 #include "nsDataHashtable.h"
 #include "nsTArray.h"
 
 class nsCSSPropertyIDSet;
 class nsAtom;
 class nsIFrame;
 class nsPresContext;
-class nsStyleContext;
 struct RawServoAnimationValueMap;
 typedef RawServoAnimationValueMap* RawServoAnimationValueMapBorrowedMut;
 
 namespace mozilla {
 
+class ComputedStyle;
 class EffectSet;
 class RestyleTracker;
 class StyleAnimationValue;
 struct AnimationPerformanceWarning;
 struct AnimationProperty;
 struct NonOwningAnimationTarget;
 
 namespace dom {
@@ -148,53 +148,53 @@ public:
   static void ClearIsRunningOnCompositor(const nsIFrame* aFrame,
                                          nsCSSPropertyID aProperty);
 
   // Update animation cascade results for the specified (pseudo-)element
   // but only if we have marked the cascade as needing an update due a
   // the change in the set of effects or a change in one of the effects'
   // "in effect" state.
   //
-  // When |aBackendType| is StyleBackendType::Gecko, |aStyleContext| is used to
-  // find overridden properties. If it is nullptr, the nsStyleContext of the
+  // When |aBackendType| is StyleBackendType::Gecko, |aComputedStyle| is used to
+  // find overridden properties. If it is nullptr, the ComputedStyle of the
   // primary frame of the specified (pseudo-)element, if available, is used.
   //
   // When |aBackendType| is StyleBackendType::Servo, we fetch the rule node
-  // from the |aElement| (i.e. |aStyleContext| is ignored).
+  // from the |aElement| (i.e. |aComputedStyle| is ignored).
   //
   // This method does NOT detect if other styles that apply above the
   // animation level of the cascade have changed.
   static void
   MaybeUpdateCascadeResults(StyleBackendType aBackendType,
                             dom::Element* aElement,
                             CSSPseudoElementType aPseudoType,
-                            nsStyleContext* aStyleContext);
+                            ComputedStyle* aComputedStyle);
 
   // Update the mPropertiesWithImportantRules and
   // mPropertiesForAnimationsLevel members of the given EffectSet, and also
   // request any restyles required by changes to the cascade result.
   //
   // NOTE: This can be expensive so we should only call it if styles that apply
   // above the animation level of the cascade might have changed. For all
   // other cases we should call MaybeUpdateCascadeResults.
   //
   // This is typically reserved for internal callers but is public here since
   // when we detect changes to the cascade on the Servo side we can't call
   // MarkCascadeNeedsUpdate during the traversal so instead we call this as part
   // of a follow-up sequential task.
   //
-  // As with MaybeUpdateCascadeResults, |aStyleContext| is only used
+  // As with MaybeUpdateCascadeResults, |aComputedStyle| is only used
   // when |aBackendType| is StyleBackendType::Gecko. When |aBackendType| is
   // StyleBackendType::Servo, it is ignored.
   static void
   UpdateCascadeResults(StyleBackendType aBackendType,
                        EffectSet& aEffectSet,
                        dom::Element* aElement,
                        CSSPseudoElementType aPseudoType,
-                       nsStyleContext* aStyleContext);
+                       ComputedStyle* aComputedStyle);
 
   // Helper to fetch the corresponding element and pseudo-type from a frame.
   //
   // For frames corresponding to pseudo-elements, the returned element is the
   // element on which we store the animations (i.e. the EffectSet and/or
   // AnimationCollection), *not* the generated content.
   //
   // Returns an empty result when a suitable element cannot be found including
@@ -237,29 +237,29 @@ private:
   ~EffectCompositor() = default;
 
 
   // Get the properties in |aEffectSet| that we are able to animate on the
   // compositor but which are also specified at a higher level in the cascade
   // than the animations level.
   //
   // When |aBackendType| is StyleBackendType::Gecko, we determine which
-  // properties are specified using the provided |aStyleContext| and
-  // |aElement| and |aPseudoType| are ignored. If |aStyleContext| is nullptr,
+  // properties are specified using the provided |aComputedStyle| and
+  // |aElement| and |aPseudoType| are ignored. If |aComputedStyle| is nullptr,
   // we automatically look up the style context of primary frame of the
   // (pseudo-)element.
   //
   // When |aBackendType| is StyleBackendType::Servo, we use the |StrongRuleNode|
   // stored on the (pseudo-)element indicated by |aElement| and |aPseudoType|.
   static nsCSSPropertyIDSet
   GetOverriddenProperties(StyleBackendType aBackendType,
                           EffectSet& aEffectSet,
                           dom::Element* aElement,
                           CSSPseudoElementType aPseudoType,
-                          nsStyleContext* aStyleContext);
+                          ComputedStyle* aComputedStyle);
 
   static nsPresContext* GetPresContext(dom::Element* aElement);
 
   nsPresContext* mPresContext;
 
   // Elements with a pending animation restyle. The associated bool value is
   // true if a pending animation restyle has also been dispatched. For
   // animations that can be throttled, we will add an entry to the hashtable to
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -1,23 +1,23 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/KeyframeEffect.h"
 
+#include "mozilla/ComputedStyle.h"
 #include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
   // For UnrestrictedDoubleOrKeyframeAnimationOptions
 #include "mozilla/dom/AnimationEffectTiming.h"
 #include "mozilla/dom/KeyframeEffectBinding.h"
 #include "nsDocument.h" // For nsDocument::IsWebAnimationsEnabled
 #include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
-#include "nsStyleContext.h"
 
 namespace mozilla {
 namespace dom {
 
 KeyframeEffect::KeyframeEffect(nsIDocument* aDocument,
                                const Maybe<OwningAnimationTarget>& aTarget,
                                const TimingParams& aTiming,
                                const KeyframeEffectParams& aOptions)
@@ -105,17 +105,17 @@ KeyframeEffect::SetTarget(const Nullable
       nsNodeUtils::AnimationRemoved(mAnimation);
     }
   }
 
   mTarget = newTarget;
 
   if (mTarget) {
     UpdateTargetRegistration();
-    RefPtr<nsStyleContext> styleContext = GetTargetStyleContext();
+    RefPtr<ComputedStyle> styleContext = GetTargetComputedStyle();
     if (styleContext) {
       UpdateProperties(styleContext);
     }
 
     MaybeUpdateFrameForCompositor();
 
     RequestRestyle(EffectCompositor::RestyleType::Layer);
 
@@ -158,17 +158,17 @@ KeyframeEffect::SetComposite(const Compo
 
   mEffectOptions.mComposite = aComposite;
 
   if (mAnimation && mAnimation->IsRelevant()) {
     nsNodeUtils::AnimationChanged(mAnimation);
   }
 
   if (mTarget) {
-    RefPtr<nsStyleContext> styleContext = GetTargetStyleContext();
+    RefPtr<ComputedStyle> styleContext = GetTargetComputedStyle();
     if (styleContext) {
       UpdateProperties(styleContext);
     }
   }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -60,21 +60,21 @@ public:
   Constructor(const GlobalObject& aGlobal,
               const Nullable<ElementOrCSSPseudoElement>& aTarget,
               JS::Handle<JSObject*> aKeyframes,
               const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
               ErrorResult& aRv);
 
   void NotifySpecifiedTimingUpdated();
 
-  // This method calls GetTargetStyleContext which is not safe to use when
+  // This method calls GetTargetComputedStyle which is not safe to use when
   // we are in the middle of updating style. If we need to use this when
-  // updating style, we should pass the nsStyleContext into this method and use
+  // updating style, we should pass the ComputedStyle into this method and use
   // that to update the properties rather than calling
-  // GetStyleContext.
+  // GetComputedStyle.
   void SetTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget);
 
   IterationCompositeOperation IterationComposite(CallerType aCallerType)
   {
     return KeyframeEffectReadOnly::IterationComposite();
   }
   void SetIterationComposite(
     const IterationCompositeOperation& aIterationComposite,
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -9,35 +9,35 @@
 #include "FrameLayerBuilder.h"
 #include "mozilla/dom/Animation.h"
 #include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
   // For UnrestrictedDoubleOrKeyframeAnimationOptions;
 #include "mozilla/dom/CSSPseudoElement.h"
 #include "mozilla/dom/KeyframeEffectBinding.h"
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/AutoRestore.h"
+#include "mozilla/ComputedStyleInlines.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/FloatingPoint.h" // For IsFinite
 #include "mozilla/LayerAnimationInfo.h"
 #include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt
 #include "mozilla/KeyframeUtils.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/TypeTraits.h"
 #include "Layers.h" // For Layer
-#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetStyleContext
+#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetComputedStyle
 #include "nsContentUtils.h"
 #include "nsCSSPropertyIDSet.h"
 #include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
 #include "nsCSSPseudoElements.h" // For CSSPseudoElementType
 #include "nsDocument.h" // For nsDocument::IsWebAnimationsEnabled
 #include "nsIFrame.h"
 #include "nsIPresShell.h"
 #include "nsIScriptError.h"
 #include "nsRefreshDriver.h"
-#include "nsStyleContextInlines.h"
 
 namespace mozilla {
 
 bool
 PropertyValuePair::operator==(const PropertyValuePair& aOther) const
 {
   if (mProperty != aOther.mProperty || mValue != aOther.mValue) {
     return false;
@@ -185,35 +185,31 @@ KeyframeEffectReadOnly::SetKeyframes(JSC
                                      ErrorResult& aRv)
 {
   nsTArray<Keyframe> keyframes =
     KeyframeUtils::GetKeyframesFromObject(aContext, mDocument, aKeyframes, aRv);
   if (aRv.Failed()) {
     return;
   }
 
-  RefPtr<nsStyleContext> styleContext = GetTargetStyleContext();
-  if (styleContext) {
-    if (styleContext->IsGecko()) {
-      MOZ_CRASH("old style system disabled");
-    } else {
-      SetKeyframes(Move(keyframes), styleContext->AsServo());
-    }
+  RefPtr<ComputedStyle> style = GetTargetComputedStyle();
+  if (style) {
+    SetKeyframes(Move(keyframes), style);
   } else {
     // SetKeyframes has the same behavior for null StyleType* for
     // both backends, just pick one and use it.
-    SetKeyframes(Move(keyframes), (ServoStyleContext*) nullptr);
+    SetKeyframes(Move(keyframes), (ComputedStyle*) nullptr);
   }
 }
 
 
 void
 KeyframeEffectReadOnly::SetKeyframes(
   nsTArray<Keyframe>&& aKeyframes,
-  const ServoStyleContext* aComputedValues)
+  const ComputedStyle* aComputedValues)
 {
   DoSetKeyframes(Move(aKeyframes), aComputedValues);
 }
 
 template<typename StyleType>
 void
 KeyframeEffectReadOnly::DoSetKeyframes(nsTArray<Keyframe>&& aKeyframes,
                                        StyleType* aStyle)
@@ -292,43 +288,30 @@ SpecifiedKeyframeArraysAreEqual(const ns
     }
   }
 
   return true;
 }
 #endif
 
 void
-KeyframeEffectReadOnly::UpdateProperties(nsStyleContext* aStyleContext)
+KeyframeEffectReadOnly::UpdateProperties(const ComputedStyle* aComputedStyle)
 {
-  MOZ_ASSERT(aStyleContext);
-
-  if (aStyleContext->IsGecko()) {
-    MOZ_CRASH("old style system disabled");
-  }
-
-  UpdateProperties(aStyleContext->AsServo());
-}
-
-void
-KeyframeEffectReadOnly::UpdateProperties(
-  const ServoStyleContext* aStyleContext)
-{
-  DoUpdateProperties(aStyleContext);
+  DoUpdateProperties(aComputedStyle);
 }
 
 template<typename StyleType>
 void
 KeyframeEffectReadOnly::DoUpdateProperties(StyleType* aStyle)
 {
   MOZ_ASSERT(aStyle);
 
   // Skip updating properties when we are composing style.
   // FIXME: Bug 1324966. Drop this check once we have a function to get
-  // nsStyleContext without resolving animating style.
+  // ComputedStyle without resolving animating style.
   MOZ_DIAGNOSTIC_ASSERT(!mIsComposingStyle,
                         "Should not be called while processing ComposeStyle()");
   if (mIsComposingStyle) {
     return;
   }
 
   nsTArray<AnimationProperty> properties = BuildProperties(aStyle);
 
@@ -362,17 +345,17 @@ KeyframeEffectReadOnly::DoUpdateProperti
   MarkCascadeNeedsUpdate();
 
   RequestRestyle(EffectCompositor::RestyleType::Layer);
 }
 
 
 void
 KeyframeEffectReadOnly::EnsureBaseStyles(
-  const ServoStyleContext* aComputedValues,
+  const ComputedStyle* aComputedValues,
   const nsTArray<AnimationProperty>& aProperties)
 {
   if (!mTarget) {
     return;
   }
 
   mBaseStyleValuesForServo.Clear();
 
@@ -387,57 +370,57 @@ KeyframeEffectReadOnly::EnsureBaseStyles
   // case where |presContext| is nullptr is so rare (we've only ever seen in
   // fuzzing, and even then we've never been able to reproduce it reliably)
   // it's not worth the runtime cost of an extra branch.
   MOZ_ASSERT(presContext || aProperties.IsEmpty(),
              "Typically presContext should not be nullptr but if it is"
              " we should have also failed to calculate the computed values"
              " passed-in as aProperties");
 
-  RefPtr<ServoStyleContext> baseStyleContext;
+  RefPtr<ComputedStyle> baseComputedStyle;
   for (const AnimationProperty& property : aProperties) {
     EnsureBaseStyle(property,
                     presContext,
                     aComputedValues,
-                    baseStyleContext);
+                    baseComputedStyle);
   }
 }
 
 void
 KeyframeEffectReadOnly::EnsureBaseStyle(
   const AnimationProperty& aProperty,
   nsPresContext* aPresContext,
-  const ServoStyleContext* aComputedStyle,
- RefPtr<ServoStyleContext>& aBaseStyleContext)
+  const ComputedStyle* aComputedStyle,
+ RefPtr<ComputedStyle>& aBaseComputedStyle)
 {
   bool hasAdditiveValues = false;
 
   for (const AnimationPropertySegment& segment : aProperty.mSegments) {
     if (!segment.HasReplaceableValues()) {
       hasAdditiveValues = true;
       break;
     }
   }
 
   if (!hasAdditiveValues) {
     return;
   }
 
-  if (!aBaseStyleContext) {
+  if (!aBaseComputedStyle) {
     Element* animatingElement =
       EffectCompositor::GetElementToRestyle(mTarget->mElement,
                                             mTarget->mPseudoType);
-    aBaseStyleContext =
+    aBaseComputedStyle =
       aPresContext->StyleSet()->AsServo()->GetBaseContextForElement(
           animatingElement,
           aPresContext,
           aComputedStyle);
   }
   RefPtr<RawServoAnimationValue> baseValue =
-    Servo_ComputedValues_ExtractAnimationValue(aBaseStyleContext,
+    Servo_ComputedValues_ExtractAnimationValue(aBaseComputedStyle,
                                                aProperty.mProperty).Consume();
   mBaseStyleValuesForServo.Put(aProperty.mProperty, baseValue);
 }
 
 void
 KeyframeEffectReadOnly::WillComposeStyle()
 {
   ComputedTiming computedTiming = GetComputedTiming();
@@ -834,31 +817,31 @@ KeyframeEffectReadOnly::RequestRestyle(
   nsPresContext* presContext = nsContentUtils::GetContextForContent(mTarget->mElement);
   if (presContext && mAnimation) {
     presContext->EffectCompositor()->
       RequestRestyle(mTarget->mElement, mTarget->mPseudoType,
                      aRestyleType, mAnimation->CascadeLevel());
   }
 }
 
-already_AddRefed<nsStyleContext>
-KeyframeEffectReadOnly::GetTargetStyleContext()
+already_AddRefed<ComputedStyle>
+KeyframeEffectReadOnly::GetTargetComputedStyle()
 {
   if (!GetRenderedDocument()) {
     return nullptr;
   }
 
   MOZ_ASSERT(mTarget,
              "Should only have a document when we have a target element");
 
   nsAtom* pseudo = mTarget->mPseudoType < CSSPseudoElementType::Count
                     ? nsCSSPseudoElements::GetPseudoAtom(mTarget->mPseudoType)
                     : nullptr;
 
-  return nsComputedDOMStyle::GetStyleContext(mTarget->mElement, pseudo);
+  return nsComputedDOMStyle::GetComputedStyle(mTarget->mElement, pseudo);
 }
 
 #ifdef DEBUG
 void
 DumpAnimationProperties(nsTArray<AnimationProperty>& aAnimationProperties)
 {
   for (auto& p : aAnimationProperties) {
     printf("%s\n", nsCSSProps::GetStringValue(p.mProperty).get());
@@ -1035,27 +1018,27 @@ KeyframeEffectReadOnly::GetKeyframes(JSC
   // a longhand that comes from a variable reference in a shorthand? Servo says,
   // "an empty string" which is not particularly helpful.
   //
   // We should just store shorthands as-is (bug 1391537) and then return the
   // variable references, but for now, since we don't do that, and in order to
   // be consistent with Gecko, we just expand the variables (assuming we have
   // enough context to do so). For that we need to grab the style context so we
   // know what custom property values to provide.
-  RefPtr<nsStyleContext> styleContext;
+  RefPtr<ComputedStyle> styleContext;
   if (isServo && isCSSAnimation) {
     // The following will flush style but that's ok since if you update
     // a variable's computed value, you expect to see that updated value in the
     // result of getKeyframes().
     //
     // If we don't have a target, the following will return null. In that case
     // we might end up returning variables as-is or empty string. That should be
     // acceptable however, since such a case is rare and this is only
     // short-term (and unshipped) behavior until bug 1391537 is fixed.
-    styleContext = GetTargetStyleContext();
+    styleContext = GetTargetComputedStyle();
   }
 
   for (const Keyframe& keyframe : mKeyframes) {
     // Set up a dictionary object for the explicit members
     BaseComputedKeyframe keyframeDict;
     if (keyframe.mOffset) {
       keyframeDict.mOffset.SetValue(keyframe.mOffset.value());
     }
@@ -1097,23 +1080,23 @@ KeyframeEffectReadOnly::GetKeyframes(JSC
       nsAutoString stringValue;
       if (isServo) {
         // Don't serialize the custom properties for this keyframe.
         if (propertyValue.mProperty ==
               nsCSSPropertyID::eCSSPropertyExtra_variable) {
           continue;
         }
         if (propertyValue.mServoDeclarationBlock) {
-          const ServoStyleContext* servoStyleContext =
+          const ComputedStyle* servoComputedStyle =
             styleContext ? styleContext->AsServo() : nullptr;
           Servo_DeclarationBlock_SerializeOneValue(
             propertyValue.mServoDeclarationBlock,
             propertyValue.mProperty,
             &stringValue,
-            servoStyleContext,
+            servoComputedStyle,
             customProperties);
         } else {
           RawServoAnimationValue* value =
             mBaseStyleValuesForServo.GetWeak(propertyValue.mProperty);
 
           if (value) {
             Servo_AnimationValue_Serialize(value,
                                            propertyValue.mProperty,
@@ -1498,40 +1481,40 @@ KeyframeEffectReadOnly::SetPerformanceWa
         AnimationUtils::LogAsyncAnimationFailure(logMessage, mTarget->mElement);
       }
       return;
     }
   }
 }
 
 
-already_AddRefed<nsStyleContext>
-KeyframeEffectReadOnly::CreateStyleContextForAnimationValue(
+already_AddRefed<ComputedStyle>
+KeyframeEffectReadOnly::CreateComputedStyleForAnimationValue(
   nsCSSPropertyID aProperty,
   const AnimationValue& aValue,
-  const ServoStyleContext* aBaseStyleContext)
+  const ComputedStyle* aBaseComputedStyle)
 {
-  MOZ_ASSERT(aBaseStyleContext,
-             "CreateStyleContextForAnimationValue needs to be called "
-             "with a valid ServoStyleContext");
+  MOZ_ASSERT(aBaseComputedStyle,
+             "CreateComputedStyleForAnimationValue needs to be called "
+             "with a valid ComputedStyle");
 
   ServoStyleSet* styleSet =
-    aBaseStyleContext->PresContext()->StyleSet()->AsServo();
+    aBaseComputedStyle->PresContext()->StyleSet()->AsServo();
   Element* elementForResolve =
     EffectCompositor::GetElementToRestyle(mTarget->mElement,
                                           mTarget->mPseudoType);
   MOZ_ASSERT(elementForResolve, "The target element shouldn't be null");
   return styleSet->ResolveServoStyleByAddingAnimation(elementForResolve,
-                                                      aBaseStyleContext,
+                                                      aBaseComputedStyle,
                                                       aValue.mServo);
 }
 
 template<typename StyleType>
 void
-KeyframeEffectReadOnly::CalculateCumulativeChangeHint(StyleType* aStyleContext)
+KeyframeEffectReadOnly::CalculateCumulativeChangeHint(StyleType* aComputedStyle)
 {
   mCumulativeChangeHint = nsChangeHint(0);
 
   for (const AnimationProperty& property : mProperties) {
     // For opacity property we don't produce any change hints that are not
     // included in nsChangeHint_Hints_CanIgnoreIfNotVisible so we can throttle
     // opacity animations regardless of the change they produce.  This
     // optimization is particularly important since it allows us to throttle
@@ -1544,29 +1527,29 @@ KeyframeEffectReadOnly::CalculateCumulat
       // In case composite operation is not 'replace' or value is null,
       // we can't throttle animations which will not cause any layout changes
       // on invisible elements because we can't calculate the change hint for
       // such properties until we compose it.
       if (!segment.HasReplaceableValues()) {
         mCumulativeChangeHint = ~nsChangeHint_Hints_CanIgnoreIfNotVisible;
         return;
       }
-      RefPtr<nsStyleContext> fromContext =
-        CreateStyleContextForAnimationValue(property.mProperty,
+      RefPtr<ComputedStyle> fromContext =
+        CreateComputedStyleForAnimationValue(property.mProperty,
                                             segment.mFromValue,
-                                            aStyleContext);
+                                            aComputedStyle);
       if (!fromContext) {
         mCumulativeChangeHint = ~nsChangeHint_Hints_CanIgnoreIfNotVisible;
         return;
       }
 
-      RefPtr<nsStyleContext> toContext =
-        CreateStyleContextForAnimationValue(property.mProperty,
+      RefPtr<ComputedStyle> toContext =
+        CreateComputedStyleForAnimationValue(property.mProperty,
                                             segment.mToValue,
-                                            aStyleContext);
+                                            aComputedStyle);
       if (!toContext) {
         mCumulativeChangeHint = ~nsChangeHint_Hints_CanIgnoreIfNotVisible;
         return;
       }
 
       uint32_t equalStructs = 0;
       uint32_t samePointerStructs = 0;
       nsChangeHint changeHint =
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -40,18 +40,18 @@ class nsIPresShell;
 namespace mozilla {
 
 class AnimValuesStyleRule;
 enum class CSSPseudoElementType : uint8_t;
 class ErrorResult;
 struct AnimationRule;
 struct TimingParams;
 class EffectSet;
-class ServoStyleContext;
-class GeckoStyleContext;
+class ComputedStyle;
+class GeckoComputedStyle;
 
 namespace dom {
 class ElementOrCSSPseudoElement;
 class GlobalObject;
 class OwningElementOrCSSPseudoElement;
 class UnrestrictedDoubleOrKeyframeAnimationOptions;
 class UnrestrictedDoubleOrKeyframeEffectOptions;
 enum class IterationCompositeOperation : uint8_t;
@@ -161,17 +161,17 @@ public:
   IterationCompositeOperation IterationComposite() const;
   CompositeOperation Composite() const;
   void NotifyAnimationTimingUpdated();
   void RequestRestyle(EffectCompositor::RestyleType aRestyleType);
   void SetAnimation(Animation* aAnimation) override;
   void SetKeyframes(JSContext* aContext, JS::Handle<JSObject*> aKeyframes,
                     ErrorResult& aRv);
   void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
-                    const ServoStyleContext* aComputedValues);
+                    const ComputedStyle* aComputedValues);
 
   // Returns true if the effect includes |aProperty| regardless of whether the
   // property is overridden by !important rule.
   bool HasAnimationOfProperty(nsCSSPropertyID aProperty) const;
 
   // GetEffectiveAnimationOfProperty returns AnimationProperty corresponding
   // to a given CSS property if the effect includes the property and the
   // property is not overridden by !important rules.
@@ -187,20 +187,18 @@ public:
     nsCSSPropertyID aProperty) const;
 
   const InfallibleTArray<AnimationProperty>& Properties() const
   {
     return mProperties;
   }
 
   // Update |mProperties| by recalculating from |mKeyframes| using
-  // |aStyleContext| to resolve specified values.
-  void UpdateProperties(nsStyleContext* aStyleContext);
-  // Servo version of the above function.
-  void UpdateProperties(const ServoStyleContext* aComputedValues);
+  // |aComputedStyle| to resolve specified values.
+  void UpdateProperties(const ComputedStyle* aComputedValues);
 
   // Update various bits of state related to running ComposeStyle().
   // We need to update this outside ComposeStyle() because we should avoid
   // mutating any state in ComposeStyle() since it might be called during
   // parallel traversal.
   void WillComposeStyle();
 
   // Updates |aComposeResult| with the animation values produced by this
@@ -242,17 +240,17 @@ public:
   // will be used to generate a localized message for devtools.
   void SetPerformanceWarning(
     nsCSSPropertyID aProperty,
     const AnimationPerformanceWarning& aWarning);
 
   // Cumulative change hint on each segment for each property.
   // This is used for deciding the animation is paint-only.
   template<typename StyleType>
-  void CalculateCumulativeChangeHint(StyleType* aStyleContext);
+  void CalculateCumulativeChangeHint(StyleType* aComputedStyle);
 
   // Returns true if all of animation properties' change hints
   // can ignore painting if the animation is not visible.
   // See nsChangeHint_Hints_CanIgnoreIfNotVisible in nsChangeHint.h
   // in detail which change hint can be ignored.
   bool CanIgnoreIfNotVisible() const;
 
   // Returns true if the effect is current state and has scale animation.
@@ -295,17 +293,17 @@ protected:
                           ErrorResult& aRv);
 
   template<class KeyframeEffectType>
   static already_AddRefed<KeyframeEffectType>
   ConstructKeyframeEffect(const GlobalObject& aGlobal,
                           KeyframeEffectReadOnly& aSource,
                           ErrorResult& aRv);
 
-  // Build properties by recalculating from |mKeyframes| using |aStyleContext|
+  // Build properties by recalculating from |mKeyframes| using |aComputedStyle|
   // to resolve specified values. This function also applies paced spacing if
   // needed.
   template<typename StyleType>
   nsTArray<AnimationProperty> BuildProperties(StyleType* aStyle);
 
   // This effect is registered with its target element so long as:
   //
   // (a) It has a target element, and
@@ -323,34 +321,34 @@ protected:
   // Update the associated frame state bits so that, if necessary, a stacking
   // context will be created and the effect sent to the compositor.  We
   // typically need to do this when the properties referenced by the keyframe
   // have changed, or when the target frame might have changed.
   void MaybeUpdateFrameForCompositor();
 
   // Looks up the style context associated with the target element, if any.
   // We need to be careful to *not* call this when we are updating the style
-  // context. That's because calling GetStyleContext when we are in the process
+  // context. That's because calling GetComputedStyle when we are in the process
   // of building a style context may trigger various forms of infinite
   // recursion.
-  already_AddRefed<nsStyleContext> GetTargetStyleContext();
+  already_AddRefed<ComputedStyle> GetTargetComputedStyle();
 
   // A wrapper for marking cascade update according to the current
   // target and its effectSet.
   void MarkCascadeNeedsUpdate();
 
-  void EnsureBaseStyles(const ServoStyleContext* aComputedValues,
+  void EnsureBaseStyles(const ComputedStyle* aComputedValues,
                         const nsTArray<AnimationProperty>& aProperties);
 
   // Stylo version of the above function that also first checks for an additive
   // value in |aProperty|'s list of segments.
   void EnsureBaseStyle(const AnimationProperty& aProperty,
                        nsPresContext* aPresContext,
-                       const ServoStyleContext* aComputedValues,
-                       RefPtr<mozilla::ServoStyleContext>& aBaseComputedValues);
+                       const ComputedStyle* aComputedValues,
+                       RefPtr<ComputedStyle>& aBaseComputedValues);
 
   Maybe<OwningAnimationTarget> mTarget;
 
   KeyframeEffectParams mEffectOptions;
 
   // The specified keyframes.
   nsTArray<Keyframe>          mKeyframes;
 
@@ -393,20 +391,20 @@ private:
 
 
   void ComposeStyleRule(RawServoAnimationValueMap& aAnimationValues,
                         const AnimationProperty& aProperty,
                         const AnimationPropertySegment& aSegment,
                         const ComputedTiming& aComputedTiming);
 
 
-  already_AddRefed<nsStyleContext> CreateStyleContextForAnimationValue(
+  already_AddRefed<ComputedStyle> CreateComputedStyleForAnimationValue(
     nsCSSPropertyID aProperty,
     const AnimationValue& aValue,
-    const ServoStyleContext* aBaseStyleContext);
+    const ComputedStyle* aBaseComputedStyle);
 
   nsIFrame* GetAnimationFrame() const;
 
   bool CanThrottle() const;
   bool CanThrottleTransformChanges(const nsIFrame& aFrame) const;
   bool CanThrottleTransformChangesInScrollable(nsIFrame& aFrame) const;
 
   // Returns true if the computedTiming has changed since the last
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/KeyframeUtils.h"
 
+#include "mozilla/ComputedStyle.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Move.h"
 #include "mozilla/RangedArray.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoBindingTypes.h"
 #include "mozilla/ServoCSSParser.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/TimingParams.h"
@@ -23,17 +24,16 @@
 #include "nsContentUtils.h" // For GetContextForContent, and
                             // AnimationsAPICoreEnabled
 #include "nsCSSParser.h"
 #include "nsCSSPropertyIDSet.h"
 #include "nsCSSProps.h"
 #include "nsCSSPseudoElements.h" // For CSSPseudoElementType
 #include "nsDocument.h" // For nsDocument::IsWebAnimationsEnabled
 #include "nsIScriptError.h"
-#include "nsStyleContext.h"
 #include "nsTArray.h"
 #include <algorithm> // For std::stable_sort, std::min
 
 namespace mozilla {
 
 // ------------------------------------------------------------------
 //
 // Internal data types
@@ -365,17 +365,17 @@ static void
 MarkAsComputeValuesFailureKey(PropertyValuePair& aPair);
 
 #endif
 
 
 static nsTArray<ComputedKeyframeValues>
 GetComputedKeyframeValues(const nsTArray<Keyframe>& aKeyframes,
                           dom::Element* aElement,
-                          const ServoStyleContext* aComputedValues);
+                          const ComputedStyle* aComputedValues);
 
 static void
 BuildSegmentsFromValueEntries(nsTArray<KeyframeValueEntry>& aEntries,
                               nsTArray<AnimationProperty>& aResult);
 
 static void
 GetKeyframeListFromPropertyIndexedKeyframe(JSContext* aCx,
                                            nsIDocument* aDocument,
@@ -940,34 +940,34 @@ MarkAsComputeValuesFailureKey(PropertyVa
 
 
 /**
  * The variation of the above function. This is for Servo backend.
  */
 static nsTArray<ComputedKeyframeValues>
 GetComputedKeyframeValues(const nsTArray<Keyframe>& aKeyframes,
                           dom::Element* aElement,
-                          const ServoStyleContext* aStyleContext)
+                          const ComputedStyle* aComputedStyle)
 {
   MOZ_ASSERT(aElement);
   MOZ_ASSERT(aElement->IsStyledByServo());
 
   nsTArray<ComputedKeyframeValues> result;
 
   nsPresContext* presContext = nsContentUtils::GetContextForContent(aElement);
   if (!presContext) {
     // This has been reported to happen with some combinations of content
     // (particularly involving resize events and layout flushes? See bug 1407898
     // and bug 1408420) but no reproducible steps have been found.
     // For now we just return an empty array.
     return result;
   }
 
   result = presContext->StyleSet()->AsServo()
-    ->GetComputedKeyframeValuesFor(aKeyframes, aElement, aStyleContext);
+    ->GetComputedKeyframeValuesFor(aKeyframes, aElement, aComputedStyle);
   return result;
 }
 
 static void
 AppendInitialSegment(AnimationProperty* aAnimationProperty,
                      const KeyframeValueEntry& aFirstEntry)
 {
   AnimationPropertySegment* segment =
@@ -1528,12 +1528,12 @@ DistributeRange(const Range<Keyframe>& a
 }
 
 
 template
 nsTArray<AnimationProperty>
 KeyframeUtils::GetAnimationPropertiesFromKeyframes(
   const nsTArray<Keyframe>& aKeyframes,
   dom::Element* aElement,
-  const ServoStyleContext* aStyle,
+  const ComputedStyle* aStyle,
   dom::CompositeOperation aEffectComposite);
 
 } // namespace mozilla
--- a/dom/animation/KeyframeUtils.h
+++ b/dom/animation/KeyframeUtils.h
@@ -10,17 +10,17 @@
 #include "mozilla/KeyframeEffectParams.h" // For CompositeOperation
 #include "nsCSSPropertyID.h"
 #include "nsTArrayForwardDeclare.h" // For nsTArray
 #include "js/RootingAPI.h" // For JS::Handle
 
 struct JSContext;
 class JSObject;
 class nsIDocument;
-class nsStyleContext;
+class ComputedStyle;
 struct RawServoDeclarationBlock;
 
 namespace mozilla {
 struct AnimationProperty;
 enum class CSSPseudoElementType : uint8_t;
 class ErrorResult;
 struct Keyframe;
 struct PropertyStyleAnimationValuePair;
@@ -76,17 +76,17 @@ public:
   /**
    * Converts an array of Keyframe objects into an array of AnimationProperty
    * objects. This involves creating an array of computed values for each
    * longhand property and determining the offset and timing function to use
    * for each value.
    *
    * @param aKeyframes The input keyframes.
    * @param aElement The context element.
-   * @param aStyleType The |ServoStyleContext| or |GeckoStyleContext| to use
+   * @param aStyleType The |ComputedStyle| or |GeckoComputedStyle| to use
    *   when computing values.
    * @param aEffectComposite The composite operation specified on the effect.
    *   For any keyframes in |aKeyframes| that do not specify a composite
    *   operation, this value will be used.
    * @return The set of animation properties. If an error occurs, the returned
    *   array will be empty.
    */
   template<typename StyleType>
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -539,18 +539,18 @@ Element::GetBindingURL(nsIDocument *aDoc
                                IsHTMLElement(nsGkAtoms::object) ||
                                IsHTMLElement(nsGkAtoms::embed));
   if (!aDocument->GetShell() || GetPrimaryFrame() || !isXULorPluginElement) {
     *aResult = nullptr;
     return true;
   }
 
   // Get the computed -moz-binding directly from the style context
-  RefPtr<nsStyleContext> sc =
-    nsComputedDOMStyle::GetStyleContextNoFlush(this, nullptr);
+  RefPtr<ComputedStyle> sc =
+    nsComputedDOMStyle::GetComputedStyleNoFlush(this, nullptr);
   NS_ENSURE_TRUE(sc, false);
 
   NS_IF_ADDREF(*aResult = sc->StyleDisplay()->mBinding);
   return true;
 }
 
 JSObject*
 Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
@@ -1500,18 +1500,18 @@ Element::GetElementsByClassName(const ns
 void
 Element::GetElementsWithGrid(nsTArray<RefPtr<Element>>& aElements)
 {
   // This helper function is passed to GetElementsByMatching()
   // to identify elements with styling which will cause them to
   // generate a nsGridContainerFrame during layout.
   auto IsDisplayGrid = [](Element* aElement) -> bool
   {
-    RefPtr<nsStyleContext> styleContext =
-      nsComputedDOMStyle::GetStyleContext(aElement, nullptr);
+    RefPtr<ComputedStyle> styleContext =
+      nsComputedDOMStyle::GetComputedStyle(aElement, nullptr);
     if (styleContext) {
       const nsStyleDisplay* display = styleContext->StyleDisplay();
       return (display->mDisplay == StyleDisplay::Grid ||
               display->mDisplay == StyleDisplay::InlineGrid);
     }
     return false;
   };
 
@@ -4380,17 +4380,17 @@ Element::AddSizeOfExcludingThis(nsWindow
     // code.
     *aNodeSize +=
       Servo_Element_SizeOfExcludingThisAndCVs(ServoElementMallocSizeOf,
                                               ServoElementMallocEnclosingSizeOf,
                                               &aSizes.mState.mSeenPtrs, this);
 
     // Now measure just the ComputedValues (and style structs) under
     // mServoData. This counts towards the relevant fields in |aSizes|.
-    RefPtr<ServoStyleContext> sc;
+    RefPtr<ComputedStyle> sc;
     if (Servo_Element_HasPrimaryComputedValues(this)) {
       sc = Servo_Element_GetPrimaryComputedValues(this).Consume();
       if (!aSizes.mState.HaveSeenPtr(sc.get())) {
         sc->AddSizeOfIncludingThis(aSizes, &aSizes.mLayoutComputedValuesDom);
       }
 
       for (size_t i = 0; i < nsCSSPseudoElements::kEagerPseudoCount; i++) {
         if (Servo_Element_HasPseudoComputedValues(this, i)) {
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2721,18 +2721,18 @@ nsDOMWindowUtils::ComputeAnimationDistan
 
   Element* element = content->AsElement();
   AnimationValue v1 = AnimationValue::FromString(property, aValue1, element);
   AnimationValue v2 = AnimationValue::FromString(property, aValue2, element);
   if (v1.IsNull() || v2.IsNull()) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
-  RefPtr<nsStyleContext> styleContext =
-    nsComputedDOMStyle::GetStyleContext(element, nullptr);
+  RefPtr<ComputedStyle> styleContext =
+    nsComputedDOMStyle::GetComputedStyle(element, nullptr);
   *aResult = v1.ComputeDistance(property, v2, styleContext);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetAnimationTypeForLonghand(const nsAString& aProperty,
                                               nsAString& aResult)
 {
@@ -2819,34 +2819,30 @@ nsDOMWindowUtils::GetUnanimatedComputedS
   }
 
   nsIPresShell* shell = GetPresShell();
   if (!shell) {
     return NS_ERROR_FAILURE;
   }
 
   RefPtr<nsAtom> pseudo = nsCSSPseudoElements::GetPseudoAtom(aPseudoElement);
-  RefPtr<nsStyleContext> styleContext =
-    nsComputedDOMStyle::GetUnanimatedStyleContextNoFlush(element, pseudo);
+  RefPtr<ComputedStyle> styleContext =
+    nsComputedDOMStyle::GetUnanimatedComputedStyleNoFlush(element, pseudo);
   if (!styleContext) {
     return NS_ERROR_FAILURE;
   }
 
-  if (styleContext->IsServo()) {
-    RefPtr<RawServoAnimationValue> value =
-      Servo_ComputedValues_ExtractAnimationValue(styleContext->AsServo(),
-                                                 propertyID).Consume();
-    if (!value) {
-      return NS_ERROR_FAILURE;
-    }
-    Servo_AnimationValue_Serialize(value, propertyID, &aResult);
-    return NS_OK;
+  RefPtr<RawServoAnimationValue> value =
+    Servo_ComputedValues_ExtractAnimationValue(styleContext->AsServo(),
+                                               propertyID).Consume();
+  if (!value) {
+    return NS_ERROR_FAILURE;
   }
-
-  MOZ_CRASH("old style system disabled");
+  Servo_AnimationValue_Serialize(value, propertyID, &aResult);
+  return NS_OK;
 }
 
 nsresult
 nsDOMWindowUtils::RenderDocument(const nsRect& aRect,
                                  uint32_t aFlags,
                                  nscolor aBackgroundColor,
                                  gfxContext* aThebesContext)
 {
--- a/dom/base/nsPlainTextSerializer.cpp
+++ b/dom/base/nsPlainTextSerializer.cpp
@@ -1846,31 +1846,31 @@ bool
 nsPlainTextSerializer::IsInPre()
 {
   return !mPreformatStack.empty() && mPreformatStack.top();
 }
 
 bool
 nsPlainTextSerializer::IsElementPreformatted(Element* aElement)
 {
-  RefPtr<nsStyleContext> styleContext =
-    nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr);
+  RefPtr<ComputedStyle> styleContext =
+    nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr);
   if (styleContext) {
     const nsStyleText* textStyle = styleContext->StyleText();
     return textStyle->WhiteSpaceOrNewlineIsSignificant();
   }
   // Fall back to looking at the tag, in case there is no style information.
   return GetIdForContent(aElement) == nsGkAtoms::pre;
 }
 
 bool
 nsPlainTextSerializer::IsElementBlock(Element* aElement)
 {
-  RefPtr<nsStyleContext> styleContext =
-    nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr);
+  RefPtr<ComputedStyle> styleContext =
+    nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr);
   if (styleContext) {
     const nsStyleDisplay* displayStyle = styleContext->StyleDisplay();
     return displayStyle->IsBlockOutsideStyle();
   }
   // Fall back to looking at the tag, in case there is no style information.
   return nsContentUtils::IsHTMLBlock(aElement);
 }
 
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -3736,18 +3736,18 @@ IsVisibleAndNotInReplacedElement(nsIFram
 }
 
 static bool
 ElementIsVisibleNoFlush(Element* aElement)
 {
   if (!aElement) {
     return false;
   }
-  RefPtr<nsStyleContext> sc =
-    nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr);
+  RefPtr<ComputedStyle> sc =
+    nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr);
   return sc && sc->StyleVisibility()->IsVisible();
 }
 
 static void
 AppendTransformedText(InnerTextAccumulator& aResult, nsIContent* aContainer)
 {
   auto textNode = static_cast<CharacterData*>(aContainer);
 
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -437,17 +437,17 @@ CollectWindowReports(nsGlobalWindowInner
                "listeners on nodes and other event targets.");
 
   REPORT_SIZE("/layout/line-boxes", mArenaSizes.mLineBoxes,
               "Memory used by line boxes within a window.");
 
   REPORT_SIZE("/layout/rule-nodes", mArenaSizes.mRuleNodes,
               "Memory used by CSS rule nodes within a window.");
 
-  REPORT_SIZE("/layout/style-contexts", mArenaSizes.mStyleContexts,
+  REPORT_SIZE("/layout/style-contexts", mArenaSizes.mComputedStyles,
               "Memory used by style contexts within a window.");
 
   // There are many different kinds of style structs, but it is likely that
   // only a few matter. Implement a cutoff so we don't bloat about:memory with
   // many uninteresting entries.
   const size_t STYLE_SUNDRIES_THRESHOLD =
     js::MemoryReportingSundriesThreshold();
 
@@ -703,17 +703,17 @@ nsWindowMemoryReporter::CollectReports(n
          windowTotalSizes.mArenaSizes.mLineBoxes,
          "This is the sum of all windows' 'layout/line-boxes' numbers.");
 
   REPORT("window-objects/layout/rule-nodes",
          windowTotalSizes.mArenaSizes.mRuleNodes,
          "This is the sum of all windows' 'layout/rule-nodes' numbers.");
 
   REPORT("window-objects/layout/style-contexts",
-         windowTotalSizes.mArenaSizes.mStyleContexts,
+         windowTotalSizes.mArenaSizes.mComputedStyles,
          "This is the sum of all windows' 'layout/style-contexts' numbers.");
 
   size_t geckoStyleTotal = 0;
 #define STYLE_STRUCT(name_, cb_) \
   geckoStyleTotal += \
     windowTotalSizes.mArenaSizes.mGeckoStyleSizes.NS_STYLE_SIZES_FIELD(name_);
 #define STYLE_STRUCT_LIST_IGNORE_VARIABLES
 #include "nsStyleStructList.h"
--- a/dom/base/nsWindowSizes.h
+++ b/dom/base/nsWindowSizes.h
@@ -98,17 +98,17 @@ struct nsStyleSizes
 };
 
 #define NS_ARENA_SIZES_FIELD(classname) mArena##classname
 
 struct nsArenaSizes {
 #define FOR_EACH_SIZE(macro) \
   macro(Other, mLineBoxes) \
   macro(Style, mRuleNodes) \
-  macro(Style, mStyleContexts)
+  macro(Style, mComputedStyles)
 
   nsArenaSizes()
     :
       FOR_EACH_SIZE(ZERO_SIZE)
 
       #define FRAME_ID(classname, ...) \
         NS_ARENA_SIZES_FIELD(classname)(0),
       #define ABSTRACT_FRAME_ID(...)
--- a/dom/base/nsXHTMLContentSerializer.cpp
+++ b/dom/base/nsXHTMLContentSerializer.cpp
@@ -715,18 +715,18 @@ nsXHTMLContentSerializer::MaybeLeaveFrom
 bool
 nsXHTMLContentSerializer::IsElementPreformatted(nsIContent* aNode)
 {
   MOZ_ASSERT(ShouldMaintainPreLevel(), "We should not be calling this needlessly");
 
   if (!aNode->IsElement()) {
     return false;
   }
-  RefPtr<nsStyleContext> styleContext =
-    nsComputedDOMStyle::GetStyleContextNoFlush(aNode->AsElement(), nullptr);
+  RefPtr<ComputedStyle> styleContext =
+    nsComputedDOMStyle::GetComputedStyleNoFlush(aNode->AsElement(), nullptr);
   if (styleContext) {
     const nsStyleText* textStyle = styleContext->StyleText();
     return textStyle->WhiteSpaceOrNewlineIsSignificant();
   }
   return false;
 }
 
 bool
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1170,18 +1170,18 @@ CanvasRenderingContext2D::ParseColor(con
     if (!ServoCSSParser::ComputeColor(set, NS_RGB(0, 0, 0), aString, aColor,
                                       &wasCurrentColor, loader)) {
       return false;
     }
 
     if (wasCurrentColor && mCanvasElement) {
       // Otherwise, get the value of the color property, flushing style
       // if necessary.
-      RefPtr<nsStyleContext> canvasStyle =
-        nsComputedDOMStyle::GetStyleContext(mCanvasElement, nullptr);
+      RefPtr<ComputedStyle> canvasStyle =
+        nsComputedDOMStyle::GetComputedStyle(mCanvasElement, nullptr);
       if (canvasStyle) {
         *aColor = canvasStyle->StyleColor()->mColor;
       }
       // Beware that the presShell could be gone here.
     }
     return true;
   }
 
@@ -1950,18 +1950,18 @@ CanvasRenderingContext2D::ClearTarget()
   SetInitialState();
 
   if (!mCanvasElement || !mCanvasElement->IsInComposedDoc()) {
     return;
   }
 
   // For vertical writing-mode, unless text-orientation is sideways,
   // we'll modify the initial value of textBaseline to 'middle'.
-  RefPtr<nsStyleContext> canvasStyle =
-    nsComputedDOMStyle::GetStyleContext(mCanvasElement, nullptr);
+  RefPtr<ComputedStyle> canvasStyle =
+    nsComputedDOMStyle::GetComputedStyle(mCanvasElement, nullptr);
   if (canvasStyle) {
     WritingMode wm(canvasStyle);
     if (wm.IsVertical() && !wm.IsSideways()) {
       CurrentState().textBaseline = TextBaseline::MIDDLE;
     }
   }
 }
 
@@ -2678,17 +2678,17 @@ CreateDeclarationForServo(nsCSSPropertyI
 
 static already_AddRefed<RawServoDeclarationBlock>
 CreateFontDeclarationForServo(const nsAString& aFont,
                               nsIDocument* aDocument)
 {
   return CreateDeclarationForServo(eCSSProperty_font, aFont, aDocument);
 }
 
-static already_AddRefed<ServoStyleContext>
+static already_AddRefed<ComputedStyle>
 GetFontStyleForServo(Element* aElement, const nsAString& aFont,
                      nsIPresShell* aPresShell,
                      nsAString& aOutUsedFont,
                      ErrorResult& aError)
 {
   MOZ_ASSERT(aPresShell->StyleSet()->IsServo());
 
   RefPtr<RawServoDeclarationBlock> declarations =
@@ -2703,21 +2703,21 @@ GetFontStyleForServo(Element* aElement, 
   // at font-size-adjust, which the font shorthand resets to 'none'.
   if (Servo_DeclarationBlock_HasCSSWideKeyword(declarations,
                                                eCSSProperty_font_size_adjust)) {
     return nullptr;
   }
 
   ServoStyleSet* styleSet = aPresShell->StyleSet()->AsServo();
 
-  RefPtr<nsStyleContext> parentStyle;
+  RefPtr<ComputedStyle> parentStyle;
   // have to get a parent style context for inherit-like relative
   // values (2em, bolder, etc.)
   if (aElement && aElement->IsInComposedDoc()) {
-    parentStyle = nsComputedDOMStyle::GetStyleContext(aElement, nullptr);
+    parentStyle = nsComputedDOMStyle::GetComputedStyle(aElement, nullptr);
     if (!parentStyle) {
       // The flush killed the shell, so we couldn't get any meaningful style
       // back.
       aError.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
   } else {
     RefPtr<RawServoDeclarationBlock> declarations =
@@ -2730,17 +2730,17 @@ GetFontStyleForServo(Element* aElement, 
   }
 
   MOZ_RELEASE_ASSERT(parentStyle, "Should have a valid parent style");
 
   MOZ_ASSERT(!aPresShell->IsDestroying(),
              "We should have returned an error above if the presshell is "
              "being destroyed.");
 
-  RefPtr<ServoStyleContext> sc =
+  RefPtr<ComputedStyle> sc =
     styleSet->ResolveForDeclarations(parentStyle->AsServo(), declarations);
 
   // The font getter is required to be reserialized based on what we
   // parsed (including having line-height removed).  (Older drafts of
   // the spec required font sizes be converted to pixels, but that no
   // longer seems to be required.)
   Servo_SerializeFontValueForCanvas(declarations, &aOutUsedFont);
   return sc.forget();
@@ -2749,19 +2749,19 @@ GetFontStyleForServo(Element* aElement, 
 
 static already_AddRefed<RawServoDeclarationBlock>
 CreateFilterDeclarationForServo(const nsAString& aFilter,
                                 nsIDocument* aDocument)
 {
   return CreateDeclarationForServo(eCSSProperty_filter, aFilter, aDocument);
 }
 
-static already_AddRefed<ServoStyleContext>
+static already_AddRefed<ComputedStyle>
 ResolveFilterStyleForServo(const nsAString& aFilterString,
-                           const ServoStyleContext* aParentStyle,
+                           const ComputedStyle* aParentStyle,
                            nsIPresShell* aPresShell,
                            ErrorResult& aError)
 {
   MOZ_ASSERT(aPresShell->StyleSet()->IsServo());
 
   RefPtr<RawServoDeclarationBlock> declarations =
     CreateFilterDeclarationForServo(aFilterString, aPresShell->GetDocument());
   if (!declarations) {
@@ -2772,17 +2772,17 @@ ResolveFilterStyleForServo(const nsAStri
   // In addition to unparseable values, the spec says we need to reject
   // 'inherit' and 'initial'.
   if (Servo_DeclarationBlock_HasCSSWideKeyword(declarations,
                                                eCSSProperty_filter)) {
     return nullptr;
   }
 
   ServoStyleSet* styleSet = aPresShell->StyleSet()->AsServo();
-  RefPtr<ServoStyleContext> computedValues =
+  RefPtr<ComputedStyle> computedValues =
     styleSet->ResolveForDeclarations(aParentStyle, declarations);
 
   return computedValues.forget();
 }
 
 bool
 CanvasRenderingContext2D::ParseFilter(const nsAString& aString,
                                       nsTArray<nsStyleFilter>& aFilterChain,
@@ -2804,27 +2804,27 @@ CanvasRenderingContext2D::ParseFilter(co
   if (presShell->StyleSet()->IsGecko()) {
     MOZ_CRASH("old style system disabled");
     return false;
   }
 
   // For stylo
   MOZ_ASSERT(presShell->StyleSet()->IsServo());
 
-  RefPtr<ServoStyleContext> parentStyle =
+  RefPtr<ComputedStyle> parentStyle =
     GetFontStyleForServo(mCanvasElement,
                          GetFont(),
                          presShell,
                          usedFont,
                          aError);
   if (!parentStyle) {
     return false;
   }
 
-  RefPtr<ServoStyleContext> computedValues =
+  RefPtr<ComputedStyle> computedValues =
     ResolveFilterStyleForServo(aString,
                                parentStyle,
                                presShell,
                                aError);
   if (!computedValues) {
     return false;
   }
 
@@ -3730,17 +3730,17 @@ CanvasRenderingContext2D::SetFontInterna
   }
 
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   if (!presShell) {
     aError.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
-  RefPtr<nsStyleContext> sc;
+  RefPtr<ComputedStyle> sc;
   nsString usedFont;
   if (presShell->StyleSet()->IsServo()) {
     sc =
       GetFontStyleForServo(mCanvasElement, aFont, presShell, usedFont, aError);
   } else {
     MOZ_CRASH("old style system disabled");
   }
   if (!sc) {
@@ -4300,21 +4300,21 @@ CanvasRenderingContext2D::DrawOrMeasureT
   // but is less than or equal to zero or equal to NaN.
   if (aMaxWidth.WasPassed() && (aMaxWidth.Value() <= 0 || IsNaN(aMaxWidth.Value()))) {
     textToDraw.Truncate();
   }
 
   // for now, default to ltr if not in doc
   bool isRTL = false;
 
-  RefPtr<nsStyleContext> canvasStyle;
+  RefPtr<ComputedStyle> canvasStyle;
   if (mCanvasElement && mCanvasElement->IsInComposedDoc()) {
     // try to find the closest context
     canvasStyle =
-      nsComputedDOMStyle::GetStyleContext(mCanvasElement, nullptr);
+      nsComputedDOMStyle::GetComputedStyle(mCanvasElement, nullptr);
     if (!canvasStyle) {
       return NS_ERROR_FAILURE;
     }
 
     isRTL = canvasStyle->StyleVisibility()->mDirection ==
       NS_STYLE_DIRECTION_RTL;
   } else {
     isRTL = GET_BIDI_OPTION_DIRECTION(document->GetBidiOptions()) == IBMBIDI_TEXTDIRECTION_RTL;
--- a/dom/events/test/test_all_synthetic_events.html
+++ b/dom/events/test/test_all_synthetic_events.html
@@ -284,16 +284,18 @@ const kEventConstructors = {
                                                          return new PopupBlockedEvent(aName, aProps);
                                                        },
                                              },
   ProgressEvent:                             { create: function (aName, aProps) {
                                                          return new ProgressEvent(aName, aProps);
                                                        },
                                              },
   RTCDataChannelEvent:                       { create: function (aName, aProps) {
+                                                         let pc = new RTCPeerConnection();
+                                                         aProps.channel = pc.createDataChannel("foo");
                                                          return new RTCDataChannelEvent(aName, aProps);
                                                        },
                                              },
   RTCDTMFToneChangeEvent:                       { create: function (aName, aProps) {
                                                          return new RTCDTMFToneChangeEvent(aName, aProps);
                                                        },
                                              },
   RTCPeerConnectionIceEvent:                 { create: function (aName, aProps) {
--- a/dom/html/ImageDocument.cpp
+++ b/dom/html/ImageDocument.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ImageDocument.h"
+#include "mozilla/ComputedStyle.h"
 #include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ImageDocumentBinding.h"
 #include "mozilla/dom/HTMLImageElement.h"
 #include "mozilla/dom/MouseEvent.h"
 #include "nsRect.h"
 #include "nsIImageLoadingContent.h"
 #include "nsGenericHTMLElement.h"
@@ -21,17 +22,16 @@
 #include "nsIFrame.h"
 #include "nsGkAtoms.h"
 #include "imgIRequest.h"
 #include "imgILoader.h"
 #include "imgIContainer.h"
 #include "imgINotificationObserver.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
-#include "nsStyleContext.h"
 #include "nsIChannel.h"
 #include "nsIContentPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMElement.h"
 #include "nsError.h"
 #include "nsURILoader.h"
 #include "nsIDocShell.h"
--- a/dom/html/reftests/reftest.list
+++ b/dom/html/reftests/reftest.list
@@ -39,17 +39,17 @@ skip-if(Android) == 649134-2.html 649134
 == image-load-shortcircuit-1.html image-load-shortcircuit-ref.html
 == image-load-shortcircuit-2.html image-load-shortcircuit-ref.html
 
 # Test that image documents taken into account CSS properties like
 # image-orientation when determining the size of the image.
 # (Fuzzy necessary due to pixel-wise comparison of different JPEGs.
 # The vast majority of the fuzziness comes from Linux and WinXP.)
 fuzzy(1,149) == bug917595-iframe-1.html    bug917595-1-ref.html
-fuzzy(3,640) fuzzy-if(skiaContent,3,7544) fuzzy-if(webrender,10-10,10916-10916) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869
+fuzzy(3,640) fuzzy-if(skiaContent,3,7544) fuzzy-if(webrender,3-3,7544-7544) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869
 
 # Test support for SVG-as-image in <picture> elements.
 == bug1106522-1.html bug1106522-ref.html
 == bug1106522-2.html bug1106522-ref.html
 
 == href-attr-change-restyles.html href-attr-change-restyles-ref.html
 == figure.html figure-ref.html
 == pre-1.html pre-1-ref.html
--- a/dom/smil/nsSMILCSSProperty.cpp
+++ b/dom/smil/nsSMILCSSProperty.cpp
@@ -18,20 +18,20 @@
 #include "nsCSSProps.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // Class Methods
 nsSMILCSSProperty::nsSMILCSSProperty(nsCSSPropertyID aPropID,
                                      Element* aElement,
-                                     nsStyleContext* aBaseStyleContext)
+                                     ComputedStyle* aBaseComputedStyle)
   : mPropID(aPropID)
   , mElement(aElement)
-  , mBaseStyleContext(aBaseStyleContext)
+  , mBaseComputedStyle(aBaseComputedStyle)
 {
   MOZ_ASSERT(IsPropertyAnimatable(mPropID,
                aElement->OwnerDoc()->GetStyleBackendType()),
              "Creating a nsSMILCSSProperty for a property "
              "that's not supported for animation");
 }
 
 nsSMILValue
@@ -42,17 +42,17 @@ nsSMILCSSProperty::GetBaseValue() const
   // from ALL return points. This function must only return THIS variable:
   nsSMILValue baseValue;
 
   // SPECIAL CASE: (a) Shorthands
   //               (b) 'display'
   //               (c) No base style context
   if (nsCSSProps::IsShorthand(mPropID) ||
       mPropID == eCSSProperty_display ||
-      !mBaseStyleContext) {
+      !mBaseComputedStyle) {
     // We can't look up the base (computed-style) value of shorthand
     // properties because they aren't guaranteed to have a consistent computed
     // value.
     //
     // Also, although we can look up the base value of the display property,
     // doing so involves clearing and resetting the property which can cause
     // frames to be recreated which we'd like to avoid.
     //
@@ -64,17 +64,17 @@ nsSMILCSSProperty::GetBaseValue() const
     nsSMILValue tmpVal(&nsSMILCSSValueType::sSingleton);
     Swap(baseValue, tmpVal);
     return baseValue;
   }
 
   AnimationValue computedValue;
   if (mElement->IsStyledByServo()) {
     computedValue.mServo =
-      Servo_ComputedValues_ExtractAnimationValue(mBaseStyleContext->AsServo(), mPropID)
+      Servo_ComputedValues_ExtractAnimationValue(mBaseComputedStyle->AsServo(), mPropID)
       .Consume();
     if (!computedValue.mServo) {
       return baseValue;
     }
   } else {
     MOZ_CRASH("old style system disabled");
   }
 
--- a/dom/smil/nsSMILCSSProperty.h
+++ b/dom/smil/nsSMILCSSProperty.h
@@ -11,19 +11,18 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/StyleBackendType.h"
 #include "nsISMILAttr.h"
 #include "nsAtom.h"
 #include "nsCSSPropertyID.h"
 #include "nsCSSValue.h"
 
-class nsStyleContext;
-
 namespace mozilla {
+class ComputedStyle;
 namespace dom {
 class Element;
 } // namespace dom
 } // namespace mozilla
 
 /**
  * nsSMILCSSProperty: Implements the nsISMILAttr interface for SMIL animations
  * that target CSS properties.  Represents a particular animation-targeted CSS
@@ -31,24 +30,24 @@ class Element;
  */
 class nsSMILCSSProperty : public nsISMILAttr
 {
 public:
   /**
    * Constructs a new nsSMILCSSProperty.
    * @param  aPropID   The CSS property we're interested in animating.
    * @param  aElement  The element whose CSS property is being animated.
-   * @param  aBaseStyleContext  The style context to use when getting the base
-   *                            value. If this is nullptr and GetBaseValue is
-   *                            called, an empty nsSMILValue initialized with
-   *                            the nsSMILCSSValueType will be returned.
+   * @param  aBaseComputedStyle  The style context to use when getting the base
+   *                             value. If this is nullptr and GetBaseValue is
+   *                             called, an empty nsSMILValue initialized with
+   *                             the nsSMILCSSValueType will be returned.
    */
   nsSMILCSSProperty(nsCSSPropertyID aPropID,
                     mozilla::dom::Element* aElement,
-                    nsStyleContext* aBaseStyleContext);
+                    mozilla::ComputedStyle* aBaseComputedStyle);
 
   // nsISMILAttr methods
   virtual nsresult ValueFromString(const nsAString& aStr,
                                    const mozilla::dom::SVGAnimationElement* aSrcElement,
                                    nsSMILValue& aValue,
                                    bool& aPreventCachingOfSandwich) const override;
   virtual nsSMILValue GetBaseValue() const override;
   virtual nsresult    SetAnimValue(const nsSMILValue& aValue) override;
@@ -71,16 +70,17 @@ public:
 protected:
   nsCSSPropertyID mPropID;
   // Using non-refcounted pointer for mElement -- we know mElement will stay
   // alive for my lifetime because a nsISMILAttr (like me) only lives as long
   // as the Compositing step, and DOM elements don't get a chance to die during
   // that time.
   mozilla::dom::Element*   mElement;
 
-  // The style context to use when fetching base styles.
+  // The style to use when fetching base styles.
+  //
   // As with mElement, since an nsISMILAttr only lives as long as the
   // compositing step and since ComposeAttribute holds an owning reference to
   // the base style context, we can use a non-owning reference here.
-  nsStyleContext* mBaseStyleContext;
+  mozilla::ComputedStyle* mBaseComputedStyle;
 };
 
 #endif // NS_SMILCSSPROPERTY_H_
--- a/dom/smil/nsSMILCSSValueType.cpp
+++ b/dom/smil/nsSMILCSSValueType.cpp
@@ -21,16 +21,17 @@
 #include "mozilla/ServoCSSParser.h"
 #include "mozilla/StyleSetHandleInlines.h"
 #include "mozilla/dom/BaseKeyframeTypesBinding.h" // For CompositeOperation
 #include "mozilla/dom/Element.h"
 #include "nsDebug.h"
 #include "nsStyleUtil.h"
 #include "nsIDocument.h"
 
+using namespace mozilla;
 using namespace mozilla::dom;
 using mozilla::StyleAnimationValue;
 
 typedef AutoTArray<RefPtr<RawServoAnimationValue>, 1> ServoAnimationValues;
 
 /*static*/ nsSMILCSSValueType nsSMILCSSValueType::sSingleton;
 
 struct ValueWrapper {
@@ -490,17 +491,17 @@ GetPresContextForElement(Element* aElem)
   return doc->GetPresContext();
 }
 
 
 static ServoAnimationValues
 ValueFromStringHelper(nsCSSPropertyID aPropID,
                       Element* aTargetElement,
                       nsPresContext* aPresContext,
-                      nsStyleContext* aStyleContext,
+                      ComputedStyle* aComputedStyle,
                       const nsAString& aString)
 {
   ServoAnimationValues result;
 
   nsIDocument* doc = aTargetElement->GetUncomposedDoc();
   if (!doc) {
     return result;
   }
@@ -514,17 +515,17 @@ ValueFromStringHelper(nsCSSPropertyID aP
                                     ParsingMode::AllowAllNumericValues);
   if (!servoDeclarationBlock) {
     return result;
   }
 
   // Compute value
   aPresContext->StyleSet()->AsServo()->GetAnimationValues(servoDeclarationBlock,
                                                           aTargetElement,
-                                                          aStyleContext->AsServo(),
+                                                          aComputedStyle->AsServo(),
                                                           result);
 
   return result;
 }
 
 // static
 void
 nsSMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID,
@@ -544,40 +545,35 @@ nsSMILCSSValueType::ValueFromString(nsCS
   if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
                                                 doc->NodePrincipal(),
                                                 nullptr,
                                                 doc->GetDocumentURI(),
                                                 0, aString, nullptr)) {
     return;
   }
 
-  RefPtr<nsStyleContext> styleContext =
-    nsComputedDOMStyle::GetStyleContext(aTargetElement, nullptr);
+  RefPtr<ComputedStyle> styleContext =
+    nsComputedDOMStyle::GetComputedStyle(aTargetElement, nullptr);
   if (!styleContext) {
     return;
   }
 
-  if (styleContext->IsServo()) {
-    ServoAnimationValues parsedValues =
-      ValueFromStringHelper(aPropID, aTargetElement, presContext,
-                            styleContext, aString);
-    if (aIsContextSensitive) {
-      // FIXME: Bug 1358955 - detect context-sensitive values and set this value
-      // appropriately.
-      *aIsContextSensitive = false;
-    }
-
-    if (!parsedValues.IsEmpty()) {
-      sSingleton.Init(aValue);
-      aValue.mU.mPtr = new ValueWrapper(aPropID, Move(parsedValues));
-    }
-    return;
+  ServoAnimationValues parsedValues =
+    ValueFromStringHelper(aPropID, aTargetElement, presContext,
+                          styleContext, aString);
+  if (aIsContextSensitive) {
+    // FIXME: Bug 1358955 - detect context-sensitive values and set this value
+    // appropriately.
+    *aIsContextSensitive = false;
   }
 
-    MOZ_CRASH("old style system disabled");
+  if (!parsedValues.IsEmpty()) {
+    sSingleton.Init(aValue);
+    aValue.mU.mPtr = new ValueWrapper(aPropID, Move(parsedValues));
+  }
 }
 
 // static
 nsSMILValue
 nsSMILCSSValueType::ValueFromAnimationValue(nsCSSPropertyID aPropID,
                                             Element* aTargetElement,
                                             const AnimationValue& aValue)
 {
--- a/dom/smil/nsSMILCompositor.cpp
+++ b/dom/smil/nsSMILCompositor.cpp
@@ -52,26 +52,26 @@ nsSMILCompositor::AddAnimationFunction(n
 void
 nsSMILCompositor::ComposeAttribute(bool& aMightHavePendingStyleUpdates)
 {
   if (!mKey.mElement)
     return;
 
   // If we might need to resolve base styles, grab a suitable style context
   // for initializing our nsISMILAttr with.
-  RefPtr<nsStyleContext> baseStyleContext;
+  RefPtr<ComputedStyle> baseComputedStyle;
   if (MightNeedBaseStyle()) {
-    baseStyleContext =
-      nsComputedDOMStyle::GetUnanimatedStyleContextNoFlush(mKey.mElement,
-                                                           nullptr);
+    baseComputedStyle =
+      nsComputedDOMStyle::GetUnanimatedComputedStyleNoFlush(mKey.mElement,
+                                                            nullptr);
   }
 
   // FIRST: Get the nsISMILAttr (to grab base value from, and to eventually
   // give animated value to)
-  UniquePtr<nsISMILAttr> smilAttr = CreateSMILAttr(baseStyleContext);
+  UniquePtr<nsISMILAttr> smilAttr = CreateSMILAttr(baseComputedStyle);
   if (!smilAttr) {
     // Target attribute not found (or, out of memory)
     return;
   }
   if (mAnimationFunctions.IsEmpty()) {
     // No active animation functions. (We can still have a nsSMILCompositor in
     // that case if an animation function has *just* become inactive)
     smilAttr->ClearAnimValue();
@@ -129,23 +129,23 @@ nsSMILCompositor::ClearAnimationEffects(
     return;
   }
   smilAttr->ClearAnimValue();
 }
 
 // Protected Helper Functions
 // --------------------------
 UniquePtr<nsISMILAttr>
-nsSMILCompositor::CreateSMILAttr(nsStyleContext* aBaseStyleContext)
+nsSMILCompositor::CreateSMILAttr(ComputedStyle* aBaseComputedStyle)
 {
   nsCSSPropertyID propID = GetCSSPropertyToAnimate();
 
   if (propID != eCSSProperty_UNKNOWN) {
     return MakeUnique<nsSMILCSSProperty>(propID, mKey.mElement.get(),
-                                         aBaseStyleContext);
+                                         aBaseComputedStyle);
   }
 
   return mKey.mElement->GetAnimatedAttr(mKey.mAttributeNamespaceID,
                                         mKey.mAttributeName);
 }
 
 nsCSSPropertyID
 nsSMILCompositor::GetCSSPropertyToAnimate() const
--- a/dom/smil/nsSMILCompositor.h
+++ b/dom/smil/nsSMILCompositor.h
@@ -70,20 +70,20 @@ public:
   // Transfers |aOther|'s mCachedBaseValue to |this|
   void StealCachedBaseValue(nsSMILCompositor* aOther) {
     mCachedBaseValue = mozilla::Move(aOther->mCachedBaseValue);
   }
 
  private:
   // Create a nsISMILAttr for my target, on the heap.
   //
-  // @param aBaseStyleContext  An optional style context which, if set, will be
+  // @param aBaseComputedStyle  An optional style context which, if set, will be
   //                           used when fetching the base style.
   mozilla::UniquePtr<nsISMILAttr>
-  CreateSMILAttr(nsStyleContext* aBaseStyleContext);
+  CreateSMILAttr(mozilla::ComputedStyle* aBaseComputedStyle);
 
   // Returns the CSS property this compositor should animate, or
   // eCSSProperty_UNKNOWN if this compositor does not animate a CSS property.
   nsCSSPropertyID GetCSSPropertyToAnimate() const;
 
   // Returns true if we might need to refer to base styles (i.e. we are
   // targeting a CSS property and have one or more animation functions that
   // don't just replace the underlying value).
--- a/dom/svg/SVGContentUtils.cpp
+++ b/dom/svg/SVGContentUtils.cpp
@@ -23,17 +23,17 @@
 #include "nsLayoutUtils.h"
 #include "nsMathUtils.h"
 #include "SVGAnimationElement.h"
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "nsContentUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Types.h"
 #include "mozilla/FloatingPoint.h"
-#include "nsStyleContext.h"
+#include "mozilla/ComputedStyle.h"
 #include "nsSVGPathDataParser.h"
 #include "SVGPathData.h"
 #include "SVGPathElement.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::SVGPreserveAspectRatioBinding;
 using namespace mozilla::gfx;
@@ -166,26 +166,26 @@ GetStrokeDashData(SVGContentUtils::AutoS
   }
 
   return eDashedStroke;
 }
 
 void
 SVGContentUtils::GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
                                   nsSVGElement* aElement,
-                                  nsStyleContext* aStyleContext,
+                                  ComputedStyle* aComputedStyle,
                                   SVGContextPaint* aContextPaint,
                                   StrokeOptionFlags aFlags)
 {
-  RefPtr<nsStyleContext> styleContext;
-  if (aStyleContext) {
-    styleContext = aStyleContext;
+  RefPtr<ComputedStyle> styleContext;
+  if (aComputedStyle) {
+    styleContext = aComputedStyle;
   } else {
     styleContext =
-      nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr);
+      nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr);
   }
 
   if (!styleContext) {
     return;
   }
 
   const nsStyleSVG* styleSVG = styleContext->StyleSVG();
 
@@ -240,25 +240,25 @@ SVGContentUtils::GetStrokeOptions(AutoSt
         aStrokeOptions->mLineCap = CapStyle::SQUARE;
         break;
     }
   }
 }
 
 Float
 SVGContentUtils::GetStrokeWidth(nsSVGElement* aElement,
-                                nsStyleContext* aStyleContext,
+                                ComputedStyle* aComputedStyle,
                                 SVGContextPaint* aContextPaint)
 {
-  RefPtr<nsStyleContext> styleContext;
-  if (aStyleContext) {
-    styleContext = aStyleContext;
+  RefPtr<ComputedStyle> styleContext;
+  if (aComputedStyle) {
+    styleContext = aComputedStyle;
   } else {
     styleContext =
-      nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr);
+      nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr);
   }
 
   if (!styleContext) {
     return 0.0f;
   }
 
   const nsStyleSVG* styleSVG = styleContext->StyleSVG();
 
@@ -270,81 +270,81 @@ SVGContentUtils::GetStrokeWidth(nsSVGEle
 }
 
 float
 SVGContentUtils::GetFontSize(Element *aElement)
 {
   if (!aElement)
     return 1.0f;
 
-  RefPtr<nsStyleContext> styleContext =
-    nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr);
+  RefPtr<ComputedStyle> styleContext =
+    nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr);
   if (!styleContext) {
     // ReportToConsole
     NS_WARNING("Couldn't get style context for content in GetFontStyle");
     return 1.0f;
   }
 
   return GetFontSize(styleContext);
 }
 
 float
 SVGContentUtils::GetFontSize(nsIFrame *aFrame)
 {
   MOZ_ASSERT(aFrame, "NULL frame in GetFontSize");
-  return GetFontSize(aFrame->StyleContext());
+  return GetFontSize(aFrame->Style());
 }
 
 float
-SVGContentUtils::GetFontSize(nsStyleContext *aStyleContext)
+SVGContentUtils::GetFontSize(ComputedStyle *aComputedStyle)
 {
-  MOZ_ASSERT(aStyleContext, "NULL style context in GetFontSize");
+  MOZ_ASSERT(aComputedStyle, "NULL style context in GetFontSize");
 
-  nsPresContext *presContext = aStyleContext->PresContext();
+  nsPresContext *presContext = aComputedStyle->PresContext();
   MOZ_ASSERT(presContext, "NULL pres context in GetFontSize");
 
-  nscoord fontSize = aStyleContext->StyleFont()->mSize;
+  nscoord fontSize = aComputedStyle->StyleFont()->mSize;
   return nsPresContext::AppUnitsToFloatCSSPixels(fontSize) /
          presContext->EffectiveTextZoom();
 }
 
 float
 SVGContentUtils::GetFontXHeight(Element *aElement)
 {
   if (!aElement)
     return 1.0f;
 
-  RefPtr<nsStyleContext> styleContext =
-    nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr);
+  RefPtr<ComputedStyle> styleContext =
+    nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr);
   if (!styleContext) {
     // ReportToConsole
     NS_WARNING("Couldn't get style context for content in GetFontStyle");
     return 1.0f;
   }
 
   return GetFontXHeight(styleContext);
 }
 
 float
 SVGContentUtils::GetFontXHeight(nsIFrame *aFrame)
 {
   MOZ_ASSERT(aFrame, "NULL frame in GetFontXHeight");
-  return GetFontXHeight(aFrame->StyleContext());
+  return GetFontXHeight(aFrame->Style());
 }
 
 float
-SVGContentUtils::GetFontXHeight(nsStyleContext *aStyleContext)
+SVGContentUtils::GetFontXHeight(ComputedStyle *aComputedStyle)
 {
-  MOZ_ASSERT(aStyleContext, "NULL style context in GetFontXHeight");
+  MOZ_ASSERT(aComputedStyle, "NULL style context in GetFontXHeight");
 
-  nsPresContext *presContext = aStyleContext->PresContext();
+  nsPresContext *presContext = aComputedStyle->PresContext();
   MOZ_ASSERT(presContext, "NULL pres context in GetFontXHeight");
 
   RefPtr<nsFontMetrics> fontMetrics =
-    nsLayoutUtils::GetFontMetricsForStyleContext(aStyleContext);
+    nsLayoutUtils::GetFontMetricsForComputedStyle(aComputedStyle);
 
   if (!fontMetrics) {
     // ReportToConsole
     NS_WARNING("no FontMetrics in GetFontXHeight()");
     return 1.0f;
   }
 
   nscoord xHeight = fontMetrics->XHeight();
--- a/dom/svg/SVGContentUtils.h
+++ b/dom/svg/SVGContentUtils.h
@@ -15,21 +15,21 @@
 #include "mozilla/RangedPtr.h"
 #include "nsError.h"
 #include "nsStringFwd.h"
 #include "gfx2DGlue.h"
 
 class nsIContent;
 class nsIDocument;
 class nsIFrame;
-class nsStyleContext;
 class nsStyleCoord;
 class nsSVGElement;
 
 namespace mozilla {
+class ComputedStyle;
 class nsSVGAnimatedTransformList;
 class SVGAnimatedPreserveAspectRatio;
 class SVGContextPaint;
 class SVGPreserveAspectRatio;
 namespace dom {
 class Element;
 class SVGSVGElement;
 class SVGViewportElement;
@@ -70,16 +70,17 @@ enum SVGTransformTypes {
 
 /**
  * Functions generally used by SVG Content classes. Functions here
  * should not generally depend on layout methods/classes e.g. nsSVGUtils
  */
 class SVGContentUtils
 {
 public:
+  typedef mozilla::ComputedStyle ComputedStyle;
   typedef mozilla::gfx::Float Float;
   typedef mozilla::gfx::Matrix Matrix;
   typedef mozilla::gfx::Rect Rect;
   typedef mozilla::gfx::StrokeOptions StrokeOptions;
   typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio;
   typedef mozilla::SVGPreserveAspectRatio SVGPreserveAspectRatio;
 
   /*
@@ -150,53 +151,53 @@ public:
   /**
    * Note: the linecap style returned in aStrokeOptions is not valid when
    * ShapeTypeHasNoCorners(aElement) == true && aFlags == eIgnoreStrokeDashing,
    * since when aElement has no corners the rendered linecap style depends on
    * whether or not the stroke is dashed.
    */
   static void GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
                                nsSVGElement* aElement,
-                               nsStyleContext* aStyleContext,
+                               ComputedStyle* aComputedStyle,
                                mozilla::SVGContextPaint* aContextPaint,
                                StrokeOptionFlags aFlags = eAllStrokeOptions);
 
   /**
    * Returns the current computed value of the CSS property 'stroke-width' for
-   * the given element. aStyleContext may be provided as an optimization.
+   * the given element. aComputedStyle may be provided as an optimization.
    * aContextPaint is also optional.
    *
    * Note that this function does NOT take account of the value of the 'stroke'
    * and 'stroke-opacity' properties to, say, return zero if they are "none" or
    * "0", respectively.
    */
   static Float GetStrokeWidth(nsSVGElement* aElement,
-                              nsStyleContext* aStyleContext,
+                              ComputedStyle* aComputedStyle,
                               mozilla::SVGContextPaint* aContextPaint);
 
   /*
    * Get the number of CSS px (user units) per em (i.e. the em-height in user
    * units) for an nsIContent
    *
    * XXX document the conditions under which these may fail, and what they
    * return in those cases.
    */
   static float GetFontSize(mozilla::dom::Element *aElement);
   static float GetFontSize(nsIFrame *aFrame);
-  static float GetFontSize(nsStyleContext *aStyleContext);
+  static float GetFontSize(ComputedStyle *aComputedStyle);
   /*
    * Get the number of CSS px (user units) per ex (i.e. the x-height in user
    * units) for an nsIContent
    *
    * XXX document the conditions under which these may fail, and what they
    * return in those cases.
    */
   static float GetFontXHeight(mozilla::dom::Element *aElement);
   static float GetFontXHeight(nsIFrame *aFrame);
-  static float GetFontXHeight(nsStyleContext *aStyleContext);
+  static float GetFontXHeight(ComputedStyle *aComputedStyle);
 
   /*
    * Report a localized error message to the error console.
    */
   static nsresult ReportToConsole(nsIDocument* doc,
                                   const char* aWarning,
                                   const char16_t **aParams,
                                   uint32_t aParamsLength);
--- a/dom/svg/SVGFEDropShadowElement.cpp
+++ b/dom/svg/SVGFEDropShadowElement.cpp
@@ -104,17 +104,17 @@ SVGFEDropShadowElement::GetPrimitiveDesc
                             SVGContentUtils::Y, &mNumberAttributes[DY])));
 
   FilterPrimitiveDescription descr(PrimitiveType::DropShadow);
   descr.Attributes().Set(eDropShadowStdDeviation, Size(stdX, stdY));
   descr.Attributes().Set(eDropShadowOffset, offset);
 
   nsIFrame* frame = GetPrimaryFrame();
   if (frame) {
-    nsStyleContext* style = frame->StyleContext();
+    ComputedStyle* style = frame->Style();
     Color color(Color::FromABGR(style->StyleSVGReset()->mFloodColor));
     color.a *= style->StyleSVGReset()->mFloodOpacity;
     descr.Attributes().Set(eDropShadowColor, color);
   } else {
     descr.Attributes().Set(eDropShadowColor, Color());
   }
   return descr;
 }
--- a/dom/svg/SVGFEFloodElement.cpp
+++ b/dom/svg/SVGFEFloodElement.cpp
@@ -38,17 +38,17 @@ FilterPrimitiveDescription
 SVGFEFloodElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
                                            const IntRect& aFilterSubregion,
                                            const nsTArray<bool>& aInputsAreTainted,
                                            nsTArray<RefPtr<SourceSurface>>& aInputImages)
 {
   FilterPrimitiveDescription descr(PrimitiveType::Flood);
   nsIFrame* frame = GetPrimaryFrame();
   if (frame) {
-    nsStyleContext* style = frame->StyleContext();
+    ComputedStyle* style = frame->Style();
     Color color(Color::FromABGR(style->StyleSVGReset()->mFloodColor));
     color.a *= style->StyleSVGReset()->mFloodOpacity;
     descr.Attributes().Set(eFloodColor, color);
   } else {
     descr.Attributes().Set(eFloodColor, Color());
   }
   return descr;
 }
--- a/dom/svg/SVGGeometryElement.cpp
+++ b/dom/svg/SVGGeometryElement.cpp
@@ -133,18 +133,18 @@ SVGGeometryElement::GetOrBuildPathForMea
   return GetOrBuildPath(drawTarget, fillRule);
 }
 
 FillRule
 SVGGeometryElement::GetFillRule()
 {
   FillRule fillRule = FillRule::FILL_WINDING; // Equivalent to StyleFillRule::Nonzero
 
-  RefPtr<nsStyleContext> styleContext =
-    nsComputedDOMStyle::GetStyleContextNoFlush(this, nullptr);
+  RefPtr<ComputedStyle> styleContext =
+    nsComputedDOMStyle::GetComputedStyleNoFlush(this, nullptr);
 
   if (styleContext) {
     MOZ_ASSERT(styleContext->StyleSVG()->mFillRule == StyleFillRule::Nonzero ||
                styleContext->StyleSVG()->mFillRule == StyleFillRule::Evenodd);
 
     if (styleContext->StyleSVG()->mFillRule == StyleFillRule::Evenodd) {
       fillRule = FillRule::FILL_EVEN_ODD;
     }
--- a/dom/svg/SVGPathElement.cpp
+++ b/dom/svg/SVGPathElement.cpp
@@ -293,18 +293,18 @@ SVGPathElement::BuildPath(PathBuilder* a
   // spec regarding zero length sub-paths when square line caps are in use,
   // SVGPathData needs to know our stroke-linecap style and, if "square", then
   // also our stroke width. See the comment for
   // ApproximateZeroLengthSubpathSquareCaps for more info.
 
   uint8_t strokeLineCap = NS_STYLE_STROKE_LINECAP_BUTT;
   Float strokeWidth = 0;
 
-  RefPtr<nsStyleContext> styleContext =
-    nsComputedDOMStyle::GetStyleContextNoFlush(this, nullptr);
+  RefPtr<ComputedStyle> styleContext =
+    nsComputedDOMStyle::GetComputedStyleNoFlush(this, nullptr);
   if (styleContext) {
     const nsStyleSVG* style = styleContext->StyleSVG();
     // Note: the path that we return may be used for hit-testing, and SVG
     // exposes hit-testing of strokes that are not actually painted. For that
     // reason we do not check for eStyleSVGPaintType_None or check the stroke
     // opacity here.
     if (style->mStrokeLinecap != NS_STYLE_STROKE_LINECAP_BUTT) {
       strokeLineCap = style->mStrokeLinecap;
--- a/dom/svg/nsSVGFilters.cpp
+++ b/dom/svg/nsSVGFilters.cpp
@@ -17,17 +17,17 @@
 #include "nsSVGFilterInstance.h"
 #include "nsSVGEnum.h"
 #include "SVGNumberList.h"
 #include "SVGAnimatedNumberList.h"
 #include "DOMSVGAnimatedNumberList.h"
 #include "nsSVGFilters.h"
 #include "nsLayoutUtils.h"
 #include "nsSVGUtils.h"
-#include "nsStyleContext.h"
+#include "mozilla/ComputedStyle.h"
 #include "nsIFrame.h"
 #include "imgIContainer.h"
 #include "mozilla/dom/SVGFilterElement.h"
 #include "nsSVGString.h"
 #include "SVGContentUtils.h"
 #include <algorithm>
 #include "mozilla/dom/SVGAnimatedLength.h"
 #include "mozilla/dom/SVGComponentTransferFunctionElement.h"
@@ -156,17 +156,17 @@ nsSVGFE::IsAttributeMapped(const nsAtom*
 
 
 bool
 nsSVGFE::StyleIsSetToSRGB()
 {
   nsIFrame* frame = GetPrimaryFrame();
   if (!frame) return false;
 
-  nsStyleContext* style = frame->StyleContext();
+  ComputedStyle* style = frame->Style();
   return style->StyleSVG()->mColorInterpolationFilters ==
            NS_STYLE_COLOR_INTERPOLATION_SRGB;
 }
 
 /* virtual */ bool
 nsSVGFE::HasValidDimensions() const
 {
   return (!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() ||
@@ -497,17 +497,17 @@ FilterPrimitiveDescription
 nsSVGFELightingElement::AddLightingAttributes(const FilterPrimitiveDescription& aDescription,
                                               nsSVGFilterInstance* aInstance)
 {
   nsIFrame* frame = GetPrimaryFrame();
   if (!frame) {
     return FilterPrimitiveDescription(PrimitiveType::Empty);
   }
 
-  nsStyleContext* style = frame->StyleContext();
+  ComputedStyle* style = frame->Style();
   Color color(Color::FromABGR(style->StyleSVGReset()->mLightingColor));
   color.a = 1.f;
   float surfaceScale = mNumberAttributes[SURFACE_SCALE].GetAnimValue();
   Size kernelUnitLength =
     GetKernelUnitLength(aInstance, &mNumberPairAttributes[KERNEL_UNIT_LENGTH]);
 
   if (kernelUnitLength.width <= 0 || kernelUnitLength.height <= 0) {
     // According to spec, A negative or zero value is an error. See link below for details.
--- a/dom/webidl/RTCDataChannelEvent.webidl
+++ b/dom/webidl/RTCDataChannelEvent.webidl
@@ -3,16 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCDataChannelEvent
  */
 
 dictionary RTCDataChannelEventInit : EventInit {
-    RTCDataChannel? channel = null;
+    required RTCDataChannel channel;
 };
 
 [Pref="media.peerconnection.enabled",
- Constructor(DOMString type, optional RTCDataChannelEventInit eventInitDict)]
+ Constructor(DOMString type, RTCDataChannelEventInit eventInitDict)]
 interface RTCDataChannelEvent : Event {
-  readonly attribute RTCDataChannel? channel;
+  readonly attribute RTCDataChannel channel;
 };
--- a/dom/xbl/nsXBLResourceLoader.cpp
+++ b/dom/xbl/nsXBLResourceLoader.cpp
@@ -12,23 +12,23 @@
 #include "nsIPresShell.h"
 #include "nsXBLService.h"
 #include "nsIServiceManager.h"
 #include "nsXBLResourceLoader.h"
 #include "nsXBLPrototypeResources.h"
 #include "nsIDocumentObserver.h"
 #include "imgILoader.h"
 #include "imgRequestProxy.h"
+#include "mozilla/ComputedStyle.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/css/Loader.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsGkAtoms.h"
-#include "nsStyleContext.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 
 using namespace mozilla;
 
 NS_IMPL_CYCLE_COLLECTION(nsXBLResourceLoader, mBoundElements)
 
@@ -253,17 +253,17 @@ nsXBLResourceLoader::NotifyBoundElements
         // has a primary frame and whether it's in the undisplayed map
         // before sending a ContentInserted notification, or bad things
         // will happen.
         nsIPresShell *shell = doc->GetShell();
         if (shell) {
           nsIFrame* childFrame = content->GetPrimaryFrame();
           if (!childFrame) {
             // Check if it's in the display:none or display:contents maps.
-            nsStyleContext* sc =
+            ComputedStyle* sc =
               shell->FrameConstructor()->GetDisplayNoneStyleFor(content);
 
             if (!sc) {
               sc = shell->FrameConstructor()->GetDisplayContentsStyleFor(content);
             }
 
             if (!sc) {
               shell->PostRecreateFramesFor(content->AsElement());
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/ComputedStyle.h"
 
 #include "nsCOMPtr.h"
 #include "nsNetUtil.h"
 #include "nsXBLService.h"
 #include "nsXBLWindowKeyHandler.h"
 #include "nsIInputStream.h"
 #include "nsNameSpaceManager.h"
 #include "nsIURI.h"
@@ -36,17 +37,16 @@
 #include "nsSyncLoadService.h"
 #include "nsContentPolicyUtils.h"
 #include "nsTArray.h"
 #include "nsError.h"
 
 #include "nsIPresShell.h"
 #include "nsIDocumentObserver.h"
 #include "nsFrameManager.h"
-#include "nsStyleContext.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptError.h"
 #include "nsXBLSerialize.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPrototypeCache.h"
 #endif
 #include "nsIDOMEventListener.h"
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -666,54 +666,35 @@ nsXULElement::UpdateEditableState(bool a
     // Don't call through to Element here because the things
     // it does don't work for cases when we're an editable control.
     nsIContent *parent = GetParent();
 
     SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
     UpdateState(aNotify);
 }
 
+#ifdef DEBUG
 /**
  * Returns true if the user-agent style sheet rules for this XUL element are
  * in minimal-xul.css instead of xul.css.
  */
 static inline bool XULElementsRulesInMinimalXULSheet(nsAtom* aTag)
 {
   return // scrollbar parts:
          aTag == nsGkAtoms::scrollbar ||
          aTag == nsGkAtoms::scrollbarbutton ||
          aTag == nsGkAtoms::scrollcorner ||
          aTag == nsGkAtoms::slider ||
          aTag == nsGkAtoms::thumb ||
-         aTag == nsGkAtoms::scale ||
          // other
          aTag == nsGkAtoms::datetimebox ||
          aTag == nsGkAtoms::resizer ||
          aTag == nsGkAtoms::label ||
          aTag == nsGkAtoms::videocontrols;
 }
-
-#ifdef DEBUG
-/**
- * Returns true if aElement is a XUL element created by the video controls
- * binding. HTML <video> and <audio> bindings pull in this binding. This
- * binding creates lots of different types of XUL elements.
- */
-static inline bool
-IsInVideoControls(nsXULElement* aElement)
-{
-  nsIContent* ancestor = aElement->GetParent();
-  while (ancestor) {
-    if (ancestor->NodeInfo()->Equals(nsGkAtoms::videocontrols, kNameSpaceID_XUL)) {
-      return true;
-    }
-    ancestor = ancestor->GetParent();
-  }
-  return false;
-}
 #endif
 
 class XULInContentErrorReporter : public Runnable
 {
 public:
   explicit XULInContentErrorReporter(nsIDocument* aDocument)
     : mozilla::Runnable("XULInContentErrorReporter")
     , mDocument(aDocument)
@@ -758,47 +739,33 @@ nsXULElement::BindToTree(nsIDocument* aD
   }
 
   nsresult rv = nsStyledElement::BindToTree(aDocument, aParent,
                                             aBindingParent,
                                             aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsIDocument* doc = GetComposedDoc();
+#ifdef DEBUG
   if (doc &&
       !doc->LoadsFullXULStyleSheetUpFront() &&
       !doc->IsUnstyledDocument()) {
 
     // To save CPU cycles and memory, non-XUL documents only load the user
     // agent style sheet rules for a minimal set of XUL elements such as
     // 'scrollbar' that may be created implicitly for their content (those
-    // rules being in minimal-xul.css).  This is where we make sure that all
-    // the other XUL UA style sheet rules (xul.css) have been loaded if the
-    // minimal set is not sufficient.
+    // rules being in minimal-xul.css).
     //
-    // We do this during binding, not element construction, because elements
-    // can be moved from the document that creates them to another document.
-
+    // This assertion makes sure no other XUL element than the ones in the
+    // minimal XUL sheet is used in the bindings.
     if (!XULElementsRulesInMinimalXULSheet(NodeInfo()->NameAtom())) {
-      auto cache = nsLayoutStylesheetCache::For(doc->GetStyleBackendType());
-      doc->EnsureOnDemandBuiltInUASheet(cache->XULSheet());
-      // To keep memory usage down it is important that we try and avoid
-      // pulling xul.css into non-XUL documents. That should be very rare, and
-      // for HTML we currently should only pull it in if the document contains
-      // an <audio> or <video> element. This assertion is here to make sure
-      // that we don't fail to notice if a change to bindings causes us to
-      // start pulling in xul.css much more frequently. If this assertion
-      // fails then we need to figure out why, and how we can continue to avoid
-      // pulling in xul.css.
-      // Note that add-ons may introduce bindings that cause this assertion to
-      // fire.
-      NS_ASSERTION(IsInVideoControls(this),
-                   "Unexpected XUL element in non-XUL doc");
+      NS_ERROR("Unexpected XUL element in non-XUL doc");
     }
   }
+#endif
 
   if (doc && NeedTooltipSupport(*this)) {
       AddTooltipSupport();
   }
 
   if (aDocument) {
       NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
                    "Missing a script blocker!");
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -23,16 +23,17 @@
 #include "InsertNodeTransaction.h"      // for InsertNodeTransaction
 #include "InsertTextTransaction.h"      // for InsertTextTransaction
 #include "JoinNodeTransaction.h"        // for JoinNodeTransaction
 #include "PlaceholderTransaction.h"     // for PlaceholderTransaction
 #include "SplitNodeTransaction.h"       // for SplitNodeTransaction
 #include "StyleSheetTransactions.h"     // for AddStyleSheetTransaction, etc.
 #include "TextEditUtils.h"              // for TextEditUtils
 #include "mozilla/CheckedInt.h"         // for CheckedInt
+#include "mozilla/ComputedStyle.h"      // for ComputedStyle
 #include "mozilla/EditAction.h"         // for EditAction
 #include "mozilla/EditorDOMPoint.h"     // for EditorDOMPoint
 #include "mozilla/EditorSpellCheck.h"   // for EditorSpellCheck
 #include "mozilla/EditorUtils.h"        // for AutoRules, etc.
 #include "mozilla/EditTransactionBase.h" // for EditTransactionBase
 #include "mozilla/FlushType.h"          // for FlushType::Frames
 #include "mozilla/IMEContentObserver.h" // for IMEContentObserver
 #include "mozilla/IMEStateManager.h"    // for IMEStateManager
@@ -98,17 +99,16 @@
 #include "nsIWidget.h"                  // for nsIWidget, IMEState, etc.
 #include "nsPIDOMWindow.h"              // for nsPIDOMWindow
 #include "nsPresContext.h"              // for nsPresContext
 #include "nsRange.h"                    // for nsRange
 #include "nsReadableUtils.h"            // for EmptyString, ToNewCString
 #include "nsString.h"                   // for nsAutoString, nsString, etc.
 #include "nsStringFwd.h"                // for nsString
 #include "nsStyleConsts.h"              // for NS_STYLE_DIRECTION_RTL, etc.
-#include "nsStyleContext.h"             // for nsStyleContext
 #include "nsStyleStruct.h"              // for nsStyleDisplay, nsStyleText, etc.
 #include "nsStyleStructFwd.h"           // for nsIFrame::StyleUIReset, etc.
 #include "nsTextNode.h"                 // for nsTextNode
 #include "nsThreadUtils.h"              // for nsRunnable
 #include "nsTransactionManager.h"       // for nsTransactionManager
 #include "prtime.h"                     // for PR_Now
 
 class nsIOutputStream;
@@ -4104,23 +4104,23 @@ EditorBase::IsPreformatted(nsIDOMNode* a
   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
 
   NS_ENSURE_TRUE(aResult && content, NS_ERROR_NULL_POINTER);
 
   nsCOMPtr<nsIPresShell> ps = GetPresShell();
   NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
 
   // Look at the node (and its parent if it's not an element), and grab its style context
-  RefPtr<nsStyleContext> elementStyle;
+  RefPtr<ComputedStyle> elementStyle;
   if (!content->IsElement()) {
     content = content->GetParent();
   }
   if (content && content->IsElement()) {
     elementStyle =
-      nsComputedDOMStyle::GetStyleContextNoFlush(content->AsElement(), nullptr);
+      nsComputedDOMStyle::GetComputedStyleNoFlush(content->AsElement(), nullptr);
   }
 
   if (!elementStyle) {
     // Consider nodes without a style context to be NOT preformatted:
     // For instance, this is true of JS tags inside the body (which show
     // up as #text nodes but have no style context).
     *aResult = false;
     return NS_OK;
--- a/editor/libeditor/HTMLAbsPositionEditor.cpp
+++ b/editor/libeditor/HTMLAbsPositionEditor.cpp
@@ -616,18 +616,18 @@ HTMLEditor::GetTemporaryStyleForFocusedP
   rv =
     CSSEditUtils::GetComputedProperty(aElement, *nsGkAtoms::backgroundColor,
                                       bgColorStr);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!bgColorStr.EqualsLiteral("rgba(0, 0, 0, 0)")) {
     return NS_OK;
   }
 
-  RefPtr<nsStyleContext> style =
-    nsComputedDOMStyle::GetStyleContext(&aElement, nullptr);
+  RefPtr<ComputedStyle> style =
+    nsComputedDOMStyle::GetComputedStyle(&aElement, nullptr);
   NS_ENSURE_STATE(style);
 
   const uint8_t kBlackBgTrigger = 0xd0;
 
   nscolor color = style->StyleColor()->mColor;
   if (NS_GET_R(color) >= kBlackBgTrigger &&
       NS_GET_G(color) >= kBlackBgTrigger &&
       NS_GET_B(color) >= kBlackBgTrigger) {
--- a/gfx/webrender/Cargo.toml
+++ b/gfx/webrender/Cargo.toml
@@ -11,18 +11,18 @@ default = ["freetype-lib"]
 freetype-lib = ["freetype/servo-freetype-sys"]
 profiler = ["thread_profiler/thread_profiler"]
 debugger = ["ws", "serde_json", "serde", "image", "base64"]
 capture = ["webrender_api/serialize", "ron", "serde"]
 replay = ["webrender_api/deserialize", "ron", "serde"]
 
 [dependencies]
 app_units = "0.6"
-bincode = "0.9"
 byteorder = "1.0"
+bincode = "1.0"
 euclid = "0.17"
 fxhash = "0.2.1"
 gleam = "0.4.20"
 lazy_static = "1"
 log = "0.4"
 num-traits = "0.1.32"
 time = "0.1"
 rayon = "1"
--- a/gfx/webrender/examples/basic.rs
+++ b/gfx/webrender/examples/basic.rs
@@ -197,17 +197,17 @@ impl Example for App {
             None,
             MixBlendMode::Normal,
             Vec::new(),
         );
 
         let image_mask_key = api.generate_image_key();
         resources.add_image(
             image_mask_key,
-            ImageDescriptor::new(2, 2, ImageFormat::R8, true),
+            ImageDescriptor::new(2, 2, ImageFormat::R8, true, false),
             ImageData::new(vec![0, 80, 180, 255]),
             None,
         );
         let mask = ImageMask {
             image: image_mask_key,
             rect: (75, 75).by(100, 100),
             repeat: false,
         };
--- a/gfx/webrender/examples/blob.rs
+++ b/gfx/webrender/examples/blob.rs
@@ -227,25 +227,25 @@ impl Example for App {
         resources: &mut ResourceUpdates,
         _framebuffer_size: api::DeviceUintSize,
         _pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         let blob_img1 = api.generate_image_key();
         resources.add_image(
             blob_img1,
-            api::ImageDescriptor::new(500, 500, api::ImageFormat::BGRA8, true),
+            api::ImageDescriptor::new(500, 500, api::ImageFormat::BGRA8, true, false),
             api::ImageData::new_blob_image(serialize_blob(api::ColorU::new(50, 50, 150, 255))),
             Some(128),
         );
 
         let blob_img2 = api.generate_image_key();
         resources.add_image(
             blob_img2,
-            api::ImageDescriptor::new(200, 200, api::ImageFormat::BGRA8, true),
+            api::ImageDescriptor::new(200, 200, api::ImageFormat::BGRA8, true, false),
             api::ImageData::new_blob_image(serialize_blob(api::ColorU::new(50, 150, 50, 255))),
             None,
         );
 
         let bounds = api::LayoutRect::new(api::LayoutPoint::zero(), builder.content_size());
         let info = api::LayoutPrimitiveInfo::new(bounds);
         builder.push_stacking_context(
             &info,
--- a/gfx/webrender/examples/common/boilerplate.rs
+++ b/gfx/webrender/examples/common/boilerplate.rs
@@ -133,17 +133,16 @@ pub fn main_wrapper<E: Example>(
     println!("OpenGL version {}", gl.get_string(gl::VERSION));
     println!("Shader resource path: {:?}", res_path);
     let device_pixel_ratio = window.hidpi_factor();
     println!("Device pixel ratio: {}", device_pixel_ratio);
 
     println!("Loading shaders...");
     let opts = webrender::RendererOptions {
         resource_override_path: res_path,
-        debug: true,
         precache_shaders: E::PRECACHE_SHADERS,
         device_pixel_ratio,
         clear_color: Some(ColorF::new(0.3, 0.0, 0.0, 1.0)),
         //scatter_gpu_cache_updates: false,
         ..options.unwrap_or(webrender::RendererOptions::default())
     };
 
     let framebuffer_size = {
--- a/gfx/webrender/examples/common/image_helper.rs
+++ b/gfx/webrender/examples/common/image_helper.rs
@@ -7,10 +7,10 @@ use webrender::api::{ImageData, ImageDes
 pub fn make_checkerboard(width: u32, height: u32) -> (ImageDescriptor, ImageData) {
     let mut image_data = Vec::new();
     for y in 0 .. height {
         for x in 0 .. width {
             let lum = 255 * (((x & 8) == 0) ^ ((y & 8) == 0)) as u8;
             image_data.extend_from_slice(&[lum, lum, lum, 0xff]);
         }
     }
-    (ImageDescriptor::new(width, height, ImageFormat::BGRA8, true), ImageData::new(image_data))
+    (ImageDescriptor::new(width, height, ImageFormat::BGRA8, true, false), ImageData::new(image_data))
 }
--- a/gfx/webrender/examples/frame_output.rs
+++ b/gfx/webrender/examples/frame_output.rs
@@ -65,17 +65,17 @@ impl App {
         framebuffer_size: DeviceUintSize,
         device_pixel_ratio: f32,
     ) {
         // Generate the external image key that will be used to render the output document to the root document.
         self.external_image_key = Some(api.generate_image_key());
         let mut resources = ResourceUpdates::new();
         resources.add_image(
             self.external_image_key.unwrap(),
-            ImageDescriptor::new(100, 100, ImageFormat::BGRA8, true),
+            ImageDescriptor::new(100, 100, ImageFormat::BGRA8, true, false),
             ImageData::External(ExternalImageData {
                 id: ExternalImageId(0),
                 channel_index: 0,
                 image_type: ExternalImageType::TextureHandle(TextureTarget::Default),
             }),
             None,
         );
 
--- a/gfx/webrender/examples/image_resize.rs
+++ b/gfx/webrender/examples/image_resize.rs
@@ -96,17 +96,17 @@ impl Example for App {
                         let g = 255 * ((x & 32) == 0) as u8;
                         image_data.extend_from_slice(&[0, g, r, 0xff]);
                     }
                 }
 
                 let mut updates = ResourceUpdates::new();
                 updates.update_image(
                     self.image_key,
-                    ImageDescriptor::new(64, 64, ImageFormat::BGRA8, true),
+                    ImageDescriptor::new(64, 64, ImageFormat::BGRA8, true, false),
                     ImageData::new(image_data),
                     None,
                 );
                 let mut txn = Transaction::new();
                 txn.update_resources(updates);
                 txn.generate_frame();
                 api.send_transaction(document_id, txn);
             }
--- a/gfx/webrender/examples/multiwindow.rs
+++ b/gfx/webrender/examples/multiwindow.rs
@@ -81,17 +81,16 @@ impl Window {
                 gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _)
             },
             glutin::Api::WebGl => unimplemented!(),
         };
 
         let device_pixel_ratio = window.hidpi_factor();
 
         let opts = webrender::RendererOptions {
-            debug: true,
             device_pixel_ratio,
             clear_color: Some(clear_color),
             ..webrender::RendererOptions::default()
         };
 
         let framebuffer_size = {
             let (width, height) = window.get_inner_size().unwrap();
             DeviceUintSize::new(width, height)
--- a/gfx/webrender/examples/texture_cache_stress.rs
+++ b/gfx/webrender/examples/texture_cache_stress.rs
@@ -106,25 +106,25 @@ impl Example for App {
 
         if self.swap_keys.is_empty() {
             let key0 = api.generate_image_key();
             let key1 = api.generate_image_key();
 
             self.image_generator.generate_image(128);
             resources.add_image(
                 key0,
-                ImageDescriptor::new(128, 128, ImageFormat::BGRA8, true),
+                ImageDescriptor::new(128, 128, ImageFormat::BGRA8, true, false),
                 ImageData::new(self.image_generator.take()),
                 None,
             );
 
             self.image_generator.generate_image(128);
             resources.add_image(
                 key1,
-                ImageDescriptor::new(128, 128, ImageFormat::BGRA8, true),
+                ImageDescriptor::new(128, 128, ImageFormat::BGRA8, true, false),
                 ImageData::new(self.image_generator.take()),
                 None,
             );
 
             self.swap_keys.push(key0);
             self.swap_keys.push(key1);
         }
 
@@ -210,17 +210,17 @@ impl Example for App {
                                 let size = 4;
 
                                 let image_key = api.generate_image_key();
 
                                 self.image_generator.generate_image(size);
 
                                 updates.add_image(
                                     image_key,
-                                    ImageDescriptor::new(size, size, ImageFormat::BGRA8, true),
+                                    ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false),
                                     ImageData::new(self.image_generator.take()),
                                     None,
                                 );
 
                                 self.stress_keys.push(image_key);
                             }
                         }
                     }
@@ -228,17 +228,17 @@ impl Example for App {
                         updates.delete_image(image_key);
                     },
                     glutin::VirtualKeyCode::U => if let Some(image_key) = self.image_key {
                         let size = 128;
                         self.image_generator.generate_image(size);
 
                         updates.update_image(
                             image_key,
-                            ImageDescriptor::new(size, size, ImageFormat::BGRA8, true),
+                            ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false),
                             ImageData::new(self.image_generator.take()),
                             None,
                         );
                     },
                     glutin::VirtualKeyCode::E => {
                         if let Some(image_key) = self.image_key.take() {
                             updates.delete_image(image_key);
                         }
@@ -249,17 +249,17 @@ impl Example for App {
                         let image_data = ExternalImageData {
                             id: ExternalImageId(0),
                             channel_index: size as u8,
                             image_type: ExternalImageType::Buffer,
                         };
 
                         updates.add_image(
                             image_key,
-                            ImageDescriptor::new(size, size, ImageFormat::BGRA8, true),
+                            ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false),
                             ImageData::External(image_data),
                             None,
                         );
 
                         self.image_key = Some(image_key);
                     }
                     glutin::VirtualKeyCode::R => {
                         if let Some(image_key) = self.image_key.take() {
@@ -267,17 +267,17 @@ impl Example for App {
                         }
 
                         let image_key = api.generate_image_key();
                         let size = 32;
                         self.image_generator.generate_image(size);
 
                         updates.add_image(
                             image_key,
-                            ImageDescriptor::new(size, size, ImageFormat::BGRA8, true),
+                            ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false),
                             ImageData::new(self.image_generator.take()),
                             None,
                         );
 
                         self.image_key = Some(image_key);
                     }
                     _ => {}
                 }
--- a/gfx/webrender/examples/yuv.rs
+++ b/gfx/webrender/examples/yuv.rs
@@ -96,53 +96,53 @@ impl Example for App {
         );
 
         let yuv_chanel1 = api.generate_image_key();
         let yuv_chanel2 = api.generate_image_key();
         let yuv_chanel2_1 = api.generate_image_key();
         let yuv_chanel3 = api.generate_image_key();
         resources.add_image(
             yuv_chanel1,
-            ImageDescriptor::new(100, 100, ImageFormat::R8, true),
+            ImageDescriptor::new(100, 100, ImageFormat::R8, true, false),
             ImageData::External(ExternalImageData {
                 id: ExternalImageId(0),
                 channel_index: 0,
                 image_type: ExternalImageType::TextureHandle(
                     TextureTarget::Default,
                 ),
             }),
             None,
         );
         resources.add_image(
             yuv_chanel2,
-            ImageDescriptor::new(100, 100, ImageFormat::RG8, true),
+            ImageDescriptor::new(100, 100, ImageFormat::RG8, true, false),
             ImageData::External(ExternalImageData {
                 id: ExternalImageId(1),
                 channel_index: 0,
                 image_type: ExternalImageType::TextureHandle(
                     TextureTarget::Default,
                 ),
             }),
             None,
         );
         resources.add_image(
             yuv_chanel2_1,
-            ImageDescriptor::new(100, 100, ImageFormat::R8, true),
+            ImageDescriptor::new(100, 100, ImageFormat::R8, true, false),
             ImageData::External(ExternalImageData {
                 id: ExternalImageId(2),
                 channel_index: 0,
                 image_type: ExternalImageType::TextureHandle(
                     TextureTarget::Default,
                 ),
             }),
             None,
         );
         resources.add_image(
             yuv_chanel3,
-            ImageDescriptor::new(100, 100, ImageFormat::R8, true),
+            ImageDescriptor::new(100, 100, ImageFormat::R8, true, false),
             ImageData::External(ExternalImageData {
                 id: ExternalImageId(3),
                 channel_index: 0,
                 image_type: ExternalImageType::TextureHandle(
                     TextureTarget::Default,
                 ),
             }),
             None,
--- a/gfx/webrender/res/brush.glsl
+++ b/gfx/webrender/res/brush.glsl
@@ -84,94 +84,66 @@ void main(void) {
     RectWithSize local_segment_rect = RectWithSize(segment_data[0].xy, segment_data[0].zw);
 
     VertexInfo vi;
 
     // Fetch the dynamic picture that we are drawing on.
     PictureTask pic_task = fetch_picture_task(brush.picture_address);
     ClipArea clip_area = fetch_clip_area(brush.clip_address);
 
-    if (pic_task.pic_kind_and_raster_mode > 0.0) {
-        vec2 local_pos = local_segment_rect.p0 + aPosition.xy * local_segment_rect.size;
-        vec2 clamped_local_pos = clamp_rect(local_pos, brush_prim.local_clip_rect);
-
-        vec2 device_pos = uDevicePixelRatio * clamped_local_pos;
-
-        vec2 final_pos = device_pos +
-                         pic_task.common_data.task_rect.p0 -
-                         uDevicePixelRatio * pic_task.content_origin;
+    ClipScrollNode scroll_node = fetch_clip_scroll_node(brush.scroll_node_id);
 
-#ifdef WR_FEATURE_ALPHA_PASS
-        write_clip(
-            vec2(0.0),
-            clip_area
-        );
-#endif
-
-        vi = VertexInfo(
-            local_pos,
-            device_pos,
-            1.0,
-            device_pos
+    // Write the normal vertex information out.
+    if (scroll_node.is_axis_aligned) {
+        vi = write_vertex(
+            local_segment_rect,
+            brush_prim.local_clip_rect,
+            float(brush.z),
+            scroll_node,
+            pic_task,
+            brush_prim.local_rect
         );
 
-        // Write the final position transformed by the orthographic device-pixel projection.
-        gl_Position = uTransform * vec4(final_pos, 0.0, 1.0);
-    } else {
-        ClipScrollNode scroll_node = fetch_clip_scroll_node(brush.scroll_node_id);
-
-        // Write the normal vertex information out.
-        if (scroll_node.is_axis_aligned) {
-            vi = write_vertex(
-                local_segment_rect,
-                brush_prim.local_clip_rect,
-                float(brush.z),
-                scroll_node,
-                pic_task,
-                brush_prim.local_rect
-            );
-
-            // TODO(gw): vLocalBounds may be referenced by
-            //           the fragment shader when running in
-            //           the alpha pass, even on non-transformed
-            //           items. For now, just ensure it has no
-            //           effect. We can tidy this up as we move
-            //           more items to be brush shaders.
+        // TODO(gw): vLocalBounds may be referenced by
+        //           the fragment shader when running in
+        //           the alpha pass, even on non-transformed
+        //           items. For now, just ensure it has no
+        //           effect. We can tidy this up as we move
+        //           more items to be brush shaders.
 #ifdef WR_FEATURE_ALPHA_PASS
-            vLocalBounds = vec4(vec2(-1000000.0), vec2(1000000.0));
+        vLocalBounds = vec4(vec2(-1000000.0), vec2(1000000.0));
 #endif
-        } else {
-            bvec4 edge_mask = notEqual(brush.edge_mask & ivec4(1, 2, 4, 8), ivec4(0));
-            bool do_perspective_interpolation = (brush.flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0;
+    } else {
+        bvec4 edge_mask = notEqual(brush.edge_mask & ivec4(1, 2, 4, 8), ivec4(0));
+        bool do_perspective_interpolation = (brush.flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0;
 
-            vi = write_transform_vertex(
-                local_segment_rect,
-                brush_prim.local_rect,
-                brush_prim.local_clip_rect,
-                mix(vec4(0.0), vec4(1.0), edge_mask),
-                float(brush.z),
-                scroll_node,
-                pic_task,
-                do_perspective_interpolation
-            );
-        }
+        vi = write_transform_vertex(
+            local_segment_rect,
+            brush_prim.local_rect,
+            brush_prim.local_clip_rect,
+            mix(vec4(0.0), vec4(1.0), edge_mask),
+            float(brush.z),
+            scroll_node,
+            pic_task,
+            do_perspective_interpolation
+        );
+    }
 
-        // For brush instances in the alpha pass, always write
-        // out clip information.
-        // TODO(gw): It's possible that we might want alpha
-        //           shaders that don't clip in the future,
-        //           but it's reasonable to assume that one
-        //           implies the other, for now.
+    // For brush instances in the alpha pass, always write
+    // out clip information.
+    // TODO(gw): It's possible that we might want alpha
+    //           shaders that don't clip in the future,
+    //           but it's reasonable to assume that one
+    //           implies the other, for now.
 #ifdef WR_FEATURE_ALPHA_PASS
-        write_clip(
-            vi.screen_pos,
-            clip_area
-        );
+    write_clip(
+        vi.screen_pos,
+        clip_area
+    );
 #endif
-    }
 
     // Run the specific brush VS code to write interpolators.
     brush_vs(
         vi,
         brush.prim_address + VECS_PER_BRUSH_PRIM,
         brush_prim.local_rect,
         brush.user_data,
         pic_task
--- a/gfx/webrender/res/brush_image.glsl
+++ b/gfx/webrender/res/brush_image.glsl
@@ -89,17 +89,21 @@ void brush_vs(
             ) / texture_size.xyxy;
             break;
         case RASTER_LOCAL:
         default: {
             f = (vi.local_pos - local_rect.p0) / local_rect.size;
 
             // Set the clip bounds to a value that won't have any
             // effect for local space images.
+#ifdef WR_FEATURE_TEXTURE_RECT
+            vUvClipBounds = vec4(0.0, 0.0, vec2(textureSize(sColor0)));
+#else
             vUvClipBounds = vec4(0.0, 0.0, 1.0, 1.0);
+#endif
             break;
         }
     }
 #else
     f = (vi.local_pos - local_rect.p0) / local_rect.size;
 #endif
 
     vUv.xy = mix(uv0, uv1, f);
deleted file mode 100644
--- a/gfx/webrender/res/cs_text_run.glsl
+++ /dev/null
@@ -1,68 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include shared,prim_shared
-
-varying vec3 vUv;
-flat varying vec4 vColor;
-flat varying vec4 vStRect;
-
-#ifdef WR_VERTEX_SHADER
-// Draw a text run to a cache target. These are always
-// drawn un-transformed. These are used for effects such
-// as text-shadow.
-
-void main(void) {
-    Primitive prim = load_primitive();
-    TextRun text = fetch_text_run(prim.specific_prim_address);
-
-    int glyph_index = prim.user_data0;
-    int resource_address = prim.user_data1;
-    int subpx_dir = prim.user_data2;
-
-    Glyph glyph = fetch_glyph(prim.specific_prim_address,
-                              glyph_index,
-                              subpx_dir);
-
-    GlyphResource res = fetch_glyph_resource(resource_address);
-
-    // Scale from glyph space to local space.
-    float scale = res.scale / uDevicePixelRatio;
-
-    // Compute the glyph rect in local space.
-    RectWithSize glyph_rect = RectWithSize(scale * res.offset + text.offset + glyph.offset,
-                                           scale * (res.uv_rect.zw - res.uv_rect.xy));
-
-    // Select the corner of the glyph rect that we are processing.
-    vec2 local_pos = (glyph_rect.p0 + glyph_rect.size * aPosition.xy);
-
-    // Clamp the local position to the text run's local clipping rectangle.
-    local_pos = clamp_rect(local_pos, prim.local_clip_rect);
-
-    // Move the point into device pixel space.
-    local_pos = (local_pos - prim.task.content_origin) * uDevicePixelRatio;
-    local_pos += prim.task.common_data.task_rect.p0;
-    gl_Position = uTransform * vec4(local_pos, 0.0, 1.0);
-
-    vec2 texture_size = vec2(textureSize(sColor0, 0));
-    vec2 st0 = res.uv_rect.xy / texture_size;
-    vec2 st1 = res.uv_rect.zw / texture_size;
-
-    vUv = vec3(mix(st0, st1, aPosition.xy), res.layer);
-    vColor = prim.task.color;
-
-    // We clamp the texture coordinates to the half-pixel offset from the borders
-    // in order to avoid sampling outside of the texture area.
-    vec2 half_texel = vec2(0.5) / texture_size;
-    vStRect = vec4(min(st0, st1) + half_texel, max(st0, st1) - half_texel);
-}
-#endif
-
-#ifdef WR_FRAGMENT_SHADER
-void main(void) {
-    vec2 uv = clamp(vUv.xy, vStRect.xy, vStRect.zw);
-    float a = texture(sColor0, vec3(uv, vUv.z)).a;
-    oFragColor = vColor * a;
-}
-#endif
--- a/gfx/webrender/src/batch.rs
+++ b/gfx/webrender/src/batch.rs
@@ -1,27 +1,27 @@
 /* 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, DeviceIntRect, DeviceIntSize, LayerToWorldScale};
 use api::{DeviceUintRect, DeviceUintPoint, DeviceUintSize, ExternalImageType, FilterOp, ImageRendering, LayerRect};
-use api::{DeviceIntPoint, LayerPoint, SubpixelDirection, YuvColorSpace, YuvFormat};
+use api::{DeviceIntPoint, SubpixelDirection, YuvColorSpace, YuvFormat};
 use api::{LayerToWorldTransform, WorldPixel};
 use border::{BorderCornerInstance, BorderCornerSide, BorderEdgeKind};
 use clip::{ClipSource, ClipStore, ClipWorkItem};
 use clip_scroll_tree::{CoordinateSystemId};
 use euclid::{TypedTransform3D, vec3};
 use glyph_rasterizer::GlyphFormat;
 use gpu_cache::{GpuCache, GpuCacheAddress};
 use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex};
 use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, RasterizationSpace};
 use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance};
 use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
-use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive};
+use picture::{PictureCompositeMode, PictureKind, PicturePrimitive};
 use plane_split::{BspSplitter, Polygon, Splitter};
 use prim_store::{CachedGradient, ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore};
 use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PictureIndex, PrimitiveRun};
 use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree};
 use renderer::{BlendMode, ImageBufferKind};
 use renderer::BLOCKS_PER_UV_RECT;
 use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache};
 use std::{usize, f32, i32};
@@ -351,40 +351,31 @@ impl PrimitiveBatch {
             instances: Vec::new(),
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct AlphaBatchContainer {
-    pub text_run_cache_prims: FastHashMap<SourceTexture, Vec<PrimitiveInstance>>,
     pub opaque_batches: Vec<PrimitiveBatch>,
     pub alpha_batches: Vec<PrimitiveBatch>,
     pub target_rect: Option<DeviceIntRect>,
 }
 
 impl AlphaBatchContainer {
     pub fn new(target_rect: Option<DeviceIntRect>) -> AlphaBatchContainer {
         AlphaBatchContainer {
-            text_run_cache_prims: FastHashMap::default(),
             opaque_batches: Vec::new(),
             alpha_batches: Vec::new(),
             target_rect,
         }
     }
 
     fn merge(&mut self, builder: AlphaBatchBuilder) {
-        for (key, value) in builder.text_run_cache_prims {
-            self.text_run_cache_prims
-                .entry(key)
-                .or_insert(vec![])
-                .extend(value);
-        }
-
         for other_batch in builder.batch_list.opaque_batch_list.batches {
             let batch_index = self.opaque_batches.iter().position(|batch| {
                 batch.key.is_compatible_with(&other_batch.key)
             });
 
             match batch_index {
                 Some(batch_index) => {
                     self.opaque_batches[batch_index].instances.extend(other_batch.instances);
@@ -415,30 +406,28 @@ impl AlphaBatchContainer {
             }
         }
     }
 }
 
 /// Encapsulates the logic of building batches for items that are blended.
 pub struct AlphaBatchBuilder {
     pub batch_list: BatchList,
-    pub text_run_cache_prims: FastHashMap<SourceTexture, Vec<PrimitiveInstance>>,
     glyph_fetch_buffer: Vec<GlyphFetchResult>,
     target_rect: DeviceIntRect,
 }
 
 impl AlphaBatchBuilder {
     pub fn new(
         screen_size: DeviceIntSize,
         target_rect: DeviceIntRect,
     ) -> Self {
         AlphaBatchBuilder {
             batch_list: BatchList::new(screen_size),
             glyph_fetch_buffer: Vec::new(),
-            text_run_cache_prims: FastHashMap::default(),
             target_rect,
         }
     }
 
     pub fn build(mut self, merged_batches: &mut AlphaBatchContainer) -> Option<AlphaBatchContainer> {
         self.batch_list.finalize();
 
         let task_relative_target_rect = DeviceIntRect::new(
@@ -451,17 +440,16 @@ impl AlphaBatchBuilder {
         if can_merge {
             merged_batches.merge(self);
             None
         } else {
             Some(AlphaBatchContainer {
                 alpha_batches: self.batch_list.alpha_batch_list.batches,
                 opaque_batches: self.batch_list.opaque_batch_list.batches,
                 target_rect: Some(self.target_rect),
-                text_run_cache_prims: self.text_run_cache_prims,
             })
         }
     }
 
     pub fn add_pic_to_batch(
         &mut self,
         pic: &PicturePrimitive,
         task_id: RenderTaskId,
@@ -495,17 +483,16 @@ impl AlphaBatchBuilder {
                 scroll_id,
                 ctx,
                 gpu_cache,
                 render_tasks,
                 task_id,
                 task_address,
                 deferred_resolves,
                 &mut splitter,
-                pic,
                 content_origin,
             );
         }
 
         // Flush the accumulated plane splits onto the task tree.
         // Z axis is directed at the screen, `sort` is ascending, and we need back-to-front order.
         for poly in splitter.sort(vec3(0.0, 0.0, 1.0)) {
             let prim_index = PrimitiveIndex(poly.anchor);
@@ -555,49 +542,35 @@ impl AlphaBatchBuilder {
         scroll_id: ClipScrollNodeIndex,
         ctx: &RenderTargetContext,
         gpu_cache: &mut GpuCache,
         render_tasks: &RenderTaskTree,
         task_id: RenderTaskId,
         task_address: RenderTaskAddress,
         deferred_resolves: &mut Vec<DeferredResolve>,
         splitter: &mut BspSplitter<f64, WorldPixel>,
-        pic: &PicturePrimitive,
-        content_origin: ContentOrigin,
+        content_origin: DeviceIntPoint,
     ) {
         for i in 0 .. run.count {
             let prim_index = PrimitiveIndex(run.base_prim_index.0 + i);
-
             let metadata = &ctx.prim_store.cpu_metadata[prim_index.0];
 
-            // Now that we walk the primitive runs in order to add
-            // items to batches, we need to check if they are
-            // visible here.
-            // We currently only support culling on normal (Image)
-            // picture types.
-            // TODO(gw): Support culling on shadow image types.
-            let is_image = match pic.kind {
-                PictureKind::Image { .. } => true,
-                PictureKind::TextShadow { .. } => false,
-            };
-
-            if !is_image || metadata.screen_rect.is_some() {
+            if metadata.screen_rect.is_some() {
                 self.add_prim_to_batch(
                     metadata.clip_chain_rect_index,
                     scroll_id,
                     prim_index,
                     ctx,
                     gpu_cache,
                     render_tasks,
                     task_id,
                     task_address,
                     deferred_resolves,
                     splitter,
                     content_origin,
-                    pic,
                 );
             }
         }
     }
 
     // Adds a primitive to a batch.
     // It can recursively call itself in some situations, for
     // example if it encounters a picture where the items
@@ -609,51 +582,34 @@ impl AlphaBatchBuilder {
         prim_index: PrimitiveIndex,
         ctx: &RenderTargetContext,
         gpu_cache: &mut GpuCache,
         render_tasks: &RenderTaskTree,
         task_id: RenderTaskId,
         task_address: RenderTaskAddress,
         deferred_resolves: &mut Vec<DeferredResolve>,
         splitter: &mut BspSplitter<f64, WorldPixel>,
-        content_origin: ContentOrigin,
-        pic: &PicturePrimitive,
+        content_origin: DeviceIntPoint,
     ) {
         let z = prim_index.0 as i32;
         let prim_metadata = ctx.prim_store.get_metadata(prim_index);
         let scroll_node = &ctx.node_data[scroll_id.0 as usize];
         // TODO(gw): Calculating this for every primitive is a bit
         //           wasteful. We should probably cache this in
         //           the scroll node...
         let transform_kind = scroll_node.transform.transform_kind();
 
-        let task_relative_bounding_rect = match content_origin {
-            ContentOrigin::Screen(point) => {
-                // translate by content-origin
-                let screen_rect = prim_metadata.screen_rect.expect("bug");
-                DeviceIntRect::new(
-                    DeviceIntPoint::new(
-                        screen_rect.unclipped.origin.x - point.x,
-                        screen_rect.unclipped.origin.y - point.y,
-                    ),
-                    screen_rect.unclipped.size,
-                )
-            }
-            ContentOrigin::Local(point) => {
-                // scale local rect by device pixel ratio
-                let content_rect = LayerRect::new(
-                    LayerPoint::new(
-                        prim_metadata.local_rect.origin.x - point.x,
-                        prim_metadata.local_rect.origin.y - point.y,
-                    ),
-                    prim_metadata.local_rect.size,
-                );
-                (content_rect * LayerToWorldScale::new(1.0) * ctx.device_pixel_scale).round().to_i32()
-            }
-        };
+        let screen_rect = prim_metadata.screen_rect.expect("bug");
+        let task_relative_bounding_rect = DeviceIntRect::new(
+            DeviceIntPoint::new(
+                screen_rect.unclipped.origin.x - content_origin.x,
+                screen_rect.unclipped.origin.y - content_origin.y,
+            ),
+            screen_rect.unclipped.size,
+        );
 
         let prim_cache_address = gpu_cache.get_address(&prim_metadata.gpu_location);
         let no_textures = BatchTextures::no_texture();
         let clip_task_address = prim_metadata
             .clip_task_id
             .map_or(OPAQUE_TASK_ADDRESS, |id| render_tasks.get_task_address(id));
         let base_instance = SimplePrimitiveInstance::new(
             prim_cache_address,
@@ -704,21 +660,21 @@ impl AlphaBatchBuilder {
                                             picture_address: task_address,
                                             prim_address: prim_cache_address,
                                             clip_chain_rect_index,
                                             scroll_id,
                                             clip_task_address,
                                             z,
                                             segment_index: 0,
                                             edge_flags: EdgeAaSegmentMask::empty(),
-                                            brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
+                                            brush_flags: BrushFlags::empty(),
                                             user_data: [
                                                 uv_rect_address,
                                                 BrushImageSourceKind::Color as i32,
-                                                RasterizationSpace::Local as i32,
+                                                RasterizationSpace::Screen as i32,
                                             ],
                                         };
                                         batch.push(PrimitiveInstance::from(instance));
                                     }
                                     PictureKind::Image {
                                         composite_mode,
                                         secondary_render_task_id,
                                         is_in_3d_context,
@@ -1131,37 +1087,24 @@ impl AlphaBatchBuilder {
                     },
                 );
                 let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
                 batch.push(base_instance.build(cache_item.uv_rect_handle.as_int(gpu_cache), 0, 0));
             }
             PrimitiveKind::TextRun => {
                 let text_cpu =
                     &ctx.prim_store.cpu_text_runs[prim_metadata.cpu_prim_index.0];
-                let is_shadow = match pic.kind {
-                    PictureKind::TextShadow { .. } => true,
-                    PictureKind::Image { .. } => false,
-                };
-
-                // TODO(gw): It probably makes sense to base this decision on the content
-                //           origin field in the future (once that's configurable).
-                let font_transform = if is_shadow {
-                    None
-                } else {
-                    Some(scroll_node.transform)
-                };
 
                 let font = text_cpu.get_font(
                     ctx.device_pixel_scale,
-                    font_transform,
+                    Some(scroll_node.transform),
                 );
 
                 let glyph_fetch_buffer = &mut self.glyph_fetch_buffer;
                 let batch_list = &mut self.batch_list;
-                let text_run_cache_prims = &mut self.text_run_cache_prims;
 
                 ctx.resource_cache.fetch_glyphs(
                     font,
                     &text_cpu.glyph_keys,
                     glyph_fetch_buffer,
                     gpu_cache,
                     |texture_id, mut glyph_format, glyphs| {
                         debug_assert_ne!(texture_id, SourceTexture::Invalid);
@@ -1172,54 +1115,48 @@ impl AlphaBatchBuilder {
                         }
 
                         let subpx_dir = match glyph_format {
                             GlyphFormat::Bitmap |
                             GlyphFormat::ColorBitmap => SubpixelDirection::None,
                             _ => text_cpu.font.subpx_dir.limit_by(text_cpu.font.render_mode),
                         };
 
-                        let batch = if is_shadow {
-                            text_run_cache_prims
-                                .entry(texture_id)
-                                .or_insert(Vec::new())
-                        } else {
-                            let textures = BatchTextures {
-                                colors: [
-                                    texture_id,
-                                    SourceTexture::Invalid,
-                                    SourceTexture::Invalid,
-                                ],
-                            };
+                        let textures = BatchTextures {
+                            colors: [
+                                texture_id,
+                                SourceTexture::Invalid,
+                                SourceTexture::Invalid,
+                            ],
+                        };
 
-                            let kind = BatchKind::Transformable(
-                                transform_kind,
-                                TransformBatchKind::TextRun(glyph_format),
-                            );
+                        let kind = BatchKind::Transformable(
+                            transform_kind,
+                            TransformBatchKind::TextRun(glyph_format),
+                        );
 
-                            let blend_mode = match glyph_format {
-                                GlyphFormat::Subpixel |
-                                GlyphFormat::TransformedSubpixel => {
-                                    if text_cpu.font.bg_color.a != 0 {
-                                        BlendMode::SubpixelWithBgColor
-                                    } else if ctx.use_dual_source_blending {
-                                        BlendMode::SubpixelDualSource
-                                    } else {
-                                        BlendMode::SubpixelConstantTextColor(text_cpu.font.color.into())
-                                    }
+                        let blend_mode = match glyph_format {
+                            GlyphFormat::Subpixel |
+                            GlyphFormat::TransformedSubpixel => {
+                                if text_cpu.font.bg_color.a != 0 {
+                                    BlendMode::SubpixelWithBgColor
+                                } else if ctx.use_dual_source_blending {
+                                    BlendMode::SubpixelDualSource
+                                } else {
+                                    BlendMode::SubpixelConstantTextColor(text_cpu.font.color.into())
                                 }
-                                GlyphFormat::Alpha |
-                                GlyphFormat::TransformedAlpha |
-                                GlyphFormat::Bitmap |
-                                GlyphFormat::ColorBitmap => BlendMode::PremultipliedAlpha,
-                            };
+                            }
+                            GlyphFormat::Alpha |
+                            GlyphFormat::TransformedAlpha |
+                            GlyphFormat::Bitmap |
+                            GlyphFormat::ColorBitmap => BlendMode::PremultipliedAlpha,
+                        };
 
-                            let key = BatchKey::new(kind, blend_mode, textures);
-                            batch_list.get_suitable_batch(key, &task_relative_bounding_rect)
-                        };
+                        let key = BatchKey::new(kind, blend_mode, textures);
+                        let batch = batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
 
                         for glyph in glyphs {
                             batch.push(base_instance.build(
                                 glyph.index_in_text_run,
                                 glyph.uv_rect_address.as_int(),
                                 subpx_dir as u32 as i32,
                             ));
                         }
--- a/gfx/webrender/src/display_list_flattener.rs
+++ b/gfx/webrender/src/display_list_flattener.rs
@@ -10,29 +10,30 @@ use api::{FilterOp, FontInstanceKey, Fon
 use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayerPoint, LayerPrimitiveInfo};
 use api::{LayerRect, LayerSize, LayerVector2D, LayoutRect, LayoutSize, LayoutTransform};
 use api::{LayoutVector2D, LineOrientation, LineStyle, LocalClip, PipelineId, PropertyBinding};
 use api::{RepeatMode, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity, Shadow};
 use api::{SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect, TileOffset};
 use api::{TransformStyle, YuvColorSpace, YuvData};
 use app_units::Au;
 use border::ImageBorderSegment;
+use box_shadow::{BLUR_SAMPLE_SCALE};
 use clip::{ClipRegion, ClipSource, ClipSources, ClipStore};
 use clip_scroll_node::{ClipScrollNode, NodeType, StickyFrameInfo};
 use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, ClipScrollTree};
 use euclid::{SideOffsets2D, vec2};
 use frame_builder::{FrameBuilder, FrameBuilderConfig};
 use glyph_rasterizer::FontInstance;
 use hit_test::{HitTestingItem, HitTestingRun};
 use image::{decompose_image, TiledImageInfo};
 use internal_types::{FastHashMap, FastHashSet};
 use picture::{PictureCompositeMode, PictureKind};
 use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, CachedGradient};
 use prim_store::{CachedGradientIndex, ImageCacheKey, ImagePrimitiveCpu, ImageSource};
-use prim_store::{PictureIndex, PrimitiveContainer, PrimitiveIndex, PrimitiveKind, PrimitiveStore};
+use prim_store::{PictureIndex, PrimitiveContainer, PrimitiveIndex, PrimitiveStore};
 use prim_store::{ScrollNodeAndClipChain, TextRunPrimitiveCpu};
 use render_backend::{DocumentView};
 use resource_cache::{FontInstanceMap, ImageRequest, TiledImageMap};
 use scene::{Scene, ScenePipeline, StackingContextHelpers};
 use scene_builder::{BuiltScene, SceneRequest};
 use std::{f32, mem, usize};
 use tiling::{CompositeOps, ScrollbarPrimitive};
 use util::{MaxRect, RectHelpers, recycle_vec};
@@ -734,18 +735,18 @@ impl<'a> DisplayListFlattener<'a> {
                     info.tile_spacing,
                 );
             }
             SpecificDisplayItem::RadialGradient(ref info) => {
                 self.add_radial_gradient(
                     clip_and_scroll,
                     &prim_info,
                     info.gradient.center,
-                    info.gradient.start_radius,
-                    info.gradient.end_radius,
+                    info.gradient.start_offset * info.gradient.radius.width,
+                    info.gradient.end_offset * info.gradient.radius.width,
                     info.gradient.radius.width / info.gradient.radius.height,
                     item.gradient_stops(),
                     info.gradient.extend_mode,
                     info.tile_size,
                     info.tile_spacing,
                 );
             }
             SpecificDisplayItem::BoxShadow(ref box_shadow_info) => {
@@ -1514,23 +1515,29 @@ impl<'a> DisplayListFlattener<'a> {
                 color: line_color.premultiplied(),
                 style,
                 orientation,
             },
             None,
         );
 
         let mut fast_shadow_prims = Vec::new();
+        let mut slow_shadow_prims = Vec::new();
         for (idx, &(shadow_prim_index, _)) in self.shadow_prim_stack.iter().enumerate() {
             let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0];
             let brush = &self.prim_store.cpu_brushes[shadow_metadata.cpu_prim_index.0];
-            let picture = &self.prim_store.pictures[brush.get_picture_index().0];
+            let pic_index = brush.get_picture_index();
+            let picture = &self.prim_store.pictures[pic_index.0];
             match picture.kind {
-                PictureKind::TextShadow { offset, color, blur_radius, .. } if blur_radius == 0.0 => {
-                    fast_shadow_prims.push((idx, offset, color));
+                PictureKind::TextShadow { offset, color, blur_radius, .. } => {
+                    if blur_radius == 0.0 {
+                        fast_shadow_prims.push((idx, offset, color));
+                    } else {
+                        slow_shadow_prims.push((pic_index, offset, color));
+                    }
                 }
                 _ => {}
             }
         }
 
         for (idx, shadow_offset, shadow_color) in fast_shadow_prims {
             let line = BrushPrimitive::new(
                 BrushKind::Line {
@@ -1547,47 +1554,56 @@ impl<'a> DisplayListFlattener<'a> {
             let prim_index = self.create_primitive(
                 &info,
                 Vec::new(),
                 PrimitiveContainer::Brush(line),
             );
             self.shadow_prim_stack[idx].1.push((prim_index, clip_and_scroll));
         }
 
-        let prim_index = self.create_primitive(
-            &info,
-            Vec::new(),
-            PrimitiveContainer::Brush(line),
-        );
+        if line_color.a > 0.0 {
+            let prim_index = self.create_primitive(
+                &info,
+                Vec::new(),
+                PrimitiveContainer::Brush(line),
+            );
 
-        if line_color.a > 0.0 {
             if self.shadow_prim_stack.is_empty() {
                 self.add_primitive_to_hit_testing_list(&info, clip_and_scroll);
                 self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
             } else {
                 self.pending_shadow_contents.push((prim_index, clip_and_scroll, *info));
             }
         }
 
-        for &(shadow_prim_index, _) in &self.shadow_prim_stack {
-            let shadow_metadata = &mut self.prim_store.cpu_metadata[shadow_prim_index.0];
-            debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::Brush);
-            let brush = &self.prim_store.cpu_brushes[shadow_metadata.cpu_prim_index.0];
-            let picture = &mut self.prim_store.pictures[brush.get_picture_index().0];
+        for (pic_index, shadow_offset, shadow_color) in slow_shadow_prims {
+            let line = BrushPrimitive::new(
+                BrushKind::Line {
+                    wavy_line_thickness,
+                    color: shadow_color.premultiplied(),
+                    style,
+                    orientation,
+                },
+                None,
+            );
+            let mut info = info.clone();
+            info.rect = info.rect.translate(&shadow_offset);
+            info.clip_rect = info.clip_rect.translate(&shadow_offset);
+            let prim_index = self.create_primitive(
+                &info,
+                Vec::new(),
+                PrimitiveContainer::Brush(line),
+            );
 
-            match picture.kind {
-                // Only run real blurs here (fast path zero blurs are handled above).
-                PictureKind::TextShadow { blur_radius, .. } if blur_radius > 0.0 => {
-                    picture.add_primitive(
-                        prim_index,
-                        clip_and_scroll,
-                    );
-                }
-                _ => {}
-            }
+            let picture = &mut self.prim_store.pictures[pic_index.0];
+
+            picture.add_primitive(
+                prim_index,
+                clip_and_scroll,
+            );
         }
     }
 
     pub fn add_border(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayerPrimitiveInfo,
         border_item: &BorderDisplayItem,
@@ -1819,18 +1835,18 @@ impl<'a> DisplayListFlattener<'a> {
                     let segment_rel = segment.origin - rect.origin;
                     let mut info = info.clone();
                     info.rect = segment;
 
                     self.add_radial_gradient(
                         clip_and_scroll,
                         &info,
                         border.gradient.center - segment_rel,
-                        border.gradient.start_radius,
-                        border.gradient.end_radius,
+                        border.gradient.start_offset * border.gradient.radius.width,
+                        border.gradient.end_offset * border.gradient.radius.width,
                         border.gradient.radius.width / border.gradient.radius.height,
                         gradient_stops,
                         border.gradient.extend_mode,
                         segment.size,
                         LayerSize::zero(),
                     );
                 }
             }
@@ -2015,17 +2031,17 @@ impl<'a> DisplayListFlattener<'a> {
             }
         }
     }
 
     pub fn add_text(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         run_offset: LayoutVector2D,
-        info: &LayerPrimitiveInfo,
+        prim_info: &LayerPrimitiveInfo,
         font_instance_key: &FontInstanceKey,
         text_color: &ColorF,
         glyph_range: ItemRange<GlyphInstance>,
         glyph_count: usize,
         glyph_options: Option<GlyphOptions>,
     ) {
         let prim = {
             let instance_map = self.font_instances.read().unwrap();
@@ -2106,86 +2122,102 @@ impl<'a> DisplayListFlattener<'a> {
         // text elements to get pixel perfect results for reftests. It's also a big
         // performance win to avoid blurs and render target allocations where
         // possible. For any text shadows that have zero blur, create a normal text
         // primitive with the shadow's color and offset. These need to be added
         // *before* the visual text primitive in order to get the correct paint
         // order. Store them in a Vec first to work around borrowck issues.
         // TODO(gw): Refactor to avoid having to store them in a Vec first.
         let mut fast_shadow_prims = Vec::new();
+        let mut slow_shadow_prims = Vec::new();
         for (idx, &(shadow_prim_index, _)) in self.shadow_prim_stack.iter().enumerate() {
             let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0];
             let brush = &self.prim_store.cpu_brushes[shadow_metadata.cpu_prim_index.0];
-            let picture_prim = &self.prim_store.pictures[brush.get_picture_index().0];
+            let pic_index = brush.get_picture_index();
+            let picture_prim = &self.prim_store.pictures[pic_index.0];
             match picture_prim.kind {
-                PictureKind::TextShadow { offset, color, blur_radius, .. } if blur_radius == 0.0 => {
+                PictureKind::TextShadow { offset, color, blur_radius, .. } => {
                     let mut text_prim = prim.clone();
                     text_prim.font.color = color.into();
                     text_prim.shadow = true;
                     text_prim.offset += offset;
-                    fast_shadow_prims.push((idx, text_prim));
+
+                    if blur_radius == 0.0 {
+                        fast_shadow_prims.push((idx, text_prim, offset));
+                    } else {
+                        text_prim.font.render_mode = text_prim
+                            .font
+                            .render_mode
+                            .limit_by(FontRenderMode::Alpha);
+
+                        slow_shadow_prims.push((pic_index, text_prim, offset, blur_radius));
+                    }
                 }
                 _ => {}
             }
         }
 
-        for (idx, text_prim) in fast_shadow_prims {
-            let rect = info.rect;
-            let mut info = info.clone();
-            info.rect = rect.translate(&text_prim.offset);
-            info.clip_rect = info.clip_rect.translate(&text_prim.offset);
+        for (idx, text_prim, offset) in fast_shadow_prims {
+            let rect = prim_info.rect;
+            let mut info = prim_info.clone();
+            info.rect = rect.translate(&offset);
+            info.clip_rect = info.clip_rect.translate(&offset);
             let prim_index = self.create_primitive(
                 &info,
                 Vec::new(),
                 PrimitiveContainer::TextRun(text_prim),
             );
             self.shadow_prim_stack[idx].1.push((prim_index, clip_and_scroll));
         }
 
-        // Create (and add to primitive store) the primitive that will be
-        // used for both the visual element and also the shadow(s).
-        let prim_index = self.create_primitive(
-            info,
-            Vec::new(),
-            PrimitiveContainer::TextRun(prim),
-        );
-
         // Only add a visual element if it can contribute to the scene.
         if text_color.a > 0.0 {
+            // Create (and add to primitive store) the primitive that will be
+            // used for both the visual element and also the shadow(s).
+            let prim_index = self.create_primitive(
+                prim_info,
+                Vec::new(),
+                PrimitiveContainer::TextRun(prim),
+            );
+
             if self.shadow_prim_stack.is_empty() {
-                self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
+                self.add_primitive_to_hit_testing_list(prim_info, clip_and_scroll);
                 self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
             } else {
-                self.pending_shadow_contents.push((prim_index, clip_and_scroll, *info));
+                self.pending_shadow_contents.push((prim_index, clip_and_scroll, *prim_info));
             }
         }
 
         // Now add this primitive index to all the currently active text shadow
         // primitives. Although we're adding the indices *after* the visual
         // primitive here, they will still draw before the visual text, since
         // the shadow primitive itself has been added to the draw cmd
         // list *before* the visual element, during push_shadow. We need
         // the primitive index of the visual element here before we can add
         // the indices as sub-primitives to the shadow primitives.
-        for &(shadow_prim_index, _) in &self.shadow_prim_stack {
-            let shadow_metadata = &mut self.prim_store.cpu_metadata[shadow_prim_index.0];
-            debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::Brush);
-            let brush = &self.prim_store.cpu_brushes[shadow_metadata.cpu_prim_index.0];
-            let picture = &mut self.prim_store.pictures[brush.get_picture_index().0];
+        for (pic_index, shadow_prim, offset, blur_radius) in slow_shadow_prims {
+            let blur_region = blur_radius * BLUR_SAMPLE_SCALE;
+
+            let rect = prim_info.rect;
+            let mut info = prim_info.clone();
+            info.rect = rect.translate(&offset).inflate(blur_region, blur_region);
+            info.clip_rect = info.clip_rect.translate(&offset);
 
-            match picture.kind {
-                // Only run real blurs here (fast path zero blurs are handled above).
-                PictureKind::TextShadow { blur_radius, .. } if blur_radius > 0.0 => {
-                    picture.add_primitive(
-                        prim_index,
-                        clip_and_scroll,
-                    );
-                }
-                _ => {}
-            }
+            let prim_index = self.create_primitive(
+                &info,
+                Vec::new(),
+                PrimitiveContainer::TextRun(shadow_prim),
+            );
+
+            let picture = &mut self.prim_store.pictures[pic_index.0];
+
+            picture.add_primitive(
+                prim_index,
+                clip_and_scroll,
+            );
         }
     }
 
     pub fn add_image(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayerPrimitiveInfo,
         stretch_size: LayerSize,
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -8,17 +8,16 @@ use api::{LayerRect, LayerSize, Pipeline
 use clip::{ClipChain, ClipStore};
 use clip_scroll_node::{ClipScrollNode};
 use clip_scroll_tree::{ClipScrollNodeIndex, ClipScrollTree};
 use display_list_flattener::{DisplayListFlattener};
 use gpu_cache::GpuCache;
 use gpu_types::{ClipChainRectIndex, ClipScrollNodeData, PictureType};
 use hit_test::{HitTester, HitTestingRun};
 use internal_types::{FastHashMap};
-use picture::{ContentOrigin};
 use prim_store::{CachedGradient, PrimitiveIndex, PrimitiveRun, PrimitiveStore};
 use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
 use render_backend::FrameId;
 use render_task::{ClearMode, RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree};
 use resource_cache::{ResourceCache};
 use scene::{ScenePipeline, SceneProperties};
 use std::{mem, f32};
 use std::sync::Arc;
@@ -27,17 +26,16 @@ use tiling::ScrollbarPrimitive;
 use util::{self, MaxRect, WorldToLayerFastTransform};
 
 #[derive(Clone, Copy)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct FrameBuilderConfig {
     pub enable_scrollbars: bool,
     pub default_font_render_mode: FontRenderMode,
-    pub debug: bool,
     pub dual_source_blending_is_supported: bool,
     pub dual_source_blending_is_enabled: bool,
 }
 
 /// A builder structure for `tiling::Frame`
 pub struct FrameBuilder {
     screen_rect: DeviceUintRect,
     background_color: Option<ColorF>,
@@ -66,22 +64,21 @@ pub struct FrameBuildingState<'a> {
     pub local_clip_rects: &'a mut Vec<LayerRect>,
     pub resource_cache: &'a mut ResourceCache,
     pub gpu_cache: &'a mut GpuCache,
     pub cached_gradients: &'a mut [CachedGradient],
 }
 
 pub struct PictureContext<'a> {
     pub pipeline_id: PipelineId,
-    pub perform_culling: bool,
     pub prim_runs: Vec<PrimitiveRun>,
     pub original_reference_frame_index: Option<ClipScrollNodeIndex>,
     pub display_list: &'a BuiltDisplayList,
-    pub draw_text_transformed: bool,
     pub inv_world_transform: Option<WorldToLayerFastTransform>,
+    pub apply_local_clip_rect: bool,
 }
 
 pub struct PictureState {
     pub tasks: Vec<RenderTaskId>,
 }
 
 impl PictureState {
     pub fn new() -> PictureState {
@@ -120,17 +117,16 @@ impl FrameBuilder {
             prim_store: PrimitiveStore::new(),
             clip_store: ClipStore::new(),
             screen_rect: DeviceUintRect::zero(),
             window_size: DeviceUintSize::zero(),
             background_color: None,
             config: FrameBuilderConfig {
                 enable_scrollbars: false,
                 default_font_render_mode: FontRenderMode::Mono,
-                debug: false,
                 dual_source_blending_is_enabled: true,
                 dual_source_blending_is_supported: false,
             },
         }
     }
 
     pub fn with_display_list_flattener(
         screen_rect: DeviceUintRect,
@@ -197,22 +193,21 @@ impl FrameBuilder {
             local_clip_rects,
             resource_cache,
             gpu_cache,
             cached_gradients: &mut self.cached_gradients,
         };
 
         let pic_context = PictureContext {
             pipeline_id: root_clip_scroll_node.pipeline_id,
-            perform_culling: true,
             prim_runs: mem::replace(&mut self.prim_store.pictures[0].runs, Vec::new()),
             original_reference_frame_index: None,
             display_list,
-            draw_text_transformed: true,
             inv_world_transform: None,
+            apply_local_clip_rect: true,
         };
 
         let mut pic_state = PictureState::new();
 
         self.prim_store.reset_prim_visibility();
         self.prim_store.prepare_prim_runs(
             &pic_context,
             &mut pic_state,
@@ -222,17 +217,17 @@ impl FrameBuilder {
 
         let pic = &mut self.prim_store.pictures[0];
         pic.runs = pic_context.prim_runs;
 
         let root_render_task = RenderTask::new_picture(
             RenderTaskLocation::Fixed(frame_context.screen_rect),
             PrimitiveIndex(0),
             RenderTargetKind::Color,
-            ContentOrigin::Screen(DeviceIntPoint::zero()),
+            DeviceIntPoint::zero(),
             PremultipliedColorF::TRANSPARENT,
             ClearMode::Transparent,
             pic_state.tasks,
             PictureType::Image,
         );
 
         let render_task_id = frame_state.render_tasks.add(root_render_task);
         pic.surface = Some(render_task_id);
--- a/gfx/webrender/src/freelist.rs
+++ b/gfx/webrender/src/freelist.rs
@@ -60,35 +60,38 @@ struct Slot<T> {
     value: Option<T>,
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct FreeList<T> {
     slots: Vec<Slot<T>>,
     free_list_head: Option<u32>,
+    active_count: usize,
 }
 
 pub enum UpsertResult<T> {
     Updated(T),
     Inserted(FreeListHandle<T>),
 }
 
 impl<T> FreeList<T> {
     pub fn new() -> Self {
         FreeList {
             slots: Vec::new(),
             free_list_head: None,
+            active_count: 0,
         }
     }
 
     pub fn recycle(self) -> FreeList<T> {
         FreeList {
             slots: recycle_vec(self.slots),
             free_list_head: None,
+            active_count: 0,
         }
     }
 
     #[allow(dead_code)]
     pub fn get(&self, id: &FreeListHandle<T>) -> &T {
         self.slots[id.index as usize].value.as_ref().unwrap()
     }
 
@@ -126,16 +129,18 @@ impl<T> FreeList<T> {
             slot.value = Some(data);
             result
         } else {
             UpsertResult::Inserted(self.insert(data))
         }
     }
 
     pub fn insert(&mut self, item: T) -> FreeListHandle<T> {
+        self.active_count += 1;
+
         match self.free_list_head {
             Some(free_index) => {
                 let slot = &mut self.slots[free_index as usize];
 
                 // Remove from free list.
                 self.free_list_head = slot.next;
                 slot.next = None;
                 slot.value = Some(item);
@@ -161,15 +166,20 @@ impl<T> FreeList<T> {
                     epoch,
                     _marker: PhantomData,
                 }
             }
         }
     }
 
     pub fn free(&mut self, id: FreeListHandle<T>) -> T {
+        self.active_count -= 1;
         let slot = &mut self.slots[id.index as usize];
         slot.next = self.free_list_head;
         slot.epoch = Epoch(slot.epoch.0 + 1);
         self.free_list_head = Some(id.index);
         slot.value.take().unwrap()
     }
+
+    pub fn len(&self) -> usize {
+        self.active_count
+    }
 }
--- a/gfx/webrender/src/glyph_rasterizer.rs
+++ b/gfx/webrender/src/glyph_rasterizer.rs
@@ -516,16 +516,17 @@ impl GlyphRasterizer {
                         texture_cache.update(
                             &mut texture_cache_handle,
                             ImageDescriptor {
                                 width: glyph.width,
                                 height: glyph.height,
                                 stride: None,
                                 format: ImageFormat::BGRA8,
                                 is_opaque: false,
+                                allow_mipmaps: false,
                                 offset: 0,
                             },
                             TextureFilter::Linear,
                             Some(ImageData::Raw(Arc::new(glyph.bytes))),
                             [glyph.left, -glyph.top, glyph.scale],
                             None,
                             gpu_cache,
                             Some(glyph_key_cache.eviction_notice()),
--- a/gfx/webrender/src/picture.rs
+++ b/gfx/webrender/src/picture.rs
@@ -1,25 +1,24 @@
 /* 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::{DeviceIntPoint, DeviceIntRect};
-use api::{LayerPoint, LayerRect, LayerToWorldScale, LayerVector2D};
 use api::{ColorF, FilterOp, MixBlendMode, PipelineId};
+use api::{DeviceIntRect, LayerRect, LayerToWorldScale, LayerVector2D};
 use api::{PremultipliedColorF, Shadow};
 use box_shadow::{BLUR_SAMPLE_SCALE};
 use clip_scroll_tree::ClipScrollNodeIndex;
 use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState};
 use gpu_cache::{GpuCacheHandle, GpuDataRequest};
 use gpu_types::{PictureType};
 use prim_store::{PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect};
 use prim_store::{PrimitiveMetadata, ScrollNodeAndClipChain};
 use render_task::{ClearMode, RenderTask};
-use render_task::{RenderTaskId, RenderTaskLocation, to_cache_size};
+use render_task::{RenderTaskId, RenderTaskLocation};
 use scene::{FilterOpHelpers, SceneProperties};
 use tiling::RenderTargetKind;
 
 /*
  A picture represents a dynamically rendered image. It consists of:
 
  * A number of primitives that are drawn onto the picture.
  * A composite operation describing how to composite this
@@ -36,33 +35,22 @@ pub enum PictureCompositeMode {
     MixBlend(MixBlendMode),
     /// Apply a CSS filter.
     Filter(FilterOp),
     /// Draw to intermediate surface, copy straight across. This
     /// is used for CSS isolation, and plane splitting.
     Blit,
 }
 
-/// Configure whether the content to be drawn by a picture
-/// in local space rasterization or the screen space.
-#[derive(Debug, Copy, Clone, PartialEq)]
-#[cfg_attr(feature = "capture", derive(Serialize))]
-#[cfg_attr(feature = "replay", derive(Deserialize))]
-pub enum ContentOrigin {
-    Local(LayerPoint),
-    Screen(DeviceIntPoint),
-}
-
 #[derive(Debug)]
 pub enum PictureKind {
     TextShadow {
         offset: LayerVector2D,
         color: ColorF,
         blur_radius: f32,
-        content_rect: LayerRect,
     },
     Image {
         // If a mix-blend-mode, contains the render task for
         // the readback of the framebuffer that we use to sample
         // from in the mix-blend-mode shader.
         // For drop-shadow filter, this will store the original
         // picture task which would be rendered on screen after
         // blur pass.
@@ -80,19 +68,16 @@ pub enum PictureKind {
         // It is only different if this is part of a 3D
         // rendering context.
         reference_frame_index: ClipScrollNodeIndex,
         real_local_rect: LayerRect,
         // An optional cache handle for storing extra data
         // in the GPU cache, depending on the type of
         // picture.
         extra_gpu_data_handle: GpuCacheHandle,
-        // The current screen-space rect of the rendered
-        // portion of this picture.
-        task_rect: DeviceIntRect,
     },
 }
 
 #[derive(Debug)]
 pub struct PicturePrimitive {
     // If this picture is drawn to an intermediate surface,
     // the associated target information.
     pub surface: Option<RenderTaskId>,
@@ -101,35 +86,33 @@ pub struct PicturePrimitive {
     pub kind: PictureKind,
 
     // List of primitive runs that make up this picture.
     pub runs: Vec<PrimitiveRun>,
 
     // The pipeline that the primitives on this picture belong to.
     pub pipeline_id: PipelineId,
 
-    // If true, apply visibility culling to primitives on this
-    // picture. For text shadows and box shadows, we want to
-    // unconditionally draw them.
-    pub cull_children: bool,
+    // The current screen-space rect of the rendered
+    // portion of this picture.
+    task_rect: DeviceIntRect,
 }
 
 impl PicturePrimitive {
     pub fn new_text_shadow(shadow: Shadow, pipeline_id: PipelineId) -> Self {
         PicturePrimitive {
             runs: Vec::new(),
             surface: None,
             kind: PictureKind::TextShadow {
                 offset: shadow.offset,
                 color: shadow.color,
                 blur_radius: shadow.blur_radius,
-                content_rect: LayerRect::zero(),
             },
             pipeline_id,
-            cull_children: false,
+            task_rect: DeviceIntRect::zero(),
         }
     }
 
     pub fn resolve_scene_properties(&mut self, properties: &SceneProperties) -> bool {
         match self.kind {
             PictureKind::Image { ref mut composite_mode, .. } => {
                 match composite_mode {
                     &mut Some(PictureCompositeMode::Filter(ref mut filter)) => {
@@ -162,20 +145,19 @@ impl PicturePrimitive {
             kind: PictureKind::Image {
                 secondary_render_task_id: None,
                 composite_mode,
                 is_in_3d_context,
                 frame_output_pipeline_id,
                 reference_frame_index,
                 real_local_rect: LayerRect::zero(),
                 extra_gpu_data_handle: GpuCacheHandle::new(),
-                task_rect: DeviceIntRect::zero(),
             },
             pipeline_id,
-            cull_children: true,
+            task_rect: DeviceIntRect::zero(),
         }
     }
 
     pub fn add_primitive(
         &mut self,
         prim_index: PrimitiveIndex,
         clip_and_scroll: ScrollNodeAndClipChain
     ) {
@@ -214,25 +196,23 @@ impl PicturePrimitive {
                         local_content_rect.inflate(inflate_size, inflate_size)
                                           .translate(&offset)
                     }
                     _ => {
                         local_content_rect
                     }
                 }
             }
-            PictureKind::TextShadow { offset, blur_radius, ref mut content_rect, .. } => {
+            PictureKind::TextShadow { blur_radius, .. } => {
                 let blur_offset = blur_radius * BLUR_SAMPLE_SCALE;
 
-                *content_rect = local_content_rect.inflate(
+                local_content_rect.inflate(
                     blur_offset,
                     blur_offset,
-                );
-
-                content_rect.translate(&offset)
+                )
             }
         }
     }
 
     pub fn prepare_for_render(
         &mut self,
         prim_index: PrimitiveIndex,
         prim_metadata: &mut PrimitiveMetadata,
@@ -241,26 +221,26 @@ impl PicturePrimitive {
         frame_context: &FrameBuildingContext,
         frame_state: &mut FrameBuildingState,
     ) {
         let content_scale = LayerToWorldScale::new(1.0) * frame_context.device_pixel_scale;
         let prim_screen_rect = prim_metadata
                                 .screen_rect
                                 .as_ref()
                                 .expect("bug: trying to draw an off-screen picture!?");
+        let device_rect;
 
         match self.kind {
             PictureKind::Image {
                 ref mut secondary_render_task_id,
                 ref mut extra_gpu_data_handle,
-                ref mut task_rect,
                 composite_mode,
                 ..
             } => {
-                let device_rect = match composite_mode {
+                device_rect = match composite_mode {
                     Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => {
                         // If blur radius is 0, we can skip drawing this an an
                         // intermediate surface.
                         if blur_radius == 0.0 {
                             pic_state.tasks.extend(pic_state_for_children.tasks);
                             self.surface = None;
 
                             DeviceIntRect::zero()
@@ -277,23 +257,21 @@ impl PicturePrimitive {
                             // then intersect with the total screen rect, to minimize the
                             // allocation size.
                             let device_rect = prim_screen_rect
                                 .clipped
                                 .inflate(blur_range, blur_range)
                                 .intersection(&prim_screen_rect.unclipped)
                                 .unwrap();
 
-                            let content_origin = ContentOrigin::Screen(device_rect.origin);
-
                             let picture_task = RenderTask::new_picture(
                                 RenderTaskLocation::Dynamic(None, device_rect.size),
                                 prim_index,
                                 RenderTargetKind::Color,
-                                content_origin,
+                                device_rect.origin,
                                 PremultipliedColorF::TRANSPARENT,
                                 ClearMode::Transparent,
                                 pic_state_for_children.tasks,
                                 PictureType::Image,
                             );
 
                             let picture_task_id = frame_state.render_tasks.add(picture_task);
 
@@ -315,17 +293,17 @@ impl PicturePrimitive {
                     Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, _))) => {
                         // TODO(gw): This is totally wrong and can never work with
                         //           transformed drop-shadow elements. Fix me!
                         let rect = (prim_metadata.local_rect.translate(&-offset) * content_scale).round().to_i32();
                         let mut picture_task = RenderTask::new_picture(
                             RenderTaskLocation::Dynamic(None, rect.size),
                             prim_index,
                             RenderTargetKind::Color,
-                            ContentOrigin::Screen(rect.origin),
+                            rect.origin,
                             PremultipliedColorF::TRANSPARENT,
                             ClearMode::Transparent,
                             pic_state_for_children.tasks,
                             PictureType::Image,
                         );
                         picture_task.mark_for_saving();
 
                         let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
@@ -343,23 +321,21 @@ impl PicturePrimitive {
 
                         let render_task_id = frame_state.render_tasks.add(blur_render_task);
                         pic_state.tasks.push(render_task_id);
                         self.surface = Some(render_task_id);
 
                         rect
                     }
                     Some(PictureCompositeMode::MixBlend(..)) => {
-                        let content_origin = ContentOrigin::Screen(prim_screen_rect.clipped.origin);
-
                         let picture_task = RenderTask::new_picture(
                             RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size),
                             prim_index,
                             RenderTargetKind::Color,
-                            content_origin,
+                            prim_screen_rect.clipped.origin,
                             PremultipliedColorF::TRANSPARENT,
                             ClearMode::Transparent,
                             pic_state_for_children.tasks,
                             PictureType::Image,
                         );
 
                         let readback_task_id = frame_state.render_tasks.add(
                             RenderTask::new_readback(prim_screen_rect.clipped)
@@ -370,18 +346,16 @@ impl PicturePrimitive {
 
                         let render_task_id = frame_state.render_tasks.add(picture_task);
                         pic_state.tasks.push(render_task_id);
                         self.surface = Some(render_task_id);
 
                         prim_screen_rect.clipped
                     }
                     Some(PictureCompositeMode::Filter(filter)) => {
-                        let content_origin = ContentOrigin::Screen(prim_screen_rect.clipped.origin);
-
                         // If this filter is not currently going to affect
                         // the picture, just collapse this picture into the
                         // current render task. This most commonly occurs
                         // when opacity == 1.0, but can also occur on other
                         // filters and be a significant performance win.
                         if filter.is_noop() {
                             pic_state.tasks.extend(pic_state_for_children.tasks);
                             self.surface = None;
@@ -394,38 +368,36 @@ impl PicturePrimitive {
                                     }
                                 }
                             }
 
                             let picture_task = RenderTask::new_picture(
                                 RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size),
                                 prim_index,
                                 RenderTargetKind::Color,
-                                content_origin,
+                                prim_screen_rect.clipped.origin,
                                 PremultipliedColorF::TRANSPARENT,
                                 ClearMode::Transparent,
                                 pic_state_for_children.tasks,
                                 PictureType::Image,
                             );
 
                             let render_task_id = frame_state.render_tasks.add(picture_task);
                             pic_state.tasks.push(render_task_id);
                             self.surface = Some(render_task_id);
                         }
 
                         prim_screen_rect.clipped
                     }
                     Some(PictureCompositeMode::Blit) => {
-                        let content_origin = ContentOrigin::Screen(prim_screen_rect.clipped.origin);
-
                         let picture_task = RenderTask::new_picture(
                             RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size),
                             prim_index,
                             RenderTargetKind::Color,
-                            content_origin,
+                            prim_screen_rect.clipped.origin,
                             PremultipliedColorF::TRANSPARENT,
                             ClearMode::Transparent,
                             pic_state_for_children.tasks,
                             PictureType::Image,
                         );
 
                         let render_task_id = frame_state.render_tasks.add(picture_task);
                         pic_state.tasks.push(render_task_id);
@@ -435,44 +407,42 @@ impl PicturePrimitive {
                     }
                     None => {
                         pic_state.tasks.extend(pic_state_for_children.tasks);
                         self.surface = None;
 
                         DeviceIntRect::zero()
                     }
                 };
-
-                // If scrolling or property animation has resulted in the task
-                // rect being different than last time, invalidate the GPU
-                // cache entry for this picture to ensure that the correct
-                // task rect is provided to the image shader.
-                if *task_rect != device_rect {
-                    frame_state.gpu_cache.invalidate(&prim_metadata.gpu_location);
-                    *task_rect = device_rect;
-                }
             }
-            PictureKind::TextShadow { blur_radius, color, content_rect, .. } => {
+            PictureKind::TextShadow { blur_radius, color, .. } => {
                 // This is a shadow element. Create a render task that will
                 // render the text run to a target, and then apply a gaussian
                 // blur to that text run in order to build the actual primitive
                 // which will be blitted to the framebuffer.
-                let cache_size = to_cache_size(content_rect.size * content_scale);
 
                 // Quote from https://drafts.csswg.org/css-backgrounds-3/#shadow-blur
                 // "the image that would be generated by applying to the shadow a
                 // Gaussian blur with a standard deviation equal to half the blur radius."
                 let device_radius = (blur_radius * frame_context.device_pixel_scale.0).round();
                 let blur_std_deviation = device_radius * 0.5;
 
+                let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
+
+                device_rect = prim_screen_rect
+                    .clipped
+                    .inflate(blur_range, blur_range)
+                    .intersection(&prim_screen_rect.unclipped)
+                    .unwrap();
+
                 let picture_task = RenderTask::new_picture(
-                    RenderTaskLocation::Dynamic(None, cache_size),
+                    RenderTaskLocation::Dynamic(None, device_rect.size),
                     prim_index,
                     RenderTargetKind::Color,
-                    ContentOrigin::Local(content_rect.origin),
+                    device_rect.origin,
                     color.premultiplied(),
                     ClearMode::Transparent,
                     Vec::new(),
                     PictureType::TextShadow,
                 );
 
                 let picture_task_id = frame_state.render_tasks.add(picture_task);
 
@@ -484,32 +454,41 @@ impl PicturePrimitive {
                     ClearMode::Transparent,
                 );
 
                 let render_task_id = frame_state.render_tasks.add(blur_render_task);
                 pic_state.tasks.push(render_task_id);
                 self.surface = Some(render_task_id);
             }
         }
+
+        // If scrolling or property animation has resulted in the task
+        // rect being different than last time, invalidate the GPU
+        // cache entry for this picture to ensure that the correct
+        // task rect is provided to the image shader.
+        if self.task_rect != device_rect {
+            frame_state.gpu_cache.invalidate(&prim_metadata.gpu_location);
+            self.task_rect = device_rect;
+        }
     }
 
     pub fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
+        request.push(self.task_rect.to_f32());
+
         match self.kind {
             PictureKind::TextShadow { .. } => {
-                request.push([0.0; 4]);
                 request.push(PremultipliedColorF::WHITE);
             }
-            PictureKind::Image { task_rect, composite_mode, .. } => {
+            PictureKind::Image { composite_mode, .. } => {
                 let color = match composite_mode {
                     Some(PictureCompositeMode::Filter(FilterOp::DropShadow(_, _, color))) => {
                         color.premultiplied()
                     }
                     _ => {
                         PremultipliedColorF::WHITE
                     }
                 };
 
-                request.push(task_rect.to_f32());
                 request.push(color);
             }
         }
     }
 }
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -1102,21 +1102,17 @@ impl PrimitiveStore {
         frame_state: &mut FrameBuildingState,
     ) {
         let metadata = &mut self.cpu_metadata[prim_index.0];
         match metadata.prim_kind {
             PrimitiveKind::Border => {}
             PrimitiveKind::TextRun => {
                 let text = &mut self.cpu_text_runs[metadata.cpu_prim_index.0];
                 // The transform only makes sense for screen space rasterization
-                let transform = if pic_context.draw_text_transformed {
-                    Some(prim_run_context.scroll_node.world_content_transform.into())
-                } else {
-                    None
-                };
+                let transform = Some(prim_run_context.scroll_node.world_content_transform.into());
                 text.prepare_for_render(
                     frame_state.resource_cache,
                     frame_context.device_pixel_scale,
                     transform,
                     pic_context.display_list,
                     frame_state.gpu_cache,
                 );
             }
@@ -1710,18 +1706,17 @@ impl PrimitiveStore {
         let mut may_need_clip_mask = true;
         let mut pic_state_for_children = PictureState::new();
 
         // Do some basic checks first, that can early out
         // without even knowing the local rect.
         let (prim_kind, cpu_prim_index) = {
             let metadata = &self.cpu_metadata[prim_index.0];
 
-            if pic_context.perform_culling &&
-               !metadata.is_backface_visible &&
+            if !metadata.is_backface_visible &&
                prim_run_context.scroll_node.world_content_transform.is_backface_visible() {
                 return None;
             }
 
             (metadata.prim_kind, metadata.cpu_prim_index)
         };
 
         // If we have dependencies, we need to prepare them first, in order
@@ -1733,17 +1728,17 @@ impl PrimitiveStore {
             if let BrushKind::Picture { pic_index } = self.cpu_brushes[cpu_prim_index.0].kind {
                 let pic_context_for_children = {
                     let pic = &mut self.pictures[pic_index.0];
 
                     if !pic.resolve_scene_properties(frame_context.scene_properties) {
                         return None;
                     }
 
-                    let (draw_text_transformed, original_reference_frame_index) = match pic.kind {
+                    let (apply_local_clip_rect, original_reference_frame_index) = match pic.kind {
                         PictureKind::Image { reference_frame_index, composite_mode, .. } => {
                             may_need_clip_mask = composite_mode.is_some();
                             (true, Some(reference_frame_index))
                         }
                         PictureKind::TextShadow { .. } => {
                             (false, None)
                         }
                     };
@@ -1756,22 +1751,21 @@ impl PrimitiveStore {
 
                     let inv_world_transform = prim_run_context
                         .scroll_node
                         .world_content_transform
                         .inverse();
 
                     PictureContext {
                         pipeline_id: pic.pipeline_id,
-                        perform_culling: pic.cull_children,
                         prim_runs: mem::replace(&mut pic.runs, Vec::new()),
                         original_reference_frame_index,
                         display_list,
-                        draw_text_transformed,
                         inv_world_transform,
+                        apply_local_clip_rect,
                     }
                 };
 
                 let result = self.prepare_prim_runs(
                     &pic_context_for_children,
                     &mut pic_state_for_children,
                     frame_context,
                     frame_state,
@@ -1792,18 +1786,17 @@ impl PrimitiveStore {
                metadata.local_rect.size.height <= 0.0 {
                 //warn!("invalid primitive rect {:?}", metadata.local_rect);
                 return None;
             }
 
             let local_rect = metadata.local_clip_rect.intersection(&metadata.local_rect);
             let local_rect = match local_rect {
                 Some(local_rect) => local_rect,
-                None if pic_context.perform_culling => return None,
-                None => LayerRect::zero(),
+                None => return None,
             };
 
             let screen_bounding_rect = calculate_screen_bounding_rect(
                 &prim_run_context.scroll_node.world_content_transform,
                 &local_rect,
                 frame_context.device_pixel_scale,
             );
 
@@ -1811,26 +1804,26 @@ impl PrimitiveStore {
                 .intersection(&prim_run_context.clip_chain.combined_outer_screen_rect)
                 .map(|clipped| {
                     ScreenRect {
                         clipped,
                         unclipped: screen_bounding_rect,
                     }
                 });
 
-            if metadata.screen_rect.is_none() && pic_context.perform_culling {
+            if metadata.screen_rect.is_none() {
                 return None;
             }
 
             metadata.clip_chain_rect_index = prim_run_context.clip_chain_rect_index;
 
             (local_rect, screen_bounding_rect)
         };
 
-        if pic_context.perform_culling && may_need_clip_mask && !self.update_clip_task(
+        if may_need_clip_mask && !self.update_clip_task(
             prim_index,
             prim_run_context,
             &unclipped_device_rect,
             pic_state,
             frame_context,
             frame_state,
         ) {
             return None;
@@ -1875,26 +1868,24 @@ impl PrimitiveStore {
             //           lookups ever show up in a profile).
             let scroll_node = &frame_context
                 .clip_scroll_tree
                 .nodes[run.clip_and_scroll.scroll_node_id.0];
             let clip_chain = frame_context
                 .clip_scroll_tree
                 .get_clip_chain(run.clip_and_scroll.clip_chain_index);
 
-            if pic_context.perform_culling {
-                if !scroll_node.invertible {
-                    debug!("{:?} {:?}: position not invertible", run.base_prim_index, pic_context.pipeline_id);
-                    continue;
-                }
+            if !scroll_node.invertible {
+                debug!("{:?} {:?}: position not invertible", run.base_prim_index, pic_context.pipeline_id);
+                continue;
+            }
 
-                if clip_chain.combined_outer_screen_rect.is_empty() {
-                    debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id);
-                    continue;
-                }
+            if clip_chain.combined_outer_screen_rect.is_empty() {
+                debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id);
+                continue;
             }
 
             let parent_relative_transform = pic_context
                 .inv_world_transform
                 .map(|inv_parent| {
                     inv_parent.pre_mul(&scroll_node.world_content_transform)
                 });
 
@@ -1905,19 +1896,20 @@ impl PrimitiveStore {
                         .nodes[original_reference_frame_index.0]
                         .world_content_transform;
                     parent.inverse()
                         .map(|inv_parent| {
                             inv_parent.pre_mul(&scroll_node.world_content_transform)
                         })
                 });
 
-            let clip_chain_rect = match pic_context.perform_culling {
-                true => get_local_clip_rect_for_nodes(scroll_node, clip_chain),
-                false => None,
+            let clip_chain_rect = if pic_context.apply_local_clip_rect {
+                get_local_clip_rect_for_nodes(scroll_node, clip_chain)
+            } else {
+                None
             };
 
             let clip_chain_rect_index = match clip_chain_rect {
                 Some(rect) if rect.is_empty() => continue,
                 Some(rect) => {
                     frame_state.local_clip_rects.push(rect);
                     ClipChainRectIndex(frame_state.local_clip_rects.len() - 1)
                 }
--- a/gfx/webrender/src/record.rs
+++ b/gfx/webrender/src/record.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{ApiMsg, FrameMsg, SceneMsg};
-use bincode::{serialize, Infinite};
+use bincode::serialize;
 use byteorder::{LittleEndian, WriteBytesExt};
 use std::any::TypeId;
 use std::fmt::Debug;
 use std::fs::File;
 use std::io::Write;
 use std::mem;
 use std::path::PathBuf;
 
@@ -44,17 +44,17 @@ impl BinaryRecorder {
         self.file.write_u32::<LittleEndian>(data.len() as u32).ok();
         self.file.write(data).ok();
     }
 }
 
 impl ApiRecordingReceiver for BinaryRecorder {
     fn write_msg(&mut self, _: u32, msg: &ApiMsg) {
         if should_record_msg(msg) {
-            let buf = serialize(msg, Infinite).unwrap();
+            let buf = serialize(msg).unwrap();
             self.write_length_and_data(&buf);
         }
     }
 
     fn write_payload(&mut self, _: u32, data: &[u8]) {
         // signal payload with a 0 length
         self.file.write_u32::<LittleEndian>(0).ok();
         self.write_length_and_data(data);
--- a/gfx/webrender/src/render_task.rs
+++ b/gfx/webrender/src/render_task.rs
@@ -6,17 +6,16 @@ use api::{DeviceIntPoint, DeviceIntRect,
 use api::{DeviceSize, PremultipliedColorF};
 use box_shadow::{BoxShadowCacheKey};
 use clip::{ClipSource, ClipStore, ClipWorkItem};
 use clip_scroll_tree::CoordinateSystemId;
 use device::TextureFilter;
 use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
 use gpu_types::{ImageSource, PictureType, RasterizationSpace};
 use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
-use picture::ContentOrigin;
 use prim_store::{PrimitiveIndex, ImageCacheKey};
 #[cfg(feature = "debugger")]
 use print_tree::{PrintTreePrinter};
 use resource_cache::{CacheItem, ResourceCache};
 use std::{cmp, ops, usize, f32, i32};
 use texture_cache::{TextureCache, TextureCacheHandle};
 use tiling::{RenderPass, RenderTargetIndex};
 use tiling::{RenderTargetKind};
@@ -162,17 +161,17 @@ pub struct ClipRegionTask {
 }
 
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct PictureTask {
     pub prim_index: PrimitiveIndex,
     pub target_kind: RenderTargetKind,
-    pub content_origin: ContentOrigin,
+    pub content_origin: DeviceIntPoint,
     pub color: PremultipliedColorF,
     pub pic_type: PictureType,
     pub uv_rect_handle: GpuCacheHandle,
 }
 
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
@@ -254,17 +253,17 @@ pub struct RenderTask {
     pub saved_index: Option<SavedTargetIndex>,
 }
 
 impl RenderTask {
     pub fn new_picture(
         location: RenderTaskLocation,
         prim_index: PrimitiveIndex,
         target_kind: RenderTargetKind,
-        content_origin: ContentOrigin,
+        content_origin: DeviceIntPoint,
         color: PremultipliedColorF,
         clear_mode: ClearMode,
         children: Vec<RenderTaskId>,
         pic_type: PictureType,
     ) -> Self {
         RenderTask {
             children,
             location,
@@ -523,29 +522,21 @@ impl RenderTask {
         // TODO(gw): Maybe there's a way to make this stuff a bit
         //           more type-safe. Although, it will always need
         //           to be kept in sync with the GLSL code anyway.
 
         let (data1, data2) = match self.kind {
             RenderTaskKind::Picture(ref task) => {
                 (
                     // Note: has to match `PICTURE_TYPE_*` in shaders
-                    // TODO(gw): Instead of using the sign of the picture
-                    //           type here, we should consider encoding it
-                    //           as a set of flags that get casted here
-                    //           and in the shader. This is a bit tidier
-                    //           and allows for future expansion of flags.
-                    match task.content_origin {
-                        ContentOrigin::Local(point) => [
-                            point.x, point.y, task.pic_type as u32 as f32,
-                        ],
-                        ContentOrigin::Screen(point) => [
-                            point.x as f32, point.y as f32, -(task.pic_type as u32 as f32),
-                        ],
-                    },
+                    [
+                        task.content_origin.x as f32,
+                        task.content_origin.y as f32,
+                        task.pic_type as u32 as f32,
+                    ],
                     task.color.to_array()
                 )
             }
             RenderTaskKind::CacheMask(ref task) => {
                 (
                     [
                         task.actual_rect.origin.x as f32,
                         task.actual_rect.origin.y as f32,
@@ -916,16 +907,17 @@ impl RenderTaskCache {
             // TODO(gw): Support color tasks in the texture cache,
             //           and perhaps consider if we can determine
             //           if some tasks are opaque as an optimization.
             let descriptor = ImageDescriptor::new(
                 size.width as u32,
                 size.height as u32,
                 image_format,
                 is_opaque,
+                false,
             );
 
             // Allocate space in the texture cache, but don't supply
             // and CPU-side data to be uploaded.
             texture_cache.update(
                 &mut cache_entry.handle,
                 descriptor,
                 TextureFilter::Linear,
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -37,17 +37,16 @@ use frame_builder::FrameBuilderConfig;
 use gleam::gl;
 use glyph_rasterizer::{GlyphFormat, GlyphRasterizer};
 use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
 use gpu_types::PrimitiveInstance;
 use internal_types::{SourceTexture, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceCacheError};
 use internal_types::{CacheTextureId, DebugOutput, FastHashMap, RenderedDocument, ResultMsg};
 use internal_types::{TextureUpdateList, TextureUpdateOp, TextureUpdateSource};
 use internal_types::{RenderTargetInfo, SavedTargetIndex};
-use picture::ContentOrigin;
 use prim_store::DeferredResolve;
 use profiler::{BackendProfileCounters, FrameProfileCounters, Profiler};
 use profiler::{GpuProfileTag, RendererProfileCounters, RendererProfileTimers};
 use query::{GpuProfiler, GpuTimer};
 use rayon::{ThreadPool, ThreadPoolBuilder};
 use record::ApiRecordingReceiver;
 use render_backend::RenderBackend;
 use scene_builder::SceneBuilder;
@@ -116,20 +115,16 @@ const GPU_TAG_BRUSH_SOLID: GpuProfileTag
 const GPU_TAG_BRUSH_LINE: GpuProfileTag = GpuProfileTag {
     label: "Line",
     color: debug_colors::DARKRED,
 };
 const GPU_TAG_CACHE_CLIP: GpuProfileTag = GpuProfileTag {
     label: "C_Clip",
     color: debug_colors::PURPLE,
 };
-const GPU_TAG_CACHE_TEXT_RUN: GpuProfileTag = GpuProfileTag {
-    label: "C_TextRun",
-    color: debug_colors::MISTYROSE,
-};
 const GPU_TAG_SETUP_TARGET: GpuProfileTag = GpuProfileTag {
     label: "target init",
     color: debug_colors::SLATEGREY,
 };
 const GPU_TAG_SETUP_DATA: GpuProfileTag = GpuProfileTag {
     label: "data init",
     color: debug_colors::LIGHTGREY,
 };
@@ -1440,17 +1435,16 @@ impl Renderer {
             (true, true) => FontRenderMode::Subpixel,
             (true, false) => FontRenderMode::Alpha,
             (false, _) => FontRenderMode::Mono,
         };
 
         let config = FrameBuilderConfig {
             enable_scrollbars: options.enable_scrollbars,
             default_font_render_mode,
-            debug: options.debug,
             dual_source_blending_is_enabled: true,
             dual_source_blending_is_supported: ext_dual_source_blending,
         };
 
         let device_pixel_ratio = options.device_pixel_ratio;
         // First set the flags to default and later call set_debug_flags to ensure any
         // potential transition when enabling a flag is run.
         let debug_flags = DebugFlags::default();
@@ -1479,16 +1473,17 @@ impl Renderer {
                     .build();
                 Arc::new(worker.unwrap())
             });
         let enable_render_on_scroll = options.enable_render_on_scroll;
 
         let blob_image_renderer = options.blob_image_renderer.take();
         let thread_listener_for_render_backend = thread_listener.clone();
         let thread_listener_for_scene_builder = thread_listener.clone();
+        let renderer_id_for_render_backend = options.renderer_id.clone();
         let rb_thread_name = format!("WRRenderBackend#{}", options.renderer_id.unwrap_or(0));
         let scene_thread_name = format!("WRSceneBuilder#{}", options.renderer_id.unwrap_or(0));
         let glyph_rasterizer = GlyphRasterizer::new(workers)?;
 
         let (scene_builder, scene_tx, scene_rx) = SceneBuilder::new(config, api_tx.clone());
         thread::Builder::new().name(scene_thread_name.clone()).spawn(move || {
             register_thread_with_profiler(scene_thread_name.clone());
             if let Some(ref thread_listener) = *thread_listener_for_scene_builder {
@@ -1501,16 +1496,17 @@ impl Renderer {
             if let Some(ref thread_listener) = *thread_listener_for_scene_builder {
                 thread_listener.thread_stopped(&scene_thread_name);
             }
         })?;
 
         thread::Builder::new().name(rb_thread_name.clone()).spawn(move || {
             register_thread_with_profiler(rb_thread_name.clone());
             if let Some(ref thread_listener) = *thread_listener_for_render_backend {
+                thread_listener.new_render_backend_thread(renderer_id_for_render_backend);
                 thread_listener.thread_started(&rb_thread_name);
             }
 
             let texture_cache = TextureCache::new(max_device_size);
             let resource_cache = ResourceCache::new(
                 texture_cache,
                 glyph_rasterizer,
                 blob_image_renderer,
@@ -1718,17 +1714,17 @@ impl Renderer {
         String::new()
     }
 
 
     #[cfg(feature = "debugger")]
     fn get_screenshot_for_debugger(&mut self) -> String {
         use api::ImageDescriptor;
 
-        let desc = ImageDescriptor::new(1024, 768, ImageFormat::BGRA8, true);
+        let desc = ImageDescriptor::new(1024, 768, ImageFormat::BGRA8, true, false);
         let data = self.device.read_pixels(&desc);
         let screenshot = debug_server::Screenshot::new(desc.width, desc.height, data);
 
         serde_json::to_string(&screenshot).unwrap()
     }
 
     #[cfg(not(feature = "debugger"))]
     fn get_passes_for_debugger(&self) -> String {
@@ -1809,24 +1805,16 @@ impl Renderer {
         );
         debug_target.add(
             debug_server::BatchKind::Cache,
             "Horizontal Blur",
             target.horizontal_blurs.len(),
         );
 
         for alpha_batch_container in &target.alpha_batch_containers {
-            for (_, batch) in &alpha_batch_container.text_run_cache_prims {
-                debug_target.add(
-                    debug_server::BatchKind::Cache,
-                    "Text Shadow",
-                    batch.len(),
-                );
-            }
-
             for batch in alpha_batch_container
                 .opaque_batches
                 .iter()
                 .rev() {
                 debug_target.add(
                     debug_server::BatchKind::Opaque,
                     batch.key.kind.debug_name(),
                     batch.instances.len(),
@@ -2420,27 +2408,21 @@ impl Renderer {
             .unwrap();
 
         // Before submitting the composite batch, do the
         // framebuffer readbacks that are needed for each
         // composite operation in this batch.
         let (readback_rect, readback_layer) = readback.get_target_rect();
         let (backdrop_rect, _) = backdrop.get_target_rect();
         let backdrop_screen_origin = match backdrop.kind {
-            RenderTaskKind::Picture(ref task_info) => match task_info.content_origin {
-                ContentOrigin::Local(_) => panic!("bug: composite from a local-space rasterized picture?"),
-                ContentOrigin::Screen(p) => p,
-            },
+            RenderTaskKind::Picture(ref task_info) => task_info.content_origin,
             _ => panic!("bug: composite on non-picture?"),
         };
         let source_screen_origin = match source.kind {
-            RenderTaskKind::Picture(ref task_info) => match task_info.content_origin {
-                ContentOrigin::Local(_) => panic!("bug: composite from a local-space rasterized picture?"),
-                ContentOrigin::Screen(p) => p,
-            },
+            RenderTaskKind::Picture(ref task_info) => task_info.content_origin,
             _ => panic!("bug: composite on non-picture?"),
         };
 
         // Bind the FBO to blit the backdrop to.
         // Called per-instance in case the layer (and therefore FBO)
         // changes. The device will skip the GL call if the requested
         // target is already bound.
         let cache_draw_target = (cache_texture, readback_layer.0 as i32);
@@ -2679,41 +2661,16 @@ impl Renderer {
                     &BatchTextures::no_texture(),
                     stats,
                 );
             }
         }
 
         self.handle_scaling(render_tasks, &target.scalings, SourceTexture::CacheRGBA8);
 
-        // Draw any textrun caches for this target. For now, this
-        // is only used to cache text runs that are to be blurred
-        // for shadow support. In the future it may be worth
-        // considering using this for (some) other text runs, since
-        // it removes the overhead of submitting many small glyphs
-        // to multiple tiles in the normal text run case.
-        for alpha_batch_container in &target.alpha_batch_containers {
-            if !alpha_batch_container.text_run_cache_prims.is_empty() {
-                self.device.set_blend(true);
-                self.device.set_blend_mode_premultiplied_alpha();
-
-                let _timer = self.gpu_profile.start_timer(GPU_TAG_CACHE_TEXT_RUN);
-                self.shaders.cs_text_run
-                    .bind(&mut self.device, projection, &mut self.renderer_errors);
-                for (texture_id, instances) in &alpha_batch_container.text_run_cache_prims {
-                    self.draw_instanced_batch(
-                        instances,
-                        VertexArrayKind::Primitive,
-                        &BatchTextures::color(*texture_id),
-                        stats,
-                    );
-                }
-            }
-        }
-
         //TODO: record the pixel count for cached primitives
 
         if target.needs_depth() {
             let _gl = self.gpu_profile.start_marker("opaque batches");
             let opaque_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_OPAQUE);
             self.device.set_blend(false);
             //Note: depth equality is needed for split planes
             self.device.set_depth_func(DepthFunction::LessEqual);
@@ -3816,25 +3773,25 @@ pub trait ExternalImageHandler {
 pub trait OutputImageHandler {
     fn lock(&mut self, pipeline_id: PipelineId) -> Option<(u32, DeviceIntSize)>;
     fn unlock(&mut self, pipeline_id: PipelineId);
 }
 
 pub trait ThreadListener {
     fn thread_started(&self, thread_name: &str);
     fn thread_stopped(&self, thread_name: &str);
+    fn new_render_backend_thread(&self, renderer_id: Option<u64>);
 }
 
 pub struct RendererOptions {
     pub device_pixel_ratio: f32,
     pub resource_override_path: Option<PathBuf>,
     pub enable_aa: bool,
     pub enable_dithering: bool,
     pub max_recorded_profiles: usize,
-    pub debug: bool,
     pub enable_scrollbars: bool,
     pub precache_shaders: bool,
     pub renderer_kind: RendererKind,
     pub enable_subpixel_aa: bool,
     pub clear_color: Option<ColorF>,
     pub enable_clear_scissor: bool,
     pub max_texture_size: Option<u32>,
     pub scatter_gpu_cache_updates: bool,
@@ -3854,17 +3811,16 @@ impl Default for RendererOptions {
     fn default() -> Self {
         RendererOptions {
             device_pixel_ratio: 1.0,
             resource_override_path: None,
             enable_aa: true,
             enable_dithering: true,
             debug_flags: DebugFlags::empty(),
             max_recorded_profiles: 0,
-            debug: false,
             enable_scrollbars: false,
             precache_shaders: false,
             renderer_kind: RendererKind::Native,
             enable_subpixel_aa: false,
             clear_color: Some(ColorF::new(1.0, 1.0, 1.0, 1.0)),
             enable_clear_scissor: true,
             max_texture_size: None,
             // Scattered GPU cache updates haven't met a test that would show their superiority yet.
--- a/gfx/webrender/src/resource_cache.rs
+++ b/gfx/webrender/src/resource_cache.rs
@@ -884,18 +884,17 @@ impl ResourceCache {
                     (Some(stride), offset)
                 };
 
                 ImageDescriptor {
                     width: actual_width,
                     height: actual_height,
                     stride,
                     offset,
-                    format: image_descriptor.format,
-                    is_opaque: image_descriptor.is_opaque,
+                    ..*image_descriptor
                 }
             } else {
                 image_template.descriptor.clone()
             };
 
             let filter = match request.rendering {
                 ImageRendering::Pixelated => {
                     TextureFilter::Nearest
@@ -903,17 +902,18 @@ impl ResourceCache {
                 ImageRendering::Auto | ImageRendering::CrispEdges => {
                     // If the texture uses linear filtering, enable mipmaps and
                     // trilinear filtering, for better image quality. We only
                     // support this for now on textures that are not placed
                     // into the shared cache. This accounts for any image
                     // that is > 512 in either dimension, so it should cover
                     // the most important use cases. We may want to support
                     // mip-maps on shared cache items in the future.
-                    if descriptor.width > 512 &&
+                    if descriptor.allow_mipmaps &&
+                       descriptor.width > 512 &&
                        descriptor.height > 512 &&
                        !self.texture_cache.is_allowed_in_shared_cache(
                         TextureFilter::Linear,
                         &descriptor,
                     ) {
                         TextureFilter::Trilinear
                     } else {
                         TextureFilter::Linear
@@ -949,16 +949,19 @@ impl ResourceCache {
             self.cached_glyphs.clear();
         }
         if what.contains(ClearCache::GLYPH_DIMENSIONS) {
             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();
+        }
     }
 
     pub fn clear_namespace(&mut self, namespace: IdNamespace) {
         self.resources
             .image_templates
             .images
             .retain(|key, _| key.0 != namespace);
         self.cached_images
--- a/gfx/webrender/src/shade.rs
+++ b/gfx/webrender/src/shade.rs
@@ -408,17 +408,16 @@ fn create_clip_shader(name: &'static str
     program
 }
 
 
 pub struct Shaders {
     // These are "cache shaders". These shaders are used to
     // draw intermediate results to cache targets. The results
     // of these shaders are then used by the primitive shaders.
-    pub cs_text_run: LazilyCompiledShader,
     pub cs_blur_a8: LazilyCompiledShader,
     pub cs_blur_rgba8: LazilyCompiledShader,
 
     // Brush shaders
     brush_solid: BrushShader,
     brush_line: BrushShader,
     brush_image: Vec<Option<BrushShader>>,
     brush_blend: BrushShader,
@@ -453,24 +452,16 @@ pub struct Shaders {
 }
 
 impl Shaders {
     pub fn new(
         device: &mut Device,
         gl_type: GlType,
         options: &RendererOptions,
     ) -> Result<Self, ShaderError> {
-        let cs_text_run = LazilyCompiledShader::new(
-            ShaderKind::Cache(VertexArrayKind::Primitive),
-            "cs_text_run",
-            &[],
-            device,
-            options.precache_shaders,
-        )?;
-
         let brush_solid = BrushShader::new(
             "brush_solid",
             device,
             &[],
             options.precache_shaders,
         )?;
 
         let brush_line = BrushShader::new(
@@ -677,17 +668,16 @@ impl Shaders {
             ShaderKind::Primitive,
             "ps_split_composite",
             &[],
             device,
             options.precache_shaders,
         )?;
 
         Ok(Shaders {
-            cs_text_run,
             cs_blur_a8,
             cs_blur_rgba8,
             brush_solid,
             brush_line,
             brush_image,
             brush_blend,
             brush_mix_blend,
             brush_yuv_image,
@@ -777,17 +767,16 @@ impl Shaders {
                     }
                 };
                 prim_shader.get(transform_kind)
             }
         }
     }
 
     pub fn deinit(self, device: &mut Device) {
-        self.cs_text_run.deinit(device);
         self.cs_blur_a8.deinit(device);
         self.cs_blur_rgba8.deinit(device);
         self.brush_solid.deinit(device);
         self.brush_line.deinit(device);
         self.brush_blend.deinit(device);
         self.brush_mix_blend.deinit(device);
         self.brush_radial_gradient.deinit(device);
         self.brush_linear_gradient.deinit(device);
--- a/gfx/webrender/src/texture_cache.rs
+++ b/gfx/webrender/src/texture_cache.rs
@@ -276,16 +276,66 @@ impl TextureCache {
             pending_updates: TextureUpdateList::new(),
             frame_id: FrameId(0),
             entries: FreeList::new(),
             standalone_entry_handles: Vec::new(),
             shared_entry_handles: Vec::new(),
         }
     }
 
+    pub fn clear(&mut self) {
+        let standalone_entry_handles = mem::replace(
+            &mut self.standalone_entry_handles,
+            Vec::new(),
+        );
+
+        for handle in standalone_entry_handles {
+            let entry = self.entries.free(handle);
+            entry.evict();
+            self.free(entry);
+        }
+
+        let shared_entry_handles = mem::replace(
+            &mut self.shared_entry_handles,
+            Vec::new(),
+        );
+
+        for handle in shared_entry_handles {
+            let entry = self.entries.free(handle);
+            entry.evict();
+            self.free(entry);
+        }
+
+        assert!(self.entries.len() == 0);
+
+        if let Some(texture_id) = self.array_a8_linear.clear() {
+            self.pending_updates.push(TextureUpdate {
+                id: texture_id,
+                op: TextureUpdateOp::Free,
+            });
+            self.cache_textures.free(texture_id, self.array_a8_linear.format);
+        }
+
+        if let Some(texture_id) = self.array_rgba8_linear.clear() {
+            self.pending_updates.push(TextureUpdate {
+                id: texture_id,
+                op: TextureUpdateOp::Free,
+            });
+            self.cache_textures.free(texture_id, self.array_rgba8_linear.format);
+        }
+
+        if let Some(texture_id) = self.array_rgba8_nearest.clear() {
+            self.pending_updates.push(TextureUpdate {
+                id: texture_id,
+                op: TextureUpdateOp::Free,
+            });
+            self.cache_textures.free(texture_id, self.array_rgba8_nearest.format);
+        }
+    }
+
     pub fn begin_frame(&mut self, frame_id: FrameId) {
         self.frame_id = frame_id;
     }
 
     pub fn end_frame(&mut self, texture_cache_profile: &mut TextureCacheProfileCounters) {
         self.expire_old_standalone_entries();
 
         self.array_a8_linear
@@ -1008,16 +1058,22 @@ impl TextureArray {
             filter,
             layer_count,
             is_allocated: false,
             regions: Vec::new(),
             texture_id: None,
         }
     }
 
+    fn clear(&mut self) -> Option<CacheTextureId> {
+        self.is_allocated = false;
+        self.regions.clear();
+        self.texture_id.take()
+    }
+
     fn update_profile(&self, counter: &mut ResourceProfileCounter) {
         if self.is_allocated {
             let size = self.layer_count as u32 * TEXTURE_LAYER_DIMENSIONS *
                 TEXTURE_LAYER_DIMENSIONS * self.format.bytes_per_pixel();
             counter.set(self.layer_count as usize, size as usize);
         } else {
             counter.set(0, 0);
         }
--- a/gfx/webrender/tests/angle_shader_validation.rs
+++ b/gfx/webrender/tests/angle_shader_validation.rs
@@ -40,20 +40,16 @@ const SHADERS: &[Shader] = &[
         name: "cs_clip_border",
         features: CLIP_FEATURES,
     },
     // Cache shaders
     Shader {
         name: "cs_blur",
         features: CACHE_FEATURES,
     },
-    Shader {
-        name: "cs_text_run",
-        features: CACHE_FEATURES,
-    },
     // Prim shaders
     Shader {
         name: "ps_border_corner",
         features: PRIM_FEATURES,
     },
     Shader {
         name: "ps_border_edge",
         features: PRIM_FEATURES,
--- a/gfx/webrender_api/Cargo.toml
+++ b/gfx/webrender_api/Cargo.toml
@@ -8,21 +8,21 @@ repository = "https://github.com/servo/w
 [features]
 nightly = ["euclid/unstable", "serde/unstable"]
 ipc = ["ipc-channel"]
 serialize = []
 deserialize = []
 
 [dependencies]
 app_units = "0.6"
+bincode = "1.0"
 bitflags = "1.0"
-bincode = "0.9"
 byteorder = "1.2.1"
+ipc-channel = {version = "0.10.0", optional = true}
 euclid = { version = "0.17", features = ["serde"] }
-ipc-channel = {version = "0.9", optional = true}
 serde = { version = "=1.0.27", features = ["rc"] }
 serde_derive = { version = "=1.0.27", features = ["deserialize_in_place"] }
 time = "0.1"
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-foundation = "0.5"
 core-graphics = "0.13"
 
--- a/gfx/webrender_api/src/api.rs
+++ b/gfx/webrender_api/src/api.rs
@@ -531,16 +531,17 @@ bitflags!{
 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;
     }
 }
 
 /// 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/display_item.rs
+++ b/gfx/webrender_api/src/display_item.rs
@@ -415,18 +415,18 @@ pub struct GradientStop {
     pub offset: f32,
     pub color: ColorF,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct RadialGradient {
     pub center: LayoutPoint,
     pub radius: LayoutSize,
-    pub start_radius: f32,
-    pub end_radius: f32,
+    pub start_offset: f32,
+    pub end_offset: f32,
     pub extend_mode: ExtendMode,
 } // IMPLICIT stops: Vec<GradientStop>
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ClipChainItem {
     pub id: ClipChainId,
     pub parent: Option<ClipChainId>,
 } // IMPLICIT stops: Vec<ClipId>
--- a/gfx/webrender_api/src/display_list.rs
+++ b/gfx/webrender_api/src/display_list.rs
@@ -157,24 +157,24 @@ impl BuiltDisplayList {
         AuxIter::new(&self.data[range.start .. range.start + range.length])
     }
 }
 
 /// Returns the byte-range the slice occupied, and the number of elements
 /// in the slice.
 fn skip_slice<T: for<'de> Deserialize<'de>>(
     list: &BuiltDisplayList,
-    data: &mut &[u8],
+    mut data: &mut &[u8],
 ) -> (ItemRange<T>, usize) {
     let base = list.data.as_ptr() as usize;
 
-    let byte_size: usize = bincode::deserialize_from(data, bincode::Infinite)
+    let byte_size: usize = bincode::deserialize_from(&mut data)
                                     .expect("MEH: malicious input?");
     let start = data.as_ptr() as usize;
-    let item_count: usize = bincode::deserialize_from(data, bincode::Infinite)
+    let item_count: usize = bincode::deserialize_from(&mut data)
                                     .expect("MEH: malicious input?");
 
     // Remember how many bytes item_count occupied
     let item_count_size = data.as_ptr() as usize - start;
 
     let range = ItemRange {
         start: start - base,                      // byte offset to item_count
         length: byte_size + item_count_size,      // number of bytes for item_count + payload
@@ -236,19 +236,18 @@ impl<'a> BuiltDisplayListIter<'a> {
         self.cur_clip_chain_items = ItemRange::default();
 
         loop {
             if self.data.len() == 0 {
                 return None;
             }
 
             {
-                let reader = bincode::read_types::IoReader::new(UnsafeReader::new(&mut self.data));
-                let mut deserializer = bincode::Deserializer::new(reader, bincode::Infinite);
-                Deserialize::deserialize_in_place(&mut deserializer, &mut self.cur_item)
+                let reader = bincode::IoReader::new(UnsafeReader::new(&mut self.data));
+                bincode::deserialize_in_place(reader, &mut self.cur_item)
                     .expect("MEH: malicious process?");
             }
 
             match self.cur_item.item {
                 SetGradientStops => {
                     self.cur_stops = skip_slice::<GradientStop>(self.list, &mut self.data).0;
 
                     // This is a dummy item, skip over it
@@ -388,18 +387,17 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> {
     }
 }
 
 impl<'de, 'a, T: Deserialize<'de>> AuxIter<'a, T> {
     pub fn new(mut data: &'a [u8]) -> Self {
         let size: usize = if data.len() == 0 {
             0 // Accept empty ItemRanges pointing anywhere
         } else {
-            bincode::deserialize_from(&mut UnsafeReader::new(&mut data), bincode::Infinite)
-                .expect("MEH: malicious input?")
+            bincode::deserialize_from(&mut UnsafeReader::new(&mut data)).expect("MEH: malicious input?")
         };
 
         AuxIter {
             data,
             size,
             _boo: PhantomData,
         }
     }
@@ -409,17 +407,17 @@ impl<'a, T: for<'de> Deserialize<'de>> I
     type Item = T;
 
     fn next(&mut self) -> Option<T> {
         if self.size == 0 {
             None
         } else {
             self.size -= 1;
             Some(
-                bincode::deserialize_from(&mut UnsafeReader::new(&mut self.data), bincode::Infinite)
+                bincode::deserialize_from(&mut UnsafeReader::new(&mut self.data))
                     .expect("MEH: malicious input?"),
             )
         }
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
         (self.size, Some(self.size))
     }
@@ -660,23 +658,23 @@ impl<'a> Write for SizeCounter {
 /// invocations.
 ///
 /// If this assumption is incorrect, the result will be Undefined Behaviour. This
 /// assumption should hold for all derived Serialize impls, which is all we currently
 /// use.
 fn serialize_fast<T: Serialize>(vec: &mut Vec<u8>, e: &T) {
     // manually counting the size is faster than vec.reserve(bincode::serialized_size(&e) as usize) for some reason
     let mut size = SizeCounter(0);
-    bincode::serialize_into(&mut size, e, bincode::Infinite).unwrap();
+    bincode::serialize_into(&mut size, e).unwrap();
     vec.reserve(size.0);
 
     let old_len = vec.len();
     let ptr = unsafe { vec.as_mut_ptr().offset(old_len as isize) };
     let mut w = UnsafeVecWriter(ptr);
-    bincode::serialize_into(&mut w, e, bincode::Infinite).unwrap();
+    bincode::serialize_into(&mut w, e).unwrap();
 
     // fix up the length
     unsafe { vec.set_len(old_len + size.0); }
 
     // make sure we wrote the right amount
     debug_assert_eq!(((w.0 as usize) - (vec.as_ptr() as usize)), vec.len());
 }
 
@@ -697,29 +695,29 @@ fn serialize_iter_fast<I>(vec: &mut Vec<
 where I: ExactSizeIterator + Clone,
       I::Item: Serialize,
 {
     // manually counting the size is faster than vec.reserve(bincode::serialized_size(&e) as usize) for some reason
     let mut size = SizeCounter(0);
     let mut count1 = 0;
 
     for e in iter.clone() {
-        bincode::serialize_into(&mut size, &e, bincode::Infinite).unwrap();
+        bincode::serialize_into(&mut size, &e).unwrap();
         count1 += 1;
     }
 
     vec.reserve(size.0);
 
     let old_len = vec.len();
     let ptr = unsafe { vec.as_mut_ptr().offset(old_len as isize) };
     let mut w = UnsafeVecWriter(ptr);
     let mut count2 = 0;
 
     for e in iter {
-        bincode::serialize_into(&mut w, &e, bincode::Infinite).unwrap();
+        bincode::serialize_into(&mut w, &e).unwrap();
         count2 += 1;
     }
 
     // fix up the length
     unsafe { vec.set_len(old_len + size.0); }
 
     // make sure we wrote the right amount
     debug_assert_eq!(((w.0 as usize) - (vec.as_ptr() as usize)), vec.len());
@@ -957,17 +955,16 @@ impl DisplayListBuilder {
         // Now write the actual byte_size
         let final_offset = data.len();
         let byte_size = final_offset - payload_offset;
 
         // Note we don't use serialize_fast because we don't want to change the Vec's len
         bincode::serialize_into(
             &mut &mut data[byte_size_offset..],
             &byte_size,
-            bincode::Infinite,
         ).unwrap();
 
         debug_assert_eq!(len, count);
     }
 
     fn push_iter<I>(&mut self, iter: I)
     where
         I: IntoIterator,
@@ -1070,70 +1067,51 @@ impl DisplayListBuilder {
     fn normalize_stops(stops: &mut Vec<GradientStop>, extend_mode: ExtendMode) -> (f32, f32) {
         assert!(stops.len() >= 2);
 
         let first = *stops.first().unwrap();
         let last = *stops.last().unwrap();
 
         assert!(first.offset <= last.offset);
 
-        let stops_origin = first.offset;
         let stops_delta = last.offset - first.offset;
 
         if stops_delta > 0.000001 {
             for stop in stops {
-                stop.offset = (stop.offset - stops_origin) / stops_delta;
+                stop.offset = (stop.offset - first.offset) / stops_delta;
             }
 
             (first.offset, last.offset)
         } else {
             // We have a degenerate gradient and can't accurately transform the stops
             // what happens here depends on the repeat behavior, but in any case
             // we reconstruct the gradient stops to something simpler and equivalent
             stops.clear();
 
             match extend_mode {
                 ExtendMode::Clamp => {
                     // This gradient is two colors split at the offset of the stops,
                     // so create a gradient with two colors split at 0.5 and adjust
                     // the gradient line so 0.5 is at the offset of the stops
-                    stops.push(GradientStop {
-                        color: first.color,
-                        offset: 0.0,
-                    });
-                    stops.push(GradientStop {
-                        color: first.color,
-                        offset: 0.5,
-                    });
-                    stops.push(GradientStop {
-                        color: last.color,
-                        offset: 0.5,
-                    });
-                    stops.push(GradientStop {
-                        color: last.color,
-                        offset: 1.0,
-                    });
+                    stops.push(GradientStop { color: first.color, offset: 0.0, });
+                    stops.push(GradientStop { color: first.color, offset: 0.5, });
+                    stops.push(GradientStop { color: last.color, offset: 0.5, });
+                    stops.push(GradientStop { color: last.color, offset: 1.0, });
 
                     let offset = last.offset;
 
                     (offset - 0.5, offset + 0.5)
                 }
                 ExtendMode::Repeat => {
                     // A repeating gradient with stops that are all in the same
                     // position should just display the last color. I believe the
                     // spec says that it should be the average color of the gradient,
                     // but this matches what Gecko and Blink does
-                    stops.push(GradientStop {
-                        color: last.color,
-                        offset: 0.0,
-                    });
-                    stops.push(GradientStop {
-                        color: last.color,
-                        offset: 1.0,
-                    });
+                    stops.push(GradientStop { color: last.color, offset: 0.0, });
+                    stops.push(GradientStop { color: last.color, offset: 1.0, });
 
                     (0.0, 1.0)
                 }
             }
         }
     }
 
     // NOTE: gradients must be pushed in the order they're created
@@ -1170,69 +1148,41 @@ impl DisplayListBuilder {
     ) -> RadialGradient {
         if radius.width <= 0.0 || radius.height <= 0.0 {
             // The shader cannot handle a non positive radius. So
             // reuse the stops vector and construct an equivalent
             // gradient.
             let last_color = stops.last().unwrap().color;
 
             let stops = [
-                GradientStop {
-                    offset: 0.0,
-                    color: last_color,
-                },
-                GradientStop {
-                    offset: 1.0,
-                    color: last_color,
-                },
+                GradientStop { offset: 0.0, color: last_color, },
+                GradientStop { offset: 1.0, color: last_color, },
             ];
 
             self.push_stops(&stops);
 
             return RadialGradient {
                 center,
                 radius: LayoutSize::new(1.0, 1.0),
-                start_radius: 0.0,
-                end_radius: 1.0,
+                start_offset: 0.0,
+                end_offset: 1.0,
                 extend_mode,
             };
         }
 
         let (start_offset, end_offset) =
             DisplayListBuilder::normalize_stops(&mut stops, extend_mode);
 
         self.push_stops(&stops);
 
         RadialGradient {
             center,
             radius,
-            start_radius: radius.width * start_offset,
-            end_radius: radius.width * end_offset,
-            extend_mode,
-        }
-    }
-
-    // NOTE: gradients must be pushed in the order they're created
-    // because create_gradient stores the stops in anticipation
-    pub fn create_complex_radial_gradient(
-        &mut self,
-        center: LayoutPoint,
-        radius: LayoutSize,
-        start_radius: f32,
-        end_radius: f32,
-        stops: Vec<GradientStop>,
-        extend_mode: ExtendMode,
-    ) -> RadialGradient {
-        self.push_stops(&stops);
-
-        RadialGradient {
-            center,
-            radius,
-            start_radius,
-            end_radius,
+            start_offset: start_offset,
+            end_offset: end_offset,
             extend_mode,
         }
     }
 
     pub fn push_border(
         &mut self,
         info: &LayoutPrimitiveInfo,
         widths: BorderWidths,
--- a/gfx/webrender_api/src/image.rs
+++ b/gfx/webrender_api/src/image.rs
@@ -71,27 +71,35 @@ impl ImageFormat {
 #[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ImageDescriptor {
     pub format: ImageFormat,
     pub width: u32,
     pub height: u32,
     pub stride: Option<u32>,
     pub offset: u32,
     pub is_opaque: bool,
+    pub allow_mipmaps: bool,
 }
 
 impl ImageDescriptor {
-    pub fn new(width: u32, height: u32, format: ImageFormat, is_opaque: bool) -> Self {
+    pub fn new(
+        width: u32,
+        height: u32,
+        format: ImageFormat,
+        is_opaque: bool,
+        allow_mipmaps: bool,
+    ) -> Self {
         ImageDescriptor {
             width,
             height,
             format,
             stride: None,
             offset: 0,
             is_opaque,
+            allow_mipmaps,
         }
     }
 
     pub fn compute_stride(&self) -> u32 {
         self.stride
             .unwrap_or(self.width * self.format.bytes_per_pixel())
     }
 
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-2083e83d958dd4a230ccae5c518e4bc8fbf88009
+30cfecc343e407ce277d07cf09f27ad9dd1917a1
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -262,16 +262,17 @@ impl<'a> Into<ImageDescriptor> for &'a W
             stride: if self.stride != 0 {
                 Some(self.stride)
             } else {
                 None
             },
             format: self.format,
             is_opaque: self.is_opaque,
             offset: 0,
+            allow_mipmaps: false,
         }
     }
 }
 
 /// cbindgen:field-names=[mHandle]
 #[repr(C)]
 #[derive(Copy, Clone)]
 pub struct WrExternalImageId(pub u64);
@@ -666,16 +667,19 @@ impl ThreadListener for GeckoProfilerThr
         }
     }
 
     fn thread_stopped(&self, _: &str) {
         unsafe {
             gecko_profiler_unregister_thread();
         }
     }
+
+    fn new_render_backend_thread(&self, _renderer_id: Option<u64>) {
+    }
 }
 
 pub struct WrThreadPool(Arc<rayon::ThreadPool>);
 
 #[no_mangle]
 pub unsafe extern "C" fn wr_thread_pool_new() -> *mut WrThreadPool {
     let worker = rayon::ThreadPoolBuilder::new()
         .thread_name(|idx|{ format!("WRWorker#{}", idx) })
--- a/gfx/wrench/Cargo.toml
+++ b/gfx/wrench/Cargo.toml
@@ -2,17 +2,17 @@
 name = "wrench"
 version = "0.3.0"
 authors = ["Vladimir Vukicevic <vladimir@pobox.com>"]
 build = "build.rs"
 license = "MPL-2.0"
 
 [dependencies]
 base64 = "0.6"
-bincode = "0.9"
+bincode = "1.0"
 byteorder = "1.0"
 env_logger = { version = "0.5", optional = true }
 euclid = "0.17"
 gleam = "0.4"
 glutin = "0.12"
 app_units = "0.6"
 image = "0.18"
 clap = { version = "2", features = ["yaml"] }
--- a/gfx/wrench/src/args.yaml
+++ b/gfx/wrench/src/args.yaml
@@ -12,20 +12,16 @@ args:
       short: v
       long: verbose
       help: Enable verbose display
   - zoom:
       short: z
       long: zoom
       help: Set zoom factor
       takes_value: true
-  - debug:
-      short: d
-      long: debug
-      help: Enable debug renderer
   - shaders:
       long: shaders
       help: Override path for shaders
       takes_value: true
   - rebuild:
       short: r
       long: rebuild
       help: Rebuild display list from scratch every frame
--- a/gfx/wrench/src/main.rs
+++ b/gfx/wrench/src/main.rs
@@ -424,17 +424,16 @@ fn main() {
         &mut window,
         events_loop.as_mut().map(|el| el.create_proxy()),
         res_path,
         dp_ratio,
         save_type,
         dim,
         args.is_present("rebuild"),
         args.is_present("no_subpixel_aa"),
-        args.is_present("debug"),
         args.is_present("verbose"),
         args.is_present("no_scissor"),
         args.is_present("no_batch"),
         args.is_present("precache"),
         args.is_present("slow_subpixel"),
         zoom_factor.unwrap_or(1.0),
         notifier,
     );
--- a/gfx/wrench/src/rawtest.rs
+++ b/gfx/wrench/src/rawtest.rs
@@ -83,17 +83,17 @@ impl<'a> RawtestHarness<'a> {
         println!("\ttile decomposition...");
         // This exposes a crash in tile decomposition
         let layout_size = LayoutSize::new(800., 800.);
         let mut resources = ResourceUpdates::new();
 
         let blob_img = self.wrench.api.generate_image_key();
         resources.add_image(
             blob_img,
-            ImageDescriptor::new(151, 56, ImageFormat::BGRA8, true),
+            ImageDescriptor::new(151, 56, ImageFormat::BGRA8, true, false),
             ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
             Some(128),
         );
 
         let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
 
         let info = LayoutPrimitiveInfo::new(rect(448.899994, 74.0, 151.000031, 56.));
 
@@ -135,17 +135,17 @@ impl<'a> RawtestHarness<'a> {
         let layout_size = LayoutSize::new(400., 400.);
         let mut resources = ResourceUpdates::new();
         {
             let api = &self.wrench.api;
 
             blob_img = api.generate_image_key();
             resources.add_image(
                 blob_img,
-                ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
+                ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false),
                 ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
                 None,
             );
         }
 
         // draw the blob the first time
         let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
         let info = LayoutPrimitiveInfo::new(rect(0.0, 60.0, 200.0, 200.0));
@@ -215,24 +215,24 @@ impl<'a> RawtestHarness<'a> {
         let layout_size = LayoutSize::new(400., 400.);
         let mut resources = ResourceUpdates::new();
         let (blob_img, blob_img2) = {
             let api = &self.wrench.api;
 
             blob_img = api.generate_image_key();
             resources.add_image(
                 blob_img,
-                ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
+                ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false),
                 ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
                 None,
             );
             blob_img2 = api.generate_image_key();
             resources.add_image(
                 blob_img2,
-                ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
+                ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false),
                 ImageData::new_blob_image(blob::serialize_blob(ColorU::new(80, 50, 150, 255))),
                 None,
             );
             (blob_img, blob_img2)
         };
 
         // setup some counters to count how many times each image is requested
         let img1_requested = Arc::new(AtomicIsize::new(0));
@@ -280,38 +280,38 @@ impl<'a> RawtestHarness<'a> {
         self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
         let _pixels_first = self.render_and_get_pixels(window_rect);
 
 
         // update and redraw both images
         let mut resources = ResourceUpdates::new();
         resources.update_image(
             blob_img,
-            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
+            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false),
             ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
             Some(rect(100, 100, 100, 100)),
         );
         resources.update_image(
             blob_img2,
-            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
+            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false),
             ImageData::new_blob_image(blob::serialize_blob(ColorU::new(59, 50, 150, 255))),
             Some(rect(100, 100, 100, 100)),
         );
 
         let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
         push_images(&mut builder);
         self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
         let _pixels_second = self.render_and_get_pixels(window_rect);
 
 
         // only update the first image
         let mut resources = ResourceUpdates::new();
         resources.update_image(
             blob_img,
-            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
+            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false),
             ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 150, 150, 255))),
             Some(rect(200, 200, 100, 100)),
         );
 
         let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
         push_images(&mut builder);
         self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
         let _pixels_third = self.render_and_get_pixels(window_rect);
@@ -334,17 +334,17 @@ impl<'a> RawtestHarness<'a> {
         );
         let layout_size = LayoutSize::new(400., 400.);
         let mut resources = ResourceUpdates::new();
 
         let blob_img = {
             let img = self.wrench.api.generate_image_key();
             resources.add_image(
                 img,
-                ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
+                ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false),
                 ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
                 None,
             );
             img
         };
 
         // draw the blobs the first time
         let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
@@ -363,17 +363,17 @@ impl<'a> RawtestHarness<'a> {
 
         self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
         let pixels_first = self.render_and_get_pixels(window_rect);
 
         // draw the blob image a second time after updating it with the same color
         let mut resources = ResourceUpdates::new();
         resources.update_image(
             blob_img,
-            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
+            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false),
             ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
             Some(rect(100, 100, 100, 100)),
         );
 
         // make a new display list that refers to the first image
         let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
         let info = LayoutPrimitiveInfo::new(rect(0.0, 60.0, 200.0, 200.0));
         builder.push_image(
@@ -387,17 +387,17 @@ impl<'a> RawtestHarness<'a> {
 
         self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
         let pixels_second = self.render_and_get_pixels(window_rect);
 
         // draw the blob image a third time after updating it with a different color
         let mut resources = ResourceUpdates::new();
         resources.update_image(
             blob_img,
-            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
+            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false),
             ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 150, 150, 255))),
             Some(rect(200, 200, 100, 100)),
         );
 
         // make a new display list that refers to the first image
         let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
         let info = LayoutPrimitiveInfo::new(rect(0.0, 60.0, 200.0, 200.0));
         builder.push_image(
@@ -502,17 +502,17 @@ impl<'a> RawtestHarness<'a> {
         );
 
         // 1. render some scene
 
         let mut resources = ResourceUpdates::new();
         let image = self.wrench.api.generate_image_key();
         resources.add_image(
             image,
-            ImageDescriptor::new(1, 1, ImageFormat::BGRA8, true),
+            ImageDescriptor::new(1, 1, ImageFormat::BGRA8, true, false),
             ImageData::new(vec![0xFF, 0, 0, 0xFF]),
             None,
         );
 
         let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
 
         builder.push_image(
             &LayoutPrimitiveInfo::new(rect(300.0, 70.0, 150.0, 50.0)),
--- a/gfx/wrench/src/reftest.rs
+++ b/gfx/wrench/src/reftest.rs
@@ -27,16 +27,17 @@ const PLATFORM: &str = "linux";
 #[cfg(target_os = "macos")]
 const PLATFORM: &str = "mac";
 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
 const PLATFORM: &str = "other";
 
 const OPTION_DISABLE_SUBPX: &str = "disable-subpixel";
 const OPTION_DISABLE_AA: &str = "disable-aa";
 const OPTION_DISABLE_DUAL_SOURCE_BLENDING: &str = "disable-dual-source-blending";
+const OPTION_ALLOW_MIPMAPS: &str = "allow-mipmaps";
 
 pub struct ReftestOptions {
     // These override values that are lower.
     pub allow_max_difference: usize,
     pub allow_num_differences: usize,
 }
 
 impl ReftestOptions {
@@ -72,16 +73,17 @@ pub struct Reftest {
     reference: PathBuf,
     font_render_mode: Option<FontRenderMode>,
     max_difference: usize,
     num_differences: usize,
     expected_draw_calls: Option<usize>,
     expected_alpha_targets: Option<usize>,
     expected_color_targets: Option<usize>,
     disable_dual_source_blending: bool,
+    allow_mipmaps: bool,
     zoom_factor: f32,
 }
 
 impl Display for Reftest {
     fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
         write!(
             f,
             "{} {} {}",
@@ -191,16 +193,17 @@ impl ReftestManifest {
             let mut max_count = 0;
             let mut op = ReftestOp::Equal;
             let mut font_render_mode = None;
             let mut expected_color_targets = None;
             let mut expected_alpha_targets = None;
             let mut expected_draw_calls = None;
             let mut disable_dual_source_blending = false;
             let mut zoom_factor = 1.0;
+            let mut allow_mipmaps = false;
 
             for (i, token) in tokens.iter().enumerate() {
                 match *token {
                     "include" => {
                         assert!(i == 0, "include must be by itself");
                         let include = dir.join(tokens[1]);
 
                         reftests.append(
@@ -243,16 +246,19 @@ impl ReftestManifest {
                             font_render_mode = Some(FontRenderMode::Alpha);
                         }
                         if args.iter().any(|arg| arg == &OPTION_DISABLE_AA) {
                             font_render_mode = Some(FontRenderMode::Mono);
                         }
                         if args.iter().any(|arg| arg == &OPTION_DISABLE_DUAL_SOURCE_BLENDING) {
                             disable_dual_source_blending = true;
                         }
+                        if args.iter().any(|arg| arg == &OPTION_ALLOW_MIPMAPS) {
+                            allow_mipmaps = true;
+                        }
                     }
                     "==" => {
                         op = ReftestOp::Equal;
                     }
                     "!=" => {
                         op = ReftestOp::NotEqual;
                     }
                     _ => {
@@ -262,16 +268,17 @@ impl ReftestManifest {
                             reference: dir.join(tokens[i + 1]),
                             font_render_mode,
                             max_difference: cmp::max(max_difference, options.allow_max_difference),
                             num_differences: cmp::max(max_count, options.allow_num_differences),
                             expected_draw_calls,
                             expected_alpha_targets,
                             expected_color_targets,
                             disable_dual_source_blending,
+                            allow_mipmaps,
                             zoom_factor,
                         });
 
                         break;
                     }
                 }
             }
         }
@@ -329,16 +336,22 @@ impl<'a> ReftestHarness<'a> {
         }
 
         failing.len()
     }
 
     fn run_reftest(&mut self, t: &Reftest) -> bool {
         println!("REFTEST {}", t);
 
+        self.wrench
+            .api
+            .send_debug_cmd(
+                DebugCommand::ClearCaches(ClearCache::all())
+            );
+
         self.wrench.set_page_zoom(ZoomFactor::new(t.zoom_factor));
 
         if t.disable_dual_source_blending {
             self.wrench
                 .api
                 .send_debug_cmd(
                     DebugCommand::EnableDualSourceBlending(false)
                 );
@@ -346,31 +359,33 @@ impl<'a> ReftestHarness<'a> {
 
         let window_size = self.window.get_inner_size();
         let reference = match t.reference.extension().unwrap().to_str().unwrap() {
             "yaml" => {
                 let (reference, _) = self.render_yaml(
                     t.reference.as_path(),
                     window_size,
                     t.font_render_mode,
+                    t.allow_mipmaps,
                 );
                 reference
             }
             "png" => {
                 self.load_image(t.reference.as_path(), ImageFormat::PNG)
             }
             other => panic!("Unknown reftest extension: {}", other),
         };
 
         // the reference can be smaller than the window size,
         // in which case we only compare the intersection
         let (test, stats) = self.render_yaml(
             t.test.as_path(),
             reference.size,
             t.font_render_mode,
+            t.allow_mipmaps,
         );
 
         if t.disable_dual_source_blending {
             self.wrench
                 .api
                 .send_debug_cmd(
                     DebugCommand::EnableDualSourceBlending(true)
                 );
@@ -459,19 +474,21 @@ impl<'a> ReftestHarness<'a> {
         }
     }
 
     fn render_yaml(
         &mut self,
         filename: &Path,
         size: DeviceUintSize,
         font_render_mode: Option<FontRenderMode>,
+        allow_mipmaps: bool,
     ) -> (ReftestImage, RendererStats) {
         let mut reader = YamlFrameReader::new(filename);
         reader.set_font_render_mode(font_render_mode);
+        reader.allow_mipmaps(allow_mipmaps);
         reader.do_frame(self.wrench);
 
         // wait for the frame
         self.rx.recv().unwrap();
         let stats = self.wrench.render();
 
         let window_size = self.window.get_inner_size();
         assert!(size.width <= window_size.width && size.height <= window_size.height);
--- a/gfx/wrench/src/wrench.rs
+++ b/gfx/wrench/src/wrench.rs
@@ -169,17 +169,16 @@ impl Wrench {
         window: &mut WindowWrapper,
         proxy: Option<EventsLoopProxy>,
         shader_override_path: Option<PathBuf>,
         dp_ratio: f32,
         save_type: Option<SaveType>,
         size: DeviceUintSize,
         do_rebuild: bool,
         no_subpixel_aa: bool,
-        debug: bool,
         verbose: bool,
         no_scissor: bool,
         no_batch: bool,
         precache_shaders: bool,
         disable_dual_source_blending: bool,
         zoom_factor: f32,
         notifier: Option<Box<RenderNotifier>>,
     ) -> Self {
@@ -202,17 +201,16 @@ impl Wrench {
         debug_flags.set(DebugFlags::DISABLE_BATCHING, no_batch);
         let callbacks = Arc::new(Mutex::new(blob::BlobCallbacks::new()));
 
         let opts = webrender::RendererOptions {
             device_pixel_ratio: dp_ratio,
             resource_override_path: shader_override_path,
             recorder,
             enable_subpixel_aa: !no_subpixel_aa,
-            debug,
             debug_flags,
             enable_clear_scissor: !no_scissor,
             max_recorded_profiles: 16,
             precache_shaders,
             blob_image_renderer: Some(Box::new(blob::CheckerboardRenderer::new(callbacks.clone()))),
             disable_dual_source_blending,
             ..Default::default()
         };
--- a/gfx/wrench/src/yaml_frame_reader.rs
+++ b/gfx/wrench/src/yaml_frame_reader.rs
@@ -99,17 +99,17 @@ fn generate_checkerboard_image(
                 pixels.push(value);
                 pixels.push(value);
                 pixels.push(0xff);
             }
         }
     }
 
     (
-        ImageDescriptor::new(width, height, ImageFormat::BGRA8, true),
+        ImageDescriptor::new(width, height, ImageFormat::BGRA8, true, false),
         ImageData::new(pixels),
     )
 }
 
 fn generate_xy_gradient_image(w: u32, h: u32) -> (ImageDescriptor, ImageData) {
     let mut pixels = Vec::with_capacity((w * h * 4) as usize);
     for y in 0 .. h {
         for x in 0 .. w {
@@ -117,17 +117,17 @@ fn generate_xy_gradient_image(w: u32, h:
             pixels.push((y as f32 / h as f32 * 255.0 * grid) as u8);
             pixels.push(0);
             pixels.push((x as f32 / w as f32 * 255.0 * grid) as u8);
             pixels.push(255);
         }
     }
 
     (
-        ImageDescriptor::new(w, h, ImageFormat::BGRA8, true),
+        ImageDescriptor::new(w, h, ImageFormat::BGRA8, true, false),
         ImageData::new(pixels),
     )
 }
 
 fn generate_solid_color_image(
     r: u8,
     g: u8,
     b: u8,
@@ -147,17 +147,17 @@ fn generate_solid_color_image(
         let end = ptr.offset((w * h) as isize);
         while ptr < end {
             *ptr = color;
             ptr = ptr.offset(1);
         }
     }
 
     (
-        ImageDescriptor::new(w, h, ImageFormat::BGRA8, a == 255),
+        ImageDescriptor::new(w, h, ImageFormat::BGRA8, a == 255, false),
         ImageData::new(pixels),
     )
 }
 
 
 
 fn is_image_opaque(format: ImageFormat, bytes: &[u8]) -> bool {
     match format {
@@ -195,16 +195,17 @@ pub struct YamlFrameReader {
     /// scroll layers should be initialized with.
     scroll_offsets: HashMap<ExternalScrollId, LayerPoint>,
 
     image_map: HashMap<(PathBuf, Option<i64>), (ImageKey, LayoutSize)>,
 
     fonts: HashMap<FontDescriptor, FontKey>,
     font_instances: HashMap<(FontKey, Au, FontInstanceFlags), FontInstanceKey>,
     font_render_mode: Option<FontRenderMode>,
+    allow_mipmaps: bool,
 
     /// A HashMap that allows specifying a numeric id for clip and clip chains in YAML
     /// and having each of those ids correspond to a unique ClipId.
     clip_id_map: HashMap<u64, ClipId>,
 }
 
 impl YamlFrameReader {
     pub fn new(yaml_path: &Path) -> YamlFrameReader {
@@ -219,16 +220,17 @@ impl YamlFrameReader {
             queue_depth: 1,
             include_only: vec![],
             scroll_offsets: HashMap::new(),
             fonts: HashMap::new(),
             font_instances: HashMap::new(),
             font_render_mode: None,
             image_map: HashMap::new(),
             clip_id_map: HashMap::new(),
+            allow_mipmaps: false,
         }
     }
 
     pub fn deinit(mut self, wrench: &mut Wrench) {
         let mut updates = ResourceUpdates::new();
 
         for (_, font_instance) in self.font_instances.drain() {
             updates.delete_font_instance(font_instance);
@@ -410,16 +412,17 @@ impl YamlFrameReader {
                     }
                     _ => panic!("We don't support whatever your crazy image type is, come on"),
                 };
                 let descriptor = ImageDescriptor::new(
                     image_dims.0,
                     image_dims.1,
                     format,
                     is_image_opaque(format, &bytes[..]),
+                    self.allow_mipmaps,
                 );
                 let data = ImageData::new(bytes);