Merge autoland to mozilla-central. a=merge
authorGurzau Raul <rgurzau@mozilla.com>
Fri, 13 Apr 2018 02:06:13 +0300
changeset 413044 46615d425bcb02f4b9b6ce530e0c34f3b582ac32
parent 413015 325ef357e5b73d63794e47c02c7f8e7cf58ccb48 (current diff)
parent 413043 9866b049f5d8658c5ccae89e6cdac8b3feb128a8 (diff)
child 413059 da809ecceaf3a8ada0aa2d7115822d39d0439654
push id33831
push userrgurzau@mozilla.com
push dateThu, 12 Apr 2018 23:07:19 +0000
treeherdermozilla-central@46615d425bcb [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
testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/masking/mask-clip-1.html.ini
testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-039.html.ini
testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-040.html.ini
testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-045.html.ini
testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-046.html.ini
testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-040.html.ini
testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-041.html.ini
testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-042.html.ini
testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-043.html.ini
testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-018.html.ini
testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-019.html.ini
--- a/.cargo/config.in
+++ b/.cargo/config.in
@@ -4,15 +4,15 @@
 # taskcluster/scripts/builder/build-sm-rust-bindings.sh
 
 [source.crates-io]
 registry = 'https://github.com/rust-lang/crates.io-index'
 replace-with = 'vendored-sources'
 
 [source."https://github.com/servo/serde"]
 git = "https://github.com/servo/serde"
-branch = "deserialize_from_enums5"
+branch = "deserialize_from_enums6"
 replace-with = "vendored-sources"
 
 [source.vendored-sources]
 directory = '@top_srcdir@/third_party/rust'
 
 @WIN64_CARGO_LINKER_CONFIG@
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -26,17 +26,17 @@ 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.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.37 (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 = [
  "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -84,18 +84,18 @@ dependencies = [
  "cubeb 0.5.2 (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)",
  "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
+ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.37 (git+https://github.com/servo/serde?branch=deserialize_from_enums6)",
  "tokio-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "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.4.0"
@@ -143,17 +143,17 @@ version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "bincode"
 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.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "bindgen"
 version = "0.33.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -559,18 +559,18 @@ source = "registry+https://github.com/ru
 
 [[package]]
 name = "docopt"
 version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "lazy_static 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)",
- "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
+ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.37 (git+https://github.com/servo/serde?branch=deserialize_from_enums6)",
  "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "dtoa"
 version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
@@ -586,18 +586,18 @@ dependencies = [
 name = "dwrote"
 version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
+ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.37 (git+https://github.com/servo/serde?branch=deserialize_from_enums6)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "either"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
@@ -650,17 +650,17 @@ 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.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "fallible"
 version = "0.0.1"
 dependencies = [
  "hashglobe 0.1.0",
  "smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -839,31 +839,30 @@ dependencies = [
  "rsdparsa_capi 0.1.0",
  "u2fhid 0.1.0",
  "webrender_bindings 0.1.0",
  "xpcom 0.1.0",
 ]
 
 [[package]]
 name = "gl_generator"
-version = "0.8.0"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "khronos_api 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "khronos_api 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gleam"
-version = "0.4.20"
+version = "0.4.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "gl_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "glob"
 version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -975,17 +974,17 @@ 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)",
  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "khronos_api"
-version = "2.0.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "lalrpop"
 version = "0.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "ascii-canvas 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -995,18 +994,18 @@ dependencies = [
  "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "ena 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "lalrpop-snap 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lalrpop-util 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "petgraph 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
+ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.37 (git+https://github.com/servo/serde?branch=deserialize_from_enums6)",
  "string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "lalrpop-intern"
 version = "0.15.1"
@@ -1661,17 +1660,17 @@ name = "regex-syntax"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "ron"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "rsdparsa"
 version = "0.1.0"
 
 [[package]]
 name = "rsdparsa_capi"
@@ -1750,48 +1749,48 @@ dependencies = [
 
 [[package]]
 name = "semver-parser"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "serde"
-version = "1.0.35"
+version = "1.0.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
+ "serde_derive 1.0.37 (git+https://github.com/servo/serde?branch=deserialize_from_enums6)",
 ]
 
 [[package]]
 name = "serde_bytes"
 version = "0.10.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.35"
-source = "git+https://github.com/servo/serde?branch=deserialize_from_enums5#de4534b21f263752ed3b641c3c07e012574985bf"
+version = "1.0.37"
+source = "git+https://github.com/servo/serde?branch=deserialize_from_enums6#b8d39b013bec85b6146dfb1061e0e8fc55e99b5e"
 dependencies = [
- "proc-macro2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive_internals 0.22.1 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
- "syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive_internals 0.23.0 (git+https://github.com/servo/serde?branch=deserialize_from_enums6)",
+ "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "serde_derive_internals"
-version = "0.22.1"
-source = "git+https://github.com/servo/serde?branch=deserialize_from_enums5#de4534b21f263752ed3b641c3c07e012574985bf"
+version = "0.23.0"
+source = "git+https://github.com/servo/serde?branch=deserialize_from_enums6#b8d39b013bec85b6146dfb1061e0e8fc55e99b5e"
 dependencies = [
- "proc-macro2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "servo_arc"
 version = "0.1.1"
 dependencies = [
  "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1835,17 +1834,17 @@ source = "registry+https://github.com/ru
 name = "string_cache"
 version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "string_cache_codegen"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2102,17 +2101,17 @@ dependencies = [
  "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "toml"
 version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "traitobject"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -2282,24 +2281,24 @@ dependencies = [
  "cfg-if 0.1.2 (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.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.4.32 (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.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.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.37 (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.2",
 ]
 
 [[package]]
 name = "webrender_api"
@@ -2308,33 +2307,33 @@ dependencies = [
  "app_units 0.6.0 (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.2 (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.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
+ "serde_derive 1.0.37 (git+https://github.com/servo/serde?branch=deserialize_from_enums6)",
  "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender_bindings"
 version = "0.1.0"
 dependencies = [
  "app_units 0.6.0 (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.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "gleam 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gleam 0.4.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webrender 0.57.2",
 ]
 
 [[package]]
 name = "which"
@@ -2531,31 +2530,31 @@ dependencies = [
 "checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866"
 "checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159"
 "checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82"
 "checksum futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0bab5b5e94f5c31fc764ba5dd9ad16568aae5d4825538c01d6bca680c9bf94a7"
 "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
 "checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
 "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
 "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
-"checksum gl_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f5c19cde55637681450c92f7a05ea16c78e2b6d0587e601ec1ebdab6960854b"
-"checksum gleam 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "959c818d9bbe9f7b7db55dce0bc44673c4da4f4ee122536c40550f984c3b8017"
+"checksum gl_generator 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a795170cbd85b5a7baa58d6d7525cae6a03e486859860c220f7ebbbdd379d0a"
+"checksum gleam 0.4.32 (registry+https://github.com/rust-lang/crates.io-index)" = "70363479f033b72dbd558fd3b6f153dd824bf4f9dcd05dfcff6cd29a3eb9a63d"
 "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
 "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07"
 "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
 "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2"
 "checksum ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9826188e666f2ed92071d2dadef6edc430b11b158b5b2b3f4babbcc891eaaa"
 "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
 "checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be"
 "checksum itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3f2be4da1690a039e9ae5fd575f706a63ad5a2120f161b1d653c9da3930dd21"
 "checksum itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b07332223953b5051bceb67e8c4700aa65291535568e1f12408c43c4a42c0394"
 "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c"
 "checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-"checksum khronos_api 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d867c645cfeb8a7fec503731679eac03ac11b7105aa5a71cb8f8ee5271636add"
+"checksum khronos_api 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "037ab472c33f67b5fbd3e9163a2645319e5356fcd355efa6d4eb7fff4bbcb554"
 "checksum lalrpop 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88035943c3cfbb897a499a556212b2b053574f32b4238b71b61625bc470f80aa"
 "checksum lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4fd87be4a815fd373e02773983940f0d75fb26fde8c098e9e45f7af03154c0"
 "checksum lalrpop-snap 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f244285324e4e33d486910b66fd3b7cb37e2072c5bf63319f506fe99ed72650"
 "checksum lalrpop-util 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "de408fd50dea8ad7a77107144983a25c7fdabf5f8faf707a6e020d68874ed06c"
 "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
 "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
 "checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
 "checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff"
@@ -2621,20 +2620,20 @@ dependencies = [
 "checksum rust-ini 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22dab655e8122ccb15db25a56852ce62506f1486cdefd37e86371bf34ea8f601"
 "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
 "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
 "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
 "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
 "checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918"
 "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
 "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"checksum serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "800fdb0a894572994f3970035a8a5f65d8ec2cd40e6cdf7d8cd9001d7b30648e"
+"checksum serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "d3bcee660dcde8f52c3765dd9ca5ee36b4bf35470a738eb0bd5a8752b0389645"
 "checksum serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3"
-"checksum serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)" = "<none>"
-"checksum serde_derive_internals 0.22.1 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)" = "<none>"
+"checksum serde_derive 1.0.37 (git+https://github.com/servo/serde?branch=deserialize_from_enums6)" = "<none>"
+"checksum serde_derive_internals 0.23.0 (git+https://github.com/servo/serde?branch=deserialize_from_enums6)" = "<none>"
 "checksum simd 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd0805c7363ab51a829a1511ad24b6ed0349feaa756c4bc2f977f9f496e6673"
 "checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
 "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
 "checksum smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "79b776f00dfe01df905fa3b2eaa1659522e99e3fc4a7b1334171622205c4bdcf"
 "checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9"
 "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
 "checksum string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39cb4173bcbd1319da31faa5468a7e3870683d7a237150b0b0aaafd546f6ad12"
 "checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7"
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -54,9 +54,9 @@ panic = "abort"
 opt-level = 2
 rpath = false
 debug-assertions = false
 panic = "abort"
 codegen-units = 1
 
 [patch.crates-io]
 libudev-sys = { path = "dom/webauthn/libudev-sys" }
-serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums5" }
+serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums6" }
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -432,17 +432,17 @@ PlacesViewBase.prototype = {
       aPopup._siteURIMenuitem = document.createElement("menuitem");
       aPopup._siteURIMenuitem.className = "openlivemarksite-menuitem";
       if (typeof this.options.extraClasses.entry == "string") {
         aPopup._siteURIMenuitem.classList.add(this.options.extraClasses.entry);
       }
       aPopup._siteURIMenuitem.setAttribute("targetURI", siteUrl);
       aPopup._siteURIMenuitem.setAttribute("oncommand",
         "openUILink(this.getAttribute('targetURI'), event, {" +
-        " triggeringPrincipal: Services.scriptSecurityManger.createNullPrincipal({})});");
+        " triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({})});");
 
       // If a user middle-clicks this item we serve the oncommand event.
       // We are using checkForMiddleClick because of Bug 246720.
       // Note: stopPropagation is needed to avoid serving middle-click
       // with BT_onClick that would open all items in tabs.
       aPopup._siteURIMenuitem.setAttribute("onclick",
         "checkForMiddleClick(this, event); event.stopPropagation();");
       let label =
--- a/devtools/client/preferences/devtools-client.js
+++ b/devtools/client/preferences/devtools-client.js
@@ -321,23 +321,17 @@ pref("devtools.netmonitor.persistlog", f
 pref("devtools.webconsole.timestampMessages", false);
 
 // Web Console automatic multiline mode: |true| if you want incomplete statements
 // to automatically trigger multiline editing (equivalent to shift + enter).
 pref("devtools.webconsole.autoMultiline", true);
 
 // Enable the new webconsole frontend
 pref("devtools.webconsole.new-frontend-enabled", true);
-
-// Enable the new webconsole frontend in the browser console
-#if defined(NIGHTLY_BUILD)
 pref("devtools.browserconsole.new-frontend-enabled", true);
-#else
-pref("devtools.browserconsole.new-frontend-enabled", false);
-#endif
 
 // Enable the webconsole sidebar toggle
 pref("devtools.webconsole.sidebarToggle", false);
 
 // Disable the new performance recording panel by default
 pref("devtools.performance.new-panel-enabled", false);
 
 // Enable client-side mapping service for source maps
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -47,16 +47,18 @@ skip-if = true # needed by test_enumerat
 skip-if = os == 'android'
 [test_getUserMedia_active_autoplay.html]
 [test_getUserMedia_audioCapture.html]
 skip-if = toolkit == 'android' # android(Bug 1189784, timeouts on 4.3 emulator), android(Bug 1264333)
 [test_getUserMedia_addTrackRemoveTrack.html]
 skip-if = android_version == '18' || os == 'linux' # android(Bug 1189784, timeouts on 4.3 emulator), linux bug 1377450
 [test_getUserMedia_addtrack_removetrack_events.html]
 skip-if = os == 'linux' && debug # Bug 1389983
+[test_getUserMedia_audioConstraints.html]
+skip-if = os == 'mac' || os == 'win' || toolkit == 'android' # Bug 1404995, no loopback devices on some platforms
 [test_getUserMedia_basicAudio_loopback.html]
 skip-if = os == 'mac' || os == 'win' || toolkit == 'android' # Bug 1404995, no loopback devices on some platforms
 [test_getUserMedia_basicAudio.html]
 [test_getUserMedia_basicVideo.html]
 [test_getUserMedia_basicVideo_playAfterLoadedmetadata.html]
 [test_getUserMedia_basicScreenshare.html]
 skip-if = toolkit == 'android' || (webrender && toolkit == 'windows') # no screenshare on android; bug 1405083 permafail on webrender
 [test_getUserMedia_basicTabshare.html]
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_getUserMedia_audioConstraints.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+"use strict";
+
+createHTML({
+  title: "Test that microphone getSettings report correct settings after applyConstraints",
+  bug: "1447982",
+});
+
+function testTrackAgainstAudioConstraints(track, audioConstraints) {
+  let constraints = track.getConstraints();
+  is(constraints.autoGainControl, audioConstraints.autoGainControl,
+     "Should report correct autoGainControl constraint");
+  is(constraints.echoCancellation, audioConstraints.echoCancellation,
+     "Should report correct echoCancellation constraint");
+  is(constraints.noiseSuppression, audioConstraints.noiseSuppression,
+     "Should report correct noiseSuppression constraint");
+
+  let settings = track.getSettings();
+  is(settings.autoGainControl, audioConstraints.autoGainControl,
+     "Should report correct autoGainControl setting");
+  is(settings.echoCancellation, audioConstraints.echoCancellation,
+     "Should report correct echoCancellation setting");
+  is(settings.noiseSuppression, audioConstraints.noiseSuppression,
+     "Should report correct noiseSuppression setting");
+}
+
+async function testAudioConstraints(track, audioConstraints) {
+  // We applyConstraints() first and do a fresh gUM later, to avoid
+  // testing multiple concurrent captures at different settings.
+
+  info(`Testing applying constraints ${JSON.stringify(audioConstraints)} ` +
+       `to track with settings ${JSON.stringify(track.getSettings())}`);
+  await track.applyConstraints(audioConstraints);
+  testTrackAgainstAudioConstraints(track, audioConstraints);
+
+  info("Testing fresh gUM request with audio constraints " +
+       JSON.stringify(audioConstraints));
+  let stream = await getUserMedia({audio: audioConstraints});
+  testTrackAgainstAudioConstraints(stream.getTracks()[0], audioConstraints);
+  stream.getTracks().forEach(t => t.stop());
+}
+
+runTest(async () => {
+  let audioDevice = SpecialPowers.getCharPref("media.audio_loopback_dev", "");
+  if (!audioDevice) {
+    ok(false, "No device set by framework. Try --use-test-media-devices");
+    return;
+  }
+
+  let supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
+  is(supportedConstraints.autoGainControl, true,
+     "autoGainControl constraint should be supported");
+  is(supportedConstraints.echoCancellation, true,
+     "echoCancellation constraint should be supported");
+  is(supportedConstraints.noiseSuppression, true,
+     "noiseSuppression constraint should be supported");
+
+  let egn = (e, g, n) => ({
+    echoCancellation: e,
+    autoGainControl: g,
+    noiseSuppression: n
+  });
+
+  let stream = await getUserMedia({
+    audio: egn(true, true, true),
+  });
+  let track = stream.getTracks()[0];
+  let audioConstraintsToTest = [
+    egn(false, true,  true),
+    egn(true,  false, true),
+    egn(true,  true,  false),
+    egn(false, false, true),
+    egn(false, true,  false),
+    egn(true,  false, false),
+    egn(false, false, false),
+    egn(true,  true,  true),
+  ];
+  for (let audioConstraints of audioConstraintsToTest) {
+    await testAudioConstraints(track, audioConstraints);
+  }
+  track.stop();
+});
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/webrtc/AllocationHandle.h
+++ b/dom/media/webrtc/AllocationHandle.h
@@ -39,27 +39,24 @@ public:
     return sId++;
   }
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AllocationHandle);
 
   AllocationHandle() = delete;
   AllocationHandle(const dom::MediaTrackConstraints& aConstraints,
                    const ipc::PrincipalInfo& aPrincipalInfo,
-                   const MediaEnginePrefs& aPrefs,
                    const nsString& aDeviceId)
     : mId(GetUniqueId())
     , mDeviceId(aDeviceId)
     , mPrincipalInfo(aPrincipalInfo)
     , mConstraints(aConstraints)
-    , mPrefs(aPrefs)
   {}
 
   const uint64_t mId;
   const nsString mDeviceId;
   const ipc::PrincipalInfo mPrincipalInfo;
   NormalizedConstraints mConstraints;
-  MediaEnginePrefs mPrefs;
 };
 
 } // namespace mozilla
 
 #endif // AllocationHandle_h
--- a/dom/media/webrtc/MediaEngineWebRTC.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTC.cpp
@@ -70,20 +70,17 @@ void AudioInputCubeb::UpdateDeviceList()
   // For some reason the "fake" device for automation is marked as DISABLED,
   // so white-list it.
   mDefaultDevice = -1;
   for (uint32_t i = 0; i < devices.count; i++) {
     LOG(("Cubeb device %u: type 0x%x, state 0x%x, name %s, id %p",
          i, devices.device[i].type, devices.device[i].state,
          devices.device[i].friendly_name, devices.device[i].device_id));
     if (devices.device[i].type == CUBEB_DEVICE_TYPE_INPUT && // paranoia
-        (devices.device[i].state == CUBEB_DEVICE_STATE_ENABLED ||
-         (devices.device[i].state == CUBEB_DEVICE_STATE_DISABLED &&
-          devices.device[i].friendly_name &&
-          strcmp(devices.device[i].friendly_name, "Sine source at 440 Hz") == 0)))
+        devices.device[i].state == CUBEB_DEVICE_STATE_ENABLED )
     {
       auto j = mDeviceNames->IndexOf(devices.device[i].device_id);
       if (j != nsTArray<nsCString>::NoIndex) {
         // match! update the mapping
         (*mDeviceIndexes)[j] = i;
       } else {
         // new device, add to the array
         mDeviceIndexes->AppendElement(i);
--- a/dom/media/webrtc/MediaEngineWebRTC.h
+++ b/dom/media/webrtc/MediaEngineWebRTC.h
@@ -528,17 +528,18 @@ private:
                               const nsString& aDeviceId,
                               const char** aOutBadConstraint);
 
 
   void UpdateAECSettingsIfNeeded(bool aEnable, webrtc::EcModes aMode);
   void UpdateAGCSettingsIfNeeded(bool aEnable, webrtc::AgcModes aMode);
   void UpdateNSSettingsIfNeeded(bool aEnable, webrtc::NsModes aMode);
 
-  void ApplySettings(const MediaEnginePrefs& aPrefs);
+  void ApplySettings(const MediaEnginePrefs& aPrefs,
+                     RefPtr<MediaStreamGraphImpl> aGraph);
 
   bool HasEnabledTrack() const;
 
   template<typename T>
   void InsertInGraph(const T* aBuffer,
                      size_t aFrames,
                      uint32_t aChannels);
 
@@ -598,19 +599,21 @@ private:
   uint64_t mLastLogFrames;
 
   // mSkipProcessing is true if none of the processing passes are enabled,
   // because of prefs or constraints. This allows simply copying the audio into
   // the MSG, skipping resampling and the whole webrtc.org code.
   // This is read and written to only on the MSG thread.
   bool mSkipProcessing;
 
-  // To only update microphone when needed, we keep track of previous settings.
+  // To only update microphone when needed, we keep track of the prefs
+  // representing the currently applied settings for this source. This is the
+  // net result of the prefs across all allocations.
   // Owning thread only.
-  MediaEnginePrefs mLastPrefs;
+  MediaEnginePrefs mNetPrefs;
 
   // Stores the mixed audio output for the reverse-stream of the AEC.
   AlignedFloatBuffer mOutputBuffer;
 
   AlignedFloatBuffer mInputBuffer;
   AlignedFloatBuffer mDeinterleavedBuffer;
   AlignedFloatBuffer mInputDownmixBuffer;
 };
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -243,16 +243,20 @@ MediaEngineWebRTCMicrophoneSource::Recon
     nsAutoCString name;
     GetErrorName(rv, name);
     LOG(("Mic source %p Reconfigure() failed unexpectedly. rv=%s",
          this, name.Data()));
     Stop(aHandle);
     return NS_ERROR_UNEXPECTED;
   }
 
+  size_t i = mAllocations.IndexOf(aHandle, 0, AllocationHandleComparator());
+  MOZ_DIAGNOSTIC_ASSERT(i != mAllocations.NoIndex);
+  ApplySettings(mNetPrefs, mAllocations[i].mStream->GraphImpl());
+
   return NS_OK;
 }
 
 bool operator == (const MediaEnginePrefs& a, const MediaEnginePrefs& b)
 {
   return !memcmp(&a, &b, sizeof(MediaEnginePrefs));
 };
 
@@ -461,92 +465,80 @@ MediaEngineWebRTCMicrophoneSource::Updat
         uint32_t channelCount = 0;
         mAudioInput->GetChannelCount(channelCount);
         MOZ_ASSERT(channelCount > 0);
         prefs.mChannels = channelCount;
       }
       break;
 
     case kStarted:
-      if (prefs == mLastPrefs) {
-        return NS_OK;
-      }
-
-      if (prefs.mChannels != mLastPrefs.mChannels) {
+    case kStopped:
+      if (prefs.mChannels != mNetPrefs.mChannels) {
         // If the channel count changed, tell the MSG to open a new driver with
         // the correct channel count.
         MOZ_ASSERT(!mAllocations.IsEmpty());
         RefPtr<SourceMediaStream> stream;
         for (const Allocation& allocation : mAllocations) {
-          if (allocation.mStream) {
+          if (allocation.mStream && allocation.mStream->GraphImpl()) {
             stream = allocation.mStream;
             break;
           }
         }
         MOZ_ASSERT(stream);
 
         mAudioInput->SetUserChannelCount(prefs.mChannels);
         // Get validated number of channel
         uint32_t channelCount = 0;
         mAudioInput->GetChannelCount(channelCount);
-        MOZ_ASSERT(channelCount > 0 && mLastPrefs.mChannels > 0);
-        if (mLastPrefs.mChannels != prefs.mChannels &&
-            !stream->OpenNewAudioCallbackDriver(mListener)) {
+        MOZ_ASSERT(channelCount > 0 && mNetPrefs.mChannels > 0);
+        if (!stream->OpenNewAudioCallbackDriver(mListener)) {
           MOZ_LOG(GetMediaManagerLog(), LogLevel::Error, ("Could not open a new AudioCallbackDriver for input"));
           return NS_ERROR_FAILURE;
         }
       }
-
-      if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) {
-        if (mAllocations.IsEmpty()) {
-          LOG(("Audio device %d reallocated", mCapIndex));
-        } else {
-          LOG(("Audio device %d allocated shared", mCapIndex));
-        }
-      }
       break;
 
     default:
       LOG(("Audio device %d in ignored state %d", mCapIndex, mState));
       break;
   }
 
+  if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) {
+    if (mAllocations.IsEmpty()) {
+      LOG(("Audio device %d reallocated", mCapIndex));
+    } else {
+      LOG(("Audio device %d allocated shared", mCapIndex));
+    }
+  }
+
   if (sChannelsOpen > 0) {
     UpdateAGCSettingsIfNeeded(prefs.mAgcOn, static_cast<AgcModes>(prefs.mAgc));
     UpdateNSSettingsIfNeeded(prefs.mNoiseOn, static_cast<NsModes>(prefs.mNoise));
     UpdateAECSettingsIfNeeded(prefs.mAecOn, static_cast<EcModes>(prefs.mAec));
 
     webrtc::Config config;
     config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(mExtendedFilter));
     config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(mDelayAgnostic));
     mAudioProcessing->SetExtraOptions(config);
   }
-  mLastPrefs = prefs;
+  mNetPrefs = prefs;
   return NS_OK;
 }
 
 #undef HANDLE_APM_ERROR
 
 void
-MediaEngineWebRTCMicrophoneSource::ApplySettings(const MediaEnginePrefs& aPrefs)
+MediaEngineWebRTCMicrophoneSource::ApplySettings(const MediaEnginePrefs& aPrefs,
+                                                 RefPtr<MediaStreamGraphImpl> aGraph)
 {
   AssertIsOnOwningThread();
-
-  mLastPrefs = aPrefs;
+  MOZ_DIAGNOSTIC_ASSERT(aGraph);
 
   RefPtr<MediaEngineWebRTCMicrophoneSource> that = this;
-  RefPtr<MediaStreamGraphImpl> graph;
-  for (const Allocation& allocation : mAllocations) {
-    if (allocation.mStream && allocation.mStream->GraphImpl()) {
-      graph = allocation.mStream->GraphImpl();
-      break;
-    }
-  }
-  MOZ_DIAGNOSTIC_ASSERT(graph);
-  NS_DispatchToMainThread(media::NewRunnableFrom([that, graph, aPrefs]() mutable {
+  NS_DispatchToMainThread(media::NewRunnableFrom([that, graph = Move(aGraph), aPrefs]() mutable {
     that->mSettings->mEchoCancellation.Value() = aPrefs.mAecOn;
     that->mSettings->mAutoGainControl.Value() = aPrefs.mAgcOn;
     that->mSettings->mNoiseSuppression.Value() = aPrefs.mNoiseOn;
     that->mSettings->mChannelCount.Value() = aPrefs.mChannels;
 
     class Message : public ControlMessage {
     public:
       Message(MediaEngineWebRTCMicrophoneSource* aSource,
@@ -581,17 +573,17 @@ MediaEngineWebRTCMicrophoneSource::Alloc
                                             const nsString& aDeviceId,
                                             const ipc::PrincipalInfo& aPrincipalInfo,
                                             AllocationHandle** aOutHandle,
                                             const char** aOutBadConstraint)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aOutHandle);
   auto handle = MakeRefPtr<AllocationHandle>(aConstraints, aPrincipalInfo,
-                                             aPrefs, aDeviceId);
+                                             aDeviceId);
 
   LOG(("Mic source %p allocation %p Allocate()", this, handle.get()));
 
   nsresult rv = ReevaluateAllocation(handle, nullptr, aPrefs, aDeviceId,
                                      aOutBadConstraint);
   if (NS_FAILED(rv)) {
     return rv;
   }
@@ -729,17 +721,17 @@ MediaEngineWebRTCMicrophoneSource::Start
 
     // Must be *before* StartSend() so it will notice we selected external input (full_duplex)
     mAudioInput->StartRecording(allocation.mStream, mListener);
 
     MOZ_ASSERT(mState != kReleased);
     mState = kStarted;
   }
 
-  ApplySettings(mLastPrefs);
+  ApplySettings(mNetPrefs, allocation.mStream->GraphImpl());
 
   return NS_OK;
 }
 
 nsresult
 MediaEngineWebRTCMicrophoneSource::Stop(const RefPtr<const AllocationHandle>& aHandle)
 {
   AssertIsOnOwningThread();
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -314,16 +314,17 @@ AsyncImagePipelineManager::ApplyAsyncIma
     wr::DisplayListBuilder builder(pipelineId, contentSize);
 
     MOZ_ASSERT(!keys.IsEmpty());
     MOZ_ASSERT(pipeline->mCurrentTexture.get());
 
     float opacity = 1.0f;
     builder.PushStackingContext(wr::ToLayoutRect(pipeline->mScBounds),
                                 nullptr,
+                                nullptr,
                                 &opacity,
                                 pipeline->mScTransform.IsIdentity() ? nullptr : &pipeline->mScTransform,
                                 wr::TransformStyle::Flat,
                                 nullptr,
                                 pipeline->mMixBlendMode,
                                 nsTArray<wr::WrFilterOp>(),
                                 true);
 
--- a/gfx/layers/wr/StackingContextHelper.cpp
+++ b/gfx/layers/wr/StackingContextHelper.cpp
@@ -48,16 +48,17 @@ StackingContextHelper::StackingContextHe
     mInheritedTransform = transform2d * aParentSC.mInheritedTransform;
     mScale = mInheritedTransform.ScaleFactors(true);
   } else {
     mInheritedTransform = aParentSC.mInheritedTransform;
     mScale = aParentSC.mScale;
   }
 
   mBuilder->PushStackingContext(wr::ToLayoutRect(aBounds),
+                                nullptr,
                                 aAnimation,
                                 aOpacityPtr,
                                 aTransformPtr,
                                 aIsPreserve3D ? wr::TransformStyle::Preserve3D : wr::TransformStyle::Flat,
                                 aPerspectivePtr,
                                 wr::ToMixBlendMode(aMixBlendMode),
                                 aFilters,
                                 aBackfaceVisible);
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -357,17 +357,16 @@ struct DIGroup
     if (!aData->mGeometry) {
       // This item is being added for the first time, invalidate its entire area.
       UniquePtr<nsDisplayItemGeometry> geometry(aItem->AllocateGeometry(aBuilder));
       combined = clip.ApplyNonRoundedIntersection(geometry->ComputeInvalidationRegion());
       aData->mGeometry = Move(geometry);
       nsRect bounds = combined.GetBounds();
 
       IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mGroupOffset);
-      ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mGroupOffset);
       aData->mRect = transformedRect.Intersect(imageRect);
       GP("CGC %s %d %d %d %d\n", aItem->Name(), bounds.x, bounds.y, bounds.width, bounds.height);
       GP("%d %d,  %f %f\n", mGroupOffset.x, mGroupOffset.y, aMatrix._11, aMatrix._22);
       GP("mRect %d %d %d %d\n", aData->mRect.x, aData->mRect.y, aData->mRect.width, aData->mRect.height);
       InvalidateRect(aData->mRect);
       aData->mInvalid = true;
     } else if (/*aData->mIsInvalid || XXX: handle image load invalidation */ (aItem->IsInvalid(invalid) && invalid.IsEmpty())) {
       MOZ_RELEASE_ASSERT(imageRect.IsEqualEdges(aData->mImageRect));
--- a/gfx/webrender/Cargo.toml
+++ b/gfx/webrender/Cargo.toml
@@ -17,17 +17,17 @@ debug_renderer = []
 pathfinder = ["pathfinder_font_renderer", "pathfinder_gfx_utils", "pathfinder_partitioner", "pathfinder_path_utils"]
 
 [dependencies]
 app_units = "0.6"
 byteorder = "1.0"
 bincode = "1.0"
 euclid = "0.17"
 fxhash = "0.2.1"
-gleam = "0.4.20"
+gleam = "0.4.32"
 lazy_static = "1"
 log = "0.4"
 num-traits = "0.1.43"
 time = "0.1"
 rayon = "1"
 webrender_api = {path = "../webrender_api"}
 bitflags = "1.0"
 thread_profiler = "0.1.1"
--- a/gfx/webrender/examples/common/boilerplate.rs
+++ b/gfx/webrender/examples/common/boilerplate.rs
@@ -137,16 +137,17 @@ pub fn main_wrapper<E: Example>(
 
     println!("Loading shaders...");
     let opts = webrender::RendererOptions {
         resource_override_path: res_path,
         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,
+        debug_flags: webrender::DebugFlags::ECHO_DRIVER_MESSAGES,
         ..options.unwrap_or(webrender::RendererOptions::default())
     };
 
     let framebuffer_size = {
         let (width, height) = window.get_inner_size().unwrap();
         DeviceUintSize::new(width, height)
     };
     let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
--- a/gfx/webrender/src/batch.rs
+++ b/gfx/webrender/src/batch.rs
@@ -970,33 +970,27 @@ impl AlphaBatchBuilder {
                         }
                     }
                 }
             }
             PrimitiveKind::Border => {
                 let border_cpu =
                     &ctx.prim_store.cpu_borders[prim_metadata.cpu_prim_index.0];
                 // TODO(gw): Select correct blend mode for edges and corners!!
-                let corner_kind = BatchKind::Transformable(
-                    transform_kind,
-                    TransformBatchKind::BorderCorner,
-                );
-                let corner_key = BatchKey::new(corner_kind, non_segmented_blend_mode, no_textures);
-                let edge_kind = BatchKind::Transformable(
-                    transform_kind,
-                    TransformBatchKind::BorderEdge,
-                );
-                let edge_key = BatchKey::new(edge_kind, non_segmented_blend_mode, no_textures);
 
-                // Work around borrow ck on borrowing batch_list twice.
-                {
-                    let batch =
-                        self.batch_list.get_suitable_batch(corner_key, &task_relative_bounding_rect);
-                    for (i, instance_kind) in border_cpu.corner_instances.iter().enumerate()
-                    {
+                if border_cpu.corner_instances.iter().any(|&kind| kind != BorderCornerInstance::None) {
+                    let corner_kind = BatchKind::Transformable(
+                        transform_kind,
+                        TransformBatchKind::BorderCorner,
+                    );
+                    let corner_key = BatchKey::new(corner_kind, non_segmented_blend_mode, no_textures);
+                    let batch = self.batch_list
+                        .get_suitable_batch(corner_key, &task_relative_bounding_rect);
+
+                    for (i, instance_kind) in border_cpu.corner_instances.iter().enumerate() {
                         let sub_index = i as i32;
                         match *instance_kind {
                             BorderCornerInstance::None => {}
                             BorderCornerInstance::Single => {
                                 batch.push(base_instance.build(
                                     sub_index,
                                     BorderCornerSide::Both as i32,
                                     0,
@@ -1013,22 +1007,32 @@ impl AlphaBatchBuilder {
                                     BorderCornerSide::Second as i32,
                                     0,
                                 ));
                             }
                         }
                     }
                 }
 
-                let batch = self.batch_list.get_suitable_batch(edge_key, &task_relative_bounding_rect);
-                for (border_segment, instance_kind) in border_cpu.edges.iter().enumerate() {
-                    match *instance_kind {
-                        BorderEdgeKind::None => {},
-                        _ => {
-                          batch.push(base_instance.build(border_segment as i32, 0, 0));
+                if border_cpu.edges.iter().any(|&kind| kind != BorderEdgeKind::None) {
+                    let edge_kind = BatchKind::Transformable(
+                        transform_kind,
+                        TransformBatchKind::BorderEdge,
+                    );
+                    let edge_key = BatchKey::new(edge_kind, non_segmented_blend_mode, no_textures);
+                    let batch = self.batch_list
+                        .get_suitable_batch(edge_key, &task_relative_bounding_rect);
+
+                    for (border_segment, instance_kind) in border_cpu.edges.iter().enumerate() {
+                        match *instance_kind {
+                            BorderEdgeKind::None => {},
+                            BorderEdgeKind::Solid |
+                            BorderEdgeKind::Clip => {
+                                batch.push(base_instance.build(border_segment as i32, 0, 0));
+                            }
                         }
                     }
                 }
             }
             PrimitiveKind::Image => {
                 let image_cpu = &ctx.prim_store.cpu_images[prim_metadata.cpu_prim_index.0];
 
                 let cache_item = match image_cpu.source {
--- a/gfx/webrender/src/border.rs
+++ b/gfx/webrender/src/border.rs
@@ -98,144 +98,126 @@ impl BorderCornerKind {
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum BorderEdgeKind {
     None,
     Solid,
     Clip,
 }
 
-trait NormalBorderHelpers {
-    fn get_corner(
-        &self,
-        edge0: &BorderSide,
-        width0: f32,
-        edge1: &BorderSide,
-        width1: f32,
-        radius: &LayerSize,
-        corner: BorderCorner,
-        border_rect: &LayerRect,
-    ) -> BorderCornerKind;
-
-    fn get_edge(&self, edge: &BorderSide, width: f32) -> (BorderEdgeKind, f32);
-}
+fn get_corner(
+    edge0: &BorderSide,
+    width0: f32,
+    edge1: &BorderSide,
+    width1: f32,
+    radius: &LayerSize,
+    corner: BorderCorner,
+    border_rect: &LayerRect,
+) -> BorderCornerKind {
+    // If both widths are zero, a corner isn't formed.
+    if width0 == 0.0 && width1 == 0.0 {
+        return BorderCornerKind::None;
+    }
 
-impl NormalBorderHelpers for NormalBorder {
-    fn get_corner(
-        &self,
-        edge0: &BorderSide,
-        width0: f32,
-        edge1: &BorderSide,
-        width1: f32,
-        radius: &LayerSize,
-        corner: BorderCorner,
-        border_rect: &LayerRect,
-    ) -> BorderCornerKind {
-        // If both widths are zero, a corner isn't formed.
-        if width0 == 0.0 && width1 == 0.0 {
-            return BorderCornerKind::None;
+    // If both edges are transparent, no corner is formed.
+    if edge0.color.a == 0.0 && edge1.color.a == 0.0 {
+        return BorderCornerKind::None;
+    }
+
+    match (edge0.style, edge1.style) {
+        // If both edges are none or hidden, no corner is needed.
+        (BorderStyle::None, BorderStyle::None) |
+        (BorderStyle::None, BorderStyle::Hidden) |
+        (BorderStyle::Hidden, BorderStyle::None) |
+        (BorderStyle::Hidden, BorderStyle::Hidden) => {
+            BorderCornerKind::None
         }
 
-        // If both edges are transparent, no corner is formed.
-        if edge0.color.a == 0.0 && edge1.color.a == 0.0 {
-            return BorderCornerKind::None;
+        // If one of the edges is none or hidden, we just draw one style.
+        (BorderStyle::None, _) |
+        (_, BorderStyle::None) |
+        (BorderStyle::Hidden, _) |
+        (_, BorderStyle::Hidden) => {
+            BorderCornerKind::Clip(BorderCornerInstance::Single)
         }
 
-        match (edge0.style, edge1.style) {
-            // If both edges are none or hidden, no corner is needed.
-            (BorderStyle::None, BorderStyle::None) |
-            (BorderStyle::None, BorderStyle::Hidden) |
-            (BorderStyle::Hidden, BorderStyle::None) |
-            (BorderStyle::Hidden, BorderStyle::Hidden) => {
-                BorderCornerKind::None
-            }
-
-            // If one of the edges is none or hidden, we just draw one style.
-            (BorderStyle::None, _) |
-            (_, BorderStyle::None) |
-            (BorderStyle::Hidden, _) |
-            (_, BorderStyle::Hidden) => {
+        // If both borders are solid, we can draw them with a simple rectangle if
+        // both the colors match and there is no radius.
+        (BorderStyle::Solid, BorderStyle::Solid) => {
+            if edge0.color == edge1.color && radius.width == 0.0 && radius.height == 0.0 {
+                BorderCornerKind::Solid
+            } else {
                 BorderCornerKind::Clip(BorderCornerInstance::Single)
             }
+        }
 
-            // If both borders are solid, we can draw them with a simple rectangle if
-            // both the colors match and there is no radius.
-            (BorderStyle::Solid, BorderStyle::Solid) => {
-                if edge0.color == edge1.color && radius.width == 0.0 && radius.height == 0.0 {
-                    BorderCornerKind::Solid
-                } else {
-                    BorderCornerKind::Clip(BorderCornerInstance::Single)
-                }
-            }
-
-            // Inset / outset borders just modify the color of edges, so can be
-            // drawn with the normal border corner shader.
-            (BorderStyle::Outset, BorderStyle::Outset) |
-            (BorderStyle::Inset, BorderStyle::Inset) |
-            (BorderStyle::Double, BorderStyle::Double) |
-            (BorderStyle::Groove, BorderStyle::Groove) |
-            (BorderStyle::Ridge, BorderStyle::Ridge) => {
-                BorderCornerKind::Clip(BorderCornerInstance::Single)
-            }
+        // Inset / outset borders just modify the color of edges, so can be
+        // drawn with the normal border corner shader.
+        (BorderStyle::Outset, BorderStyle::Outset) |
+        (BorderStyle::Inset, BorderStyle::Inset) |
+        (BorderStyle::Double, BorderStyle::Double) |
+        (BorderStyle::Groove, BorderStyle::Groove) |
+        (BorderStyle::Ridge, BorderStyle::Ridge) => {
+            BorderCornerKind::Clip(BorderCornerInstance::Single)
+        }
 
-            // Dashed and dotted border corners get drawn into a clip mask.
-            (BorderStyle::Dashed, BorderStyle::Dashed) => BorderCornerKind::new_mask(
-                BorderCornerClipKind::Dash,
-                width0,
-                width1,
-                corner,
-                *radius,
-                *border_rect,
-            ),
-            (BorderStyle::Dotted, BorderStyle::Dotted) => BorderCornerKind::new_mask(
-                BorderCornerClipKind::Dot,
-                width0,
-                width1,
-                corner,
-                *radius,
-                *border_rect,
-            ),
+        // Dashed and dotted border corners get drawn into a clip mask.
+        (BorderStyle::Dashed, BorderStyle::Dashed) => BorderCornerKind::new_mask(
+            BorderCornerClipKind::Dash,
+            width0,
+            width1,
+            corner,
+            *radius,
+            *border_rect,
+        ),
+        (BorderStyle::Dotted, BorderStyle::Dotted) => BorderCornerKind::new_mask(
+            BorderCornerClipKind::Dot,
+            width0,
+            width1,
+            corner,
+            *radius,
+            *border_rect,
+        ),
 
-            // Draw border transitions with dots and/or dashes as
-            // solid segments. The old border path didn't support
-            // this anyway, so we might as well start using the new
-            // border path here, since the dashing in the edges is
-            // much higher quality anyway.
-            (BorderStyle::Dotted, _) |
-            (_, BorderStyle::Dotted) |
-            (BorderStyle::Dashed, _) |
-            (_, BorderStyle::Dashed) => BorderCornerKind::Clip(BorderCornerInstance::Single),
+        // Draw border transitions with dots and/or dashes as
+        // solid segments. The old border path didn't support
+        // this anyway, so we might as well start using the new
+        // border path here, since the dashing in the edges is
+        // much higher quality anyway.
+        (BorderStyle::Dotted, _) |
+        (_, BorderStyle::Dotted) |
+        (BorderStyle::Dashed, _) |
+        (_, BorderStyle::Dashed) => BorderCornerKind::Clip(BorderCornerInstance::Single),
 
-            // Everything else can be handled by drawing the corner twice,
-            // where the shader outputs zero alpha for the side it's not
-            // drawing. This is somewhat inefficient in terms of pixels
-            // written, but it's a fairly rare case, and we can optimize
-            // this case later.
-            _ => BorderCornerKind::Clip(BorderCornerInstance::Double),
-        }
+        // Everything else can be handled by drawing the corner twice,
+        // where the shader outputs zero alpha for the side it's not
+        // drawing. This is somewhat inefficient in terms of pixels
+        // written, but it's a fairly rare case, and we can optimize
+        // this case later.
+        _ => BorderCornerKind::Clip(BorderCornerInstance::Double),
+    }
+}
+
+fn get_edge(edge: &BorderSide, width: f32, height: f32) -> (BorderEdgeKind, f32) {
+    if width == 0.0 || height <= 0.0 {
+        return (BorderEdgeKind::None, 0.0);
     }
 
-    fn get_edge(&self, edge: &BorderSide, width: f32) -> (BorderEdgeKind, f32) {
-        if width == 0.0 {
-            return (BorderEdgeKind::None, 0.0);
+    match edge.style {
+        BorderStyle::None | BorderStyle::Hidden => (BorderEdgeKind::None, 0.0),
+
+        BorderStyle::Solid | BorderStyle::Inset | BorderStyle::Outset => {
+            (BorderEdgeKind::Solid, width)
         }
 
-        match edge.style {
-            BorderStyle::None | BorderStyle::Hidden => (BorderEdgeKind::None, 0.0),
-
-            BorderStyle::Solid | BorderStyle::Inset | BorderStyle::Outset => {
-                (BorderEdgeKind::Solid, width)
-            }
-
-            BorderStyle::Double |
-            BorderStyle::Groove |
-            BorderStyle::Ridge |
-            BorderStyle::Dashed |
-            BorderStyle::Dotted => (BorderEdgeKind::Clip, width),
-        }
+        BorderStyle::Double |
+        BorderStyle::Groove |
+        BorderStyle::Ridge |
+        BorderStyle::Dashed |
+        BorderStyle::Dotted => (BorderEdgeKind::Clip, width),
     }
 }
 
 pub fn ensure_no_corner_overlap(
     radius: &mut BorderRadius,
     rect: &LayerRect,
 ) {
     let mut ratio = 1.0;
@@ -426,58 +408,62 @@ impl<'a> DisplayListFlattener<'a> {
                 None,
                 extra_clips,
             );
 
             return;
         }
 
         let corners = [
-            border.get_corner(
+            get_corner(
                 left,
                 widths.left,
                 top,
                 widths.top,
                 &radius.top_left,
                 BorderCorner::TopLeft,
                 &info.rect,
             ),
-            border.get_corner(
+            get_corner(
                 right,
                 widths.right,
                 top,
                 widths.top,
                 &radius.top_right,
                 BorderCorner::TopRight,
                 &info.rect,
             ),
-            border.get_corner(
+            get_corner(
                 right,
                 widths.right,
                 bottom,
                 widths.bottom,
                 &radius.bottom_right,
                 BorderCorner::BottomRight,
                 &info.rect,
             ),
-            border.get_corner(
+            get_corner(
                 left,
                 widths.left,
                 bottom,
                 widths.bottom,
                 &radius.bottom_left,
                 BorderCorner::BottomLeft,
                 &info.rect,
             ),
         ];
 
-        let (left_edge, left_len) = border.get_edge(left, widths.left);
-        let (top_edge, top_len) = border.get_edge(top, widths.top);
-        let (right_edge, right_len) = border.get_edge(right, widths.right);
-        let (bottom_edge, bottom_len) = border.get_edge(bottom, widths.bottom);
+        let (left_edge, left_len) = get_edge(left, widths.left,
+            info.rect.size.height - radius.top_left.height - radius.bottom_left.height);
+        let (top_edge, top_len) = get_edge(top, widths.top,
+            info.rect.size.width - radius.top_left.width - radius.top_right.width);
+        let (right_edge, right_len) = get_edge(right, widths.right,
+            info.rect.size.height - radius.top_right.height - radius.bottom_right.height);
+        let (bottom_edge, bottom_len) = get_edge(bottom, widths.bottom,
+            info.rect.size.width - radius.bottom_right.width - radius.bottom_left.width);
 
         let edges = [left_edge, top_edge, right_edge, bottom_edge];
 
         // Use a simple rectangle case when all edges and corners are either
         // solid or none.
         let all_corners_simple = corners.iter().all(|c| {
             *c == BorderCornerKind::Solid || *c == BorderCornerKind::None
         });
--- a/gfx/webrender/src/debug_server.rs
+++ b/gfx/webrender/src/debug_server.rs
@@ -58,17 +58,17 @@ impl ws::Handler for Server {
                     "enable_gpu_sample_queries" => DebugCommand::EnableGpuSampleQueries(true),
                     "disable_gpu_sample_queries" => DebugCommand::EnableGpuSampleQueries(false),
                     "fetch_passes" => DebugCommand::FetchPasses,
                     "fetch_screenshot" => DebugCommand::FetchScreenshot,
                     "fetch_documents" => DebugCommand::FetchDocuments,
                     "fetch_clip_scroll_tree" => DebugCommand::FetchClipScrollTree,
                     "fetch_render_tasks" => DebugCommand::FetchRenderTasks,
                     msg => {
-                        println!("unknown msg {}", msg);
+                        error!("unknown msg {}", msg);
                         return Ok(());
                     }
                 };
 
                 let msg = ApiMsg::DebugCommand(cmd);
                 self.api_tx.send(msg).unwrap();
             }
             ws::Message::Binary(..) => {}
@@ -100,19 +100,19 @@ impl DebugServer {
                 }
             })
             .unwrap();
 
         let broadcaster = socket.broadcaster();
 
         let join_handle = Some(thread::spawn(move || {
             let address = "127.0.0.1:3583";
-            println!("WebRender debug server started: {}", address);
+            debug!("WebRender debug server started: {}", address);
             if let Err(..) = socket.listen(address) {
-                println!("ERROR: Unable to bind debugger websocket (port may be in use).");
+                error!("ERROR: Unable to bind debugger websocket (port may be in use).");
             }
         }));
 
         DebugServer {
             join_handle,
             broadcaster,
             debug_rx,
             senders: Vec::new(),
--- a/gfx/webrender/src/device.rs
+++ b/gfx/webrender/src/device.rs
@@ -6,16 +6,17 @@ use super::shader_source;
 use api::{ColorF, ImageFormat};
 use api::{DeviceIntPoint, DeviceIntRect, DeviceUintRect, DeviceUintSize};
 use api::TextureTarget;
 #[cfg(any(feature = "debug_renderer", feature="capture"))]
 use api::ImageDescriptor;
 use euclid::Transform3D;
 use gleam::gl;
 use internal_types::{FastHashMap, RenderTargetInfo};
+use log::Level;
 use smallvec::SmallVec;
 use std::cell::RefCell;
 use std::fs::File;
 use std::io::Read;
 use std::marker::PhantomData;
 use std::mem;
 use std::ops::Add;
 use std::path::PathBuf;
@@ -782,39 +783,39 @@ impl Device {
             Some(pos) => 2 + pos,
             None => return,
         };
         let base_line_number = match log[2 .. end_pos].parse::<usize>() {
             Ok(number) if number >= 2 => number - 2,
             _ => return,
         };
         for (line, prefix) in source.lines().skip(base_line_number).zip(&["|",">","|"]) {
-            println!("{}\t{}", prefix, line);
+            error!("{}\t{}", prefix, line);
         }
     }
 
     pub fn compile_shader(
         gl: &gl::Gl,
         name: &str,
         shader_type: gl::GLenum,
         source: &String,
     ) -> Result<gl::GLuint, ShaderError> {
         debug!("compile {}", name);
         let id = gl.create_shader(shader_type);
         gl.shader_source(id, &[source.as_bytes()]);
         gl.compile_shader(id);
         let log = gl.get_shader_info_log(id);
         if gl.get_shader_iv(id, gl::COMPILE_STATUS) == (0 as gl::GLint) {
-            println!("Failed to compile shader: {}\n{}", name, log);
+            error!("Failed to compile shader: {}\n{}", name, log);
             #[cfg(debug_assertions)]
             Self::print_shader_errors(source, &log);
             Err(ShaderError::Compilation(name.to_string(), log))
         } else {
             if !log.is_empty() {
-                println!("Warnings detected on shader: {}\n{}", name, log);
+                warn!("Warnings detected on shader: {}\n{}", name, log);
             }
             Ok(id)
         }
     }
 
     pub fn begin_frame(&mut self) -> FrameId {
         debug_assert!(!self.inside_frame);
         self.inside_frame = true;
@@ -1375,17 +1376,17 @@ impl Device {
 
         if let Some(ref cached_programs) = self.cached_programs {
             if let Some(binary) = cached_programs.binaries.borrow().get(&sources)
             {
                 self.gl.program_binary(pid, binary.format, &binary.binary);
 
                 if self.gl.get_program_iv(pid, gl::LINK_STATUS) == (0 as gl::GLint) {
                     let error_log = self.gl.get_program_info_log(pid);
-                    println!(
+                    error!(
                       "Failed to load a program object with a program binary: {} renderer {}\n{}",
                       base_filename,
                       self.renderer_name,
                       error_log
                     );
                 } else {
                     loaded = true;
                 }
@@ -1437,17 +1438,17 @@ impl Device {
             // to free any memory associated with the parsing and compilation.
             self.gl.detach_shader(pid, vs_id);
             self.gl.detach_shader(pid, fs_id);
             self.gl.delete_shader(vs_id);
             self.gl.delete_shader(fs_id);
 
             if self.gl.get_program_iv(pid, gl::LINK_STATUS) == (0 as gl::GLint) {
                 let error_log = self.gl.get_program_info_log(pid);
-                println!(
+                error!(
                     "Failed to link shader program: {}\n{}",
                     base_filename,
                     error_log
                 );
                 self.gl.delete_program(pid);
                 return Err(ShaderError::Link(base_filename.to_string(), error_log));
             }
         }
@@ -2098,16 +2099,41 @@ impl Device {
     pub fn set_blend_mode_subpixel_dual_source(&self) {
         self.gl.blend_func(gl::ONE, gl::ONE_MINUS_SRC1_COLOR);
         self.gl.blend_equation(gl::FUNC_ADD);
     }
 
     pub fn supports_extension(&self, extension: &str) -> bool {
         self.extensions.iter().any(|s| s == extension)
     }
+
+    pub fn echo_driver_messages(&self) {
+        for msg in self.gl.get_debug_messages() {
+            let level = match msg.severity {
+                gl::DEBUG_SEVERITY_HIGH => Level::Error,
+                gl::DEBUG_SEVERITY_MEDIUM => Level::Warn,
+                gl::DEBUG_SEVERITY_LOW => Level::Info,
+                gl::DEBUG_SEVERITY_NOTIFICATION => Level::Debug,
+                _ => Level::Trace,
+            };
+            let ty = match msg.ty {
+                gl::DEBUG_TYPE_ERROR => "error",
+                gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR => "deprecated",
+                gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR => "undefined",
+                gl::DEBUG_TYPE_PORTABILITY => "portability",
+                gl::DEBUG_TYPE_PERFORMANCE => "perf",
+                gl::DEBUG_TYPE_MARKER => "marker",
+                gl::DEBUG_TYPE_PUSH_GROUP => "group push",
+                gl::DEBUG_TYPE_POP_GROUP => "group pop",
+                gl::DEBUG_TYPE_OTHER => "other",
+                _ => "?",
+            };
+            log!(level, "({}) {}", ty, msg.message);
+        }
+    }
 }
 
 struct FormatDesc {
     internal: gl::GLint,
     external: gl::GLuint,
     pixel_type: gl::GLuint,
 }
 
--- a/gfx/webrender/src/display_list_flattener.rs
+++ b/gfx/webrender/src/display_list_flattener.rs
@@ -565,17 +565,21 @@ impl<'a> DisplayListFlattener<'a> {
         item: &DisplayItemRef,
         info: &IframeDisplayItem,
         clip_and_scroll_ids: &ClipAndScrollInfo,
         reference_frame_relative_offset: &LayerVector2D,
     ) {
         let iframe_pipeline_id = info.pipeline_id;
         let pipeline = match self.scene.pipelines.get(&iframe_pipeline_id) {
             Some(pipeline) => pipeline,
-            None => return,
+            None => {
+                //TODO: assert/debug_assert?
+                error!("Unknown pipeline used for iframe {:?}", info);
+                return
+            },
         };
 
         self.id_to_index_mapper.initialize_for_pipeline(pipeline);
 
         self.add_clip_node(
             info.clip_id,
             clip_and_scroll_ids.scroll_node_id,
             ClipRegion::create_for_clip_node_with_local_clip(
--- a/gfx/webrender/src/freelist.rs
+++ b/gfx/webrender/src/freelist.rs
@@ -85,16 +85,22 @@ impl<T> FreeList<T> {
     pub fn recycle(self) -> FreeList<T> {
         FreeList {
             slots: recycle_vec(self.slots),
             free_list_head: None,
             active_count: 0,
         }
     }
 
+    pub fn clear(&mut self) {
+        self.slots.clear();
+        self.free_list_head = None;
+        self.active_count = 0;
+    }
+
     #[allow(dead_code)]
     pub fn get(&self, id: &FreeListHandle<T>) -> &T {
         self.slots[id.index as usize].value.as_ref().unwrap()
     }
 
     #[allow(dead_code)]
     pub fn get_mut(&mut self, id: &FreeListHandle<T>) -> &mut T {
         self.slots[id.index as usize].value.as_mut().unwrap()
--- a/gfx/webrender/src/glyph_rasterizer.rs
+++ b/gfx/webrender/src/glyph_rasterizer.rs
@@ -3,16 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #[cfg(test)]
 use api::{IdNamespace, LayoutPoint};
 use api::{ColorF, ColorU};
 use api::{FontInstanceFlags, FontInstancePlatformOptions};
 use api::{FontKey, FontRenderMode, FontTemplate, FontVariation};
 use api::{GlyphDimensions, GlyphKey, LayerToWorldTransform, SubpixelDirection};
+#[cfg(feature = "pathfinder")]
+use api::NativeFontHandle;
 #[cfg(any(test, feature = "pathfinder"))]
 use api::DeviceIntSize;
 #[cfg(not(feature = "pathfinder"))]
 use api::{ImageData, ImageDescriptor, ImageFormat};
 use app_units::Au;
 #[cfg(not(feature = "pathfinder"))]
 use device::TextureFilter;
 #[cfg(feature = "pathfinder")]
@@ -123,44 +125,44 @@ impl FontTransform {
         FontTransform::new(
             (self.scale_x * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE,
             (self.skew_x * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE,
             (self.skew_y * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE,
             (self.scale_y * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE,
         )
     }
 
-    #[cfg(not(feature = "pathfinder"))]
+    #[allow(dead_code)]
     pub fn determinant(&self) -> f64 {
         self.scale_x as f64 * self.scale_y as f64 - self.skew_y as f64 * self.skew_x as f64
     }
 
-    #[cfg(not(feature = "pathfinder"))]
+    #[allow(dead_code)]
     pub fn compute_scale(&self) -> Option<(f64, f64)> {
         let det = self.determinant();
         if det != 0.0 {
             let x_scale = (self.scale_x as f64).hypot(self.skew_y as f64);
             let y_scale = det.abs() / x_scale;
             Some((x_scale, y_scale))
         } else {
             None
         }
     }
 
-    #[cfg(not(feature = "pathfinder"))]
+    #[allow(dead_code)]
     pub fn pre_scale(&self, scale_x: f32, scale_y: f32) -> Self {
         FontTransform::new(
             self.scale_x * scale_x,
             self.skew_x * scale_y,
             self.skew_y * scale_x,
             self.scale_y * scale_y,
         )
     }
 
-    #[cfg(not(feature = "pathfinder"))]
+    #[allow(dead_code)]
     pub fn invert_scale(&self, x_scale: f64, y_scale: f64) -> Self {
         self.pre_scale(x_scale.recip() as f32, y_scale.recip() as f32)
     }
 
     pub fn synthesize_italics(&self, skew_factor: f32) -> Self {
         FontTransform::new(
             self.scale_x,
             self.skew_x - self.scale_x * skew_factor,
@@ -448,16 +450,17 @@ impl GlyphRasterizer {
         }
 
         self.add_font_to_pathfinder(&font_key, &template);
     }
 
     #[cfg(feature = "pathfinder")]
     fn add_font_to_pathfinder(&mut self, font_key: &FontKey, template: &FontTemplate) {
         let font_contexts = Arc::clone(&self.font_contexts);
+        debug!("add_font_to_pathfinder({:?})", font_key);
         font_contexts.lock_pathfinder_context().add_font(&font_key, &template);
     }
 
     #[cfg(not(feature = "pathfinder"))]
     fn add_font_to_pathfinder(&mut self, _: &FontKey, _: &FontTemplate) {}
 
     pub fn delete_font(&mut self, font_key: FontKey) {
         self.fonts_to_remove.push(font_key);
@@ -856,20 +859,20 @@ impl AddFont for FontContext {
     }
 }
 
 #[cfg(feature = "pathfinder")]
 impl AddFont for PathfinderFontContext {
     fn add_font(&mut self, font_key: &FontKey, template: &FontTemplate) {
         match *template {
             FontTemplate::Raw(ref bytes, index) => {
-                drop(self.add_font_from_memory(font_key, bytes.clone(), index));
+                drop(self.add_font_from_memory(&font_key, bytes.clone(), index))
             }
             FontTemplate::Native(ref native_font_handle) => {
-                drop(self.add_native_font(font_key, (*native_font_handle).clone().0));
+                drop(self.add_native_font(&font_key, NativeFontHandleWrapper(native_font_handle)))
             }
         }
     }
 }
 
 #[derive(Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
@@ -1062,8 +1065,11 @@ fn request_render_task_from_pathfinder(g
     let render_pass = match render_mode {
         FontRenderMode::Mono | FontRenderMode::Alpha => &mut render_passes.alpha_glyph_pass,
         FontRenderMode::Subpixel => &mut render_passes.color_glyph_pass,
     };
     render_pass.add_render_task(root_task_id, *glyph_size, RenderTargetKind::Color);
 
     Ok((root_task_id, false))
 }
+
+#[cfg(feature = "pathfinder")]
+pub struct NativeFontHandleWrapper<'a>(pub &'a NativeFontHandle);
--- a/gfx/webrender/src/platform/macos/font.rs
+++ b/gfx/webrender/src/platform/macos/font.rs
@@ -23,16 +23,18 @@ use core_graphics::font::{CGFont, CGGlyp
 use core_graphics::geometry::{CGAffineTransform, CGPoint, CGSize};
 #[cfg(not(feature = "pathfinder"))]
 use core_graphics::geometry::CGRect;
 use core_text;
 use core_text::font::{CTFont, CTFontRef};
 use core_text::font_descriptor::{kCTFontDefaultOrientation, kCTFontColorGlyphsTrait};
 use gamma_lut::{ColorLut, GammaLut};
 use glyph_rasterizer::{FontInstance, FontTransform};
+#[cfg(feature = "pathfinder")]
+use glyph_rasterizer::NativeFontHandleWrapper;
 #[cfg(not(feature = "pathfinder"))]
 use glyph_rasterizer::{GlyphFormat, GlyphRasterResult, RasterizedGlyph};
 use internal_types::{FastHashMap, ResourceCacheError};
 use std::collections::hash_map::Entry;
 use std::sync::Arc;
 
 pub struct FontContext {
     cg_fonts: FastHashMap<FontKey, CGFont>,
@@ -724,8 +726,15 @@ impl FontContext {
             width: metrics.rasterized_width,
             height: metrics.rasterized_height,
             scale: if bitmap { y_scale.recip() as f32 } else { 1.0 },
             format: if bitmap { GlyphFormat::ColorBitmap } else { font.get_glyph_format() },
             bytes: rasterized_pixels,
         })
     }
 }
+
+#[cfg(feature = "pathfinder")]
+impl<'a> Into<CGFont> for NativeFontHandleWrapper<'a> {
+    fn into(self) -> CGFont {
+        (self.0).0.clone()
+    }
+}
--- a/gfx/webrender/src/platform/unix/font.rs
+++ b/gfx/webrender/src/platform/unix/font.rs
@@ -14,17 +14,21 @@ use freetype::freetype::{FT_Init_FreeTyp
 use freetype::freetype::{FT_Library, FT_Outline_Get_CBox, FT_Set_Char_Size, FT_Select_Size};
 use freetype::freetype::{FT_Fixed, FT_Matrix, FT_Set_Transform};
 use freetype::freetype::{FT_LOAD_COLOR, FT_LOAD_DEFAULT, FT_LOAD_FORCE_AUTOHINT};
 use freetype::freetype::{FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH, FT_LOAD_NO_AUTOHINT};
 use freetype::freetype::{FT_LOAD_NO_BITMAP, FT_LOAD_NO_HINTING, FT_LOAD_VERTICAL_LAYOUT};
 use freetype::freetype::{FT_FACE_FLAG_SCALABLE, FT_FACE_FLAG_FIXED_SIZES};
 use freetype::succeeded;
 use glyph_rasterizer::{FontInstance, GlyphFormat, GlyphRasterResult, RasterizedGlyph};
+#[cfg(feature = "pathfinder")]
+use glyph_rasterizer::NativeFontHandleWrapper;
 use internal_types::{FastHashMap, ResourceCacheError};
+#[cfg(feature = "pathfinder")]
+use pathfinder_font_renderer::freetype as pf_freetype;
 use std::{cmp, mem, ptr, slice};
 use std::cmp::max;
 use std::ffi::CString;
 use std::sync::Arc;
 
 // These constants are not present in the freetype
 // bindings due to bindgen not handling the way
 // the macros are defined.
@@ -187,17 +191,17 @@ impl FontContext {
                 self.faces.insert(
                     *font_key,
                     Face {
                         face,
                         _bytes: Some(bytes),
                     },
                 );
             } else {
-                println!("WARN: webrender failed to load font");
+                warn!("WARN: webrender failed to load font");
                 debug!("font={:?}", font_key);
             }
         }
     }
 
     pub fn add_native_font(&mut self, font_key: &FontKey, native_font_handle: NativeFontHandle) {
         if !self.faces.contains_key(&font_key) {
             let mut face: FT_Face = ptr::null_mut();
@@ -214,17 +218,17 @@ impl FontContext {
                 self.faces.insert(
                     *font_key,
                     Face {
                         face,
                         _bytes: None,
                     },
                 );
             } else {
-                println!("WARN: webrender failed to load font");
+                warn!("WARN: webrender failed to load font");
                 debug!("font={:?}, path={:?}", font_key, pathname);
             }
         }
     }
 
     pub fn delete_font(&mut self, font_key: &FontKey) {
         if let Some(face) = self.faces.remove(font_key) {
             let result = unsafe { FT_Done_Face(face.face) };
@@ -783,8 +787,16 @@ impl FontContext {
 
 impl Drop for FontContext {
     fn drop(&mut self) {
         unsafe {
             FT_Done_FreeType(self.lib);
         }
     }
 }
+
+#[cfg(feature = "pathfinder")]
+impl<'a> Into<pf_freetype::FontDescriptor> for NativeFontHandleWrapper<'a> {
+    fn into(self) -> pf_freetype::FontDescriptor {
+        let NativeFontHandleWrapper(font_handle) = self;
+        pf_freetype::FontDescriptor::new(font_handle.pathname.clone().into(), font_handle.index)
+    }
+}
--- a/gfx/webrender/src/render_backend.rs
+++ b/gfx/webrender/src/render_backend.rs
@@ -661,16 +661,20 @@ impl RenderBackend {
                 profile_scope!("GetScrollNodeState");
                 tx.send(doc.get_scroll_node_state()).unwrap();
                 DocumentOps::nop()
             }
             FrameMsg::UpdateDynamicProperties(property_bindings) => {
                 doc.dynamic_properties.set_properties(property_bindings);
                 DocumentOps::render()
             }
+            FrameMsg::AppendDynamicProperties(property_bindings) => {
+                doc.dynamic_properties.add_properties(property_bindings);
+                DocumentOps::render()
+            }
         }
     }
 
     fn next_namespace_id(&self) -> IdNamespace {
         IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32)
     }
 
     pub fn run(&mut self, mut profile_counters: BackendProfileCounters) {
--- a/gfx/webrender/src/render_task.rs
+++ b/gfx/webrender/src/render_task.rs
@@ -6,16 +6,17 @@ use api::{DeviceIntPoint, DeviceIntRect,
 #[cfg(feature = "pathfinder")]
 use api::FontRenderMode;
 use box_shadow::{BoxShadowCacheKey};
 use clip::{ClipSource, ClipStore, ClipWorkItem};
 use clip_scroll_tree::CoordinateSystemId;
 use device::TextureFilter;
 #[cfg(feature = "pathfinder")]
 use euclid::{TypedPoint2D, TypedVector2D};
+use freelist::{FreeList, FreeListHandle};
 use glyph_rasterizer::GpuGlyphCacheKey;
 use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
 use gpu_types::{ImageSource, RasterizationSpace};
 use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
 #[cfg(feature = "pathfinder")]
 use pathfinder_partitioner::mesh::Mesh;
 use prim_store::{PrimitiveIndex, ImageCacheKey};
 #[cfg(feature = "debugger")]
@@ -861,37 +862,40 @@ pub enum RenderTaskCacheKeyKind {
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct RenderTaskCacheKey {
     pub size: DeviceIntSize,
     pub kind: RenderTaskCacheKeyKind,
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-struct RenderTaskCacheEntry {
-    handle: TextureCacheHandle,
+pub struct RenderTaskCacheEntry {
+    pub handle: TextureCacheHandle,
 }
 
 // A cache of render tasks that are stored in the texture
 // cache for usage across frames.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct RenderTaskCache {
-    entries: FastHashMap<RenderTaskCacheKey, RenderTaskCacheEntry>,
+    map: FastHashMap<RenderTaskCacheKey, FreeListHandle<RenderTaskCacheEntry>>,
+    cache_entries: FreeList<RenderTaskCacheEntry>,
 }
 
 impl RenderTaskCache {
     pub fn new() -> Self {
         RenderTaskCache {
-            entries: FastHashMap::default(),
+            map: FastHashMap::default(),
+            cache_entries: FreeList::new(),
         }
     }
 
     pub fn clear(&mut self) {
-        self.entries.clear();
+        self.map.clear();
+        self.cache_entries.clear();
     }
 
     pub fn begin_frame(
         &mut self,
         texture_cache: &mut TextureCache,
     ) {
         // Drop any items from the cache that have been
         // evicted from the texture cache.
@@ -901,38 +905,53 @@ impl RenderTaskCache {
         // It will evict render tasks as required, since
         // the access time in the texture cache entry will
         // be stale if this task hasn't been requested
         // for a while.
         //
         // Nonetheless, we should remove stale entries
         // from here so that this hash map doesn't
         // grow indefinitely!
-        self.entries.retain(|_, value| {
-            texture_cache.is_allocated(&value.handle)
-        });
+        let mut keys_to_remove = Vec::new();
+
+        for (key, handle) in &self.map {
+            let entry = self.cache_entries.get(handle);
+            if !texture_cache.is_allocated(&entry.handle) {
+                keys_to_remove.push(key.clone())
+            }
+        }
+
+        for key in &keys_to_remove {
+            let handle = self.map.remove(key).unwrap();
+            self.cache_entries.free(handle);
+        }
     }
 
     pub fn request_render_task<F>(
         &mut self,
         key: RenderTaskCacheKey,
         texture_cache: &mut TextureCache,
         gpu_cache: &mut GpuCache,
         render_tasks: &mut RenderTaskTree,
         user_data: Option<[f32; 3]>,
         mut f: F,
     ) -> Result<CacheItem, ()>
          where F: FnMut(&mut RenderTaskTree) -> Result<(RenderTaskId, bool), ()> {
         // Get the texture cache handle for this cache key,
         // or create one.
-        let cache_entry = self.entries
-                              .entry(key)
-                              .or_insert(RenderTaskCacheEntry {
-                                  handle: TextureCacheHandle::new(),
-                              });
+        let cache_entries = &mut self.cache_entries;
+        let entry_handle = self.map
+                               .entry(key)
+                               .or_insert_with(|| {
+                                    let entry = RenderTaskCacheEntry {
+                                        handle: TextureCacheHandle::new(),
+                                    };
+                                    cache_entries.insert(entry)
+                                });
+        let cache_entry = cache_entries.get_mut(entry_handle);
 
         // Check if this texture cache handle is valid.
         if texture_cache.request(&cache_entry.handle, gpu_cache) {
             // Invoke user closure to get render task chain
             // to draw this into the texture cache.
             let (render_task_id, is_opaque) = try!(f(render_tasks));
             let render_task = &mut render_tasks[render_task_id];
 
@@ -995,26 +1014,28 @@ impl RenderTaskCache {
     }
 
     #[allow(dead_code)]
     pub fn get_cache_item_for_render_task(&self,
                                           texture_cache: &TextureCache,
                                           key: &RenderTaskCacheKey)
                                           -> CacheItem {
         // Get the texture cache handle for this cache key.
-        let cache_entry = self.entries.get(key).unwrap();
+        let handle = self.map.get(key).unwrap();
+        let cache_entry = self.cache_entries.get(handle);
         texture_cache.get(&cache_entry.handle)
     }
 
     #[allow(dead_code)]
     pub fn cache_item_is_allocated_for_render_task(&self,
                                                    texture_cache: &TextureCache,
                                                    key: &RenderTaskCacheKey)
                                                    -> bool {
-        let cache_entry = self.entries.get(key).unwrap();
+        let handle = self.map.get(key).unwrap();
+        let cache_entry = self.cache_entries.get(handle);
         texture_cache.is_allocated(&cache_entry.handle)
     }
 }
 
 // TODO(gw): Rounding the content rect here to device pixels is not
 // technically correct. Ideally we should ceil() here, and ensure that
 // the extra part pixel in the case of fractional sizes is correctly
 // handled. For now, just use rounding which passes the existing
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -250,16 +250,17 @@ bitflags! {
         const PROFILER_DBG      = 1 << 0;
         const RENDER_TARGET_DBG = 1 << 1;
         const TEXTURE_CACHE_DBG = 1 << 2;
         const GPU_TIME_QUERIES  = 1 << 3;
         const GPU_SAMPLE_QUERIES= 1 << 4;
         const DISABLE_BATCHING  = 1 << 5;
         const EPOCHS            = 1 << 6;
         const COMPACT_PROFILER  = 1 << 7;
+        const ECHO_DRIVER_MESSAGES = 1 << 8;
     }
 }
 
 fn flag_changed(before: DebugFlags, after: DebugFlags, select: DebugFlags) -> Option<bool> {
     if before & select != after & select {
         Some(after.contains(select))
     } else {
         None
@@ -1252,16 +1253,22 @@ impl LazyInitializedDebugRenderer {
 
     pub fn deinit(self, device: &mut Device) {
         if let Some(debug_renderer) = self.debug_renderer {
             debug_renderer.deinit(device);
         }
     }
 }
 
+pub struct RendererVAOs {
+    prim_vao: VAO,
+    blur_vao: VAO,
+    clip_vao: VAO,
+}
+
 /// The renderer is responsible for submitting to the GPU the work prepared by the
 /// RenderBackend.
 pub struct Renderer {
     result_rx: Receiver<ResultMsg>,
     debug_server: DebugServer,
     pub device: Device,
     pending_texture_updates: Vec<TextureUpdateList>,
     pending_gpu_cache_updates: Vec<GpuCacheUpdateList>,
@@ -1282,19 +1289,17 @@ pub struct Renderer {
     debug_flags: DebugFlags,
     backend_profile_counters: BackendProfileCounters,
     profile_counters: RendererProfileCounters,
     #[cfg(feature = "debug_renderer")]
     profiler: Profiler,
     last_time: u64,
 
     pub gpu_profile: GpuProfiler<GpuProfileTag>,
-    prim_vao: VAO,
-    blur_vao: VAO,
-    clip_vao: VAO,
+    vaos: RendererVAOs,
 
     node_data_texture: VertexDataTexture,
     local_clip_rects_texture: VertexDataTexture,
     render_task_texture: VertexDataTexture,
     gpu_cache_texture: CacheTexture,
 
     gpu_cache_frame_id: FrameId,
     gpu_cache_overflow: bool,
@@ -1407,17 +1412,17 @@ impl Renderer {
             device.supports_extension("GL_ARB_blend_func_extended");
 
         let device_max_size = device.max_texture_size();
         // 512 is the minimum that the texture cache can work with.
         // Broken GL contexts can return a max texture size of zero (See #1260). Better to
         // gracefully fail now than panic as soon as a texture is allocated.
         let min_texture_size = 512;
         if device_max_size < min_texture_size {
-            println!(
+            error!(
                 "Device reporting insufficient max texture size ({})",
                 device_max_size
             );
             return Err(RendererError::MaxTextureSize);
         }
         let max_device_size = cmp::max(
             cmp::min(
                 device_max_size,
@@ -1684,19 +1689,21 @@ impl Renderer {
             profiler: Profiler::new(),
             max_texture_size: max_device_size,
             max_recorded_profiles: options.max_recorded_profiles,
             clear_color: options.clear_color,
             enable_clear_scissor: options.enable_clear_scissor,
             last_time: 0,
             gpu_profile,
             gpu_glyph_renderer,
-            prim_vao,
-            blur_vao,
-            clip_vao,
+            vaos: RendererVAOs {
+                prim_vao,
+                blur_vao,
+                clip_vao,
+            },
             node_data_texture,
             local_clip_rects_texture,
             render_task_texture,
             pipeline_info: PipelineInfo::default(),
             dither_matrix_texture,
             external_image_handler: None,
             output_image_handler: None,
             output_targets: FastHashMap::default(),
@@ -2293,16 +2300,20 @@ impl Renderer {
                         screen_fraction,
                         self.debug.get_mut(&mut self.device),
                         self.debug_flags.contains(DebugFlags::COMPACT_PROFILER),
                     );
                 }
             }
         }
 
+        if self.debug_flags.contains(DebugFlags::ECHO_DRIVER_MESSAGES) {
+            self.device.echo_driver_messages();
+        }
+
         self.backend_profile_counters.reset();
         self.profile_counters.reset();
         self.profile_counters.frame_counter.inc();
 
         profile_timers.cpu_time.profile(|| {
             let _gm = self.gpu_profile.start_marker("end frame");
             self.gpu_profile.end_frame();
             #[cfg(feature = "debug_renderer")]
@@ -2507,21 +2518,17 @@ impl Renderer {
     }
 
     pub(crate) fn draw_instanced_batch_with_previously_bound_textures<T>(
         &mut self,
         data: &[T],
         vertex_array_kind: VertexArrayKind,
         stats: &mut RendererStats,
     ) {
-        let vao = get_vao(vertex_array_kind,
-                          &self.prim_vao,
-                          &self.clip_vao,
-                          &self.blur_vao,
-                          &self.gpu_glyph_renderer);
+        let vao = get_vao(vertex_array_kind, &self.vaos, &self.gpu_glyph_renderer);
 
         self.device.bind_vao(vao);
 
         let batched = !self.debug_flags.contains(DebugFlags::DISABLE_BATCHING);
 
         if batched {
             self.device
                 .update_vao_instances(vao, data, VertexUsageHint::Stream);
@@ -3915,19 +3922,19 @@ impl Renderer {
         if let Some(dither_matrix_texture) = self.dither_matrix_texture {
             self.device.delete_texture(dither_matrix_texture);
         }
         self.node_data_texture.deinit(&mut self.device);
         self.local_clip_rects_texture.deinit(&mut self.device);
         self.render_task_texture.deinit(&mut self.device);
         self.device.delete_pbo(self.texture_cache_upload_pbo);
         self.texture_resolver.deinit(&mut self.device);
-        self.device.delete_vao(self.prim_vao);
-        self.device.delete_vao(self.clip_vao);
-        self.device.delete_vao(self.blur_vao);
+        self.device.delete_vao(self.vaos.prim_vao);
+        self.device.delete_vao(self.vaos.clip_vao);
+        self.device.delete_vao(self.vaos.blur_vao);
 
         #[cfg(feature = "debug_renderer")]
         {
             self.debug.deinit(&mut self.device);
         }
 
         for (_, target) in self.output_targets {
             self.device.delete_fbo(target.fbo_id);
@@ -4483,40 +4490,34 @@ impl Renderer {
         }
 
         self.output_image_handler = Some(Box::new(()) as Box<_>);
         self.external_image_handler = Some(Box::new(image_handler) as Box<_>);
         info!("done.");
     }
 }
 
-// FIXME(pcwalton): We should really gather up all the VAOs into a separate structure so that they
-// don't have to be passed in as parameters here.
 #[cfg(feature = "pathfinder")]
 fn get_vao<'a>(vertex_array_kind: VertexArrayKind,
-               prim_vao: &'a VAO,
-               clip_vao: &'a VAO,
-               blur_vao: &'a VAO,
+               vaos: &'a RendererVAOs,
                gpu_glyph_renderer: &'a GpuGlyphRenderer)
                -> &'a VAO {
     match vertex_array_kind {
-        VertexArrayKind::Primitive => prim_vao,
-        VertexArrayKind::Clip => clip_vao,
-        VertexArrayKind::Blur => blur_vao,
+        VertexArrayKind::Primitive => &vaos.prim_vao,
+        VertexArrayKind::Clip => &vaos.clip_vao,
+        VertexArrayKind::Blur => &vaos.blur_vao,
         VertexArrayKind::VectorStencil => &gpu_glyph_renderer.vector_stencil_vao,
         VertexArrayKind::VectorCover => &gpu_glyph_renderer.vector_cover_vao,
     }
 }
 
 #[cfg(not(feature = "pathfinder"))]
 fn get_vao<'a>(vertex_array_kind: VertexArrayKind,
-               prim_vao: &'a VAO,
-               clip_vao: &'a VAO,
-               blur_vao: &'a VAO,
+               vaos: &'a RendererVAOs,
                _: &'a GpuGlyphRenderer)
                -> &'a VAO {
     match vertex_array_kind {
-        VertexArrayKind::Primitive => prim_vao,
-        VertexArrayKind::Clip => clip_vao,
-        VertexArrayKind::Blur => blur_vao,
+        VertexArrayKind::Primitive => &vaos.prim_vao,
+        VertexArrayKind::Clip => &vaos.clip_vao,
+        VertexArrayKind::Blur => &vaos.blur_vao,
         VertexArrayKind::VectorStencil | VertexArrayKind::VectorCover => unreachable!(),
     }
 }
--- a/gfx/webrender/src/resource_cache.rs
+++ b/gfx/webrender/src/resource_cache.rs
@@ -1,15 +1,15 @@
 /* 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::{AddFont, BlobImageData, BlobImageResources, ResourceUpdate, ResourceUpdates};
 use api::{BlobImageDescriptor, BlobImageError, BlobImageRenderer, BlobImageRequest};
-use api::{ClearCache, ColorF, DevicePoint, DeviceUintRect, DeviceUintSize};
+use api::{ClearCache, ColorF, DevicePoint, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
 use api::{Epoch, FontInstanceKey, FontKey, FontTemplate};
 use api::{ExternalImageData, ExternalImageType};
 use api::{FontInstanceOptions, FontInstancePlatformOptions, FontVariation};
 use api::{GlyphDimensions, GlyphKey, IdNamespace};
 use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering};
 use api::{TileOffset, TileSize};
 use app_units::Au;
 #[cfg(feature = "capture")]
@@ -477,17 +477,18 @@ impl ResourceCache {
             );
         }
 
         let resource = ImageResource {
             descriptor,
             data,
             epoch: Epoch(0),
             tiling,
-            dirty_rect: None,
+            dirty_rect: Some(DeviceUintRect::new(DeviceUintPoint::zero(),
+                                                 DeviceUintSize::new(descriptor.width, descriptor.height))),
         };
 
         self.resources.image_templates.insert(image_key, resource);
     }
 
     pub fn update_image_template(
         &mut self,
         image_key: ImageKey,
--- a/gfx/webrender/src/scene.rs
+++ b/gfx/webrender/src/scene.rs
@@ -26,17 +26,21 @@ impl SceneProperties {
             float_properties: FastHashMap::default(),
         }
     }
 
     /// Set the current property list for this display list.
     pub fn set_properties(&mut self, properties: DynamicProperties) {
         self.transform_properties.clear();
         self.float_properties.clear();
+        self.add_properties(properties);
+    }
 
+    /// Add to the current property list for this display list.
+    pub fn add_properties(&mut self, properties: DynamicProperties) {
         for property in properties.transforms {
             self.transform_properties
                 .insert(property.key.id, property.value);
         }
 
         for property in properties.floats {
             self.float_properties
                 .insert(property.key.id, property.value);
--- a/gfx/webrender/src/shade.rs
+++ b/gfx/webrender/src/shade.rs
@@ -469,16 +469,25 @@ pub struct Shaders {
 }
 
 impl Shaders {
     pub fn new(
         device: &mut Device,
         gl_type: GlType,
         options: &RendererOptions,
     ) -> Result<Self, ShaderError> {
+        // needed for the precache fake draws
+        let dummy_vao = if options.precache_shaders {
+            let vao = device.create_custom_vao(&[]);
+            device.bind_custom_vao(&vao);
+            Some(vao)
+        } else {
+            None
+        };
+
         let brush_solid = BrushShader::new(
             "brush_solid",
             device,
             &[],
             options.precache_shaders,
         )?;
 
         let brush_blend = BrushShader::new(
@@ -676,16 +685,20 @@ impl Shaders {
         let ps_split_composite = LazilyCompiledShader::new(
             ShaderKind::Primitive,
             "ps_split_composite",
             &[],
             device,
             options.precache_shaders,
         )?;
 
+        if let Some(vao) = dummy_vao {
+            device.delete_custom_vao(vao);
+        }
+
         Ok(Shaders {
             cs_blur_a8,
             cs_blur_rgba8,
             brush_solid,
             brush_image,
             brush_blend,
             brush_mix_blend,
             brush_yuv_image,
--- a/gfx/webrender_api/Cargo.toml
+++ b/gfx/webrender_api/Cargo.toml
@@ -13,18 +13,18 @@ deserialize = []
 
 [dependencies]
 app_units = "0.6"
 bincode = "1.0"
 bitflags = "1.0"
 byteorder = "1.2.1"
 ipc-channel = {version = "0.10.0", optional = true}
 euclid = { version = "0.17", features = ["serde"] }
-serde = { version = "=1.0.35", features = ["rc"] }
-serde_derive = { version = "=1.0.35", features = ["deserialize_in_place"] }
+serde = { version = "=1.0.37", features = ["rc"] }
+serde_derive = { version = "=1.0.37", features = ["deserialize_in_place"] }
 serde_bytes = "0.10"
 time = "0.1"
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-foundation = "0.5"
 core-graphics = "0.13"
 
 [target.'cfg(target_os = "windows")'.dependencies]
--- a/gfx/webrender_api/src/api.rs
+++ b/gfx/webrender_api/src/api.rs
@@ -319,16 +319,24 @@ impl Transaction {
     }
 
     /// Supply a list of animated property bindings that should be used to resolve
     /// bindings in the current display list.
     pub fn update_dynamic_properties(&mut self, properties: DynamicProperties) {
         self.frame_ops.push(FrameMsg::UpdateDynamicProperties(properties));
     }
 
+    /// Add to the list of animated property bindings that should be used to
+    /// resolve bindings in the current display list. This is a convenience method
+    /// so the caller doesn't have to figure out all the dynamic properties before
+    /// setting them on the transaction but can do them incrementally.
+    pub fn append_dynamic_properties(&mut self, properties: DynamicProperties) {
+        self.frame_ops.push(FrameMsg::AppendDynamicProperties(properties));
+    }
+
     /// Enable copying of the output of this pipeline id to
     /// an external texture for callers to consume.
     pub fn enable_frame_output(&mut self, pipeline_id: PipelineId, enable: bool) {
         self.frame_ops.push(FrameMsg::EnableFrameOutput(pipeline_id, enable));
     }
 
     fn finalize(self) -> (TransactionMsg, Vec<Payload>) {
         (
@@ -481,16 +489,17 @@ pub enum FrameMsg {
     UpdateEpoch(PipelineId, Epoch),
     HitTest(Option<PipelineId>, WorldPoint, HitTestFlags, MsgSender<HitTestResult>),
     SetPan(DeviceIntPoint),
     EnableFrameOutput(PipelineId, bool),
     Scroll(ScrollLocation, WorldPoint),
     ScrollNodeWithId(LayoutPoint, ExternalScrollId, ScrollClamping),
     GetScrollNodeState(MsgSender<Vec<ScrollNodeState>>),
     UpdateDynamicProperties(DynamicProperties),
+    AppendDynamicProperties(DynamicProperties),
 }
 
 impl fmt::Debug for SceneMsg {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str(match *self {
             SceneMsg::UpdateEpoch(..) => "SceneMsg::UpdateEpoch",
             SceneMsg::SetDisplayList { .. } => "SceneMsg::SetDisplayList",
             SceneMsg::SetPageZoom(..) => "SceneMsg::SetPageZoom",
@@ -508,16 +517,17 @@ impl fmt::Debug for FrameMsg {
             FrameMsg::UpdateEpoch(..) => "FrameMsg::UpdateEpoch",
             FrameMsg::HitTest(..) => "FrameMsg::HitTest",
             FrameMsg::SetPan(..) => "FrameMsg::SetPan",
             FrameMsg::Scroll(..) => "FrameMsg::Scroll",
             FrameMsg::ScrollNodeWithId(..) => "FrameMsg::ScrollNodeWithId",
             FrameMsg::GetScrollNodeState(..) => "FrameMsg::GetScrollNodeState",
             FrameMsg::EnableFrameOutput(..) => "FrameMsg::EnableFrameOutput",
             FrameMsg::UpdateDynamicProperties(..) => "FrameMsg::UpdateDynamicProperties",
+            FrameMsg::AppendDynamicProperties(..) => "FrameMsg::AppendDynamicProperties",
         })
     }
 }
 
 bitflags!{
     /// Bit flags for WR stages to store in a capture.
     // Note: capturing `FRAME` without `SCENE` is not currently supported.
     #[derive(Deserialize, Serialize)]
--- a/gfx/webrender_bindings/Cargo.toml
+++ b/gfx/webrender_bindings/Cargo.toml
@@ -4,17 +4,17 @@ version = "0.1.0"
 authors = ["The Mozilla Project Developers"]
 license = "MPL-2.0"
 
 [dependencies]
 rayon = "1"
 thread_profiler = "0.1.1"
 euclid = { version = "0.17", features = ["serde"] }
 app_units = "0.6"
-gleam = "0.4.20"
+gleam = "0.4.32"
 log = "0.4"
 
 [dependencies.webrender]
 path = "../webrender"
 version = "0.57.2"
 default-features = false
 features = ["capture"]
 
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -757,16 +757,17 @@ DisplayListBuilder::Finalize(wr::LayoutS
   wr_api_finalize_builder(mWrState,
                           &aOutContentSize,
                           &aOutDisplayList.dl_desc,
                           &aOutDisplayList.dl.inner);
 }
 
 void
 DisplayListBuilder::PushStackingContext(const wr::LayoutRect& aBounds,
+                                        const wr::WrClipId* aClipNodeId,
                                         const WrAnimationProperty* aAnimation,
                                         const float* aOpacity,
                                         const gfx::Matrix4x4* aTransform,
                                         wr::TransformStyle aTransformStyle,
                                         const gfx::Matrix4x4* aPerspective,
                                         const wr::MixBlendMode& aMixBlendMode,
                                         const nsTArray<wr::WrFilterOp>& aFilters,
                                         bool aIsBackfaceVisible)
@@ -776,19 +777,20 @@ DisplayListBuilder::PushStackingContext(
     matrix = ToLayoutTransform(*aTransform);
   }
   const wr::LayoutTransform* maybeTransform = aTransform ? &matrix : nullptr;
   wr::LayoutTransform perspective;
   if (aPerspective) {
     perspective = ToLayoutTransform(*aPerspective);
   }
   const wr::LayoutTransform* maybePerspective = aPerspective ? &perspective : nullptr;
+  const size_t* maybeClipNodeId = aClipNodeId ? &aClipNodeId->id : nullptr;
   WRDL_LOG("PushStackingContext b=%s t=%s\n", mWrState, Stringify(aBounds).c_str(),
       aTransform ? Stringify(*aTransform).c_str() : "none");
-  wr_dp_push_stacking_context(mWrState, aBounds, aAnimation, aOpacity,
+  wr_dp_push_stacking_context(mWrState, aBounds, maybeClipNodeId, aAnimation, aOpacity,
                               maybeTransform, aTransformStyle, maybePerspective,
                               aMixBlendMode, aFilters.Elements(), aFilters.Length(), aIsBackfaceVisible);
 }
 
 void
 DisplayListBuilder::PopStackingContext()
 {
   WRDL_LOG("PopStackingContext\n", mWrState);
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -242,16 +242,17 @@ public:
   void Restore();
   void ClearSave();
   void Dump();
 
   void Finalize(wr::LayoutSize& aOutContentSize,
                 wr::BuiltDisplayList& aOutDisplayList);
 
   void PushStackingContext(const wr::LayoutRect& aBounds, // TODO: We should work with strongly typed rects
+                           const wr::WrClipId* aClipNodeId,
                            const wr::WrAnimationProperty* aAnimation,
                            const float* aOpacity,
                            const gfx::Matrix4x4* aTransform,
                            wr::TransformStyle aTransformStyle,
                            const gfx::Matrix4x4* aPerspective,
                            const wr::MixBlendMode& aMixBlendMode,
                            const nsTArray<wr::WrFilterOp>& aFilters,
                            bool aIsBackfaceVisible);
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-092ada1154b72fe71d2f227a5df0239586d2323a
+6f997974cec5772b1797725f4a7942d742e7d7ff
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1499,16 +1499,17 @@ pub extern "C" fn wr_dp_restore(state: &
 #[no_mangle]
 pub extern "C" fn wr_dp_clear_save(state: &mut WrState) {
     state.frame_builder.dl_builder.clear_save();
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_stacking_context(state: &mut WrState,
                                               bounds: LayoutRect,
+                                              clip_node_id: *const usize,
                                               animation: *const WrAnimationProperty,
                                               opacity: *const f32,
                                               transform: *const LayoutTransform,
                                               transform_style: TransformStyle,
                                               perspective: *const LayoutTransform,
                                               mix_blend_mode: MixBlendMode,
                                               filters: *const WrFilterOp,
                                               filter_count: usize,
@@ -1529,16 +1530,22 @@ pub extern "C" fn wr_dp_push_stacking_co
             WrFilterOpType::Sepia => FilterOp::Sepia(c_filter.argument),
             WrFilterOpType::DropShadow => FilterOp::DropShadow(c_filter.offset,
                                                                c_filter.argument,
                                                                c_filter.color),
             WrFilterOpType::ColorMatrix => FilterOp::ColorMatrix(c_filter.matrix),
         }
     }).collect();
 
+    let clip_node_id_ref = unsafe { clip_node_id.as_ref() };
+    let clip_node_id = match clip_node_id_ref {
+        Some(clip_node_id) => Some(ClipId::Clip(*clip_node_id, state.pipeline_id)),
+        None => None,
+    };
+
     let opacity_ref = unsafe { opacity.as_ref() };
     if let Some(opacity) = opacity_ref {
         if *opacity < 1.0 {
             filters.push(FilterOp::Opacity(PropertyBinding::Value(*opacity), *opacity));
         }
     }
 
     let transform_ref = unsafe { transform.as_ref() };
@@ -1564,17 +1571,17 @@ pub extern "C" fn wr_dp_push_stacking_co
 
     let mut prim_info = LayoutPrimitiveInfo::new(bounds);
     prim_info.is_backface_visible = is_backface_visible;
     prim_info.tag = state.current_tag;
 
     state.frame_builder
          .dl_builder
          .push_stacking_context(&prim_info,
-                                None,
+                                clip_node_id,
                                 ScrollPolicy::Scrollable,
                                 transform_binding,
                                 transform_style,
                                 perspective,
                                 mix_blend_mode,
                                 filters);
 }
 
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -1304,16 +1304,17 @@ void wr_dp_push_shadow(WrState *aState,
                        LayoutRect aClip,
                        bool aIsBackfaceVisible,
                        Shadow aShadow)
 WR_FUNC;
 
 WR_INLINE
 void wr_dp_push_stacking_context(WrState *aState,
                                  LayoutRect aBounds,
+                                 const uintptr_t *aClipNodeId,
                                  const WrAnimationProperty *aAnimation,
                                  const float *aOpacity,
                                  const LayoutTransform *aTransform,
                                  TransformStyle aTransformStyle,
                                  const LayoutTransform *aPerspective,
                                  MixBlendMode aMixBlendMode,
                                  const WrFilterOp *aFilters,
                                  uintptr_t aFilterCount,
--- a/gfx/wrench/Cargo.toml
+++ b/gfx/wrench/Cargo.toml
@@ -19,17 +19,17 @@ clap = { version = "2", features = ["yam
 lazy_static = "1"
 log = "0.4"
 yaml-rust = { git = "https://github.com/vvuk/yaml-rust", features = ["preserve_order"] }
 serde_json = "1.0"
 ron = "0.1.5"
 time = "0.1"
 crossbeam = "0.2"
 osmesa-sys = { version = "0.1.2", optional = true }
-osmesa-src = { git = "https://github.com/servo/osmesa-src", optional = true }
+osmesa-src = { git = "https://github.com/jrmuizel/osmesa-src", optional = true, branch = "serialize" }
 webrender = {path = "../webrender", features=["capture","replay","debugger","png","profiler"]}
 webrender_api = {path = "../webrender_api", features=["serialize","deserialize"]}
 serde = {version = "1.0", features = ["derive"] }
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-graphics = "0.13"
 core-foundation = "0.5"
 
--- a/gfx/wrench/src/wrench.rs
+++ b/gfx/wrench/src/wrench.rs
@@ -192,17 +192,17 @@ impl Wrench {
                 Box<webrender::ApiRecordingReceiver>,
             SaveType::Ron => Box::new(RonFrameWriter::new(&PathBuf::from("ron_frames"))) as
                 Box<webrender::ApiRecordingReceiver>,
             SaveType::Binary => Box::new(webrender::BinaryRecorder::new(
                 &PathBuf::from("wr-record.bin"),
             )) as Box<webrender::ApiRecordingReceiver>,
         });
 
-        let mut debug_flags = DebugFlags::default();
+        let mut debug_flags = DebugFlags::ECHO_DRIVER_MESSAGES;
         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,
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -972,17 +972,18 @@ ProcessArgs(AutoJSAPI& jsapi, char** arg
         {
             RootedValue rval(cx);
 
             if (++i == argc) {
                 return printUsageAndSetExitCode();
             }
 
             JS::CompileOptions opts(cx);
-            opts.setFileAndLine("-e", 1);
+            opts.setUTF8(true)
+                .setFileAndLine("-e", 1);
             JS::Evaluate(cx, opts, argv[i], strlen(argv[i]), &rval);
 
             isInteractive = false;
             break;
         }
         case 'C':
             compileOnly = true;
             isInteractive = false;
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -50,16 +50,17 @@
 #include "mozilla/layers/WebRenderUserData.h"
 #include "mozilla/Unused.h"
 #include "GeckoProfiler.h"
 #include "LayersLogging.h"
 #include "gfxPrefs.h"
 
 #include <algorithm>
 #include <functional>
+#include <list>
 
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 
 class PaintedDisplayItemLayerUserData;
 
@@ -113,16 +114,109 @@ static inline MaskLayerImageCache* GetMa
 {
   if (!gMaskLayerImageCache) {
     gMaskLayerImageCache = new MaskLayerImageCache();
   }
 
   return gMaskLayerImageCache;
 }
 
+struct DisplayItemEntry {
+  DisplayItemEntry(nsDisplayItem* aItem,
+                   DisplayItemEntryType aType)
+    : mItem(aItem)
+    , mType(aType)
+  {}
+
+  nsDisplayItem* mItem;
+  DisplayItemEntryType mType;
+};
+
+class FLBDisplayItemIterator : protected FlattenedDisplayItemIterator
+{
+public:
+  FLBDisplayItemIterator(nsDisplayListBuilder* aBuilder,
+                         nsDisplayList* aList,
+                         ContainerState* aState)
+    : FlattenedDisplayItemIterator(aBuilder, aList, false)
+    , mState(aState)
+  {
+    MOZ_ASSERT(mState);
+    ResolveFlattening();
+  }
+
+  DisplayItemEntry GetNextEntry()
+  {
+    if (!mMarkers.empty()) {
+      DisplayItemEntry entry = mMarkers.front();
+      mMarkers.pop_front();
+      return entry;
+    }
+
+    nsDisplayItem* next = GetNext();
+    return DisplayItemEntry { next, DisplayItemEntryType::ITEM };
+  }
+
+  nsDisplayItem* GetNext()
+  {
+    // This function is only supposed to be called if there are no markers set.
+    // Breaking this invariant can potentially break effect flattening and/or
+    // display item merging.
+    MOZ_ASSERT(mMarkers.empty());
+
+    return FlattenedDisplayItemIterator::GetNext();
+  }
+
+  bool HasNext() const
+  {
+    return FlattenedDisplayItemIterator::HasNext() || !mMarkers.empty();
+  }
+
+  nsDisplayItem* PeekNext()
+  {
+    return mNext;
+  }
+
+private:
+  bool ShouldFlattenNextItem() const override;
+
+  void StartNested(nsDisplayItem* aItem) override
+  {
+    if (aItem->GetType() == DisplayItemType::TYPE_OPACITY) {
+      nsDisplayOpacity* opacity = static_cast<nsDisplayOpacity*> (aItem);
+
+      if (opacity->OpacityAppliedToChildren()) {
+        // If the opacity was already applied to children, there is no need to
+        // emit opacity markers.
+        return;
+      }
+
+      mMarkers.emplace_back(aItem, DisplayItemEntryType::PUSH_OPACITY);
+      mActiveMarkers.AppendElement(aItem);
+    }
+  }
+
+  void EndNested(nsDisplayItem* aItem) override
+  {
+    if (mActiveMarkers.IsEmpty() || mActiveMarkers.LastElement() != aItem) {
+      // Do not emit an end marker if this item did not emit a start marker.
+      return;
+    }
+
+    if (aItem->GetType() == DisplayItemType::TYPE_OPACITY) {
+      mMarkers.emplace_back(aItem, DisplayItemEntryType::POP_OPACITY);
+      mActiveMarkers.RemoveLastElement();
+    }
+  }
+
+  std::list<DisplayItemEntry> mMarkers;
+  AutoTArray<nsDisplayItem*, 4> mActiveMarkers;
+  ContainerState* mState;
+};
+
 DisplayItemData::DisplayItemData(LayerManagerData* aParent, uint32_t aKey,
                                  Layer* aLayer, nsIFrame* aFrame)
 
   : mRefCnt(0)
   , mParent(aParent)
   , mLayer(aLayer)
   , mDisplayItemKey(aKey)
   , mItem(nullptr)
@@ -477,17 +571,18 @@ public:
    * @param aSolidColor if non-null, the visible area of the item is
    * a constant color given by *aSolidColor
    */
   void Accumulate(ContainerState* aState,
                   nsDisplayItem* aItem,
                   const nsIntRect& aVisibleRect,
                   const DisplayItemClip& aClip,
                   LayerState aLayerState,
-                  nsDisplayList *aList);
+                  nsDisplayList *aList,
+                  DisplayItemEntryType aType);
   AnimatedGeometryRoot* GetAnimatedGeometryRoot() { return mAnimatedGeometryRoot; }
 
   /**
    * A region including the horizontal pan, vertical pan, and no action regions.
    */
   nsRegion CombinedTouchActionRegion();
 
   /**
@@ -673,17 +768,21 @@ public:
    * This is a conservative approximation: it contains the true region.
    */
   nsIntRegion mVisibleAboveRegion;
   /**
    * All the display items that have been assigned to this painted layer.
    * These items get added by Accumulate().
    */
   nsTArray<AssignedDisplayItem> mAssignedDisplayItems;
-
+  /**
+   * Tracks the active opacity markers by holding the indices to PUSH_OPACITY
+   * items in |mAssignedDisplayItems|.
+   */
+  nsTArray<size_t> mOpacityIndices;
 };
 
 struct NewLayerEntry {
   NewLayerEntry()
     : mAnimatedGeometryRoot(nullptr)
     , mASR(nullptr)
     , mClipChain(nullptr)
     , mScrollMetadataASR(nullptr)
@@ -1209,16 +1308,17 @@ public:
    * aData. Make sure that a real PaintedLayer exists for it, and set the final
    * visible region and opaque-content.
    */
   template<typename FindOpaqueBackgroundColorCallbackType>
   void FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueBackgroundColorCallbackType aFindOpaqueBackgroundColor);
 
 protected:
   friend class PaintedLayerData;
+  friend class FLBDisplayItemIterator;
 
   LayerManager::PaintedLayerCreationHint
     GetLayerCreationHint(AnimatedGeometryRoot* aAnimatedGeometryRoot);
 
   /**
    * Creates a new PaintedLayer and sets up the transform on the PaintedLayer
    * to account for scrolling.
    */
@@ -1472,16 +1572,53 @@ protected:
   nsDataHashtable<nsGenericHashKey<MaskLayerKey>, RefPtr<ImageLayer>>
     mRecycledMaskImageLayers;
   // Keep display port of AGR to avoid wasting time on doing the same
   // thing repeatly.
   AnimatedGeometryRoot* mLastDisplayPortAGR;
   nsRect mLastDisplayPortRect;
 };
 
+bool
+FLBDisplayItemIterator::ShouldFlattenNextItem() const
+{
+  if (!mNext) {
+    return false;
+  }
+
+  if (!mNext->ShouldFlattenAway(mBuilder)) {
+    return false;
+  }
+
+  if (mNext->GetType() == DisplayItemType::TYPE_OPACITY) {
+    nsDisplayOpacity* opacity = static_cast<nsDisplayOpacity*>(mNext);
+
+    if (opacity->OpacityAppliedToChildren()) {
+      // This is the previous opacity flattening path, where the opacity has
+      // been applied to children.
+      return true;
+    }
+
+    if (!mState->mManager->IsWidgetLayerManager()) {
+      // Do not flatten opacity inside an inactive layer tree.
+      return false;
+    }
+
+    LayerState layerState = mNext->GetLayerState(mState->mBuilder,
+                                                 mState->mManager,
+                                                 mState->mParameters);
+
+    // Do not flatten opacity if child display items require an active layer.
+    return (layerState == LayerState::LAYER_NONE ||
+            layerState == LayerState::LAYER_INACTIVE);
+  }
+
+  return true;
+}
+
 class PaintedDisplayItemLayerUserData : public LayerUserData
 {
 public:
   PaintedDisplayItemLayerUserData()
     : mForcedBackgroundColor(NS_RGBA(0, 0, 0, 0))
     , mXScale(1.f)
     , mYScale(1.f)
     , mAppUnitsPerDevPixel(0)
@@ -2599,16 +2736,23 @@ ContainerState::FindOpaqueBackgroundColo
   *aOutIntersectsLayer = true;
 
   // Scan the candidate's display items.
   nsIntRect deviceRect = aRect;
   nsRect appUnitRect = ToAppUnits(deviceRect, mAppUnitsPerDevPixel);
   appUnitRect.ScaleInverseRoundOut(mParameters.mXScale, mParameters.mYScale);
 
   for (auto& assignedItem : Reversed(aData->mAssignedDisplayItems)) {
+    if (assignedItem.mType != DisplayItemEntryType::ITEM ||
+        assignedItem.mHasOpacity) {
+      // |assignedItem| is either an effect marker, or within a flatten opacity
+      // group. In both cases, there is no opaque area.
+      continue;
+    }
+
     nsDisplayItem* item = assignedItem.mItem;
     bool snap;
     nsRect bounds = item->GetBounds(mBuilder, &snap);
     if (snap && mSnappingEnabled) {
       nsIntRect snappedBounds = ScaleToNearestPixels(bounds);
       if (!snappedBounds.Intersects(deviceRect))
         continue;
 
@@ -3168,16 +3312,18 @@ SetBackfaceHiddenForLayer(bool aBackface
   }
 }
 
 template<typename FindOpaqueBackgroundColorCallbackType>
 void ContainerState::FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueBackgroundColorCallbackType aFindOpaqueBackgroundColor)
 {
   PaintedLayerData* data = &aData;
 
+  MOZ_ASSERT(data->mOpacityIndices.IsEmpty());
+
   if (!data->mLayer) {
     // No layer was recycled, so we create a new one.
     RefPtr<PaintedLayer> paintedLayer = CreatePaintedLayer(data);
     data->mLayer = paintedLayer;
 
     NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, paintedLayer) < 0,
                  "Layer already in list???");
     mNewChildLayers[data->mNewChildLayersIndex].mLayer = paintedLayer.forget();
@@ -3236,16 +3382,21 @@ void ContainerState::FinishPaintedLayerD
     layer->SetClipRect(Nothing());
     FLB_LOG_PAINTED_LAYER_DECISION(data, "  Selected painted layer=%p\n", layer.get());
   }
 
   for (auto& item : data->mAssignedDisplayItems) {
     MOZ_ASSERT(item.mItem->GetType() != DisplayItemType::TYPE_LAYER_EVENT_REGIONS);
     MOZ_ASSERT(item.mItem->GetType() != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO);
 
+    if (item.mType == DisplayItemEntryType::POP_OPACITY) {
+      // Do not invalidate for end markers.
+      continue;
+    }
+
     InvalidateForLayerChange(item.mItem, data->mLayer, item.mDisplayItemData);
     mLayerBuilder->AddPaintedDisplayItem(data, item, *this, layer);
     item.mDisplayItemData = nullptr;
   }
 
   if (mLayerBuilder->IsBuildingRetainedLayers()) {
     newLayerEntry->mVisibleRegion = data->mVisibleRegion;
     newLayerEntry->mOpaqueRegion = data->mOpaqueRegion;
@@ -3443,42 +3594,78 @@ IsItemAreaInWindowOpaqueRegion(nsDisplay
     // the window.
     return false;
   }
   return aBuilder->GetWindowOpaqueRegion().Contains(aComponentAlphaBounds);
 }
 
 void
 PaintedLayerData::Accumulate(ContainerState* aState,
-                            nsDisplayItem* aItem,
-                            const nsIntRect& aVisibleRect,
-                            const DisplayItemClip& aClip,
-                            LayerState aLayerState,
-                            nsDisplayList* aList)
+                             nsDisplayItem* aItem,
+                             const nsIntRect& aVisibleRect,
+                             const DisplayItemClip& aClip,
+                             LayerState aLayerState,
+                             nsDisplayList* aList,
+                             DisplayItemEntryType aType)
 {
   FLB_LOG_PAINTED_LAYER_DECISION(this, "Accumulating dp=%s(%p), f=%p against pld=%p\n", aItem->Name(), aItem, aItem->Frame(), this);
 
+  const bool hasOpacity = mOpacityIndices.Length() > 0;
+
+  if (aType == DisplayItemEntryType::POP_OPACITY) {
+    MOZ_ASSERT(!mOpacityIndices.IsEmpty());
+    mOpacityIndices.RemoveLastElement();
+
+    AssignedDisplayItem item(aItem, aClip, aLayerState,
+                             nullptr, aType, hasOpacity);
+    mAssignedDisplayItems.AppendElement(Move(item));
+    return;
+  }
+
   if (aState->mBuilder->NeedToForceTransparentSurfaceForItem(aItem)) {
     mForceTransparentSurface = true;
   }
+
+  nsRect componentAlphaBounds;
   if (aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
     // Disable component alpha.
-    // Note that the transform (if any) on the PaintedLayer is always an integer translation so
-    // we don't have to factor that in here.
+    // Note that the transform (if any) on the PaintedLayer is always an integer
+    // translation so we don't have to factor that in here.
     aItem->DisableComponentAlpha();
+  } else {
+    componentAlphaBounds = aItem->GetComponentAlphaBounds(aState->mBuilder);
+
+    if (!componentAlphaBounds.IsEmpty()) {
+      // This display item needs background copy when pushing opacity group.
+      for (size_t i : mOpacityIndices) {
+        AssignedDisplayItem& item = mAssignedDisplayItems[i];
+        MOZ_ASSERT(item.mType == DisplayItemEntryType::PUSH_OPACITY ||
+                   item.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG);
+        item.mType = DisplayItemEntryType::PUSH_OPACITY_WITH_BG;
+      }
+    }
   }
 
   bool clipMatches = mItemClip == aClip;
   mItemClip = aClip;
 
+  DisplayItemData* currentData =
+    aItem->HasMergedFrames() ? nullptr : aItem->GetDisplayItemData();
+
   DisplayItemData* oldData =
-      aState->mLayerBuilder->GetOldLayerForFrame(aItem->Frame(),
-                                         aItem->GetPerFrameKey(),
-                                         aItem->HasMergedFrames() ? nullptr : aItem->GetDisplayItemData());
-  mAssignedDisplayItems.AppendElement(AssignedDisplayItem(aItem, aClip, aLayerState, oldData));
+    aState->mLayerBuilder->GetOldLayerForFrame(aItem->Frame(),
+                                               aItem->GetPerFrameKey(),
+                                               currentData);
+  AssignedDisplayItem item(aItem, aClip, aLayerState,
+                           oldData, aType, hasOpacity);
+  mAssignedDisplayItems.AppendElement(Move(item));
+
+  if (aType == DisplayItemEntryType::PUSH_OPACITY) {
+    mOpacityIndices.AppendElement(mAssignedDisplayItems.Length() - 1);
+  }
 
   if (aItem->MustPaintOnContentSide()) {
      mShouldPaintOnContentSide = true;
   }
 
   if (!mIsSolidColorInVisibleRegion && mOpaqueRegion.Contains(aVisibleRect) &&
       mVisibleRegion.Contains(aVisibleRect) && !mImage) {
     // A very common case! Most pages have a PaintedLayer with the page
@@ -3487,37 +3674,45 @@ PaintedLayerData::Accumulate(ContainerSt
     // The rest of this method won't do anything. mVisibleRegion and mOpaqueRegion
     // don't need updating. mVisibleRegion contains aVisibleRect already,
     // mOpaqueRegion contains aVisibleRect and therefore whatever the opaque
     // region of the item is. mVisibleRegion must contain mOpaqueRegion
     // and therefore aVisibleRect.
     return;
   }
 
-  nsIntRegion opaquePixels = aState->ComputeOpaqueRect(aItem,
-                                                       mAnimatedGeometryRoot, mASR, aClip, aList,
-                                                       &mHideAllLayersBelow, &mOpaqueForAnimatedGeometryRootParent);
-  opaquePixels.AndWith(aVisibleRect);
+  nsIntRegion opaquePixels;
+
+  // Active opacity means no opaque pixels.
+  if (!hasOpacity) {
+    opaquePixels = aState->ComputeOpaqueRect(aItem, mAnimatedGeometryRoot, mASR,
+                                             aClip, aList, &mHideAllLayersBelow,
+                                             &mOpaqueForAnimatedGeometryRootParent);
+    opaquePixels.AndWith(aVisibleRect);
+  }
 
   /* Mark as available for conversion to image layer if this is a nsDisplayImage and
    * it's the only thing visible in this layer.
    */
   if (nsIntRegion(aVisibleRect).Contains(mVisibleRegion) &&
       opaquePixels.Contains(mVisibleRegion) &&
       aItem->SupportsOptimizingToImage()) {
     mImage = static_cast<nsDisplayImageContainer*>(aItem);
     FLB_LOG_PAINTED_LAYER_DECISION(this, "  Tracking image: nsDisplayImageContainer covers the layer\n");
   } else if (mImage) {
     FLB_LOG_PAINTED_LAYER_DECISION(this, "  No longer tracking image\n");
     mImage = nullptr;
   }
 
   bool isFirstVisibleItem = mVisibleRegion.IsEmpty();
 
-  Maybe<nscolor> uniformColor = aItem->IsUniform(aState->mBuilder);
+  Maybe<nscolor> uniformColor;
+  if (!hasOpacity) {
+    uniformColor = aItem->IsUniform(aState->mBuilder);
+  }
 
   // Some display items have to exist (so they can set forceTransparentSurface
   // below) but don't draw anything. They'll return true for isUniform but
   // a color with opacity 0.
   if (!uniformColor || NS_GET_A(*uniformColor) > 0) {
     // Make sure that the visible area is covered by uniform pixels. In
     // particular this excludes cases where the edges of the item are not
     // pixel-aligned (thus the item will not be truly uniform).
@@ -3565,39 +3760,37 @@ PaintedLayerData::Accumulate(ContainerSt
        // transparent are always added to the opaque region. This helps ensure
        // that we get as much subpixel-AA as possible in the chrome.
        if (tmp.GetNumRects() <= 4 || aItem->Frame()->PresContext()->IsChrome()) {
         mOpaqueRegion = Move(tmp);
       }
     }
   }
 
-  if (!aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
-    nsRect componentAlpha = aItem->GetComponentAlphaBounds(aState->mBuilder);
-    if (!componentAlpha.IsEmpty()) {
-      nsIntRect componentAlphaRect =
-        aState->ScaleToOutsidePixels(componentAlpha, false).Intersect(aVisibleRect);
-      if (!mOpaqueRegion.Contains(componentAlphaRect)) {
-        if (IsItemAreaInWindowOpaqueRegion(aState->mBuilder, aItem,
-              componentAlpha.Intersect(aItem->GetVisibleRect()))) {
-          mNeedComponentAlpha = true;
-        } else {
-          aItem->DisableComponentAlpha();
-        }
+  if (!aState->mParameters.mDisableSubpixelAntialiasingInDescendants &&
+      !componentAlphaBounds.IsEmpty()) {
+    nsIntRect componentAlphaRect =
+      aState->ScaleToOutsidePixels(componentAlphaBounds, false).Intersect(aVisibleRect);
+
+    if (!mOpaqueRegion.Contains(componentAlphaRect)) {
+      if (IsItemAreaInWindowOpaqueRegion(aState->mBuilder, aItem,
+            componentAlphaBounds.Intersect(aItem->GetVisibleRect()))) {
+        mNeedComponentAlpha = true;
+      } else {
+        aItem->DisableComponentAlpha();
       }
     }
   }
 
   // Ensure animated text does not get flattened, even if it forces other
   // content in the container to be layerized. The content backend might
   // not support subpixel positioning of text that animated transforms can
   // generate. bug 633097
   if (aState->mParameters.mInActiveTransformedSubtree &&
-       (mNeedComponentAlpha ||
-         !aItem->GetComponentAlphaBounds(aState->mBuilder).IsEmpty())) {
+       (mNeedComponentAlpha || !componentAlphaBounds.IsEmpty())) {
     mDisableFlattening = true;
   }
 }
 
 nsRegion
 PaintedLayerData::CombinedTouchActionRegion()
 {
   nsRegion result;
@@ -4084,21 +4277,30 @@ ContainerState::ProcessDisplayItems(nsDi
 #endif
 
   if (!mManager->IsWidgetLayerManager()) {
     mPaintedLayerDataTree.InitializeForInactiveLayer(mContainerAnimatedGeometryRoot);
   }
 
   AnimatedGeometryRoot* lastAnimatedGeometryRoot = nullptr;
   nsPoint lastTopLeft;
-  FlattenedDisplayItemIterator iter(mBuilder, aList);
-  while (nsDisplayItem* i = iter.GetNext()) {
+
+  // Tracks the PaintedLayerData that the item will be accumulated in, if it is
+  // non-null. Currently only used with PUSH_OPACITY and POP_OPACITY markers.
+  PaintedLayerData* selectedPLD = nullptr;
+
+  FLBDisplayItemIterator iter(mBuilder, aList, this);
+  while (iter.HasNext()) {
+    DisplayItemEntry e = iter.GetNextEntry();
+    nsDisplayItem* i = e.mItem;
+    DisplayItemEntryType marker = e.mType;
+
+
     nsDisplayItem* item = i;
     MOZ_ASSERT(item);
-
     DisplayItemType itemType = item->GetType();
 
     // If the item is a event regions item, but is empty (has no regions in it)
     // then we should just throw it out
     if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
 #ifdef DEBUG
       hadLayerEventRegions = true;
 #endif
@@ -4120,30 +4322,33 @@ ContainerState::ProcessDisplayItems(nsDi
       if (hitTestInfo->Area().IsEmpty()) {
         continue;
       }
     }
 
     // Only allow either LayerEventRegions or CompositorHitTestInfo items.
     MOZ_ASSERT(!(hadLayerEventRegions && hadCompositorHitTestInfo));
 
-
     // Peek ahead to the next item and see if it can be merged with the current
     // item. We create a list of consecutive items that can be merged together.
     AutoTArray<nsDisplayItem*, 1> mergedItems;
-    mergedItems.AppendElement(item);
-    while (nsDisplayItem* peek = iter.PeekNext()) {
-      if (!item->CanMerge(peek)) {
-        break;
+
+    if (marker == DisplayItemEntryType::ITEM) {
+      mergedItems.AppendElement(item);
+
+      while (nsDisplayItem* peek = iter.PeekNext()) {
+        if (!item->CanMerge(peek)) {
+          break;
+        }
+
+        mergedItems.AppendElement(peek);
+
+        // Move the iterator forward since we will merge this item.
+        i = iter.GetNext();
       }
-
-      mergedItems.AppendElement(peek);
-
-      // Move the iterator forward since we will merge this item.
-      i = iter.GetNext();
     }
 
     if (mergedItems.Length() > 1) {
       // We have items that can be merged together. Merge them into a temporary
       // item and process that item immediately.
       item = mBuilder->MergeItems(mergedItems);
       MOZ_ASSERT(item && itemType == item->GetType());
     }
@@ -4159,20 +4364,24 @@ ContainerState::ProcessDisplayItems(nsDi
 
     if (mParameters.mForEventsAndPluginsOnly && !item->GetChildren() &&
         (itemType != DisplayItemType::TYPE_LAYER_EVENT_REGIONS &&
          itemType != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO &&
          itemType != DisplayItemType::TYPE_PLUGIN)) {
       continue;
     }
 
-    LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
-    if (layerState == LAYER_INACTIVE &&
-        nsDisplayItem::ForceActiveLayers()) {
-      layerState = LAYER_ACTIVE;
+    LayerState layerState = LAYER_NONE;
+
+    if (marker == DisplayItemEntryType::ITEM) {
+      layerState = item->GetLayerState(mBuilder, mManager, mParameters);
+
+      if (layerState == LAYER_INACTIVE && nsDisplayItem::ForceActiveLayers()) {
+        layerState = LAYER_ACTIVE;
+      }
     }
 
     bool forceInactive = false;
     AnimatedGeometryRoot* animatedGeometryRoot;
     const ActiveScrolledRoot* itemASR = nullptr;
     const DisplayItemClipChain* layerClipChain = nullptr;
 
     if (mManager->IsWidgetLayerManager()) {
@@ -4265,16 +4474,21 @@ ContainerState::ProcessDisplayItems(nsDi
     if (layerState == LAYER_ACTIVE_FORCE ||
         (layerState == LAYER_INACTIVE && !mManager->IsWidgetLayerManager()) ||
         (!forceInactive &&
          (layerState == LAYER_ACTIVE_EMPTY ||
           layerState == LAYER_ACTIVE))) {
 
       layerCount++;
 
+      // Currently we do not support flattening effects within nested inactive
+      // layer trees.
+      MOZ_ASSERT(selectedPLD == nullptr);
+      MOZ_ASSERT(marker == DisplayItemEntryType::ITEM);
+
       // LAYER_ACTIVE_EMPTY means the layer is created just for its metadata.
       // We should never see an empty layer with any visible content!
       NS_ASSERTION(layerState != LAYER_ACTIVE_EMPTY ||
                    itemVisibleRect.IsEmpty(),
                    "State is LAYER_ACTIVE_EMPTY but visible rect is not.");
 
       // As long as the new layer isn't going to be a PaintedLayer,
       // InvalidateForLayerChange doesn't need the new layer pointer.
@@ -4584,35 +4798,43 @@ ContainerState::ProcessDisplayItems(nsDi
         oldData =
           mLayerBuilder->GetOldLayerForFrame(item->Frame(), item->GetPerFrameKey());
         mLayerBuilder->StoreDataForFrame(item, ownLayer, layerState, oldData);
       }
     } else {
       const bool backfaceHidden = item->In3DContextAndBackfaceIsHidden();
       const nsIFrame* referenceFrame = item->ReferenceFrame();
 
-      PaintedLayerData* paintedLayerData =
-        mPaintedLayerDataTree.FindPaintedLayerFor(animatedGeometryRoot, itemASR, layerClipChain,
-                                                  itemVisibleRect, backfaceHidden,
-                                                  [&](PaintedLayerData* aData) {
-          NewPaintedLayerData(aData, animatedGeometryRoot, itemASR,
-                              layerClipChain, scrollMetadataASR, topLeft,
-                              referenceFrame, backfaceHidden);
+      PaintedLayerData* paintedLayerData = selectedPLD;
+
+      if (!selectedPLD) {
+        MOZ_ASSERT(marker != DisplayItemEntryType::POP_OPACITY);
+
+        paintedLayerData =
+          mPaintedLayerDataTree.FindPaintedLayerFor(animatedGeometryRoot, itemASR, layerClipChain,
+                                                    itemVisibleRect, backfaceHidden,
+                                                    [&](PaintedLayerData* aData) {
+            NewPaintedLayerData(aData, animatedGeometryRoot, itemASR,
+                                layerClipChain, scrollMetadataASR, topLeft,
+                                referenceFrame, backfaceHidden);
         });
+      }
+      MOZ_ASSERT(paintedLayerData);
 
       if (itemType == DisplayItemType::TYPE_LAYER_EVENT_REGIONS) {
         nsDisplayLayerEventRegions* eventRegions =
           static_cast<nsDisplayLayerEventRegions*>(item);
         paintedLayerData->AccumulateEventRegions(this, eventRegions);
       } else if (itemType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO) {
         nsDisplayCompositorHitTestInfo* hitTestInfo =
           static_cast<nsDisplayCompositorHitTestInfo*>(item);
         paintedLayerData->AccumulateHitTestInfo(this, hitTestInfo);
       } else {
-        paintedLayerData->Accumulate(this, item, itemVisibleRect, itemClip, layerState, aList);
+        paintedLayerData->Accumulate(this, item, itemVisibleRect, itemClip,
+                                     layerState, aList, marker);
 
         if (!paintedLayerData->mLayer) {
           // Try to recycle the old layer of this display item.
           RefPtr<PaintedLayer> layer =
             AttemptToRecyclePaintedLayer(animatedGeometryRoot, item,
                                          topLeft, referenceFrame);
           if (layer) {
             paintedLayerData->mLayer = layer;
@@ -4621,23 +4843,37 @@ ContainerState::ProcessDisplayItems(nsDi
             paintedLayerData->mAssignedDisplayItems.SetCapacity(userData->mLastItemCount);
 
             NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0,
                          "Layer already in list???");
             mNewChildLayers[paintedLayerData->mNewChildLayersIndex].mLayer = layer.forget();
           }
         }
       }
+
+      if (marker == DisplayItemEntryType::PUSH_OPACITY) {
+        selectedPLD = paintedLayerData;
+      }
+
+      if (marker == DisplayItemEntryType::POP_OPACITY ) {
+        MOZ_ASSERT(selectedPLD);
+
+        if (selectedPLD->mOpacityIndices.IsEmpty()) {
+          selectedPLD = nullptr;
+        }
+      }
     }
 
     nsDisplayList* childItems = item->GetSameCoordinateSystemChildren();
     if (childItems && childItems->NeedsTransparentSurface()) {
       aList->SetNeedsTransparentSurface();
     }
   }
+
+  MOZ_ASSERT(selectedPLD == nullptr);
 }
 
 void
 ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
                                          PaintedLayer* aNewLayer,
                                          DisplayItemData* aData)
 {
   NS_ASSERTION(aItem->GetPerFrameKey(),
@@ -4960,23 +5196,27 @@ FrameLayerBuilder::StoreDataForFrame(nsI
   data->BeginUpdate(aLayer, aState);
 
   lmd->mDisplayItems.PutEntry(data);
 }
 
 AssignedDisplayItem::AssignedDisplayItem(nsDisplayItem* aItem,
                                          const DisplayItemClip& aClip,
                                          LayerState aLayerState,
-                                         DisplayItemData* aData)
+                                         DisplayItemData* aData,
+                                         DisplayItemEntryType aType,
+                                         const bool aHasOpacity)
   : mItem(aItem)
   , mClip(aClip)
   , mLayerState(aLayerState)
   , mDisplayItemData(aData)
   , mReused(aItem->IsReused())
   , mMerged(aItem->HasMergedFrames())
+  , mType(aType)
+  , mHasOpacity(aHasOpacity)
 {}
 
 AssignedDisplayItem::~AssignedDisplayItem()
 {
   if (mInactiveLayerManager) {
     mInactiveLayerManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
   }
 }
@@ -5907,16 +6147,26 @@ FrameLayerBuilder::RecomputeVisibilityFo
                  NSIntPixelsToAppUnits(aOffset.y, aAppUnitsPerDevPixel));
   visible.ScaleInverseRoundOut(aXScale, aYScale);
 
   for (i = aItems.Length(); i > 0; --i) {
     AssignedDisplayItem* cdi = &aItems[i - 1];
     if (!cdi->mItem) {
       continue;
     }
+
+    if (cdi->mType == DisplayItemEntryType::POP_OPACITY ||
+        (cdi->mType == DisplayItemEntryType::ITEM && cdi->mHasOpacity)) {
+      // The visibility calculations are skipped when the item is an effect end
+      // marker, or when the display item is within a flattened opacity group.
+      // This is because RecomputeVisibility has already been called for the
+      // group item, and all the children.
+      continue;
+    }
+
     const DisplayItemClip& clip = cdi->mItem->GetClip();
 
     NS_ASSERTION(AppUnitsPerDevPixel(cdi->mItem) == aAppUnitsPerDevPixel,
                  "a painted layer should contain items only at the same zoom");
 
     MOZ_ASSERT(clip.HasClip() || clip.GetRoundedRectCount() == 0,
                "If we have rounded rects, we must have a clip rect");
 
@@ -5941,16 +6191,80 @@ FrameLayerBuilder::RecomputeVisibilityFo
       // Don't let the visible region get too complex.
       if (newVisible.GetNumRects() <= 15) {
         visible = Move(newVisible);
       }
     }
   }
 }
 
+/**
+ * Sets the clip chain and starts a new opacity group.
+ */
+static void
+PushOpacity(gfxContext* aContext,
+            const nsRect& aPaintRect,
+            AssignedDisplayItem& aItem,
+            const int32_t aAUPDP)
+{
+  MOZ_ASSERT(aItem.mType == DisplayItemEntryType::PUSH_OPACITY ||
+             aItem.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG);
+  MOZ_ASSERT(aItem.mItem->GetType() == DisplayItemType::TYPE_OPACITY);
+
+  aContext->Save();
+
+  DisplayItemClip clip;
+  clip.SetTo(aPaintRect);
+  clip.IntersectWith(aItem.mItem->GetClip());
+  clip.ApplyTo(aContext, aAUPDP);
+
+  nsDisplayOpacity* opacityItem = static_cast<nsDisplayOpacity*>(aItem.mItem);
+  const float opacity = opacityItem->GetOpacity();
+
+  if (aItem.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG) {
+    aContext->PushGroupAndCopyBackground(gfxContentType::COLOR_ALPHA, opacity);
+  } else {
+    aContext->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity);
+  }
+}
+
+/**
+ * Tracks item clips per opacity nesting level.
+ */
+struct ClipTracker {
+  explicit ClipTracker(gfxContext* aContext)
+    : mContext(aContext)
+  {}
+
+  bool HasClip(int aOpacityNesting) const
+  {
+    return !mClips.IsEmpty() &&
+            mClips.LastElement() == aOpacityNesting;
+  }
+
+  void PopClipIfNeeded(int aOpacityNesting)
+  {
+    if (!HasClip(aOpacityNesting)) {
+      return;
+    }
+
+    mContext->Restore();
+    mClips.RemoveLastElement();
+  };
+
+  void SaveClip(int aOpacityNesting)
+  {
+    mContext->Save();
+    mClips.AppendElement(aOpacityNesting);
+  };
+
+  AutoTArray<int, 2> mClips;
+  gfxContext* mContext;
+};
+
 void
 FrameLayerBuilder::PaintItems(nsTArray<AssignedDisplayItem>& aItems,
                               const nsIntRect& aRect,
                               gfxContext *aContext,
                               nsDisplayListBuilder* aBuilder,
                               nsPresContext* aPresContext,
                               const nsIntPoint& aOffset,
                               float aXScale, float aYScale)
@@ -5958,83 +6272,112 @@ FrameLayerBuilder::PaintItems(nsTArray<A
   DrawTarget& aDrawTarget = *aContext->GetDrawTarget();
 
   int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
   nsRect boundRect = ToAppUnits(aRect, appUnitsPerDevPixel);
   boundRect.MoveBy(NSIntPixelsToAppUnits(aOffset.x, appUnitsPerDevPixel),
                  NSIntPixelsToAppUnits(aOffset.y, appUnitsPerDevPixel));
   boundRect.ScaleInverseRoundOut(aXScale, aYScale);
 
-  DisplayItemClip currentClip;
-  bool currentClipIsSetInContext = false;
-  DisplayItemClip tmpClip;
+  DisplayItemClip currentClip, tmpClip;
+
+  int opacityNesting = 0;
+  ClipTracker clipTracker(aContext);
 
   for (uint32_t i = 0; i < aItems.Length(); ++i) {
-    AssignedDisplayItem* cdi = &aItems[i];
-    if (!cdi->mItem) {
+    AssignedDisplayItem& cdi = aItems[i];
+    nsDisplayItem* item = cdi.mItem;
+
+    if (!item) {
+      MOZ_ASSERT(cdi.mType == DisplayItemEntryType::ITEM);
       continue;
     }
 
-    nsRect paintRect = cdi->mItem->GetVisibleRect().Intersect(boundRect);
-    if (paintRect.IsEmpty())
+    const nsRect& visibleRect = item->GetVisibleRect();
+
+    nsRect paintRect = visibleRect.Intersect(boundRect);
+    if (paintRect.IsEmpty()) {
       continue;
+    }
 
 #ifdef MOZ_DUMP_PAINTING
     AUTO_PROFILER_LABEL_DYNAMIC_CSTR("FrameLayerBuilder::PaintItems", GRAPHICS,
-                                     cdi->mItem->Name());
+                                     item->Name());
 #else
     AUTO_PROFILER_LABEL("FrameLayerBuilder::PaintItems", GRAPHICS);
 #endif
 
+    MOZ_ASSERT((opacityNesting == 0 && !cdi.mHasOpacity) ||
+               (opacityNesting > 0 && cdi.mHasOpacity));
+
+    if (cdi.mType == DisplayItemEntryType::PUSH_OPACITY ||
+        cdi.mType == DisplayItemEntryType::PUSH_OPACITY_WITH_BG) {
+      clipTracker.PopClipIfNeeded(opacityNesting);
+      PushOpacity(aContext, paintRect, cdi, appUnitsPerDevPixel);
+      opacityNesting++;
+    }
+
+    if (cdi.mType == DisplayItemEntryType::POP_OPACITY) {
+      MOZ_ASSERT(item->GetType() == DisplayItemType::TYPE_OPACITY);
+      MOZ_ASSERT(opacityNesting > 0);
+
+      clipTracker.PopClipIfNeeded(opacityNesting);
+      aContext->PopGroupAndBlend();
+      aContext->Restore();
+      opacityNesting--;
+    }
+
+    if (cdi.mType != DisplayItemEntryType::ITEM) {
+      continue;
+    }
+
     // If the new desired clip state is different from the current state,
     // update the clip.
-    const DisplayItemClip* clip = &cdi->mItem->GetClip();
+    const DisplayItemClip* clip = &item->GetClip();
     if (clip->GetRoundedRectCount() > 0 &&
-        !clip->IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) {
+        !clip->IsRectClippedByRoundedCorner(visibleRect)) {
       tmpClip = *clip;
       tmpClip.RemoveRoundedCorners();
       clip = &tmpClip;
     }
-    if (currentClipIsSetInContext != clip->HasClip() ||
+    if (clipTracker.HasClip(opacityNesting) != clip->HasClip() ||
         (clip->HasClip() && *clip != currentClip)) {
-      if (currentClipIsSetInContext) {
-        aContext->Restore();
-      }
-      currentClipIsSetInContext = clip->HasClip();
-      if (currentClipIsSetInContext) {
+      clipTracker.PopClipIfNeeded(opacityNesting);
+
+      if (clip->HasClip()) {
         currentClip = *clip;
-        aContext->Save();
-        currentClip.ApplyTo(aContext, aPresContext->AppUnitsPerDevPixel());
+        clipTracker.SaveClip(opacityNesting);
+        currentClip.ApplyTo(aContext, appUnitsPerDevPixel);
         aContext->NewPath();
       }
     }
 
-    if (cdi->mInactiveLayerManager) {
+    if (cdi.mInactiveLayerManager) {
       bool saved = aDrawTarget.GetPermitSubpixelAA();
-      PaintInactiveLayer(aBuilder, cdi->mInactiveLayerManager, cdi->mItem, aContext, aContext);
+      PaintInactiveLayer(aBuilder, cdi.mInactiveLayerManager,
+                         item, aContext, aContext);
       aDrawTarget.SetPermitSubpixelAA(saved);
     } else {
-      nsIFrame* frame = cdi->mItem->Frame();
+      nsIFrame* frame = item->Frame();
       if (aBuilder->IsPaintingToWindow()) {
         frame->AddStateBits(NS_FRAME_PAINTED_THEBES);
       }
 #ifdef MOZ_DUMP_PAINTING
       if (gfxEnv::DumpPaintItems()) {
-        DebugPaintItem(aDrawTarget, aPresContext, cdi->mItem, aBuilder);
+        DebugPaintItem(aDrawTarget, aPresContext, item, aBuilder);
       } else
 #endif
       {
-        cdi->mItem->Paint(aBuilder, aContext);
+        item->Paint(aBuilder, aContext);
       }
     }
   }
 
-  if (currentClipIsSetInContext) {
-    aContext->Restore();
-  }
+  clipTracker.PopClipIfNeeded(opacityNesting);
+  MOZ_ASSERT(opacityNesting == 0);
 }
 
 /**
  * Returns true if it is preferred to draw the list of display
  * items separately for each rect in the visible region rather
  * than clipping to a complex region.
  */
 static bool
--- a/layout/painting/FrameLayerBuilder.h
+++ b/layout/painting/FrameLayerBuilder.h
@@ -40,16 +40,23 @@ class ImageLayer;
 } // namespace layers
 
 class FrameLayerBuilder;
 class LayerManagerData;
 class PaintedLayerData;
 class ContainerState;
 class PaintedDisplayItemLayerUserData;
 
+enum class DisplayItemEntryType {
+  ITEM,
+  PUSH_OPACITY,
+  PUSH_OPACITY_WITH_BG,
+  POP_OPACITY
+};
+
 /**
   * Retained data storage:
   *
   * Each layer manager (widget, and inactive) stores a LayerManagerData object
   * that keeps a hash-set of DisplayItemData items that were drawn into it.
   * Each frame also keeps a list of DisplayItemData pointers that were
   * created for that frame. DisplayItemData objects manage these lists automatically.
   *
@@ -210,33 +217,38 @@ public:
   bool mIsInfinite;
 };
 
 struct AssignedDisplayItem
 {
   AssignedDisplayItem(nsDisplayItem* aItem,
                       const DisplayItemClip& aClip,
                       LayerState aLayerState,
-                      DisplayItemData* aData);
+                      DisplayItemData* aData,
+                      DisplayItemEntryType aType,
+                      const bool aHasOpacity);
   ~AssignedDisplayItem();
 
   nsDisplayItem* mItem;
   DisplayItemClip mClip;
   LayerState mLayerState;
   DisplayItemData* mDisplayItemData;
 
   /**
    * If the display item is being rendered as an inactive
    * layer, then this stores the layer manager being
    * used for the inactive transaction.
    */
   RefPtr<layers::LayerManager> mInactiveLayerManager;
 
   bool mReused;
   bool mMerged;
+
+  DisplayItemEntryType mType;
+  bool mHasOpacity;
 };
 
 
 struct ContainerLayerParameters {
   ContainerLayerParameters()
     : mXScale(1)
     , mYScale(1)
     , mLayerContentsVisibleRect(nullptr)
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -6404,16 +6404,17 @@ nsresult nsDisplayWrapper::WrapListsInPl
 
 nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder,
                                    nsIFrame* aFrame, nsDisplayList* aList,
                                    const ActiveScrolledRoot* aActiveScrolledRoot,
                                    bool aForEventsAndPluginsOnly)
     : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, true)
     , mOpacity(aFrame->StyleEffects()->mOpacity)
     , mForEventsAndPluginsOnly(aForEventsAndPluginsOnly)
+    , mOpacityAppliedToChildren(false)
 {
   MOZ_COUNT_CTOR(nsDisplayOpacity);
   mState.mOpacity = mOpacity;
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayOpacity::~nsDisplayOpacity() {
   MOZ_COUNT_DTOR(nsDisplayOpacity);
@@ -6539,37 +6540,18 @@ CollectItemsWithOpacity(nsDisplayList* a
 
     aArray.AppendElement(i);
   }
 
   return true;
 }
 
 bool
-nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
-{
-  if (mFrame->GetPrevContinuation() ||
-      mFrame->GetNextContinuation()) {
-    // If we've been split, then we might need to merge, so
-    // don't flatten us away.
-    return false;
-  }
-
-  if (NeedsActiveLayer(aBuilder, mFrame) || mOpacity == 0.0) {
-    // If our opacity is zero then we'll discard all descendant display items
-    // except for layer event regions, so there's no point in doing this
-    // optimization (and if we do do it, then invalidations of those descendants
-    // might trigger repainting).
-    return false;
-  }
-
-  if (mList.IsEmpty()) {
-    return false;
-  }
-
+nsDisplayOpacity::ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder)
+{
   // Only try folding our opacity down if we have at most kMaxChildCount
   // children that don't overlap and can all apply the opacity to themselves.
   static const size_t kMaxChildCount = 3;
 
   // Iterate through the child display list and copy at most kMaxChildCount
   // child display item pointers to a temporary list.
   AutoTArray<nsDisplayItem*, kMaxChildCount> items;
   if (!CollectItemsWithOpacity(&mList, items, kMaxChildCount)) {
@@ -6596,19 +6578,51 @@ nsDisplayOpacity::ShouldFlattenAway(nsDi
       }
     }
   }
 
   for (uint32_t i = 0; i < childCount; i++) {
     children[i].item->ApplyOpacity(aBuilder, mOpacity, mClipChain);
   }
 
+  mOpacityAppliedToChildren = true;
   return true;
 }
 
+bool
+nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
+{
+  // ShouldFlattenAway() should be called only once during painting.
+  MOZ_ASSERT(!mOpacityAppliedToChildren);
+
+  if (mFrame->GetPrevContinuation() ||
+      mFrame->GetNextContinuation()) {
+    // If we've been split, then we might need to merge, so
+    // don't flatten us away.
+    return false;
+  }
+
+  if (NeedsActiveLayer(aBuilder, mFrame) || mOpacity == 0.0) {
+    // If our opacity is zero then we'll discard all descendant display items
+    // except for layer event regions, so there's no point in doing this
+    // optimization (and if we do do it, then invalidations of those descendants
+    // might trigger repainting).
+    return false;
+  }
+
+  if (mList.IsEmpty()) {
+    return false;
+  }
+
+  // Return true if we successfully applied opacity to child items, or if
+  // WebRender is not in use. In the latter case, the opacity gets flattened and
+  // applied during layer building.
+  return ApplyOpacityToChildren(aBuilder) || !gfxVars::UseWebRender();
+}
+
 nsDisplayItem::LayerState
 nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
                                 LayerManager* aManager,
                                 const ContainerLayerParameters& aParameters) {
   // If we only created this item so that we'd get correct nsDisplayEventRegions for child
   // frames, then force us to inactive to avoid unnecessary layerization changes for content
   // that won't ever be painted.
   if (mForEventsAndPluginsOnly) {
@@ -6636,16 +6650,30 @@ nsDisplayOpacity::ComputeVisibility(nsDi
   nsRect bounds = GetClippedBounds(aBuilder);
   nsRegion visibleUnderChildren;
   visibleUnderChildren.And(*aVisibleRegion, bounds);
   return
     nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren);
 }
 
 void
+nsDisplayOpacity::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+                                            const nsDisplayItemGeometry* aGeometry,
+                                            nsRegion* aInvalidRegion) const
+{
+  const nsDisplayOpacityGeometry* geometry =
+    static_cast<const nsDisplayOpacityGeometry*>(aGeometry);
+
+  bool snap;
+  if (mOpacity != geometry->mOpacity) {
+    aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
+  }
+}
+
+void
 nsDisplayOpacity::WriteDebugInfo(std::stringstream& aStream)
 {
   aStream << " (opacity " << mOpacity << ")";
 }
 
 bool
 nsDisplayOpacity::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                           mozilla::wr::IpcResourceUpdateQueue& aResources,
@@ -9653,28 +9681,43 @@ nsDisplayMask::CreateWebRenderCommands(m
   float appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   nsRect displayBound = GetBounds(aDisplayListBuilder, &snap);
   LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(displayBound, appUnitsPerDevPixel);
 
   Maybe<wr::WrImageMask> mask = aManager->CommandBuilder().BuildWrMaskImage(this, aBuilder, aResources,
                                                                             aSc, aDisplayListBuilder,
                                                                             bounds);
   if (mask) {
+    auto layoutBounds = wr::ToRoundedLayoutRect(bounds);
     wr::WrClipId clipId = aBuilder.DefineClip(Nothing(), Nothing(),
-        wr::ToRoundedLayoutRect(bounds), nullptr, mask.ptr());
-    // Don't record this clip push in aBuilder's internal clip stack, because
-    // otherwise any nested ScrollingLayersHelper instances that are created
-    // will get confused about which clips are pushed.
-    aBuilder.PushClip(clipId, GetClipChain());
+        layoutBounds, nullptr, mask.ptr());
+
+    // Create a new stacking context to attach the mask to, ensuring the mask is
+    // applied to the aggregate, and not the individual elements.
+
+    // The stacking context shouldn't have any offset.
+    layoutBounds.origin.x = 0;
+    layoutBounds.origin.y = 0;
+
+    aBuilder.PushStackingContext(/*aBounds: */ layoutBounds,
+                                 /*aClipNodeId: */ &clipId,
+                                 /*aAnimation: */ nullptr,
+                                 /*aOpacity: */ nullptr,
+                                 /*aTransform: */ nullptr,
+                                 /*aTransformStyle: */ wr::TransformStyle::Flat,
+                                 /*aPerspective: */ nullptr,
+                                 /*aMixBlendMode: */ wr::MixBlendMode::Normal,
+                                 /*aFilters: */ nsTArray<wr::WrFilterOp>(),
+                                 /*aBackfaceVisible: */ true);
   }
 
   nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aResources, aSc, aManager, aDisplayListBuilder);
 
   if (mask) {
-    aBuilder.PopClip(GetClipChain());
+    aBuilder.PopStackingContext();
   }
 
   return true;
 }
 
 Maybe<nsRect>
 nsDisplayMask::GetClipWithRespectToASR(nsDisplayListBuilder* aBuilder,
                                        const ActiveScrolledRoot* aASR) const
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -3202,16 +3202,102 @@ private:
   // is empty (i.e. everything that was visible is covered by some
   // opaque content in this list).
   bool mIsOpaque;
   // This is set to true by FrameLayerBuilder if any display item in this
   // list needs to force the surface containing this list to be transparent.
   bool mForceTransparentSurface;
 };
 
+class FlattenedDisplayItemIterator
+{
+public:
+  FlattenedDisplayItemIterator(nsDisplayListBuilder* aBuilder,
+                               nsDisplayList* aList,
+                               const bool aResolveFlattening = true)
+    : mBuilder(aBuilder)
+    , mNext(aList->GetBottom())
+  {
+    if (aResolveFlattening) {
+      // This is done conditionally in case subclass overrides
+      // ShouldFlattenNextItem().
+      ResolveFlattening();
+    }
+  }
+
+  virtual ~FlattenedDisplayItemIterator()
+  {
+    MOZ_ASSERT(!HasNext());
+  }
+
+  nsDisplayItem* GetNext()
+  {
+    nsDisplayItem* next = mNext;
+
+    // Advance mNext to the following item
+    if (next) {
+      mNext = mNext->GetAbove();
+      ResolveFlattening();
+    }
+    return next;
+  }
+
+  bool HasNext() const
+  {
+    return mNext || !mStack.IsEmpty();
+  }
+
+  nsDisplayItem* PeekNext()
+  {
+    return mNext;
+  }
+
+protected:
+  bool AtEndOfNestedList() const
+  {
+    return !mNext && mStack.Length() > 0;
+  }
+
+  virtual bool ShouldFlattenNextItem() const
+  {
+    return mNext && mNext->ShouldFlattenAway(mBuilder);
+  }
+
+  void ResolveFlattening()
+  {
+    // Handle the case where we reach the end of a nested list, or the current
+    // item should start a new nested list. Repeat this until we find an actual
+    // item, or the very end of the outer list.
+    while (AtEndOfNestedList() || ShouldFlattenNextItem()) {
+      if (AtEndOfNestedList()) {
+        // Pop the last item off the stack.
+        mNext = mStack.LastElement();
+        EndNested(mNext);
+        mStack.RemoveElementAt(mStack.Length() - 1);
+        // We stored the item that was flattened, so advance to the next.
+        mNext = mNext->GetAbove();
+      } else {
+        // This item wants to be flattened. Store the current item on the stack,
+        // and use the first item in the child list instead.
+        mStack.AppendElement(mNext);
+        StartNested(mNext);
+        nsDisplayList* childItems = mNext->GetSameCoordinateSystemChildren();
+        mNext = childItems->GetBottom();
+      }
+    }
+  }
+
+  virtual void EndNested(nsDisplayItem* aItem) {}
+  virtual void StartNested(nsDisplayItem* aItem) {}
+
+  nsDisplayListBuilder* mBuilder;
+  nsDisplayItem* mNext;
+  AutoTArray<nsDisplayItem*, 10> mStack;
+};
+
 /**
  * This is passed as a parameter to nsIFrame::BuildDisplayList. That method
  * will put any generated items onto the appropriate list given here. It's
  * basically just a collection with one list for each separate stacking layer.
  * The lists themselves are external to this object and thus can be shared
  * with others. Some of the list pointers may even refer to the same list.
  */
 class nsDisplayListSet {
@@ -5159,30 +5245,37 @@ protected:
  * set by the stacking context root frame's 'opacity' style.
  */
 class nsDisplayOpacity : public nsDisplayWrapList {
 public:
   nsDisplayOpacity(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                    nsDisplayList* aList,
                    const ActiveScrolledRoot* aActiveScrolledRoot,
                    bool aForEventsAndPluginsOnly);
+
   nsDisplayOpacity(nsDisplayListBuilder* aBuilder,
                    const nsDisplayOpacity& aOther)
     : nsDisplayWrapList(aBuilder, aOther)
     , mOpacity(aOther.mOpacity)
     , mForEventsAndPluginsOnly(aOther.mForEventsAndPluginsOnly)
-  {}
+    , mOpacityAppliedToChildren(false)
+  {
+    // We should not try to merge flattened opacities.
+    MOZ_ASSERT(!aOther.mOpacityAppliedToChildren);
+  }
+
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayOpacity();
 #endif
 
   virtual void RestoreState() override
   {
     nsDisplayItem::RestoreState();
     mOpacity = mState.mOpacity;
+    mOpacityAppliedToChildren = false;
   }
 
   virtual nsDisplayWrapList* Clone(nsDisplayListBuilder* aBuilder) const override
   {
     MOZ_COUNT_CTOR(nsDisplayOpacity);
     return MakeDisplayItem<nsDisplayOpacity>(aBuilder, *this);
   }
 
@@ -5200,51 +5293,63 @@ public:
   virtual bool CanMerge(const nsDisplayItem* aItem) const override
   {
     // items for the same content element should be merged into a single
     // compositing group
     // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
     return HasSameTypeAndClip(aItem) && HasSameContent(aItem);
   }
 
+  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override
+  {
+    return new nsDisplayOpacityGeometry(this, aBuilder, mOpacity);
+  }
+
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
-                                         nsRegion* aInvalidRegion) const override
-  {
-    // We don't need to compute an invalidation region since we have LayerTreeInvalidation
-  }
+                                         nsRegion* aInvalidRegion) const override;
+
   virtual bool IsInvalid(nsRect& aRect) const override
   {
     if (mForEventsAndPluginsOnly) {
       return false;
     }
     return nsDisplayWrapList::IsInvalid(aRect);
   }
   virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
                             float aOpacity,
                             const DisplayItemClipChain* aClip) override;
   virtual bool CanApplyOpacity() const override;
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
+
+  /**
+   * Returns true if ShouldFlattenAway() applied opacity to children.
+   */
+  bool OpacityAppliedToChildren() const { return mOpacityAppliedToChildren; }
+
   static bool NeedsActiveLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
   NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)
   virtual void WriteDebugInfo(std::stringstream& aStream) override;
 
   bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override;
 
   virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        mozilla::wr::IpcResourceUpdateQueue& aResources,
                                        const StackingContextHelper& aSc,
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder) override;
 
   float GetOpacity() { return mOpacity; }
 
 private:
+  bool ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder);
+
   float mOpacity;
   bool mForEventsAndPluginsOnly;
+  bool mOpacityAppliedToChildren;
 
   struct {
     float mOpacity;
   } mState;
 };
 
 class nsDisplayBlendMode : public nsDisplayWrapList {
 public:
@@ -6770,82 +6875,16 @@ public:
   // (i.e. left and right respectively in horizontal writing modes,
   // regardless of bidi directionality; top and bottom in vertical modes).
   nscoord mVisIStartEdge;
   nscoord mVisIEndEdge;
   // Cached result of mFrame->IsSelected().  Only initialized when needed.
   mutable mozilla::Maybe<bool> mIsFrameSelected;
 };
 
-class FlattenedDisplayItemIterator
-{
-public:
-  FlattenedDisplayItemIterator(nsDisplayListBuilder* aBuilder,
-                               nsDisplayList* aList)
-    : mBuilder(aBuilder)
-    , mNext(aList->GetBottom())
-  {
-    ResolveFlattening();
-  }
-
-  nsDisplayItem* GetNext()
-  {
-    nsDisplayItem* next = mNext;
-
-    // Advance mNext to the following item
-    if (next) {
-      mNext = mNext->GetAbove();
-      ResolveFlattening();
-    }
-    return next;
-  }
-
-  nsDisplayItem* PeekNext()
-  {
-    return mNext;
-  }
-
-private:
-  bool AtEndOfNestedList()
-  {
-    return !mNext && mStack.Length() > 0;
-  }
-
-  bool ShouldFlattenNextItem()
-  {
-    return mNext && mNext->ShouldFlattenAway(mBuilder);
-  }
-
-  void ResolveFlattening()
-  {
-    // Handle the case where we reach the end of a nested list, or the current
-    // item should start a new nested list. Repeat this until we find an actual
-    // item, or the very end of the outer list.
-    while (AtEndOfNestedList() || ShouldFlattenNextItem()) {
-      if (AtEndOfNestedList()) {
-        // Pop the last item off the stack.
-        mNext = mStack.PopLastElement();
-        // We stored the item that was flattened, so advance to the next.
-        mNext = mNext->GetAbove();
-      } else {
-        // This item wants to be flattened. Store the current item on the stack,
-        // and use the first item in the child list instead.
-        mStack.AppendElement(mNext);
-        nsDisplayList* childItems = mNext->GetSameCoordinateSystemChildren();
-        mNext = childItems->GetBottom();
-      }
-    }
-  }
-
-
-  nsDisplayListBuilder* mBuilder;
-  nsDisplayItem* mNext;
-  AutoTArray<nsDisplayItem*, 10> mStack;
-};
-
 /**
  * A display item that for webrender to handle SVG
  */
 class nsDisplaySVGWrapper : public nsDisplayWrapList {
 public:
   NS_DISPLAY_DECL_NAME("SVGWrapper", TYPE_SVG_WRAPPER)
 
   nsDisplaySVGWrapper(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
--- a/layout/painting/nsDisplayListInvalidation.h
+++ b/layout/painting/nsDisplayListInvalidation.h
@@ -348,9 +348,22 @@ public:
   virtual bool InvalidateForSyncDecodeImages() const override
   {
     return ShouldInvalidateToSyncDecodeImages();
   }
 
   nsPoint mFrameOffsetToViewport;
 };
 
+class nsDisplayOpacityGeometry : public nsDisplayItemGenericGeometry
+{
+public:
+  nsDisplayOpacityGeometry(nsDisplayItem* aItem,
+                           nsDisplayListBuilder* aBuilder,
+                           float aOpacity)
+    : nsDisplayItemGenericGeometry(aItem, aBuilder)
+    , mOpacity(aOpacity)
+  {}
+
+  float mOpacity;
+};
+
 #endif /*NSDISPLAYLISTINVALIDATION_H_*/
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1412375-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Masks need to cause grouping / intermediate surfaces</title>
+<style>
+
+.outer {
+  filter: opacity(50%);
+}
+
+.box {
+  width: 100px;
+  height: 100px;
+}
+
+.one {
+  background: green;
+}
+
+.another {
+  background: blue;
+  margin-top: -50px;
+  margin-left: 50px;
+}
+
+</style>
+
+<div class="outer">
+  <div class="one box"></div>
+  <div class="another box"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1412375.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Masks need to cause grouping / intermediate surfaces</title>
+<style>
+
+.outer {
+  /* should give similar results to opacity: 0.5 */
+  mask: linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5));
+}
+
+.box {
+  width: 100px;
+  height: 100px;
+}
+
+.one {
+  background: green;
+}
+
+.another {
+  background: blue;
+  margin-top: -50px;
+  margin-left: 50px;
+}
+
+</style>
+
+<div class="outer">
+  <div class="one box"></div>
+  <div class="another box"></div>
+</div>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1677,17 +1677,17 @@ needs-focus == 652301-1b.html 652301-1-r
 fuzzy-if(skiaContent,2,5) == 652775-1.html 652775-1-ref.html
 HTTP == 652991-1a.html 652991-1-ref.html
 HTTP == 652991-1b.html 652991-1-ref.html
 HTTP == 652991-2.html 652991-2-ref.html
 HTTP == 652991-3.html 652991-3-ref.html
 HTTP == 652991-4.html 652991-4-ref.html
 fuzzy-if(skiaContent,1,5) == 653930-1.html 653930-1-ref.html
 == 654057-1.html 654057-1-ref.html
-fuzzy-if(skiaContent,1,4500) == 654950-1.html 654950-1-ref.html # Quartz alpha blending doesn't match GL alpha blending
+fuzzy-if(skiaContent,1,65536) == 654950-1.html 654950-1-ref.html # Quartz alpha blending doesn't match GL alpha blending
 == 655549-1.html 655549-1-ref.html
 == 655836-1.html 655836-1-ref.html
 != 656875.html about:blank
 == 658952.html 658952-ref.html
 fuzzy-if(skiaContent,7,3500) fuzzy-if(webrender&&winWidget,37-37,777-777) == 660682-1.html 660682-1-ref.html
 fuzzy-if(d2d,1,256) skip-if(Android) fuzzy-if(skiaContent,1,68000) == 664127-1.xul 664127-1-ref.xul # Android: Intermittent failures - bug 1019131
 == 665597-1.html 665597-1-ref.html
 == 665597-2.html 665597-2-ref.html
@@ -2061,8 +2061,9 @@ test-pref(font.size.systemFontScale,200)
 == 1424680.html 1424680-ref.html
 == 1424798-1.html 1424798-ref.html
 fuzzy(74,2234) random-if(webrender) == 1425243-1.html 1425243-1-ref.html
 fuzzy-if(Android,66,574) fuzzy-if(d2d,89,777) fuzzy-if(!Android&&!d2d,1,31219) == 1425243-2.html 1425243-2-ref.html
 == 1432541.html 1432541-ref.html
 pref(layout.css.moz-document.url-prefix-hack.enabled,true) == 1446470.html 1035091-ref.html
 pref(layout.css.moz-document.url-prefix-hack.enabled,false) == 1446470-2.html 1035091-ref.html
 test-pref(layout.css.prefixes.gradients,false) == 1451874.html 1451874-ref.html
+fuzzy-if(!(webrender&&gtkWidget),1-2,17500-17500) == 1412375.html 1412375-ref.html
--- a/layout/reftests/css-grid/reftest.list
+++ b/layout/reftests/css-grid/reftest.list
@@ -11,17 +11,17 @@ fails == grid-whitespace-handling-1b.xht
 == grid-placement-auto-col-dense-001.html grid-placement-auto-col-dense-001-ref.html
 == grid-placement-implicit-named-areas-001.html grid-placement-implicit-named-areas-001-ref.html
 == grid-placement-named-lines-001.html grid-placement-named-lines-001-ref.html
 == grid-placement-named-lines-002.html grid-placement-named-lines-002-ref.html
 == grid-placement-named-lines-003.html grid-placement-named-lines-003-ref.html
 == grid-track-sizing-001.html grid-track-sizing-001-ref.html
 == grid-track-sizing-002.html grid-track-sizing-002-ref.html
 == grid-abspos-items-001.html grid-abspos-items-001-ref.html
-== grid-abspos-items-002.html grid-abspos-items-002-ref.html
+fuzzy(180,3) == grid-abspos-items-002.html grid-abspos-items-002-ref.html # flattening differences
 == grid-abspos-items-003.html grid-abspos-items-003-ref.html
 == grid-abspos-items-004.html grid-abspos-items-004-ref.html
 == grid-abspos-items-005.html grid-abspos-items-005-ref.html
 == grid-abspos-items-006.html grid-abspos-items-006-ref.html
 == grid-abspos-items-007.html grid-abspos-items-007-ref.html
 == grid-abspos-items-008.html grid-abspos-items-008-ref.html
 == grid-abspos-items-009.html grid-abspos-items-009-ref.html
 == grid-abspos-items-010.html grid-abspos-items-010-ref.html
--- a/layout/reftests/svg/svg-integration/clip-path/reftest.list
+++ b/layout/reftests/svg/svg-integration/clip-path/reftest.list
@@ -11,33 +11,33 @@
 == clip-path-polygon-007.html clip-path-stripes-001-ref.html
 == clip-path-polygon-008.html clip-path-stripes-002-ref.html
 == clip-path-polygon-009.html clip-path-square-002-ref.html
 == clip-path-polygon-010.html clip-path-stripes-001-ref.html
 == clip-path-polygon-011.html clip-path-stripes-001-ref.html
 == clip-path-polygon-012.html clip-path-stripes-001-ref.html
 fuzzy-if(skiaContent,1,20) fails-if(webrender&&winWidget) == clip-path-polygon-013.html clip-path-stripes-003-ref.html
 
-fuzzy-if(webrender,90-90,690-690) == clip-path-circle-001.html clip-path-circle-001-ref.html
-fuzzy-if(webrender,90-90,690-690) == clip-path-circle-002.html clip-path-circle-001-ref.html
-fuzzy-if(webrender,90-90,690-690) == clip-path-circle-003.html clip-path-circle-001-ref.html
-fuzzy-if(webrender,90-90,690-690) == clip-path-circle-004.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,64-64,714-714) == clip-path-circle-001.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,64-64,714-714) == clip-path-circle-002.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,64-64,714-714) == clip-path-circle-003.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,64-64,714-714) == clip-path-circle-004.html clip-path-circle-001-ref.html
 fuzzy-if(webrender,64-64,714-714) == clip-path-circle-005.html clip-path-circle-002-ref.html
-fuzzy-if(webrender,90-90,690-690) == clip-path-circle-006.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,64-64,714-714) == clip-path-circle-006.html clip-path-circle-001-ref.html
 fuzzy-if(webrender,64-64,714-714) == clip-path-circle-007.html clip-path-circle-002-ref.html
 fuzzy-if(webrender,64-64,714-714) == clip-path-circle-008.html clip-path-circle-002-ref.html
 fuzzy-if(webrender,64-64,714-714) == clip-path-circle-009.html clip-path-circle-003-ref.html
 fuzzy-if(webrender,64-64,714-714) == clip-path-circle-010.html clip-path-circle-004-ref.html
 fuzzy-if(webrender,64-64,714-714) == clip-path-circle-011.html clip-path-circle-005-ref.html
 fuzzy-if(webrender,64-64,714-714) == clip-path-circle-012.html clip-path-circle-006-ref.html
 fuzzy-if(webrender,64-64,714-714) == clip-path-circle-013.html clip-path-circle-002-ref.html
-fuzzy-if(webrender,90-90,698-698) == clip-path-circle-014.html clip-path-circle-007-ref.html
+fuzzy-if(webrender,64-64,714-714) == clip-path-circle-014.html clip-path-circle-007-ref.html
 fuzzy-if(webrender,64-64,714-714) == clip-path-circle-015.html clip-path-circle-008-ref.html
-fuzzy-if(webrender,90-90,702-702) == clip-path-circle-016.html clip-path-circle-009-ref.html
-fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),16,9) fuzzy-if(webrender,90-90,698-698) == clip-path-circle-017.html clip-path-circle-007-ref.html
+fuzzy-if(webrender,64-64,714-714) == clip-path-circle-016.html clip-path-circle-009-ref.html
+fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),16,9) fuzzy-if(webrender,64-64,714-714) == clip-path-circle-017.html clip-path-circle-007-ref.html
 fuzzy-if(webrender,64-64,714-714) == clip-path-circle-018.html clip-path-circle-010-ref.html
 fuzzy-if(webrender,64-64,714-714) == clip-path-circle-019.html clip-path-circle-002-ref.html
 fuzzy-if(webrender,64-64,714-714) == clip-path-circle-020.html clip-path-circle-002-ref.html
 == clip-path-circle-021.html clip-path-circle-021-ref.html
 
 fuzzy-if(webrender,64-64,1106-1106) == clip-path-ellipse-001.html clip-path-ellipse-001-ref.html
 fuzzy-if(webrender,64-64,1106-1106) == clip-path-ellipse-002.html clip-path-ellipse-001-ref.html
 fuzzy-if(webrender,64-64,1106-1106) == clip-path-ellipse-003.html clip-path-ellipse-001-ref.html
@@ -46,16 +46,16 @@ fuzzy-if(webrender,64-64,1106-1106) == c
 fuzzy-if(webrender,64-64,1106-1106) == clip-path-ellipse-006.html clip-path-ellipse-001-ref.html
 fuzzy-if(webrender,64-64,1106-1106) == clip-path-ellipse-007.html clip-path-ellipse-001-ref.html
 fuzzy-if(webrender,64-64,1106-1106) == clip-path-ellipse-008.html clip-path-ellipse-001-ref.html
 
 == clip-path-inset-001a.html clip-path-inset-001-ref.html
 == clip-path-inset-001b.html clip-path-inset-001-ref.html
 == clip-path-inset-001c.html clip-path-inset-001-ref.html
 # Anti-aliasing behavior for masking and borders is different
-fuzzy(64,146) == clip-path-inset-002a.html clip-path-inset-002-ref.html
-fuzzy(64,146) == clip-path-inset-002b.html clip-path-inset-002-ref.html
-fuzzy(64,146) == clip-path-inset-002c.html clip-path-inset-002-ref.html
-fuzzy(64,340) fuzzy-if(webrender,69-69,292-292) == clip-path-inset-003.html clip-path-inset-003-ref.html
+fuzzy(64,146) fuzzy-if(webrender,90-90,132-132) == clip-path-inset-002a.html clip-path-inset-002-ref.html
+fuzzy(64,146) fuzzy-if(webrender,90-90,132-132) == clip-path-inset-002b.html clip-path-inset-002-ref.html
+fuzzy(64,146) fuzzy-if(webrender,90-90,132-132) == clip-path-inset-002c.html clip-path-inset-002-ref.html
+fuzzy(64,340) fuzzy-if(webrender,104-104,311-311) == clip-path-inset-003.html clip-path-inset-003-ref.html
 
 == clip-path-stroke-001.html clip-path-stroke-001-ref.html
 
 == clip-path-transform-001.html clip-path-transform-001-ref.html
--- a/layout/reftests/text-overflow/reftest.list
+++ b/layout/reftests/text-overflow/reftest.list
@@ -1,16 +1,16 @@
 == ellipsis-font-fallback.html ellipsis-font-fallback-ref.html
 == line-clipping.html line-clipping-ref.html
 fuzzy-if(Android,16,244) == marker-basic.html marker-basic-ref.html  # Bug 1128229
 == marker-string.html marker-string-ref.html
 skip-if(Android) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing
 skip-if(!gtkWidget) fuzzy-if(gtkWidget,2,289) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing
 fuzzy-if(Android,24,4000) fuzzy-if(cocoaWidget,1,40) fuzzy-if(asyncPan&&!layersGPUAccelerated,149,1836) == scroll-rounding.html scroll-rounding-ref.html # bug 760264
-fuzzy(2,453) fuzzy-if(skiaContent,9,2100) fails-if(gtkWidget) fuzzy-if(webrender&&winWidget,50-50,499-499) == anonymous-block.html anonymous-block-ref.html # gtkWidget:bug 1309103
+fuzzy(16,454) fails-if(gtkWidget) fuzzy-if(webrender&&winWidget,50-50,499-499) == anonymous-block.html anonymous-block-ref.html # gtkWidget:bug 1309103, fuzzy: subpixel aa
 == false-marker-overlap.html false-marker-overlap-ref.html
 == visibility-hidden.html visibility-hidden-ref.html
 fuzzy-if(asyncPan&&!layersGPUAccelerated,102,1724) fuzzy-if(gtkWidget,10,8) == block-padding.html block-padding-ref.html
 fuzzy-if(webrender,3,825) == quirks-decorations.html quirks-decorations-ref.html
 == quirks-line-height.html quirks-line-height-ref.html
 == standards-decorations.html standards-decorations-ref.html
 == standards-line-height.html standards-line-height-ref.html
 fuzzy-if(skiaContent,1,4200) == selection.html selection-ref.html
--- a/layout/reftests/w3c-css/submitted/masking/reftest.list
+++ b/layout/reftests/w3c-css/submitted/masking/reftest.list
@@ -88,26 +88,26 @@ fails == mask-origin-2.html mask-origin-
 == mask-size-percent-percent-stretch.html mask-size-percent-percent-stretch-ref.html
 
 fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) fuzzy-if(webrender,64,371) == clip-path-contentBox-1a.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,16,21) fuzzy-if(skiaContent,1,60) == clip-path-contentBox-1b.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,16,21) fuzzy-if(skiaContent,1,60) fuzzy-if(webrender,64-64,371-371) == clip-path-contentBox-1c.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,16,21) fuzzy-if(skiaContent,1,60) fuzzy-if(webrender,64,371) == clip-path-paddingBox-1a.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,16,21) fuzzy-if(skiaContent,1,60) == clip-path-paddingBox-1b.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,16,21) fuzzy-if(skiaContent,1,60) fuzzy-if(webrender,64,371) == clip-path-paddingBox-1c.html clip-path-geometryBox-1-ref.html
-fuzzy(64,370) == clip-path-borderBox-1a.html clip-path-geometryBox-1-ref.html
+fuzzy(64,371) == clip-path-borderBox-1a.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,16,21) fuzzy-if(skiaContent,1,60) == clip-path-borderBox-1b.html clip-path-geometryBox-1-ref.html
-fuzzy(64,370) == clip-path-borderBox-1c.html clip-path-geometryBox-1-ref.html
+fuzzy(64,371) == clip-path-borderBox-1c.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,16,21) fuzzy-if(skiaContent,1,60) == clip-path-marginBox-1a.html clip-path-geometryBox-1-ref.html
-fuzzy(64,370) == clip-path-fillBox-1a.html clip-path-geometryBox-1-ref.html
-fuzzy(64,370) == clip-path-strokeBox-1a.html clip-path-geometryBox-1-ref.html
+fuzzy(64,371) == clip-path-fillBox-1a.html clip-path-geometryBox-1-ref.html
+fuzzy(64,371) == clip-path-strokeBox-1a.html clip-path-geometryBox-1-ref.html
 fuzzy(64,370) == clip-path-strokeBox-1b.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-viewBox-1a.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-viewBox-1b.html clip-path-geometryBox-1-ref.html
-fuzzy(64,370) == clip-path-viewBox-1c.html clip-path-geometryBox-1-ref.html
+fuzzy(64,371) == clip-path-viewBox-1c.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,9,98) fuzzy-if(webrender,64,100) == clip-path-geometryBox-2.html clip-path-geometryBox-2-ref.html
 
 == clip-path-localRef-1.html clip-path-localRef-1-ref.html
 
 # mask with opacity test cases
 fuzzy(1,5000) == mask-opacity-1a.html mask-opacity-1-ref.html
 fuzzy(1,5000) == mask-opacity-1b.html mask-opacity-1-ref.html
 fuzzy(1,5000) == mask-opacity-1c.html mask-opacity-1-ref.html
deleted file mode 100644
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/masking/mask-clip-1.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[mask-clip-1.html]
-  expected:
-    if webrender: FAIL
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/masking/mask-opacity-1a.html.ini
+++ b/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/masking/mask-opacity-1a.html.ini
@@ -1,2 +1,4 @@
 [mask-opacity-1a.html]
-  expected: FAIL
+  expected:
+    if webrender: PASS
+    FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-039.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[shape-outside-circle-039.html]
-  expected:
-    if webrender: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-040.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[shape-outside-circle-040.html]
-  expected:
-    if webrender: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-045.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[shape-outside-circle-045.html]
-  expected:
-    if webrender: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-046.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[shape-outside-circle-046.html]
-  expected:
-    if webrender: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-040.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[shape-outside-ellipse-040.html]
-  expected:
-    if webrender: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-041.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[shape-outside-ellipse-041.html]
-  expected:
-    if webrender: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-042.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[shape-outside-ellipse-042.html]
-  expected:
-    if webrender: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-043.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[shape-outside-ellipse-043.html]
-  expected:
-    if webrender: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-018.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[shape-outside-inset-018.html]
-  expected:
-    if webrender: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-inset-019.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[shape-outside-inset-019.html]
-  expected:
-    if webrender: FAIL
--- a/third_party/rust/gl_generator/.cargo-checksum.json
+++ b/third_party/rust/gl_generator/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"629fd3c2eb896803544c82298d3db10b37d8af15d37a311da617baf6c6fabb28","README.md":"e0ae9e1224f6ce5d6df8e30272a1a23044d2d33b0051bf32ccd74e559f8a9f6c","generators/debug_struct_gen.rs":"35984ebe92529467d61112d95c380c84d4bd00d5dc8280749c4eb2f185313df7","generators/global_gen.rs":"eb7836db702777cb13b47b4ab46b9287a3c41995d4bafa0e659ba23688d34475","generators/mod.rs":"8622cd66c69530ed156dd3852d126a44a1ab6d84ea3086240c0b5f5cd7e91316","generators/static_gen.rs":"9fb4ee9f056263611658234539977fb415f93435d290053b84b092e05de16924","generators/static_struct_gen.rs":"23b910c2b14936766036876b9915639058e0cf3bca468c317d4edc7f6498b471","generators/struct_gen.rs":"07d1b52409c31c09010bd7f03459559f772f8b9396b3c60563401a8627b5e247","generators/templates/types/egl.rs":"d1785a30f1098e101302ba74ba4c22cf95ac44b17edf221dbb9d890f4bd635a2","generators/templates/types/gl.rs":"f71f3a2200c0fa13f09687ef05e51c28c5b11c1bb841acd402c0097d8f9130bd","generators/templates/types/glx.rs":"f444166d117b96afed2d8d13db6cd3369d6c59704f296e76202269f411bbd4a8","generators/templates/types/wgl.rs":"9d626e0959374c694c19a36d4dd34dae2f37acf3cb94e9bd4d242a16b41a970d","lib.rs":"4d68840c600a1025025438454d68d70e6da3891f2a5bb33406d4255cb257cda1","registry/mod.rs":"4c42448775dc25449c9995a5ec76e95d6c0762d92443f3c12e865768e4e1dc2a","registry/parse.rs":"e508a1c20c47a92f000d444c34e7818443b15cc9e4a45350e73791fb9c6f68a8"},"package":"4f5c19cde55637681450c92f7a05ea16c78e2b6d0587e601ec1ebdab6960854b"}
\ No newline at end of file
+{"files":{"Cargo.toml":"a11980c70bdc8957d169c4482a3e57a0dd5cb3de6e9eae7b9c15caac7ad8f835","README.md":"e0ae9e1224f6ce5d6df8e30272a1a23044d2d33b0051bf32ccd74e559f8a9f6c","generators/debug_struct_gen.rs":"35223dab284989801bbb7bd676e25533d7fef8e2d990f686867eec1efe95dc62","generators/global_gen.rs":"cad1d5f209dc7ce06d0cea897ee56870c33b812403735adedf2c2d9d3712783f","generators/mod.rs":"9d9f9c20c70de67ca16f4692aff3cdcb7f9209433ebd49e771dbce94349a2a75","generators/static_gen.rs":"9fb4ee9f056263611658234539977fb415f93435d290053b84b092e05de16924","generators/static_struct_gen.rs":"23b910c2b14936766036876b9915639058e0cf3bca468c317d4edc7f6498b471","generators/struct_gen.rs":"03d1bcb9d8ddd64d9326fefe2898633e6714e0caffc32f54b6c873bc75b8a497","generators/templates/types/egl.rs":"d1785a30f1098e101302ba74ba4c22cf95ac44b17edf221dbb9d890f4bd635a2","generators/templates/types/gl.rs":"f71f3a2200c0fa13f09687ef05e51c28c5b11c1bb841acd402c0097d8f9130bd","generators/templates/types/glx.rs":"f444166d117b96afed2d8d13db6cd3369d6c59704f296e76202269f411bbd4a8","generators/templates/types/wgl.rs":"9d626e0959374c694c19a36d4dd34dae2f37acf3cb94e9bd4d242a16b41a970d","lib.rs":"4d68840c600a1025025438454d68d70e6da3891f2a5bb33406d4255cb257cda1","registry/mod.rs":"4c42448775dc25449c9995a5ec76e95d6c0762d92443f3c12e865768e4e1dc2a","registry/parse.rs":"5619135099e9be42e47c45a29a359d63890ab60da482bd4f437728a53d561e95"},"package":"7a795170cbd85b5a7baa58d6d7525cae6a03e486859860c220f7ebbbdd379d0a"}
\ No newline at end of file
--- a/third_party/rust/gl_generator/Cargo.toml
+++ b/third_party/rust/gl_generator/Cargo.toml
@@ -7,33 +7,33 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "gl_generator"
-version = "0.8.0"
+version = "0.9.0"
 authors = ["Brendan Zabarauskas <bjzaba@yahoo.com.au>", "Corey Richardson", "Arseny Kapoulkine"]
 description = "Code generators for creating bindings to the Khronos OpenGL APIs."
 homepage = "https://github.com/brendanzab/gl-rs/gl_generator/"
 documentation = "https://docs.rs/gl_generator"
 readme = "README.md"
 keywords = ["gl", "egl", "opengl", "khronos"]
 categories = ["api-bindings", "rendering::graphics-api"]
 license = "Apache-2.0"
 repository = "https://github.com/brendanzab/gl-rs/"
 
 [lib]
 name = "gl_generator"
 path = "lib.rs"
 [dependencies.khronos_api]
-version = "2.0.0"
+version = "2.1.0"
 
 [dependencies.log]
-version = "0.3.5"
+version = "0.4.1"
 
 [dependencies.xml-rs]
 version = "0.7.0"
 
 [features]
 unstable_generator_utils = []
--- a/third_party/rust/gl_generator/generators/debug_struct_gen.rs
+++ b/third_party/rust/gl_generator/generators/debug_struct_gen.rs
@@ -162,32 +162,32 @@ fn write_impl<W>(registry: &Registry, de
                   "impl {api} {{
             /// Load each OpenGL symbol using a custom load function. This allows for the
             /// use of functions like `glfwGetProcAddress` or `SDL_GL_GetProcAddress`.
             ///
             /// ~~~ignore
             /// let gl = Gl::load_with(|s| glfw.get_proc_address(s));
             /// ~~~
             #[allow(dead_code, unused_variables)]
-            pub fn load_with<F>(mut loadfn: F) -> {api} where F: FnMut(&str) -> *const __gl_imports::raw::c_void {{
+            pub fn load_with<F>(mut loadfn: F) -> {api} where F: FnMut(&'static str) -> *const __gl_imports::raw::c_void {{
                 #[inline(never)]
-                fn do_metaloadfn(loadfn: &mut FnMut(&str) -> *const __gl_imports::raw::c_void,
-                                 symbol: &str,
-                                 symbols: &[&str])
+                fn do_metaloadfn(loadfn: &mut FnMut(&'static str) -> *const __gl_imports::raw::c_void,
+                                 symbol: &'static str,
+                                 symbols: &[&'static str])
                                  -> *const __gl_imports::raw::c_void {{
                     let mut ptr = loadfn(symbol);
                     if ptr.is_null() {{
                         for &sym in symbols {{
                             ptr = loadfn(sym);
                             if !ptr.is_null() {{ break; }}
                         }}
                     }}
                     ptr
                 }}
-                let mut metaloadfn = |symbol: &str, symbols: &[&str]| {{
+                let mut metaloadfn = |symbol: &'static str, symbols: &[&'static str]| {{
                     do_metaloadfn(&mut loadfn, symbol, symbols)
                 }};
                 {api} {{",
                   api = super::gen_struct_name(registry.api)));
 
     for cmd in &registry.cmds {
         try!(writeln!(dest,
             "{name}: FnPtr::new(metaloadfn(\"{symbol}\", &[{fallbacks}])),",
--- a/third_party/rust/gl_generator/generators/global_gen.rs
+++ b/third_party/rust/gl_generator/generators/global_gen.rs
@@ -52,19 +52,19 @@ fn write_header<W>(dest: &mut W) -> io::
 
 /// Creates the metaloadfn function for fallbacks
 fn write_metaloadfn<W>(dest: &mut W) -> io::Result<()>
     where W: io::Write
 {
     writeln!(dest,
              r#"
         #[inline(never)]
-        fn metaloadfn(loadfn: &mut FnMut(&str) -> *const __gl_imports::raw::c_void,
-                      symbol: &str,
-                      fallbacks: &[&str]) -> *const __gl_imports::raw::c_void {{
+        fn metaloadfn(loadfn: &mut FnMut(&'static str) -> *const __gl_imports::raw::c_void,
+                      symbol: &'static str,
+                      fallbacks: &[&'static str]) -> *const __gl_imports::raw::c_void {{
             let mut ptr = loadfn(symbol);
             if ptr.is_null() {{
                 for &sym in fallbacks {{
                     ptr = loadfn(sym);
                     if !ptr.is_null() {{ break; }}
                 }}
             }}
             ptr
@@ -213,17 +213,17 @@ fn write_fn_mods<W>(registry: &Registry,
 
                 #[inline]
                 #[allow(dead_code)]
                 pub fn is_loaded() -> bool {{
                     unsafe {{ storage::{fnname}.is_loaded }}
                 }}
 
                 #[allow(dead_code)]
-                pub fn load_with<F>(mut loadfn: F) where F: FnMut(&str) -> *const raw::c_void {{
+                pub fn load_with<F>(mut loadfn: F) where F: FnMut(&'static str) -> *const raw::c_void {{
                     unsafe {{
                         storage::{fnname} = FnPtr::new(metaloadfn(&mut loadfn, "{symbol}", {fallbacks}))
                     }}
                 }}
             }}
         "##, fnname = fnname, fallbacks = fallbacks, symbol = symbol));
     }
 
@@ -254,17 +254,17 @@ fn write_load_fn<W>(registry: &Registry,
     try!(writeln!(dest,
                   "
         /// Load each OpenGL symbol using a custom load function. This allows for the
         /// use of functions like `glfwGetProcAddress` or `SDL_GL_GetProcAddress`.
         /// ~~~ignore
         /// gl::load_with(|s| glfw.get_proc_address(s));
         /// ~~~
         #[allow(dead_code)]
-        pub fn load_with<F>(mut loadfn: F) where F: FnMut(&str) -> *const __gl_imports::raw::c_void {{
+        pub fn load_with<F>(mut loadfn: F) where F: FnMut(&'static str) -> *const __gl_imports::raw::c_void {{
     "));
 
     for c in &registry.cmds {
         try!(writeln!(dest,
                       "{cmd_name}::load_with(&mut loadfn);",
                       cmd_name = &c.proto.ident[..]));
     }
 
--- a/third_party/rust/gl_generator/generators/mod.rs
+++ b/third_party/rust/gl_generator/generators/mod.rs
@@ -60,22 +60,26 @@ pub fn gen_enum_item<W>(enm: &Enum, type
 
 /// Generates all the type aliases for a namespace.
 ///
 /// Aliases are either `pub type = ...` or `#[repr(C)] pub struct ... { ... }` and contain all the
 /// things that we can't obtain from the XML files.
 pub fn gen_types<W>(api: Api, dest: &mut W) -> io::Result<()>
     where W: io::Write
 {
+    if let Api::Egl = api {
+        try!(writeln!(dest, "{}", include_str!("templates/types/egl.rs")));
+        return Ok(());
+    }
+
     try!(writeln!(dest, "{}", include_str!("templates/types/gl.rs")));
 
     match api {
         Api::Glx => try!(writeln!(dest, "{}", include_str!("templates/types/glx.rs"))),
         Api::Wgl => try!(writeln!(dest, "{}", include_str!("templates/types/wgl.rs"))),
-        Api::Egl => try!(writeln!(dest, "{}", include_str!("templates/types/egl.rs"))),
         _ => {}
     }
 
     Ok(())
 }
 
 /// Generates the list of Rust `Arg`s that a `Cmd` requires.
 pub fn gen_parameters(cmd: &Cmd, with_idents: bool, with_types: bool) -> Vec<String> {
--- a/third_party/rust/gl_generator/generators/struct_gen.rs
+++ b/third_party/rust/gl_generator/generators/struct_gen.rs
@@ -162,32 +162,32 @@ fn write_impl<W>(registry: &Registry, de
                   "impl {api} {{
             /// Load each OpenGL symbol using a custom load function. This allows for the
             /// use of functions like `glfwGetProcAddress` or `SDL_GL_GetProcAddress`.
             ///
             /// ~~~ignore
             /// let gl = Gl::load_with(|s| glfw.get_proc_address(s));
             /// ~~~
             #[allow(dead_code, unused_variables)]
-            pub fn load_with<F>(mut loadfn: F) -> {api} where F: FnMut(&str) -> *const __gl_imports::raw::c_void {{
+            pub fn load_with<F>(mut loadfn: F) -> {api} where F: FnMut(&'static str) -> *const __gl_imports::raw::c_void {{
                 #[inline(never)]
-                fn do_metaloadfn(loadfn: &mut FnMut(&str) -> *const __gl_imports::raw::c_void,
-                                 symbol: &str,
-                                 symbols: &[&str])
+                fn do_metaloadfn(loadfn: &mut FnMut(&'static str) -> *const __gl_imports::raw::c_void,
+                                 symbol: &'static str,
+                                 symbols: &[&'static str])
                                  -> *const __gl_imports::raw::c_void {{
                     let mut ptr = loadfn(symbol);
                     if ptr.is_null() {{
                         for &sym in symbols {{
                             ptr = loadfn(sym);
                             if !ptr.is_null() {{ break; }}
                         }}
                     }}
                     ptr
                 }}
-                let mut metaloadfn = |symbol: &str, symbols: &[&str]| {{
+                let mut metaloadfn = |symbol: &'static str, symbols: &[&'static str]| {{
                     do_metaloadfn(&mut loadfn, symbol, symbols)
                 }};
                 {api} {{",
                   api = super::gen_struct_name(registry.api)));
 
     for cmd in &registry.cmds {
         try!(writeln!(dest,
             "{name}: FnPtr::new(metaloadfn(\"{symbol}\", &[{fallbacks}])),",
--- a/third_party/rust/gl_generator/registry/parse.rs
+++ b/third_party/rust/gl_generator/registry/parse.rs
@@ -150,28 +150,16 @@ fn make_enum(ident: String, ty: Option<S
             if let Some((i, _)) = working.match_indices(")").next() {
                 let ty = working[..i].to_string();
                 let value = working[i + 1..].to_string();
 
                 (Cow::Owned(ty), value, true)
             } else {
                 panic!("Unexpected value format: {}", value)
             }
-        } else if value.starts_with("EGL_CAST(") && value.ends_with(")") {
-            // Handling "SpecialNumbers" in the egl.xml file
-            // The values for these enums has the form `'EGL_CAST(' type ',' expr ')'`.
-            let working = &value[9..value.len() - 1];
-            if let Some((i, _)) = working.match_indices(",").next() {
-                let ty = working[..i].to_string();
-                let value = working[i + 1..].to_string();
-
-                (Cow::Owned(ty), value, true)
-            } else {
-                panic!("Unexpected value format: {}", value)
-            }
         } else {
             let ty = match ty {
                 Some(ref ty) if ty == "u" => "GLuint",
                 Some(ref ty) if ty == "ull" => "GLuint64",
                 Some(ty) => panic!("Unhandled enum type: {}", ty),
                 None if value.starts_with("\"") => "&'static str",
                 None if ident == "TRUE" || ident == "FALSE" => "GLboolean",
                 None => "GLenum",
@@ -184,16 +172,57 @@ fn make_enum(ident: String, ty: Option<S
         ident: ident,
         value: value,
         cast: cast,
         alias: alias,
         ty: ty,
     }
 }
 
+fn make_egl_enum(ident: String, ty: Option<String>, value: String, alias: Option<String>) -> Enum {
+    let (ty, value, cast) = {
+        if value.starts_with("EGL_CAST(") && value.ends_with(")") {
+            // Handling "SpecialNumbers" in the egl.xml file
+            // The values for these enums has the form `'EGL_CAST(' type ',' expr ')'`.
+            let working = &value[9..value.len() - 1];
+            if let Some((i, _)) = working.match_indices(",").next() {
+                let ty = working[..i].to_string();
+                let value = working[i + 1..].to_string();
+
+                (Cow::Owned(ty), value, true)
+            } else {
+                panic!("Unexpected value format: {}", value)
+            }
+        } else {
+            match value.chars().next() {
+                Some('-') | Some('0' ... '9') => (),
+                _ => panic!("Unexpected value format: {}", value),
+            }
+
+            let ty = match ty {
+                Some(ref ty) if ty == "ull" => "EGLuint64KHR",
+                Some(ty) => panic!("Unhandled enum type: {}", ty),
+                None if value.starts_with('-') => "EGLint",
+                None if ident == "TRUE" || ident == "FALSE" => "EGLBoolean",
+                None => "EGLenum",
+            };
+            (Cow::Borrowed(ty), value, false)
+        }
+    };
+
+    Enum {
+        ident: ident,
+        value: value,
+        cast: cast,
+        alias: alias,
+        ty: ty,
+    }
+}
+
+
 fn trim_cmd_prefix(ident: &str, api: Api) -> &str {
     match api {
         Api::Gl | Api::GlCore | Api::Gles1 | Api::Gles2 | Api::Glsc2 => trim_str(ident, "gl"),
         Api::Glx => trim_str(ident, "glX"),
         Api::Wgl => trim_str(ident, "wgl"),
         Api::Egl => trim_str(ident, "egl"),
     }
 }
@@ -498,17 +527,20 @@ trait Parse: Sized + Iterator<Item = Par
 
     fn consume_enum(&mut self, api: Api, attributes: &[Attribute]) -> Enum {
         let ident = trim_enum_prefix(&get_attribute(&attributes, "name").unwrap(), api).to_string();
         let value = get_attribute(&attributes, "value").unwrap();
         let alias = get_attribute(&attributes, "alias");
         let ty = get_attribute(&attributes, "type");
         self.consume_end_element("enum");
 
-        make_enum(ident, ty, value, alias)
+        match api {
+            Api::Egl => make_egl_enum(ident, ty, value, alias),
+            _ => make_enum(ident, ty, value, alias)
+        }
     }
 
     fn consume_cmds(&mut self, api: Api) -> (Vec<Cmd>, BTreeMap<String, Vec<String>>) {
         let mut cmds = Vec::new();
         let mut aliases: BTreeMap<String, Vec<String>> = BTreeMap::new();
         loop {
             match self.next().unwrap() {
                 // add command definition
@@ -1060,27 +1092,16 @@ mod tests {
                                      "((EGLint)(-1))".to_string(),
                                      Some("BAR".to_string()));
             assert_eq!(e.ident, "FOO");
             assert_eq!((&*e.ty, &*e.value), ("EGLint", "(-1)"));
             assert_eq!(e.alias, Some("BAR".to_string()));
         }
 
         #[test]
-        fn test_cast_egl() {
-            let e = parse::make_enum("FOO".to_string(),
-                                     None,
-                                     "EGL_CAST(EGLint,-1)".to_string(),
-                                     Some("BAR".to_string()));
-            assert_eq!(e.ident, "FOO");
-            assert_eq!((&*e.ty, &*e.value), ("EGLint", "-1"));
-            assert_eq!(e.alias, Some("BAR".to_string()));
-        }
-
-        #[test]
         fn test_no_type() {
             let e = parse::make_enum("FOO".to_string(),
                                      None,
                                      "value".to_string(),
                                      Some("BAR".to_string()));
             assert_eq!(e.ident, "FOO");
             assert_eq!(e.value, "value");
             assert_eq!(e.alias, Some("BAR".to_string()));
@@ -1129,16 +1150,88 @@ mod tests {
 
         #[test]
         fn test_ident_false() {
             let e = parse::make_enum("FALSE".to_string(), None, String::new(), None);
             assert_eq!(e.ty, "GLboolean");
         }
     }
 
+    mod make_egl_enum {
+        use registry::parse;
+
+        #[test]
+        fn test_cast_egl() {
+            let e = parse::make_egl_enum("FOO".to_string(),
+                                     None,
+                                     "EGL_CAST(EGLint,-1)".to_string(),
+                                     Some("BAR".to_string()));
+            assert_eq!(e.ident, "FOO");
+            assert_eq!((&*e.ty, &*e.value), ("EGLint", "-1"));
+            assert_eq!(e.alias, Some("BAR".to_string()));
+        }
+
+        #[test]
+        fn test_ident_true() {
+            let e = parse::make_egl_enum("TRUE".to_string(), None, "1234".to_string(), None);
+            assert_eq!(e.ty, "EGLBoolean");
+        }
+
+        #[test]
+        fn test_ident_false() {
+            let e = parse::make_egl_enum("FALSE".to_string(), None, "1234".to_string(), None);
+            assert_eq!(e.ty, "EGLBoolean");
+        }
+
+        #[test]
+        fn test_ull() {
+            let e = parse::make_egl_enum("FOO".to_string(),
+                                     Some("ull".to_string()),
+                                     "1234".to_string(),
+                                     None);
+            assert_eq!(e.ty, "EGLuint64KHR");
+        }
+
+        #[test]
+        fn test_negative_value() {
+            let e = parse::make_egl_enum("FOO".to_string(),
+                                     None,
+                                     "-1".to_string(),
+                                     None);
+            assert_eq!(e.ty, "EGLint");
+        }
+
+        #[test]
+        #[should_panic]
+        fn test_unknown_type() {
+            parse::make_egl_enum("FOO".to_string(),
+                             Some("blargh".to_string()),
+                             String::new(),
+                             None);
+        }
+
+        #[test]
+        #[should_panic]
+        fn test_unknown_value() {
+            parse::make_egl_enum("FOO".to_string(),
+                             None,
+                             "a".to_string(),
+                             None);
+        }
+
+        #[test]
+        #[should_panic]
+        fn test_empty_value() {
+            parse::make_egl_enum("FOO".to_string(),
+                             None,
+                             String::new(),
+                             None);
+        }
+    }
+
     mod parse_event {
         mod from_xml {
             use xml::attribute::OwnedAttribute;
             use xml::common::XmlVersion;
             use xml::name::OwnedName;
             use xml::namespace::Namespace;
             use xml::reader::XmlEvent;
 
--- a/third_party/rust/gleam/.cargo-checksum.json
+++ b/third_party/rust/gleam/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".travis.yml":"29b74b95210896ce634c11a9037638668473b5a1b3b1716c505cb04dbb6341fa","COPYING":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"dacadef6f04af7170b41899ce02202e0f261b03fb4907828095ea6b0480e20a4","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"2de24b7458d6b88f20324303a48acf64a4f2bbfb83d2ec4d6ff2b4f4a1fd2275","build.rs":"b37b2926b74c1f01bfed9aeaac7286e6570b2b2cc80e51a7583f30c039675ddc","src/gl.rs":"aecca69eced4fa373a58dd8253a2811e5e10d8e247e9a935943ac5160273d1bc","src/gl_fns.rs":"7414bf2232d181de751941b47e67f0b9a74f3672788684556b8bf61773c1d8ee","src/gles_fns.rs":"51bbbece61ebec9cfb6d68eda1fffc1a9955af58f848c9f0e6fb026e5c65e5df","src/lib.rs":"16610c19b45a3f26d56b379a3591aa2e4fc9477e7bd88f86b31c6ea32e834861"},"package":"959c818d9bbe9f7b7db55dce0bc44673c4da4f4ee122536c40550f984c3b8017"}
\ No newline at end of file
+{"files":{".travis.yml":"29b74b95210896ce634c11a9037638668473b5a1b3b1716c505cb04dbb6341fa","COPYING":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"7eb0bbf4c4679d7be4c073b22b77036fa5f89264ee615bbf1f93bdbcc1b9fe75","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"2de24b7458d6b88f20324303a48acf64a4f2bbfb83d2ec4d6ff2b4f4a1fd2275","build.rs":"a1616d76f35b3a6015c2ee22ecf13eb225095b22e4190ef5ef2fcd9197b43ad1","src/gl.rs":"982935c8c519e749b42f124ed105a3cacefc186d597f476bd72ea7c88a3e5070","src/gl_fns.rs":"ea24ea0c6deb06af7809140facd5e0f7fce2bb5b340ef425ce0b10029e95294a","src/gles_fns.rs":"aaced55ced12f5dcbeec9ee88eb91696ab65ca24c41cb6fd7f2bdf380641ceb7","src/lib.rs":"16610c19b45a3f26d56b379a3591aa2e4fc9477e7bd88f86b31c6ea32e834861"},"package":"70363479f033b72dbd558fd3b6f153dd824bf4f9dcd05dfcff6cd29a3eb9a63d"}
\ No newline at end of file
--- a/third_party/rust/gleam/Cargo.toml
+++ b/third_party/rust/gleam/Cargo.toml
@@ -7,20 +7,17 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "gleam"
-version = "0.4.20"
+version = "0.4.32"
 authors = ["The Servo Project Developers"]
 build = "build.rs"
 description = "Generated OpenGL bindings and wrapper for Servo."
 documentation = "http://doc.servo.org/gleam/"
 license = "Apache-2.0/MIT"
 repository = "https://github.com/servo/gleam"
 [build-dependencies.gl_generator]
-version = "0.8"
-
-[build-dependencies.pkg-config]
-version = "0.3.8"
+version = "0.9"
--- a/third_party/rust/gleam/build.rs
+++ b/third_party/rust/gleam/build.rs
@@ -1,43 +1,46 @@
 extern crate gl_generator;
-extern crate pkg_config;
 
 use std::env;
 use std::fs::File;
 use std::path::Path;
 use gl_generator::{Registry, Api, Profile, Fallbacks};
 
 fn main() {
     let dest = env::var("OUT_DIR").unwrap();
     let mut file_gl_and_gles = File::create(&Path::new(&dest).join("gl_and_gles_bindings.rs")).unwrap();
     let mut file_gl = File::create(&Path::new(&dest).join("gl_bindings.rs")).unwrap();
     let mut file_gles = File::create(&Path::new(&dest).join("gles_bindings.rs")).unwrap();
 
     // OpenGL 3.3 bindings
-    let gl_extensions = ["GL_ARB_texture_rectangle",
-                         "GL_EXT_debug_marker",
-                         "GL_APPLE_client_storage",
-                         "GL_APPLE_texture_range",
-                         "GL_APPLE_fence",
-                         "GL_ARB_get_program_binary",
-                         "GL_ARB_blend_func_extended"];
+    let gl_extensions = [
+        "GL_ARB_texture_rectangle",
+        "GL_EXT_debug_marker",
+        "GL_APPLE_client_storage",
+        "GL_APPLE_texture_range",
+        "GL_APPLE_fence",
+        "GL_ARB_get_program_binary",
+        "GL_ARB_blend_func_extended",
+        "GL_KHR_debug",
+    ];
     let gl_reg = Registry::new(Api::Gl, (3, 3), Profile::Core, Fallbacks::All, gl_extensions);
     gl_reg.write_bindings(gl_generator::StructGenerator, &mut file_gl)
-          .unwrap();
+        .unwrap();
 
     // GLES 3.0 bindings
     let gles_extensions = [
         "GL_EXT_texture_format_BGRA8888",
         "GL_OES_EGL_image",
         "GL_OES_EGL_image_external",
         "GL_EXT_disjoint_timer_query",
         "GL_EXT_debug_marker",
+        "GL_KHR_debug",
     ];
     let gles_reg = Registry::new(Api::Gles2, (3, 0), Profile::Core, Fallbacks::All, gles_extensions);
     gles_reg.write_bindings(gl_generator::StructGenerator, &mut file_gles)
-            .unwrap();
+        .unwrap();
 
     // OpenGL 3.3 + GLES 3.0 bindings. Used to get all enums
     let gl_reg = gl_reg + gles_reg;
     gl_reg.write_bindings(gl_generator::StructGenerator, &mut file_gl_and_gles)
-          .unwrap();
+        .unwrap();
 }
--- a/third_party/rust/gleam/src/gl.rs
+++ b/third_party/rust/gleam/src/gl.rs
@@ -8,17 +8,16 @@
 // except according to those terms.
 
 use std::mem;
 use std::mem::size_of;
 use std::os::raw::{c_char, c_int, c_void};
 use std::ptr;
 use std::rc::Rc;
 use std::str;
-use std::iter::repeat;
 use std::ffi::{CString, CStr};
 use ffi;
 
 pub use ffi::types::*;
 pub use ffi::*;
 
 pub use ffi_gl::Gl as GlFfi;
 pub use ffi_gles::Gles2 as GlesFfi;
@@ -58,16 +57,55 @@ fn calculate_length(width: GLsizei, heig
         ffi::UNSIGNED_BYTE => 1,
         ffi::FLOAT=> 4,
         _ => panic!("unsupported pixel_type for read_pixels: {:?}", pixel_type),
     };
 
     return (width * height * colors * depth) as usize;
 }
 
+// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
+fn get_uniform_iv_vector_length(uniform_type: &GLuint) -> usize {
+    match *uniform_type {
+        ffi::BOOL |
+        ffi::INT |
+        ffi::SAMPLER_2D |
+        ffi::SAMPLER_CUBE => 1,
+        ffi::INT_VEC2 |
+        ffi::BOOL_VEC2 => 2,
+        ffi::INT_VEC3 |
+        ffi::BOOL_VEC3 => 3,
+        ffi::INT_VEC4 |
+        ffi::BOOL_VEC4 => 4,
+        _ => panic!("Invalid location argument"),
+    }
+}
+
+// https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10
+fn get_uniform_fv_vector_length(uniform_type: &GLuint) -> usize {
+    match *uniform_type {
+        ffi::FLOAT => 1,
+        ffi::FLOAT_VEC2 => 2,
+        ffi::FLOAT_VEC3 => 3,
+        ffi::FLOAT_VEC4 |
+        ffi::FLOAT_MAT2 => 4,
+        ffi::FLOAT_MAT3 => 9,
+        ffi::FLOAT_MAT4 => 16,
+        _ => panic!("Invalid location argument"),
+    }
+}
+
+pub struct DebugMessage {
+    pub message: String,
+    pub source: GLenum,
+    pub ty: GLenum,
+    pub id: GLenum,
+    pub severity: GLenum,
+}
+
 pub trait Gl {
     fn get_type(&self) -> GlType;
     fn buffer_data_untyped(&self,
                            target: GLenum,
                            size: GLsizeiptr,
                            data: *const GLvoid,
                            usage: GLenum);
     fn buffer_sub_data_untyped(&self,
@@ -125,29 +163,32 @@ pub trait Gl {
                             target: GLenum,
                             internalformat: GLenum,
                             width: GLsizei,
                             height: GLsizei);
     fn depth_func(&self, func: GLenum);
     fn active_texture(&self, texture: GLenum);
     fn attach_shader(&self, program: GLuint, shader: GLuint);
     fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str);
+    fn get_uniform_iv(&self, program: GLuint, location: GLint) -> Vec<GLint>;
+    fn get_uniform_fv(&self, program: GLuint, location: GLint) -> Vec<GLfloat>;
     fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint;
     fn get_uniform_indices(&self,  program: GLuint, names: &[&str]) -> Vec<GLuint>;
     fn bind_buffer_base(&self, target: GLenum, index: GLuint, buffer: GLuint);
     fn bind_buffer_range(&self, target: GLenum, index: GLuint, buffer: GLuint, offset: GLintptr, size: GLsizeiptr);
     fn uniform_block_binding(&self,
                              program: GLuint,
                              uniform_block_index: GLuint,
                              uniform_block_binding: GLuint);
     fn bind_buffer(&self, target: GLenum, buffer: GLuint);
     fn bind_vertex_array(&self, vao: GLuint);
     fn bind_renderbuffer(&self, target: GLenum, renderbuffer: GLuint);
     fn bind_framebuffer(&self, target: GLenum, framebuffer: GLuint);
     fn bind_texture(&self, target: GLenum, texture: GLuint);
+    fn draw_buffers(&self, bufs: &[GLenum]);
     fn tex_image_2d(&self,
                     target: GLenum,
                     level: GLint,
                     internal_format: GLint,
                     width: GLsizei,
                     height: GLsizei,
                     border: GLint,
                     format: GLenum,
@@ -260,16 +301,22 @@ pub trait Gl {
                                  ty: GLenum,
                                  output: &mut [u8]);
     fn get_integer_v(&self, name: GLenum) -> GLint;
     fn get_integer_64v(&self, name: GLenum) -> GLint64;
     fn get_integer_iv(&self, name: GLenum, index: GLuint) -> GLint;
     fn get_integer_64iv(&self, name: GLenum, index: GLuint) -> GLint64;
     fn get_boolean_v(&self, name: GLenum) -> GLboolean;
     fn get_float_v(&self, name: GLenum) -> GLfloat;
+    fn get_framebuffer_attachment_parameter_iv(&self,
+                                               target: GLenum,
+                                               attachment: GLenum,
+                                               pname: GLenum) -> GLint;
+    fn get_tex_parameter_iv(&self, target: GLenum, name: GLenum) -> GLint;
+    fn get_tex_parameter_fv(&self, target: GLenum, name: GLenum) -> GLfloat;
     fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint);
     fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat);
     fn framebuffer_texture_2d(&self,
                               target: GLenum,
                               attachment: GLenum,
                               textarget: GLenum,
                               texture: GLuint,
                               level: GLint);
@@ -307,16 +354,17 @@ pub trait Gl {
     fn vertex_attrib_i_pointer(&self,
                                index: GLuint,
                                size: GLint,
                                type_: GLenum,
                                stride: GLsizei,
                                offset: GLuint);
     fn vertex_attrib_divisor(&self, index: GLuint, divisor: GLuint);
     fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei);
+    fn get_viewport(&self) -> (GLint, GLint, GLsizei, GLsizei);
     fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei);
     fn line_width(&self, width: GLfloat);
     fn use_program(&self, program: GLuint);
     fn validate_program(&self, program: GLuint);
     fn draw_arrays(&self, mode: GLenum, first: GLint, count: GLsizei);
     fn draw_arrays_instanced(&self,
                              mode: GLenum,
                              first: GLint,
@@ -451,16 +499,24 @@ pub trait Gl {
         index: GLuint,
         name: &str,
     );
     fn get_frag_data_index(
         &self,
         program: GLuint,
         name: &str,
     ) -> GLint;
+
+    fn alias_point_size_range(&self) -> (GLfloat, GLfloat);
+
+    /// Returns the the maximum supported width and height of the viewport.
+    fn max_viewport_dims(&self) -> (GLint, GLint);
+
+    // GL_KHR_debug
+    fn get_debug_messages(&self) -> Vec<DebugMessage>;
 }
 
 #[inline]
 pub fn buffer_data<T>(gl_: &Gl, target: GLenum, data: &[T], usage: GLenum) {
     gl_.buffer_data_untyped(target,
                             (data.len() * size_of::<T>()) as GLsizeiptr,
                             data.as_ptr() as *const GLvoid,
                             usage)
--- a/third_party/rust/gleam/src/gl_fns.rs
+++ b/third_party/rust/gleam/src/gl_fns.rs
@@ -14,16 +14,31 @@ pub struct GlFns {
 impl GlFns
 {
     pub unsafe fn load_with<'a, F>(loadfn: F) -> Rc<Gl> where F: FnMut(&str) -> *const c_void {
         let ffi_gl_ = GlFfi::load_with(loadfn);
         Rc::new(GlFns {
             ffi_gl_: ffi_gl_,
         }) as Rc<Gl>
     }
+
+    fn get_active_uniform_type(&self, program: GLuint) -> GLuint {
+        let mut size: GLint = 0;
+        let mut uniform_type: GLuint = 0;
+        unsafe {
+            self.ffi_gl_.GetActiveUniform(program,
+                                          0 as GLuint,
+                                          0 as GLsizei,
+                                          ptr::null_mut(),
+                                          &mut size,
+                                          &mut uniform_type,
+                                          ptr::null_mut());
+        }
+        uniform_type
+    }
 }
 
 impl Gl for GlFns {
     fn get_type(&self) -> GlType {
         GlType::Gl
     }
 
     fn buffer_data_untyped(&self, target: GLenum, size: GLsizeiptr, data: *const GLvoid, usage: GLenum) {
@@ -104,57 +119,57 @@ impl Gl for GlFns {
 
     fn pixel_store_i(&self, name: GLenum, param: GLint) {
         unsafe {
             self.ffi_gl_.PixelStorei(name, param);
         }
     }
 
     fn gen_buffers(&self, n: GLsizei) -> Vec<GLuint> {
+        let mut result = vec![0 as GLuint; n as usize];
         unsafe {
-            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
             self.ffi_gl_.GenBuffers(n, result.as_mut_ptr());
-            return result;
         }
+        result
     }
 
     fn gen_renderbuffers(&self, n: GLsizei) -> Vec<GLuint> {
+        let mut result = vec![0 as GLuint; n as usize];
         unsafe {
-            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
             self.ffi_gl_.GenRenderbuffers(n, result.as_mut_ptr());
-            return result;
         }
+        result
     }
 
     fn gen_framebuffers(&self, n: GLsizei) -> Vec<GLuint> {
+        let mut result = vec![0 as GLuint; n as usize];
         unsafe {
-            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
             self.ffi_gl_.GenFramebuffers(n, result.as_mut_ptr());
-            return result;
         }
+        result
     }
 
     fn gen_textures(&self, n: GLsizei) -> Vec<GLuint> {
+        let mut result = vec![0 as GLuint; n as usize];
         unsafe {
-            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
             self.ffi_gl_.GenTextures(n, result.as_mut_ptr());
-            return result;
         }
+        result
     }
 
     fn gen_vertex_arrays(&self, n: GLsizei) -> Vec<GLuint> {
+        let mut result = vec![0 as GLuint; n as usize];
         unsafe {
-            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
             self.ffi_gl_.GenVertexArrays(n, result.as_mut_ptr());
-            return result;
         }
+        result
     }
 
     fn gen_queries(&self, n: GLsizei) -> Vec<GLuint> {
-        let mut result = vec![0; n as usize];
+        let mut result = vec![0 as GLuint; n as usize];
         unsafe {
             self.ffi_gl_.GenQueries(n, result.as_mut_ptr());
         }
         result
     }
 
     fn begin_query(&self, target: GLenum, id: GLuint) {
         unsafe {
@@ -288,16 +303,38 @@ impl Gl for GlFns {
 
     fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str) {
         let c_string = CString::new(name).unwrap();
         unsafe {
             self.ffi_gl_.BindAttribLocation(program, index, c_string.as_ptr())
         }
     }
 
+    // https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetUniform.xml
+    fn get_uniform_iv(&self, program: GLuint, location: GLint) -> Vec<GLint> {
+        let uniform_type = self.get_active_uniform_type(program);
+        let len = get_uniform_iv_vector_length(&uniform_type);
+        let mut result: [GLint; 4] = [0; 4];
+        unsafe {
+            self.ffi_gl_.GetUniformiv(program, location, result.as_mut_ptr());
+        }
+        Vec::from(&result[0..len])
+    }
+
+    // https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetUniform.xml
+    fn get_uniform_fv(&self, program: GLuint, location: GLint) -> Vec<GLfloat> {
+        let uniform_type = self.get_active_uniform_type(program);
+        let len = get_uniform_fv_vector_length(&uniform_type);
+        let mut result: [GLfloat; 16] = [0.0; 16];
+        unsafe {
+            self.ffi_gl_.GetUniformfv(program, location, result.as_mut_ptr());
+        }
+        Vec::from(&result[0..len])
+    }
+
     fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint {
         let c_string = CString::new(name).unwrap();
         unsafe {
             self.ffi_gl_.GetUniformBlockIndex(program, c_string.as_ptr())
         }
     }
 
     fn get_uniform_indices(&self,  program: GLuint, names: &[&str]) -> Vec<GLuint> {
@@ -357,16 +394,22 @@ impl Gl for GlFns {
     }
 
     fn bind_texture(&self, target: GLenum, texture: GLuint) {
         unsafe {
             self.ffi_gl_.BindTexture(target, texture);
         }
     }
 
+    fn draw_buffers(&self, bufs: &[GLenum]) {
+        unsafe {
+            self.ffi_gl_.DrawBuffers(bufs.len() as GLsizei, bufs.as_ptr());
+        }
+    }
+
     // FIXME: Does not verify buffer size -- unsafe!
     fn tex_image_2d(&self,
                     target: GLenum,
                     level: GLint,
                     internal_format: GLint,
                     width: GLsizei,
                     height: GLsizei,
                     border: GLint,
@@ -640,31 +683,55 @@ impl Gl for GlFns {
         let mut result = 0;
         unsafe {
             self.ffi_gl_.GetInteger64i_v(name, index, &mut result);
         }
         result
     }
 
     fn get_boolean_v(&self, name: GLenum) -> GLboolean {
-        let mut result: GLboolean = 0 as GLboolean;
+        let mut result = 0 as GLboolean;
         unsafe {
             self.ffi_gl_.GetBooleanv(name, &mut result);
         }
         result
     }
 
     fn get_float_v(&self, name: GLenum) -> GLfloat {
-        let mut result: GLfloat = 0 as GLfloat;
+        let mut result = 0 as GLfloat;
         unsafe {
             self.ffi_gl_.GetFloatv(name, &mut result);
         }
         result
     }
 
+    fn get_framebuffer_attachment_parameter_iv(&self, target: GLenum, attachment: GLenum, pname: GLenum) -> GLint {
+        let mut result: GLint = 0;
+        unsafe {
+            self.ffi_gl_.GetFramebufferAttachmentParameteriv(target, attachment, pname, &mut result);
+        }
+        result
+    }
+
+    fn get_tex_parameter_iv(&self, target: GLenum, pname: GLenum) -> GLint {
+        let mut result: GLint = 0;
+        unsafe {
+            self.ffi_gl_.GetTexParameteriv(target, pname, &mut result);
+        }
+        result
+    }
+
+    fn get_tex_parameter_fv(&self, target: GLenum, pname: GLenum) -> GLfloat {
+        let mut result: GLfloat = 0.0;
+        unsafe {
+            self.ffi_gl_.GetTexParameterfv(target, pname, &mut result);
+        }
+        result
+    }
+
     fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint) {
         unsafe {
             self.ffi_gl_.TexParameteri(target, pname, param);
         }
     }
 
     fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat) {
         unsafe {
@@ -785,16 +852,24 @@ impl Gl for GlFns {
     }
 
     fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
         unsafe {
             self.ffi_gl_.Viewport(x, y, width, height);
         }
     }
 
+    fn get_viewport(&self) -> (GLint, GLint, GLsizei, GLsizei) {
+        unsafe {
+            let mut ret = [0; 4];
+            self.ffi_gl_.GetIntegerv(ffi::VIEWPORT, ret.as_mut_ptr());
+            (ret[0], ret[1], ret[2], ret[3])
+        }
+    }
+
     fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
         unsafe {
             self.ffi_gl_.Scissor(x, y, width, height);
         }
     }
 
     fn line_width(&self, width: GLfloat) {
         unsafe {
@@ -1230,34 +1305,35 @@ impl Gl for GlFns {
     fn get_uniform_location(&self, program: GLuint, name: &str) -> c_int {
         let name = CString::new(name).unwrap();
         unsafe {
             self.ffi_gl_.GetUniformLocation(program, name.as_ptr())
         }
     }
 
     fn get_program_info_log(&self, program: GLuint) -> String {
+        let max_len = self.get_program_iv(program, ffi::INFO_LOG_LENGTH);
+        let mut result = vec![0u8; max_len as usize];
+        let mut result_len = 0 as GLsizei;
         unsafe {
-            let mut result = vec![0u8; 1024];
-            let mut result_len: GLsizei = 0 as GLsizei;
             self.ffi_gl_.GetProgramInfoLog(program,
-                                           1024 as GLsizei,
+                                           max_len as GLsizei,
                                            &mut result_len,
                                            result.as_mut_ptr() as *mut GLchar);
-            result.truncate(if result_len > 0 {result_len as usize} else {0});
-            String::from_utf8(result).unwrap()
         }
+        result.truncate(if result_len > 0 {result_len as usize} else {0});
+        String::from_utf8(result).unwrap()
     }
 
     fn get_program_iv(&self, program: GLuint, pname: GLenum) -> GLint {
+        let mut result = 0 as GLint;
         unsafe {
-            let mut result: GLint = 0 as GLint;
             self.ffi_gl_.GetProgramiv(program, pname, &mut result);
-            return result;
         }
+        result
     }
 
     fn get_program_binary(&self, program: GLuint) -> (Vec<u8>, GLenum) {
         if !self.ffi_gl_.GetProgramBinary.is_loaded() {
             return (Vec::new(), NONE);
         }
         let len = self.get_program_iv(program, ffi::PROGRAM_BINARY_LENGTH);
         if len <= 0 {
@@ -1298,58 +1374,59 @@ impl Gl for GlFns {
             return;
         }
         unsafe {
             self.ffi_gl_.ProgramParameteri(program, pname, value);
         }
     }
 
     fn get_vertex_attrib_iv(&self, index: GLuint, pname: GLenum) -> GLint {
+        let mut result = 0 as GLint;
         unsafe {
-            let mut result: GLint = 0 as GLint;
             self.ffi_gl_.GetVertexAttribiv(index, pname, &mut result);
-            return result;
         }
+        result
     }
 
     fn get_vertex_attrib_fv(&self, index: GLuint, pname: GLenum) -> Vec<GLfloat> {
+        let mut result = vec![0 as GLfloat; 4];
         unsafe {
-            let mut result = vec![0 as GLfloat; 4];
             self.ffi_gl_.GetVertexAttribfv(index, pname, result.as_mut_ptr());
-            return result;
         }
+        result
     }
 
     fn get_vertex_attrib_pointer_v(&self, index: GLuint, pname: GLenum) -> GLsizeiptr {
         let mut result = 0 as *mut GLvoid;
         unsafe {
             self.ffi_gl_.GetVertexAttribPointerv(index, pname, &mut result)
         }
         result as GLsizeiptr
     }
 
     fn get_buffer_parameter_iv(&self, target: GLuint, pname: GLenum) -> GLint {
+        let mut result = 0 as GLint;
         unsafe {
-            let mut result: GLint = 0 as GLint;
             self.ffi_gl_.GetBufferParameteriv(target, pname, &mut result);
-            return result;
         }
+        result
     }
 
     fn get_shader_info_log(&self, shader: GLuint) -> String {
+        let max_len = self.get_shader_iv(shader, ffi::INFO_LOG_LENGTH);
+        let mut result = vec![0u8; max_len as usize];
+        let mut result_len = 0 as GLsizei;
         unsafe {
-            let mut result = vec![0u8; 1024];
-            let mut result_len: GLsizei = 0 as GLsizei;
             self.ffi_gl_.GetShaderInfoLog(shader,
-                                          1024 as GLsizei,
+                                          max_len as GLsizei,
                                           &mut result_len,
                                           result.as_mut_ptr() as *mut GLchar);
-            result.truncate(if result_len > 0 {result_len as usize} else {0});
-            String::from_utf8(result).unwrap()
         }
+        result.truncate(if result_len > 0 {result_len as usize} else {0});
+        String::from_utf8(result).unwrap()
     }
 
     fn get_string(&self, which: GLenum) -> String {
         unsafe {
             let llstr = self.ffi_gl_.GetString(which);
             if !llstr.is_null() {
                 return str::from_utf8_unchecked(CStr::from_ptr(llstr as *const c_char).to_bytes()).to_string();
             } else {
@@ -1365,21 +1442,21 @@ impl Gl for GlFns {
                 str::from_utf8_unchecked(CStr::from_ptr(llstr as *const c_char).to_bytes()).to_string()
             } else {
                 "".to_string()
             }
         }
     }
 
     fn get_shader_iv(&self, shader: GLuint, pname: GLenum) -> GLint {
+        let mut result = 0 as GLint;
         unsafe {
-            let mut result: GLint = 0 as GLint;
             self.ffi_gl_.GetShaderiv(shader, pname, &mut result);
-            return result;
         }
+        result
     }
 
     fn get_shader_precision_format(&self, _shader_type: GLuint, precision_type: GLuint) -> (GLint, GLint, GLint) {
         // gl.GetShaderPrecisionFormat is not available until OpenGL 4.1.
         // Fallback to OpenGL standard precissions that most desktop hardware support.
         match precision_type {
             ffi::LOW_FLOAT | ffi::MEDIUM_FLOAT | ffi::HIGH_FLOAT => {
                 // Fallback to IEEE 754 single precision
@@ -1594,21 +1671,21 @@ impl Gl for GlFns {
 
     fn delete_sync(&self, sync: GLsync) {
         unsafe {
             self.ffi_gl_.DeleteSync(sync as *const _);
         }
     }
 
     fn gen_fences_apple(&self, n: GLsizei) -> Vec<GLuint> {
+        let mut result = vec![0 as GLuint; n as usize];
         unsafe {
-            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
             self.ffi_gl_.GenFencesAPPLE(n, result.as_mut_ptr());
-            result
         }
+        result
     }
 
     fn delete_fences_apple(&self, fences: &[GLuint]) {
         unsafe {
             self.ffi_gl_.DeleteFencesAPPLE(fences.len() as GLsizei, fences.as_ptr());
         }
     }
 
@@ -1667,10 +1744,84 @@ impl Gl for GlFns {
 
         unsafe {
             self.ffi_gl_.GetFragDataIndex(
                 program,
                 c_string.as_ptr(),
             )
         }
     }
+
+    fn alias_point_size_range(&self) -> (GLfloat, GLfloat) {
+        unsafe {
+            let mut ret = [0.; 2];
+            self.ffi_gl_.GetFloatv(ffi::ALIASED_POINT_SIZE_RANGE, ret.as_mut_ptr());
+            (ret[0], ret[1])
+        }
+    }
+
+    fn max_viewport_dims(&self) -> (GLint, GLint) {
+        unsafe {
+            let mut ret = [0; 2];
+            self.ffi_gl_.GetIntegerv(ffi::MAX_VIEWPORT_DIMS, ret.as_mut_ptr());
+            (ret[0], ret[1])
+        }
+    }
+
+    // GL_KHR_debug
+    fn get_debug_messages(&self) -> Vec<DebugMessage> {
+        if !self.ffi_gl_.GetDebugMessageLog.is_loaded() {
+            return Vec::new();
+        }
+
+        let mut max_message_len = 0;
+        unsafe {
+            self.ffi_gl_.GetIntegerv(
+                ffi::MAX_DEBUG_MESSAGE_LENGTH,
+                &mut max_message_len
+            )
+        }
+
+        let mut output = Vec::new();
+        const CAPACITY: usize = 4;
+
+        let mut msg_data = vec![0u8; CAPACITY * max_message_len as usize];
+        let mut sources = [0 as GLenum; CAPACITY];
+        let mut types = [0 as GLenum; CAPACITY];
+        let mut severities = [0 as GLenum; CAPACITY];
+        let mut ids = [0 as GLuint; CAPACITY];
+        let mut lengths = [0 as GLsizei; CAPACITY];
+
+        loop {
+            let count = unsafe {
+                self.ffi_gl_.GetDebugMessageLog(
+                    CAPACITY as _,
+                    msg_data.len() as _,
+                    sources.as_mut_ptr(),
+                    types.as_mut_ptr(),
+                    ids.as_mut_ptr(),
+                    severities.as_mut_ptr(),
+                    lengths.as_mut_ptr(),
+                    msg_data.as_mut_ptr() as *mut _,
+                )
+            };
+
+            let mut offset = 0;
+            output.extend((0 .. count as usize).map(|i| {
+                let len = lengths[i] as usize;
+                let slice = &msg_data[offset .. offset + len];
+                offset += len;
+                DebugMessage {
+                    message: String::from_utf8_lossy(slice).to_string(),
+                    source: sources[i],
+                    ty: types[i],
+                    id: ids[i],
+                    severity: severities[i],
+                }
+            }));
+
+            if (count as usize) < CAPACITY {
+                return output
+            }
+        }
+    }
 }
 
--- a/third_party/rust/gleam/src/gles_fns.rs
+++ b/third_party/rust/gleam/src/gles_fns.rs
@@ -14,16 +14,31 @@ pub struct GlesFns {
 impl GlesFns
 {
     pub unsafe fn load_with<'a, F>(loadfn: F) -> Rc<Gl> where F: FnMut(&str) -> *const c_void {
         let ffi_gl_ = GlesFfi::load_with(loadfn);
         Rc::new(GlesFns {
             ffi_gl_: ffi_gl_,
         }) as Rc<Gl>
     }
+
+    fn get_active_uniform_type(&self, program: GLuint) -> GLuint {
+        let mut size: GLint = 0;
+        let mut uniform_type: GLuint = 0;
+        unsafe {
+            self.ffi_gl_.GetActiveUniform(program,
+                                          0 as GLuint,
+                                          0 as GLsizei,
+                                          ptr::null_mut(),
+                                          &mut size,
+                                          &mut uniform_type,
+                                          ptr::null_mut());
+        }
+        uniform_type
+    }
 }
 
 impl Gl for GlesFns {
     fn get_type(&self) -> GlType {
         GlType::Gles
     }
 
     fn buffer_data_untyped(&self, target: GLenum, size: GLsizeiptr, data: *const GLvoid, usage: GLenum) {
@@ -101,60 +116,60 @@ impl Gl for GlesFns {
 
     fn pixel_store_i(&self, name: GLenum, param: GLint) {
         unsafe {
             self.ffi_gl_.PixelStorei(name, param);
         }
     }
 
     fn gen_buffers(&self, n: GLsizei) -> Vec<GLuint> {
+        let mut result = vec![0 as GLuint; n as usize];
         unsafe {
-            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
             self.ffi_gl_.GenBuffers(n, result.as_mut_ptr());
-            return result;
         }
+        result
     }
 
     fn gen_renderbuffers(&self, n: GLsizei) -> Vec<GLuint> {
+        let mut result = vec![0 as GLuint; n as usize];
         unsafe {
-            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
             self.ffi_gl_.GenRenderbuffers(n, result.as_mut_ptr());
-            return result;
         }
+        result
     }
 
     fn gen_framebuffers(&self, n: GLsizei) -> Vec<GLuint> {
+        let mut result = vec![0 as GLuint; n as usize];
         unsafe {
-            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
             self.ffi_gl_.GenFramebuffers(n, result.as_mut_ptr());
-            return result;
         }
+        result
     }
 
     fn gen_textures(&self, n: GLsizei) -> Vec<GLuint> {
+        let mut result = vec![0 as GLuint; n as usize];
         unsafe {
-            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
             self.ffi_gl_.GenTextures(n, result.as_mut_ptr());
-            return result;
         }
+        result
     }
 
     fn gen_vertex_arrays(&self, n: GLsizei) -> Vec<GLuint> {
+        let mut result = vec![0 as GLuint; n as usize];
         unsafe {
-            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
             self.ffi_gl_.GenVertexArrays(n, result.as_mut_ptr());
-            return result;
         }
+        result
     }
 
     fn gen_queries(&self, n: GLsizei) -> Vec<GLuint> {
         if !self.ffi_gl_.GenQueriesEXT.is_loaded() {
             return Vec::new();
         }
-        let mut result = vec![0; n as usize];
+        let mut result = vec![0 as GLuint; n as usize];
         unsafe {
             self.ffi_gl_.GenQueriesEXT(n, result.as_mut_ptr());
         }
         result
     }
 
     fn begin_query(&self, target: GLenum, id: GLuint) {
         if !self.ffi_gl_.BeginQueryEXT.is_loaded() {
@@ -312,16 +327,38 @@ impl Gl for GlesFns {
 
     fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str) {
         let c_string = CString::new(name).unwrap();
         unsafe {
             self.ffi_gl_.BindAttribLocation(program, index, c_string.as_ptr())
         }
     }
 
+    // https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetUniform.xml
+    fn get_uniform_iv(&self, program: GLuint, location: GLint) -> Vec<GLint> {
+        let uniform_type = self.get_active_uniform_type(program);
+        let len = get_uniform_iv_vector_length(&uniform_type);
+        let mut result: [GLint; 4] = [0; 4];
+        unsafe {
+            self.ffi_gl_.GetUniformiv(program, location, result.as_mut_ptr());
+        }
+        Vec::from(&result[0..len])
+    }
+
+    // https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetUniform.xml
+    fn get_uniform_fv(&self, program: GLuint, location: GLint) -> Vec<GLfloat> {
+        let uniform_type = self.get_active_uniform_type(program);
+        let len = get_uniform_fv_vector_length(&uniform_type);
+        let mut result: [GLfloat; 16] = [0.0; 16];
+        unsafe {
+            self.ffi_gl_.GetUniformfv(program, location, result.as_mut_ptr());
+        }
+        Vec::from(&result[0..len])
+    }
+
     fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint {
         let c_string = CString::new(name).unwrap();
         unsafe {
             self.ffi_gl_.GetUniformBlockIndex(program, c_string.as_ptr())
         }
     }
 
     fn get_uniform_indices(&self,  program: GLuint, names: &[&str]) -> Vec<GLuint> {
@@ -381,16 +418,22 @@ impl Gl for GlesFns {
     }
 
     fn bind_texture(&self, target: GLenum, texture: GLuint) {
         unsafe {
             self.ffi_gl_.BindTexture(target, texture);
         }
     }
 
+    fn draw_buffers(&self, bufs: &[GLenum]) {
+        unsafe {
+            self.ffi_gl_.DrawBuffers(bufs.len() as GLsizei, bufs.as_ptr());
+        }
+    }
+
     // FIXME: Does not verify buffer size -- unsafe!
     fn tex_image_2d(&self,
                     target: GLenum,
                     level: GLint,
                     internal_format: GLint,
                     width: GLsizei,
                     height: GLsizei,
                     border: GLint,
@@ -660,31 +703,55 @@ impl Gl for GlesFns {
         let mut result = 0;
         unsafe {
             self.ffi_gl_.GetInteger64i_v(name, index, &mut result);
         }
         result
     }
 
     fn get_boolean_v(&self, name: GLenum) -> GLboolean {
-        let mut result: GLboolean = 0 as GLboolean;
+        let mut result = 0 as GLboolean;
         unsafe {
             self.ffi_gl_.GetBooleanv(name, &mut result);
         }
         result
     }
 
     fn get_float_v(&self, name: GLenum) -> GLfloat {
-        let mut result: GLfloat = 0 as GLfloat;
+        let mut result = 0 as GLfloat;
         unsafe {
             self.ffi_gl_.GetFloatv(name, &mut result);
         }
         result
     }
 
+    fn get_framebuffer_attachment_parameter_iv(&self, target: GLenum, attachment: GLenum, pname: GLenum) -> GLint {
+        let mut result: GLint = 0;
+        unsafe {
+            self.ffi_gl_.GetFramebufferAttachmentParameteriv(target, attachment, pname, &mut result);
+        }
+        result
+    }
+
+    fn get_tex_parameter_iv(&self, target: GLenum, pname: GLenum) -> GLint {
+        let mut result: GLint = 0;
+        unsafe {
+            self.ffi_gl_.GetTexParameteriv(target, pname, &mut result);
+        }
+        result
+    }
+
+    fn get_tex_parameter_fv(&self, target: GLenum, pname: GLenum) -> GLfloat {
+        let mut result: GLfloat = 0.0;
+        unsafe {
+            self.ffi_gl_.GetTexParameterfv(target, pname, &mut result);
+        }
+        result
+    }
+
     fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint) {
         unsafe {
             self.ffi_gl_.TexParameteri(target, pname, param);
         }
     }
 
     fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat) {
         unsafe {
@@ -805,16 +872,24 @@ impl Gl for GlesFns {
     }
 
     fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
         unsafe {
             self.ffi_gl_.Viewport(x, y, width, height);
         }
     }
 
+    fn get_viewport(&self) -> (GLint, GLint, GLsizei, GLsizei) {
+        unsafe {
+            let mut ret = [0; 4];
+            self.ffi_gl_.GetIntegerv(ffi::VIEWPORT, ret.as_mut_ptr());
+            (ret[0], ret[1], ret[2], ret[3])
+        }
+    }
+
     fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
         unsafe {
             self.ffi_gl_.Scissor(x, y, width, height);
         }
     }
 
     fn line_width(&self, width: GLfloat) {
         unsafe {
@@ -1191,17 +1266,17 @@ impl Gl for GlesFns {
                                              indices.as_ptr(),
                                              pname,
                                              result.as_mut_ptr());
         }
         result
     }
 
     fn get_active_uniform_block_i(&self, program: GLuint, index: GLuint, pname: GLenum) -> GLint {
-        let mut result = 0;
+        let mut result = 0 as GLint;
         unsafe {
             self.ffi_gl_.GetActiveUniformBlockiv(program, index, pname, &mut result);
         }
         result
     }
 
     fn get_active_uniform_block_iv(&self, program: GLuint, index: GLuint, pname: GLenum) -> Vec<GLint> {
         let count = self.get_active_uniform_block_i(program, index, ffi::UNIFORM_BLOCK_ACTIVE_UNIFORMS);
@@ -1244,34 +1319,35 @@ impl Gl for GlesFns {
     fn get_uniform_location(&self, program: GLuint, name: &str) -> c_int {
         let name = CString::new(name).unwrap();
         unsafe {
             self.ffi_gl_.GetUniformLocation(program, name.as_ptr())
         }
     }
 
     fn get_program_info_log(&self, program: GLuint) -> String {
+        let max_len = self.get_program_iv(program, ffi::INFO_LOG_LENGTH);
+        let mut result = vec![0u8; max_len as usize];
+        let mut result_len = 0 as GLsizei;
         unsafe {
-            let mut result = vec![0u8; 1024];
-            let mut result_len: GLsizei = 0 as GLsizei;
             self.ffi_gl_.GetProgramInfoLog(program,
-                                           1024 as GLsizei,
+                                           max_len as GLsizei,
                                            &mut result_len,
                                            result.as_mut_ptr() as *mut GLchar);
-            result.truncate(if result_len > 0 {result_len as usize} else {0});
-            String::from_utf8(result).unwrap()
         }
+        result.truncate(if result_len > 0 {result_len as usize} else {0});
+        String::from_utf8(result).unwrap()
     }
 
     fn get_program_iv(&self, program: GLuint, pname: GLenum) -> GLint {
+        let mut result = 0 as GLint;
         unsafe {
-            let mut result: GLint = 0 as GLint;
             self.ffi_gl_.GetProgramiv(program, pname, &mut result);
-            return result;
         }
+        result
     }
 
     fn get_program_binary(&self, program: GLuint) -> (Vec<u8>, GLenum) {
         let len = self.get_program_iv(program, ffi::PROGRAM_BINARY_LENGTH);
         if len <= 0 {
             return (Vec::new(), NONE);
         }
         let mut binary: Vec<u8> = Vec::with_capacity(len as usize);
@@ -1303,58 +1379,59 @@ impl Gl for GlesFns {
 
     fn program_parameter_i(&self, program: GLuint, pname: GLenum, value: GLint) {
         unsafe {
             self.ffi_gl_.ProgramParameteri(program, pname, value);
         }
     }
 
     fn get_vertex_attrib_iv(&self, index: GLuint, pname: GLenum) -> GLint {
+        let mut result = 0 as GLint;
         unsafe {
-            let mut result: GLint = 0 as GLint;
             self.ffi_gl_.GetVertexAttribiv(index, pname, &mut result);
-            return result;
         }
+        result
     }
 
     fn get_vertex_attrib_fv(&self, index: GLuint, pname: GLenum) -> Vec<GLfloat> {
+        let mut result = vec![0 as GLfloat; 4];
         unsafe {
-            let mut result = vec![0 as GLfloat; 4];
             self.ffi_gl_.GetVertexAttribfv(index, pname, result.as_mut_ptr());
-            return result;
         }
+        result
     }
 
     fn get_vertex_attrib_pointer_v(&self, index: GLuint, pname: GLenum) -> GLsizeiptr {
         let mut result = 0 as *mut GLvoid;
         unsafe {
             self.ffi_gl_.GetVertexAttribPointerv(index, pname, &mut result)
         }
         result as GLsizeiptr
     }
 
     fn get_buffer_parameter_iv(&self, target: GLuint, pname: GLenum) -> GLint {
+        let mut result = 0 as GLint;
         unsafe {
-            let mut result: GLint = 0 as GLint;
             self.ffi_gl_.GetBufferParameteriv(target, pname, &mut result);
-            return result;
         }
+        result
     }
 
     fn get_shader_info_log(&self, shader: GLuint) -> String {
+        let max_len = self.get_shader_iv(shader, ffi::INFO_LOG_LENGTH);
+        let mut result = vec![0u8; max_len as usize];
+        let mut result_len = 0 as GLsizei;
         unsafe {
-            let mut result = vec![0u8; 1024];
-            let mut result_len: GLsizei = 0 as GLsizei;
             self.ffi_gl_.GetShaderInfoLog(shader,
-                                          1024 as GLsizei,
+                                          max_len as GLsizei,
                                           &mut result_len,
                                           result.as_mut_ptr() as *mut GLchar);
-            result.truncate(if result_len > 0 {result_len as usize} else {0});
-            String::from_utf8(result).unwrap()
         }
+        result.truncate(if result_len > 0 {result_len as usize} else {0});
+        String::from_utf8(result).unwrap()
     }
 
     fn get_string(&self, which: GLenum) -> String {
         unsafe {
             let llstr = self.ffi_gl_.GetString(which);
             if !llstr.is_null() {
                 return str::from_utf8_unchecked(CStr::from_ptr(llstr as *const c_char).to_bytes()).to_string();
             } else {
@@ -1370,21 +1447,21 @@ impl Gl for GlesFns {
                 str::from_utf8_unchecked(CStr::from_ptr(llstr as *const c_char).to_bytes()).to_string()
             } else {
                 "".to_string()
             }
         }
     }
 
     fn get_shader_iv(&self, shader: GLuint, pname: GLenum) -> GLint {
+        let mut result = 0 as GLint;
         unsafe {
-            let mut result: GLint = 0 as GLint;
             self.ffi_gl_.GetShaderiv(shader, pname, &mut result);
-            return result;
         }
+        result
     }
 
     fn get_shader_precision_format(&self,
                                    shader_type: GLuint,
                                    precision_type: GLuint)
                                    -> (GLint, GLint, GLint) {
         let mut range = [0 as GLint, 0];
         let mut precision = 0 as GLint;
@@ -1628,10 +1705,84 @@ impl Gl for GlesFns {
 
     fn get_frag_data_index(
         &self,
         _program: GLuint,
         _name: &str,
     ) -> GLint {
         panic!("not supported");
     }
+
+    fn alias_point_size_range(&self) -> (GLfloat, GLfloat) {
+        unsafe {
+            let mut ret = [0.; 2];
+            self.ffi_gl_.GetFloatv(ffi::ALIASED_POINT_SIZE_RANGE, ret.as_mut_ptr());
+            (ret[0], ret[1])
+        }
+    }
+
+    fn max_viewport_dims(&self) -> (GLint, GLint) {
+        unsafe {
+            let mut ret = [0; 2];
+            self.ffi_gl_.GetIntegerv(ffi::MAX_VIEWPORT_DIMS, ret.as_mut_ptr());
+            (ret[0], ret[1])
+        }
+    }
+
+    // GL_KHR_debug
+    fn get_debug_messages(&self) -> Vec<DebugMessage> {
+        if !self.ffi_gl_.GetDebugMessageLog.is_loaded() {
+            return Vec::new();
+        }
+
+        let mut max_message_len = 0;
+        unsafe {
+            self.ffi_gl_.GetIntegerv(
+                ffi::MAX_DEBUG_MESSAGE_LENGTH,
+                &mut max_message_len
+            )
+        }
+
+        let mut output = Vec::new();
+        const CAPACITY: usize = 4;
+
+        let mut msg_data = vec![0u8; CAPACITY * max_message_len as usize];
+        let mut sources = [0 as GLenum; CAPACITY];
+        let mut types = [0 as GLenum; CAPACITY];
+        let mut severities = [0 as GLenum; CAPACITY];
+        let mut ids = [0 as GLuint; CAPACITY];
+        let mut lengths = [0 as GLsizei; CAPACITY];
+
+        loop {
+            let count = unsafe {
+                self.ffi_gl_.GetDebugMessageLog(
+                    CAPACITY as _,
+                    msg_data.len() as _,
+                    sources.as_mut_ptr(),
+                    types.as_mut_ptr(),
+                    ids.as_mut_ptr(),
+                    severities.as_mut_ptr(),
+                    lengths.as_mut_ptr(),
+                    msg_data.as_mut_ptr() as *mut _,
+                )
+            };
+
+            let mut offset = 0;
+            output.extend((0 .. count as usize).map(|i| {
+                let len = lengths[i] as usize;
+                let slice = &msg_data[offset .. offset + len];
+                offset += len;
+                DebugMessage {
+                    message: String::from_utf8_lossy(slice).to_string(),
+                    source: sources[i],
+                    ty: types[i],
+                    id: ids[i],
+                    severity: severities[i],
+                }
+            }));
+
+            if (count as usize) < CAPACITY {
+                return output
+            }
+        }
+    }
 }
 
--- a/third_party/rust/khronos_api/.cargo-checksum.json
+++ b/third_party/rust/khronos_api/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{"Cargo.toml":"b66b03a3e075e128ad40dc3d3d62c38ea14c47257634b8a012d99965e5071ddd","README.md":"dff09e27dcecc37f1e477d62ea89aa49b4dc743514ea6990c7c83b8b0fc602e4","api/xml/gl.xml":"5c3d768a361dc998b3497e93c1e0d837615c942ab82ff17dfeed8c1917b74bbb","api/xml/glx.xml":"1862e651300ae36fa6621b23910f55f63f29cd3550c114312be27c204e9828c5","api/xml/wgl.xml":"27fdf88d0f9fae2b025820f28ee3cb67dfc0388e68532a135ca7043db0427a35","api_egl/api/egl.xml":"7b20c062af2fda6dd340f4d03983c49204d75067ed161f10f671c805ace692f7","src/lib.rs":"9ff0a4ccce8f3fca7b2c6340a42d8b0f2f52f30ccae28db5a86be10c4341ca01"},"package":"d867c645cfeb8a7fec503731679eac03ac11b7105aa5a71cb8f8ee5271636add"}
\ No newline at end of file
+{"files":{"Cargo.toml":"e0120828d1aa70c40f47a6c7dc0cc08e089470d8faf8644e68836c31f44248b3","README.md":"45772358ebfb8a7554056ce7faab27c3dc73d881ba4be66891d39e4830657877","api/xml/gl.xml":"5c3d768a361dc998b3497e93c1e0d837615c942ab82ff17dfeed8c1917b74bbb","api/xml/glx.xml":"1862e651300ae36fa6621b23910f55f63f29cd3550c114312be27c204e9828c5","api/xml/wgl.xml":"27fdf88d0f9fae2b025820f28ee3cb67dfc0388e68532a135ca7043db0427a35","api_egl/api/egl.xml":"7b20c062af2fda6dd340f4d03983c49204d75067ed161f10f671c805ace692f7","api_webgl/extensions/ANGLE_instanced_arrays/extension.xml":"213f7e7636e8df0c390a18ad1339618335d7744970837998a191c275f7d1a95c","api_webgl/extensions/EXT_blend_minmax/extension.xml":"d1798c0faf13dfa7930032994f5a47c07b6f2f44b45d033059bfcffb7c1d579c","api_webgl/extensions/EXT_color_buffer_float/extension.xml":"48dacbcce0e0e96c206fc6dd2050266680ba24c2f6b254c3a6871c8715639d36","api_webgl/extensions/EXT_color_buffer_half_float/extension.xml":"1900351880046b495af97e6d38e9f3213538b133f74625a4dd73165d43e7710c","api_webgl/extensions/EXT_disjoint_timer_query/extension.xml":"b4df1205df86474e27459dc1cea3c75cba533d0245c38bb3ea5fe608612c512b","api_webgl/extensions/EXT_disjoint_timer_query_webgl2/extension.xml":"09cf6ddc69af0a032a5712df3808be30ff5fecaea0080ec73f464b87e4b3a313","api_webgl/extensions/EXT_float_blend/extension.xml":"5a298482adee7bb1fcc8f613a8aa9b61bb71bf5523fac56da45bb68136e451b8","api_webgl/extensions/EXT_frag_depth/extension.xml":"d19cf823811272352972ac4cb1d37405dcf63a91c48c1dd046e475487fecf9ea","api_webgl/extensions/EXT_sRGB/extension.xml":"7688ba25fa05558fbae72b21661e5bece2c36e899fe78da83bc8a172db9622fd","api_webgl/extensions/EXT_shader_texture_lod/extension.xml":"f1e5741d5d12d6e9a6bbc95049da2ec62ee55a4d1b6ec7b03e87e9f91282c6cb","api_webgl/extensions/EXT_texture_filter_anisotropic/extension.xml":"131ed0429a9951c05ae5c30859179f47c99b9bd6f47ca2825bdecf791f0188b6","api_webgl/extensions/OES_element_index_uint/extension.xml":"734f7a90af440ea559fa0fe777144aaef8acc7de94a8c3ce153a75ff85cb1f6b","api_webgl/extensions/OES_fbo_render_mipmap/extension.xml":"43bede667b814b80e15b5af463620c53f6fa9e1a610c2e9756ad2fa55b9f7589","api_webgl/extensions/OES_standard_derivatives/extension.xml":"2fa53259457d9f6042194bfb13c0db4b3c63d2d99d9e44f057d8fe4d5b28fe69","api_webgl/extensions/OES_texture_float/extension.xml":"42a782fcc2cafd3df9ea33c9259343c66b3fbd2ebfc216dc20ee6be53481f042","api_webgl/extensions/OES_texture_float_linear/extension.xml":"98041c4427f5abf741eb2c34e23f9b8c84090d4d5b4e2e0f1b04f9b53c73259a","api_webgl/extensions/OES_texture_half_float/extension.xml":"14cb4ce4e6f259fcb6ce0d988c4e81880299f28343cdcba4f7abbf8956207529","api_webgl/extensions/OES_texture_half_float_linear/extension.xml":"d2f29c9a9bf31e757fc8c6da277cdb813350a1504be773c3bd105bfa92e45502","api_webgl/extensions/OES_vertex_array_object/extension.xml":"8262ec860c2af3b23daacc27a17bcf29054bcc03baf59f90779c4e53fc469f41","api_webgl/extensions/WEBGL_color_buffer_float/extension.xml":"d68800fe416384a951fe45fdbcb324494d848cbecdecbdcacf7bbafe8a2aae93","api_webgl/extensions/WEBGL_compressed_texture_astc/extension.xml":"9ba9c29e7e09aa8ec950ec70c79eae42c6f844d354b49fc88d9f048318a9c400","api_webgl/extensions/WEBGL_compressed_texture_atc/extension.xml":"a8de4e909b3d7c29ff6ca58ff6bc91b14c298a12beded04c025bb0ecb1d74db2","api_webgl/extensions/WEBGL_compressed_texture_etc/extension.xml":"d926f0a7f533ea6ce43215a7e90f35064e1a51df539e04c49a2e918f69943aad","api_webgl/extensions/WEBGL_compressed_texture_etc1/extension.xml":"02a008b04a5b40e274023defe3a2fb94f06a2150c059ae703c282faa6b6b4b0e","api_webgl/extensions/WEBGL_compressed_texture_pvrtc/extension.xml":"1570f8ebb56480908e46706683182a097928e8e0a2e992e3eab8f1a2c16124c9","api_webgl/extensions/WEBGL_compressed_texture_s3tc/extension.xml":"87585ba713ad1a8dd5c04fd24a7068a0cf88799ea697e940752c68698de0c707","api_webgl/extensions/WEBGL_compressed_texture_s3tc_srgb/extension.xml":"e22e01bd35b437adabfc7592f5eb6d750fdaabac61b0f79561fe58e860843993","api_webgl/extensions/WEBGL_debug_renderer_info/extension.xml":"af71073e0031b0296b7e5b609cdd272458cbae434a7fa31649054be0969a72e0","api_webgl/extensions/WEBGL_debug_shaders/extension.xml":"fc8c59747ee8cc289aa269c6ac5b6a45f7dc036d509209ace8db7062481a1abe","api_webgl/extensions/WEBGL_depth_texture/extension.xml":"5d91c9b8252b9f3a19f3f6a2f861a660d200446cfcaf09fa2a337e6f6b2dd5bd","api_webgl/extensions/WEBGL_draw_buffers/extension.xml":"9b465aa066d86ba044ad1604f6a3ce9f9e9a3afe3b4d36750a60870a67697fa1","api_webgl/extensions/WEBGL_get_buffer_sub_data_async/extension.xml":"abea14f4cb2012a04db6edc1219ad3da97bfc0975c4756f9d61ab3378a283cae","api_webgl/extensions/WEBGL_lose_context/extension.xml":"71defc6045fefdf7b14cd2d1fe4a432d504b2567e7acb1e77b8737aea7ba1bb0","api_webgl/extensions/WEBGL_multiview/extension.xml":"ac8368b843bb76afb9a82460ef619aa278be180f285964070ccedcd66213f0e0","api_webgl/extensions/WEBGL_security_sensitive_resources/extension.xml":"99634c2e0117d7abb9b44bbd64d8c4e8c8ebbcfe6342222dfc624b05e8532249","api_webgl/extensions/WEBGL_shared_resources/extension.xml":"90b6f51521fbb2ba23563cdfd2029cf28de1233aba4b2844b7d832b323c0fa10","api_webgl/extensions/proposals/EXT_clip_cull_distance/extension.xml":"a4f9b465b1e1efa0367a8fbbada7a6156ffb3e4ee1c677a0d220a7ea1402a260","api_webgl/extensions/proposals/WEBGL_debug/extension.xml":"c8cdbb65c17dfe4851e7a56094c492b835f76f06a9cdb1b3fd273584357864b1","api_webgl/extensions/proposals/WEBGL_dynamic_texture/extension.xml":"7f5bc906ba61037befd4acd9fc39209d2e4bd8eea20ba01f34ebe4700bfd1806","api_webgl/extensions/proposals/WEBGL_subarray_uploads/extension.xml":"87cde732f220d4b54faaef1e6d5efc6174849c1b54983908084659f525c7f40f","api_webgl/extensions/proposals/WEBGL_texture_multisample/extension.xml":"338f0fc6f62bf875a0f7b19e4c284ed48e5a76e791e55414843659cf402636da","api_webgl/extensions/proposals/WEBGL_texture_source_iframe/extension.xml":"378beada6abe201a0ebdb68a3935e8bf27f620ae2653d696a38df9e499808eda","api_webgl/extensions/proposals/WEBGL_video_texture/extension.xml":"b9e0ffa1cf37c827b9be82d71adcd40ce44d05e434a87d174b289c7a5b9d30b0","api_webgl/extensions/rejected/EXT_texture_storage/extension.xml":"9fb3883d1b6d73e09b03129a30845031e0b27c9003b9fb0e2f2b2b2d5a9dbb1e","api_webgl/extensions/rejected/OES_depth24/extension.xml":"159c541fc025c3d454887cdedd1ff5c19ed17e9356c63d95510d70c586502af7","api_webgl/extensions/rejected/WEBGL_debug_shader_precision/extension.xml":"f618d6f82e21cf78146e86c396a3d7b3dd51cf778ab2dc7a504834d835abc5c8","api_webgl/extensions/rejected/WEBGL_draw_elements_no_range_check/extension.xml":"a3a616760a9cca44ecca27e8a8afd49679974f1bf0dfd4624231bcffaf4aec54","api_webgl/extensions/rejected/WEBGL_subscribe_uniform/extension.xml":"7ec77103308177cdfa0efbc995f62151622c30bab46a4ee191e04520c51965ae","api_webgl/extensions/rejected/WEBGL_texture_from_depth_video/extension.xml":"eabf2a9003050f8ef5ceb4d5cc0fafc98977aef407fb4060d08d704884a3d462","api_webgl/extensions/template/extension.xml":"8da65e0a5d053bf36373c6fcfdf7d8fa2738c48345671cf61b62e30ba9cce117","api_webgl/specs/latest/1.0/webgl.idl":"9ffefd8ed7b99053f0db70966749e8f3d6398e1393367f2772dda6325daf3db8","api_webgl/specs/latest/2.0/webgl2.idl":"121a6d79dae3ce4483b60cf26ee2dbca2e402ad19658c0ba951a5726d49aed22","build.rs":"28156f946b5f8b2ac39237d8ff9070bae75eb0f8f6ac66e5df9c6a0998784d2b","src/lib.rs":"7f1378f4337b537d46a8d67f7224b2c2cc50a633d0326692711e3514374799f4"},"package":"037ab472c33f67b5fbd3e9163a2645319e5356fcd355efa6d4eb7fff4bbcb554"}
\ No newline at end of file
--- a/third_party/rust/khronos_api/Cargo.toml
+++ b/third_party/rust/khronos_api/Cargo.toml
@@ -7,19 +7,19 @@
 #
 # If you believe there's an error in this file please file an
 # issue against the rust-lang/cargo repository. If you're
 # editing this file be aware that the upstream Cargo.toml
 # will likely look very different (and much more reasonable)
 
 [package]
 name = "khronos_api"
-version = "2.0.0"
+version = "2.2.0"
 authors = ["Brendan Zabarauskas <bjzaba@yahoo.com.au>", "Corey Richardson", "Arseny Kapoulkine", "Pierre Krieger <pierre.krieger1708@gmail.com>"]
-include = ["/README.md", "/src/**/*", "/Cargo.toml", "/api/xml/**/*.xml", "/api_egl/api/**/*.xml"]
+include = ["/README.md", "/src/**/*", "/Cargo.toml", "/build.rs", "/api/xml/**/*.xml", "/api_egl/api/**/*.xml", "/api_webgl/specs/latest/**/*.idl", "/api_webgl/extensions/**/extension.xml"]
 description = "The Khronos XML API Registry, exposed as byte string constants."
 homepage = "https://github.com/brendanzab/gl-rs/khronos_api/"
 documentation = "https://docs.rs/khronos_api"
 readme = "README.md"
 keywords = ["gl", "egl", "opengl", "khronos"]
 categories = ["rendering::graphics-api"]
 license = "Apache-2.0"
 repository = "https://github.com/brendanzab/gl-rs/"
--- a/third_party/rust/khronos_api/README.md
+++ b/third_party/rust/khronos_api/README.md
@@ -12,15 +12,18 @@ khronos_api = "1.0.0"
 ```
 
 The following constants are provided:
 
 - `GL_XML`: the contents of [`gl.xml`](https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/gl.xml)
 - `EGL_XML`: the contents of [`egl.xml`](https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/egl.xml)
 - `WGL_XML`: the contents of [`wgl.xml`](https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/wgl.xml)
 - `GLX_XML`: the contents of [`glx.xml`](https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/glx.xml)
+- `WEBGL_IDL`: the contents of [`webgl.idl`](https://raw.githubusercontent.com/KhronosGroup/WebGL/master/specs/latest/1.0/webgl.idl)
+- `WEBGL2_IDL`: the contents of [`webgl2.idl`](https://raw.githubusercontent.com/KhronosGroup/WebGL/master/specs/latest/2.0/webgl2.idl)
+- `WEBGL_EXT_XML`: the contents of the WebGL extension XML files
 
 ## Changelog
 
 ### v1.0.0
 
 - Initial release
 - Documentation improvements
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/ANGLE_instanced_arrays/extension.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0"?>
+<ratified href="ANGLE_instanced_arrays/">
+  <name>ANGLE_instanced_arrays</name>
+  <contact>
+    <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL working group</a> (public_webgl 'at' khronos.org)
+  </contact>
+  <contributors>
+    <contributor>Contributors to ANGLE_instanced_arrays</contributor>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+  <number>19</number>
+  <depends>
+    <api version="1.0"/>
+    <core version="2.0" />
+  </depends>
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt" name="ANGLE_instanced_arrays">
+      <addendum>
+        The implementation must validate the indices referenced by <code>drawArraysInstancedANGLE</code> and <code>drawElementsInstancedANGLE</code>
+        similarly to how indices referenced by <code>drawArrays</code> and <code>drawElements</code> are validated according to section
+        <a href="http://www.khronos.org/registry/webgl/specs/1.0/#ATTRIBS_AND_RANGE_CHECKING">Enabled Vertex Attributes and Range Checking</a> of the
+        WebGL specification.
+      </addendum>
+    </mirrors>
+    <p>
+      Although the extension contains ANGLE in the name it may be exposed by any implementation, whether or not the implementation uses the ANGLE library.
+    </p>
+  </overview>
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface ANGLE_instanced_arrays {
+    const GLenum VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
+    void drawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+    void drawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, GLintptr offset, GLsizei primcount);
+    void vertexAttribDivisorANGLE(GLuint index, GLuint divisor); 
+};
+  </idl>
+  <issues>
+    <p>How does ANGLE_instanced_arrays interact with OES_vertex_array_object?</p>
+    <ul>
+      <li>
+        <p>RESOLVED: When the ANGLE_instanced_arrays and OES_vertex_array_object
+        extensions are both enabled, attribute divisors are tracked by the
+        vertex array objects like any other vertex array state.
+        </p>
+      </li>
+    </ul>
+  </issues>
+  <history>
+    <revision date="2012/03/06">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2013/01/26">
+      <change>Moved from proposal to draft.</change>
+    </revision>
+    <revision date="2013/03/11">
+      <change>Renumbered to 19 to fix misnumbering problem.</change>
+    </revision>
+    <revision date="2013/08/06">
+      <change>Moved to community approved.</change>
+    </revision>
+    <revision date="2013/08/22">
+      <change>Clarified non-ANGLE support.</change>
+    </revision>
+    <revision date="2014/03/13">
+      <change>Addendum about index validation.</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+    <revision date="2014/08/08">
+      <change>Ratified by Khronos Board of Promoters.</change>
+    </revision>
+    <revision date="2015/09/23">
+      <change>Clarified interaction with OES_vertex_array_object.</change>
+    </revision>
+  </history>
+</ratified>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/EXT_blend_minmax/extension.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ratified href="EXT_blend_minmax/">
+  <name>EXT_blend_minmax</name>
+
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Florian Boesch (pyalot 'at' gmail.com)</contributor>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>25</number>
+
+  <depends>
+    <api version="1.0"/>
+    <core version="2.0" />
+  </depends>
+
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/EXT/blend_minmax.txt"
+             name="EXT_blend_minmax">
+    </mirrors>
+
+    <features>
+      <feature>
+        The <code>blendEquation</code> and <code>blendEquationSeparate</code>
+        entry points are extended to accept <code>MIN_EXT</code> and <code>MAX_EXT</code>
+      </feature>
+    </features>
+  </overview>
+
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface EXT_blend_minmax {
+  const GLenum MIN_EXT = 0x8007;
+  const GLenum MAX_EXT = 0x8008;
+};
+  </idl>
+
+  <samplecode xml:space="preserve">
+    <pre>
+        var ext = gl.getExtension('EXT_blend_minmax');
+        gl.blendEquation(ext.MAX_EXT);
+        gl.getParameter(gl.BLEND_EQUATION) == ext.MAX_EXT;
+    </pre>
+  </samplecode>
+
+  <history>
+    <revision date="2012/12/12">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2014/02/12">
+      <change>Moved to draft.</change>
+    </revision>
+    <revision date="2014/05/12">
+      <change>Removed blendEquationEXT function and the BLEND_EQUATION_EXT and
+        FUNC_ADD_EXT enums, all of which are already have equivalents in WebGL.</change>
+    </revision>
+    <revision date="2014/06/27">
+      <change>Moved to community approved after discussion on public_webgl list.</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+    <revision date="2015/05/29">
+      <change>Ratified by Khronos Board of Promoters.</change>
+    </revision>
+  </history>
+</ratified>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/EXT_color_buffer_float/extension.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<extension href="EXT_color_buffer_float/">
+  <name>EXT_color_buffer_float</name>
+
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Mark Callow, HI Corporation</contributor>
+
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>31</number>
+
+  <depends>
+    <api version="2.0"/>
+  </depends>
+
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/EXT/EXT_color_buffer_float.txt"
+             name="EXT_color_buffer_float">
+      <addendum>
+        The sized internal format <code>RGB16F</code> is not color-renderable in this
+        extension. This is a difference in functionality compared to the <a
+        href="../EXT_color_buffer_half_float">EXT_color_buffer_half_float</a> extension.
+      </addendum>
+    </mirrors>
+
+    <features>
+      <feature>
+        <p>The following floating-point internal formats become <span
+        style="font-style: italic">color-renderable</span>: <code>R16F</code>,
+        <code>RG16F</code>, <code>RGBA16F</code>, <code>R32F</code>,
+        <code>RG32F</code>, <code>RGBA32F</code> and
+        <code>R11F_G11F_B10F</code>. A renderbuffer or a texture with a
+        color-renderable internal format can be used as a rendering target by
+        attaching it to a framebuffer object as a color attachment.</p>
+      </feature>
+
+      <feature>
+        <p>Renderbuffers with these internal formats can be created.</p>
+      </feature>
+
+      <feature>
+        <p>The format and type combination <code>RGBA</code> and
+        <code>FLOAT</code> becomes valid for reading from a floating-point
+        color buffer.</p>
+      </feature>
+    </features>
+
+    <p>Notes: <ul style="list-style-type: circle">
+        <li>Fragment shader outputs to buffers with these internal formats are
+        not clamped.</li>
+
+        <li>Colors specified with <code>clearColor</code> and
+        <code>blendColor</code> are not clamped when applied to buffers with
+        these internal formats.</li>
+
+        <li>The format and type combination <code>RGBA</code> and
+        <code>UNSIGNED_BYTE</code> cannot be used for reading from a
+        floating-point color buffer.</li>
+
+        <li>Multi-sample floating-point color renderbuffers may optionally be supported. Limitations
+        are defined in the <a
+        href="http://www.khronos.org/registry/gles/extensions/EXT/EXT_color_buffer_float.txt">EXT_color_buffer_float</a>
+        extension.</li>
+
+        <li>The sized internal format <code>RGB16F</code> is not color-renderable in this
+        extension.</li>
+      </ul></p>
+  </overview>
+
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface EXT_color_buffer_float {
+}; // interface EXT_color_buffer_float
+</idl>
+
+  <history>
+    <revision date="2012/11/08">
+      <change>Initial revision.</change>
+    </revision>
+
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+
+    <revision date="2014/10/29">
+      <change>Moved to draft status.</change>
+    </revision>
+
+    <revision date="2016/04/14">
+      <change>Moved to community approved status.</change>
+    </revision>
+
+    <revision date="2016/06/16">
+      <change>Added note about RGB16F not being color-renderable.</change>
+    </revision>
+
+    <revision date="2016/07/21">
+      <change>Allowed allocation of multi-sample floating-point color renderbuffers as optional functionality.</change>
+      <change>Changed XML tags to fix incorrect statement that there are no behavioral changes compared to the native extension.</change>
+    </revision>
+
+    <revision date="2016/08/03">
+      <change>Removed incorrect statement about framebuffer completeness and multi-sampled floating-point color renderbuffers.</change>
+    </revision>
+
+    <revision date="2017/04/19">
+      <change>Allowed these float formats for CopyTexImage2D.</change>
+    </revision>
+  </history>
+</extension>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/EXT_color_buffer_half_float/extension.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<extension href="EXT_color_buffer_half_float/">
+  <name>EXT_color_buffer_half_float</name>
+
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Mark Callow, HI Corporation</contributor>
+
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>14</number>
+
+  <depends>
+    <api version="1.0"/>
+
+    <ext name="OES_texture_half_float" require="true"/>
+
+    <subsumed version="2.0" by="EXT_color_buffer_float" />
+  </depends>
+
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/EXT/EXT_color_buffer_half_float.txt"
+             name="EXT_color_buffer_half_float">
+      <addendum>
+        <p>All references to <code>R16F</code> and <code>RG16F</code> types
+        are ignored.</p>
+      </addendum>
+      <addendum>
+	<p>WebGL implementations supporting this extension are required to
+	support rendering to <code>RGBA16F</code> format.</p>
+      </addendum>
+    </mirrors>
+
+    <features>
+      <feature>
+        <p>The 16-bit floating-point types <code>RGB16F</code> and
+        <code>RGBA16F</code> become available as color-renderable formats.
+        Renderbuffers can be created in these formats. These and textures
+        created with <code>type = HALF_FLOAT_OES</code>, which will have one
+        of these internal formats, can be attached to framebuffer object color
+        attachments for rendering. Implementations supporting this extension are
+	required to support rendering to <code>RGBA16F</code> format.
+	Applications must check framebuffer completeness to determine if
+	<code>RGB16F</code> is supported.</p>
+      </feature>
+
+      <feature>
+        <p><span style="color: red">NOTE:</span> fragment shaders outputs
+        gl_FragColor and gl_FragData[0] will only be clamped and converted
+        when the color buffer is fixed-point and <code>blendColor()</code> and
+        <code>clearColor()</code> will no longer clamp their parameter values
+        on input. Clamping will be applied as necessary at draw time according
+        to the type of color buffer in use.</p>
+      </feature>
+
+      <feature>
+        <p>The format and type combination <code>RGBA</code> and
+        <code>FLOAT</code> becomes valid for reading from a floating-point
+        rendering buffer. Note: <code>RGBA</code> and
+        <code>UNSIGNED_BYTE</code> cannot be used for reading from a
+        floating-point rendering buffer.</p>
+      </feature>
+
+      <feature>
+        <p>The component types of framebuffer object attachments can be
+        queried.</p>
+      </feature>
+    </features>
+  </overview>
+
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface EXT_color_buffer_half_float {
+  const GLenum RGBA16F_EXT = 0x881A;
+  const GLenum RGB16F_EXT = 0x881B;
+  const GLenum FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT = 0x8211;
+  const GLenum UNSIGNED_NORMALIZED_EXT = 0x8C17;
+}; // interface EXT_color_buffer_half_float
+  </idl>
+
+  <additions>
+    <p>In section 5.13.12 <cite>Reading back pixels</cite>, change the allowed
+    format and types table to:</p>
+
+    <dl class="methods">
+      <dd>
+        <table>
+          <tbody>
+            <tr>
+              <th>frame buffer type</th>
+              <th>
+                <code>format</code>
+              </th>
+              <th>
+                <code>type</code>
+              </th>
+            </tr>
+
+            <tr>
+              <td>normalized fixed-point</td>
+              <td>RGBA</td>
+              <td>UNSIGNED_BYTE</td>
+            </tr>
+
+            <tr>
+              <td>floating-point</td>
+              <td>RGBA</td>
+              <td>FLOAT</td>
+            </tr>
+          </tbody>
+        </table>
+      </dd>
+    </dl>
+
+    <p>Change the paragraph beginning "If <code>pixels</code> is null ..."
+    to</p><blockquote>If frame buffer type is not that indicated in the table for
+    the <code>format</code> and <code>type</code> combination, an
+    INVALID_OPERATON error is generated. If pixels is null
+    ...</blockquote>
+  </additions>
+
+  <history>
+    <revision date="2012/11/08">
+      <change>Initial revision.</change>
+    </revision>
+
+    <revision date="2012/11/13">
+      <change>"Add reading-pixels-as-FLOAT feature to the Overview and related
+      changes to WebGL section 5.13.12.</change>
+    </revision>
+
+    <revision date="2012/11/26">
+      <change>Move to draft.</change>
+    </revision>
+
+    <revision date="2014/07/15">
+      <change>Removed webgl module. Added NoInterfaceObject extended attribute.</change>
+    </revision>
+
+    <revision date="2014/11/24">
+      <change>Move to community approved.</change>
+    </revision>
+
+    <revision date="2016/05/05">
+      <change>Subsumed in WebGL 2.0 by EXT_color_buffer_float.</change>
+    </revision>
+
+    <revision date="2017/09/14">
+      <change>Require RGBA16F to be color-renderable and RGB16F to be optionally color-renderable.</change>
+    </revision>
+  </history>
+</extension>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/EXT_disjoint_timer_query/extension.xml
@@ -0,0 +1,358 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<extension href="EXT_disjoint_timer_query/">
+  <name>EXT_disjoint_timer_query</name>
+
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Contributors to ARB_occlusion_query</contributor>
+    <contributor>Contributors to EXT_timer_query</contributor>
+    <contributor>Contributors to ARB_timer_query</contributor>
+    <contributor>Ben Vanik, Google Inc.</contributor>
+    <contributor>Daniel Koch, TransGaming Inc.</contributor>
+    <contributor>Florian Boesch (pyalot 'at' gmail.com)</contributor>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>26</number>
+
+  <depends>
+    <api version="1.0"/>
+  </depends>
+
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt"
+             name="EXT_disjoint_timer_query">
+      <addendum>
+        Specifies that queries' results only become available at certain well-defined times.
+      </addendum>
+    </mirrors>
+
+    <features>
+      <feature>
+        This extension provides a query mechanism that can be used to determine
+        the amount of time it takes to fully complete a set of GL commands, and
+        without stalling the rendering pipeline.  It uses the query object
+        mechanisms first introduced in the occlusion query extension, which allow
+        time intervals to be polled asynchronously by the application.
+      </feature>
+      <feature>
+        This version of the disjoint_timer_query extension is exposed
+        only on on WebGL 1.0 contexts. See the _webgl2 version of the
+        extension for how it is exposed on WebGL 2.0 contexts.
+      </feature>
+    </features>
+  </overview>
+
+  <idl xml:space="preserve">
+typedef unsigned long long GLuint64EXT;
+
+[NoInterfaceObject]
+interface WebGLTimerQueryEXT : WebGLObject {
+};
+
+[NoInterfaceObject]
+interface EXT_disjoint_timer_query {
+  const GLenum QUERY_COUNTER_BITS_EXT      = 0x8864;
+  const GLenum CURRENT_QUERY_EXT           = 0x8865;
+  const GLenum QUERY_RESULT_EXT            = 0x8866;
+  const GLenum QUERY_RESULT_AVAILABLE_EXT  = 0x8867;
+  const GLenum TIME_ELAPSED_EXT            = 0x88BF;
+  const GLenum TIMESTAMP_EXT               = 0x8E28;
+  const GLenum GPU_DISJOINT_EXT            = 0x8FBB;
+
+  WebGLTimerQueryEXT? createQueryEXT();
+  void deleteQueryEXT(WebGLTimerQueryEXT? query);
+  [WebGLHandlesContextLoss] boolean isQueryEXT(WebGLTimerQueryEXT? query);
+  void beginQueryEXT(enum target, WebGLTimerQueryEXT query);
+  void endQueryEXT(enum target);
+  void queryCounterEXT(WebGLTimerQueryEXT query, enum target);
+  any getQueryEXT(enum target, enum pname);
+  any getQueryObjectEXT(WebGLTimerQueryEXT query, enum pname);
+};
+  </idl>
+
+  <newfun>
+    <function name="createQueryEXT" type="WebGLTimerQueryEXT?">
+    </function>
+  </newfun>
+
+  <newfun>
+    <function name="deleteQueryEXT" type="void">
+      <param name="query" type="WebGLTimerQueryEXT?"/>
+    </function>
+  </newfun>
+
+  <newfun>
+    <function name="isQueryEXT" type="boolean">
+      <param name="query" type="WebGLTimerQueryEXT?"/>
+      Returns true if the passed WebGLTimerQueryEXT is valid and false otherwise. Returns false if
+      the query's <a
+      href="http://www.khronos.org/registry/webgl/specs/1.0.1/#webgl-object-invalidated-flag">invalidated
+      flag</a> is set.
+    </function>
+  </newfun>
+
+  <newfun>
+    <function name="beginQueryEXT" type="void">
+      <param name="target" type="GLenum"/>
+      <param name="query" type="WebGLTimerQueryEXT?"/>
+      <code>target</code> accepts <code>TIME_ELAPSED_EXT</code>.
+    </function>
+  </newfun>
+
+  <newfun>
+    <function name="endQueryEXT" type="void">
+      <param name="target" type="GLenum"/>
+      <code>target</code> accepts <code>TIME_ELAPSED_EXT</code>.
+    </function>
+  </newfun>
+
+  <newfun>
+    <function name="queryCounterEXT" type="void">
+      <param name="query" type="WebGLTimerQueryEXT?"/>
+      <param name="target" type="GLenum"/>
+      <code>target</code> accepts <code>TIMESTAMP_EXT</code>.
+    </function>
+  </newfun>
+
+  <newfun>
+    <function name="getQueryEXT" type="any">
+      <param name="target" type="GLenum"/>
+      <param name="pname" type="GLenum"/>
+      <code>target</code> and <code>pname</code> accept the following combinations of
+      parameters. The return type of this method depends on the parameter queried.
+      <br/>
+      <table width="30%">
+      <tr><th>target</th><th>pname</th><th>returned type</th></tr>
+      <tr><td>TIME_ELAPSED_EXT</td><td>CURRENT_QUERY</td><td>WebGLQuery?</td></tr>
+      <tr><td>TIMESTAMP_EXT</td><td>CURRENT_QUERY</td><td>null</td></tr>
+      <tr><td>TIME_ELAPSED_EXT</td><td>QUERY_COUNTER_BITS_EXT</td><td>GLint</td></tr>
+      <tr><td>TIMESTAMP_EXT</td><td>QUERY_COUNTER_BITS_EXT</td><td>GLint</td></tr>
+      </table>      
+    </function>
+  </newfun>
+
+  <newfun>
+    <function name="getQueryObjectEXT" type="any">
+      <param name="query" type="WebGLTimerQueryEXT?"/>
+      <param name="pname" type="GLenum"/>
+      <code>pname</code> accepts <code>QUERY_RESULT_EXT</code> or <code>QUERY_RESULT_AVAILABLE_EXT</code>.
+      <br/>
+      The return type of this method depends on the parameter queried:
+      <table width="30%">
+      <tr><th>pname</th><th>returned type</th></tr>
+      <tr><td>QUERY_RESULT_EXT</td><td>GLuint64EXT</td></tr>
+      <tr><td>QUERY_RESULT_AVAILABLE_EXT</td><td>boolean</td></tr>
+      </table>      
+      <br/>
+      In order to ensure consistent behavior across platforms, queries' results must only be made
+      available when the user agent's <a
+      href="http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#event-loops">event
+      loop</a> is not executing a task. In other words:
+      <ul>
+        <li> A query's result must not be made available until control has returned to the user
+             agent's main loop. </li>
+        <li> Repeatedly fetching a query's QUERY_RESULT_AVAILABLE_EXT parameter in a loop, without
+             returning control to the user agent, must always return the same value. </li>
+      </ul>
+
+      <div class="note">
+        A query's result may or may not be made available when control returns to the user
+        agent's event loop. It is not guaranteed that using a single setTimeout callback with a
+        delay of 0, or a single requestAnimationFrame callback, will allow sufficient time for
+        the WebGL implementation to supply the query's results.
+      </div>
+
+      <div class="note rationale">
+        This change compared to the original extension specification is enforced in order to prevent
+        applications from relying on being able to issue a query and fetch its result in the same
+        frame. In order to ensure best portability among devices and best performance among
+        implementations, applications must expect that queries' results will become available
+        asynchronously.
+      </div>
+    </function>
+  </newfun>
+  
+  <newtok>
+    <function name="getParameter" type="any">
+      <param name="pname" type="GLenum"/>
+      <code>pname</code> accepts <code>TIMESTAMP_EXT</code> or <code>GPU_DISJOINT_EXT</code>.
+      <br/>
+
+      The return type depends on the parameter queried:
+      <table width="30%">
+      <tr><th>pname</th><th>returned type</th></tr>
+      <tr><td>TIMESTAMP_EXT</td><td>GLuint64EXT</td></tr>
+      <tr><td>GPU_DISJOINT_EXT</td><td>boolean</td></tr>
+      </table>      
+    </function>
+  </newtok>
+
+  <issues>
+    <ol>
+      <li>
+        <p>
+          Can getQueryObjectEXT be exposed in its current form according to ECMAScript
+          semantics?  ECMAScript's <a
+          href="http://wiki.ecmascript.org/doku.php?id=strawman:concurrency">de-facto concurrency
+          model</a> is "shared nothing" communicating event loops. Is it acceptable for sequential
+          calls to getQueryObjectEXT to return different answers? Note that Date.now() advances
+          during script execution, so this may be fine; but if concerns are raised, then the API may
+          need to be redesigned to use callbacks.
+        </p>
+      </li>
+    </ol>
+  </issues>
+
+  <samplecode xml:space="preserve">
+    <pre>
+        // Example (1) -- uses beginQueryEXT/endQueryEXT.
+        var ext = gl.getExtension('EXT_disjoint_timer_query');
+        var query = ext.createQueryEXT();
+        ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, query);
+
+        // Draw object
+        gl.drawElements(...);
+
+        ext.endQueryEXT(ext.TIME_ELAPSED_EXT);
+
+        // ...at some point in the future, after returning control to the browser and being called again:
+        var available = ext.getQueryObjectEXT(query, ext.QUERY_RESULT_AVAILABLE_EXT);
+        var disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
+
+        if (available &amp;&amp; !disjoint) {
+          // See how much time the rendering of the object took in nanoseconds.
+          var timeElapsed = ext.getQueryObjectEXT(query, ext.QUERY_RESULT_EXT);
+
+          // Do something useful with the time.  Note that care should be
+          // taken to use all significant bits of the result, not just the
+          // least significant 32 bits.
+          adjustObjectLODBasedOnDrawTime(timeElapsed);
+        }
+
+        //----------------------------------------------------------------------
+
+        // Example (2) -- same as the example above, but uses queryCounterEXT instead.
+        var ext = gl.getExtension('EXT_disjoint_timer_query');
+        var startQuery = ext.createQueryEXT();
+        var endQuery = ext.createQueryEXT();
+        ext.queryCounterEXT(startQuery, ext.TIMESTAMP_EXT);
+
+        // Draw object
+        gl.drawElements(...);
+
+        ext.queryCounterEXT(endQuery, ext.TIMESTAMP_EXT);
+
+        // ...at some point in the future, after returning control to the browser and being called again:
+        var available = ext.getQueryObjectEXT(endQuery, ext.QUERY_RESULT_AVAILABLE_EXT);
+        var disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
+
+        if (available &amp;&amp; !disjoint) {
+          // See how much time the rendering of the object took in nanoseconds.
+          var timeStart = ext.getQueryObjectEXT(startQuery, ext.QUERY_RESULT_EXT);
+          var timeEnd = ext.getQueryObjectEXT(endQuery, ext.QUERY_RESULT_EXT);
+
+          // Do something useful with the time.  Note that care should be
+          // taken to use all significant bits of the result, not just the
+          // least significant 32 bits.
+          adjustObjectLODBasedOnDrawTime(timeEnd - timeStart);
+        }
+
+        //----------------------------------------------------------------------
+
+        // Example (3) -- check the number of timestamp bits to determine how to best
+        // measure elapsed time.
+        var ext = gl.getExtension('EXT_disjoint_timer_query');
+        var timeElapsedQuery;
+        var startQuery;
+        var endQuery;
+
+        var useTimestamps = false;
+
+        if (ext.getQueryEXT(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT) > 0) {
+          useTimestamps = true;
+        }
+
+        // Clear the disjoint state before starting to work with queries to increase
+        // the chances that the results will be valid.
+        gl.getParameter(ext.GPU_DISJOINT_EXT);
+
+        if (useTimestamps) {
+          startQuery = ext.createQueryEXT();
+          endQuery = ext.createQueryEXT();
+          ext.queryCounterEXT(startQuery, ext.TIMESTAMP_EXT);
+        } else {
+          timeElapsedQuery = ext.createQueryEXT();
+          ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, timeElapsedQuery);
+        }
+
+        // Draw object
+        gl.drawElements(...);
+
+        if (useTimestamps) {
+          ext.queryCounterEXT(endQuery, ext.TIMESTAMP_EXT);
+        } else {
+          ext.endQueryEXT(ext.TIME_ELAPSED_EXT);
+        }
+
+        // ...at some point in the future, after returning control to the browser and being called again:
+        var disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
+        if (disjoint) {
+          // Have to redo all of the measurements.
+        } else {
+          var available;
+          if (useTimestamps) {
+            available = ext.getQueryObjectEXT(endQuery, ext.QUERY_RESULT_AVAILABLE_EXT);
+          } else {
+            available = ext.getQueryObjectEXT(timeElapsedQuery, ext.QUERY_RESULT_AVAILABLE_EXT);
+          }
+
+          if (available) {
+            var timeElapsed;
+            if (useTimestamps) {
+              // See how much time the rendering of the object took in nanoseconds.
+              var timeStart = ext.getQueryObjectEXT(startQuery, ext.QUERY_RESULT_EXT);
+              var timeEnd = ext.getQueryObjectEXT(endQuery, ext.QUERY_RESULT_EXT);
+              timeElapsed = timeEnd - timeStart;
+            } else {
+              timeElapsed = ext.getQueryObjectEXT(query, ext.QUERY_RESULT_EXT);
+            }
+
+            // Do something useful with the time.  Note that care should be
+            // taken to use all significant bits of the result, not just the
+            // least significant 32 bits.
+            adjustObjectLODBasedOnDrawTime(timeElapsed);
+          }
+        }
+    </pre>
+  </samplecode>
+
+  <history>
+    <revision date="2013/04/02">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2013/04/03">
+      <change>Based on public_webgl discussion, specified that queries' results only become available at well-defined times.</change>
+    </revision>
+    <revision date="2014/02/12">
+      <change>Recast as EXT_disjoint_timer_query and harmonized with mirrored extension.</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+    <revision date="2015/10/05">
+      <change>Revised language regarding queries' availability based on feedback from Jeff Gilbert.</change>
+    </revision>
+    <revision date="2015/10/19">
+      <change>Promoted to community approved after discussion on public_webgl.</change>
+    </revision>
+    <revision date="2016/06/08">
+      <change>Added example choosing measurement technique based on number of timestamp bits.</change>
+    </revision>
+    <revision date="2016/09/30">
+      <change>Added clarifying note that this document only applies to WebGL 1.0. Minor reformatting and typo fixes.</change>
+    </revision>
+  </history>
+</extension>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/EXT_disjoint_timer_query_webgl2/extension.xml
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<extension href="EXT_disjoint_timer_query_webgl2/">
+  <name>EXT_disjoint_timer_query_webgl2</name>
+
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Contributors to ARB_occlusion_query</contributor>
+    <contributor>Contributors to EXT_timer_query</contributor>
+    <contributor>Contributors to ARB_timer_query</contributor>
+    <contributor>Ben Vanik, Google Inc.</contributor>
+    <contributor>Daniel Koch, TransGaming Inc.</contributor>
+    <contributor>Florian Boesch (pyalot 'at' gmail.com)</contributor>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>33</number>
+
+  <depends>
+    <api version="2.0"/>
+  </depends>
+
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt"
+             name="EXT_disjoint_timer_query">
+      <addendum>
+        Specifies that queries' results only become available at certain well-defined times.
+      </addendum>
+    </mirrors>
+
+    <features>
+      <feature>
+        This extension provides the same functionality as <a
+        href="../EXT_disjoint_timer_query/">EXT_disjoint_timer_query</a>. The IDL, description, and
+        extension name are specialized for WebGL 2.0, which incorporates query objects into the core
+        specification.
+      </feature>
+    </features>
+  </overview>
+
+  <idl xml:space="preserve">
+typedef unsigned long long GLuint64EXT;
+
+[NoInterfaceObject]
+interface EXT_disjoint_timer_query_webgl2 {
+  const GLenum QUERY_COUNTER_BITS_EXT      = 0x8864;
+  const GLenum TIME_ELAPSED_EXT            = 0x88BF;
+  const GLenum TIMESTAMP_EXT               = 0x8E28;
+  const GLenum GPU_DISJOINT_EXT            = 0x8FBB;
+
+  void queryCounterEXT(WebGLQuery query, enum target);
+};
+  </idl>
+
+  <newtok>
+    <function name="beginQuery" type="">
+      <param name="target" type="GLenum"/>
+      <param name="query" type="WebGLQuery?"/>
+      <code>target</code> accepts <code>TIME_ELAPSED_EXT</code>.
+    </function>
+  </newtok>
+
+  <newtok>
+    <function name="endQuery" type="void">
+      <param name="target" type="GLenum"/>
+      <code>target</code> accepts <code>TIME_ELAPSED_EXT</code>.
+    </function>
+  </newtok>
+
+  <newfun>
+    <function name="queryCounterEXT" type="void">
+      <param name="query" type="WebGLQuery"/>
+      <param name="target" type="GLenum"/>
+      <code>target</code> accepts <code>TIMESTAMP_EXT</code>.
+    </function>
+  </newfun>
+
+  <newtok>
+    <function name="getQuery" type="any">
+      <param name="target" type="GLenum"/>
+      <param name="pname" type="GLenum"/>
+      <code>target</code> and <code>pname</code> accept the following combinations of
+      parameters. The return type of this method now depends on the parameter queried.
+      <br/>
+      <table width="30%">
+      <tr><th>target</th><th>pname</th><th>returned type</th></tr>
+      <tr><td>TIME_ELAPSED_EXT</td><td>CURRENT_QUERY</td><td>WebGLQuery?</td></tr>
+      <tr><td>TIMESTAMP_EXT</td><td>CURRENT_QUERY</td><td>null</td></tr>
+      <tr><td>TIME_ELAPSED_EXT</td><td>QUERY_COUNTER_BITS_EXT</td><td>GLint</td></tr>
+      <tr><td>TIMESTAMP_EXT</td><td>QUERY_COUNTER_BITS_EXT</td><td>GLint</td></tr>
+      </table>      
+    </function>
+  </newtok>
+
+  <newtok>
+    <function name="getParameter" type="any">
+      <param name="pname" type="GLenum"/>
+      <code>pname</code> accepts <code>TIMESTAMP_EXT</code> or <code>GPU_DISJOINT_EXT</code>.
+      <br/>
+
+      The return type depends on the parameter queried:
+      <table width="30%">
+      <tr><th>pname</th><th>returned type</th></tr>
+      <tr><td>TIMESTAMP_EXT</td><td>GLuint64EXT</td></tr>
+      <tr><td>GPU_DISJOINT_EXT</td><td>boolean</td></tr>
+      </table>      
+    </function>
+  </newtok>
+
+  <samplecode xml:space="preserve">
+    <pre>
+        // Example (1) -- uses beginQuery/endQuery.
+        var ext = gl.getExtension('EXT_disjoint_timer_query_webgl2');
+        var query = gl.createQuery();
+        gl.beginQuery(ext.TIME_ELAPSED_EXT, query);
+
+        // Draw object
+        gl.drawElements(...);
+
+        gl.endQuery(ext.TIME_ELAPSED_EXT);
+
+        // ...at some point in the future, after returning control to the browser and being called again:
+        var available = gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE);
+        var disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
+
+        if (available &amp;&amp; !disjoint) {
+          // See how much time the rendering of the object took in nanoseconds.
+          var timeElapsed = gl.getQueryParameter(query, gl.QUERY_RESULT);
+
+          // Do something useful with the time.  Note that care should be
+          // taken to use all significant bits of the result, not just the
+          // least significant 32 bits.
+          adjustObjectLODBasedOnDrawTime(timeElapsed);
+        }
+
+        //----------------------------------------------------------------------
+
+        // Example (2) -- same as the example above, but uses queryCounterEXT instead.
+        var ext = gl.getExtension('EXT_disjoint_timer_query_webgl2');
+        var startQuery = gl.createQuery();
+        var endQuery = gl.createQuery();
+        ext.queryCounterEXT(startQuery, ext.TIMESTAMP_EXT);
+
+        // Draw object
+        gl.drawElements(...);
+
+        ext.queryCounterEXT(endQuery, ext.TIMESTAMP_EXT);
+
+        // ...at some point in the future, after returning control to the browser and being called again:
+        var available = gl.getQueryParameter(endQuery, gl.QUERY_RESULT_AVAILABLE);
+        var disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
+
+        if (available &amp;&amp; !disjoint) {
+          // See how much time the rendering of the object took in nanoseconds.
+          var timeStart = gl.getQueryParameter(startQuery, gl.QUERY_RESULT);
+          var timeEnd = gl.getQueryParameter(endQuery, gl.QUERY_RESULT);
+
+          // Do something useful with the time.  Note that care should be
+          // taken to use all significant bits of the result, not just the
+          // least significant 32 bits.
+          adjustObjectLODBasedOnDrawTime(timeEnd - timeStart);
+        }
+
+        //----------------------------------------------------------------------
+
+        // Example (3) -- check the number of timestamp bits to determine how to best
+        // measure elapsed time.
+        var ext = gl.getExtension('EXT_disjoint_timer_query_webgl2');
+        var timeElapsedQuery;
+        var startQuery;
+        var endQuery;
+
+        var useTimestamps = false;
+
+        if (gl.getQuery(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT) > 0) {
+          useTimestamps = true;
+        }
+
+        // Clear the disjoint state before starting to work with queries to increase
+        // the chances that the results will be valid.
+        gl.getParameter(ext.GPU_DISJOINT_EXT);
+
+        if (useTimestamps) {
+          startQuery = gl.createQuery();
+          endQuery = gl.createQuery();
+          ext.queryCounterEXT(startQuery, ext.TIMESTAMP_EXT);
+        } else {
+          timeElapsedQuery = gl.createQuery();
+          gl.beginQuery(ext.TIME_ELAPSED_EXT, timeElapsedQuery);
+        }
+
+        // Draw object
+        gl.drawElements(...);
+
+        if (useTimestamps) {
+          ext.queryCounterEXT(endQuery, ext.TIMESTAMP_EXT);
+        } else {
+          gl.endQuery(ext.TIME_ELAPSED_EXT);
+        }
+
+        // ...at some point in the future, after returning control to the browser and being called again:
+        var disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
+        if (disjoint) {
+          // Have to redo all of the measurements.
+        } else {
+          var available;
+          if (useTimestamps) {
+            available = gl.getQueryParameter(endQuery, gl.QUERY_RESULT_AVAILABLE);
+          } else {
+            available = gl.getQueryParameter(timeElapsedQuery, gl.QUERY_RESULT_AVAILABLE);
+          }
+
+          if (available) {
+            var timeElapsed;
+            if (useTimestamps) {
+              // See how much time the rendering of the object took in nanoseconds.
+              var timeStart = gl.getQueryParameter(startQuery, gl.QUERY_RESULT);
+              var timeEnd = gl.getQueryParameter(endQuery, gl.QUERY_RESULT);
+              timeElapsed = timeEnd - timeStart;
+            } else {
+              timeElapsed = gl.getQueryParameter(query, gl.QUERY_RESULT);
+            }
+
+            // Do something useful with the time.  Note that care should be
+            // taken to use all significant bits of the result, not just the
+            // least significant 32 bits.
+            adjustObjectLODBasedOnDrawTime(timeElapsed);
+          }
+        }
+    </pre>
+  </samplecode>
+
+  <history>
+    <revision date="2016/09/30">
+      <change>Split WebGL 2.0 specification of this extension into its own file
+      for better comprehensibility.</change>
+    </revision>
+    <revision date="2016/10/11">
+      <change>Fixed errors in sample code pointed out by @juj.</change>
+    </revision>
+  </history>
+</extension>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/EXT_float_blend/extension.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<draft href="EXT_float_blend/">
+  <name>EXT_float_blend</name>
+
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Mark Callow</contributor>
+
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>35</number>
+
+  <depends>
+    <api version="2.0"/>
+    <ext name="EXT_color_buffer_float" require="true"/>
+  </depends>
+
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/EXT/EXT_float_blend.txt"
+             name="EXT_float_blend"/>
+
+    <features>
+      <feature>
+        <p>An <code>INVALID_OPERATION</code> error will no longer be raised by
+        <code>drawArrays</code> or <code>drawElements</code> when blending is
+        enabled and the draw buffer has 32-bit floating-point components. Note
+        that in order to create such a draw buffer the
+        <a href="http://www.khronos.org/registry/webgl/extensions/EXT_color_buffer_float">
+        EXT_color_buffer_float</a> extension must be enabled.</p>
+      </feature>
+    </features>
+
+  </overview>
+
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface EXT_float_blend {
+}; // interface EXT_float_blend
+</idl>
+
+  <history>
+    <revision date="2015/04/13">
+      <change>Initial revision.</change>
+    </revision>
+
+    <revision date="2017/01/03">
+      <change>Promoted to draft status after discussion on public_webgl.</change>
+    </revision>
+  </history>
+</draft>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/EXT_frag_depth/extension.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ratified href="EXT_frag_depth/">
+  <name>EXT_frag_depth</name>
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Florian Boesch (pyalot 'at' gmail.com)</contributor>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>16</number>
+
+  <depends>
+    <api version="1.0"/>
+    <core version="2.0">
+      <glsl version="300 es"/>
+    </core>
+  </depends>
+
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/EXT/EXT_frag_depth.txt"
+             name="EXT_frag_depth">
+    </mirrors>
+
+    <features>
+      <feature>
+            Adds the ability to set the depth value of a fragment from
+            within the fragment shader with the built-in output variable gl_FragDepthEXT.
+      </feature>
+      <glsl extname="GL_EXT_frag_depth">
+        <stage type="fragment"/>
+        <output name="gl_FragDepthEXT" type="float" />
+      </glsl>
+    </features>
+  </overview>
+  
+  <idl xml:space="preserve">
+    [NoInterfaceObject]
+    interface EXT_frag_depth {
+    };
+  </idl>
+
+  <samplecode xml:space="preserve">
+    <pre>
+    void main(){
+        gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
+        gl_FragDepthEXT = 0.5;
+    }
+    </pre>
+  </samplecode>
+
+  <history>
+    <revision date="2012/11/22">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2012/12/17">
+      <change>Moved to draft.</change>
+    </revision>
+    <revision date="2014/05/13">
+      <change>Moved to community approved.</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+    <revision date="2015/05/29">
+      <change>Ratified by Khronos Board of Promoters.</change>
+    </revision>
+  </history>
+</ratified>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/EXT_sRGB/extension.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<extension href="EXT_sRGB/">
+  <name>EXT_sRGB</name>
+
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Florian Boesch (pyalot 'at' gmail.com)</contributor>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>17</number>
+
+  <depends>
+    <api version="1.0"/>
+    <core version="2.0">
+      <addendum>Additional format restrictions apply for CopyTexImage2D</addendum>
+    </core>
+  </depends>
+
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/EXT/EXT_sRGB.txt"
+             name="EXT_sRGB">
+    </mirrors>
+
+    <features>
+      <feature>
+         Adds the sRGB support to textures and framebuffer objects.
+      </feature>
+    </features>
+  </overview>
+
+  <idl xml:space="preserve">
+    [NoInterfaceObject]
+    interface EXT_sRGB {
+      const GLenum SRGB_EXT                                     = 0x8C40;
+      const GLenum SRGB_ALPHA_EXT                               = 0x8C42;
+      const GLenum SRGB8_ALPHA8_EXT                             = 0x8C43;
+      const GLenum FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT    = 0x8210;
+    };
+  </idl>
+
+  <newtok>
+    <function name="texImage2D">
+      <param name="format" type="GLenum"/>
+      <param name="internalformat" type="GLenum"/>
+      Accepted by the <code>format</code> and <code>internalformat</code> parameters: <code>SRGB_EXT</code> and <code>SRGB_ALPHA_EXT</code>
+    </function>
+    <function name="texSubImage2D">
+      <param name="format" type="GLenum"/>
+      Accepted by the <code>format</code> parameter: <code>SRGB_EXT</code> and <code>SRGB_ALPHA_EXT</code>
+    </function>
+    <function name="renderbufferStorage">
+      <param name="internalformat" type="GLenum"/>
+      Accepted by the <code>internalformat</code> parameter: <code>SRGB_ALPHA8_EXT</code>
+    </function>
+    <function name="getFramebufferAttachmentParameter">
+      <param name="pname" type="GLenum"/>
+      Accepted by the <code>pname</code> parameter: FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT
+    </function>
+  </newtok>
+
+  <samplecode xml:space="preserve">
+    <pre>
+        var ext = gl.getExtension('EXT_sRGB');
+        var texture = gl.createTexture();
+        gl.bindTexture(gl.TEXTURE_2D, texture);
+        texImage2D(gl.TEXTURE_2D, 0, ext.SRGB_EXT, 256, 256, 0, ext.SRGB_EXT, gl.UNSIGNED_BYTE, data);
+    </pre>
+  </samplecode>
+
+  <history>
+    <revision date="2012/12/16">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2013/01/26">
+      <change>Moved from proposal to draft</change>
+    </revision>
+    <revision date="2014/05/13">
+      <change>Moved from draft to community approved</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+  </history>
+</extension>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/EXT_shader_texture_lod/extension.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ratified href="EXT_shader_texture_lod/">
+  <name>EXT_shader_texture_lod</name>
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Vladimir Vukicevic (vladimir 'at' mozilla.com)</contributor>
+    <contributor>Florian Boesch (pyalot 'at' gmail.com)</contributor>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>27</number>
+
+  <depends>
+    <api version="1.0"/>
+    <core version="2.0">
+      <glsl version="300 es"/>
+    </core>
+  </depends>
+
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/EXT/EXT_shader_texture_lod.txt"
+             name="EXT_shader_texture_lod">
+    </mirrors>
+
+    <features>
+      <feature>
+            This extension adds additional texture functions to the
+            OpenGL ES Shading Language which provide the shader writer
+            with explicit control of LOD.
+      </feature>
+      <glsl extname="GL_EXT_shader_texture_lod">
+        <stage type="fragment"/>
+        <function name="texture2DLodEXT" type="vec4">
+          <param name="sampler" type="sampler2D" />
+          <param name="coord" type="vec2" />
+          <param name="lod" type="float" />
+        </function>
+        <function name="texture2DProjLodEXT" type="vec4">
+          <param name="sampler" type="sampler2D" />
+          <param name="coord" type="vec3" />
+          <param name="lod" type="float" />
+        </function>
+        <function name="texture2DProjLodEXT" type="vec4">
+          <param name="sampler" type="sampler2D" />
+          <param name="coord" type="vec4" />
+          <param name="lod" type="float" />
+        </function>
+        <function name="textureCubeLodEXT" type="vec4">
+          <param name="sampler" type="samplerCube" />
+          <param name="coord" type="vec3" />
+          <param name="lod" type="float" />
+        </function>
+        <function name="texture2DGradEXT" type="vec4">
+          <param name="sampler" type="sampler2D" />
+          <param name="P" type="vec2" />
+          <param name="dPdx" type="vec2" />
+          <param name="dPdy" type="vec2" />
+        </function>
+        <function name="texture2DProjGradEXT" type="vec4">
+          <param name="sampler" type="sampler2D" />
+          <param name="P" type="vec3" />
+          <param name="dPdx" type="vec2" />
+          <param name="dPdy" type="vec2" />
+        </function>
+        <function name="texture2DProjGradEXT" type="vec4">
+          <param name="sampler" type="sampler2D" />
+          <param name="P" type="vec4" />
+          <param name="dPdx" type="vec2" />
+          <param name="dPdy" type="vec2" />
+        </function>
+        <function name="textureCubeGradEXT" type="vec4">
+          <param name="sampler" type="samplerCube" />
+          <param name="P" type="vec3" />
+          <param name="dPdx" type="vec3" />
+          <param name="dPdy" type="vec3" />
+        </function>
+      </glsl>
+    </features>
+  </overview>
+  
+  <idl xml:space="preserve">
+    [NoInterfaceObject]
+    interface EXT_shader_texture_lod {
+    };
+  </idl>
+
+  <samplecode xml:space="preserve">
+    <pre>
+    #extension GL_EXT_shader_texture_lod : enable
+    #extension GL_OES_standard_derivatives : enable
+
+    uniform sampler2D myTexture;
+    varying vec2 texcoord;
+
+    void main(){
+        // avoids artifacts when wrapping texture coordinates
+        gl_FragColor = texture2DGradEXT(myTexture, mod(texcoord, vec2(0.1, 0.5)), dFdx(texcoord), dFdy(texcoord));
+    }
+    </pre>
+  </samplecode>
+
+  <history>
+    <revision date="2014/02/10">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2014/02/18">
+      <change>Moved to draft.</change>
+    </revision>
+    <revision date="2014/06/27">
+      <change>Moved to community approved after discussion on public_webgl list.</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+    <revision date="2014/11/07">
+      <change>Corrected extension name to include GL_ prefix.</change>
+    </revision>
+    <revision date="2015/05/29">
+      <change>Ratified by Khronos Board of Promoters.</change>
+    </revision>
+  </history>
+</ratified>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/EXT_texture_filter_anisotropic/extension.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+
+<ratified href="EXT_texture_filter_anisotropic/">
+  <name>EXT_texture_filter_anisotropic</name>
+  <contact>
+    <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL working group</a> (public_webgl 'at' khronos.org)
+  </contact>
+  <contributors>
+    <contributor>Members of the WebGL working group</contributor>
+    <contributor>Florian B&#246;sch (pyalot 'at' gmail.com)</contributor>
+  </contributors>
+  <number>11</number>
+  <depends>
+    <api version="1.0" />
+  </depends>
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/EXT/texture_filter_anisotropic.txt" name="EXT_texture_filter_anisotropic"/>
+    <features>
+      <feature>
+        The <code>getTexParameter</code>, <code>texParameterf</code> and <code>texParameteri</code> entry points'
+        parameter <code>pname</code> accepts the value <code>TEXTURE_MAX_ANISOTROPY_EXT</code>
+      </feature>
+      <feature>
+        The <code>getParameter</code> entry point parameter <code>pname</code> accepts the value <code>MAX_TEXTURE_MAX_ANISOTROPY_EXT</code>, returning a value of type <code>float</code>.
+      </feature>
+    </features>
+  </overview>
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface EXT_texture_filter_anisotropic {
+  const GLenum TEXTURE_MAX_ANISOTROPY_EXT       = 0x84FE;
+  const GLenum MAX_TEXTURE_MAX_ANISOTROPY_EXT   = 0x84FF;
+};
+  </idl>
+  <history>
+    <revision date="2012/01/27">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2012/02/24">
+      <change>Added the EXT suffix to the enumerants and aliases to the extension name</change>
+    </revision>
+    <revision date="2012/07/19">
+      <change>Moved from draft to community approved status</change>
+    </revision>
+    <revision date="2013/05/15">
+      <change>Ratified by Khronos Board of Promoters.</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+  </history>
+</ratified>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/OES_element_index_uint/extension.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+
+<ratified href="OES_element_index_uint/">
+  <name>OES_element_index_uint</name>
+  <contact>
+    <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL working group</a> (public_webgl 'at' khronos.org)
+  </contact>
+  <contributors>
+    <contributor>Members of the WebGL working group</contributor>
+    <contributor>Florian B&#246;sch (pyalot 'at' gmail.com)</contributor>
+  </contributors>
+  <number>10</number>
+  <depends>
+    <api version="1.0" />
+    <core version="2.0" />
+  </depends>
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/OES/OES_element_index_uint.txt" name="OES_element_index_uint"/>
+    <features>
+      <feature>
+        The <code>drawElements</code> entry point parameter <code>type</code> accepts the value <code>UNSIGNED_INT</code>
+      </feature>
+    </features>
+  </overview>
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface OES_element_index_uint {
+};
+  </idl>
+  <history>
+    <revision date="2012/01/24">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2012/01/27">
+      <change>Removed the bufferData requirement as this is not checked by webgl</change>
+    </revision>
+    <revision date="2012/02/24">
+      <change>Removed the enumerants from the IDL which are contained in the context and added aliases to the extension name</change>
+    </revision>
+    <revision date="2012/10/16">
+      <change>Based on feedback on public_webgl, moved from draft to community approved, and removed aliases.</change>
+    </revision>
+    <revision date="2013/05/15">
+      <change>Ratified by Khronos Board of Promoters.</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+  </history>
+</ratified>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/OES_fbo_render_mipmap/extension.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<draft href="OES_fbo_render_mipmap/">
+  <name>OES_fbo_render_mipmap</name>
+
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Florian Boesch (pyalot 'at' gmail.com)</contributor>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>28</number>
+
+  <depends>
+    <api version="1.0"/>
+    <core version="2.0" />
+  </depends>
+
+  <overview>
+    <mirrors href="https://www.khronos.org/registry/gles/extensions/OES/OES_fbo_render_mipmap.txt"
+             name="OES_fbo_render_mipmap">
+    </mirrors>
+
+    <features>
+      <feature>
+        Any level of a texture can be attached to a framebuffer object.
+      </feature>
+    </features>
+  </overview>
+
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface OES_fbo_render_mipmap {
+};
+  </idl>
+
+  <samplecode xml:space="preserve">
+    <pre>
+        var extension = gl.getExtension('OES_fbo_render_mipmap');
+        if(extension !=== null){
+            var texture = gl.createTexture();
+            gl.bindTexture(gl.TEXTURE_2D, texture);
+            var fbos = [];
+            
+            for(var level=0; level&lt;7; level++){
+                var size = 128/Math.pow(2, level);
+                gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+                var fbo = gl.createFramebuffer();
+                gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, level);
+                fbos.push(fbo);
+                
+                var fboStatus = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+                console.assert(fboStatus == gl.FRAMEBUFFER_COMPLETE, 'Framebuffer is not complete');
+            }
+
+            gl.bindTexture(gl.TEXTURE_2D, null);
+            gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+
+            console.assert(gl.getError() == gl.NO_ERROR, 'A GL error occured');
+        }
+    </pre>
+  </samplecode>
+
+  <history>
+    <revision date="2015/01/26">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2015/01/31">
+      <change>Moved to draft.</change>
+    </revision>
+  </history>
+</draft>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/OES_standard_derivatives/extension.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+
+<ratified href="OES_standard_derivatives/">
+  <name>OES_standard_derivatives</name>
+  <contact>
+    <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL working group</a> (public_webgl 'at' khronos.org)
+  </contact>
+  <contributors>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+  <number>4</number>
+  <depends>
+    <api version="1.0"/>
+    <core version="2.0">
+      <glsl version="300 es"/>
+    </core>
+  </depends>
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/OES/OES_standard_derivatives.txt" name="OES_standard_derivatives" />
+    <features>
+      <feature>
+        The <code>hint</code> entry point accepts <code>FRAGMENT_SHADER_DERIVATIVE_HINT_OES</code>
+           as a target and the <code>getParameter</code> entry point accepts it as a pname.
+      </feature>
+      <glsl extname="GL_OES_standard_derivatives">
+        <stage type="fragment"/>
+        <function name="dFdx" type="genType">
+          <param type="genType" />
+        </function>
+        <function name="dFdy" type="genType">
+          <param type="genType" />
+        </function>
+        <function name="fwidth" type="genType">
+          <param type="genType" />
+        </function>
+      </glsl>
+    </features>
+  </overview>
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface OES_standard_derivatives {
+    const GLenum FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x8B8B;
+};
+  </idl>
+  <history>
+    <revision date="2010/01/13">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2011/12/07">
+      <change>Added <code>genType</code> argument and return type to function declarations.</change>
+    </revision>
+    <revision date="2012/01/03">
+      <change>Removed webgl module per changes to Web IDL spec.</change>
+    </revision>
+    <revision date="2013/05/15">
+      <change>Ratified by Khronos Board of Promoters.</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+  </history>
+</ratified>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/OES_texture_float/extension.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ratified href="OES_texture_float/">
+  <name>OES_texture_float</name>
+
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>1</number>
+
+  <depends>
+    <api version="1.0"/>
+    <removed version="2.0" />
+  </depends>
+
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/OES/OES_texture_float.txt"
+             name="OES_texture_float">
+      <addendum>Optional support for <code>FLOAT</code> textures as FBO
+      attachments.</addendum>
+    </mirrors>
+
+    <features>
+      <feature> The <code>texImage2D</code> and <code>texSubImage2D</code>
+      entry points taking <code>ArrayBufferView</code> are extended to accept
+      <code>Float32Array</code> with the pixel type <code>FLOAT</code>.
+      </feature>
+
+      <feature> The <code>texImage2D</code> and <code>texSubImage2D</code>
+      entry points taking <code>ImageData</code>,
+      <code>HTMLImageElement</code>, <code>HTMLCanvasElement</code> and
+      <code>HTMLVideoElement</code> are extended to accept the pixel type
+      <code>FLOAT</code>. </feature>
+
+      <feature>Upon activation of this extension, implementations supporting
+      <a href="../WEBGL_color_buffer_float/">WEBGL_color_buffer_float</a>
+      shall implicitly enable it. This requirement maintains the historical
+      behavior prior to the differentiation of float renderability from float
+      textures, so as to not break existing content.</feature>
+    </features>
+  </overview>
+
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface OES_texture_float { }; </idl>
+
+  <history>
+    <revision date="2010/11/29">
+      <change>Initial revision.</change>
+    </revision>
+
+    <revision date="2010/12/13">
+      <change>Extended to support pixel type FLOAT for texImage2D and
+      texSubImage2D entry points taking ImageData, HTMLImageElement,
+      HTMLCanvasElement and HTMLVideoElement. </change>
+    </revision>
+
+    <revision date="2011/09/12">
+      <change>Added optional ability to use a FLOAT type texture as an FBO's
+      color attachment. </change>
+    </revision>
+
+    <revision date="2012/01/03">
+      <change>Removed webgl module per changes to Web IDL spec.</change>
+    </revision>
+
+    <revision date="2012/12/04">
+      <change>Specify that implementations supporting FLOAT color attachments
+      implicitly enable WEBGL_color_buffer_float.</change>
+    </revision>
+
+    <revision date="2013/05/15">
+      <change>Ratified by Khronos Board of Promoters.</change>
+    </revision>
+
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+
+    <revision date="2014/09/11">
+      <change>Corrected link to WEBGL_color_buffer_float.</change>
+    </revision>
+
+    <revision date="2017/09/14">
+      <change>Clarify behaviors regarding WEBGL_color_buffer_float.</change>
+    </revision>
+  </history>
+</ratified>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/OES_texture_float_linear/extension.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ratified href="OES_texture_float_linear/">
+  <name>OES_texture_float_linear</name>
+
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>20</number>
+
+  <depends>
+    <api version="1.0"/>
+  </depends>
+
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/OES/OES_texture_float_linear.txt"
+             name="OES_texture_float_linear">
+    </mirrors>
+
+    <features>
+      Expands upon the OES_texture_float extension by allowing support for
+      LINEAR magnification filter and LINEAR, NEAREST_MIPMAP_LINEAR,
+      LINEAR_MIPMAP_NEAREST and LINEAR_MIPMAP_NEAREST minification filters.
+    </features>
+  </overview>
+
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface OES_texture_float_linear { };</idl>
+
+  <history>
+    <revision date="2013/02/20">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2013/03/11">
+      <change>Moved to draft status after discussion on public_webgl.</change>
+    </revision>
+    <revision date="2013/08/06">
+      <change>Moved to community approved.</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+    <revision date="2014/08/08">
+      <change>Ratified by Khronos Board of Promoters.</change>
+    </revision>
+  </history>
+</ratified>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/OES_texture_half_float/extension.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ratified href="OES_texture_half_float/">
+  <name>OES_texture_half_float</name>
+
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>2</number>
+
+  <depends>
+    <api version="1.0"/>
+    <removed version="2.0" />
+  </depends>
+
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/OES/OES_texture_float.txt"
+             name="OES_texture_half_float">
+      <addendum>Optional support for <code>HALF_FLOAT</code> textures as FBO
+      attachments.</addendum>
+    </mirrors>
+
+    <features>
+      <feature> The <code>texImage2D</code> and <code>texSubImage2D</code>
+      entry points taking <code>ArrayBufferView</code> are extended to accept
+      <code>Uint16Array</code> with the pixel type <code>HALF_FLOAT_OES</code>.
+      </feature>
+
+      <feature> The <code>texImage2D</code> and <code>texSubImage2D</code>
+      entry points taking <code>ImageData</code>,
+      <code>HTMLImageElement</code>, <code>HTMLCanvasElement</code> and
+      <code>HTMLVideoElement</code> are extended to accept the pixel type
+      <code>HALF_FLOAT_OES</code>. </feature>
+
+      <feature>Upon activation of this extension, implementations supporting
+      <a href="../EXT_color_buffer_half_float/">EXT_color_buffer_half_float</a>
+      shall implicitly enable it. This requirement maintains the historical
+      behavior prior to the differentiation of float renderability from float
+      textures, so as to not break existing content.</feature>
+    </features>
+  </overview>
+
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface OES_texture_half_float {
+  const GLenum HALF_FLOAT_OES = 0x8D61;
+};
+</idl>
+
+  <history>
+    <revision date="2010/11/29">
+      <change>Initial revision.</change>
+    </revision>
+
+    <revision date="2011/09/12">
+      <change> Added similar text about <code>texImage2D</code> and
+      <code>texSubImage2D</code> as in OES_texture_float spec. </change>
+
+      <change> Added optional ability to use a HALF_FLOAT_OES type texture as
+      an FBO's color attachment. </change>
+    </revision>
+
+    <revision date="2012/01/03">
+      <change>Removed webgl module per changes to Web IDL spec.</change>
+    </revision>
+
+    <revision date="2012/12/04">
+      <change>Specify that implementations supporting HALF_FLOAT_OES color
+      attachments implicitly enable EXT_color_buffer_half_float.</change>
+    </revision>
+
+    <revision date="2013/05/15">
+      <change>Ratified by Khronos Board of Promoters.</change>
+    </revision>
+
+    <revision date="2014/02/12">
+      <change>Allow texture uploads of half-floats via Uint16Arrays.</change>
+    </revision>
+
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+
+    <revision date="2014/09/11">
+      <change>Corrected link to EXT_color_buffer_half_float.</change>
+    </revision>
+
+    <revision date="2017/09/14">
+      <change>Clarify behaviors regarding EXT_color_buffer_half_float.</change>
+    </revision>
+  </history>
+</ratified>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/OES_texture_half_float_linear/extension.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ratified href="OES_texture_half_float_linear/">
+  <name>OES_texture_half_float_linear</name>
+
+  <contact> <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>21</number>
+
+  <depends>
+    <api version="1.0"/>
+    <removed version="2.0" />
+  </depends>
+
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/OES/OES_texture_float_linear.txt"
+             name="OES_texture_half_float_linear">
+    </mirrors>
+
+    <features>
+      Expands upon the OES_texture_half_float extension by allowing support for
+      LINEAR magnification filter and LINEAR, NEAREST_MIPMAP_LINEAR,
+      LINEAR_MIPMAP_NEAREST and LINEAR_MIPMAP_NEAREST minification filters.
+    </features>
+  </overview>
+
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface OES_texture_half_float_linear { };</idl>
+
+  <history>
+    <revision date="2013/02/20">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2013/03/11">
+      <change>Moved to draft status after discussion on public_webgl.</change>
+    </revision>
+    <revision date="2013/08/06">
+      <change>Moved to community approved.</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+    <revision date="2014/08/08">
+      <change>Ratified by Khronos Board of Promoters.</change>
+    </revision>
+  </history>
+</ratified>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/OES_vertex_array_object/extension.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0"?>
+
+<ratified href="OES_vertex_array_object/">
+  <name>OES_vertex_array_object</name>
+  <contact>
+    <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL working group</a> (public_webgl 'at' khronos.org)
+  </contact>
+  <contributors>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+  <number>5</number>
+  <depends>
+    <api version="1.0"/>
+    <core version="2.0" />
+  </depends>
+  <overview>
+    <mirrors href="http://www.khronos.org/registry/gles/extensions/OES/OES_vertex_array_object.txt" name="OES_vertex_array_object" />
+  </overview>
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface WebGLVertexArrayObjectOES : WebGLObject {
+};
+
+[NoInterfaceObject]
+interface OES_vertex_array_object {
+    const GLenum VERTEX_ARRAY_BINDING_OES = 0x85B5;
+
+    WebGLVertexArrayObjectOES? createVertexArrayOES();
+    void deleteVertexArrayOES(WebGLVertexArrayObjectOES? arrayObject);
+    [WebGLHandlesContextLoss] GLboolean isVertexArrayOES(WebGLVertexArrayObjectOES? arrayObject);
+    void bindVertexArrayOES(WebGLVertexArrayObjectOES? arrayObject);
+};
+  </idl>
+
+  <newfun>
+    <function name="createVertexArrayOES" type="WebGLVertexArrayObjectOES?">
+    </function>
+  </newfun>
+
+  <newfun>
+    <function name="deleteVertexArrayOES" type="void">
+      <param name="arrayObject" type="WebGLVertexArrayObjectOES?"/>
+    </function>
+  </newfun>
+
+  <newfun>
+    <function name="isVertexArrayOES" type="GLboolean">
+      <param name="arrayObject" type="WebGLVertexArrayObjectOES?"/>
+      Returns false if the vertex array object's <a
+      href="../../specs/1.0/#webgl-object-invalidated-flag">invalidated
+      flag</a> is set.
+    </function>
+  </newfun>
+
+  <newfun>
+    <function name="bindVertexArrayOES" type="void">
+      <param name="arrayObject" type="WebGLVertexArrayObjectOES?"/>
+    </function>
+  </newfun>
+
+  <issues>
+    <p>The OES_vertex_array_object spec does not make it clear
+    what happens to buffers that are deleted when they are referenced
+    by vertex array objects. It is inferred that all buffers are
+    reference counted.
+    </p>
+    <p>Before OES_vertex_array_object there was no way to use a deleted
+    buffer in a single context as the spec states it would be unbound
+    from all bind points. After OES_vertex_array_object it is now
+    possible to use deleted buffers.
+    </p>
+    <p>Furthermore, the OpenGL ES 2.0 spec specifies that using a
+    deleted buffer has undefined results including possibly
+    corrupt rendering and generating GL errors. Undefined behavior
+    is unacceptable for WebGL.
+    </p>
+    <ul>
+      <li>
+        <p>RESOLVED: Buffers should be reference counted when attached to
+        a vertex array object. This is consistent with the OpenGL ES 3.0
+        spec's implementation of Vertex Array Objects and matches the 
+        behavior of other WebGL objects, such as textures that are attached
+        to framebuffers.
+        </p>
+        <p>This will require that most implementations do not call 
+        glDeleteBuffer when the user calls deleteBuffer on the WebGL context.
+        Instead the implementation must wait for all references to be released
+        before calling glDeleteBuffer to prevent undefined behavior.
+        </p>
+        <p>If a buffer object is deleted while it is attached to the currently
+        bound vertex array object, then it is as if BindBuffer had been called,
+        with a buffer of 0, for each target to which this buffer was attached
+        in the currently bound vertex array object. In other words, this buffer
+        is first detached from all attachment points in the currently bound 
+        vertex array object. Note that the buffer is specifically not detached
+        from any other vertex array object. Detaching the buffer from any other
+        vertex array objects is the responsibility of the application.
+        </p>
+      </li>
+    </ul>
+  </issues>
+  <history>
+    <revision date="2011/01/27">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2011/11/12">
+      <change>Demotion to draft.</change>
+    </revision>
+    <revision date="2011/12/06">
+      <change>Added vendor-specific name strings for draft extension per discussion on WebGL mailing list.</change>
+    </revision>
+    <revision date="2011/12/07">
+      <change>Renamed "Name Strings" section to "Alias Name Strings".</change>
+      <change>Sorted Revision History in ascending order.</change>
+    </revision>
+    <revision date="2012/01/03">
+      <change>Removed webgl module per changes to Web IDL spec.</change>
+    </revision>
+    <revision date="2012/09/24">
+      <change>Added resolution to deleted buffer issue</change>
+    </revision>
+    <revision date="2012/10/16">
+      <change>Based on feedback on public_webgl, moved from draft to community approved, and removed aliases.</change>
+    </revision>
+    <revision date="2013/05/08">
+      <change>Made WebGLVertexArrayObjectOES return values and arguments nullable on feedback from Benoit Jacob.</change>
+    </revision>
+    <revision date="2013/05/14">
+      <change>Based on pull request from J Kenneth King, added WebGLHandlesContextLoss extended attribute to isVertexArrayOES and added markup for new functions.</change>
+    </revision>
+    <revision date="2013/05/15">
+      <change>Ratified by Khronos Board of Promoters.</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute to extension and WebGLVertexArrayObjectOES interface.</change>
+    </revision>
+  </history>
+</ratified>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/WEBGL_color_buffer_float/extension.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<extension href="WEBGL_color_buffer_float/">
+  <name>WEBGL_color_buffer_float</name>
+
+  <contact><a href="https://www.khronos.org/webgl/public-mailing-list">WebGL
+  working group</a> (public_webgl 'at' khronos.org) </contact>
+
+  <contributors>
+    <contributor>Mark Callow, HI Corporation</contributor>
+
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+
+  <number>15</number>
+
+  <depends>
+    <api version="1.0"/>
+
+    <ext name="EXT_color_buffer_half_float"/>
+
+    <ext name="OES_texture_float" require="true"/>
+
+    <subsumed version="2.0" by="EXT_color_buffer_float" />
+  </depends>
+
+  <overview>
+    <p>Adds support for rendering to 32-bit floating-point color buffers.</p>
+
+    <features>
+      <feature>
+        <p>The 32-bit floating-point type <code>RGBA32F</code> becomes available
+        as a color-renderable format. Renderbuffers can be created in this
+        format. These and textures created with <code>format = RGBA</code> and
+        <code>type = FLOAT</code> as specified in <a
+        href="http://www.khronos.org/registry/webgl/extensions/OES_texture_float/">OES_texture_float</a>,
+        can be attached to framebuffer object color attachments for rendering.
+        </p>
+      </feature>
+
+      <feature>
+        <p>The 32-bit floating-point type <code>RGB32F</code> may also optionally
+	become available as a color-renderable format. These and textures created
+	with <code>format = RGB</code> and <code>type = FLOAT</code> as specified in
+	<a href="http://www.khronos.org/registry/webgl/extensions/OES_texture_float/">OES_texture_float</a>,
+        can be attached to framebuffer object color attachments for rendering.
+	Applications must check framebuffer completeness to determine if an
+	implementation actually supports this format.
+        </p>
+      </feature>
+
+      <feature>
+        <p><span style="color: red">NOTE:</span> fragment shaders outputs
+        gl_FragColor and gl_FragData[0] will only be clamped and converted
+        when the color buffer is fixed-point and <code>blendColor()</code> and
+        <code>clearColor()</code> will no longer clamp their parameter values
+        on input. Clamping will be applied as necessary at draw time according
+        to the type of color buffer in use.</p>
+      </feature>
+
+      <feature>
+        <p>The format and type combination <code>RGBA</code> and
+        <code>FLOAT</code> becomes valid for reading from a floating-point
+        rendering buffer. Note: <code>RGBA</code> and
+        <code>UNSIGNED_BYTE</code> cannot be used for reading from a
+        floating-point rendering buffer.</p>
+      </feature>
+
+      <feature>
+        <p>The component types of framebuffer object attachments can be
+        queried.</p>
+      </feature>
+    </features>
+  </overview>
+
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface WEBGL_color_buffer_float {
+  const GLenum RGBA32F_EXT = 0x8814;
+  const GLenum FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT = 0x8211;
+  const GLenum UNSIGNED_NORMALIZED_EXT = 0x8C17;
+}; // interface WEBGL_color_buffer_float
+  </idl>
+
+  <newtok>
+    <function name="renderbufferStorage" type="void"><param name="target"
+    type="GLenum"/><param name="internalformat" type="GLenum"/><param
+    name="width" type="GLsizei"/><param name="height"
+    type="GLsizei"/><code>RGBA32F_EXT</code> is accepted as the
+    <code>internalformat</code> parameter of
+    <code>renderbufferStorage()</code>.</function>
+  </newtok>
+
+  <additions>
+    <p>The new tokens and the behavioral changes for floating-point color
+    buffers specified in <a
+    href="http://www.khronos.org/registry/webgl/extensions/EXT_color_buffer_half_float/">EXT_color_buffer_half_float</a>
+    are incorporated into WebGL except for the <code>RGB16F</code> and
+    <code>RGBA16F</code> types. References to <code>RGB16F</code> are ignored,
+    and references to <code>RGBA16F</code> are replaced by references to
+    <code>RGBA32F</code>.</p>
+  </additions>
+
+  <history>
+    <revision date="2012/11/08">
+      <change>Initial revision.</change>
+    </revision>
+
+    <revision date="2012/11/12">
+      <change>Don't mirror EXT_color_buffer_half_float. Mirror has a different
+      meaning from what is done here.</change>
+    </revision>
+
+    <revision date="2012/11/13">
+      <change>Add reading-pixels-as-FLOAT feature to the Overview.</change>
+    </revision>
+
+    <revision date="2012/11/26">
+      <change>Move to draft.</change>
+    </revision>
+
+    <revision date="2014/07/15">
+      <change>Removed webgl module. Added NoInterfaceObject extended attribute.</change>
+    </revision>
+
+    <revision date="2014/09/11">
+      <change>Fixed the name of the interface from EXT_color_buffer_float to WEBGL_color_buffer_float.</change>
+    </revision>
+
+    <revision date="2014/11/24">
+      <change>Removed the support for RGB32F, since it is not natively supported on all platforms where WebGL is implemented.</change>
+    </revision>
+
+    <revision date="2014/11/24">
+      <change>Move to community approved.</change>
+    </revision>
+
+    <revision date="2016/05/05">
+      <change>Subsumed in WebGL 2.0 by EXT_color_buffer_float.</change>
+    </revision>
+
+    <revision date="2017/09/14">
+      <change>Add optional RGB renderability.</change>
+    </revision>
+  </history>
+</extension>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/WEBGL_compressed_texture_astc/extension.xml
@@ -0,0 +1,577 @@
+<?xml version="1.0"?>
+
+<extension href="WEBGL_compressed_texture_astc/">
+  <name>WEBGL_compressed_texture_astc</name>
+  <contact>
+    <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL working group</a> (public_webgl 'at' khronos.org)
+  </contact>
+  <contributors>
+    <contributor>Christophe Riccio, Unity</contributor>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+  <number>30</number>
+  <depends>
+    <api version="1.0"/>
+  </depends>
+  <overview>
+    <p>
+      This extension exposes the compressed texture format defined in the 
+      <a href="https://www.opengl.org/registry/specs/KHR/texture_compression_astc_hdr.txt">
+      KHR_texture_compression_astc_hdr</a> OpenGL ES extension to WebGL. Consult that extension
+      specification for behavioral definitions, including error behaviors.
+    </p>
+    <p>
+      ASTC textures may be encoded using either high or low dynamic range, corresponding to an "HDR
+      profile" and "LDR profile". The compression format is designed to be extended, and for new
+      profiles to be added in the future. For this reason, enabling the WebGL extension enables all
+      of the profiles supported by the implementation. The supported profiles may be queried by
+      calling <code>getSupportedProfiles</code> against the extension object.
+    </p>
+    <features>
+      <feature>
+        Compression format <code>COMPRESSED_RGBA_ASTC_4x4_KHR</code>,
+        <code>COMPRESSED_RGBA_ASTC_5x4_KHR</code>,
+        <code>COMPRESSED_RGBA_ASTC_5x5_KHR</code>,
+        <code>COMPRESSED_RGBA_ASTC_6x5_KHR</code>,
+        <code>COMPRESSED_RGBA_ASTC_6x6_KHR</code>,
+        <code>COMPRESSED_RGBA_ASTC_8x5_KHR</code>,
+        <code>COMPRESSED_RGBA_ASTC_8x6_KHR</code>,
+        <code>COMPRESSED_RGBA_ASTC_8x8_KHR</code>,
+        <code>COMPRESSED_RGBA_ASTC_10x5_KHR</code>,
+        <code>COMPRESSED_RGBA_ASTC_10x6_KHR</code>,
+        <code>COMPRESSED_RGBA_ASTC_10x8_KHR</code>,
+        <code>COMPRESSED_RGBA_ASTC_10x10_KHR</code>,
+        <code>COMPRESSED_RGBA_ASTC_12x10_KHR</code>,
+        <code>COMPRESSED_RGBA_ASTC_12x12_KHR</code>,
+        <code>COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR</code>,
+        <code>COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR</code>,
+        <code>COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR</code>,
+        <code>COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR</code>,
+        <code>COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR</code>,
+        <code>COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR</code>,
+        <code>COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR</code>,
+        <code>COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR</code>,
+        <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR</code>,
+        <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR</code>,
+        <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR</code>,
+        <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR</code>,
+        <code>COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR</code>,
+        and <code>COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR</code> may be passed to
+        the <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code> entry points.
+      </feature>
+      <feature>
+        Calling <code>getParameter</code> with the argument <code>COMPRESSED_TEXTURE_FORMATS</code>
+        will include the format from this specification.
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_4x4_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 3) / 4) * floor((height + 3) / 4) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_5x4_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 4) / 5) * floor((height + 3) / 4) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_5x5_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 4) / 5) * floor((height + 4) / 5) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_6x5_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 5) / 6) * floor((height + 4) / 5) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_6x6_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 5) / 6) * floor((height + 5) / 6) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_8x5_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 7) / 8) * floor((height + 4) / 5) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_8x6_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 7) / 8) * floor((height + 5) / 6) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_8x8_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 7) / 8) * floor((height + 7) / 8) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_10x5_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 9) / 10) * floor((height + 4) / 5) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_10x6_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 9) / 10) * floor((height + 5) / 6) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_10x8_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 9) / 10) * floor((height + 7) / 8) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_10x10_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 9) / 10) * floor((height + 9) / 10) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_12x10_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 11) / 12) * floor((height + 9) / 10) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGBA_ASTC_12x12_KHR</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR</dt>
+          <dd>
+            <p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+              <code>compressedTexImage2D</code> or <code>compressedTexSubImage2D</code> must be 
+              equal to the following number of bytes:
+            </p>
+            <blockquote><code>
+              floor((width + 11) / 12) * floor((height + 11) / 12) * 16
+            </code></blockquote>
+            <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+    </features>
+  </overview>
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface WEBGL_compressed_texture_astc {
+    /* Compressed Texture Format */
+    const GLenum COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0;
+    const GLenum COMPRESSED_RGBA_ASTC_5x4_KHR = 0x93B1;
+    const GLenum COMPRESSED_RGBA_ASTC_5x5_KHR = 0x93B2;
+    const GLenum COMPRESSED_RGBA_ASTC_6x5_KHR = 0x93B3;
+    const GLenum COMPRESSED_RGBA_ASTC_6x6_KHR = 0x93B4;
+    const GLenum COMPRESSED_RGBA_ASTC_8x5_KHR = 0x93B5;
+    const GLenum COMPRESSED_RGBA_ASTC_8x6_KHR = 0x93B6;
+    const GLenum COMPRESSED_RGBA_ASTC_8x8_KHR = 0x93B7;
+    const GLenum COMPRESSED_RGBA_ASTC_10x5_KHR = 0x93B8;
+    const GLenum COMPRESSED_RGBA_ASTC_10x6_KHR = 0x93B9;
+    const GLenum COMPRESSED_RGBA_ASTC_10x8_KHR = 0x93BA;
+    const GLenum COMPRESSED_RGBA_ASTC_10x10_KHR = 0x93BB;
+    const GLenum COMPRESSED_RGBA_ASTC_12x10_KHR = 0x93BC;
+    const GLenum COMPRESSED_RGBA_ASTC_12x12_KHR = 0x93BD;
+
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x93D0;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR = 0x93D1;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR = 0x93D2;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR = 0x93D3;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR = 0x93D4;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR = 0x93D5;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR = 0x93D6;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR = 0x93D7;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR = 0x93D8;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR = 0x93D9;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR = 0x93DA;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 0x93DB;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD;
+
+    // Profile query support.
+    sequence&lt;DOMString&gt; getSupportedProfiles();
+};
+  </idl>
+
+  <newfun>
+    <function name="getSupportedProfiles" type="sequence&lt;DOMString&gt;">
+      Returns the names of the ASTC profiles supported by the implementation. As of this writing,
+      valid return values will include "ldr", corresponding to the
+      GL_KHR_texture_compression_astc_ldr extension string; and "hdr", corresponding to the
+      GL_KHR_texture_compression_astc_hdr extension string. More profiles may be added in the
+      future.
+    </function>
+    <div class="note">
+      The intent of the <code>getSupportedProfiles</code> function is to allow easy reconstruction
+      of the underlying OpenGL or OpenGL ES extension strings for environments like Emscripten, by
+      prepending the string <code>GL_KHR_texture_compression_astc_</code> to the returned profile
+      names.
+    </div>
+  </newfun>
+
+  <newtok>
+    <function name="compressedTexImage2D">
+      <param name="internalformat" type="GLenum"/>
+      Accepted by the <code>internalformat</code> parameter:
+      <code>COMPRESSED_RGBA_ASTC_4x4_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_5x4_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_5x5_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_6x5_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_6x6_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_8x5_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_8x6_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_8x8_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_10x5_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_10x6_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_10x8_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_10x10_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_12x10_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_12x12_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR</code>
+      <br/>
+    </function>
+    
+    <function name="compressedTexSubImage2D">
+      <param name="internalformat" type="GLenum"/>
+      Accepted by the <code>internalformat</code> parameter:
+      <code>COMPRESSED_RGBA_ASTC_4x4_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_5x4_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_5x5_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_6x5_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_6x6_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_8x5_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_8x6_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_8x8_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_10x5_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_10x6_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_10x8_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_10x10_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_12x10_KHR</code>,
+      <code>COMPRESSED_RGBA_ASTC_12x12_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR</code>,
+      <code>COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR</code>
+      <br/>
+    </function>
+  </newtok>
+
+  <errors>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_4x4_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 3) / 4) * floor((height + 3) / 4) * 16
+      </code></blockquote>
+    </error>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_5x4_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 4) / 5) * floor((height + 3) / 4) * 16
+      </code></blockquote>
+    </error>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_5x5_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 4) / 5) * floor((height + 4) / 5) * 16
+      </code></blockquote>
+    </error>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_6x5_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 5) / 6) * floor((height + 4) / 5) * 16
+      </code></blockquote>
+    </error>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_6x6_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 5) / 6) * floor((height + 5) / 6) * 16
+      </code></blockquote>
+    </error>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_8x5_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 7) / 8) * floor((height + 4) / 5) * 16
+      </code></blockquote>
+    </error>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_8x6_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 7) / 8) * floor((height + 5) / 6) * 16
+      </code></blockquote>
+    </error>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_8x8_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 7) / 8) * floor((height + 7) / 8) * 16
+      </code></blockquote>
+    </error>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_10x5_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 9) / 10) * floor((height + 4) / 5) * 16
+      </code></blockquote>
+    </error>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_10x6_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 9) / 10) * floor((height + 5) / 6) * 16
+      </code></blockquote>
+    </error>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_10x8_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 9) / 10) * floor((height + 7) / 8) * 16
+      </code></blockquote>
+    </error>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_10x10_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 9) / 10) * floor((height + 9) / 10) * 16
+      </code></blockquote>
+    </error>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_12x10_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 11) / 12) * floor((height + 9) / 10) * 16
+      </code></blockquote>
+     </error>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code>
+      if the <code>internalformat</code> parameter is 
+      <code>COMPRESSED_RGBA_ASTC_12x12_KHR</code> or <code>COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR</code>
+      and the byteLength of the ArrayBufferView is not:
+      <blockquote><code>
+        floor((width + 11) / 12) * floor((height + 11) / 12) * 16
+      </code></blockquote>
+     </error>
+  </errors>
+
+  <history>
+    <revision date="2015/03/10">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2015/08/07">
+      <change>Added profile string support. Renamed constants back to _KHR.</change>
+    </revision>
+    <revision date="2015/08/10">
+      <change>Clarified intent of getSupportedProfiles. Stressed that OpenGL ES extension defines the behavior.</change>
+    </revision>
+    <revision date="2015/08/10">
+      <change>Moved to draft status.</change>
+    </revision>
+    <revision date="2016/12/12">
+      <change>Moved to community approved after discussion on public_webgl list.</change>
+    </revision>
+  </history>
+</extension>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/WEBGL_compressed_texture_atc/extension.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0"?>
+
+<extension href="WEBGL_compressed_texture_atc/">
+  <name>WEBGL_compressed_texture_atc</name>
+  <contact>
+    <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL working group</a> (public_webgl 'at' khronos.org)
+  </contact>
+  <contributors>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+  <number>12</number>
+  <depends>
+    <api version="1.0"/>
+  </depends>
+  <overview>
+    <p>
+      This extension exposes the compressed texture formats defined in the 
+      <a href="http://www.khronos.org/registry/gles/extensions/AMD/AMD_compressed_ATC_texture.txt">
+      AMD_compressed_ATC_texture</a> OpenGL extension to WebGL.
+    </p>
+    <features>
+      <feature>
+        Compression formats <code>COMPRESSED_RGB_ATC_WEBGL</code>,
+        <code>COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL</code>, and
+        <code>COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL</code> may be passed to
+        the <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code> entry points.
+
+        These formats correspond to the 3 formats defined in the AMD_compressed_ATC_texture OpenGL
+        extension. Although the enum names are changed, their numeric values are the same. The correspondence
+        is given by this table:
+        <table>
+          <tr>
+            <th>WebGL format enum</th>
+            <th>OpenGL format enum</th>
+            <th>Numeric value</th>
+          </tr>
+          <tr>
+            <td>COMPRESSED_RGB_ATC_WEBGL</td>
+            <td>ATC_RGB_AMD</td>
+            <td>0x8C92</td>
+          </tr>
+          <tr>
+            <td>COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL</td>
+            <td>ATC_RGBA_EXPLICIT_ALPHA_AMD</td>
+            <td>0x8C93</td>
+          </tr>
+          <tr>
+            <td>COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL</td>
+            <td>ATC_RGBA_INTERPOLATED_ALPHA_AMD</td>
+            <td>0x87EE</td>
+          </tr>
+        </table>
+      </feature>
+      <feature>
+        Calling <code>getParameter</code> with the argument <code>COMPRESSED_TEXTURE_FORMATS</code>
+        will include the 3 formats from this specification.
+      </feature>
+      <feature>
+        <p>The following format-specific restrictions must be enforced:</p>
+        <dl>
+          <dt>COMPRESSED_RGB_ATC_WEBGL</dt>
+          <dd><p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+          <code>compressedTexImage2D</code>, must be equal to the following number of bytes:</p>
+          <blockquote><code>
+            floor((width + 3) / 4) * floor((height + 3) / 4) * 8
+          </code></blockquote>
+          <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+
+          <dt>COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL</dt>
+          <dt>COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL</dt>
+          <dd><p>The <code>byteLength</code> of the ArrayBufferView, <code>pixels</code>, passed to
+          <code>compressedTexImage2D</code>, must be equal to the following number of bytes:</p>
+          <blockquote><code>
+            floor((width + 3) / 4) * floor((height + 3) / 4) * 16
+          </code></blockquote>
+          <p>If it is not, an <code>INVALID_VALUE</code> error is generated.</p>
+          </dd>
+        </dl>
+      </feature>
+    </features>
+  </overview>
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface WEBGL_compressed_texture_atc {
+    /* Compressed Texture Formats */
+    const GLenum COMPRESSED_RGB_ATC_WEBGL                     = 0x8C92;
+    const GLenum COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL     = 0x8C93;
+    const GLenum COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE;
+};
+  </idl>
+  <history>
+    <revision date="2012/09/11">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2013/07/03">
+      <change>Clarified that length of ArrayBufferView is actually byteLength.</change>
+    </revision>
+    <revision date="2014/04/17">
+      <change>Removed reference to compressedTexSubImage2D. This format can only be used with compressedTexImage2D.</change>
+    </revision>
+    <revision date="2014/06/27">
+      <change>Moved to community approved after discussion on public_webgl list.</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+  </history>
+</extension>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/WEBGL_compressed_texture_etc/extension.xml
@@ -0,0 +1,189 @@
+<?xml version="1.0"?>
+
+<extension href="WEBGL_compressed_texture_etc/">
+  <name>WEBGL_compressed_texture_etc</name>
+  <contact>
+    <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL working group</a> (public_webgl 'at' khronos.org)
+  </contact>
+  <contributors>
+    <contributor>Jeff Gilbert, Mozilla</contributor>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+  <number>29</number>
+  <depends>
+    <api version="1.0"/>
+  </depends>
+  <overview>
+    <p>
+      This extension exposes the compressed texture formats defined as core in the
+      <a href="http://www.khronos.org/registry/gles/specs/3.0/es_spec_3.0.4.pdf">
+      OpenGL ES 3.0</a> spec to WebGL. These include the ETC2 and EAC formats, where
+      ETC2 is a superset of ETC1. ETC1 textures can be loaded using the ETC2 token
+      value. All of these formats are in the ETC family.
+    </p>
+    <p>
+      Browsers should not advertise this extension when the WebGL implementation, or
+      graphics driver, supports these formats by decompressing them.
+    </p>
+    <features>
+      <feature>
+        Compression formats <code>COMPRESSED_R11_EAC</code>,
+        <code>COMPRESSED_SIGNED_R11_EAC</code>,
+        <code>COMPRESSED_RG11_EAC</code>,
+        <code>COMPRESSED_SIGNED_RG11_EAC</code>,
+        <code>COMPRESSED_RGB8_ETC2</code>,
+        <code>COMPRESSED_SRGB8_ETC2</code>,
+        <code>COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2</code>,
+        <code>COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2</code>,
+        <code>COMPRESSED_RGBA8_ETC2_EAC</code>,
+        and <code>COMPRESSED_SRGB8_ALPHA8_ETC2_EAC</code> may be passed to the
+        <code>compressedTexImage2D</code> and <code>compressedTexSubImage2D</code> entry points. In
+        WebGL 2.0, they may also be passed to the <code>compressedTexImage3D</code> and
+        <code>compressedTexSubImage3D</code> entry points with the <code>TEXTURE_2D_ARRAY</code>
+        target.
+      </feature>
+      <feature>
+        Calling <code>getParameter</code> with the argument <code>COMPRESSED_TEXTURE_FORMATS</code>
+        will include the formats from this specification.
+      </feature>
+      <feature>
+        For all of the formats, <code>validatedSize</code> (defined for each specific format
+        below) is validated in the following ways:
+        <ul>
+            <li>
+                <b>WebGL 1.0 and 2.0</b>: if the variant of <code>compressedTexImage*D</code> or
+                <code>compressedTexSubImage*D</code> taking <code>ArrayBufferView pixels</code> is
+                called, then the <code>byteLength</code> of the view must be equal to
+                <code>validatedSize</code>, or an INVALID_VALUE error is generated.
+            </li>
+            <li>
+                <b>WebGL 2.0</b>: if the variant of <code>compressedTexImage*D</code> or
+                <code>compressedTexSubImage*D</code> taking <code>GLintptr offset</code> is called,
+                and <code>offset + validatedSize</code> is greater than the size of the bound
+                <code>PIXEL_UNPACK_BUFFER</code>, an <code>INVALID_OPERATION</code> error is
+                generated.
+            </li>
+        </ul>
+        <dl>
+          <dt>COMPRESSED_R11_EAC</dt>
+          <dt>COMPRESSED_SIGNED_R11_EAC</dt>
+          <dt>COMPRESSED_RGB8_ETC2</dt>
+          <dt>COMPRESSED_SRGB8_ETC2</dt>
+          <dt>COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2</dt>
+          <dt>COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2</dt>
+          <dd><p><code>validatedSize</code> is computed in the following way:</p>
+          <blockquote><code>
+            floor((width + 3) / 4) * floor((height + 3) / 4) * 8
+          </code></blockquote>
+          </dd>
+        </dl>
+        <dl>
+          <dt>COMPRESSED_RG11_EAC</dt>
+          <dt>COMPRESSED_SIGNED_RG11_EAC</dt>
+          <dt>COMPRESSED_RGBA8_ETC2_EAC</dt>
+          <dt>COMPRESSED_SRGB8_ALPHA8_ETC2_EAC</dt>
+          <dd><p><code>validatedSize</code> is computed in the following way:</p>
+          <blockquote><code>
+            floor((width + 3) / 4) * floor((height + 3) / 4) * 16
+          </code></blockquote>
+          </dd>
+        </dl>
+      </feature>
+    </features>
+  </overview>
+  <idl xml:space="preserve">
+[NoInterfaceObject]
+interface WEBGL_compressed_texture_etc {
+    /* Compressed Texture Formats */
+    const GLenum COMPRESSED_R11_EAC                        = 0x9270;
+    const GLenum COMPRESSED_SIGNED_R11_EAC                 = 0x9271;
+    const GLenum COMPRESSED_RG11_EAC                       = 0x9272;
+    const GLenum COMPRESSED_SIGNED_RG11_EAC                = 0x9273;
+    const GLenum COMPRESSED_RGB8_ETC2                      = 0x9274;
+    const GLenum COMPRESSED_SRGB8_ETC2                     = 0x9275;
+    const GLenum COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2  = 0x9276;
+    const GLenum COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277;
+    const GLenum COMPRESSED_RGBA8_ETC2_EAC                 = 0x9278;
+    const GLenum COMPRESSED_SRGB8_ALPHA8_ETC2_EAC          = 0x9279;
+};
+  </idl>
+  
+  <newtok>
+    <function name="compressedTexImage2D">
+      <param name="internalformat" type="GLenum"/>
+      Accepted by the <code>internalformat</code> parameter:
+      <code>COMPRESSED_R11_EAC</code>,
+      <code>COMPRESSED_SIGNED_R11_EAC</code>,
+      <code>COMPRESSED_RG11_EAC</code>,
+      <code>COMPRESSED_SIGNED_RG11_EAC</code>,
+      <code>COMPRESSED_RGB8_ETC2</code>,
+      <code>COMPRESSED_SRGB8_ETC2</code>,
+      <code>COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2</code>,
+      <code>COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2</code>,
+      <code>COMPRESSED_RGBA8_ETC2_EAC</code> or
+      <code>COMPRESSED_SRGB8_ALPHA8_ETC2_EAC</code>
+      <br/>
+    </function>
+    
+    <function name="compressedTexSubImage2D">
+      <param name="internalformat" type="GLenum"/>
+      Accepted by the <code>internalformat</code> parameter:
+      <code>COMPRESSED_R11_EAC</code>,
+      <code>COMPRESSED_SIGNED_R11_EAC</code>,
+      <code>COMPRESSED_RG11_EAC</code>,
+      <code>COMPRESSED_SIGNED_RG11_EAC</code>,
+      <code>COMPRESSED_RGB8_ETC2</code>,
+      <code>COMPRESSED_SRGB8_ETC2</code>,
+      <code>COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2</code>,
+      <code>COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2</code>,
+      <code>COMPRESSED_RGBA8_ETC2_EAC</code> or
+      <code>COMPRESSED_SRGB8_ALPHA8_ETC2_EAC</code>
+      <br/>
+    </function>
+  </newtok>
+
+  <errors>
+    <error enum="INVALID_VALUE">
+      The error <code>INVALID_VALUE</code> is generated by <code>compressedTexImage2D</code>,
+      <code>compressedTexSubImage2D</code>, <code>compressedTexImage3D</code>, and
+      <code>compressedTexSubImage3D</code> if the variant taking <code>ArrayBufferView pixels</code>
+      is called and the size restrictions above are not met.
+    </error>
+    <error enum="INVALID_OPERATION">
+      The error <code>INVALID_OPERATION</code> is generated by <code>compressedTexImage2D</code>,
+      <code>compressedTexSubImage2D</code>, <code>compressedTexImage3D</code>, and
+      <code>compressedTexSubImage3D</code> if the variant taking <code>GLintptr offset</code> is
+      called and the size restrictions above are not met.
+    </error>
+  </errors>
+  <history>
+    <revision date="2013/12/9">
+      <change>Initial revision.</change>
+    </revision>
+    <revision date="2014/07/15">
+      <change>Added NoInterfaceObject extended attribute.</change>
+    </revision>
+    <revision date="2014/12/12">
+      <change>COMPRESSED_RGB_ETC2 should be COMPRESSED_RGB8_ETC2.</change>
+      <change>Remove unnecessary language.</change>
+    </revision>
+    <revision date="2015/01/31">
+      <change>Moved to draft.</change>
+      <change>Added issue questions.</change>
+      <change>Formalized the newtok and error codes.</change>
+    </revision>
+    <revision date="2016/09/16">
+      <change>Renamed to WEBGL_compressed_texture_es3_0.</change>
+    </revision>
+    <revision date="2016/09/21">
+      <change>Clarifications to the supported formats on suggestion from Mark Callow.</change>
+    </revision>
+    <revision date="2016/09/30">
+      <change>Addressed issues regarding 3D entry points, description of interation with WebGL 2.0,
+      and generation of INVALID_OPERATION and INVALID_VALUE errors. Added note that browsers should
+      not advertise this extension if these compressed texture formats are decompressed. Renamed to
+      WEBGL_compressed_texture_etc after further discussion. Promoted to community
+      approved.</change>
+    </revision>
+  </history>
+</extension>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/khronos_api/api_webgl/extensions/WEBGL_compressed_texture_etc1/extension.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0"?>
+
+<extension href="WEBGL_compressed_texture_etc1/">
+  <name>WEBGL_compressed_texture_etc1</name>
+  <contact>
+    <a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL working group</a> (public_webgl 'at' khronos.org)
+  </contact>
+  <contributors>
+    <contributor>Members of the WebGL working group</contributor>
+  </contributors>
+  <number>24</number>
+  <depends>
+    <api version="1.0"/>
+  </depends>
+  <overview>
+    <p>
+      This extension exposes the compressed texture format defined in the 
+      <a href="http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt">
+      OES_compressed_ETC1_RGB8_texture</a> OpenGL ES extension to WebGL.
+    </p>
+    <features>
+      <feature>
+        Compression format <code>COMPRESSED_RGB_ETC1_WEBGL</code> may be passed to
+        the <code>compressedTexImage2D</code> entry point.
+
+        This format correspond to the format defined in the OES_compressed_ETC1_RGB8_texture OpenGL ES
+        extension. Although the enum name is changed, the numeric value is the same. The correspondence