mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Merge autoland to mozilla-central. a=merge
This commit is contained in:
commit
22b13f01c9
123
Cargo.lock
generated
123
Cargo.lock
generated
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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">
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
},
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
8
browser/locales/en-US/browser/readerView.ftl
Normal file
8
browser/locales/en-US/browser/readerView.ftl
Normal 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
|
@ -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");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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 }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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 }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ DIRS += [
|
||||
'components',
|
||||
'modules',
|
||||
'reducers',
|
||||
'types',
|
||||
]
|
||||
|
||||
DevToolsModules(
|
||||
|
18
devtools/client/application/src/types/index.js
Normal file
18
devtools/client/application/src/types/index.js
Normal 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,
|
||||
}
|
||||
);
|
79
devtools/client/application/src/types/manifest.js
Normal file
79
devtools/client/application/src/types/manifest.js
Normal 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,
|
||||
};
|
10
devtools/client/application/src/types/moz.build
Normal file
10
devtools/client/application/src/types/moz.build
Normal 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',
|
||||
)
|
14
devtools/client/application/src/types/routing.js
Normal file
14
devtools/client/application/src/types/routing.js
Normal 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,
|
||||
};
|
25
devtools/client/application/src/types/service-workers.js
Normal file
25
devtools/client/application/src/types/service-workers.js
Normal 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,
|
||||
};
|
@ -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",
|
||||
},
|
||||
|
@ -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 => ({
|
||||
|
@ -208,6 +208,7 @@ const PANELS = {
|
||||
SECURITY: "security",
|
||||
STACK_TRACE: "stack-trace",
|
||||
TIMINGS: "timings",
|
||||
SEARCH: "network-action-bar-search",
|
||||
BLOCKING: "network-action-bar-blocked",
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 }
|
||||
);
|
||||
}
|
||||
},
|
||||
|
312
devtools/server/actors/highlighters/box-model-observer.js
Normal file
312
devtools/server/actors/highlighters/box-model-observer.js
Normal 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;
|
752
devtools/server/actors/highlighters/box-model-renderer.js
Normal file
752
devtools/server/actors/highlighters/box-model-renderer.js
Normal 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;
|
@ -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)
|
||||
|
202
devtools/server/actors/highlighters/highlighter-renderer.js
Normal file
202
devtools/server/actors/highlighters/highlighter-renderer.js
Normal 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;
|
@ -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',
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -406,6 +406,7 @@ const inspectorSpec = generateActorSpec({
|
||||
getHighlighter: {
|
||||
request: {
|
||||
autohide: Arg(0, "boolean"),
|
||||
useNewBoxModelHighlighter: Arg(1, "nullable:boolean"),
|
||||
},
|
||||
response: {
|
||||
highligter: RetVal("highlighter"),
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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)");
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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]
|
||||
|
@ -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>
|
@ -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());
|
||||
|
427
dom/indexedDB/test/gtest/TestKey.cpp
Normal file
427
dom/indexedDB/test/gtest/TestKey.cpp
Normal 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
|
@ -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'
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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),
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
22
dom/media/UnderrunHandler.h
Normal file
22
dom/media/UnderrunHandler.h
Normal 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_
|
77
dom/media/UnderrunHandlerLinux.cpp
Normal file
77
dom/media/UnderrunHandlerLinux.cpp
Normal 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
|
14
dom/media/UnderrunHandlerNoop.cpp
Normal file
14
dom/media/UnderrunHandlerNoop.cpp
Normal 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
|
@ -11,6 +11,7 @@
|
||||
#endif
|
||||
#include "MediaDecoderOwner.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
|
||||
using namespace mozilla::layers;
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
@ -635,7 +635,6 @@ WEBIDL_FILES = [
|
||||
'KeyframeAnimationOptions.webidl',
|
||||
'KeyframeEffect.webidl',
|
||||
'KeyIdsInitData.webidl',
|
||||
'LegacyQueryInterface.webidl',
|
||||
'LinkStyle.webidl',
|
||||
'LoadURIOptions.webidl',
|
||||
'Location.webidl',
|
||||
|
@ -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]
|
||||
|
@ -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>
|
@ -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>
|
@ -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]
|
||||
|
@ -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>
|
@ -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>
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -406,6 +406,10 @@ void RenderCompositorANGLE::EndFrame() {
|
||||
}
|
||||
|
||||
mSwapChain->Present(0, 0);
|
||||
|
||||
if (mDCLayerTree) {
|
||||
mDCLayerTree->MaybeUpdateDebug();
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderCompositorANGLE::WaitForGPU() {
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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 {
|
||||
|
@ -178,7 +178,7 @@ const WHITELIST_TYPES: &'static [&'static str] = &[
|
||||
"JSErrorFormatString",
|
||||
"JSErrorReport",
|
||||
"JSExnType",
|
||||
"JSFlatString",
|
||||
"JSLinearString",
|
||||
"JSFunction",
|
||||
"JSFunctionSpec",
|
||||
"JS::GCDescription",
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user