Merge autoland to mozilla-central. a=merge

This commit is contained in:
Csoregi Natalia 2019-10-15 00:30:01 +03:00
commit 22b13f01c9
303 changed files with 9501 additions and 5931 deletions

123
Cargo.lock generated
View File

@ -74,7 +74,7 @@ dependencies = [
[[package]]
name = "audio_thread_priority"
version = "0.19.1"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -89,10 +89,11 @@ dependencies = [
name = "audioipc"
version = "0.2.4"
dependencies = [
"audio_thread_priority 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb 0.6.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.23 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -102,7 +103,7 @@ dependencies = [
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-named-pipes 0.1.6 (git+https://github.com/alexcrichton/mio-named-pipes)",
"mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -116,12 +117,11 @@ dependencies = [
name = "audioipc-client"
version = "0.4.0"
dependencies = [
"audio_thread_priority 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
"audio_thread_priority 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)",
"audioipc 0.2.4",
"cubeb-backend 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-backend 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -130,14 +130,14 @@ dependencies = [
name = "audioipc-server"
version = "0.2.3"
dependencies = [
"audio_thread_priority 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
"audio_thread_priority 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)",
"audioipc 0.2.4",
"cubeb-core 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-core 0.6.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.23 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -146,7 +146,7 @@ name = "authenticator"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"boxfnonce 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"devd-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -244,7 +244,7 @@ name = "bindgen"
version = "0.51.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cexpr 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -280,7 +280,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.0.4"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -470,7 +470,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -483,7 +483,7 @@ name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -536,7 +536,7 @@ name = "core-graphics"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
@ -749,27 +749,27 @@ dependencies = [
[[package]]
name = "cubeb"
version = "0.5.5"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cubeb-core 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cubeb-backend"
version = "0.5.5"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cubeb-core 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cubeb-core"
version = "0.5.5"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-sys 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -777,10 +777,10 @@ name = "cubeb-coreaudio"
version = "0.1.0"
dependencies = [
"atomic 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"coreaudio-sys-utils 0.1.0",
"cubeb-backend 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-backend 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"mach 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -788,18 +788,18 @@ dependencies = [
[[package]]
name = "cubeb-pulse"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"cubeb-backend 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"pulse 0.2.0",
"cubeb-backend 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pulse 0.3.0",
"pulse-ffi 0.1.0",
"ringbuf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cubeb-sys"
version = "0.5.5"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1099,7 +1099,7 @@ name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1219,7 +1219,7 @@ name = "gkrust-shared"
version = "0.1.0"
dependencies = [
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"audio_thread_priority 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
"audio_thread_priority 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)",
"audioipc-client 0.4.0",
"audioipc-server 0.2.3",
"authenticator 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1228,8 +1228,8 @@ dependencies = [
"cert_storage 0.0.1",
"cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-coreaudio 0.1.0",
"cubeb-pulse 0.2.0",
"cubeb-sys 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cubeb-pulse 0.3.0",
"cubeb-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_glue 0.1.0",
"env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"geckoservo 0.0.1",
@ -1336,7 +1336,7 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"headers-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"headers-derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1622,7 +1622,7 @@ name = "lmdb-rkv"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"lmdb-rkv-sys 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2017,7 +2017,7 @@ dependencies = [
name = "nsstring"
version = "0.1.0"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -2243,7 +2243,7 @@ name = "png"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)",
"inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2298,9 +2298,9 @@ dependencies = [
[[package]]
name = "pulse"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pulse-ffi 0.1.0",
]
@ -2522,7 +2522,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayref 0.3.5 (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.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2624,11 +2624,6 @@ dependencies = [
"winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)",
]
[[package]]
name = "scoped-tls"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "scoped-tls"
version = "1.0.0"
@ -2662,7 +2657,7 @@ dependencies = [
name = "selectors"
version = "0.21.0"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.25.9 (registry+https://github.com/rust-lang/crates.io-index)",
"derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2686,6 +2681,14 @@ dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver"
version = "0.9.0"
@ -2829,11 +2832,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "size_of_test"
version = "0.0.1"
[[package]]
name = "slab"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slab"
version = "0.4.1"
@ -2911,7 +2909,7 @@ dependencies = [
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.25.9 (registry+https://github.com/rust-lang/crates.io-index)",
"derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2975,7 +2973,7 @@ name = "style_traits"
version = "0.0.1"
dependencies = [
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.25.9 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3538,7 +3536,7 @@ version = "0.60.0"
dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3577,7 +3575,7 @@ name = "webrender_api"
version = "0.60.0"
dependencies = [
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3813,7 +3811,7 @@ dependencies = [
"checksum atomic 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c210c1f4db048cda477b652d170572d84c9640695835f17663595d3bd543fc28"
"checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum audio_thread_priority 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c1e4aab7f57d8334168073cd0d0f11c7d1f7f3aabef84a1733a42629d0da80c"
"checksum audio_thread_priority 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)" = "197b2d259505d11c92d266e1784f01cc935eb764d2f54e16aedf4e5085197871"
"checksum authenticator 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ec149e5d5d4caa2c9ead53a8ce1ea9c4204c388c65bf3b96c2d1dc0fcf4aeb66"
"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875"
"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
@ -3825,7 +3823,7 @@ dependencies = [
"checksum binjs_meta 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6c9a0da2208ceb785c1626fa8b7d250d2e5546ae230294b4a998e4f818c1768e"
"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
"checksum bit_reverse 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5e97e02db5a2899c0377f3d6031d5da8296ca2b47abef6ed699de51b9e40a28c"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2"
"checksum bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80b13e2ab064ff3aa0bdbf1eff533f9822dc37899821f5f98c67f263eab51707"
"checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182"
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
@ -3867,10 +3865,10 @@ dependencies = [
"checksum cssparser-macros 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "5bb1c84e87c717666564ec056105052331431803d606bd45529b28547b611eef"
"checksum cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b6557bdb1dc9647eae1cf7f5601b14cd45fc3c7ccf2df618387416fe542da6ea"
"checksum cstr-macros 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "cd670e5ff58768ef624207fb95709ce63b8d05573fb9a05165f0eef471ea6a3a"
"checksum cubeb 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "50f6a746cc3a80bdc96203e617d3bfc8988169c012c85c4ca4f1bad7862441bc"
"checksum cubeb-backend 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "54c14a298d865c7f454dd809b2feb1fdb361b0a143f8ed2ea0b3a9becfa0a2ea"
"checksum cubeb-core 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "20c6cde72d3505dc4f2452e0378b970b03d1fddf3ad8ac1b98dcb65fc7721907"
"checksum cubeb-sys 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "318d9b60d6d5de52f815882ab5405adedc0ac7e91414950eff27a440c2860a3b"
"checksum cubeb 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3cbcdfde9ea319160af6eff068ffaa96aad3532e1b5c0ebc134614cfacacae24"
"checksum cubeb-backend 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5a1e7add4e7642a8aebb24172922318482bed52389a12cb339f728bbd4c4ed9c"
"checksum cubeb-core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfd9b2ea1cb6afed9419b0d18fc4093df552ccb2300eb57793629f8cd370b4c8"
"checksum cubeb-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "309c5839c5fa03c08363bd308566cbe4654b25a9984342d7546a33d55b80a3d6"
"checksum darling 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe629a532efad5526454efb0700f86d5ad7ff001acb37e431c8bf017a432a8e"
"checksum darling_core 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ee54512bec54b41cf2337a22ddfadb53c7d4c738494dc2a186d7b037ad683b85"
"checksum darling_macro 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cd3e432e52c0810b72898296a69d66b1d78d1517dff6cde7a130557a55a62c1"
@ -4031,12 +4029,12 @@ dependencies = [
"checksum ryu 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0568787116e13c652377b6846f5931454a363a8fdf8ae50463ee40935b278b"
"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
"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 scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
"checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383"
"checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb"
"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
"checksum semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd61b85a0fa777f7fb7c454b9189b2941b110d1385ce84d7f76efdf1606a85"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "9f301d728f2b94c9a7691c90f07b0b4e8a4517181d9461be94c04bddeb4bd850"
@ -4052,7 +4050,6 @@ dependencies = [
"checksum shift_or_euc_c 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c81ec08c8a68c45c48d8ef58b80ce038cc9945891c4a4996761e2ec5cba05abc"
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
"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 slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d"
"checksum smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1764fe2b30ee783bfe3b9b37b2649d8d590b3148bb12e0079715d4d5c673562e"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"

View File

@ -12,7 +12,7 @@ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
async function runTests() {
const alert = document.getElementById("a11y-announcement");
let alerted = waitForEvent(EVENT_ALERT, alert);
A11yUtils.announce("first");
A11yUtils.announce({ raw: "first" });
let event = await alerted;
const alertAcc = event.accessible;
is(alertAcc.role, ROLE_ALERT);
@ -21,11 +21,37 @@ async function runTests() {
is(alertAcc.firstChild.name, "first");
alerted = waitForEvent(EVENT_ALERT, alertAcc);
A11yUtils.announce("second");
A11yUtils.announce({ raw: "second" });
event = await alerted;
ok(!alertAcc.name);
is(alertAcc.childCount, 1);
is(alertAcc.firstChild.name, "second");
info("Testing Fluent message");
// We need a simple Fluent message here without arguments or attributes.
const fluentId = "search-one-offs-with-title";
const fluentMessage = await document.l10n.formatValue(fluentId);
alerted = waitForEvent(EVENT_ALERT, alertAcc);
A11yUtils.announce({ id: fluentId });
event = await alerted;
ok(!alertAcc.name);
is(alertAcc.childCount, 1);
is(alertAcc.firstChild.name, fluentMessage);
info("Ensuring Fluent message is cancelled if announce is re-entered");
alerted = waitForEvent(EVENT_ALERT, alertAcc);
// This call runs async.
let asyncAnnounce = A11yUtils.announce({ id: fluentId });
// Before the async call finishes, call announce again.
A11yUtils.announce({ raw: "third" });
// Wait for the async call to complete.
await asyncAnnounce;
event = await alerted;
ok(!alertAcc.name);
is(alertAcc.childCount, 1);
// The async call should have been cancelled. If it wasn't, we would get
// fluentMessage here instead of "third".
is(alertAcc.firstChild.name, "third");
}
addAccessibleTask(``, runTests);

View File

@ -24,10 +24,20 @@ function isEventForAutocompleteItem(event) {
return event.accessible.role == ROLE_COMBOBOX_OPTION;
}
function isEventForOneOffButton(event) {
function isEventForButton(event) {
return event.accessible.role == ROLE_PUSHBUTTON;
}
function isEventForOneOffEngine(event) {
let parent = event.accessible.parent;
return (
event.accessible.role == ROLE_PUSHBUTTON &&
parent &&
parent.role == ROLE_GROUPING &&
parent.name
);
}
function isEventForMenuPopup(event) {
return event.accessible.role == ROLE_MENUPOPUP;
}
@ -147,7 +157,7 @@ async function runTests() {
testStates(event.accessible, STATE_FOCUSED);
info("Ensuring autocomplete focus on arrow up for search settings button");
focused = waitForEvent(EVENT_FOCUS, isEventForOneOffButton);
focused = waitForEvent(EVENT_FOCUS, isEventForButton);
EventUtils.synthesizeKey("KEY_ArrowUp");
event = await focused;
testStates(event.accessible, STATE_FOCUSED);
@ -179,7 +189,7 @@ async function runTests() {
testStates(event.accessible, STATE_FOCUSED);
info("Ensuring one-off search button focus on arrow down");
focused = waitForEvent(EVENT_FOCUS, isEventForOneOffButton);
focused = waitForEvent(EVENT_FOCUS, isEventForOneOffEngine);
EventUtils.synthesizeKey("KEY_ArrowDown");
event = await focused;
testStates(event.accessible, STATE_FOCUSED);

View File

@ -153,7 +153,7 @@ function invokeFocus(browser, id) {
Logger.log(`Setting focus on a node with id: ${id}`);
return ContentTask.spawn(browser, id, contentId => {
let elm = content.document.getElementById(contentId);
if (elm.editor || elm.localName == "textbox") {
if (elm.editor) {
elm.selectionStart = elm.selectionEnd = elm.value.length;
}
elm.focus();

View File

@ -1464,7 +1464,7 @@ function synthFocus(aNodeOrID, aCheckerOrEventSeq) {
this.__proto__ = new synthAction(aNodeOrID, checkerOfEventSeq);
this.invoke = function synthFocus_invoke() {
if (this.DOMNode.editor || this.DOMNode.localName == "textbox") {
if (this.DOMNode.editor) {
this.DOMNode.selectionStart = this.DOMNode.selectionEnd = this.DOMNode.value.length;
}
this.DOMNode.focus();
@ -1634,10 +1634,7 @@ function synthSelectAll(aNodeOrID, aCheckerOrEventSeq) {
this.__proto__ = new synthAction(aNodeOrID, aCheckerOrEventSeq);
this.invoke = function synthSelectAll_invoke() {
if (
ChromeUtils.getClassName(this.DOMNode) === "HTMLInputElement" ||
this.DOMNode.localName == "textbox"
) {
if (ChromeUtils.getClassName(this.DOMNode) === "HTMLInputElement") {
this.DOMNode.select();
} else {
window.getSelection().selectAllChildren(this.DOMNode);

View File

@ -279,17 +279,13 @@
// child.
var localName = getNode(aID).localName;
// XUL autocomplete
if (localName == "textbox")
return getAccessible(aID).firstChild;
// HTML form autocomplete
if (localName == "input")
return getAccessible(aID);
// XUL searchbar
if (localName == "searchbar")
return getAccessible(getNode(aID).textbox.inputField);
return getAccessible(getNode(aID).textbox);
return null;
}

View File

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1570701652245">
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1570713923845">
<emItems>
<emItem blockID="i334" id="{0F827075-B026-42F3-885D-98981EE7B1AE}">
<prefs/>
@ -3505,6 +3505,10 @@
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
<emItem blockID="986aac02-beba-40b2-b463-d8447a778a2e" id="/^((\{2B0EC7FF-F330-4e0c-8B33-EFFEC8D39E70\})|(\{f70c89b0-bbf3-41a9-bc1f-0912dcf53f33\})|(@Classifieds)|(@Converter)|(@Coupons)|(@Directions)|(@DownloadManager)|(@Email)|(@Fitness)|(@Flights)|(@FormsApp)|(@Games)|(@Maps)|(@News)|(@Package)|(@Photo)|(@Radio)|(@Recipes)|(@search-encrypt)|(@search-incognito)|(@searchencrypt-b)|(@searchencryptblocker)|(@Speedtest)|(@Sports)|(@Transit)|(@TV)|(@Weather)|(aweapps@Email)|(classified@jetpack)|(email@searchleasier\.com)|(foo-bar@example\.com)|(games@jetpack)|(JS@Converter)|(login@easier)|(maps-webext@jetpack)|(Maps@SSA)|(web-ext@games\.com)|(web@ShoppingNewTab)|(web@SocialNewTab)|(web@WebDesignNewTab)|(webapp@LoginAssistantTab)|(webex@Converter)|(webex@Email)|(webtab@Shopping)|(webtab@Social)|(webtab@WebDesign))$/">
<prefs/>
<versionRange minVersion="0" maxVersion="*" severity="3"/>
</emItem>
</emItems>
<pluginItems>
<pluginItem blockID="p332">

View File

@ -2015,6 +2015,8 @@ pref("devtools.inspector.showUserAgentShadowRoots", false);
pref("devtools.inspector.new-rulesview.enabled", false);
// Enable the compatibility tool in the inspector.
pref("devtools.inspector.compatibility.enabled", false);
// Enable the new Box Model Highlighter with renderer in parent process
pref("devtools.inspector.use-new-box-model-highlighter", false);
// Grid highlighter preferences
pref("devtools.gridinspector.gridOutlineMaxColumns", 50);

View File

@ -37,7 +37,7 @@
<!-- Action buttons -->
<div id="buttons" class="button-container">
<!-- Commands handled in browser.js -->
<button id="goBackButton" data-l10n-id="safeb-palm-accept-label"></button>
<button id="goBackButton" class="primary" data-l10n-id="safeb-palm-accept-label"></button>
<button id="seeDetailsButton" data-l10n-id="safeb-palm-see-details-label"></button>
</div>
</div>

View File

@ -21,15 +21,47 @@ var A11yUtils = {
* can thus hinder rather than help users if used incorrectly.
* Please only use this after consultation with the Mozilla accessibility
* team.
* @param aMessage The message to announce.
* @param aSource The element with which the announcement is associated.
* This should generally be something the user can interact with to
* respond to the announcement.
* For example, for an announcement indicating that Reader View is
* available, this should be the Reader View button on the toolbar.
* @param {string} [options.id] The Fluent id of the message to announce. The
* ftl file must already be included in browser.xhtml. This must be
* specified unless a raw message is specified instead.
* @param {object} [options.args] Arguments for the Fluent message.
* @param {string} [options.raw] The raw, already localized message to
* announce. You should generally prefer a Fluent id instead, but in
* rare cases, this might not be feasible.
* @param {Element} [options.source] The element with which the announcement
* is associated. This should generally be something the user can
* interact with to respond to the announcement. For example, for an
* announcement indicating that Reader View is available, this should
* be the Reader View button on the toolbar.
*/
announce(aMessage, aSource = document) {
// For now, we don't use aSource, but it might be useful in future.
async announce({ id = null, args = {}, raw = null, source = document } = {}) {
if ((!id && !raw) || (id && raw)) {
throw new Error("One of raw or id must be specified.");
}
// Cancel a previous pending call if any.
if (this._cancelAnnounce) {
this._cancelAnnounce();
this._cancelAnnounce = null;
}
let message;
if (id) {
let cancel = false;
this._cancelAnnounce = () => (cancel = true);
message = await document.l10n.formatValue(id, args);
if (cancel) {
// announce() was called again while we were waiting for translation.
return;
}
// No more async operations from this point.
this._cancelAnnounce = null;
} else {
// We run fully synchronously if a raw message is provided.
message = raw;
}
// For now, we don't use source, but it might be useful in future.
// For example, we might use it when we support announcement events on
// more platforms or it could be used to have a keyboard shortcut which
// focuses the last element to announce a message.
@ -42,7 +74,7 @@ var A11yUtils = {
live.firstChild.remove();
}
let label = document.createElement("label");
label.setAttribute("aria-label", aMessage);
label.setAttribute("aria-label", message);
live.appendChild(label);
},
};

View File

@ -1347,3 +1347,24 @@ toolbarpaletteitem > toolbaritem {
toolbar[keyNav=true]:not([collapsed=true]):not([customizing=true]) toolbartabstop {
-moz-user-focus: normal;
}
/* Frame used for rendering the DevTools inspector highlighters */
iframe.devtools-highlighter-renderer {
border: none;
pointer-events: none;
}
/* Highlighter for the Browser Toolbox */
:root > iframe.devtools-highlighter-renderer {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2;
}
/* Highlighter for web content */
.browserStack > iframe.devtools-highlighter-renderer {
-moz-box-flex: 1;
}

View File

@ -78,6 +78,7 @@
<html:link rel="localization" href="browser/browser.ftl"/>
<html:link rel="localization" href="browser/menubar.ftl"/>
<html:link rel="localization" href="browser/appmenu.ftl"/>
<html:link rel="localization" href="browser/readerView.ftl"/>
</linkset>
# All JS files which are needed by browser.xhtml and other top level windows to

View File

@ -76,7 +76,6 @@ fail-if = fission
[browser_firstPartyIsolation.js]
skip-if = fission || debug #Bug 1345346
[browser_firstPartyIsolation_about_newtab.js]
fail-if = fission
[browser_firstPartyIsolation_aboutPages.js]
fail-if = fission
[browser_firstPartyIsolation_blobURI.js]

View File

@ -22,7 +22,10 @@ add_task(async function setup() {
* first.
**/
add_task(async function test_aboutNewTab() {
let win = await BrowserTestUtils.openNewBrowserWindow({ remote: false });
// In Fission, we cannot open a non-remote window.
let win = await BrowserTestUtils.openNewBrowserWindow({
remote: SpecialPowers.useRemoteSubframes,
});
let gbrowser = win.gBrowser;
let tab = BrowserTestUtils.addTab(gbrowser, "about:newtab");
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
@ -30,8 +33,10 @@ add_task(async function test_aboutNewTab() {
let attrs = {
firstPartyDomain: "about.ef2a7dd5-93bc-417f-a698-142c3116864f.mozilla",
};
await ContentTask.spawn(tab.linkedBrowser, { attrs }, async function(args) {
info("principal " + content.document.nodePrincipal.origin);
await SpecialPowers.spawn(tab.linkedBrowser, [{ attrs }], async function(
args
) {
Assert.ok(true, "principal " + content.document.nodePrincipal.origin);
Assert.equal(
content.document.nodePrincipal.originAttributes.firstPartyDomain,
args.attrs.firstPartyDomain,

View File

@ -352,10 +352,6 @@ function test_custom_retention(controlToChange, expect, valueIncrement) {
case "checkbox":
controlToChange.checked = !controlToChange.checked;
break;
case "textbox":
controlToChange.value =
parseInt(controlToChange.value) + valueIncrement;
break;
case "menulist":
controlToChange.value = valueIncrement;
break;

View File

@ -469,7 +469,8 @@ class SearchOneOffs {
let headerText = this.header.querySelector(
".search-panel-one-offs-header-label"
);
this.buttons.setAttribute("aria-label", headerText.value);
headerText.id = this.telemetryOrigin + "-one-offs-header-label";
this.buttons.setAttribute("aria-labelledby", headerText.id);
let engines = await this.getEngines();
let defaultEngine = PrivateBrowsingUtils.isWindowPrivate(window)

View File

@ -0,0 +1,8 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
## Reader View
# Announced by screen readers when Reader View is available for a page.
reader-available-announcement = Reader View available

View File

@ -78,10 +78,6 @@ var ReaderParent = {
let button = win.document.getElementById("reader-mode-button");
let menuitem = win.document.getElementById("menu_readerModeItem");
let key = win.document.getElementById("key_toggleReaderMode");
// aria-reader is not a real ARIA attribute. However, this will cause
// Gecko accessibility to expose the "reader" object attribute. We do this
// so that the reader state is easy for accessibility clients to access
// programmatically.
if (browser.currentURI.spec.startsWith("about:reader")) {
let closeText = gStringBundle.GetStringFromName("readerView.close");
@ -98,7 +94,6 @@ var ReaderParent = {
key.setAttribute("disabled", false);
browser.setAttribute("aria-reader", "active");
Services.obs.notifyObservers(null, "reader-mode-available");
} else {
let enterText = gStringBundle.GetStringFromName("readerView.enter");
@ -117,10 +112,11 @@ var ReaderParent = {
key.setAttribute("disabled", !browser.isArticle);
if (browser.isArticle) {
browser.setAttribute("aria-reader", "available");
win.A11yUtils.announce({
id: "reader-available-announcement",
source: button,
});
Services.obs.notifyObservers(null, "reader-mode-available");
} else {
browser.removeAttribute("aria-reader");
}
}
},

View File

@ -4,56 +4,30 @@
@import url("chrome://browser/skin/error-pages.css");
html {
background-color: #A4000F;
}
body {
color: white;
:root {
--in-content-page-background: #A4000F;
--in-content-page-color: white;
--in-content-text-color: white;
--in-content-selected-text: black;
--in-content-button-background: transparent;
--in-content-button-background-hover: #5a0002;
--in-content-button-background-active: #3e0200;
--in-content-primary-button-background: white;
--in-content-primary-button-background-hover: rgba(255, 255, 255, 0.8);
--in-content-primary-button-background-active: rgba(255, 255, 255, 0.7);
}
.title {
background-image: url("chrome://global/skin/icons/blocked.svg");
}
.title-text {
color: white;
}
.button-container button {
background-color: transparent;
/* !important overrides the common.css button color */
color: white !important;
border: 1px solid white;
margin-inline-end: 0;
margin-top: 1.5em;
}
.button-container button:hover {
background-color: #5a0002;
}
.button-container button:hover:active {
background-color: #3e0200;
}
#goBackButton {
color: black !important;
background-color: white;
}
#goBackButton:hover {
background-color: white;
opacity: 0.8;
}
#goBackButton:active {
background-color: white;
opacity: 0.7;
}
#advisory_provider {
color: white;
text-decoration: underline;
}

View File

@ -185,6 +185,10 @@ p {
padding-inline-start: 44px;
}
.banner-body:dir(rtl) {
background-position-x: right;
}
.banner-body h1 {
font-size: 18px;
font-weight: bold;
@ -227,12 +231,15 @@ p {
}
.search-banner-close-button {
float: right;
min-width: 20px;
min-height: 20px;
float: inline-end;
/* min-width and min-height override values set on button elements. */
min-width: 28px;
min-height: 28px;
height: 28px;
margin: 16px;
padding: 0;
background-color: inherit;
border: 0;
}
.search-banner-close-image {

View File

@ -4,7 +4,6 @@
"use strict";
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const {
createFactory,
PureComponent,
@ -28,20 +27,15 @@ const ManifestSection = createFactory(require("./ManifestSection"));
const ManifestJsonLink = createFactory(require("./ManifestJsonLink"));
const { MANIFEST_MEMBER_VALUE_TYPES } = require("../../constants");
const Types = require("../../types/index");
/**
* A canonical manifest, splitted in different sections
*/
class Manifest extends PureComponent {
static get propTypes() {
// TODO: Use well-defined types
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1576881
return {
icons: PropTypes.array.isRequired,
identity: PropTypes.array.isRequired,
presentation: PropTypes.array.isRequired,
validation: PropTypes.array.isRequired,
url: PropTypes.string.isRequired,
...Types.manifest, // { identity, presentation, icons, validation, url }
};
}

View File

@ -4,13 +4,13 @@
"use strict";
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const {
createFactory,
PureComponent,
} = require("devtools/client/shared/vendor/react");
const { span } = require("devtools/client/shared/vendor/react-dom-factories");
const Types = require("../../types/index");
const ManifestItem = createFactory(require("./ManifestItem"));
/**
@ -19,8 +19,7 @@ const ManifestItem = createFactory(require("./ManifestItem"));
class ManifestColorItem extends PureComponent {
static get propTypes() {
return {
label: PropTypes.string.isRequired,
value: PropTypes.string,
...Types.manifestItemColor, // { label, value }
};
}

View File

@ -4,7 +4,6 @@
"use strict";
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const {
createFactory,
PureComponent,
@ -20,6 +19,7 @@ const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const Localized = createFactory(FluentReact.Localized);
const { l10n } = require("../../modules/l10n");
const Types = require("../../types/index");
const ManifestItem = createFactory(require("./ManifestItem"));
/**
@ -28,14 +28,11 @@ const ManifestItem = createFactory(require("./ManifestItem"));
class ManifestIconItem extends PureComponent {
static get propTypes() {
return {
label: PropTypes.shape({
contentType: PropTypes.string,
sizes: PropTypes.string,
}).isRequired,
value: PropTypes.shape({
src: PropTypes.string.isRequired,
purpose: PropTypes.string.isRequired,
}).isRequired,
// {
// label: { contentType, sizes },
// value: { src, purpose }
// }
...Types.manifestItemIcon,
};
}

View File

@ -19,6 +19,7 @@ const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const Localized = createFactory(FluentReact.Localized);
const { MANIFEST_ISSUE_LEVELS } = require("../../constants");
const Types = require("../../types/index");
/**
* A Manifest validation issue (warning, error)
@ -27,10 +28,7 @@ class ManifestIssue extends PureComponent {
static get propTypes() {
return {
className: PropTypes.string,
level: PropTypes.oneOf(Object.values(MANIFEST_ISSUE_LEVELS)).isRequired,
message: PropTypes.string.isRequired,
// NOTE: we are currently ignoring the 'type' field that platform adds to
// errors
...Types.manifestIssue, // { level, message }
};
}

View File

@ -4,7 +4,6 @@
"use strict";
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const {
createFactory,
PureComponent,
@ -12,6 +11,8 @@ const {
const { ul } = require("devtools/client/shared/vendor/react-dom-factories");
const { MANIFEST_ISSUE_LEVELS } = require("../../constants");
const Types = require("../../types/index");
const ManifestIssue = createFactory(require("./ManifestIssue"));
/**
@ -19,10 +20,8 @@ const ManifestIssue = createFactory(require("./ManifestIssue"));
*/
class ManifestIssueList extends PureComponent {
static get propTypes() {
// TODO: Use well-defined types
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1576881
return {
issues: PropTypes.array.isRequired,
issues: Types.manifestIssueArray.isRequired,
};
}

View File

@ -15,20 +15,19 @@ const {
const { connect } = require("devtools/client/shared/vendor/react-redux");
const ManifestLoader = createFactory(require("../manifest/ManifestLoader"));
const Types = require("../../types/index");
const ManifestLoader = createFactory(require("../manifest/ManifestLoader"));
const Manifest = createFactory(require("./Manifest"));
const ManifestEmpty = createFactory(require("./ManifestEmpty"));
class ManifestPage extends PureComponent {
// TODO: Use well-defined types
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1576881
static get propTypes() {
return {
// these props are automatically injected via connect
hasLoadingFailed: PropTypes.bool.isRequired,
isManifestLoading: PropTypes.bool.isRequired,
manifest: PropTypes.object,
manifest: PropTypes.shape(Types.manifest),
};
}

View File

@ -9,9 +9,9 @@ const {
PureComponent,
} = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { PAGE_TYPES } = require("../../constants");
const Types = require("../../types/index");
const ManifestPage = createFactory(require("../manifest/ManifestPage"));
const WorkersPage = createFactory(require("../service-workers/WorkersPage"));
@ -19,7 +19,7 @@ const WorkersPage = createFactory(require("../service-workers/WorkersPage"));
class PageSwitcher extends PureComponent {
static get propTypes() {
return {
page: PropTypes.oneOf(Object.values(PAGE_TYPES)),
page: Types.page.isRequired,
};
}

View File

@ -12,19 +12,19 @@ const {
aside,
ul,
} = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const SidebarItem = createFactory(require("./SidebarItem"));
const Types = require("../../types/index");
const { PAGE_TYPES } = require("../../constants");
class Sidebar extends PureComponent {
static get propTypes() {
return {
// this prop is automatically injected via connect
selectedPage: PropTypes.oneOf(Object.values(PAGE_TYPES)),
selectedPage: Types.page.isRequired,
};
}

View File

@ -23,6 +23,7 @@ const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const Localized = createFactory(FluentReact.Localized);
const { PAGE_TYPES } = require("../../constants");
const Types = require("../../types/index");
const ICONS = {
[PAGE_TYPES.MANIFEST]:
@ -39,7 +40,7 @@ const LOCALIZATION_IDS = {
class SidebarItem extends PureComponent {
static get propTypes() {
return {
page: PropTypes.oneOf(Object.values(PAGE_TYPES)),
page: Types.page.isRequired,
isSelected: PropTypes.bool.isRequired,
// this prop is automatically injected via connect
dispatch: PropTypes.func.isRequired,

View File

@ -31,6 +31,8 @@ const {
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const Localized = createFactory(FluentReact.Localized);
const Types = require("../../types/index");
const UIButton = createFactory(require("../ui/UIButton"));
loader.lazyRequireGetter(
@ -50,16 +52,7 @@ class Worker extends PureComponent {
static get propTypes() {
return {
isDebugEnabled: PropTypes.bool.isRequired,
worker: PropTypes.shape({
active: PropTypes.bool,
name: PropTypes.string.isRequired,
scope: PropTypes.string.isRequired,
lastUpdateTime: PropTypes.number.isRequired,
url: PropTypes.string.isRequired,
// registrationFront can be missing in e10s.
registrationFront: PropTypes.object,
workerTargetFront: PropTypes.object,
}).isRequired,
worker: PropTypes.shape(Types.worker).isRequired,
};
}

View File

@ -17,11 +17,13 @@ const {
h1,
ul,
} = require("devtools/client/shared/vendor/react-dom-factories");
const Worker = createFactory(require("./Worker"));
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const Localized = createFactory(FluentReact.Localized);
const Types = require("../../types/index");
const Worker = createFactory(require("./Worker"));
/**
* This component handles the list of service workers displayed in the application panel
* and also displays a suggestion to use about debugging for debugging other service
@ -31,7 +33,7 @@ class WorkerList extends PureComponent {
static get propTypes() {
return {
canDebugWorkers: PropTypes.bool.isRequired,
workers: PropTypes.array.isRequired,
workers: Types.workerArray.isRequired,
};
}

View File

@ -14,6 +14,7 @@ const {
} = require("devtools/client/shared/vendor/react-dom-factories");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const Types = require("../../types/index");
const WorkerList = createFactory(require("./WorkerList"));
const WorkerListEmpty = createFactory(require("./WorkerListEmpty"));
@ -23,7 +24,7 @@ class WorkersPage extends PureComponent {
// mapped from state
canDebugWorkers: PropTypes.bool.isRequired,
domain: PropTypes.string.isRequired,
workers: PropTypes.array.isRequired,
workers: Types.workerArray.isRequired,
};
}

View File

@ -7,6 +7,7 @@ DIRS += [
'components',
'modules',
'reducers',
'types',
]
DevToolsModules(

View File

@ -0,0 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const manifestTypes = require("./manifest");
const routingTypes = require("./routing");
const workersTypes = require("./service-workers");
module.exports = Object.assign(
{},
{
...manifestTypes,
...routingTypes,
...workersTypes,
}
);

View File

@ -0,0 +1,79 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { MANIFEST_ISSUE_LEVELS } = require("../constants");
const { MANIFEST_MEMBER_VALUE_TYPES } = require("../constants");
const manifestIssue = {
level: PropTypes.oneOf(Object.values(MANIFEST_ISSUE_LEVELS)).isRequired,
message: PropTypes.string.isRequired,
// NOTE: we are currently ignoring the 'type' field that platform adds to errors
};
const manifestIssueArray = PropTypes.arrayOf(PropTypes.shape(manifestIssue));
const manifestItemColor = {
label: PropTypes.string.isRequired,
value: PropTypes.string,
};
const manifestItemIcon = {
label: PropTypes.shape({
contentType: PropTypes.string,
sizes: PropTypes.string,
}).isRequired,
value: PropTypes.shape({
src: PropTypes.string.isRequired,
purpose: PropTypes.string.isRequired,
}).isRequired,
};
const manifestMemberColor = {
key: manifestItemColor.label,
value: manifestItemColor.value,
type: PropTypes.oneOf([MANIFEST_MEMBER_VALUE_TYPES.COLOR]),
};
const manifestMemberIcon = {
key: manifestItemIcon.label,
value: manifestItemIcon.value,
type: PropTypes.oneOf([MANIFEST_MEMBER_VALUE_TYPES.ICON]),
};
const manifestMemberString = {
key: PropTypes.string.isRequired,
value: PropTypes.string,
type: PropTypes.oneOf([MANIFEST_MEMBER_VALUE_TYPES.STRING]),
};
const manifest = {
// members
identity: PropTypes.arrayOf(PropTypes.shape(manifestMemberString)).isRequired,
presentation: PropTypes.arrayOf(
PropTypes.oneOfType([
PropTypes.shape(manifestMemberColor),
PropTypes.shape(manifestMemberString),
])
).isRequired,
icons: PropTypes.arrayOf(PropTypes.shape(manifestMemberIcon)).isRequired,
// validation issues
validation: manifestIssueArray.isRequired,
// misc
url: PropTypes.string.isRequired,
};
module.exports = {
// full manifest
manifest,
// specific manifest items
manifestItemColor,
manifestItemIcon,
// manifest issues
manifestIssue,
manifestIssueArray,
};

View File

@ -0,0 +1,10 @@
# 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/.
DevToolsModules(
'index.js',
'manifest.js',
'routing.js',
'service-workers.js',
)

View File

@ -0,0 +1,14 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { PAGE_TYPES } = require("../constants");
const page = PropTypes.oneOf(Object.values(PAGE_TYPES));
module.exports = {
page,
};

View File

@ -0,0 +1,25 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const worker = {
active: PropTypes.bool,
name: PropTypes.string.isRequired,
scope: PropTypes.string.isRequired,
lastUpdateTime: PropTypes.number.isRequired,
url: PropTypes.string.isRequired,
// registrationFront can be missing in e10s.
registrationFront: PropTypes.object,
workerTargetFront: PropTypes.object,
};
const workerArray = PropTypes.arrayOf(PropTypes.shape(worker));
module.exports = {
worker,
workerArray,
};

View File

@ -68,7 +68,7 @@ class NetworkActionBar extends Component {
showSearchPanel &&
TabPanel(
{
id: "network-action-bar-search",
id: PANELS.SEARCH,
title: L10N.getStr("netmonitor.actionbar.search"),
className: "network-action-bar-search",
},

View File

@ -12,6 +12,7 @@ const {
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { div, span } = dom;
const Actions = require("devtools/client/netmonitor/src/actions/index");
const { PANELS } = require("../../constants");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const {
connect,
@ -47,6 +48,7 @@ class SearchPanel extends Component {
query: PropTypes.string.isRequired,
results: PropTypes.array,
navigate: PropTypes.func.isRequired,
isDisplaying: PropTypes.bool.isRequired,
};
}
@ -66,6 +68,12 @@ class SearchPanel extends Component {
}
}
componentDidUpdate(prevProps) {
if (this.props.isDisplaying && !prevProps.isDisplaying) {
this.searchboxRef.current.focus();
}
}
onClickTreeRow(path, event, member) {
if (member.object.parentResource) {
this.props.navigate(member.object);
@ -234,6 +242,7 @@ module.exports = connect(
caseSensitive: state.search.caseSensitive,
results: state.search.results,
ongoingSearch: state.search.ongoingSearch,
isDisplaying: state.ui.selectedActionBarTabId === PANELS.SEARCH,
status: state.search.status,
}),
dispatch => ({

View File

@ -208,6 +208,7 @@ const PANELS = {
SECURITY: "security",
STACK_TRACE: "stack-trace",
TIMINGS: "timings",
SEARCH: "network-action-bar-search",
BLOCKING: "network-action-bar-blocked",
};

View File

@ -46,6 +46,12 @@ loader.lazyRequireGetter(
"devtools/server/actors/highlighters/box-model",
true
);
loader.lazyRequireGetter(
this,
"BoxModelHighlighterObserver",
"devtools/server/actors/highlighters/box-model-observer",
true
);
const HIGHLIGHTER_PICKED_TIMER = 1000;
const IS_OSX = Services.appinfo.OS === "Darwin";
@ -110,7 +116,7 @@ exports.register = register;
* The HighlighterActor class
*/
exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
initialize: function(inspector, autohide) {
initialize: function(inspector, autohide, useNewBoxModelHighlighter = false) {
protocol.Actor.prototype.initialize.call(this, null);
this._autohide = autohide;
@ -119,6 +125,7 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
this._targetActor = this._inspector.targetActor;
this._highlighterEnv = new HighlighterEnvironment();
this._highlighterEnv.initFromTargetActor(this._targetActor);
this._useNewBoxModelHighlighter = useNewBoxModelHighlighter;
this._onNavigate = this._onNavigate.bind(this);
@ -147,6 +154,15 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
_createHighlighter: function() {
this._isPreviousWindowXUL = isXUL(this._targetActor.window);
if (this._useNewBoxModelHighlighter) {
this._highlighter = new BoxModelHighlighterObserver(
this._highlighterEnv,
this.conn
);
return;
}
if (!this._isPreviousWindowXUL) {
this._highlighter = new BoxModelHighlighter(
this._highlighterEnv,

View File

@ -85,6 +85,7 @@ function AutoRefreshHighlighter(highlighterEnv) {
AutoRefreshHighlighter.prototype = {
_ignoreZoom: false,
_ignoreScroll: false,
/**
* Window corresponding to the current highlighterEnv. When replaying, this
@ -194,7 +195,7 @@ AutoRefreshHighlighter.prototype = {
this.contentWindow,
this.currentNode,
region,
{ ignoreZoom: this._ignoreZoom }
{ ignoreScroll: this._ignoreScroll, ignoreZoom: this._ignoreZoom }
);
}
},

View File

@ -0,0 +1,312 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { DebuggerServer } = require("devtools/server/debugger-server");
const { AutoRefreshHighlighter } = require("./auto-refresh");
const {
getBindingElementAndPseudo,
hasPseudoClassLock,
isNodeValid,
} = require("./utils/markup");
const { PSEUDO_CLASSES } = require("devtools/shared/css/constants");
const { getCurrentZoom } = require("devtools/shared/layout/utils");
const {
getNodeDisplayName,
getNodeGridFlexType,
} = require("devtools/server/actors/inspector/utils");
const nodeConstants = require("devtools/shared/dom-node-constants");
const { LocalizationHelper } = require("devtools/shared/l10n");
const STRINGS_URI = "devtools/shared/locales/highlighters.properties";
const L10N = new LocalizationHelper(STRINGS_URI);
const {
BOX_MODEL_REGIONS,
BoxModelHighlighterRenderer,
} = require("devtools/server/actors/highlighters/box-model-renderer");
/**
* The BoxModelHighlighterObserver observes the coordinates of a node and communicates
* with the BoxModelHighlighterRenderer which draws the box model regions on top the a
* node.
*
* When in the context of the content toolbox, the observer lives in
* the child process (aka content process) and the renderer is set up in the parent
* process. They communicate via messages.
*
* When in the context of the browser toolbox, both observer and renderer live in the
* parent process. They communicate by direct reference.
*/
class BoxModelHighlighterObserver extends AutoRefreshHighlighter {
constructor(highlighterEnv, conn) {
super(highlighterEnv);
this.conn = conn;
this._ignoreScroll = true;
this.typeName = this.constructor.name.replace("Observer", "");
if (DebuggerServer.isInChildProcess) {
// eslint-disable-next-line no-restricted-properties
this.conn.setupInParent({
module: "devtools/server/actors/highlighters/box-model-renderer",
setupParent: "setupParentProcess",
});
} else {
this.renderer = new BoxModelHighlighterRenderer();
}
/**
* Optionally customize each region's fill color by adding an entry to the
* regionFill property: `highlighter.regionFill.margin = "red";
*/
this.regionFill = {};
this.onPageHide = this.onPageHide.bind(this);
this.onWillNavigate = this.onWillNavigate.bind(this);
this.highlighterEnv.on("will-navigate", this.onWillNavigate);
const { pageListenerTarget } = highlighterEnv;
pageListenerTarget.addEventListener("pagehide", this.onPageHide);
}
/**
* Destroy the nodes. Remove listeners.
*/
destroy() {
this.highlighterEnv.off("will-navigate", this.onWillNavigate);
const { pageListenerTarget } = this.highlighterEnv;
if (pageListenerTarget) {
pageListenerTarget.removeEventListener("pagehide", this.onPageHide);
}
if (DebuggerServer.isInChildProcess) {
this.postMessage("destroy");
} else {
this.renderer.destroy();
this.renderer = null;
}
AutoRefreshHighlighter.prototype.destroy.call(this);
}
get messageManager() {
if (!DebuggerServer.isInChildProcess) {
throw new Error(
"Message manager should only be used when actor is in child process."
);
}
return this.conn.parentMessageManager;
}
postMessage(topic, data = {}) {
this._msgName = `debug:${this.conn.prefix}${this.typeName}`;
this.messageManager.sendAsyncMessage(this._msgName, { topic, data });
}
/**
* Tell the renderer to update the markup of the box model highlighter.
*
* @param {Object} data
* Object with data about the node position, type and its attributes.
* @see BoxModelHighlighterRenderer.render()
*/
render(data) {
if (DebuggerServer.isInChildProcess) {
this.postMessage("render", data);
} else {
this.renderer.render(data);
}
}
/**
* Override the AutoRefreshHighlighter's _isNodeValid method to also return true for
* text nodes since these can also be highlighted.
* @param {DOMNode} node
* @return {Boolean}
*/
_isNodeValid(node) {
return (
node && (isNodeValid(node) || isNodeValid(node, nodeConstants.TEXT_NODE))
);
}
/**
* Show the highlighter on a given node
*/
_show() {
if (!BOX_MODEL_REGIONS.includes(this.options.region)) {
this.options.region = "content";
}
const shown = this._update();
this._trackMutations();
return shown;
}
/**
* Track the current node markup mutations so that the node info bar can be
* updated to reflects the node's attributes
*/
_trackMutations() {
if (isNodeValid(this.currentNode)) {
const win = this.currentNode.ownerGlobal;
this.currentNodeObserver = new win.MutationObserver(this.update);
this.currentNodeObserver.observe(this.currentNode, { attributes: true });
}
}
_untrackMutations() {
if (isNodeValid(this.currentNode) && this.currentNodeObserver) {
this.currentNodeObserver.disconnect();
this.currentNodeObserver = null;
}
}
/**
* Update the highlighter on the current highlighted node (the one that was
* passed as an argument to show(node)).
* Should be called whenever node size or attributes change
*/
_update() {
const node = this.currentNode;
let shown = false;
if (this._nodeNeedsHighlighting()) {
// Tell the renderer to update the highlighter markup and provide it
// with options, metadata and coordinates of the target node.
const data = {
...this.options,
currentQuads: { ...this.currentQuads },
regionFill: { ...this.regionFill },
nodeData: this._getNodeData(),
showBoxModel: true,
showInfoBar:
!this.options.hideInfoBar &&
(node.nodeType === node.ELEMENT_NODE ||
node.nodeType === node.TEXT_NODE),
};
this.render(data);
shown = true;
} else {
// Nothing to highlight (0px rectangle like a <script> tag for instance)
this._hide();
}
return shown;
}
/**
* Hide the highlighter, the outline and the infobar.
*/
_hide() {
this._untrackMutations();
// Tell the renderer to hide the highlighter markup.
this.render({
showBoxModel: false,
showInfoBar: false,
});
}
/**
* Can the current node be highlighted? Does it have quads.
* @return {Boolean}
*/
_nodeNeedsHighlighting() {
return (
this.currentQuads.margin.length ||
this.currentQuads.border.length ||
this.currentQuads.padding.length ||
this.currentQuads.content.length
);
}
/**
* Get data from the highlighted node to populate the infobar tooltip with
* information such as the node's id, class names, grid or flex item type, etc.
*
* @return {Object|null} Information about the highlighted node
*/
_getNodeData() {
if (!this.currentNode) {
return null;
}
const { bindingElement: node, pseudo } = getBindingElementAndPseudo(
this.currentNode
);
// Update the tag, id, classes, pseudo-classes and dimensions
const displayName = getNodeDisplayName(node);
const id = node.id ? "#" + node.id : "";
const classList = (node.classList || []).length
? "." + [...node.classList].join(".")
: "";
let pseudos = this._getPseudoClasses(node).join("");
if (pseudo) {
// Display :after as ::after
pseudos += ":" + pseudo;
}
const zoom = getCurrentZoom(this.win);
const { grid: gridType, flex: flexType } = getNodeGridFlexType(node);
const gridLayoutTextType = this._getLayoutTextType("gridType", gridType);
const flexLayoutTextType = this._getLayoutTextType("flexType", flexType);
return {
classList,
displayName,
flexLayoutTextType,
gridLayoutTextType,
id,
pseudos,
zoom,
};
}
_getLayoutTextType(layoutTypeKey, { isContainer, isItem }) {
if (!isContainer && !isItem) {
return "";
}
if (isContainer && !isItem) {
return L10N.getStr(`${layoutTypeKey}.container`);
}
if (!isContainer && isItem) {
return L10N.getStr(`${layoutTypeKey}.item`);
}
return L10N.getStr(`${layoutTypeKey}.dual`);
}
_getPseudoClasses(node) {
if (node.nodeType !== nodeConstants.ELEMENT_NODE) {
// hasPseudoClassLock can only be used on Elements.
return [];
}
return PSEUDO_CLASSES.filter(pseudo => hasPseudoClassLock(node, pseudo));
}
onPageHide({ target }) {
// If a pagehide event is triggered for current window's highlighter, hide the
// highlighter.
if (target.defaultView === this.win) {
this.hide();
}
}
onWillNavigate({ isTopLevel }) {
if (isTopLevel) {
this.hide();
}
}
}
exports.BoxModelHighlighterObserver = BoxModelHighlighterObserver;

View File

@ -0,0 +1,752 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
createNode,
createSVGNode,
moveInfobar,
} = require("devtools/server/actors/highlighters/utils/markup");
const {
HighlighterRenderer,
} = require("devtools/server/actors/highlighters/highlighter-renderer");
// Note that the order of items in this array is important because it is used
// for drawing the BoxModelHighlighter's path elements correctly.
const BOX_MODEL_REGIONS = ["margin", "border", "padding", "content"];
exports.BOX_MODEL_REGIONS = BOX_MODEL_REGIONS;
const BOX_MODEL_SIDES = ["top", "right", "bottom", "left"];
// Width of BoxModelHighlighter guides
const GUIDE_STROKE_WIDTH = 1;
/**
* The BoxModelHighlighterRenderer receives node coordinates from the
* BoxModelHighlighterObserver and draws the box model regions on top of a node.
* If the node is a block box, then each region will be displayed as 1 polygon.
* If the node is an inline box though, each region may be represented by 1 or
* more polygons, depending on how many line boxes the inline element has.
*
* Structure:
* <div class="highlighter-container">
* <div class="box-model-root">
* <svg class="box-model-elements" hidden="true">
* <g class="box-model-regions">
* <path class="box-model-margin" points="..." />
* <path class="box-model-border" points="..." />
* <path class="box-model-padding" points="..." />
* <path class="box-model-content" points="..." />
* </g>
* <line class="box-model-guide-top" x1="..." y1="..." x2="..." y2="..." />
* <line class="box-model-guide-right" x1="..." y1="..." x2="..." y2="..." />
* <line class="box-model-guide-bottom" x1="..." y1="..." x2="..." y2="..." />
* <line class="box-model-guide-left" x1="..." y1="..." x2="..." y2="..." />
* </svg>
* <div class="box-model-infobar-container">
* <div class="box-model-infobar-arrow highlighter-infobar-arrow-top" />
* <div class="box-model-infobar">
* <div class="box-model-infobar-text" align="center">
* <span class="box-model-infobar-tagname">Node name</span>
* <span class="box-model-infobar-id">Node id</span>
* <span class="box-model-infobar-classes">.someClass</span>
* <span class="box-model-infobar-pseudo-classes">:hover</span>
* <span class="box-model-infobar-grid-type">Grid Type</span>
* <span class="box-model-infobar-flex-type">Flex Type</span>
* </div>
* </div>
* <div class="box-model-infobar-arrow box-model-infobar-arrow-bottom"/>
* </div>
* </div>
* </div>
*/
class BoxModelHighlighterRenderer extends HighlighterRenderer {
constructor(mm, prefix) {
super();
// @override Highlighter type name.
this.typeName = this.constructor.name.replace("Renderer", "");
// String used to prefix ids and classnames of highlighter nodes.
this.ID_CLASS_PREFIX = "box-model-";
// If there is a message manager and connection prefix, it means the observer lives
// in the content process so we need to setup a communication system with it.
// Otherwise, both renderer and observer live in the parent process and there is no
// need for a message-based communication system.
if (mm && prefix) {
this.setMessageManager(mm, prefix);
this.init(false);
} else {
this.init(true);
}
}
/**
* Update the rendering of the box model highlighter, inforbar and guides for a node
* using quad coordinates, node information and options from the BoxModelHighlighterObserver.
*
* @override
*
* @param {Object} data
* Information used for rendering the box model highlighter, infobar and guides.
*
* @param {Boolean} data.showBoxModel
* Whether to show the box model highlighter.
* Defaults to false
* @param {Boolean} data.showInfoBar
* Whether to show the tooltip with the node's dimensions, class names, id, etc.
* Defaults to false
* @param {Object} data.currentQuads
* Collection of quad coordinates for a node's box model regions keyed by region
* @param {Object} data.regionFill
* Optional collection of custom fill colors for box model regions keyed by
* region. Ex: data.regionFill.margin = "red"
*
* @param {Object} data.nodeData
* Collection of information about a node used for the infobar tooltip.
* @param {String} data.nodeData.classList
* String with list of class names separated by a dot (.) insead of space.
* @param {String} data.nodeData.displayName
* Node tag name.
* @param {String} data.nodeData.flexLayoutTextType
* Flex item or flex container.
* @param {String} data.nodeData.gridLayoutTextType
* Grid idem or flex container.
* @param {String} data.nodeData.id
* Node id attribute.
* @param {String} data.nodeData.pseudos
* Pseudo-element type if the node is a ::before/::after pseudo-element
* @param {Number} data.nodeData.zoom
* Zoom level of the content page where the node exists.
*
* @param {Object} data.options
* Collection of optional overrides in the highlighter rendering.
* @param {String} data.options.region
* Specifies the region that the guides should outline:
* "content" (default), "padding", "border" or "margin".
* @param {Boolean} data.options.hideGuides
* Defaults to false
* @param {Boolean} data.options.hideInfoBar
* Defaults to false
* @param {String} data.options.showOnly
* If set, only this region will be highlighted. Use with onlyRegionArea
* to only highlight the area of the region:
* "content", "padding", "border" or "margin"
* @param {Boolean} data.options.onlyRegionArea
* This can be set to true to make each region's box only highlight the
* area of the corresponding region rather than the area of nested
* regions too. This is useful when used with showOnly.
*/
render(data = {}) {
this.currentQuads = data.currentQuads || {};
this.nodeData = data.nodeData || null;
this.options = data.options || {};
this.regionFill = data.regionFill || {};
const { showBoxModel = false, showInfoBar = false } = data;
if (!showBoxModel) {
this._hideBoxModel();
this._hideInfobar();
return;
}
this._updateBoxModel();
this._showBoxModel();
if (!showInfoBar) {
this._hideInfobar();
} else {
this._updateInfobar();
this._showInfobar();
}
}
getElement(id) {
return this.markup.getElement(this.ID_CLASS_PREFIX + id);
}
/**
* Hide the infobar
*/
_hideInfobar() {
this.getElement("infobar-container").setAttribute("hidden", "true");
}
/**
* Show the infobar
*/
_showInfobar() {
this.getElement("infobar-container").removeAttribute("hidden");
}
/**
* Hide the box model
*/
_hideBoxModel() {
this.getElement("elements").setAttribute("hidden", "true");
}
/**
* Show the box model
*/
_showBoxModel() {
this.getElement("elements").removeAttribute("hidden");
}
/**
* Update the box model
*/
_updateBoxModel() {
const options = this.options;
options.region = options.region || "content";
for (let i = 0; i < BOX_MODEL_REGIONS.length; i++) {
const boxType = BOX_MODEL_REGIONS[i];
const nextBoxType = BOX_MODEL_REGIONS[i + 1];
const box = this.getElement(boxType);
if (this.regionFill[boxType]) {
box.setAttribute("style", "fill:" + this.regionFill[boxType]);
} else {
box.setAttribute("style", "");
}
// Highlight all quads for this region by setting the "d" attribute of the
// corresponding <path>.
const path = [];
for (let j = 0; j < this.currentQuads[boxType].length; j++) {
const boxQuad = this.currentQuads[boxType][j];
const nextBoxQuad = this.currentQuads[nextBoxType]
? this.currentQuads[nextBoxType][j]
: null;
path.push(this._getBoxPathCoordinates(boxQuad, nextBoxQuad));
}
box.setAttribute("d", path.join(" "));
box.removeAttribute("faded");
// If showOnly is defined, either hide the other regions, or fade them out
// if onlyRegionArea is set too.
if (options.showOnly && options.showOnly !== boxType) {
if (options.onlyRegionArea) {
box.setAttribute("faded", "true");
} else {
box.removeAttribute("d");
}
}
if (boxType === options.region && !options.hideGuides) {
this._showGuides(boxType);
} else if (options.hideGuides) {
this._hideGuides();
}
}
}
/**
* Calculate an outer quad based on the quads returned by getAdjustedQuads.
* The BoxModelHighlighter may highlight more than one boxes, so in this case
* create a new quad that "contains" all of these quads.
* This is useful to position the guides and infobar.
* This may happen if the BoxModelHighlighter is used to highlight an inline
* element that spans line breaks.
* @param {String} region The box-model region to get the outer quad for.
* @return {Object} A quad-like object {p1,p2,p3,p4,bounds}
*/
_getOuterQuad(region) {
const quads = this.currentQuads[region];
if (!quads || !quads.length) {
return null;
}
const quad = {
p1: { x: Infinity, y: Infinity },
p2: { x: -Infinity, y: Infinity },
p3: { x: -Infinity, y: -Infinity },
p4: { x: Infinity, y: -Infinity },
bounds: {
bottom: -Infinity,
height: 0,
left: Infinity,
right: -Infinity,
top: Infinity,
width: 0,
x: 0,
y: 0,
},
};
for (const q of quads) {
quad.p1.x = Math.min(quad.p1.x, q.p1.x);
quad.p1.y = Math.min(quad.p1.y, q.p1.y);
quad.p2.x = Math.max(quad.p2.x, q.p2.x);
quad.p2.y = Math.min(quad.p2.y, q.p2.y);
quad.p3.x = Math.max(quad.p3.x, q.p3.x);
quad.p3.y = Math.max(quad.p3.y, q.p3.y);
quad.p4.x = Math.min(quad.p4.x, q.p4.x);
quad.p4.y = Math.max(quad.p4.y, q.p4.y);
quad.bounds.bottom = Math.max(quad.bounds.bottom, q.bounds.bottom);
quad.bounds.top = Math.min(quad.bounds.top, q.bounds.top);
quad.bounds.left = Math.min(quad.bounds.left, q.bounds.left);
quad.bounds.right = Math.max(quad.bounds.right, q.bounds.right);
}
quad.bounds.x = quad.bounds.left;
quad.bounds.y = quad.bounds.top;
quad.bounds.width = quad.bounds.right - quad.bounds.left;
quad.bounds.height = quad.bounds.bottom - quad.bounds.top;
return quad;
}
_getBoxPathCoordinates(boxQuad, nextBoxQuad) {
const { p1, p2, p3, p4 } = boxQuad;
let path;
if (!nextBoxQuad || !this.options.onlyRegionArea) {
// If this is the content box (inner-most box) or if we're not being asked
// to highlight only region areas, then draw a simple rectangle.
path =
"M" +
p1.x +
"," +
p1.y +
" " +
"L" +
p2.x +
"," +
p2.y +
" " +
"L" +
p3.x +
"," +
p3.y +
" " +
"L" +
p4.x +
"," +
p4.y;
} else {
// Otherwise, just draw the region itself, not a filled rectangle.
const { p1: np1, p2: np2, p3: np3, p4: np4 } = nextBoxQuad;
path =
"M" +
p1.x +
"," +
p1.y +
" " +
"L" +
p2.x +
"," +
p2.y +
" " +
"L" +
p3.x +
"," +
p3.y +
" " +
"L" +
p4.x +
"," +
p4.y +
" " +
"L" +
p1.x +
"," +
p1.y +
" " +
"L" +
np1.x +
"," +
np1.y +
" " +
"L" +
np4.x +
"," +
np4.y +
" " +
"L" +
np3.x +
"," +
np3.y +
" " +
"L" +
np2.x +
"," +
np2.y +
" " +
"L" +
np1.x +
"," +
np1.y;
}
return path;
}
_getOuterBounds() {
for (const region of BOX_MODEL_REGIONS) {
const quad = this._getOuterQuad(region);
if (!quad) {
// Invisible element such as a script tag.
break;
}
const { bottom, height, left, right, top, width, x, y } = quad.bounds;
if (width > 0 || height > 0) {
return { bottom, height, left, right, top, width, x, y };
}
}
return {
bottom: 0,
height: 0,
left: 0,
right: 0,
top: 0,
width: 0,
x: 0,
y: 0,
};
}
/**
* We only want to show guides for horizontal and vertical edges as this helps
* to line them up. This method finds these edges and displays a guide there.
* @param {String} region The region around which the guides should be shown.
*/
_showGuides(region) {
const quad = this._getOuterQuad(region);
if (!quad) {
// Invisible element such as a script tag.
return;
}
const { p1, p2, p3, p4 } = quad;
const allX = [p1.x, p2.x, p3.x, p4.x].sort((a, b) => a - b);
const allY = [p1.y, p2.y, p3.y, p4.y].sort((a, b) => a - b);
const toShowX = [];
const toShowY = [];
for (const arr of [allX, allY]) {
for (let i = 0; i < arr.length; i++) {
const val = arr[i];
if (i !== arr.lastIndexOf(val)) {
if (arr === allX) {
toShowX.push(val);
} else {
toShowY.push(val);
}
arr.splice(arr.lastIndexOf(val), 1);
}
}
}
// Move guide into place or hide it if no valid co-ordinate was found.
this._updateGuide("top", Math.round(toShowY[0]));
this._updateGuide("right", Math.round(toShowX[1]) - 1);
this._updateGuide("bottom", Math.round(toShowY[1] - 1));
this._updateGuide("left", Math.round(toShowX[0]));
}
_hideGuides() {
for (const side of BOX_MODEL_SIDES) {
this.getElement("guide-" + side).setAttribute("hidden", "true");
}
}
/**
* Move a guide to the appropriate position and display it. If no point is
* passed then the guide is hidden.
*
* @param {String} side
* The guide to update
* @param {Integer} point
* x or y co-ordinate. If this is undefined we hide the guide.
*/
_updateGuide(side, point = -1) {
const guide = this.getElement("guide-" + side);
if (point <= 0) {
guide.setAttribute("hidden", "true");
return false;
}
if (side === "top" || side === "bottom") {
guide.setAttribute("x1", "0");
guide.setAttribute("y1", point + "");
guide.setAttribute("x2", "100%");
guide.setAttribute("y2", point + "");
} else {
guide.setAttribute("x1", point + "");
guide.setAttribute("y1", "0");
guide.setAttribute("x2", point + "");
guide.setAttribute("y2", "100%");
}
guide.removeAttribute("hidden");
return true;
}
/**
* Move the Infobar to the right place in the highlighter.
*/
_moveInfobar() {
const bounds = this._getOuterBounds();
const container = this.getElement("infobar-container");
moveInfobar(container, bounds, this.iframe.contentWindow);
}
/**
* Update node information (displayName#id.class)
*/
_updateInfobar() {
if (!this.nodeData) {
return;
}
const {
classList,
displayName,
flexLayoutTextType,
gridLayoutTextType,
id,
pseudos,
zoom,
} = this.nodeData;
// We want to display the original `width` and `height`, instead of the ones affected
// by any zoom. Since the infobar can be displayed also for text nodes, we can't
// access the computed style for that, and this is why we recalculate them here.
const quad = this._getOuterQuad("border");
if (!quad) {
return;
}
const { width, height } = quad.bounds;
const dim =
parseFloat((width / zoom).toPrecision(6)) +
" \u00D7 " +
parseFloat((height / zoom).toPrecision(6));
this.getElement("infobar-tagname").setTextContent(displayName);
this.getElement("infobar-id").setTextContent(id);
this.getElement("infobar-classes").setTextContent(classList);
this.getElement("infobar-pseudo-classes").setTextContent(pseudos);
this.getElement("infobar-dimensions").setTextContent(dim);
this.getElement("infobar-grid-type").setTextContent(gridLayoutTextType);
this.getElement("infobar-flex-type").setTextContent(flexLayoutTextType);
this._moveInfobar();
}
/**
* @override
*/
_buildMarkup() {
const doc = this.win.document;
const highlighterContainer = doc.createElement("div");
highlighterContainer.setAttribute("role", "presentation");
highlighterContainer.className = "highlighter-container box-model";
// Build the root wrapper, used to adapt to the page zoom.
const rootWrapper = createNode(this.win, {
parent: highlighterContainer,
attributes: {
id: "root",
class: "root",
role: "presentation",
},
prefix: this.ID_CLASS_PREFIX,
});
// Building the nodeinfo bar markup
const infobarContainer = createNode(this.win, {
parent: rootWrapper,
attributes: {
class: "infobar-container",
id: "infobar-container",
position: "top",
hidden: "true",
},
prefix: this.ID_CLASS_PREFIX,
});
const infobar = createNode(this.win, {
parent: infobarContainer,
attributes: {
class: "infobar",
},
prefix: this.ID_CLASS_PREFIX,
});
const texthbox = createNode(this.win, {
parent: infobar,
attributes: {
class: "infobar-text",
},
prefix: this.ID_CLASS_PREFIX,
});
createNode(this.win, {
nodeType: "span",
parent: texthbox,
attributes: {
class: "infobar-tagname",
id: "infobar-tagname",
},
prefix: this.ID_CLASS_PREFIX,
});
createNode(this.win, {
nodeType: "span",
parent: texthbox,
attributes: {
class: "infobar-id",
id: "infobar-id",
},
prefix: this.ID_CLASS_PREFIX,
});
createNode(this.win, {
nodeType: "span",
parent: texthbox,
attributes: {
class: "infobar-classes",
id: "infobar-classes",
},
prefix: this.ID_CLASS_PREFIX,
});
createNode(this.win, {
nodeType: "span",
parent: texthbox,
attributes: {
class: "infobar-pseudo-classes",
id: "infobar-pseudo-classes",
},
prefix: this.ID_CLASS_PREFIX,
});
createNode(this.win, {
nodeType: "span",
parent: texthbox,
attributes: {
class: "infobar-dimensions",
id: "infobar-dimensions",
},
prefix: this.ID_CLASS_PREFIX,
});
createNode(this.win, {
nodeType: "span",
parent: texthbox,
attributes: {
class: "infobar-grid-type",
id: "infobar-grid-type",
},
prefix: this.ID_CLASS_PREFIX,
});
createNode(this.win, {
nodeType: "span",
parent: texthbox,
attributes: {
class: "infobar-flex-type",
id: "infobar-flex-type",
},
prefix: this.ID_CLASS_PREFIX,
});
// Building the SVG element with its polygons and lines
const svg = createSVGNode(this.win, {
nodeType: "svg",
parent: rootWrapper,
attributes: {
id: "elements",
width: "100%",
height: "100%",
hidden: "true",
role: "presentation",
},
prefix: this.ID_CLASS_PREFIX,
});
const regions = createSVGNode(this.win, {
nodeType: "g",
parent: svg,
attributes: {
class: "regions",
role: "presentation",
},
prefix: this.ID_CLASS_PREFIX,
});
for (const region of BOX_MODEL_REGIONS) {
createSVGNode(this.win, {
nodeType: "path",
parent: regions,
attributes: {
class: region,
id: region,
role: "presentation",
},
prefix: this.ID_CLASS_PREFIX,
});
}
for (const side of BOX_MODEL_SIDES) {
createSVGNode(this.win, {
nodeType: "line",
parent: svg,
attributes: {
class: "guide-" + side,
id: "guide-" + side,
"stroke-width": GUIDE_STROKE_WIDTH,
role: "presentation",
},
prefix: this.ID_CLASS_PREFIX,
});
}
return highlighterContainer;
}
}
exports.BoxModelHighlighterRenderer = BoxModelHighlighterRenderer;
/**
* Setup function that runs in parent process and sets up the rendering part of the
* box model highlighter and the communication channel with the observer part
* of the box model highlighter which lives in the content process.
*
*
* @param {Object} options.mm
* Message manager that corresponds to the current content tab.
* @param {String} options.prefix
* Unique prefix for message manager messages.
* This is the debugger-server-connection prefix.
* @return {Object}
* Defines event listeners for when client disconnects or browser gets
* swapped.
*/
function setupParentProcess({ mm, prefix }) {
let renderer = new BoxModelHighlighterRenderer(mm, prefix);
return {
onBrowserSwap: newMM => renderer.setMessageManager(newMM, prefix),
onDisconnected: () => {
renderer.destroy();
renderer = null;
},
};
}
exports.setupParentProcess = setupParentProcess;

View File

@ -101,7 +101,6 @@ class BoxModelHighlighter extends AutoRefreshHighlighter {
super(highlighterEnv);
this.ID_CLASS_PREFIX = "box-model-";
this.markup = new CanvasFrameAnonymousContentHelper(
this.highlighterEnv,
this._buildMarkup.bind(this)

View File

@ -0,0 +1,202 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Services = require("Services");
const {
HighlighterEnvironment,
} = require("devtools/server/actors/highlighters");
const {
CanvasFrameAnonymousContentHelper,
} = require("devtools/server/actors/highlighters/utils/markup");
/**
* HighlighterRenderer is the base class that implements the rendering surface for a
* highlighter in the parent process.
*
* It injects an iframe in the browser window which hosts the anonymous canvas
* frame where the highlighter's markup is generated and manipulated.
*
* This is the renderer part of a highlighter. It has a counterpart: the observer part of
* a highlighter which lives in the content process so it can observe changes to a node's
* position and attributes over time. The observer communicates any changes either through
* messages (via message manager) or directly to the renderer which updates the
* highlighter markup.
*
* NOTE: When the highlighter is used in the context of the browser toolbox, for example,
* when inspecting the browser UI, both observer and renderer live in the parent process
* and communication is done by direct reference, not using messages.
*
* Classes that extend HighlighterRenderer must implement:
* - a `typeName` string to identify the highighter type
* - a `_buildMarkup()` method to generate the highlighter markup;
* - a `render()` method to update the highlighter markup when given new information
* about the observed node.
*/
class HighlighterRenderer {
constructor() {
// The highlighter's type name. To be implemented by sub classes.
this.typeName = "";
this.onMessage = this.onMessage.bind(this);
}
/**
* Create an HTML iframe in order to use the anonymous canvas frame within it
* for hosting and manipulating the highlighter's markup.
*
* @param {Boolean} isBrowserToolboxHighlighter
* Whether the highlighter is used in the context of the
* browser toolbox (as opposed to the content toolbox).
* When set to true, this will influence where the
* iframe is appended so that it overlaps the browser UI
* (as opposed to overlapping just the page content).
*/
init(isBrowserToolboxHighlighter) {
// Get a reference to the parent process window.
this.win = Services.wm.getMostRecentBrowserWindow();
const { gBrowser } = this.win;
// Get a reference to the selected <browser> element.
const browser = gBrowser.selectedBrowser;
const browserContainer = gBrowser.getBrowserContainer(browser);
// The parent node of the iframe depends on the highlighter context:
// - browser toolbox: top-level browser window
// - content toolbox: host node of the <browser> element for the selected tab
const parent = isBrowserToolboxHighlighter
? this.win.document.documentElement
: browserContainer.querySelector(".browserStack");
// Grab the host iframe if it was previously created by another highlighter.
const iframe = parent.querySelector(
`:scope > .devtools-highlighter-renderer`
);
if (iframe) {
this.iframe = iframe;
this.setupMarkup();
} else {
this.iframe = this.win.document.createElement("iframe");
this.iframe.classList.add("devtools-highlighter-renderer");
if (isBrowserToolboxHighlighter) {
parent.append(this.iframe);
} else {
// Ensure highlighters are drawn underneath alerts and dialog boxes.
parent.querySelector("browser").after(this.iframe);
}
this.iframe.contentWindow.addEventListener(
"DOMContentLoaded",
this.setupMarkup.bind(this)
);
}
}
/**
* Generate the highlighter markup and insert it into the anoymous canvas frame.
*/
setupMarkup() {
if (!this.iframe || !this.iframe.contentWindow) {
throw Error(
"The highlighter renderer's host iframe is missing or not yet ready"
);
}
this.highlighterEnv = new HighlighterEnvironment();
this.highlighterEnv.initFromWindow(this.iframe.contentWindow);
this.markup = new CanvasFrameAnonymousContentHelper(
this.highlighterEnv,
this._buildMarkup.bind(this)
);
}
/**
* Set up message manager listener to listen for messages
* coming from the from the child process.
*
* @param {Object} mm
* Message manager that corresponds to the current content tab.
* @param {String} prefix
* Cross-process connection prefix.
*/
setMessageManager(mm, prefix) {
if (this.messageManager === mm) {
return;
}
// Message name used to distinguish between messages over the message manager.
this._msgName = `debug:${prefix}${this.typeName}`;
if (this.messageManager) {
// If the browser was swapped we need to reset the message manager.
const oldMM = this.messageManager;
oldMM.removeMessageListener(this._msgName, this.onMessage);
}
this.messageManager = mm;
if (mm) {
mm.addMessageListener(this._msgName, this.onMessage);
}
}
postMessage(topic, data = {}) {
this.messageManager.sendAsyncMessage(`${this._msgName}:event`, {
topic,
data,
});
}
/**
* Handler for messages coming from the content process.
*
* @param {Object} msg
* Data payload associated with the message.
*/
onMessage(msg) {
const { topic, data } = msg.json;
switch (topic) {
case "render":
this.render(data);
break;
case "destroy":
this.destroy();
break;
}
}
render() {
// When called, sub classes should update the highlighter.
// To be implemented by sub classes.
throw new Error(
"Highlighter renderer class had to implement render method"
);
}
destroy() {
if (this.highlighterEnv) {
this.highlighterEnv.destroy();
this.highlighterEnv = null;
}
if (this.markup) {
this.markup.destroy();
this.markup = null;
}
if (this.iframe) {
this.iframe.remove();
this.iframe = null;
}
this.win = null;
this.setMessageManager(null);
}
}
exports.HighlighterRenderer = HighlighterRenderer;

View File

@ -11,6 +11,8 @@ DIRS += [
DevToolsModules(
'accessible.js',
'auto-refresh.js',
'box-model-observer.js',
'box-model-renderer.js',
'box-model.js',
'css-grid.js',
'css-transform.js',
@ -18,6 +20,7 @@ DevToolsModules(
'flexbox.js',
'fonts.js',
'geometry-editor.js',
'highlighter-renderer.js',
'measuring-tool.js',
'paused-debugger.js',
'rulers.js',

View File

@ -304,15 +304,22 @@ class MainEventCollector {
}
isChromeHandler(handler) {
const handlerPrincipal = Cu.getObjectPrincipal(handler);
try {
const handlerPrincipal = Cu.getObjectPrincipal(handler);
// Chrome codebase may register listeners on the page from a frame script or
// JSM <video> tags may also report internal listeners, but they won't be
// coming from the system principal. Instead, they will be using an expanded
// principal.
return (
handlerPrincipal.isSystemPrincipal || handlerPrincipal.isExpandedPrincipal
);
// Chrome codebase may register listeners on the page from a frame script or
// JSM <video> tags may also report internal listeners, but they won't be
// coming from the system principal. Instead, they will be using an expanded
// principal.
return (
handlerPrincipal.isSystemPrincipal ||
handlerPrincipal.isExpandedPrincipal
);
} catch (e) {
// Anything from a dead object to a CSP error can leave us here so let's
// return false so that we can fail gracefully.
return false;
}
}
}

View File

@ -196,15 +196,21 @@ exports.InspectorActor = protocol.ActorClassWithSpec(inspectorSpec, {
*
* @param {Boolean} autohide Optionally autohide the highlighter after an
* element has been picked
* @param {Boolean} useNewBoxModelHighlighter Whether to use the new box model
* highlighter that has split renderer and observer parts.
* @return {HighlighterActor}
*/
getHighlighter: function(autohide) {
getHighlighter: function(autohide, useNewBoxModelHighlighter) {
if (this._highlighterPromise) {
return this._highlighterPromise;
}
this._highlighterPromise = this.getWalker().then(walker => {
const highlighter = HighlighterActor(this, autohide);
const highlighter = HighlighterActor(
this,
autohide,
useNewBoxModelHighlighter
);
this.manage(highlighter);
return highlighter;
});

View File

@ -30,7 +30,9 @@ const TELEMETRY_EYEDROPPER_OPENED_MENU =
const SHOW_ALL_ANONYMOUS_CONTENT_PREF =
"devtools.inspector.showAllAnonymousContent";
const SHOW_UA_SHADOW_ROOTS_PREF = "devtools.inspector.showUserAgentShadowRoots";
const FISSION_ENABLED = "devtools.browsertoolbox.fission";
const FISSION_ENABLED_PREF = "devtools.browsertoolbox.fission";
const USE_NEW_BOX_MODEL_HIGHLIGHTER_PREF =
"devtools.inspector.use-new-box-model-highlighter";
const telemetry = new Telemetry();
@ -531,7 +533,10 @@ class InspectorFront extends FrontClassWithSpec(inspectorSpec) {
async _getHighlighter() {
const autohide = !flags.testing;
this.highlighter = await this.getHighlighter(autohide);
this.highlighter = await this.getHighlighter(
autohide,
Services.prefs.getBoolPref(USE_NEW_BOX_MODEL_HIGHLIGHTER_PREF)
);
}
hasHighlighter(type) {
@ -604,7 +609,7 @@ class InspectorFront extends FrontClassWithSpec(inspectorSpec) {
* @return {Array} The list of InspectorFront instances.
*/
async getChildInspectors() {
const fissionEnabled = Services.prefs.getBoolPref(FISSION_ENABLED);
const fissionEnabled = Services.prefs.getBoolPref(FISSION_ENABLED_PREF);
const childInspectors = [];
const target = this.targetFront;
// this line can be removed when we are ready for fission frames

View File

@ -154,7 +154,12 @@ exports.getFrameOffsets = getFrameOffsets;
* An array of objects that have the same structure as quads returned by
* getBoxQuads. An empty array if the node has no quads or is invalid.
*/
function getAdjustedQuads(boundaryWindow, node, region, { ignoreZoom } = {}) {
function getAdjustedQuads(
boundaryWindow,
node,
region,
{ ignoreZoom, ignoreScroll } = {}
) {
if (!node || !node.getBoxQuads) {
return [];
}
@ -170,7 +175,9 @@ function getAdjustedQuads(boundaryWindow, node, region, { ignoreZoom } = {}) {
}
const scale = ignoreZoom ? 1 : getCurrentZoom(node);
const { scrollX, scrollY } = boundaryWindow;
const { scrollX, scrollY } = ignoreScroll
? { scrollX: 0, scrollY: 0 }
: boundaryWindow;
const xOffset = scrollX * scale;
const yOffset = scrollY * scale;

View File

@ -406,6 +406,7 @@ const inspectorSpec = generateActorSpec({
getHighlighter: {
request: {
autohide: Arg(0, "boolean"),
useNewBoxModelHighlighter: Arg(1, "nullable:boolean"),
},
response: {
highligter: RetVal("highlighter"),

View File

@ -130,11 +130,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(CallbackTimeoutHandler)
JSFunction* fun =
JS_GetObjectFunction(js::UncheckedUnwrapWithoutExpose(obj));
if (fun && JS_GetFunctionId(fun)) {
JSFlatString* funId = JS_ASSERT_STRING_IS_FLAT(JS_GetFunctionId(fun));
size_t size = 1 + JS_PutEscapedFlatString(nullptr, 0, funId, 0);
JSLinearString* funId = JS_ASSERT_STRING_IS_LINEAR(JS_GetFunctionId(fun));
size_t size = 1 + JS_PutEscapedLinearString(nullptr, 0, funId, 0);
char* funIdName = new char[size];
if (funIdName) {
JS_PutEscapedFlatString(funIdName, size, funId, 0);
JS_PutEscapedLinearString(funIdName, size, funId, 0);
name.AppendLiteral(" [");
name.Append(funIdName);
delete[] funIdName;

View File

@ -270,12 +270,12 @@ inline bool AssignJSString(JSContext* cx, T& dest, JSString* s) {
return js::CopyStringChars(cx, dest.BeginWriting(), s, len);
}
inline void AssignJSFlatString(nsAString& dest, JSFlatString* s) {
size_t len = js::GetFlatStringLength(s);
inline void AssignJSLinearString(nsAString& dest, JSLinearString* s) {
size_t len = js::GetLinearStringLength(s);
static_assert(js::MaxStringLength < (1 << 30),
"Shouldn't overflow here or in SetCapacity");
dest.SetLength(len);
js::CopyFlatStringChars(dest.BeginWriting(), s, len);
js::CopyLinearStringChars(dest.BeginWriting(), s, len);
}
class nsAutoJSString : public nsAutoString {

View File

@ -211,28 +211,16 @@
function recvDomTest(message) {
savedElement = message.objects.element;
is(savedElement.QueryInterface(Ci.nsISupports), savedElement,
"QI to nsISupports works");
function testNoInterface(savedElement, i) {
try {
savedElement.QueryInterface(i);
ok(false, "should have thrown an exception");
} catch (e) {
is(e.result, Cr.NS_ERROR_NO_INTERFACE, "threw the right exception");
}
}
testNoInterface(savedElement, Ci.nsIClassInfo);
is(savedElement.QueryInterface, undefined,
"Should not have a QueryInterface");
// Test to ensure that we don't pass CPOWs to C++-implemented interfaces.
// See bug 1072980.
if (test_state == "remote") {
// This doesn't work because we intercept toString and QueryInterface specially
// This doesn't work because we intercept toString specially
// and don't cache the function pointer.
// See bug 1140636.
todo_is(savedElement.toString, savedElement.toString, "toString identity works");
todo_is(savedElement.QueryInterface, savedElement.QueryInterface, "toString identity works");
is(Object.prototype.toString.call(savedElement), "[object HTMLDivElement]",
"prove that this works (and doesn't leak)");

View File

@ -1238,58 +1238,6 @@ bool InitIds(JSContext* cx, const NativeProperties* nativeProperties) {
#undef INIT_IDS_IF_DEFINED
bool QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp) {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
if (!args.thisv().isObject()) {
JS_ReportErrorASCII(cx, "QueryInterface called on incompatible non-object");
return false;
}
// Get the object. It might be a security wrapper, in which case we do a
// checked unwrap.
JS::Rooted<JSObject*> origObj(cx, &args.thisv().toObject());
JS::Rooted<JSObject*> obj(
cx, js::CheckedUnwrapDynamic(origObj, cx,
/* stopAtWindowProxy = */ false));
if (!obj) {
JS_ReportErrorASCII(cx, "Permission denied to access object");
return false;
}
nsCOMPtr<nsISupports> native = UnwrapDOMObjectToISupports(obj);
if (!native) {
return Throw(cx, NS_ERROR_FAILURE);
}
if (argc < 1) {
return Throw(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
}
Maybe<nsIID> iid = xpc::JSValue2ID(cx, args[0]);
if (!iid) {
return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
}
if (iid->Equals(NS_GET_IID(nsIClassInfo))) {
nsresult rv;
nsCOMPtr<nsIClassInfo> ci = do_QueryInterface(native, &rv);
if (NS_FAILED(rv)) {
return Throw(cx, rv);
}
return WrapObject(cx, ci, &NS_GET_IID(nsIClassInfo), args.rval());
}
nsCOMPtr<nsISupports> unused;
nsresult rv = native->QueryInterface(*iid, getter_AddRefs(unused));
if (NS_FAILED(rv)) {
return Throw(cx, rv);
}
args.rval().set(args.thisv());
return true;
}
void GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
nsWrapperCache* aCache, JS::Handle<JS::Value> aIID,
JS::MutableHandle<JS::Value> aRetval,

View File

@ -1765,17 +1765,6 @@ static inline bool AtomizeAndPinJSString(JSContext* cx, jsid& id,
bool InitIds(JSContext* cx, const NativeProperties* properties);
bool QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
template <class T>
struct WantsQueryInterface {
static_assert(IsBaseOf<nsISupports, T>::value,
"QueryInterface can't work without an nsISupports.");
static bool Enabled(JSContext* aCx, JSObject* aGlobal) {
return NS_IsMainThread() && IsChromeOrXBL(aCx, aGlobal);
}
};
void GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
nsWrapperCache* aCache, JS::Handle<JS::Value> aIID,
JS::MutableHandle<JS::Value> aRetval,

View File

@ -20,8 +20,7 @@ bool CallbackInterface::GetCallableProperty(
return false;
}
if (!aCallable.isObject() || !JS::IsCallable(&aCallable.toObject())) {
JS::RootedString propId(
cx, JS_FORGET_STRING_FLATNESS(JSID_TO_FLAT_STRING(aPropId)));
JS::RootedString propId(cx, JSID_TO_STRING(aPropId));
JS::UniqueChars propName = JS_EncodeStringToUTF8(cx, propId);
nsPrintfCString description("Property '%s'", propName.get());
ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get());

View File

@ -2344,36 +2344,6 @@ class MethodDefiner(PropertyDefiner):
self.chrome = []
self.regular = []
for m in methods:
if m.identifier.name == 'QueryInterface':
# QueryInterface is special, because instead of generating an
# impl we just call out directly to our shared one.
if m.isStatic():
raise TypeError("Legacy QueryInterface member shouldn't be static")
signatures = m.signatures()
if (len(signatures) > 1 or len(signatures[0][1]) > 1 or
not signatures[0][1][0].type.isAny()):
raise TypeError("There should be only one QueryInterface method with 1 argument of type any")
# Make sure to not stick QueryInterface on abstract interfaces.
if (not self.descriptor.interface.hasInterfacePrototypeObject() or
not self.descriptor.concrete):
raise TypeError("QueryInterface is only supported on "
"interfaces that are concrete: " +
self.descriptor.name)
if not isChromeOnly(m):
raise TypeError("QueryInterface must be ChromeOnly")
self.chrome.append({
"name": 'QueryInterface',
"methodInfo": False,
"length": 1,
"flags": "0",
"condition": PropertyDefiner.getControllingCondition(m, descriptor)
})
continue
method = self.methodData(m, descriptor)
if m.isStatic():
@ -11836,7 +11806,7 @@ def missingPropUseCountersForDescriptor(desc):
# We're down to one string: just check whether we match it.
return fill(
"""
if (JS_FlatStringEqualsLiteral(str, "${name}")) {
if (JS_LinearStringEqualsLiteral(str, "${name}")) {
counter.emplace(eUseCounter_${iface}_${name});
}
""",
@ -11846,7 +11816,7 @@ def missingPropUseCountersForDescriptor(desc):
switch = dict()
if charIndex == 0:
switch['precondition'] = \
'StringIdChars chars(nogc, js::FlatStringToLinearString(str));\n'
'StringIdChars chars(nogc, str);\n'
else:
switch['precondition'] = ""
@ -11874,7 +11844,7 @@ def missingPropUseCountersForDescriptor(desc):
return switch
lengths = set(len(prop[1]) for prop in instrumentedProps)
switchDesc = { 'condition': 'js::GetFlatStringLength(str)',
switchDesc = { 'condition': 'js::GetLinearStringLength(str)',
'precondition': '' }
switchDesc['cases'] = dict()
for length in sorted(lengths):
@ -11890,7 +11860,7 @@ def missingPropUseCountersForDescriptor(desc):
{
// Scope for our no-GC section, so we don't need to rely on SetUseCounter not GCing.
JS::AutoCheckCannotGC nogc;
JSFlatString* str = js::AtomToFlatString(JSID_TO_ATOM(id));
JSLinearString* str = js::AtomToLinearString(JSID_TO_ATOM(id));
// Don't waste time fetching the chars until we've done the length switch.
$*{switch}
}
@ -14536,11 +14506,11 @@ class CGGlobalNames(CGGeneric):
phfCodegen = phf.codegen('WebIDLGlobalNameHash::sEntries',
'WebIDLNameTableEntry')
entries = phfCodegen.gen_entries(lambda e: e[1])
getter = phfCodegen.gen_jsflatstr_getter(
getter = phfCodegen.gen_jslinearstr_getter(
name='WebIDLGlobalNameHash::GetEntry',
return_type='const WebIDLNameTableEntry*',
return_entry=dedent("""
if (JS_FlatStringEqualsAscii(aKey, sNames + entry.mNameOffset, entry.mNameLength)) {
if (JS_LinearStringEqualsAscii(aKey, sNames + entry.mNameOffset, entry.mNameLength)) {
return &entry;
}
return nullptr;

View File

@ -58,17 +58,12 @@ class Configuration(DescriptorProvider):
# different .webidl file than their LHS interface. Make sure we
# don't have any of those. See similar block below for partial
# interfaces!
#
# But whitelist a RHS that is LegacyQueryInterface,
# since people shouldn't be adding any of those.
if (thing.interface.filename() != thing.filename() and
thing.mixin.identifier.name != "LegacyQueryInterface"):
if (thing.interface.filename() != thing.filename()):
raise TypeError(
"The binding build system doesn't really support "
"'includes' statements which don't appear in the "
"file in which the left-hand side of the statement is "
"defined. Don't do this unless your right-hand side "
"is LegacyQueryInterface.\n"
"defined.\n"
"%s\n"
"%s" %
(thing.location, thing.interface.location))

View File

@ -62,9 +62,7 @@ bool WebIDLGlobalNameHash::DefineIfEnabled(
JS::MutableHandle<JS::PropertyDescriptor> aDesc, bool* aFound) {
MOZ_ASSERT(JSID_IS_STRING(aId), "Check for string id before calling this!");
const WebIDLNameTableEntry* entry;
{ entry = GetEntry(JSID_TO_FLAT_STRING(aId)); }
const WebIDLNameTableEntry* entry = GetEntry(JSID_TO_LINEAR_STRING(aId));
if (!entry) {
*aFound = false;
return true;
@ -175,7 +173,7 @@ bool WebIDLGlobalNameHash::DefineIfEnabled(
/* static */
bool WebIDLGlobalNameHash::MayResolve(jsid aId) {
return GetEntry(JSID_TO_FLAT_STRING(aId)) != nullptr;
return GetEntry(JSID_TO_LINEAR_STRING(aId)) != nullptr;
}
/* static */
@ -228,7 +226,7 @@ bool WebIDLGlobalNameHash::ResolveForSystemGlobal(JSContext* aCx,
MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(aObj), "Xrays not supported!");
// Look up the corresponding entry in the name table, and resolve if enabled.
const WebIDLNameTableEntry* entry = GetEntry(JSID_TO_FLAT_STRING(aId));
const WebIDLNameTableEntry* entry = GetEntry(JSID_TO_LINEAR_STRING(aId));
if (entry && (!entry->mEnabled || entry->mEnabled(aCx, aObj))) {
if (NS_WARN_IF(!GetPerInterfaceObjectHandle(
aCx, entry->mConstructorId, entry->mCreate,

View File

@ -11,7 +11,7 @@
#include "nsTArray.h"
#include "mozilla/dom/BindingDeclarations.h"
class JSFlatString;
class JSLinearString;
namespace mozilla {
namespace dom {
@ -77,7 +77,7 @@ class WebIDLGlobalNameHash {
// Look up an entry by key name. `nullptr` if the entry was not found.
// The impl of GetEntry is generated by Codegen.py in RegisterBindings.cpp
static const WebIDLNameTableEntry* GetEntry(JSFlatString* aKey);
static const WebIDLNameTableEntry* GetEntry(JSLinearString* aKey);
// The total number of names in the hash.
// The value of sCount is generated by Codegen.py in RegisterBindings.cpp.

View File

@ -45,7 +45,6 @@ tags = webrtc
[test_named_getter_enumerability.html]
[test_Object.prototype_props.html]
[test_proxy_expandos.html]
[test_queryInterface.html]
[test_returnUnion.html]
skip-if = debug == false
[test_usvstring.html]

View File

@ -1,41 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=827546
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 827546</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 827546 **/
var notImage = document.createElement("div");
var thrown;
try {
thrown = false;
SpecialPowers.do_QueryInterface(notImage, "nsIImageLoadingContent");
} catch (e) {
thrown = true;
}
ok(thrown,
"QI to nsIImageLoadingContent on a non-image element should fail");
var image = document.createElement("img");
ok(SpecialPowers.do_QueryInterface(image, "nsIImageLoadingContent"),
"Image element needs to support QI to nsIImageLoadingContent");
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=827546">Mozilla Bug 827546</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -209,9 +209,9 @@ void FileReader::OnLoadEndArrayBuffer() {
}
nsAutoString errorName;
JSFlatString* name = js::GetErrorTypeName(cx, er->exnType);
JSLinearString* name = js::GetErrorTypeName(cx, er->exnType);
if (name) {
AssignJSFlatString(errorName, name);
AssignJSLinearString(errorName, name);
}
nsAutoCString errorMsg(er->message().c_str());

View File

@ -0,0 +1,427 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gtest/gtest.h"
#include "mozilla/dom/SimpleGlobalObject.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/indexedDB/Key.h"
#include "jsapi.h"
#include "js/ArrayBuffer.h"
// TODO: This PrintTo overload is defined in dom/media/gtest/TestGroupId.cpp.
// However, it is not used, probably because of
// https://stackoverflow.com/a/36941270
void PrintTo(const nsString& value, std::ostream* os);
using namespace mozilla;
using namespace mozilla::dom::indexedDB;
// DOM_IndexedDB_Key_Ctor tests test the construction of a Key, and check the
// properties of the constructed key with the const methods afterwards. The
// tested ctors include the default ctor, which constructs an unset key, and the
// ctors that accepts an encoded buffer, which is then decoded using the
// Key::To* method corresponding to its type.
//
// So far, only some cases are tested:
// - scalar binary
// -- empty
// -- with 1-byte encoded representation
// - scalar string
// -- empty
// -- with 1-byte encoded representation
//
// TODO More test cases should be added, including
// - empty (?)
// - scalar binary
// -- containing 0 byte(s)
// -- with 2-byte encoded representation
// - scalar string
// -- with 2-byte and 3-byte encoded representation
// - scalar number
// - scalar date
// - arrays, incl. nested arrays, with various combinations of contained types
TEST(DOM_IndexedDB_Key, Ctor_Default)
{
auto key = Key{};
EXPECT_TRUE(key.IsUnset());
}
// TODO does such a helper function already exist?
template <size_t N>
static auto BufferAsCString(const uint8_t (&aBuffer)[N]) {
return nsCString{reinterpret_cast<const char*>(
static_cast<std::decay_t<const uint8_t[]>>(aBuffer)),
N};
}
#if 0
static void ExpectKeyIsBinary(const Key& aKey) {
EXPECT_FALSE(aKey.IsUnset());
EXPECT_FALSE(aKey.IsArray());
EXPECT_TRUE(aKey.IsBinary());
EXPECT_FALSE(aKey.IsDate());
EXPECT_FALSE(aKey.IsFloat());
EXPECT_FALSE(aKey.IsString());
}
#endif
static void ExpectKeyIsString(const Key& aKey) {
EXPECT_FALSE(aKey.IsUnset());
EXPECT_FALSE(aKey.IsArray());
EXPECT_FALSE(aKey.IsBinary());
EXPECT_FALSE(aKey.IsDate());
EXPECT_FALSE(aKey.IsFloat());
EXPECT_TRUE(aKey.IsString());
}
#if 0
static void ExpectKeyIsArray(const Key& aKey) {
EXPECT_FALSE(aKey.IsUnset());
EXPECT_TRUE(aKey.IsArray());
EXPECT_FALSE(aKey.IsBinary());
EXPECT_FALSE(aKey.IsDate());
EXPECT_FALSE(aKey.IsFloat());
EXPECT_FALSE(aKey.IsString());
}
#endif
#if 0
static JSObject& ExpectArrayBufferObject(const JS::Value& aValue) {
EXPECT_TRUE(aValue.isObject());
auto& object = aValue.toObject();
EXPECT_TRUE(JS::IsArrayBufferObject(&object));
return object;
}
static JSObject& ExpectArrayObject(JSContext* const aContext,
const JS::Heap<JS::Value>& aValue) {
EXPECT_TRUE(aValue.get().isObject());
auto&& value = JS::RootedValue(aContext, aValue.get());
bool rv;
EXPECT_TRUE(JS_IsArrayObject(aContext, value, &rv));
EXPECT_TRUE(rv);
return value.toObject();
}
static void CheckArrayBuffer(const nsCString& aExpected,
const JS::Value& aActual) {
auto& obj = ExpectArrayBufferObject(aActual);
uint32_t length;
bool isSharedMemory;
uint8_t* data;
JS::GetArrayBufferLengthAndData(&obj, &length, &isSharedMemory, &data);
EXPECT_EQ(aExpected.Length(), length);
EXPECT_EQ(0, memcmp(aExpected.get(), data, length));
}
static void CheckString(JSContext* const aContext, const nsString& aExpected,
const JS::Value& aActual) {
EXPECT_TRUE(aActual.isString());
int32_t rv;
EXPECT_TRUE(JS_CompareStrings(aContext,
JS_NewUCStringCopyZ(aContext, aExpected.get()),
aActual.toString(), &rv));
EXPECT_EQ(0, rv);
}
#endif
namespace {
// TODO Using AutoTestJSContext causes rooting hazards. Disabling for now.
// See https://phabricator.services.mozilla.com/D38360#inline-272833
#if 0
// TODO cf. AutoJSContext, which doesn't work here. Should it?
// This is modeled after dom/base/test/gtest/TestContentUtils.cpp
struct AutoTestJSContext {
AutoTestJSContext()
: mGlobalObject{mozilla::dom::SimpleGlobalObject::Create(
mozilla::dom::SimpleGlobalObject::GlobalType::BindingDetail)} {
EXPECT_TRUE(mJsAPI.Init(mGlobalObject));
mContext = mJsAPI.cx();
}
operator JSContext*() { return mContext; }
private:
JSObject* mGlobalObject;
mozilla::dom::AutoJSAPI mJsAPI;
JSContext* mContext;
};
#endif
// The following classes serve as base classes for the parametrized tests below.
// The name of each class reflects the parameter type.
class TestWithParam_CString_ArrayBuffer_Pair
: public ::testing::TestWithParam<std::pair<nsCString, nsLiteralCString>> {
};
class TestWithParam_CString_String_Pair
: public ::testing::TestWithParam<std::pair<nsCString, nsLiteralString>> {};
class TestWithParam_LiteralString
: public ::testing::TestWithParam<nsLiteralString> {};
class TestWithParam_StringArray
: public ::testing::TestWithParam<std::vector<nsString>> {};
class TestWithParam_ArrayBufferArray
: public ::testing::TestWithParam<std::vector<nsCString>> {};
} // namespace
#if 0
TEST_P(TestWithParam_CString_ArrayBuffer_Pair, Ctor_EncodedBinary) {
const auto key = Key{GetParam().first};
ExpectKeyIsBinary(key);
AutoTestJSContext context;
JS::Heap<JS::Value> rv;
EXPECT_EQ(NS_OK, key.ToJSVal(context, rv));
CheckArrayBuffer(GetParam().second, rv);
}
static const uint8_t zeroLengthBinaryEncodedBuffer[] = {Key::eBinary};
static const uint8_t nonZeroLengthBinaryEncodedBuffer[] = {Key::eBinary,
'a' + 1, 'b' + 1};
INSTANTIATE_TEST_CASE_P(
DOM_IndexedDB_Key, TestWithParam_CString_ArrayBuffer_Pair,
::testing::Values(
std::make_pair(BufferAsCString(zeroLengthBinaryEncodedBuffer),
NS_LITERAL_CSTRING("")),
std::make_pair(BufferAsCString(nonZeroLengthBinaryEncodedBuffer),
NS_LITERAL_CSTRING("ab"))));
#endif
TEST_P(TestWithParam_CString_String_Pair, Ctor_EncodedString) {
const auto key = Key{GetParam().first};
ExpectKeyIsString(key);
nsString rv;
key.ToString(rv);
EXPECT_EQ(GetParam().second, rv);
}
static const uint8_t zeroLengthStringEncodedBuffer[] = {Key::eString};
static const uint8_t nonZeroLengthStringEncodedBuffer[] = {Key::eString,
'a' + 1, 'b' + 1};
INSTANTIATE_TEST_CASE_P(
DOM_IndexedDB_Key, TestWithParam_CString_String_Pair,
::testing::Values(
std::make_pair(BufferAsCString(zeroLengthStringEncodedBuffer),
NS_LITERAL_STRING("")),
std::make_pair(BufferAsCString(nonZeroLengthStringEncodedBuffer),
NS_LITERAL_STRING("ab"))));
TEST_P(TestWithParam_LiteralString, SetFromString) {
auto key = Key{};
mozilla::ErrorResult error;
const auto result = key.SetFromString(GetParam(), error);
EXPECT_FALSE(error.Failed());
EXPECT_TRUE(result.Is(mozilla::dom::indexedDB::Ok, error));
ExpectKeyIsString(key);
nsString rv;
key.ToString(rv);
EXPECT_EQ(GetParam(), rv);
}
INSTANTIATE_TEST_CASE_P(DOM_IndexedDB_Key, TestWithParam_LiteralString,
::testing::Values(NS_LITERAL_STRING(""),
NS_LITERAL_STRING(u"abc"),
NS_LITERAL_STRING(u"\u007f"),
NS_LITERAL_STRING(u"\u0080"),
NS_LITERAL_STRING(u"\u1fff"),
NS_LITERAL_STRING(u"\u7fff"),
NS_LITERAL_STRING(u"\u8000"),
NS_LITERAL_STRING(u"\uffff")));
#if 0
static JS::RootedValue CreateArrayBufferValue(JSContext* const aContext,
const size_t aSize,
char* const aData) {
auto&& arrayBuffer = JS::RootedObject{
aContext, JS::NewArrayBufferWithContents(aContext, aSize, aData)};
return {aContext, JS::ObjectValue(*arrayBuffer)};
}
// This tests calling SetFromJSVal with an ArrayBuffer scalar of length 0.
// TODO Probably there should be more test cases for SetFromJSVal with other
// ArrayBuffer scalars, which convert this into a parametrized test as well.
TEST(DOM_IndexedDB_Key, SetFromJSVal_ZeroLengthArrayBuffer)
{
AutoTestJSContext context;
auto key = Key{};
auto&& arrayBuffer = CreateArrayBufferValue(context, 0, nullptr);
auto rv1 = mozilla::ErrorResult{};
const auto result = key.SetFromJSVal(context, arrayBuffer, rv1);
EXPECT_FALSE(rv1.Failed());
EXPECT_TRUE(result.Is(mozilla::dom::indexedDB::Ok, rv1));
ExpectKeyIsBinary(key);
JS::Heap<JS::Value> rv2;
EXPECT_EQ(NS_OK, key.ToJSVal(context, rv2));
CheckArrayBuffer(NS_LITERAL_CSTRING(""), rv2);
}
template <typename CheckElement>
static void CheckArray(JSContext* const context,
const JS::Heap<JS::Value>& arrayValue,
const size_t expectedLength,
const CheckElement& checkElement) {
auto&& actualArray =
JS::RootedObject(context, &ExpectArrayObject(context, arrayValue));
uint32_t actualLength;
EXPECT_TRUE(JS_GetArrayLength(context, actualArray, &actualLength));
EXPECT_EQ(expectedLength, actualLength);
for (size_t i = 0; i < expectedLength; ++i) {
JS::RootedValue element(static_cast<JSContext*>(context));
EXPECT_TRUE(JS_GetElement(context, actualArray, i, &element));
checkElement(i, element);
}
}
static JS::RootedValue CreateArrayBufferArray(
JSContext* const context, const std::vector<nsCString>& elements) {
auto* const array = JS_NewArrayObject(context, elements.size());
auto&& arrayObject = JS::RootedObject{context, array};
for (size_t i = 0; i < elements.size(); ++i) {
// TODO strdup only works if the element is actually 0-terminated
auto&& arrayBuffer = CreateArrayBufferValue(
context, elements[i].Length(),
elements[i].Length() ? strdup(elements[i].get()) : nullptr);
EXPECT_TRUE(JS_SetElement(context, arrayObject, i, arrayBuffer));
}
return {context, JS::ObjectValue(*array)};
}
TEST_P(TestWithParam_ArrayBufferArray, SetFromJSVal) {
const auto& elements = GetParam();
AutoTestJSContext context;
auto&& arrayValue = CreateArrayBufferArray(context, elements);
auto rv1 = mozilla::ErrorResult{};
auto key = Key{};
const auto result = key.SetFromJSVal(context, arrayValue, rv1);
EXPECT_FALSE(rv1.Failed());
EXPECT_TRUE(result.Is(mozilla::dom::indexedDB::Ok, rv1));
ExpectKeyIsArray(key);
JS::Heap<JS::Value> rv2;
EXPECT_EQ(NS_OK, key.ToJSVal(context, rv2));
CheckArray(context, rv2, elements.size(),
[&elements](const size_t i, const JS::HandleValue& element) {
CheckArrayBuffer(elements[i], element);
});
}
const uint8_t element2[] = "foo";
INSTANTIATE_TEST_CASE_P(
DOM_IndexedDB_Key, TestWithParam_ArrayBufferArray,
testing::Values(std::vector<nsCString>{},
std::vector<nsCString>{NS_LITERAL_CSTRING("")},
std::vector<nsCString>{NS_LITERAL_CSTRING(""),
BufferAsCString(element2)}));
static JS::RootedValue CreateStringValue(JSContext* const context,
const nsString& string) {
return {context, JS::StringValue(JS_NewUCStringCopyZ(context, string.get()))};
}
static JS::RootedValue CreateStringArray(
JSContext* const context, const std::vector<nsString>& elements) {
auto* const array = JS_NewArrayObject(context, elements.size());
auto&& arrayObject = JS::RootedObject{context, array};
for (size_t i = 0; i < elements.size(); ++i) {
auto&& string = CreateStringValue(context, elements[i]);
EXPECT_TRUE(JS_SetElement(context, arrayObject, i, string));
}
return {context, JS::ObjectValue(*array)};
}
TEST_P(TestWithParam_StringArray, SetFromJSVal) {
const auto& elements = GetParam();
AutoTestJSContext context;
auto&& arrayValue = CreateStringArray(context, elements);
auto rv1 = mozilla::ErrorResult{};
auto key = Key{};
const auto result = key.SetFromJSVal(context, arrayValue, rv1);
EXPECT_FALSE(rv1.Failed());
EXPECT_TRUE(result.Is(mozilla::dom::indexedDB::Ok, rv1));
ExpectKeyIsArray(key);
JS::Heap<JS::Value> rv2;
EXPECT_EQ(NS_OK, key.ToJSVal(context, rv2));
CheckArray(
context, rv2, elements.size(),
[&elements, &context](const size_t i, const JS::HandleValue& element) {
CheckString(context, elements[i], element);
});
}
INSTANTIATE_TEST_CASE_P(
DOM_IndexedDB_Key, TestWithParam_StringArray,
testing::Values(std::vector<nsString>{NS_LITERAL_STRING(""),
NS_LITERAL_STRING("abc\u0080\u1fff")},
std::vector<nsString>{
NS_LITERAL_STRING("abc\u0080\u1fff"),
NS_LITERAL_STRING("abc\u0080\u1fff")}));
TEST(DOM_IndexedDB_Key, CompareKeys_NonZeroLengthArrayBuffer)
{
AutoTestJSContext context;
const char buf[] = "abc\x80";
auto first = Key{};
auto rv1 = mozilla::ErrorResult{};
auto&& arrayBuffer1 =
CreateArrayBufferValue(context, sizeof buf, strdup(buf));
const auto result1 = first.SetFromJSVal(context, arrayBuffer1, rv1);
EXPECT_FALSE(rv1.Failed());
EXPECT_TRUE(result1.Is(mozilla::dom::indexedDB::Ok, rv1));
auto second = Key{};
auto rv2 = mozilla::ErrorResult{};
auto&& arrayBuffer2 =
CreateArrayBufferValue(context, sizeof buf, strdup(buf));
const auto result2 = second.SetFromJSVal(context, arrayBuffer2, rv2);
EXPECT_FALSE(rv2.Failed());
EXPECT_TRUE(result2.Is(mozilla::dom::indexedDB::Ok, rv2));
EXPECT_EQ(0, Key::CompareKeys(first, second));
}
#endif

View File

@ -6,6 +6,12 @@ UNIFIED_SOURCES = [
'TestIDBResult.cpp',
]
# not UNIFIED_SOURCES because TestKey.cpp has classes in an anonymous namespace
# which result in a GCC error when used in tests, cf. gfx/tests/gtest/moz.build
SOURCES = [
'TestKey.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul-gtest'

View File

@ -71,8 +71,14 @@
// eslint-disable-next-line no-eval
let message = eval(event.data);
is(message.source, "iframe", "Good source");
is(message.result, testData[testIndex].expectedResult, "Good result");
// TODO: This is an ad-hoc solution to get a useful assertion message.
// It would be desirable that the test framework provides the ability
// to capture context information and provide it on assertion failures,
// automatically stringified.
let testContext = `testData[${testIndex}] == ${JSON.stringify(testData[testIndex])}`;
is(message.source, "iframe", `Good source for ${testContext}`);
is(message.result, testData[testIndex].expectedResult, `Good result for ${testContext}`);
openedWindow.close();

View File

@ -97,6 +97,7 @@
#include "mozilla/WebBrowserPersistDocumentChild.h"
#include "mozilla/HangDetails.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/UnderrunHandler.h"
#include "nsIChildProcessChannelListener.h"
#include "mozilla/net/HttpChannelChild.h"
#include "nsQueryObject.h"
@ -108,6 +109,7 @@
#include "nsGeolocation.h"
#include "audio_thread_priority.h"
#include "nsIConsoleService.h"
#include "audio_thread_priority.h"
#if !defined(XP_WIN)
# include "mozilla/Omnijar.h"
@ -1776,14 +1778,14 @@ mozilla::ipc::IPCResult ContentChild::RecvSetProcessSandbox(
sandboxEnabled = false;
} else {
// Pre-start audio before sandboxing; see bug 1443612.
if (!Preferences::GetBool("media.cubeb.sandbox")) {
if (Preferences::GetBool("media.cubeb.sandbox")) {
if (atp_set_real_time_limit(0, 48000)) {
NS_WARNING("could not set real-time limit at process startup");
}
InstallSoftRealTimeLimitHandler();
} else {
Unused << CubebUtils::GetCubebContext();
}
# if defined(XP_LINUX)
else {
CubebUtils::InitAudioThreads();
}
# endif
}
if (sandboxEnabled) {

View File

@ -19,6 +19,7 @@
#include "CubebUtils.h"
#include "nsPrintfCString.h"
#include "AudioConverter.h"
#include "UnderrunHandler.h"
#if defined(XP_WIN)
# include "nsXULAppAPI.h"
#endif
@ -566,6 +567,10 @@ long AudioStream::DataCallback(void* aBuffer, long aFrames) {
MonitorAutoLock mon(mMonitor);
MOZ_ASSERT(mState != SHUTDOWN, "No data callback after shutdown");
if (SoftRealTimeLimitReached()) {
DemoteThreadFromRealTime();
}
auto writer = AudioBufferWriter(
MakeSpan<AudioDataValue>(reinterpret_cast<AudioDataValue*>(aBuffer),
mOutChannels * aFrames),

View File

@ -81,9 +81,6 @@ extern void audioipc_server_stop(void*);
// These functions are provided by audioipc-client crate
extern int audioipc_client_init(cubeb**, const char*,
const AudioIpcInitParams*);
#ifdef XP_LINUX
extern void audioipc_init_threads(const AudioIpcInitParams*);
#endif
}
namespace mozilla {
@ -445,18 +442,6 @@ ipc::FileDescriptor CreateAudioIPCConnection() {
#endif
}
#if defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID)
void InitAudioThreads() {
AudioIpcInitParams initParams;
initParams.mPoolSize = sAudioIPCPoolSize;
initParams.mStackSize = sAudioIPCStackSize;
initParams.mThreadCreateCallback = [](const char* aName) {
PROFILER_REGISTER_THREAD(aName);
};
audioipc_init_threads(&initParams);
}
#endif
cubeb* GetCubebContextUnlocked() {
sMutex.AssertCurrentThreadOwns();
if (sCubebForceNullContext) {

View File

@ -23,9 +23,6 @@ typedef cubeb_devid AudioDeviceID;
// Initialize Audio Library. Some Audio backends require initializing the
// library before using it.
void InitLibrary();
# ifdef XP_LINUX
void InitAudioThreads();
# endif
// Shutdown Audio Library. Some Audio backends require shutting down the
// library after using it.

View File

@ -898,6 +898,18 @@ long AudioCallbackDriver::DataCallback(const AudioDataValue* aInputBuffer,
GraphImpl()->NotifyOutputData(aOutputBuffer, static_cast<size_t>(aFrames),
mSampleRate, mOutputChannels);
#ifdef XP_MACOSX
// This only happens when the output is on a macbookpro's external speaker,
// that are stereo, but let's just be safe.
if (mNeedsPanning && mOutputChannels == 2) {
// hard pan to the right
for (uint32_t i = 0; i < aFrames * 2; i += 2) {
aOutputBuffer[i + 1] += aOutputBuffer[i];
aOutputBuffer[i] = 0.0;
}
}
#endif
if (!stillProcessing) {
// About to hand over control of the graph. Do not start a new driver if
// StateCallback() receives an error for this stream while the main thread
@ -1013,19 +1025,12 @@ void AudioCallbackDriver::PanOutputIfNeeded(bool aMicrophoneActive) {
// Check if we are currently outputing sound on external speakers.
if (!strcmp(out->output_name, "ispk")) {
// Pan everything to the right speaker.
if (aMicrophoneActive) {
if (cubeb_stream_set_panning(mAudioStream, 1.0) != CUBEB_OK) {
NS_WARNING("Could not pan audio output to the right.");
}
} else {
if (cubeb_stream_set_panning(mAudioStream, 0.0) != CUBEB_OK) {
NS_WARNING("Could not pan audio output to the center.");
}
}
LOG(LogLevel::Debug, ("Using the built-in speakers, with%s audio input",
aMicrophoneActive ? "" : "out"));
mNeedsPanning = aMicrophoneActive;
} else {
if (cubeb_stream_set_panning(mAudioStream, 0.0) != CUBEB_OK) {
NS_WARNING("Could not pan audio output to the center.");
}
LOG(LogLevel::Debug, ("Using an external output device"));
mNeedsPanning = false;
}
cubeb_stream_device_destroy(mAudioStream, out);
}
@ -1040,7 +1045,12 @@ void AudioCallbackDriver::DeviceChangedCallback() {
MonitorAutoLock mon(mGraphImpl->GetMonitor());
GraphImpl()->DeviceChanged();
#ifdef XP_MACOSX
PanOutputIfNeeded(mInputChannelCount);
RefPtr<AudioCallbackDriver> self(this);
bool hasInput = mInputChannelCount;
NS_DispatchToBackgroundThread(NS_NewRunnableFunction(
"PanOutputIfNeeded", [self{std::move(self)}, hasInput]() {
self->PanOutputIfNeeded(hasInput);
}));
#endif
}

View File

@ -534,6 +534,12 @@ class AudioCallbackDriver : public GraphDriver,
/* True if this driver was created from a driver created because of a previous
* AudioCallbackDriver failure. */
bool mFromFallback;
#ifdef XP_MACOSX
/* When using the built-in speakers on macbook pro (13 and 15, all models),
* it's best to hard pan the audio on the right, to avoid feedback into the
* microphone that is located next to the left speaker. */
Atomic<bool> mNeedsPanning;
#endif
};
class AsyncCubebTask : public Runnable {

View File

@ -34,6 +34,7 @@
#include "VideoUtils.h"
#include "GraphRunner.h"
#include "Tracing.h"
#include "UnderrunHandler.h"
#include "webaudio/blink/DenormalDisabler.h"
#include "webaudio/blink/HRTFDatabaseLoader.h"
@ -1297,6 +1298,10 @@ bool MediaTrackGraphImpl::OneIteration(GraphTime aStateEnd) {
bool MediaTrackGraphImpl::OneIterationImpl(GraphTime aStateEnd) {
TRACE_AUDIO_CALLBACK();
if (SoftRealTimeLimitReached()) {
DemoteThreadFromRealTime();
}
// Changes to LIFECYCLE_RUNNING occur before starting or reviving the graph
// thread, and so the monitor need not be held to check mLifecycleState.
// LIFECYCLE_THREAD_NOT_STARTED is possible when shutting down offline

View File

@ -0,0 +1,22 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_UNDERRUNHANDLER_H_
#define MOZILLA_UNDERRUNHANDLER_H_
namespace mozilla {
// Install an handler on SIGXPCU for the calling thread, that calls
// `UnderrunHandler` when the soft real-time limit has been reached. If a
// handler was already in place, this does nothing. No-op if not on Linux
// Desktop.
void InstallSoftRealTimeLimitHandler();
// Query whether or not the soft-real-time limit has been reached. Always
// false when not on Linux desktop. Can be called from any thread.
bool SoftRealTimeLimitReached();
// Set the calling thread to a normal scheduling class.
void DemoteThreadFromRealTime();
} // namespace mozilla
#endif // MOZILLA_UNDERRUNHANDLER_H_

View File

@ -0,0 +1,77 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <csignal>
#include <cerrno>
#include <pthread.h>
#include <mozilla/Sprintf.h>
#include <mozilla/Atomics.h>
#include "audio_thread_priority.h"
namespace mozilla {
Atomic<bool, MemoryOrdering::ReleaseAcquire> gRealtimeLimitReached;
void UnderrunHandler(int signum) { gRealtimeLimitReached = true; }
bool SoftRealTimeLimitReached() { return gRealtimeLimitReached; }
void InstallSoftRealTimeLimitHandler() {
struct sigaction action, previous;
action.sa_handler = UnderrunHandler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
int rv = sigaction(SIGXCPU, &action, &previous);
if (rv != 0) {
char buf[256];
SprintfLiteral(buf, "sigaction(SIGXCPU, ...): %s", strerror(errno));
NS_WARNING(buf);
return;
}
void* previous_handler = previous.sa_flags == SA_SIGINFO
? reinterpret_cast<void*>(previous.sa_sigaction)
: reinterpret_cast<void*>(previous.sa_handler);
MOZ_ASSERT(previous_handler != UnderrunHandler,
"Only install the SIGXCPU handler once per process.");
if (previous_handler != SIG_DFL && previous_handler != UnderrunHandler) {
NS_WARNING(
"SIGXCPU handler was already set by something else, dropping real-time "
"priority.");
rv = sigaction(SIGXCPU, &previous, nullptr);
if (rv != 0) {
NS_WARNING("Could not restore previous handler for SIGXCPU.");
}
gRealtimeLimitReached = true;
return;
}
gRealtimeLimitReached = false;
}
void DemoteThreadFromRealTime() {
atp_thread_info* info = atp_get_current_thread_info();
if (!info) {
NS_WARNING("Could not get current thread info when demoting thread.");
return;
}
int rv = atp_demote_thread_from_real_time(info);
if (rv) {
NS_WARNING("Could not demote thread from real-time.");
return;
}
rv = atp_free_thread_info(info);
if (rv) {
NS_WARNING("Could not free atp_thread_info struct");
}
gRealtimeLimitReached = false;
}
} // namespace mozilla

View File

@ -0,0 +1,14 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace mozilla {
bool SoftRealTimeLimitReached() { return false; }
void InstallSoftRealTimeLimitHandler() {}
void DemoteThreadFromRealTime() {}
} // namespace mozilla

View File

@ -11,6 +11,7 @@
#endif
#include "MediaDecoderOwner.h"
#include "mozilla/Telemetry.h"
#include "mozilla/AbstractThread.h"
using namespace mozilla::layers;

View File

@ -186,6 +186,7 @@ EXPORTS += [
EXPORTS.mozilla += [
'MediaManager.h',
'UnderrunHandler.h',
]
EXPORTS.mozilla.media.webrtc += [
@ -302,6 +303,11 @@ UNIFIED_SOURCES += [
'XiphExtradata.cpp',
]
if CONFIG['OS_TARGET'] == 'Linux':
UNIFIED_SOURCES += [ 'UnderrunHandlerLinux.cpp' ]
else:
UNIFIED_SOURCES += [ 'UnderrunHandlerNoop.cpp']
if CONFIG['OS_TARGET'] == 'WINNT':
EXPORTS.mozilla.audio += [
'AudioNotificationReceiver.h',

View File

@ -751,7 +751,7 @@ NPUTF8* _utf8fromidentifier(NPIdentifier id) {
JSString* str = NPIdentifierToString(id);
nsAutoString autoStr;
AssignJSFlatString(autoStr, JS_ASSERT_STRING_IS_FLAT(str));
AssignJSLinearString(autoStr, JS_ASSERT_STRING_IS_LINEAR(str));
return ToNewUTF8String(autoStr);
}

View File

@ -1,16 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
interface nsISupports;
[Exposed=Window]
interface mixin LegacyQueryInterface {
// Legacy QueryInterface, only exposed to chrome code on the main thread.
[Exposed=Window, ChromeOnly]
nsISupports QueryInterface(any iid);
};
Element includes LegacyQueryInterface;

View File

@ -635,7 +635,6 @@ WEBIDL_FILES = [
'KeyframeAnimationOptions.webidl',
'KeyframeEffect.webidl',
'KeyIdsInitData.webidl',
'LegacyQueryInterface.webidl',
'LinkStyle.webidl',
'LoadURIOptions.webidl',
'Location.webidl',

View File

@ -1,6 +1,5 @@
[DEFAULT]
support-files =
file_bug950909.xml
file_fieldScopeChain.xml
[test_bug378518.xul]
@ -10,6 +9,5 @@ skip-if = (verify && debug && (os == 'linux' || os == 'mac'))
[test_bug721452.xul]
[test_bug723676.xul]
[test_bug772966.xul]
[test_bug950909.xul]
[test_bug1086996.xhtml]
[test_fieldScopeChain.html]

View File

@ -1,8 +0,0 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div style="-moz-binding: url(chrome://mochitests/content/chrome/dom/xbl/test/file_bug950909.xml#testBinding"></div>
</body>
</html>

View File

@ -1,34 +0,0 @@
<?xml version="1.0"?>
<bindings id="chromeTestBindings" xmlns="http://www.mozilla.org/xbl">
<binding id="testBinding" bindToUntrustedContent="true">
<implementation implements="nsIObserver">
<constructor>
<![CDATA[
var win = window;
var SpecialPowers = win.SpecialPowers;
var ok = SpecialPowers.unwrap(SpecialPowers.wrap(window).parent.ok);
// Generate an XPCWrappedJS for the reflector. We need to do this
// explicitly with a testing helper, because we're converging on
// removing XPConnect from the web, which means that it won't be
// possible to generate an XPCWrappedJS from content (or XBL) code.
var scope = {};
var holder = SpecialPowers.Cu.generateXPCWrappedJS(this, scope);
// Now, QI |this|, which will generate an aggregated native.
SpecialPowers.wrap(this).QueryInterface(SpecialPowers.Ci.nsIObserver);
ok(true, "Didn't assert or crash");
SpecialPowers.wrap(window).parent.SimpleTest.finish();
]]>
</constructor>
<method name="observe">
<parameter name="aSubject"/>
<parameter name="aTopic"/>
<parameter name="aData"/>
<body><![CDATA[]]></body>
</method>
</implementation>
</binding>
</bindings>

View File

@ -13,7 +13,6 @@ support-files =
file_bug591198_inner.html
file_bug591198_xbl.xml
file_bug844783.xhtml
file_bug950909.html
[test_bug310107.html]
[test_bug366770.html]

View File

@ -1,36 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=950909
-->
<window title="Mozilla Bug 950909"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=950909"
target="_blank">Mozilla Bug 950909</a>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/*
* Test for bug 950909. This has to be a chrome tests because content needs
* to apply a chrome binding (file_bug950909.xml), which will only be registered
* as a chrome:// URI during mochitest-chrome runs. And the binding has to be
* served from a chrome origin, because otherwise implements="nsIFoo" attributes
* are ignored. So this test needs 3 files, all told. Ugh.
*/
// Just wait. When the iframe loads, it'll apply the binding, which will
// trigger the constructor for the binding.
SimpleTest.waitForExplicitFinish();
]]>
</script>
<iframe src="http://example.com/tests/dom/xbl/test/file_bug950909.html"/>
</window>

View File

@ -1,21 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript">
<![CDATA[
function boom()
{
var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var prefs = document.createElementNS(XUL_NS, "preferences");
var textbox = document.createElementNS(XUL_NS, "textbox");
textbox.setAttribute("onchange", "1");
prefs.appendChild(textbox);
prefs.cloneNode(true);
}
]]>
</script>
</head>
<body onload="boom();"></body>
</html>

View File

@ -17,7 +17,6 @@ load 386914-1.html
skip-if(!xbl) asserts(1) load chrome://reftest/content/crashtests/dom/xul/crashtests/386947-1.xul
load chrome://reftest/content/crashtests/dom/xul/crashtests/425821-1.xul
load chrome://reftest/content/crashtests/dom/xul/crashtests/428951-1.xul
load 429085-1.xhtml
load 431906-1.html
load 461917-1.xhtml
skip-if(!xbl) load chrome://reftest/content/crashtests/dom/xul/crashtests/468211-1.xul

View File

@ -42,7 +42,9 @@ UniquePtr<DCLayerTree> DCLayerTree::Create(HWND aHwnd) {
}
DCLayerTree::DCLayerTree(IDCompositionDevice2* aCompositionDevice)
: mCompositionDevice(aCompositionDevice) {}
: mCompositionDevice(aCompositionDevice),
mDebugCounter(false),
mDebugVisualRedrawRegions(false) {}
DCLayerTree::~DCLayerTree() {}
@ -78,18 +80,6 @@ bool DCLayerTree::Initialize(HWND aHwnd) {
return false;
}
if (StaticPrefs::gfx_webrender_dcomp_win_debug_counter_enabled_AtStartup()) {
RefPtr<IDCompositionDeviceDebug> debugDevice;
hr = mCompositionDevice->QueryInterface(
(IDCompositionDeviceDebug**)getter_AddRefs(debugDevice));
if (SUCCEEDED(hr)) {
debugDevice->EnableDebugCounters();
} else {
gfxCriticalNote << "Failed to get IDCompositionDesktopDevice: "
<< gfx::hexa(hr);
}
}
mCompositionTarget->SetRoot(mRootVisual);
// Set interporation mode to Linear.
// By default, a visual inherits the interpolation mode of the parent visual.
@ -109,6 +99,62 @@ void DCLayerTree::SetDefaultSwapChain(IDXGISwapChain1* aSwapChain) {
mCompositionDevice->Commit();
}
void DCLayerTree::MaybeUpdateDebug() {
bool updated = false;
updated |= MaybeUpdateDebugCounter();
updated |= MaybeUpdateDebugVisualRedrawRegions();
if (updated) {
mCompositionDevice->Commit();
}
}
bool DCLayerTree::MaybeUpdateDebugCounter() {
bool debugCounter = StaticPrefs::gfx_webrender_debug_dcomp_counter();
if (mDebugCounter == debugCounter) {
return false;
}
RefPtr<IDCompositionDeviceDebug> debugDevice;
HRESULT hr = mCompositionDevice->QueryInterface(
(IDCompositionDeviceDebug**)getter_AddRefs(debugDevice));
if (FAILED(hr)) {
return false;
}
if (debugCounter) {
debugDevice->EnableDebugCounters();
} else {
debugDevice->DisableDebugCounters();
}
mDebugCounter = debugCounter;
return true;
}
bool DCLayerTree::MaybeUpdateDebugVisualRedrawRegions() {
bool debugVisualRedrawRegions =
StaticPrefs::gfx_webrender_debug_dcomp_redraw_regions();
if (mDebugVisualRedrawRegions == debugVisualRedrawRegions) {
return false;
}
RefPtr<IDCompositionVisualDebug> visualDebug;
HRESULT hr = mRootVisual->QueryInterface(
(IDCompositionVisualDebug**)getter_AddRefs(visualDebug));
if (FAILED(hr)) {
return false;
}
if (debugVisualRedrawRegions) {
visualDebug->EnableRedrawRegions();
} else {
visualDebug->DisableRedrawRegions();
}
mDebugVisualRedrawRegions = debugVisualRedrawRegions;
return true;
}
#endif
} // namespace wr
} // namespace mozilla

View File

@ -35,20 +35,27 @@ class DCLayerTree {
~DCLayerTree();
void SetDefaultSwapChain(IDXGISwapChain1* aSwapChain);
void MaybeUpdateDebug();
protected:
bool Initialize(HWND aHwnd);
bool MaybeUpdateDebugCounter();
bool MaybeUpdateDebugVisualRedrawRegions();
RefPtr<IDCompositionDevice2> mCompositionDevice;
RefPtr<IDCompositionTarget> mCompositionTarget;
RefPtr<IDCompositionVisual2> mRootVisual;
RefPtr<IDCompositionVisual2> mDefaultSwapChainVisual;
bool mDebugCounter;
bool mDebugVisualRedrawRegions;
};
#else
class DCLayerTree {
public:
static UniquePtr<DCLayerTree> Create(HWND aHwnd) { return nullptr; }
void SetDefaultSwapChain(IDXGISwapChain1* aSwapChain) {}
void MaybeUpdateDebug() {}
};
#endif

View File

@ -406,6 +406,10 @@ void RenderCompositorANGLE::EndFrame() {
}
mSwapChain->Present(0, 0);
if (mDCLayerTree) {
mDCLayerTree->MaybeUpdateDebug();
}
}
bool RenderCompositorANGLE::WaitForGPU() {

View File

@ -28,7 +28,6 @@ struct AuxCPOWData {
ObjectId id;
bool isCallable;
bool isConstructor;
bool isDOMObject;
// The object tag is just some auxilliary information that clients can use
// however they see fit.
@ -38,11 +37,10 @@ struct AuxCPOWData {
nsCString className;
AuxCPOWData(ObjectId id, bool isCallable, bool isConstructor,
bool isDOMObject, const nsACString& objectTag)
const nsACString& objectTag)
: id(id),
isCallable(isCallable),
isConstructor(isConstructor),
isDOMObject(isDOMObject),
objectTag(objectTag) {}
};
@ -312,17 +310,6 @@ bool CPOWProxyHandler::get(JSContext* cx, HandleObject proxy,
FORWARD(get, (cx, proxy, receiver, id, vp), false);
}
static bool CPOWDOMQI(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.thisv().isObject() || !IsCPOW(&args.thisv().toObject())) {
JS_ReportErrorASCII(cx, "bad this object passed to special QI");
return false;
}
RootedObject proxy(cx, &args.thisv().toObject());
FORWARD(DOMQI, (cx, proxy, args), false);
}
static bool CPOWToString(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject callee(cx, &args.callee());
@ -379,41 +366,6 @@ bool WrapperOwner::toString(JSContext* cx, HandleObject cpow,
return true;
}
bool WrapperOwner::DOMQI(JSContext* cx, JS::HandleObject proxy,
JS::CallArgs& args) {
// Someone's calling us, handle nsISupports specially to avoid unnecessary
// CPOW traffic.
if (Maybe<nsID> id = xpc::JSValue2ID(cx, args[0])) {
if (id->Equals(NS_GET_IID(nsISupports))) {
args.rval().set(args.thisv());
return true;
}
// Webidl-implemented DOM objects never have nsIClassInfo.
if (id->Equals(NS_GET_IID(nsIClassInfo))) {
return Throw(cx, NS_ERROR_NO_INTERFACE);
}
}
// It wasn't nsISupports, call into the other process to do the QI for us
// (since we don't know what other interfaces our object supports). Note
// that we have to use JS_GetPropertyDescriptor here to avoid infinite
// recursion back into CPOWDOMQI via WrapperOwner::get().
// We could stash the actual QI function on our own function object to avoid
// if we're called multiple times, but since we're transient, there's no
// point right now.
JS::Rooted<PropertyDescriptor> propDesc(cx);
if (!JS_GetPropertyDescriptor(cx, proxy, "QueryInterface", &propDesc)) {
return false;
}
if (!propDesc.value().isObject()) {
MOZ_ASSERT_UNREACHABLE("We didn't get QueryInterface off a node");
return Throw(cx, NS_ERROR_UNEXPECTED);
}
return JS_CallFunctionValue(cx, proxy, propDesc.value(), args, args.rval());
}
bool WrapperOwner::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
HandleId id, MutableHandleValue vp) {
ObjectId objId = idOf(proxy);
@ -428,21 +380,6 @@ bool WrapperOwner::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
return false;
}
AuxCPOWData* data = AuxCPOWDataOf(proxy);
if (data->isDOMObject && idVar.type() == JSIDVariant::TnsString &&
idVar.get_nsString().EqualsLiteral("QueryInterface")) {
// Handle QueryInterface on DOM Objects specially since we can assume
// certain things about their implementation.
RootedFunction qi(cx,
JS_NewFunction(cx, CPOWDOMQI, 1, 0, "QueryInterface"));
if (!qi) {
return false;
}
vp.set(ObjectValue(*JS_GetFunctionObject(qi)));
return true;
}
JSVariant val;
ReturnStatus status;
if (!SendGet(objId, receiverVar, idVar, &status, &val)) {
@ -1146,9 +1083,8 @@ JSObject* WrapperOwner::fromRemoteObjectVariant(JSContext* cx,
// Incref once we know the decref will be called.
incref();
AuxCPOWData* aux =
new AuxCPOWData(objId, objVar.isCallable(), objVar.isConstructor(),
objVar.isDOMObject(), objVar.objectTag());
AuxCPOWData* aux = new AuxCPOWData(
objId, objVar.isCallable(), objVar.isConstructor(), objVar.objectTag());
SetProxyReservedSlot(obj, 0, PrivateValue(this));
SetProxyReservedSlot(obj, 1, PrivateValue(aux));

View File

@ -67,7 +67,6 @@ class WrapperOwner : public virtual JavaScriptShared {
nsresult instanceOf(JSObject* obj, const nsID* id, bool* bp);
bool toString(JSContext* cx, JS::HandleObject callee, JS::CallArgs& args);
bool DOMQI(JSContext* cx, JS::HandleObject callee, JS::CallArgs& args);
/*
* Check that |obj| is a DOM wrapper whose prototype chain contains

View File

@ -13,7 +13,7 @@
#include "js/TypeDecls.h"
#include "js/Utility.h"
class JSFlatString;
class JSLinearString;
namespace JS {
@ -283,7 +283,7 @@ LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8,
* Returns the length of the char buffer required to encode |s| as UTF8.
* Does not include the null-terminator.
*/
JS_PUBLIC_API size_t GetDeflatedUTF8StringLength(JSFlatString* s);
JS_PUBLIC_API size_t GetDeflatedUTF8StringLength(JSLinearString* s);
/*
* Encode whole scalar values of |src| into |dst| as UTF-8 until |src| is
@ -292,16 +292,16 @@ JS_PUBLIC_API size_t GetDeflatedUTF8StringLength(JSFlatString* s);
* the number of bytes of |dst| that were filled.
*
* Use |JS_EncodeStringToUTF8BufferPartial| if your string isn't already
* flat.
* linear.
*
* Given |JSString* str = JS_FORGET_STRING_FLATNESS(src)|,
* Given |JSString* str = JS_FORGET_STRING_LINEARNESS(src)|,
* if |JS_StringHasLatin1Chars(str)|, then |src| is always fully converted
* if |dst.Length() >= JS_GetStringLength(str) * 2|. Otherwise |src| is
* always fully converted if |dst.Length() >= JS_GetStringLength(str) * 3|.
*
* The exact space required is always |GetDeflatedUTF8StringLength(str)|.
*/
JS_PUBLIC_API size_t DeflateStringToUTF8Buffer(JSFlatString* src,
JS_PUBLIC_API size_t DeflateStringToUTF8Buffer(JSLinearString* src,
mozilla::Span<char> dst);
/*

View File

@ -263,8 +263,6 @@ class JS_FRIEND_API GCCellPtr {
: ptr(checkedCast(p, JS::MapTypeToTraceKind<T>::kind)) {}
explicit GCCellPtr(JSFunction* p)
: ptr(checkedCast(p, JS::TraceKind::Object)) {}
explicit GCCellPtr(JSFlatString* str)
: ptr(checkedCast(str, JS::TraceKind::String)) {}
explicit GCCellPtr(const Value& v);
JS::TraceKind kind() const {

View File

@ -178,7 +178,7 @@ const WHITELIST_TYPES: &'static [&'static str] = &[
"JSErrorFormatString",
"JSErrorReport",
"JSExnType",
"JSFlatString",
"JSLinearString",
"JSFunction",
"JSFunctionSpec",
"JS::GCDescription",

View File

@ -283,7 +283,7 @@ impl RootKind for *mut JSObject {
fn rootKind() -> JS::RootKind { JS::RootKind::Object }
}
impl RootKind for *mut JSFlatString {
impl RootKind for *mut JSLinearString {
#[inline(always)]
fn rootKind() -> JS::RootKind { JS::RootKind::String }
}

Some files were not shown because too many files have changed in this diff Show More