author | Csoregi Natalia <ncsoregi@mozilla.com> |
Tue, 15 Oct 2019 00:30:01 +0300 | |
changeset 497444 | a212b426f6651c50464a0781103000821738e43c |
parent 497373 | 439341f3e28c1a0782ac0d59cd1f44cb9741de57 (current diff) |
parent 497443 | b4c5c8d78d5f9bfbbaacc34929ff6bece064cc44 (diff) |
child 497472 | e8606a6a0c25a3c355934caaa4afe56eb521368e |
push id | 36689 |
push user | ncsoregi@mozilla.com |
push date | Mon, 14 Oct 2019 21:30:51 +0000 |
treeherder | mozilla-central@a212b426f665 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 71.0a1 |
first release with | nightly linux32
a212b426f665
/
71.0a1
/
20191014213051
/
files
nightly linux64
a212b426f665
/
71.0a1
/
20191014213051
/
files
nightly mac
a212b426f665
/
71.0a1
/
20191014213051
/
files
nightly win32
a212b426f665
/
71.0a1
/
20191014213051
/
files
nightly win64
a212b426f665
/
71.0a1
/
20191014213051
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
71.0a1
/
20191014213051
/
pushlog to previous
nightly linux64
71.0a1
/
20191014213051
/
pushlog to previous
nightly mac
71.0a1
/
20191014213051
/
pushlog to previous
nightly win32
71.0a1
/
20191014213051
/
pushlog to previous
nightly win64
71.0a1
/
20191014213051
/
pushlog to previous
|
--- a/Cargo.lock +++ b/Cargo.lock @@ -69,89 +69,89 @@ source = "registry+https://github.com/ru dependencies = [ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)", ] [[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)", "dbus 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mach 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)", ] [[package]] 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)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-named-pipes 0.2.0 (git+https://github.com/NikVolf/tokio-named-pipes?branch=stable)", "tokio-reactor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (git+https://github.com/froydnj/winapi-rs?branch=aarch64)", ] [[package]] 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)", ] [[package]] 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)", ] [[package]] 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)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", "libudev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "runloop 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -239,17 +239,17 @@ dependencies = [ "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] 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)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -275,17 +275,17 @@ source = "registry+https://github.com/ru [[package]] name = "bit_reverse" version = "0.1.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]] name = "bitreader" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -465,30 +465,30 @@ dependencies = [ [[package]] name = "clap" version = "2.31.2" 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)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] 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]] name = "cmake" version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", @@ -531,17 +531,17 @@ name = "core-foundation-sys" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] 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)", ] [[package]] name = "core-text" version = "13.0.0" @@ -744,67 +744,67 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cubeb" -version = "0.5.5" -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)", +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cubeb-core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cubeb-backend" -version = "0.5.5" -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)", +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cubeb-core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cubeb-core" -version = "0.5.5" -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)", +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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]] 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)", ] [[package]] name = "cubeb-pulse" -version = "0.2.0" -dependencies = [ - "cubeb-backend 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pulse 0.2.0", +version = "0.3.0" +dependencies = [ + "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)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "darling" @@ -1094,17 +1094,17 @@ name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] 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)", ] [[package]] name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1214,27 +1214,27 @@ dependencies = [ "xpcom-gtest 0.1.0", ] [[package]] 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)", "bitsdownload 0.1.0", "bookmark_sync 0.1.0", "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", "gkrust_utils 0.1.0", "jsrust_shared 0.1.0", "kvstore 0.1.0", "lmdb-rkv-sys 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1331,17 +1331,17 @@ dependencies = [ ] [[package]] name = "headers" 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)", "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1617,17 +1617,17 @@ name = "linked-hash-map" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] 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)", ] [[package]] name = "lmdb-rkv-sys" version = "0.9.5" @@ -2012,17 +2012,17 @@ version = "0.1.0" dependencies = [ "nsstring 0.1.0", ] [[package]] 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)", ] [[package]] name = "nsstring-gtest" version = "0.1.0" dependencies = [ "nsstring 0.1.0", @@ -2238,17 +2238,17 @@ dependencies = [ "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] 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)", ] [[package]] name = "podio" version = "0.1.5" @@ -2293,19 +2293,19 @@ dependencies = [ "object 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "thin-vec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pulse" -version = "0.2.0" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +version = "0.3.0" +dependencies = [ + "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pulse-ffi 0.1.0", ] [[package]] name = "pulse-ffi" version = "0.1.0" dependencies = [ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2517,17 +2517,17 @@ dependencies = [ [[package]] name = "rkv" version = "0.10.2" 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)", "lmdb-rkv 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 1.0.1 (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)", "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2621,21 +2621,16 @@ name = "same-file" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" 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" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "scopeguard" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2657,17 +2652,17 @@ dependencies = [ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] 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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", "phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2683,16 +2678,24 @@ name = "semver" version = "0.6.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.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" 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-parser" @@ -2826,21 +2829,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] 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" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallbitvec" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2906,17 +2904,17 @@ source = "registry+https://github.com/ru [[package]] name = "style" version = "0.0.1" dependencies = [ "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", "fallible 0.0.1", "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "hashglobe 0.1.0", "indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2970,17 +2968,17 @@ dependencies = [ "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] 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)", "malloc_size_of 0.0.1", "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.21.0", "servo_arc 0.1.1", "to_shmem 0.0.1", @@ -3533,17 +3531,17 @@ dependencies = [ ] [[package]] name = "webrender" 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)", "core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", "core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3572,17 +3570,17 @@ dependencies = [ "ws 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] 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)", "derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "peek-poke 0.2.0", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3808,29 +3806,29 @@ dependencies = [ "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9dadc668390b373e73e4abbfc1f07238b09a25858f2f39c06cebc6d8e141d774" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" "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" "checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff" "checksum bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bda13183df33055cbb84b847becce220d392df502ebe7a4a78d7021771ed94d0" "checksum bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebd71393f1ec0509b553aa012b9b58e81dadbdff7130bd3b8cba576e69b32f75" "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" "checksum block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc4358306e344bf9775d0197fd00d2603e5afb0771bb353538630f022068ea3" "checksum boxfnonce 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8380105befe91099e6f69206164072c05bc92427ff6aa8a5171388317346dd75" "checksum byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e178b8e0e239e844b083d5a0d4a156b2654e67f9f80144d48398fcd736a24fb8" @@ -3862,20 +3860,20 @@ dependencies = [ "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum cssparser 0.25.9 (registry+https://github.com/rust-lang/crates.io-index)" = "fbe18ca4efb9ba3716c6da66cc3d7e673bf59fa576353011f48c4cfddbdd740e" "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" "checksum dbus 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e1b39f3f6aa3d4a1522c4f0f9f1e9e9167bd93740a8690874caa7cf8ce47d7" "checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86" "checksum derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f57d78cf3bd45270dad4e70c21ec77a960b36c7a841ff9db76aaa775a8fb871" "checksum devd-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d009f166c0d9e9f9909dc751630b3a6411ab7f85a153d32d01deb364ffe52a7" "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" @@ -4026,38 +4024,37 @@ dependencies = [ "checksum rust-ini 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a654c5bda722c699be6b0fe4c0d90de218928da5b724c3e467fc48865c37263" "checksum rust_cascade 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f3fe4900d38dab1ad21a515e44687dd0711e6b0ec5b214a3b1aa8857343bcf3a" "checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649" "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "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" "checksum serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "45af0182ff64abaeea290235eb67da3825a576c5d53e642c4d5b652e12e6effc" "checksum serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "beed18e6f5175aef3ba670e57c60ef3b1b74d250d962a26604bff4c80e970dd4" "checksum serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae" "checksum serde_repr 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "29a734c298df0346c4cd5919595981c266dabbf12dc747c85e1a95e96077a52b" "checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" "checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582" "checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum shift_or_euc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f930dea4685b9803954b9d74cdc175c6d946a22f2eafe5aa2e9a58cdcae7da8c" "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" "checksum socket2 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df028e0e632c2a1823d920ad74895e7f9128e6438cbc4bc6fd1f180e644767b9" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00caf261d6f90f588f8450b8e1230fa0d5be49ee6140fdfbcb55335aff350970" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum svg_fmt 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c666f0fed8e1e20e057af770af9077d72f3d5a33157b8537c1475dd8ffd6d32b"
--- a/accessible/tests/browser/events/browser_test_A11yUtils_announce.js +++ b/accessible/tests/browser/events/browser_test_A11yUtils_announce.js @@ -7,25 +7,51 @@ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR }); // Check that the browser A11yUtils.announce() function works correctly. // Note that this does not use mozilla::a11y::Accessible::Announce and a11y // announcement events, as these aren't yet supported on desktop. 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); ok(!alertAcc.name); is(alertAcc.childCount, 1); 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);
--- a/accessible/tests/browser/events/browser_test_focus_urlbar.js +++ b/accessible/tests/browser/events/browser_test_focus_urlbar.js @@ -19,20 +19,30 @@ ChromeUtils.defineModuleGetter( "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm" ); 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; } function isEventForMenuItem(event) { return event.accessible.role == ROLE_MENUITEM; } @@ -142,17 +152,17 @@ async function runTests() { info("Ensuring autocomplete focus on down arrow (2)"); focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem); EventUtils.synthesizeKey("KEY_ArrowDown"); event = await focused; 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); info("Ensuring text box focus when text is typed"); focused = waitForEvent(EVENT_FOCUS, textBox); EventUtils.sendString("z"); await focused; @@ -174,17 +184,17 @@ async function runTests() { info("Ensuring autocomplete focus on arrow down (4)"); focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem); EventUtils.synthesizeKey("KEY_ArrowDown"); event = await focused; 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); info("Ensuring autocomplete focus on arrow up"); focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem); EventUtils.synthesizeKey("KEY_ArrowUp"); event = await focused;
--- a/accessible/tests/browser/shared-head.js +++ b/accessible/tests/browser/shared-head.js @@ -148,17 +148,17 @@ function invokeSetStyle(browser, id, sty * @param {Object} browser current "tabbrowser" element * @param {String} id content element id * @return {Promise} promise indicating that focus is set */ 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(); }); } /** * Load a list of scripts into the test
--- a/accessible/tests/mochitest/events.js +++ b/accessible/tests/mochitest/events.js @@ -1459,17 +1459,17 @@ function synthOpenComboboxKey(aID, aChec */ function synthFocus(aNodeOrID, aCheckerOrEventSeq) { var checkerOfEventSeq = aCheckerOrEventSeq ? aCheckerOrEventSeq : new focusChecker(aNodeOrID); 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(); }; this.getID = function synthFocus_getID() { return prettyName(aNodeOrID) + " focus"; }; @@ -1629,20 +1629,17 @@ function closeCombobox(aComboboxID) { /** * Select all invoker. */ 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); } }; this.getID = function synthSelectAll_getID() { return aNodeOrID + " selectall";
--- a/accessible/tests/mochitest/events/test_focus_autocomplete.xul +++ b/accessible/tests/mochitest/events/test_focus_autocomplete.xul @@ -274,27 +274,23 @@ function getTextEntry(aID) { // For form autocompletes the autocomplete widget and text entry widget // is the same widget, for XUL autocompletes the text entry is a first // 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; } function itemObj(aID, aIdx) { this.autocompleteNode = getNode(aID);
--- a/browser/app/blocklist.xml +++ b/browser/app/blocklist.xml @@ -1,10 +1,10 @@ <?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/> <versionRange minVersion="0" maxVersion="*" severity="3"/> </emItem> <emItem blockID="i1211" id="flvto@hotger.com"> <prefs/> <versionRange minVersion="0" maxVersion="*" severity="1"/> @@ -3500,16 +3500,20 @@ <emItem blockID="ab0b6868-6077-4d47-bd58-1df3f572c04d" id="{2e106fa4-ee23-4b4a-9ed0-f93edee539b5}"> <prefs/> <versionRange minVersion="0" maxVersion="*" severity="3"/> </emItem> <emItem blockID="bb76b262-7087-4cf2-a82f-12cfbf91239a" id="{2a78ab07-91b2-4086-889d-619e43d5e5f8}"> <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"> <match name="filename" exp="libflashplayer\.so"/> <match name="description" exp="^Shockwave Flash 11.(0|1) r[0-9]{1,3}$"/> <infoURL>https://get.adobe.com/flashplayer/</infoURL> <versionRange severity="0" vulnerabilitystatus="1"> <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -2010,16 +2010,18 @@ pref("devtools.inspector.showUserAgentSt // Show all native anonymous content pref("devtools.inspector.showAllAnonymousContent", false); // Show user agent shadow roots pref("devtools.inspector.showUserAgentShadowRoots", false); // Enable the new Rules View 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); pref("devtools.gridinspector.gridOutlineMaxRows", 50); pref("devtools.gridinspector.showGridAreas", false); pref("devtools.gridinspector.showGridLineNumbers", false); pref("devtools.gridinspector.showInfiniteLines", false); // Max number of grid highlighters that can be displayed
--- a/browser/base/content/blockedSite.xhtml +++ b/browser/base/content/blockedSite.xhtml @@ -32,17 +32,17 @@ <p id="advisoryDescText"> <a id="advisory_provider" data-l10n-name="advisory_provider"></a> </p> </div> <!-- 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> <div id="errorDescriptionContainer" hidden="true"> <!-- Error Descriptions Handled in blockedSite.js --> <div class="error-description" id="errorLongDesc"> <p id="errorInnerDescription"> <span id="error_desc_sitename" data-l10n-name="sitename"></span>
--- a/browser/base/content/browser-a11yUtils.js +++ b/browser/base/content/browser-a11yUtils.js @@ -16,33 +16,65 @@ var A11yUtils = { * user and will be noticed visually, but is not related to the focused * control and is not a pop-up such as a doorhanger. * For example, this could be used to indicate that Reader View is available * or that Firefox is making a recommendation via the toolbar. * This must be used with caution, as it can create unwanted verbosity and * 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. let live = document.getElementById("a11y-announcement"); // We use role="alert" because JAWS doesn't support aria-live in browser // chrome. // Gecko a11y needs an insertion to trigger an alert event. This is why // we can't just use aria-label on the alert. if (live.firstChild) { live.firstChild.remove(); } let label = document.createElement("label"); - label.setAttribute("aria-label", aMessage); + label.setAttribute("aria-label", message); live.appendChild(label); }, };
--- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -1342,8 +1342,29 @@ toolbarpaletteitem > toolbaritem { #sidebar-box[sidebarcommand$="-sidebar-action"] > #sidebar-header > #sidebar-switcher-target > #sidebar-icon { list-style-image: var(--webextension-menuitem-image-2x, inherit); } } 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; +}
--- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -73,16 +73,17 @@ data-l10n-sync="true"> <linkset> <html:link rel="localization" href="branding/brand.ftl"/> <html:link rel="localization" href="browser/branding/sync-brand.ftl"/> <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 # support MacOS specific features *must* go into the global-scripts.inc file so # that they can be shared with macWindow.inc.xul. #include global-scripts.inc <script>
--- a/browser/components/originattributes/test/browser/browser.ini +++ b/browser/components/originattributes/test/browser/browser.ini @@ -71,17 +71,16 @@ skip-if = verify fail-if = fission [browser_favicon_firstParty.js] fail-if = fission [browser_favicon_userContextId.js] 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] skip-if = fission # Crashes: @ mozilla::dom::BrowserBridgeParent::RecvShow(mozilla::gfx::IntSizeTyped<mozilla::ScreenPixel> const&, bool const&, nsSizeMode const&) [browser_firstPartyIsolation_js_uri.js] skip-if = fission [browser_firstPartyIsolation_saveAs.js] skip-if = fission
--- a/browser/components/originattributes/test/browser/browser_firstPartyIsolation_about_newtab.js +++ b/browser/components/originattributes/test/browser/browser_firstPartyIsolation_about_newtab.js @@ -17,26 +17,31 @@ add_task(async function setup() { * tabbrowser.addTab, if it found out the uri is about:newtab, it will use * the preloaded browser, however the preloaded browser is loaded before when we * turn on the firstPartyIsolation pref, which won't have the pref set. * * To prevent to use the preloaded browser, a simple trick is open a window * 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); 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, "about:newtab should have firstPartyDomain set" ); Assert.ok( content.document.nodePrincipal.isContentPrincipal, "The principal should be a content principal."
--- a/browser/components/preferences/in-content/tests/privacypane_tests_perwindow.js +++ b/browser/components/preferences/in-content/tests/privacypane_tests_perwindow.js @@ -347,20 +347,16 @@ function test_custom_retention(controlTo controlChanged(historymode); controlToChange = win.document.getElementById(controlToChange); ok(controlToChange, "the control to change should exist"); switch (controlToChange.localName) { case "checkbox": controlToChange.checked = !controlToChange.checked; break; - case "textbox": - controlToChange.value = - parseInt(controlToChange.value) + valueIncrement; - break; case "menulist": controlToChange.value = valueIncrement; break; } controlChanged(controlToChange); }; }
--- a/browser/components/search/content/search-one-offs.js +++ b/browser/components/search/content/search-one-offs.js @@ -464,17 +464,18 @@ class SearchOneOffs { // Finally, build the list of one-off buttons. while (this.buttons.firstElementChild) { this.buttons.firstElementChild.remove(); } 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) ? await Services.search.getDefaultPrivate() : await Services.search.getDefault(); let oneOffCount = engines.length; let hideOneOffs = !oneOffCount ||
new file mode 100644 --- /dev/null +++ b/browser/locales/en-US/browser/readerView.ftl @@ -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
--- a/browser/modules/ReaderParent.jsm +++ b/browser/modules/ReaderParent.jsm @@ -73,37 +73,32 @@ var ReaderParent = { let win = browser.ownerGlobal; if (browser != win.gBrowser.selectedBrowser) { return; } 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"); button.setAttribute("readeractive", true); button.hidden = false; button.setAttribute("aria-label", closeText); menuitem.setAttribute("label", closeText); menuitem.setAttribute("hidden", false); menuitem.setAttribute( "accesskey", gStringBundle.GetStringFromName("readerView.close.accesskey") ); key.setAttribute("disabled", false); - browser.setAttribute("aria-reader", "active"); Services.obs.notifyObservers(null, "reader-mode-available"); } else { let enterText = gStringBundle.GetStringFromName("readerView.enter"); button.removeAttribute("readeractive"); button.hidden = !browser.isArticle; button.setAttribute("aria-label", enterText); @@ -112,20 +107,21 @@ var ReaderParent = { menuitem.setAttribute( "accesskey", gStringBundle.GetStringFromName("readerView.enter.accesskey") ); 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"); } } }, forceShowReaderIcon(browser) { browser.isArticle = true; this.updateReaderButton(browser); },
--- a/browser/themes/shared/blockedSite.css +++ b/browser/themes/shared/blockedSite.css @@ -1,64 +1,38 @@ /* 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/. */ @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; } #errorDescriptionContainer { position: absolute; margin: 48px auto; }
--- a/browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css +++ b/browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css @@ -180,16 +180,20 @@ p { background-position: left 0 top 50px; background-repeat: no-repeat; background-size: 32px; letter-spacing: -.2px; padding: 50px 0; padding-inline-start: 44px; } +.banner-body:dir(rtl) { + background-position-x: right; +} + .banner-body h1 { font-size: 18px; font-weight: bold; color: var(--in-content-banner-text-color); line-height: 1em; margin: 7px 0; } @@ -222,22 +226,25 @@ p { } .info p { font-size: 15px; line-height: 25px; } .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 { -moz-context-properties: fill, fill-opacity; fill: currentColor; fill-opacity: 0; width: 28px; }
--- a/devtools/client/application/src/components/manifest/Manifest.js +++ b/devtools/client/application/src/components/manifest/Manifest.js @@ -1,15 +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 { createFactory, PureComponent, } = require("devtools/client/shared/vendor/react"); const { article, h1, table, @@ -23,30 +22,25 @@ const { l10n } = require("../../modules/ const ManifestColorItem = createFactory(require("./ManifestColorItem")); const ManifestIconItem = createFactory(require("./ManifestIconItem")); const ManifestItem = createFactory(require("./ManifestItem")); const ManifestIssueList = createFactory(require("./ManifestIssueList")); 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 } }; } renderIssueSection() { const { validation } = this.props; const shouldRender = validation && validation.length > 0; return shouldRender
--- a/devtools/client/application/src/components/manifest/ManifestColorItem.js +++ b/devtools/client/application/src/components/manifest/ManifestColorItem.js @@ -1,31 +1,30 @@ /* 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 { 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")); /** * This component displays a Manifest member which holds a color value */ class ManifestColorItem extends PureComponent { static get propTypes() { return { - label: PropTypes.string.isRequired, - value: PropTypes.string, + ...Types.manifestItemColor, // { label, value } }; } renderColor() { const { value } = this.props; return value ? span( {
--- a/devtools/client/application/src/components/manifest/ManifestIconItem.js +++ b/devtools/client/application/src/components/manifest/ManifestIconItem.js @@ -1,46 +1,43 @@ /* 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 { createFactory, PureComponent, } = require("devtools/client/shared/vendor/react"); const { br, code, img, span, } = require("devtools/client/shared/vendor/react-dom-factories"); 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")); /** * This component displays a Manifest member which holds a color value */ 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, }; } getLocalizedImgTitle() { const { sizes } = this.props.label; return sizes && sizes.length > 0 ? l10n.getString("manifest-icon-img-title", { sizes })
--- a/devtools/client/application/src/components/manifest/ManifestIssue.js +++ b/devtools/client/application/src/components/manifest/ManifestIssue.js @@ -14,28 +14,26 @@ const { li, span, } = require("devtools/client/shared/vendor/react-dom-factories"); 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) */ 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 } }; } getIconData(level) { switch (level) { case MANIFEST_ISSUE_LEVELS.WARNING: return { src: "chrome://devtools/skin/images/alert-small.svg",
--- a/devtools/client/application/src/components/manifest/ManifestIssueList.js +++ b/devtools/client/application/src/components/manifest/ManifestIssueList.js @@ -1,33 +1,32 @@ /* 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 { createFactory, PureComponent, } = require("devtools/client/shared/vendor/react"); 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")); /** * A collection of manifest issues (errors, warnings) */ 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, }; } // group the errors by level, and order by severity groupIssuesByLevel() { const { issues } = this.props; const errors = issues.filter(x => x.level === MANIFEST_ISSUE_LEVELS.ERROR);
--- a/devtools/client/application/src/components/manifest/ManifestPage.js +++ b/devtools/client/application/src/components/manifest/ManifestPage.js @@ -10,30 +10,29 @@ const { PureComponent, } = require("devtools/client/shared/vendor/react"); const { section, } = require("devtools/client/shared/vendor/react-dom-factories"); const { connect } = require("devtools/client/shared/vendor/react-redux"); +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), }; } get shouldShowLoader() { const { isManifestLoading, hasLoadingFailed } = this.props; const mustLoadManifest = typeof this.props.manifest === "undefined"; return isManifestLoading || mustLoadManifest || hasLoadingFailed; }
--- a/devtools/client/application/src/components/routing/PageSwitcher.js +++ b/devtools/client/application/src/components/routing/PageSwitcher.js @@ -4,27 +4,27 @@ "use strict"; const { createFactory, 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")); class PageSwitcher extends PureComponent { static get propTypes() { return { - page: PropTypes.oneOf(Object.values(PAGE_TYPES)), + page: Types.page.isRequired, }; } render() { let component = null; switch (this.props.page) { case PAGE_TYPES.MANIFEST:
--- a/devtools/client/application/src/components/routing/Sidebar.js +++ b/devtools/client/application/src/components/routing/Sidebar.js @@ -7,29 +7,29 @@ const { createFactory, PureComponent, } = require("devtools/client/shared/vendor/react"); 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, }; } render() { const navItems = Object.values(PAGE_TYPES); const isSelected = page => { return page === this.props.selectedPage;
--- a/devtools/client/application/src/components/routing/SidebarItem.js +++ b/devtools/client/application/src/components/routing/SidebarItem.js @@ -18,33 +18,34 @@ const PropTypes = require("devtools/clie const Actions = require("./../../actions/index"); const { connect } = require("devtools/client/shared/vendor/react-redux"); 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]: "chrome://devtools/skin/images/application-manifest.svg", [PAGE_TYPES.SERVICE_WORKERS]: "chrome://devtools/skin/images/debugging-workers.svg", }; const LOCALIZATION_IDS = { [PAGE_TYPES.MANIFEST]: "sidebar-item-manifest", [PAGE_TYPES.SERVICE_WORKERS]: "sidebar-item-service-workers", }; 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, }; } render() { const { isSelected, page } = this.props;
--- a/devtools/client/application/src/components/service-workers/Worker.js +++ b/devtools/client/application/src/components/service-workers/Worker.js @@ -26,16 +26,18 @@ const { const { getUnicodeUrl, getUnicodeUrlPath, } = require("devtools/client/shared/unicode-url"); 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( this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true ); @@ -45,26 +47,17 @@ loader.lazyRequireGetter( * the list of workers displayed in the application panel. It displays information about * the worker as well as action links and buttons to interact with the worker (e.g. debug, * unregister, update etc...). */ 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, }; } constructor(props) { super(props); this.debug = this.debug.bind(this); this.start = this.start.bind(this);
--- a/devtools/client/application/src/components/service-workers/WorkerList.js +++ b/devtools/client/application/src/components/service-workers/WorkerList.js @@ -12,31 +12,33 @@ const { } = require("devtools/client/shared/vendor/react"); const { a, article, footer, 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 * workers. */ class WorkerList extends PureComponent { static get propTypes() { return { canDebugWorkers: PropTypes.bool.isRequired, - workers: PropTypes.array.isRequired, + workers: Types.workerArray.isRequired, }; } render() { const { canDebugWorkers, workers } = this.props; return [ article(
--- a/devtools/client/application/src/components/service-workers/WorkersPage.js +++ b/devtools/client/application/src/components/service-workers/WorkersPage.js @@ -9,26 +9,27 @@ const { PureComponent, } = require("devtools/client/shared/vendor/react"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const { section, } = 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")); class WorkersPage extends PureComponent { static get propTypes() { return { // mapped from state canDebugWorkers: PropTypes.bool.isRequired, domain: PropTypes.string.isRequired, - workers: PropTypes.array.isRequired, + workers: Types.workerArray.isRequired, }; } render() { const { canDebugWorkers, domain, workers } = this.props; // Filter out workers from other domains const domainWorkers = workers.filter(
--- a/devtools/client/application/src/moz.build +++ b/devtools/client/application/src/moz.build @@ -2,15 +2,16 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. DIRS += [ 'actions', 'components', 'modules', 'reducers', + 'types', ] DevToolsModules( 'base.css', 'constants.js', 'create-store.js', )
new file mode 100644 --- /dev/null +++ b/devtools/client/application/src/types/index.js @@ -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, + } +);
new file mode 100644 --- /dev/null +++ b/devtools/client/application/src/types/manifest.js @@ -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, +};
new file mode 100644 --- /dev/null +++ b/devtools/client/application/src/types/moz.build @@ -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', +)
new file mode 100644 --- /dev/null +++ b/devtools/client/application/src/types/routing.js @@ -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, +};
new file mode 100644 --- /dev/null +++ b/devtools/client/application/src/types/service-workers.js @@ -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, +};
--- a/devtools/client/netmonitor/src/components/NetworkActionBar.js +++ b/devtools/client/netmonitor/src/components/NetworkActionBar.js @@ -63,17 +63,17 @@ class NetworkActionBar extends Component Tabbar( { activeTabId: selectedActionBarTabId, onSelect: id => selectActionBarTab(id), }, showSearchPanel && TabPanel( { - id: "network-action-bar-search", + id: PANELS.SEARCH, title: L10N.getStr("netmonitor.actionbar.search"), className: "network-action-bar-search", }, SearchPanel({ connector }) ), showBlockingPanel && TabPanel( {
--- a/devtools/client/netmonitor/src/components/search/SearchPanel.js +++ b/devtools/client/netmonitor/src/components/search/SearchPanel.js @@ -7,16 +7,17 @@ const { Component, createRef, createFactory, } = require("devtools/client/shared/vendor/react"); 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, } = require("devtools/client/shared/redux/visibility-handler-connect"); const TreeViewClass = require("devtools/client/shared/components/tree/TreeView"); const TreeView = createFactory(TreeViewClass); const LabelCell = createFactory( require("devtools/client/shared/components/tree/LabelCell") @@ -42,16 +43,17 @@ class SearchPanel extends Component { closeSearch: PropTypes.func.isRequired, search: PropTypes.func.isRequired, caseSensitive: PropTypes.bool, connector: PropTypes.object.isRequired, addSearchQuery: PropTypes.func.isRequired, query: PropTypes.string.isRequired, results: PropTypes.array, navigate: PropTypes.func.isRequired, + isDisplaying: PropTypes.bool.isRequired, }; } constructor(props) { super(props); this.searchboxRef = createRef(); this.renderValue = this.renderValue.bind(this); @@ -61,16 +63,22 @@ class SearchPanel extends Component { } componentDidMount() { if (this.searchboxRef) { this.searchboxRef.current.focus(); } } + 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); } } /** * Custom TreeView label rendering. The search result @@ -229,16 +237,17 @@ class SearchPanel extends Component { } module.exports = connect( state => ({ query: state.search.query, caseSensitive: state.search.caseSensitive, results: state.search.results, ongoingSearch: state.search.ongoingSearch, + isDisplaying: state.ui.selectedActionBarTabId === PANELS.SEARCH, status: state.search.status, }), dispatch => ({ closeSearch: () => dispatch(Actions.closeSearch()), openSearch: () => dispatch(Actions.openSearch()), search: () => dispatch(Actions.search()), clearSearchResults: () => dispatch(Actions.clearSearchResults()), addSearchQuery: query => dispatch(Actions.addSearchQuery(query)),
--- a/devtools/client/netmonitor/src/constants.js +++ b/devtools/client/netmonitor/src/constants.js @@ -203,16 +203,17 @@ const PANELS = { HEADERS: "headers", MESSAGES: "messages", PARAMS: "params", RESPONSE: "response", CACHE: "cache", SECURITY: "security", STACK_TRACE: "stack-trace", TIMINGS: "timings", + SEARCH: "network-action-bar-search", BLOCKING: "network-action-bar-blocked", }; const RESPONSE_HEADERS = [ "Cache-Control", "Connection", "Content-Encoding", "Content-Length",
--- a/devtools/server/actors/highlighters.js +++ b/devtools/server/actors/highlighters.js @@ -41,16 +41,22 @@ loader.lazyRequireGetter( true ); loader.lazyRequireGetter( this, "BoxModelHighlighter", "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"; /** * The registration mechanism for highlighters provide a quick way to * have modular highlighters, instead of a hard coded list. * It allow us to split highlighers in sub modules, and add them dynamically @@ -105,25 +111,26 @@ exports.register = register; * Other types of highlighter actors exist and can be accessed via the * InspectorActor's 'getHighlighterByType' method. */ /** * 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; this._inspector = inspector; this._walker = this._inspector.walker; this._targetActor = this._inspector.targetActor; this._highlighterEnv = new HighlighterEnvironment(); this._highlighterEnv.initFromTargetActor(this._targetActor); + this._useNewBoxModelHighlighter = useNewBoxModelHighlighter; this._onNavigate = this._onNavigate.bind(this); const doc = this._targetActor.window.document; // Only try to create the highlighter when the document is loaded, // otherwise, wait for the navigate event to fire. if (doc.documentElement && doc.readyState != "uninitialized") { this._createHighlighter(); @@ -142,16 +149,25 @@ exports.HighlighterActor = protocol.Acto return { actor: this.actorID, }; }, _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, this._inspector ); } else { this._highlighter = new SimpleOutlineHighlighter(this._highlighterEnv); }
--- a/devtools/server/actors/highlighters/auto-refresh.js +++ b/devtools/server/actors/highlighters/auto-refresh.js @@ -80,16 +80,17 @@ function AutoRefreshHighlighter(highligh this._winDimensions = getWindowDimensions(this.win); this._scroll = { x: this.win.pageXOffset, y: this.win.pageYOffset }; this.update = this.update.bind(this); } AutoRefreshHighlighter.prototype = { _ignoreZoom: false, + _ignoreScroll: false, /** * Window corresponding to the current highlighterEnv. When replaying, this * will be the window against which the server is running, which is different * from the window containing the target content. */ get win() { if (!this.highlighterEnv) { @@ -189,17 +190,17 @@ AutoRefreshHighlighter.prototype = { _updateAdjustedQuads: function() { this.currentQuads = {}; for (const region of BOX_MODEL_REGIONS) { this.currentQuads[region] = getAdjustedQuads( this.contentWindow, this.currentNode, region, - { ignoreZoom: this._ignoreZoom } + { ignoreScroll: this._ignoreScroll, ignoreZoom: this._ignoreZoom } ); } }, /** * Update the knowledge we have of the current node's boxquads and return true * if any of the points x/y or bounds have change since. * @return {Boolean}
new file mode 100644 --- /dev/null +++ b/devtools/server/actors/highlighters/box-model-observer.js @@ -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;
copy from devtools/server/actors/highlighters/box-model.js copy to devtools/server/actors/highlighters/box-model-renderer.js --- a/devtools/server/actors/highlighters/box-model.js +++ b/devtools/server/actors/highlighters/box-model-renderer.js @@ -1,74 +1,40 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -const { AutoRefreshHighlighter } = require("./auto-refresh"); const { - CanvasFrameAnonymousContentHelper, createNode, createSVGNode, - getBindingElementAndPseudo, - hasPseudoClassLock, - isNodeValid, moveInfobar, -} = require("./utils/markup"); -const { PSEUDO_CLASSES } = require("devtools/shared/css/constants"); +} = require("devtools/server/actors/highlighters/utils/markup"); + const { - getCurrentZoom, - setIgnoreLayoutChanges, -} = 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); + 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 +// Width of BoxModelHighlighter guides const GUIDE_STROKE_WIDTH = 1; /** - * The BoxModelHighlighter draws the box model regions on top of a node. + * 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. * - * Usage example: - * - * let h = new BoxModelHighlighter(env); - * h.show(node, options); - * h.hide(); - * h.destroy(); - * - * @param {String} options.region - * Specifies the region that the guides should outline: - * "content" (default), "padding", "border" or "margin". - * @param {Boolean} options.hideGuides - * Defaults to false - * @param {Boolean} options.hideInfoBar - * Defaults to false - * @param {String} 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} 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. - * * 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="..." /> @@ -91,343 +57,133 @@ const GUIDE_STROKE_WIDTH = 1; * <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 BoxModelHighlighter extends AutoRefreshHighlighter { - constructor(highlighterEnv) { - super(highlighterEnv); - +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-"; - this.markup = new CanvasFrameAnonymousContentHelper( - this.highlighterEnv, - this._buildMarkup.bind(this) - ); - - /** - * 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); - } - - _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 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, - }); + // 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); } - - // 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, - }); - - return highlighterContainer; } /** - * Destroy the nodes. Remove listeners. + * 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. */ - destroy() { - this.highlighterEnv.off("will-navigate", this.onWillNavigate); + render(data = {}) { + this.currentQuads = data.currentQuads || {}; + this.nodeData = data.nodeData || null; + this.options = data.options || {}; + this.regionFill = data.regionFill || {}; - const { pageListenerTarget } = this.highlighterEnv; - if (pageListenerTarget) { - pageListenerTarget.removeEventListener("pagehide", this.onPageHide); + const { showBoxModel = false, showInfoBar = false } = data; + + if (!showBoxModel) { + this._hideBoxModel(); + this._hideInfobar(); + return; } - this.markup.destroy(); + this._updateBoxModel(); + this._showBoxModel(); - AutoRefreshHighlighter.prototype.destroy.call(this); + if (!showInfoBar) { + this._hideInfobar(); + } else { + this._updateInfobar(); + this._showInfobar(); + } } getElement(id) { return this.markup.getElement(this.ID_CLASS_PREFIX + id); } /** - * 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; - setIgnoreLayoutChanges(true); - - if (this._updateBoxModel()) { - // Show the infobar only if configured to do so and the node is an element or a text - // node. - if ( - !this.options.hideInfoBar && - (node.nodeType === node.ELEMENT_NODE || - node.nodeType === node.TEXT_NODE) - ) { - this._showInfobar(); - } else { - this._hideInfobar(); - } - this._showBoxModel(); - shown = true; - } else { - // Nothing to highlight (0px rectangle like a <script> tag for instance) - this._hide(); - } - - setIgnoreLayoutChanges( - false, - this.highlighterEnv.window.document.documentElement - ); - - return shown; - } - - _scrollUpdate() { - this._moveInfobar(); - } - - /** - * Hide the highlighter, the outline and the infobar. - */ - _hide() { - setIgnoreLayoutChanges(true); - - this._untrackMutations(); - this._hideBoxModel(); - this._hideInfobar(); - - setIgnoreLayoutChanges( - false, - this.highlighterEnv.window.document.documentElement - ); - } - - /** * Hide the infobar */ _hideInfobar() { this.getElement("infobar-container").setAttribute("hidden", "true"); } /** * Show the infobar */ _showInfobar() { this.getElement("infobar-container").removeAttribute("hidden"); - this._updateInfobar(); } /** * Hide the box model */ _hideBoxModel() { this.getElement("elements").setAttribute("hidden", "true"); } @@ -435,16 +191,66 @@ class BoxModelHighlighter extends AutoRe /** * 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} @@ -490,80 +296,16 @@ class BoxModelHighlighter extends AutoRe 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; } - /** - * Update the box model as per the current node. - * - * @return {boolean} - * True if the current node has a box model to be highlighted - */ - _updateBoxModel() { - const options = this.options; - options.region = options.region || "content"; - - if (!this._nodeNeedsHighlighting()) { - this._hideBoxModel(); - return false; - } - - 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(); - } - } - - // Un-zoom the root wrapper if the page was zoomed. - const rootId = this.ID_CLASS_PREFIX + "elements"; - this.markup.scaleRootElement(this.currentNode, rootId); - - return true; - } - _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 = @@ -639,31 +381,18 @@ class BoxModelHighlighter extends AutoRe np1.x + "," + np1.y; } return path; } - /** - * 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 - ); - } - _getOuterBounds() { - for (const region of ["margin", "border", "padding", "content"]) { + 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; @@ -763,113 +492,261 @@ class BoxModelHighlighter extends AutoRe } 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.currentNode) { + if (!this.nodeData) { return; } - 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 { + 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 zoom = getCurrentZoom(this.win); 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)); - const { grid: gridType, flex: flexType } = getNodeGridFlexType(node); - const gridLayoutTextType = this._getLayoutTextType("gridType", gridType); - const flexLayoutTextType = this._getLayoutTextType("flexType", flexType); - 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(); } - _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`); - } + /** + * @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, + }); - _getPseudoClasses(node) { - if (node.nodeType !== nodeConstants.ELEMENT_NODE) { - // hasPseudoClassLock can only be used on Elements. - return []; + 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, + }); } - return PSEUDO_CLASSES.filter(pseudo => hasPseudoClassLock(node, pseudo)); - } - - /** - * 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.win); - } + 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, + }); + } - 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(); - } + return highlighterContainer; } } -exports.BoxModelHighlighter = BoxModelHighlighter; +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;
--- a/devtools/server/actors/highlighters/box-model.js +++ b/devtools/server/actors/highlighters/box-model.js @@ -96,17 +96,16 @@ const GUIDE_STROKE_WIDTH = 1; * </div> * </div> */ class BoxModelHighlighter extends AutoRefreshHighlighter { constructor(highlighterEnv) { super(highlighterEnv); this.ID_CLASS_PREFIX = "box-model-"; - this.markup = new CanvasFrameAnonymousContentHelper( this.highlighterEnv, this._buildMarkup.bind(this) ); /** * Optionally customize each region's fill color by adding an entry to the * regionFill property: `highlighter.regionFill.margin = "red";
new file mode 100644 --- /dev/null +++ b/devtools/server/actors/highlighters/highlighter-renderer.js @@ -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;
--- a/devtools/server/actors/highlighters/moz.build +++ b/devtools/server/actors/highlighters/moz.build @@ -6,23 +6,26 @@ DIRS += [ 'utils', ] DevToolsModules( 'accessible.js', 'auto-refresh.js', + 'box-model-observer.js', + 'box-model-renderer.js', 'box-model.js', 'css-grid.js', 'css-transform.js', 'eye-dropper.js', 'flexbox.js', 'fonts.js', 'geometry-editor.js', + 'highlighter-renderer.js', 'measuring-tool.js', 'paused-debugger.js', 'rulers.js', 'selector.js', 'shapes.js', 'simple-outline.js', 'xul-accessible.js' )
--- a/devtools/server/actors/inspector/event-collector.js +++ b/devtools/server/actors/inspector/event-collector.js @@ -299,25 +299,32 @@ class MainEventCollector { return null; } unwrap(obj) { return Cu.isXrayWrapper(obj) ? obj.wrappedJSObject : obj; } 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; + } } } /** * Get or detect DOM events. These may include DOM events created by libraries * that enable their custom events to work. At this point we are unable to * effectively filter them as they may be proxied or wrapped. Although we know * there is an event, we may not know the true contents until it goes
--- a/devtools/server/actors/inspector/inspector.js +++ b/devtools/server/actors/inspector/inspector.js @@ -191,25 +191,31 @@ exports.InspectorActor = protocol.ActorC * The same instance will always be returned by this method when called * several times. * The highlighter actor returned here is used to highlighter elements's * box-models from the markup-view, box model, console, debugger, ... as * well as select elements with the pointer (pick). * * @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; }); return this._highlighterPromise; }, /** * If consumers need to display several highlighters at the same time or
--- a/devtools/shared/fronts/inspector.js +++ b/devtools/shared/fronts/inspector.js @@ -25,17 +25,19 @@ loader.lazyRequireGetter( loader.lazyRequireGetter(this, "flags", "devtools/shared/flags"); const TELEMETRY_EYEDROPPER_OPENED = "DEVTOOLS_EYEDROPPER_OPENED_COUNT"; const TELEMETRY_EYEDROPPER_OPENED_MENU = "DEVTOOLS_MENU_EYEDROPPER_OPENED_COUNT"; 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(); /** * Client side of the DOM walker. */ class WalkerFront extends FrontClassWithSpec(walkerSpec) { /** @@ -526,17 +528,20 @@ class InspectorFront extends FrontClassW this.walker = await this.getWalker({ showAllAnonymousContent, showUserAgentShadowRoots, }); } 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) { return this._highlighters.has(type); } async _getPageStyle() { this.pageStyle = await super.getPageStyle(); @@ -599,17 +604,17 @@ class InspectorFront extends FrontClassW * targets in remote frames nested within the document inspected here. * * Note that this only returns a non-empty array if the used from the Browser Toolbox * and with the FISSION_ENABLED pref on. * * @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 if (fissionEnabled && target.chrome && !target.isAddon) { const { frames } = await target.listRemoteFrames(); // attempt to get targets and filter by targets that could connect for (const descriptor of frames) { const remoteTarget = await descriptor.getTarget();
--- a/devtools/shared/layout/utils.js +++ b/devtools/shared/layout/utils.js @@ -149,33 +149,40 @@ exports.getFrameOffsets = getFrameOffset * The box model region to return: "content", "padding", "border" or * "margin". * @param {Object} [options.ignoreZoom=false] * Ignore zoom used in the context of e.g. canvas. * @return {Array} * 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 []; } const quads = node.getBoxQuads({ box: region, relativeTo: boundaryWindow.document, createFramesForSuppressedWhitespace: false, }); if (!quads.length) { return []; } 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; const adjustedQuads = []; for (const quad of quads) { const bounds = quad.getBounds(); adjustedQuads.push({
--- a/devtools/shared/specs/inspector.js +++ b/devtools/shared/specs/inspector.js @@ -401,16 +401,17 @@ const inspectorSpec = generateActorSpec( request: {}, response: { pageStyle: RetVal("pagestyle"), }, }, getHighlighter: { request: { autohide: Arg(0, "boolean"), + useNewBoxModelHighlighter: Arg(1, "nullable:boolean"), }, response: { highligter: RetVal("highlighter"), }, }, getHighlighterByType: { request: { typeName: Arg(0),
--- a/dom/base/TimeoutHandler.cpp +++ b/dom/base/TimeoutHandler.cpp @@ -125,21 +125,21 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(CallbackTimeoutHandler) if (MOZ_UNLIKELY(cb.WantDebugInfo())) { nsAutoCString name("CallbackTimeoutHandler"); JSObject* obj = tmp->mFunction->CallablePreserveColor(); 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; name.Append(']'); } } cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name.get()); } else {
--- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h @@ -265,22 +265,22 @@ inline bool AssignJSString(JSContext* cx "Shouldn't overflow here or in SetCapacity"); if (MOZ_UNLIKELY(!dest.SetLength(len, mozilla::fallible))) { JS_ReportOutOfMemory(cx); return false; } 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 { public: /** * nsAutoJSString should be default constructed, which leaves it empty * (this->IsEmpty()), and initialized with one of the init() methods below. */
--- a/dom/base/test/chrome/cpows_parent.xul +++ b/dom/base/test/chrome/cpows_parent.xul @@ -206,38 +206,26 @@ function recvErrorReportingTest(message) { throw "Test Error Probe"; } let savedElement = null; 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)"); is(Object.prototype.toString.call(savedElement), "[object HTMLDivElement]", "prove that this works twice (since we cache it and doesn't leak)"); // This does work because we create a CPOW for isEqualNode that stays
--- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -1233,68 +1233,16 @@ bool InitIds(JSContext* cx, const Native CompareIdsAtIndices, const_cast<PropertyInfo*>(nativeProperties->PropertyInfos())); return true; } #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, ErrorResult& aError) { Maybe<nsIID> iid = xpc::JSValue2ID(aCx, aIID); if (!iid) { aError.Throw(NS_ERROR_XPC_BAD_CONVERT_JS); return;
--- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -1760,27 +1760,16 @@ static inline bool AtomizeAndPinJSString id = INTERNED_STRING_TO_JSID(cx, str); return true; } return false; } 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, ErrorResult& aError); template <class T> void GetInterface(JSContext* aCx, T* aThis, JS::Handle<JS::Value> aIID, JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError) {
--- a/dom/bindings/CallbackInterface.cpp +++ b/dom/bindings/CallbackInterface.cpp @@ -15,18 +15,17 @@ namespace dom { bool CallbackInterface::GetCallableProperty( JSContext* cx, JS::Handle<jsid> aPropId, JS::MutableHandle<JS::Value> aCallable) { if (!JS_GetPropertyById(cx, CallbackKnownNotGray(), aPropId, aCallable)) { 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()); return false; } return true; }
--- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -2339,46 +2339,16 @@ class MethodDefiner(PropertyDefiner): (not crossOriginOnly or m.getExtendedAttribute("CrossOriginCallable")) and not m.isIdentifierLess() and not m.getExtendedAttribute("Unexposed")] else: methods = [] 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(): method["nativeName"] = CppKeywords.checkMethodName(IDLToCIdentifier(m.identifier.name)) if isChromeOnly(m): self.chrome.append(method) else: @@ -11831,27 +11801,27 @@ def missingPropUseCountersForDescriptor( containing interface name and prop name. Incoming props should be a sorted list. """ if len(props) == 1: # 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}); } """, iface=props[0][0], name=props[0][1]) switch = dict() if charIndex == 0: switch['precondition'] = \ - 'StringIdChars chars(nogc, js::FlatStringToLinearString(str));\n' + 'StringIdChars chars(nogc, str);\n' else: switch['precondition'] = "" # Find the first place where we might actually have a difference. while all(prop[1][charIndex] == props[0][1][charIndex] for prop in props): charIndex += 1 @@ -11869,33 +11839,33 @@ def missingPropUseCountersForDescriptor( current_props = [] curChar = nextChar current_props.append(props[idx]) idx += 1 switch['cases'][curChar] = charSwitch(current_props, charIndex + 1) 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): switchDesc['cases'][str(length)] = charSwitch( list(sorted(prop for prop in instrumentedProps if len(prop[1]) == length)), 0) return fill( """ if (StaticPrefs::${pref}() && JSID_IS_ATOM(id)) { Maybe<UseCounter> counter; { // 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} } if (counter) { SetUseCounter(proxy, *counter); } } @@ -14531,21 +14501,21 @@ class CGGlobalNames(CGGeneric): # Build the perfect hash function. phf = PerfectHash(entries, GLOBAL_NAMES_PHF_SIZE) # Generate code for the PHF 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; """)) define = fill(""" const uint32_t WebIDLGlobalNameHash::sCount = ${count};
--- a/dom/bindings/Configuration.py +++ b/dom/bindings/Configuration.py @@ -53,27 +53,22 @@ class Configuration(DescriptorProvider): self.maxProtoChainLength = 0 for thing in parseData: if isinstance(thing, IDLIncludesStatement): # Our build system doesn't support dep build involving # addition/removal of "includes" statements that appear in a # 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)) assert not thing.isType() if (not thing.isInterface() and not thing.isNamespace() and not thing.isInterfaceMixin()):
--- a/dom/bindings/WebIDLGlobalNameHash.cpp +++ b/dom/bindings/WebIDLGlobalNameHash.cpp @@ -57,19 +57,17 @@ static JSObject* FindNamedConstructorFor } /* static */ bool WebIDLGlobalNameHash::DefineIfEnabled( JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<jsid> aId, 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; } *aFound = true; ConstructorEnabled checkEnabledForScope = entry->mEnabled; @@ -170,17 +168,17 @@ bool WebIDLGlobalNameHash::DefineIfEnabl // doesn't matter what we pass for the "readonly" argument here. FillPropertyDescriptor(aDesc, aObj, JS::UndefinedValue(), false); return true; } /* static */ bool WebIDLGlobalNameHash::MayResolve(jsid aId) { - return GetEntry(JSID_TO_FLAT_STRING(aId)) != nullptr; + return GetEntry(JSID_TO_LINEAR_STRING(aId)) != nullptr; } /* static */ bool WebIDLGlobalNameHash::GetNames(JSContext* aCx, JS::Handle<JSObject*> aObj, NameType aNameType, JS::MutableHandleVector<jsid> aNames) { // aObj is always a Window here, so GetProtoAndIfaceCache on it is safe. ProtoAndIfaceCache* cache = GetProtoAndIfaceCache(aObj); @@ -223,17 +221,17 @@ bool WebIDLGlobalNameHash::ResolveForSys } // XXX(nika): In the Window case, we unwrap our global object here to handle // XRays. I don't think we ever create xrays to system globals, so I believe // we can skip this step. 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, /* aDefineOnGlobal = */ true))) { return Throw(aCx, NS_ERROR_FAILURE); } *aResolvedp = true;
--- a/dom/bindings/WebIDLGlobalNameHash.h +++ b/dom/bindings/WebIDLGlobalNameHash.h @@ -6,17 +6,17 @@ #ifndef mozilla_dom_WebIDLGlobalNameHash_h__ #define mozilla_dom_WebIDLGlobalNameHash_h__ #include "js/RootingAPI.h" #include "nsTArray.h" #include "mozilla/dom/BindingDeclarations.h" -class JSFlatString; +class JSLinearString; namespace mozilla { namespace dom { namespace constructors { namespace id { enum ID : uint16_t; } // namespace id @@ -72,17 +72,17 @@ class WebIDLGlobalNameHash { JSContext* aCx, JS::Handle<JSObject*> aObj, JS::MutableHandleVector<jsid> aProperties, bool aEnumerableOnly); private: friend struct WebIDLNameTableEntry; // 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. static const uint32_t sCount; // The name table entries in the hash. // The value of sEntries is generated by Codegen.py in RegisterBindings.cpp. static const WebIDLNameTableEntry sEntries[];
--- a/dom/bindings/test/mochitest.ini +++ b/dom/bindings/test/mochitest.ini @@ -40,17 +40,16 @@ support-files = [test_exceptions_from_jsimplemented.html] tags = webrtc [test_lenientThis.html] [test_lookupGetter.html] [test_namedNoIndexed.html] [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] skip-if = debug == false [test_sequence_wrapping.html] subsuite = gpu [test_setWithNamedGetterNoNamedSetter.html] [test_throwing_method_noDCE.html]
deleted file mode 100644 --- a/dom/bindings/test/test_queryInterface.html +++ /dev/null @@ -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>
--- a/dom/file/FileReader.cpp +++ b/dom/file/FileReader.cpp @@ -204,19 +204,19 @@ void FileReader::OnLoadEndArrayBuffer() JS::Rooted<JSObject*> exceptionObject(cx, &exceptionValue.toObject()); JSErrorReport* er = JS_ErrorFromException(cx, exceptionObject); if (!er || er->message()) { FreeDataAndDispatchError(NS_ERROR_OUT_OF_MEMORY); return; } 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()); nsAutoCString errorNameC = NS_LossyConvertUTF16toASCII(errorName); // XXX Code selected arbitrarily mError = new DOMException(NS_ERROR_DOM_INVALID_STATE_ERR, errorMsg, errorNameC, DOMException_Binding::INVALID_STATE_ERR);
new file mode 100644 --- /dev/null +++ b/dom/indexedDB/test/gtest/TestKey.cpp @@ -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
--- a/dom/indexedDB/test/gtest/moz.build +++ b/dom/indexedDB/test/gtest/moz.build @@ -1,15 +1,21 @@ # 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/. 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' LOCAL_INCLUDES += [ '/dom/indexedDB', ]
--- a/dom/indexedDB/test/test_third_party.html +++ b/dom/indexedDB/test/test_third_party.html @@ -66,18 +66,24 @@ }; }); } function messageListener(event) { // 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(); if (testIndex < testData.length - 1) { testIndex++; openWindow(); return; }
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -92,27 +92,29 @@ #include "mozilla/widget/ScreenManager.h" #include "mozilla/widget/WidgetMessageUtils.h" #include "nsBaseDragService.h" #include "mozilla/media/MediaChild.h" #include "mozilla/BasePrincipal.h" #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" #include "imgLoader.h" #include "GMPServiceChild.h" #include "nsISimpleEnumerator.h" #include "nsIStringBundle.h" #include "nsIWorkerDebuggerManager.h" #include "nsGeolocation.h" #include "audio_thread_priority.h" #include "nsIConsoleService.h" +#include "audio_thread_priority.h" #if !defined(XP_WIN) # include "mozilla/Omnijar.h" #endif #ifdef MOZ_GECKO_PROFILER # include "ChildProfilerController.h" #endif @@ -1771,24 +1773,24 @@ mozilla::ipc::IPCResult ContentChild::Re #if defined(MOZ_SANDBOX) bool sandboxEnabled = true; # if defined(XP_LINUX) // On Linux, we have to support systems that can't use any sandboxing. if (!SandboxInfo::Get().CanSandboxContent()) { 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) { sandboxEnabled = SetContentProcessSandbox( ContentProcessSandboxParams::ForThisProcess(aBroker)); } # elif defined(XP_WIN) mozilla::SandboxTarget::Instance()->StartSandbox();
--- a/dom/media/AudioStream.cpp +++ b/dom/media/AudioStream.cpp @@ -14,16 +14,17 @@ #include "mozilla/Mutex.h" #include "mozilla/Sprintf.h" #include "mozilla/Unused.h" #include <algorithm> #include "mozilla/Telemetry.h" #include "CubebUtils.h" #include "nsPrintfCString.h" #include "AudioConverter.h" +#include "UnderrunHandler.h" #if defined(XP_WIN) # include "nsXULAppAPI.h" #endif #include "Tracing.h" namespace mozilla { #undef LOG @@ -561,16 +562,20 @@ void AudioStream::GetTimeStretched(Audio } long AudioStream::DataCallback(void* aBuffer, long aFrames) { TRACE_AUDIO_CALLBACK_BUDGET(aFrames, mAudioClock.GetInputRate()); TRACE_AUDIO_CALLBACK(); 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), mOutChannels, aFrames); if (mPrefillQuirk) { // Don't consume audio data until Start() is called. // Expected only with cubeb winmm backend.
--- a/dom/media/CubebUtils.cpp +++ b/dom/media/CubebUtils.cpp @@ -76,19 +76,16 @@ struct AudioIpcInitParams { // These functions are provided by audioipc-server crate extern void* audioipc_server_start(const char*, const char*); extern mozilla::ipc::FileDescriptor::PlatformHandleType audioipc_server_new_client(void*); 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 { namespace { LazyLogModule gCubebLog("cubeb"); @@ -440,28 +437,16 @@ ipc::FileDescriptor CreateAudioIPCConnec close(rawFD); # endif return fd; #else return ipc::FileDescriptor(); #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) { // Pref set such that we should return a null context MOZ_LOG(gCubebLog, LogLevel::Debug, ("%s: returning null context due to %s!", __func__, PREF_CUBEB_FORCE_NULL_CONTEXT)); return nullptr;
--- a/dom/media/CubebUtils.h +++ b/dom/media/CubebUtils.h @@ -18,19 +18,16 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(cu namespace mozilla { namespace CubebUtils { 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. void ShutdownLibrary(); // Returns the maximum number of channels supported by the audio hardware. uint32_t MaxNumberOfChannels();
--- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -893,16 +893,28 @@ long AudioCallbackDriver::DataCallback(c // Callback any observers for the AEC speaker data. Note that one // (maybe) of these will be full-duplex, the others will get their input // data off separate cubeb callbacks. Take care with how stuff is // removed/added to this list and TSAN issues, but input and output will // use separate callback methods. 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 // or another driver has control of the graph. mShouldFallbackIfError = false; RemoveMixerCallback(); // Update the flag before handing over the graph and going to drain. mAudioThreadRunning = false; @@ -1008,44 +1020,42 @@ void AudioCallbackDriver::PanOutputIfNee return; } if (!strncmp(name, "MacBookPro", 10)) { if (cubeb_stream_get_current_device(mAudioStream, &out) == CUBEB_OK) { // 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); } } #endif } void AudioCallbackDriver::DeviceChangedCallback() { MOZ_ASSERT(!OnGraphThread()); // Tell the audio engine the device has changed, it might want to reset some // state. 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 } uint32_t AudioCallbackDriver::IterationDuration() { MOZ_ASSERT(OnGraphThread()); // The real fix would be to have an API in cubeb to give us the number. Short // of that, we approximate it here. bug 1019507 return mIterationDurationMS;
--- a/dom/media/GraphDriver.h +++ b/dom/media/GraphDriver.h @@ -529,16 +529,22 @@ class AudioCallbackDriver : public Graph * After transitioning to false on the last DataCallback(), the stream is * not accessed from another thread until the graph thread either signals * main thread cleanup or dispatches an event to switch to another * driver. */ bool mShouldFallbackIfError; /* 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 { public: AsyncCubebTask(AudioCallbackDriver* aDriver, AsyncCubebOperation aOperation); nsresult Dispatch(uint32_t aFlags = NS_DISPATCH_NORMAL) { return mDriver->mInitShutdownThread->Dispatch(this, aFlags);
--- a/dom/media/MediaTrackGraph.cpp +++ b/dom/media/MediaTrackGraph.cpp @@ -29,16 +29,17 @@ #include "VideoFrameContainer.h" #include "mozilla/AbstractThread.h" #include "mozilla/StaticPrefs_dom.h" #include "mozilla/Unused.h" #include "mtransport/runnable_utils.h" #include "VideoUtils.h" #include "GraphRunner.h" #include "Tracing.h" +#include "UnderrunHandler.h" #include "webaudio/blink/DenormalDisabler.h" #include "webaudio/blink/HRTFDatabaseLoader.h" using namespace mozilla::layers; using namespace mozilla::dom; using namespace mozilla::gfx; using namespace mozilla::media; @@ -1292,16 +1293,20 @@ bool MediaTrackGraphImpl::OneIteration(G } return OneIterationImpl(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 // graphs that have not started. MOZ_DIAGNOSTIC_ASSERT(mLifecycleState <= LIFECYCLE_RUNNING); MOZ_ASSERT(OnGraphThread()); WebCore::DenormalDisabler disabler;
new file mode 100644 --- /dev/null +++ b/dom/media/UnderrunHandler.h @@ -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_
new file mode 100644 --- /dev/null +++ b/dom/media/UnderrunHandlerLinux.cpp @@ -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
new file mode 100644 --- /dev/null +++ b/dom/media/UnderrunHandlerNoop.cpp @@ -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
--- a/dom/media/VideoFrameContainer.cpp +++ b/dom/media/VideoFrameContainer.cpp @@ -6,16 +6,17 @@ #include "VideoFrameContainer.h" #ifdef MOZ_WIDGET_ANDROID #include "GLImages.h" // for SurfaceTextureImage #endif #include "MediaDecoderOwner.h" #include "mozilla/Telemetry.h" +#include "mozilla/AbstractThread.h" using namespace mozilla::layers; namespace mozilla { static LazyLogModule gVideoFrameContainerLog("VideoFrameContainer"); #define CONTAINER_LOG(type, msg) MOZ_LOG(gVideoFrameContainerLog, type, msg) #define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead
--- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -181,16 +181,17 @@ EXPORTS += [ 'VideoUtils.h', 'VorbisUtils.h', 'WavDumper.h', 'XiphExtradata.h', ] EXPORTS.mozilla += [ 'MediaManager.h', + 'UnderrunHandler.h', ] EXPORTS.mozilla.media.webrtc += [ 'webrtc/WebrtcGlobal.h', 'webrtc/WebrtcIPCTraits.h', ] if not CONFIG['MOZ_WEBRTC']: @@ -297,16 +298,21 @@ UNIFIED_SOURCES += [ 'VideoStreamTrack.cpp', 'VideoTrack.cpp', 'VideoTrackList.cpp', 'VideoUtils.cpp', 'WebVTTListener.cpp', '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', 'AudioNotificationSender.h', ] SOURCES += [ 'AudioNotificationReceiver.cpp', 'AudioNotificationSender.cpp',
--- a/dom/plugins/base/nsNPAPIPlugin.cpp +++ b/dom/plugins/base/nsNPAPIPlugin.cpp @@ -746,17 +746,17 @@ NPUTF8* _utf8fromidentifier(NPIdentifier if (!id) return nullptr; if (!NPIdentifierIsString(id)) { return nullptr; } 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); } int32_t _intfromidentifier(NPIdentifier id) { if (!NS_IsMainThread()) { NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("NPN_intfromidentifier called from the wrong thread\n"));
deleted file mode 100644 --- a/dom/webidl/LegacyQueryInterface.webidl +++ /dev/null @@ -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;
--- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -630,17 +630,16 @@ WEBIDL_FILES = [ 'IntlUtils.webidl', 'IterableIterator.webidl', 'KeyAlgorithm.webidl', 'KeyboardEvent.webidl', 'KeyEvent.webidl', 'KeyframeAnimationOptions.webidl', 'KeyframeEffect.webidl', 'KeyIdsInitData.webidl', - 'LegacyQueryInterface.webidl', 'LinkStyle.webidl', 'LoadURIOptions.webidl', 'Location.webidl', 'MathMLElement.webidl', 'MediaCapabilities.webidl', 'MediaDebugInfo.webidl', 'MediaDeviceInfo.webidl', 'MediaDevices.webidl',
--- a/dom/xbl/test/chrome.ini +++ b/dom/xbl/test/chrome.ini @@ -1,15 +1,13 @@ [DEFAULT] support-files = - file_bug950909.xml file_fieldScopeChain.xml [test_bug378518.xul] skip-if = (verify && debug && (os == 'linux' || os == 'mac')) [test_bug398135.xul] [test_bug398492.xul] [test_bug721452.xul] [test_bug723676.xul] [test_bug772966.xul] -[test_bug950909.xul] [test_bug1086996.xhtml] [test_fieldScopeChain.html]
deleted file mode 100644 --- a/dom/xbl/test/file_bug950909.html +++ /dev/null @@ -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>
deleted file mode 100644 --- a/dom/xbl/test/file_bug950909.xml +++ /dev/null @@ -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>
--- a/dom/xbl/test/mochitest.ini +++ b/dom/xbl/test/mochitest.ini @@ -8,17 +8,16 @@ support-files = file_bug379959_data.html file_bug379959_xbl.xml file_bug397934.xhtml file_bug481558.xbl file_bug481558css.sjs file_bug591198_inner.html file_bug591198_xbl.xml file_bug844783.xhtml - file_bug950909.html [test_bug310107.html] [test_bug366770.html] [test_bug371724.xhtml] [test_bug372769.html] [test_bug378866.xhtml] [test_bug379959.html] [test_bug389322.xhtml]
deleted file mode 100644 --- a/dom/xbl/test/test_bug950909.xul +++ /dev/null @@ -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>
deleted file mode 100644 --- a/dom/xul/crashtests/429085-1.xhtml +++ /dev/null @@ -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>
--- a/dom/xul/crashtests/crashtests.list +++ b/dom/xul/crashtests/crashtests.list @@ -12,14 +12,13 @@ load 354611-1.html skip-if(!xbl) load 360078-1.xhtml load chrome://reftest/content/crashtests/dom/xul/crashtests/363791-1.xul load chrome://reftest/content/crashtests/dom/xul/crashtests/384740-1.xul load 384877-1.html 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 skip-if(!xbl) load chrome://reftest/content/crashtests/dom/xul/crashtests/468211-2.xul skip-if(!xbl) load chrome://reftest/content/crashtests/dom/xul/crashtests/468211-3.xul
--- a/gfx/webrender_bindings/DCLayerTree.cpp +++ b/gfx/webrender_bindings/DCLayerTree.cpp @@ -37,17 +37,19 @@ UniquePtr<DCLayerTree> DCLayerTree::Crea if (!layerTree->Initialize(aHwnd)) { return nullptr; } return layerTree; } DCLayerTree::DCLayerTree(IDCompositionDevice2* aCompositionDevice) - : mCompositionDevice(aCompositionDevice) {} + : mCompositionDevice(aCompositionDevice), + mDebugCounter(false), + mDebugVisualRedrawRegions(false) {} DCLayerTree::~DCLayerTree() {} bool DCLayerTree::Initialize(HWND aHwnd) { HRESULT hr; RefPtr<IDCompositionDesktopDevice> desktopDevice; hr = mCompositionDevice->QueryInterface( @@ -73,28 +75,16 @@ bool DCLayerTree::Initialize(HWND aHwnd) hr = mCompositionDevice->CreateVisual(getter_AddRefs(mDefaultSwapChainVisual)); if (FAILED(hr)) { gfxCriticalNote << "Failed to create DCompositionVisual: " << gfx::hexa(hr); 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. // If no visuals set the interpolation mode, the default for the entire visual // tree is nearest neighbor interpolation. mRootVisual->SetBitmapInterpolationMode( DCOMPOSITION_BITMAP_INTERPOLATION_MODE_LINEAR); return true; @@ -104,11 +94,67 @@ void DCLayerTree::SetDefaultSwapChain(ID mRootVisual->AddVisual(mDefaultSwapChainVisual, TRUE, nullptr); mDefaultSwapChainVisual->SetContent(aSwapChain); // Default SwapChain's visual does not need linear interporation. mDefaultSwapChainVisual->SetBitmapInterpolationMode( DCOMPOSITION_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR); 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
--- a/gfx/webrender_bindings/DCLayerTree.h +++ b/gfx/webrender_bindings/DCLayerTree.h @@ -30,29 +30,36 @@ namespace wr { */ class DCLayerTree { public: static UniquePtr<DCLayerTree> Create(HWND aHwnd); explicit DCLayerTree(IDCompositionDevice2* aCompositionDevice); ~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 } // namespace wr } // namespace mozilla #endif
--- a/gfx/webrender_bindings/RenderCompositorANGLE.cpp +++ b/gfx/webrender_bindings/RenderCompositorANGLE.cpp @@ -401,16 +401,20 @@ void RenderCompositorANGLE::EndFrame() { // window's contents to the VR window. FxROutputHandler* fxrHandler = mWidget->AsWindows()->GetFxrOutputHandler(); if (fxrHandler->TryInitialize(mSwapChain, mDevice)) { fxrHandler->UpdateOutput(mCtx); } } mSwapChain->Present(0, 0); + + if (mDCLayerTree) { + mDCLayerTree->MaybeUpdateDebug(); + } } bool RenderCompositorANGLE::WaitForGPU() { // Note: this waits on the query we inserted in the previous frame, // not the one we just inserted now. Example: // Insert query #1 // Present #1 // (first frame, no wait)
--- a/js/ipc/WrapperOwner.cpp +++ b/js/ipc/WrapperOwner.cpp @@ -23,31 +23,29 @@ using namespace js; using namespace JS; using namespace mozilla; using namespace mozilla::jsipc; 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. nsCString objectTag; // The class name for WrapperOwner::className, below. 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) {} }; WrapperOwner::WrapperOwner() : inactive_(false) {} static inline AuxCPOWData* AuxCPOWDataOf(JSObject* obj) { MOZ_ASSERT(IsCPOW(obj)); return static_cast<AuxCPOWData*>(GetProxyReservedSlot(obj, 1).toPrivate()); @@ -307,27 +305,16 @@ bool WrapperOwner::hasOwn(JSContext* cx, } bool CPOWProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id, MutableHandleValue vp) const { 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()); RootedValue cpowValue(cx); if (!JS_GetProperty(cx, callee, "__cpow__", &cpowValue)) { return false; } @@ -374,80 +361,30 @@ bool WrapperOwner::toString(JSContext* c if (!str) { return false; } args.rval().setString(str); 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); JSVariant receiverVar; if (!toVariant(cx, receiver, &receiverVar)) { return false; } JSIDVariant idVar; if (!toJSIDVariant(cx, id, &idVar)) { 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)) { return ipcfail(cx); } LOG_STACK(); @@ -1141,19 +1078,18 @@ JSObject* WrapperOwner::fromRemoteObject return nullptr; } nextCPOWNumber_ = objId.serialNumber() + 1; // 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)); } if (!JS_WrapObject(cx, &obj)) { return nullptr; }
--- a/js/ipc/WrapperOwner.h +++ b/js/ipc/WrapperOwner.h @@ -62,17 +62,16 @@ class WrapperOwner : public virtual Java bool getPrototypeIfOrdinary(JSContext* cx, JS::HandleObject proxy, bool* isOrdinary, JS::MutableHandleObject protop); js::RegExpShared* regexp_toShared(JSContext* cx, JS::HandleObject proxy); 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 * |prototypeID| at depth |depth|. */ bool domInstanceOf(JSContext* cx, JSObject* obj, int prototypeID, int depth, bool* bp);
--- a/js/public/CharacterEncoding.h +++ b/js/public/CharacterEncoding.h @@ -8,17 +8,17 @@ #define js_CharacterEncoding_h #include "mozilla/Range.h" #include "mozilla/Span.h" #include "js/TypeDecls.h" #include "js/Utility.h" -class JSFlatString; +class JSLinearString; namespace JS { /* * By default, all C/C++ 1-byte-per-character strings passed into the JSAPI * are treated as ISO/IEC 8859-1, also known as Latin-1. That is, each * byte is treated as a 2-byte character, and there is no way to pass in a * string containing characters beyond U+00FF. @@ -278,35 +278,35 @@ LossyUTF8CharsToNewTwoByteCharsZ(JSConte extern JS_PUBLIC_API TwoByteCharsZ LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8, size_t* outlen, arena_id_t destArenaId); /* * 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 * exhausted or too little space is available in |dst| to fit the scalar * value. Lone surrogates are converted to REPLACEMENT CHARACTER. Return * 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); /* * The smallest character encoding capable of fully representing a particular * string. */ enum class SmallestEncoding { ASCII, Latin1, UTF16 };
--- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -258,18 +258,16 @@ class JS_FRIEND_API GCCellPtr { : ptr(checkedCast(nullptr, JS::TraceKind::Null)) {} // Construction from an explicit type. template <typename T> explicit GCCellPtr(T* p) : 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 { JS::TraceKind traceKind = JS::TraceKind(ptr & OutOfLineTraceKindMask); if (uintptr_t(traceKind) != OutOfLineTraceKindMask) { return traceKind; } return outOfLineKind();
--- a/js/rust/build.rs +++ b/js/rust/build.rs @@ -173,17 +173,17 @@ const WHITELIST_TYPES: &'static [&'stati "JSClass", "JSClassOps", "JSContext", "JSErrNum", "JSErrorCallback", "JSErrorFormatString", "JSErrorReport", "JSExnType", - "JSFlatString", + "JSLinearString", "JSFunction", "JSFunctionSpec", "JS::GCDescription", "JSGCInvocationKind", "JSGCMode", "JSGCParamKey", "JS::GCProgress", "JSGCStatus",
--- a/js/rust/src/rust.rs +++ b/js/rust/src/rust.rs @@ -278,17 +278,17 @@ pub trait RootKind { fn rootKind() -> JS::RootKind; } impl RootKind for *mut JSObject { #[inline(always)] 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 } } impl RootKind for *mut JSFunction { #[inline(always)] fn rootKind() -> JS::RootKind { JS::RootKind::Object } }
--- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -577,29 +577,29 @@ static const struct ParamInfo { static bool GCParameter(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); JSString* str = ToString(cx, args.get(0)); if (!str) { return false; } - JSFlatString* flatStr = JS_FlattenString(cx, str); - if (!flatStr) { + JSLinearString* linearStr = JS_EnsureLinearString(cx, str); + if (!linearStr) { return false; } size_t paramIndex = 0; for (;; paramIndex++) { if (paramIndex == ArrayLength(paramMap)) { JS_ReportErrorASCII( cx, "the first argument must be one of:" GC_PARAMETER_ARGS_LIST); return false; } - if (JS_FlatStringEqualsAscii(flatStr, paramMap[paramIndex].name)) { + if (JS_LinearStringEqualsAscii(linearStr, paramMap[paramIndex].name)) { break; } } const ParamInfo& info = paramMap[paramIndex]; JSGCParamKey param = info.param; // Request mode. if (args.length() == 1) { @@ -840,16 +840,18 @@ static bool WasmTextToBinary(JSContext* return false; } if (!args[0].isString()) { ReportUsageErrorASCII(cx, callee, "First argument must be a String"); return false; } + size_t textLen = args[0].toString()->length(); + AutoStableStringChars twoByteChars(cx); if (!twoByteChars.initTwoByte(cx, args[0].toString())) { return false; } bool withOffsets = false; if (args.hasDefined(1)) { if (!args[1].isBoolean()) { @@ -860,18 +862,18 @@ static bool WasmTextToBinary(JSContext* withOffsets = ToBoolean(args[1]); } uintptr_t stackLimit = GetNativeStackLimit(cx); wasm::Bytes bytes; UniqueChars error; wasm::Uint32Vector offsets; - if (!wasm::TextToBinary(twoByteChars.twoByteChars(), stackLimit, &bytes, - &offsets, &error)) { + if (!wasm::TextToBinary(twoByteChars.twoByteChars(), textLen, stackLimit, + &bytes, &offsets, &error)) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_TEXT_FAIL, error.get() ? error.get() : "out of memory"); return false; } RootedObject binary(cx, JS_NewUint8Array(cx, bytes.length())); if (!binary) { @@ -1111,23 +1113,23 @@ static bool InternalConst(JSContext* cx, JS_ReportErrorASCII(cx, "the function takes exactly one argument"); return false; } JSString* str = ToString(cx, args[0]); if (!str) { return false; } - JSFlatString* flat = JS_FlattenString(cx, str); - if (!flat) { - return false; - } - - if (JS_FlatStringEqualsLiteral(flat, - "INCREMENTAL_MARK_STACK_BASE_CAPACITY")) { + JSLinearString* linear = JS_EnsureLinearString(cx, str); + if (!linear) { + return false; + } + + if (JS_LinearStringEqualsLiteral(linear, + "INCREMENTAL_MARK_STACK_BASE_CAPACITY")) { args.rval().setNumber(uint32_t(js::INCREMENTAL_MARK_STACK_BASE_CAPACITY)); } else { JS_ReportErrorASCII(cx, "unknown const name"); return false; } return true; }
--- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -989,17 +989,18 @@ static void BuildConversionPosition(JSCo BuildFunctionTypeSource(cx, funObj, source); break; default: MOZ_ASSERT(!funObj); break; } } -static JSFlatString* GetFieldName(HandleObject structObj, unsigned fieldIndex) { +static JSLinearString* GetFieldName(HandleObject structObj, + unsigned fieldIndex) { const FieldInfoHash* fields = StructType::GetFieldInfo(structObj); for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) { if (r.front().value().mIndex == fieldIndex) { return (&r.front())->key(); } } return nullptr; } @@ -1269,17 +1270,17 @@ static bool ArgumentTypeMismatch(JSConte } static bool CannotConstructError(JSContext* cx, const char* type) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, CTYPESMSG_CANNOT_CONSTRUCT, type); return false; } -static bool DuplicateFieldError(JSContext* cx, Handle<JSFlatString*> name) { +static bool DuplicateFieldError(JSContext* cx, Handle<JSLinearString*> name) { JS::UniqueChars nameStr = JS_EncodeStringToUTF8(cx, name); if (!nameStr) { return false; } JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, CTYPESMSG_DUPLICATE_FIELD, nameStr.get()); return false; @@ -1418,17 +1419,17 @@ static bool FieldDescriptorTypeError(JSC } JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, CTYPESMSG_FIELD_DESC_TYPE, typeStr, propStr.get()); return false; } static bool FieldMissingError(JSContext* cx, JSObject* typeObj, - JSFlatString* name_) { + JSLinearString* name_) { JS::UniqueChars typeBytes; RootedString name(cx, name_); RootedValue typeVal(cx, ObjectValue(*typeObj)); const char* typeStr = CTypesToSourceForError(cx, typeVal, typeBytes); if (!typeStr) { return false; } @@ -3641,17 +3642,17 @@ static bool ImplicitConvert(JSContext* c for (size_t i = 0; i < props.length(); ++i) { id = props[i]; if (!JSID_IS_STRING(id)) { return PropNameNonStringError(cx, id, val, convType, funObj, argIndex); } - JSFlatString* name = JSID_TO_FLAT_STRING(id); + JSLinearString* name = JSID_TO_LINEAR_STRING(id); const FieldInfo* field = StructType::LookupField(cx, targetType, name); if (!field) { return false; } RootedValue prop(cx); if (!JS_GetPropertyById(cx, valObj, id, &prop)) { @@ -5700,18 +5701,18 @@ bool ArrayType::AddressOfElement(JSConte } /******************************************************************************* ** StructType implementation *******************************************************************************/ // For a struct field descriptor 'val' of the form { name : type }, extract // 'name' and 'type'. -static JSFlatString* ExtractStructField(JSContext* cx, HandleValue val, - MutableHandleObject typeObj) { +static JSLinearString* ExtractStructField(JSContext* cx, HandleValue val, + MutableHandleObject typeObj) { if (val.isPrimitive()) { FieldDescriptorNameTypeError(cx, val); return nullptr; } RootedObject obj(cx, &val.toObject()); Rooted<IdVector> props(cx, IdVector(cx)); if (!JS_Enumerate(cx, obj, &props)) { @@ -5745,25 +5746,25 @@ static JSFlatString* ExtractStructField( // choke on a zero-size struct, so we disallow them.) typeObj.set(&propVal.toObject()); size_t size; if (!CType::GetSafeSize(typeObj, &size) || size == 0) { FieldDescriptorSizeError(cx, typeObj, nameid); return nullptr; } - return JSID_TO_FLAT_STRING(nameid); + return JSID_TO_LINEAR_STRING(nameid); } // For a struct field with 'name' and 'type', add an element of the form // { name : type }. static bool AddFieldToArray(JSContext* cx, MutableHandleValue element, - JSFlatString* name_, JSObject* typeObj_) { + JSLinearString* name_, JSObject* typeObj_) { RootedObject typeObj(cx, typeObj_); - Rooted<JSFlatString*> name(cx, name_); + Rooted<JSLinearString*> name(cx, name_); RootedObject fieldObj(cx, JS_NewPlainObject(cx)); if (!fieldObj) { return false; } element.setObject(*fieldObj); AutoStableStringChars nameChars(cx); @@ -5871,17 +5872,18 @@ bool StructType::DefineInternal(JSContex for (uint32_t i = 0; i < len; ++i) { RootedValue item(cx); if (!JS_GetElement(cx, fieldsObj, i, &item)) { return false; } RootedObject fieldType(cx, nullptr); - Rooted<JSFlatString*> name(cx, ExtractStructField(cx, item, &fieldType)); + Rooted<JSLinearString*> name(cx, + ExtractStructField(cx, item, &fieldType)); if (!name) { return false; } // Make sure each field name is unique FieldInfoHash::AddPtr entryPtr = fields.lookupForAdd(name); if (entryPtr) { return DuplicateFieldError(cx, name); @@ -5895,27 +5897,27 @@ bool StructType::DefineInternal(JSContex RootedFunction getter( cx, NewFunctionWithReserved(cx, StructType::FieldGetter, 0, 0, nullptr)); if (!getter) { return false; } SetFunctionNativeReserved(getter, StructType::SLOT_FIELDNAME, - StringValue(JS_FORGET_STRING_FLATNESS(name))); + StringValue(JS_FORGET_STRING_LINEARNESS(name))); RootedObject getterObj(cx, JS_GetFunctionObject(getter)); RootedFunction setter( cx, NewFunctionWithReserved(cx, StructType::FieldSetter, 1, 0, nullptr)); if (!setter) { return false; } SetFunctionNativeReserved(setter, StructType::SLOT_FIELDNAME, - StringValue(JS_FORGET_STRING_FLATNESS(name))); + StringValue(JS_FORGET_STRING_LINEARNESS(name))); RootedObject setterObj(cx, JS_GetFunctionObject(setter)); if (!JS_DefineUCProperty(cx, prototype, nameChars.twoByteChars(), name->length(), getterObj, setterObj, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_GETTER | JSPROP_SETTER)) { return false; } @@ -6192,17 +6194,17 @@ const FieldInfoHash* StructType::GetFiel Value slot = JS_GetReservedSlot(obj, SLOT_FIELDINFO); MOZ_ASSERT(!slot.isUndefined() && slot.toPrivate()); return static_cast<const FieldInfoHash*>(slot.toPrivate()); } const FieldInfo* StructType::LookupField(JSContext* cx, JSObject* obj, - JSFlatString* name) { + JSLinearString* name) { MOZ_ASSERT(CType::IsCType(obj)); MOZ_ASSERT(CType::GetTypeCode(obj) == TYPE_struct); FieldInfoHash::Ptr ptr = GetFieldInfo(obj)->lookup(name); if (ptr) { return &ptr->value(); } @@ -6296,17 +6298,18 @@ bool StructType::FieldGetter(JSContext* JSObject* typeObj = CData::GetCType(obj); if (CType::GetTypeCode(typeObj) != TYPE_struct) { return IncompatibleThisType(cx, "StructType property getter", "non-StructType CData", args.thisv()); } RootedValue nameVal( cx, GetFunctionNativeReserved(&args.callee(), SLOT_FIELDNAME)); - Rooted<JSFlatString*> name(cx, JS_FlattenString(cx, nameVal.toString())); + Rooted<JSLinearString*> name(cx, + JS_EnsureLinearString(cx, nameVal.toString())); if (!name) { return false; } const FieldInfo* field = LookupField(cx, typeObj, name); if (!field) { return false; } @@ -6333,17 +6336,18 @@ bool StructType::FieldSetter(JSContext* RootedObject typeObj(cx, CData::GetCType(obj)); if (CType::GetTypeCode(typeObj) != TYPE_struct) { return IncompatibleThisType(cx, "StructType property setter", "non-StructType CData", args.thisv()); } RootedValue nameVal( cx, GetFunctionNativeReserved(&args.callee(), SLOT_FIELDNAME)); - Rooted<JSFlatString*> name(cx, JS_FlattenString(cx, nameVal.toString())); + Rooted<JSLinearString*> name(cx, + JS_EnsureLinearString(cx, nameVal.toString())); if (!name) { return false; } const FieldInfo* field = LookupField(cx, typeObj, name); if (!field) { return false; } @@ -6380,17 +6384,17 @@ bool StructType::AddressOfField(JSContex ""); } if (!args[0].isString()) { return ArgumentTypeMismatch(cx, "", "StructType.prototype.addressOfField", "a string"); } - JSFlatString* str = JS_FlattenString(cx, args[0].toString()); + JSLinearString* str = JS_EnsureLinearString(cx, args[0].toString()); if (!str) { return false; } const FieldInfo* field = LookupField(cx, typeObj, str); if (!field) { return false; }
--- a/js/src/ctypes/CTypes.h +++ b/js/src/ctypes/CTypes.h @@ -320,18 +320,18 @@ struct UnbarrieredFieldInfo { size_t mIndex; // index of the field in the struct (first is 0) size_t mOffset; // offset of the field in the struct, in bytes }; static_assert(sizeof(UnbarrieredFieldInfo) == sizeof(FieldInfo), "UnbarrieredFieldInfo should be the same as FieldInfo but with " "unbarriered mType"); // Hash policy for FieldInfos. -struct FieldHashPolicy : DefaultHasher<JSFlatString*> { - typedef JSFlatString* Key; +struct FieldHashPolicy : DefaultHasher<JSLinearString*> { + typedef JSLinearString* Key; typedef Key Lookup; template <typename CharT> static uint32_t hash(const CharT* s, size_t n) { uint32_t hash = 0; for (; n > 0; s++, n--) { hash = hash * 33 + *s; } @@ -352,17 +352,17 @@ struct FieldHashPolicy : DefaultHasher<J if (k->length() != l->length()) { return false; } return EqualChars(k, l); } }; -using FieldInfoHash = GCHashMap<js::HeapPtr<JSFlatString*>, FieldInfo, +using FieldInfoHash = GCHashMap<js::HeapPtr<JSLinearString*>, FieldInfo, FieldHashPolicy, ZoneAllocPolicy>; // Descriptor of ABI, return type, argument types, and variadicity for a // FunctionType. struct FunctionInfo { explicit FunctionInfo(JS::Zone* zone) : mArgTypes(zone), mFFITypes(zone) {} // Initialized in NewFunctionInfo when !mIsVariadic, but only later, in @@ -562,17 +562,18 @@ MOZ_MUST_USE bool GetSafeLength(JSObject UniquePtrFFIType BuildFFIType(JSContext* cx, JSObject* obj); } // namespace ArrayType namespace StructType { MOZ_MUST_USE bool DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj); const FieldInfoHash* GetFieldInfo(JSObject* obj); -const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSFlatString* name); +const FieldInfo* LookupField(JSContext* cx, JSObject* obj, + JSLinearString* name); JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj); UniquePtrFFIType BuildFFIType(JSContext* cx, JSObject* obj); } // namespace StructType namespace FunctionType { JSObject* CreateInternal(JSContext* cx, HandleValue abi, HandleValue rtype, const HandleValueArray& args);
--- a/js/src/ctypes/Library.cpp +++ b/js/src/ctypes/Library.cpp @@ -102,28 +102,28 @@ JSObject* Library::Create(JSContext* cx, } if (!path.isString()) { JS_ReportErrorASCII(cx, "open takes a string argument"); return nullptr; } PRLibSpec libSpec; - RootedFlatString pathStr(cx, JS_FlattenString(cx, path.toString())); + RootedLinearString pathStr(cx, JS_EnsureLinearString(cx, path.toString())); if (!pathStr) { return nullptr; } #ifdef XP_WIN // On Windows, converting to native charset may corrupt path string. // So, we have to use Unicode path directly. - AutoStableStringChars pathStrChars(cx); - if (!pathStrChars.initTwoByte(cx, pathStr)) { + JS::UniqueTwoByteChars pathZeroTerminated(JS_CopyStringCharsZ(cx, pathStr)); + if (!pathZeroTerminated) { return nullptr; } - char16ptr_t pathChars = pathStrChars.twoByteChars(); + char16ptr_t pathChars = pathZeroTerminated.get(); libSpec.value.pathname_u = pathChars; libSpec.type = PR_LibSpec_PathnameU; #else // Convert to platform native charset if the appropriate callback has been // provided. JS::UniqueChars pathBytes; if (callbacks && callbacks->unicodeToNative) { AutoStableStringChars pathStrChars(cx);
--- a/js/src/debugger/Object.cpp +++ b/js/src/debugger/Object.cpp @@ -1140,24 +1140,24 @@ bool DebuggerObject::CallData::executeIn cx, comp, DebuggerObject::executeInGlobal(cx, object, chars, bindings, options)); return comp.get().buildCompletionValue(cx, object->owner(), args.rval()); } // Copy a narrow or wide string to a vector, appending a null terminator. template <typename T> static bool CopyStringToVector(JSContext* cx, JSString* str, Vector<T>& chars) { - JSFlatString* flat = str->ensureFlat(cx); - if (!flat) { + JSLinearString* linear = str->ensureLinear(cx); + if (!linear) { return false; } - if (!chars.appendN(0, flat->length() + 1)) { + if (!chars.appendN(0, linear->length() + 1)) { return false; } - CopyChars(chars.begin(), *flat); + CopyChars(chars.begin(), *linear); return true; } bool DebuggerObject::CallData::createSource() { if (!args.requireAtLeast(cx, "Debugger.Object.prototype.createSource", 1)) { return false; }
--- a/js/src/gc/GC.h +++ b/js/src/gc/GC.h @@ -51,16 +51,19 @@ struct MapTypeToFinalizeKind {}; }; FOR_EACH_NONOBJECT_ALLOCKIND(EXPAND_MAPTYPETOFINALIZEKIND) #undef EXPAND_MAPTYPETOFINALIZEKIND } /* namespace gc */ extern void TraceRuntime(JSTracer* trc); +// Trace roots but don't evict the nursery first; used from DumpHeap. +extern void TraceRuntimeWithoutEviction(JSTracer* trc); + extern void ReleaseAllJITCode(JSFreeOp* op); extern void PrepareForDebugGC(JSRuntime* rt); /* Functions for managing cross compartment gray pointers. */ extern void NotifyGCNukeWrapper(JSObject* o);
--- a/js/src/gc/GCInternals.h +++ b/js/src/gc/GCInternals.h @@ -245,28 +245,16 @@ struct MOZ_RAII AutoAssertNoNurseryAlloc #ifdef DEBUG AutoAssertNoNurseryAlloc(); ~AutoAssertNoNurseryAlloc(); #else AutoAssertNoNurseryAlloc() {} #endif }; -// Note that this class does not suppress buffer allocation/reallocation in the -// nursery, only Cells themselves. -class MOZ_RAII AutoSuppressNurseryCellAlloc { - JSContext* cx_; - - public: - explicit AutoSuppressNurseryCellAlloc(JSContext* cx) : cx_(cx) { - cx_->nurserySuppressions_++; - } - ~AutoSuppressNurseryCellAlloc() { cx_->nurserySuppressions_--; } -}; - /* * There are a couple of classes here that serve mostly as "tokens" indicating * that a condition holds. Some functions force the caller to possess such a * token because they would misbehave if the condition were false, and it is * far more clear to make the condition visible at the point where it can be * affected rather than just crashing in an assertion down in the place where * it is relied upon. */
--- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -311,16 +311,25 @@ void js::TraceRuntime(JSTracer* trc) { JSRuntime* rt = trc->runtime(); rt->gc.evictNursery(); AutoPrepareForTracing prep(rt->mainContextFromOwnThread()); gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP); rt->gc.traceRuntime(trc, prep); } +void js::TraceRuntimeWithoutEviction(JSTracer* trc) { + MOZ_ASSERT(!trc->isMarkingTracer()); + + JSRuntime* rt = trc->runtime(); + AutoTraceSession session(rt); + gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP); + rt->gc.traceRuntime(trc, session); +} + void js::gc::GCRuntime::traceRuntime(JSTracer* trc, AutoTraceSession& session) { MOZ_ASSERT(!rt->isBeingDestroyed()); gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS); traceRuntimeAtoms(trc, session); traceRuntimeCommon(trc, TraceRuntime); }
--- a/js/src/gdb/tests/test-JSString.cpp +++ b/js/src/gdb/tests/test-JSString.cpp @@ -1,13 +1,13 @@ #include "gdb-tests.h" #include "vm/JSContext.h" -// When JSGC_ANALYSIS is #defined, Rooted<JSFlatString*> needs the definition -// of JSFlatString in order to figure out its ThingRootKind +// When JSGC_ANALYSIS is #defined, Rooted<JSLinearString*> needs the definition +// of JSLinearString in order to figure out its ThingRootKind #include "vm/StringType.h" FRAGMENT(JSString, simple) { AutoSuppressHazardsForTest noanalysis; JS::Rooted<JSString*> empty(cx, JS_NewStringCopyN(cx, nullptr, 0)); JS::Rooted<JSString*> x(cx, JS_NewStringCopyN(cx, "x", 1)); JS::Rooted<JSString*> z(cx, JS_NewStringCopyZ(cx, "z")); @@ -48,22 +48,22 @@ FRAGMENT(JSString, null) { breakpoint(); use(null); use(nullRaw); } FRAGMENT(JSString, subclasses) { - JS::Rooted<JSFlatString*> flat( - cx, JS_FlattenString(cx, JS_NewStringCopyZ(cx, "Hi!"))); + JS::Rooted<JSLinearString*> linear( + cx, JS_EnsureLinearString(cx, JS_NewStringCopyZ(cx, "Hi!"))); breakpoint(); - use(flat); + use(linear); } FRAGMENT(JSString, atom) { JSAtom* molybdenum = js::Atomize(cx, "molybdenum", 10); breakpoint(); use(molybdenum); }
--- a/js/src/jsapi-tests/testCompileNonSyntactic.cpp +++ b/js/src/jsapi-tests/testCompileNonSyntactic.cpp @@ -1,15 +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/. */ #include "mozilla/Utf8.h" // mozilla::Utf8Unit -#include "gc/GCInternals.h" #include "js/CompilationAndEvaluation.h" // JS::Compile{,ForNonSyntacticScope}{,DontInflate} #include "js/SourceText.h" // JS::Source{Ownership,Text} #include "jsapi-tests/tests.h" #include "vm/HelperThreads.h" #include "vm/Monitor.h" #include "vm/MutexIDs.h" using namespace JS;
--- a/js/src/jsapi-tests/testDeflateStringToUTF8Buffer.cpp +++ b/js/src/jsapi-tests/testDeflateStringToUTF8Buffer.cpp @@ -3,160 +3,160 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "jsapi-tests/tests.h" using namespace JS; BEGIN_TEST(test_DeflateStringToUTF8Buffer) { JSString* str; - JSFlatString* flatStr; + JSLinearString* linearStr; // DeflateStringToUTF8Buffer does not write a null terminator, so the byte // following the last byte written to the |actual| buffer should retain // the value it held before the call to DeflateStringToUTF8Buffer, which is // initialized to 0x1. char actual[100]; auto span = mozilla::MakeSpan(actual); - // Test with an ASCII string, which calls JSFlatString::latin1Chars + // Test with an ASCII string, which calls JSLinearString::latin1Chars // to retrieve the characters from the string and generates UTF-8 output // that is identical to the ASCII input. str = JS_NewStringCopyZ(cx, "Ohai"); // { 0x4F, 0x68, 0x61, 0x69 } MOZ_RELEASE_ASSERT(str); - flatStr = JS_FlattenString(cx, str); + linearStr = JS_EnsureLinearString(cx, str); { const char expected[] = {0x4F, 0x68, 0x61, 0x69, 0x1}; memset(actual, 0x1, 100); - size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span); + size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span); CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0); CHECK_EQUAL(dstlen, 4u); } { const char expected[] = {0x4F, 0x68, 0x61, 0x1}; memset(actual, 0x1, 100); - size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(3)); + size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(3)); CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0); CHECK_EQUAL(dstlen, 3u); } { const unsigned char expected[] = {0x1}; memset(actual, 0x1, 100); - size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(0)); + size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(0)); CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0); CHECK_EQUAL(dstlen, 0u); } - // Test with a Latin-1 string, which calls JSFlatString::latin1Chars + // Test with a Latin-1 string, which calls JSLinearString::latin1Chars // like with the ASCII string but generates UTF-8 output that is different // from the ASCII input. str = JS_NewUCStringCopyZ(cx, u"\xD3\x68\xE3\xEF"); // u"Óhãï" MOZ_RELEASE_ASSERT(str); - flatStr = JS_FlattenString(cx, str); + linearStr = JS_EnsureLinearString(cx, str); { const unsigned char expected[] = {0xC3, 0x93, 0x68, 0xC3, 0xA3, 0xC3, 0xAF, 0x1}; memset(actual, 0x1, 100); - JS::DeflateStringToUTF8Buffer(flatStr, span); + JS::DeflateStringToUTF8Buffer(linearStr, span); CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0); } { const unsigned char expected[] = {0xC3, 0x93, 0x68, 0xC3, 0xA3, 0xC3, 0xAF, 0x1}; memset(actual, 0x1, 100); - size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(7)); + size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(7)); CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0); CHECK_EQUAL(dstlen, 7u); } { // Specify a destination buffer length of 3. That's exactly enough // space to encode the first two characters, which takes three bytes. const unsigned char expected[] = {0xC3, 0x93, 0x68, 0x1}; memset(actual, 0x1, 100); - size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(3)); + size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(3)); CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0); CHECK_EQUAL(dstlen, 3u); } { // Specify a destination buffer length of 4. That's only enough space // to encode the first two characters, which takes three bytes, because // the third character would take another two bytes. const unsigned char expected[] = {0xC3, 0x93, 0x68, 0x1}; memset(actual, 0x1, 100); - size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(4)); + size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(4)); CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0); CHECK_EQUAL(dstlen, 3u); } { const unsigned char expected[] = {0x1}; memset(actual, 0x1, 100); - size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(0)); + size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(0)); CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0); CHECK_EQUAL(dstlen, 0u); } - // Test with a UTF-16 string, which calls JSFlatString::twoByteChars + // Test with a UTF-16 string, which calls JSLinearString::twoByteChars // to retrieve the characters from the string. str = JS_NewUCStringCopyZ(cx, u"\x038C\x0068\x0203\x0457"); // u"Όhȃї" MOZ_RELEASE_ASSERT(str); - flatStr = JS_FlattenString(cx, str); + linearStr = JS_EnsureLinearString(cx, str); { const unsigned char expected[] = {0xCE, 0x8C, 0x68, 0xC8, 0x83, 0xD1, 0x97, 0x1}; memset(actual, 0x1, 100); - JS::DeflateStringToUTF8Buffer(flatStr, span); + JS::DeflateStringToUTF8Buffer(linearStr, span); CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0); } { const unsigned char expected[] = {0xCE, 0x8C, 0x68, 0xC8, 0x83, 0xD1, 0x97, 0x1}; memset(actual, 0x1, 100); - size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(7)); + size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(7)); CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0); CHECK_EQUAL(dstlen, 7u); } { // Specify a destination buffer length of 3. That's exactly enough // space to encode the first two characters, which takes three bytes. const unsigned char expected[] = {0xCE, 0x8C, 0x68, 0x1}; memset(actual, 0x1, 100); - size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(3)); + size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(3)); CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0); CHECK_EQUAL(dstlen, 3u); } { // Specify a destination buffer length of 4. That's only enough space // to encode the first two characters, which takes three bytes, because // the third character would take another two bytes. const unsigned char expected[] = {0xCE, 0x8C, 0x68, 0x1}; memset(actual, 0x1, 100); - size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(4)); + size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(4)); CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0); CHECK_EQUAL(dstlen, 3u); } { const unsigned char expected[] = {0x1}; memset(actual, 0x1, 100); - size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(0)); + size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(0)); CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0); CHECK_EQUAL(dstlen, 0u); } return true; } END_TEST(test_DeflateStringToUTF8Buffer)
--- a/js/src/jsapi-tests/testErrorInterceptor.cpp +++ b/js/src/jsapi-tests/testErrorInterceptor.cpp @@ -100,18 +100,18 @@ BEGIN_TEST(testErrorInterceptor) { // Check the final error. JS::RootedValue exn(cx); CHECK(JS_GetPendingException(cx, &exn)); JS_ClearPendingException(cx); js::JSStringBuilder buffer(cx); CHECK(ValueToStringBuffer(cx, exn, buffer)); - JS::Rooted<JSFlatString*> flat(cx, buffer.finishString()); - CHECK(equalStrings(cx, flat, gLatestMessage)); + JS::Rooted<JSLinearString*> linear(cx, buffer.finishString()); + CHECK(equalStrings(cx, linear, gLatestMessage)); // Cleanup. gLatestMessage = nullptr; } // Test again without callback. JS_SetErrorInterceptorCallback(cx->runtime(), nullptr); for (size_t i = 0; i < mozilla::ArrayLength(SAMPLES); ++i) { @@ -125,18 +125,18 @@ BEGIN_TEST(testErrorInterceptor) { // Check the final error. JS::RootedValue exn(cx); CHECK(JS_GetPendingException(cx, &exn)); JS_ClearPendingException(cx); js::JSStringBuilder buffer(cx); CHECK(ValueToStringBuffer(cx, exn, buffer)); - JS::Rooted<JSFlatString*> flat(cx, buffer.finishString()); - CHECK(js::StringEqualsAscii(flat, TO_STRING[i])); + JS::Rooted<JSLinearString*> linear(cx, buffer.finishString()); + CHECK(js::StringEqualsAscii(linear, TO_STRING[i])); // Cleanup. gLatestMessage = nullptr; } // Cleanup JS_SetErrorInterceptorCallback(cx->runtime(), original); gLatestMessage = nullptr;
--- a/js/src/jsapi-tests/testGCAllocator.cpp +++ b/js/src/jsapi-tests/testGCAllocator.cpp @@ -2,17 +2,16 @@ * vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include <cstdlib> -#include "gc/GCInternals.h" #include "gc/Memory.h" #include "jsapi-tests/tests.h" #if defined(XP_WIN) # include "util/Windows.h" # include <psapi.h> #else # include <algorithm>
--- a/js/src/jsapi-tests/testGCUniqueId.cpp +++ b/js/src/jsapi-tests/testGCUniqueId.cpp @@ -1,16 +1,15 @@ /* -*- 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 "gc/GCInternals.h" #include "js/GCVector.h" #include "jsapi-tests/tests.h" #include "gc/Zone-inl.h" static void MinimizeHeap(JSContext* cx) { // The second collection is to force us to wait for the background
--- a/js/src/jsapi-tests/testIntString.cpp +++ b/js/src/jsapi-tests/testIntString.cpp @@ -8,34 +8,34 @@ #include "jsapi-tests/tests.h" BEGIN_TEST(testIntString_bug515273) { JS::RootedValue v(cx); EVAL("'1';", &v); JSString* str = v.toString(); CHECK(JS_StringHasBeenPinned(cx, str)); - CHECK(JS_FlatStringEqualsLiteral(JS_ASSERT_STRING_IS_FLAT(str), "1")); + CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(str), "1")); EVAL("'42';", &v); str = v.toString(); CHECK(JS_StringHasBeenPinned(cx, str)); - CHECK(JS_FlatStringEqualsLiteral(JS_ASSERT_STRING_IS_FLAT(str), "42")); + CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(str), "42")); EVAL("'111';", &v); str = v.toString(); CHECK(JS_StringHasBeenPinned(cx, str)); - CHECK(JS_FlatStringEqualsLiteral(JS_ASSERT_STRING_IS_FLAT(str), "111")); + CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(str), "111")); /* Test other types of static strings. */ EVAL("'a';", &v); str = v.toString(); CHECK(JS_StringHasBeenPinned(cx, str)); - CHECK(JS_FlatStringEqualsLiteral(JS_ASSERT_STRING_IS_FLAT(str), "a")); + CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(str), "a")); EVAL("'bc';", &v); str = v.toString(); CHECK(JS_StringHasBeenPinned(cx, str)); - CHECK(JS_FlatStringEqualsLiteral(JS_ASSERT_STRING_IS_FLAT(str), "bc")); + CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(str), "bc")); return true; } END_TEST(testIntString_bug515273)
--- a/js/src/jsapi-tests/testLookup.cpp +++ b/js/src/jsapi-tests/testLookup.cpp @@ -44,21 +44,21 @@ bool document_resolve(JSContext* cx, JS: // If id is "all", resolve document.all=true. JS::RootedValue v(cx); if (!JS_IdToValue(cx, id, &v)) { return false; } if (v.isString()) { JSString* str = v.toString(); - JSFlatString* flatStr = JS_FlattenString(cx, str); - if (!flatStr) { + JSLinearString* linearStr = JS_EnsureLinearString(cx, str); + if (!linearStr) { return false; } - if (JS_FlatStringEqualsLiteral(flatStr, "all")) { + if (JS_LinearStringEqualsLiteral(linearStr, "all")) { JS::Rooted<JSObject*> docAll(cx, JS_NewObject(cx, &DocumentAllClass)); if (!docAll) { return false; } JS::Rooted<JS::Value> allValue(cx, JS::ObjectValue(*docAll)); if (!JS_DefinePropertyById(cx, obj, id, allValue, JSPROP_RESOLVING)) { return false;
--- a/js/src/jsapi-tests/testParseJSON.cpp +++ b/js/src/jsapi-tests/testParseJSON.cpp @@ -74,17 +74,17 @@ BEGIN_TEST(testParseJSON_success) { CHECK(TryParse(cx, "1.75", expected)); expected.setDouble(9e9); CHECK(TryParse(cx, "9e9", expected)); expected.setDouble(std::numeric_limits<double>::infinity()); CHECK(TryParse(cx, "9e99999", expected)); - JS::Rooted<JSFlatString*> str(cx); + JS::Rooted<JSLinearString*> str(cx); const char16_t emptystr[] = {'\0'}; str = js::NewStringCopyN<CanGC>(cx, emptystr, 0); CHECK(str); expected = JS::StringValue(str); CHECK(TryParse(cx, "\"\"", expected)); const char16_t nullstr[] = {'\0'}; @@ -147,17 +147,17 @@ BEGIN_TEST(testParseJSON_success) { CHECK(!isArray); CHECK(JS_GetProperty(cx, obj, "f", &v2)); CHECK(v2.isInt32(17)); return true; } template <size_t N> -static JSFlatString* NewString(JSContext* cx, const char16_t (&chars)[N]) { +static JSLinearString* NewString(JSContext* cx, const char16_t (&chars)[N]) { return js::NewStringCopyN<CanGC>(cx, chars, N); } template <size_t N> inline bool Parse(JSContext* cx, const char (&input)[N], JS::MutableHandleValue vp) { AutoInflatedString str(cx); str = input;
--- a/js/src/jsapi-tests/testRegExp.cpp +++ b/js/src/jsapi-tests/testRegExp.cpp @@ -52,13 +52,14 @@ END_TEST(testGetRegExpFlags) BEGIN_TEST(testGetRegExpSource) { JS::RootedValue val(cx); JS::RootedObject obj(cx); EVAL("/foopy/", &val); obj = val.toObjectOrNull(); JSString* source = JS::GetRegExpSource(cx, obj); CHECK(source); - CHECK(JS_FlatStringEqualsLiteral(JS_ASSERT_STRING_IS_FLAT(source), "foopy")); + CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(source), + "foopy")); return true; } END_TEST(testGetRegExpSource)
--- a/js/src/jsapi-tests/testResolveRecursion.cpp +++ b/js/src/jsapi-tests/testResolveRecursion.cpp @@ -65,36 +65,36 @@ struct AutoIncrCounters { bool doResolve(JS::HandleObject obj, JS::HandleId id, bool* resolvedp) { CHECK_EQUAL(resolveExitCount, 0); AutoIncrCounters incr(this); CHECK(obj == obj1 || obj == obj2); CHECK(JSID_IS_STRING(id)); - JSFlatString* str = JS_FlattenString(cx, JSID_TO_STRING(id)); + JSLinearString* str = JS_EnsureLinearString(cx, JSID_TO_STRING(id)); CHECK(str); JS::RootedValue v(cx); - if (JS_FlatStringEqualsLiteral(str, "x")) { + if (JS_LinearStringEqualsLiteral(str, "x")) { if (obj == obj1) { /* First resolve hook invocation. */ CHECK_EQUAL(resolveEntryCount, 1); EVAL("obj2.y = true", &v); CHECK(v.isTrue()); CHECK(JS_DefinePropertyById(cx, obj, id, JS::FalseHandleValue, JSPROP_RESOLVING)); *resolvedp = true; return true; } if (obj == obj2) { CHECK_EQUAL(resolveEntryCount, 4); *resolvedp = false; return true; } - } else if (JS_FlatStringEqualsLiteral(str, "y")) { + } else if (JS_LinearStringEqualsLiteral(str, "y")) { if (obj == obj2) { CHECK_EQUAL(resolveEntryCount, 2); CHECK(JS_DefinePropertyById(cx, obj, id, JS::NullHandleValue, JSPROP_RESOLVING)); EVAL("obj1.x", &v); CHECK(v.isUndefined()); EVAL("obj1.y", &v); CHECK(v.isInt32(0));
--- a/js/src/jsapi-tests/testScriptSourceCompression.cpp +++ b/js/src/jsapi-tests/testScriptSourceCompression.cpp @@ -9,17 +9,17 @@ #include "mozilla/Assertions.h" // MOZ_RELEASE_ASSERT #include "mozilla/Utf8.h" // mozilla::Utf8Unit #include <algorithm> // std::all_of, std::equal, std::move, std::transform #include <memory> // std::uninitialized_fill_n #include <stddef.h> // size_t #include <stdint.h> // uint32_t -#include "jsapi.h" // JS_FlattenString, JS_GC, JS_Get{Latin1,TwoByte}FlatStringChars, JS_GetStringLength, JS_ValueToFunction +#include "jsapi.h" // JS_EnsureLinearString, JS_GC, JS_Get{Latin1,TwoByte}LinearStringChars, JS_GetStringLength, JS_ValueToFunction #include "js/CompilationAndEvaluation.h" // JS::Evaluate{,DontInflate} #include "js/CompileOptions.h" // JS::CompileOptions #include "js/Conversions.h" // JS::ToString #include "js/MemoryFunctions.h" // JS_malloc #include "js/RootingAPI.h" // JS::MutableHandle, JS::Rooted #include "js/SourceText.h" // JS::SourceOwnership, JS::SourceText #include "js/UniquePtr.h" // js::UniquePtr @@ -157,18 +157,18 @@ static void WriteFunctionOfSizeAtOffset( static JSString* DecompressSource(JSContext* cx, JS::Handle<JSFunction*> fun) { JS::Rooted<JS::Value> fval(cx, JS::ObjectValue(*JS_GetFunctionObject(fun))); return JS::ToString(cx, fval); } static bool IsExpectedFunctionString(JS::Handle<JSString*> str, char functionName, JSContext* cx) { - JSFlatString* fstr = JS_FlattenString(cx, str); - MOZ_RELEASE_ASSERT(fstr); + JSLinearString* lstr = JS_EnsureLinearString(cx, str); + MOZ_RELEASE_ASSERT(lstr); size_t len = JS_GetStringLength(str); if (len < FunctionStartLength || len < FunctionEndLength) { return false; } JS::AutoAssertNoGC nogc(cx); @@ -189,20 +189,20 @@ static bool IsExpectedFunctionString(JS: chars + len - FunctionEndLength, [](auto c) { return c == FillerWhitespace; }) && std::equal(chars + len - FunctionEndLength, chars + len, FunctionEnd); }; bool hasExpectedContents; if (JS_StringHasLatin1Chars(str)) { - const JS::Latin1Char* chars = JS_GetLatin1FlatStringChars(nogc, fstr); + const JS::Latin1Char* chars = JS_GetLatin1LinearStringChars(nogc, lstr); hasExpectedContents = CheckContents(chars); } else { - const char16_t* chars = JS_GetTwoByteFlatStringChars(nogc, fstr); + const char16_t* chars = JS_GetTwoByteLinearStringChars(nogc, lstr); hasExpectedContents = CheckContents(chars); } return hasExpectedContents; } BEGIN_TEST(testScriptSourceCompression_inOneChunk) { CHECK(run<char16_t>());
--- a/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp +++ b/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp @@ -14,17 +14,17 @@ using namespace JS; class CustomProxyHandler : public Wrapper { public: CustomProxyHandler() : Wrapper(0) {} bool getOwnPropertyDescriptor( JSContext* cx, HandleObject proxy, HandleId id, MutableHandle<PropertyDescriptor> desc) const override { if (JSID_IS_STRING(id) && - JS_FlatStringEqualsLiteral(JSID_TO_FLAT_STRING(id), "phantom")) { + JS_LinearStringEqualsLiteral(JSID_TO_LINEAR_STRING(id), "phantom")) { desc.object().set(proxy); desc.attributesRef() = JSPROP_ENUMERATE; desc.value().setInt32(42); return true; } return Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc); }
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3268,17 +3268,17 @@ JS_PUBLIC_API JSFunction* JS::NewFunctio cx->check(id); #ifdef DEBUG if (fs->name.isSymbol()) { MOZ_ASSERT(SYMBOL_TO_JSID(cx->wellKnownSymbols().get(fs->name.symbol())) == id); } else { MOZ_ASSERT(JSID_IS_STRING(id) && - StringEqualsAscii(JSID_TO_FLAT_STRING(id), fs->name.string())); + StringEqualsAscii(JSID_TO_LINEAR_STRING(id), fs->name.string())); } #endif // Delay cloning self-hosted functions until they are called. This is // achieved by passing DefineFunction a nullptr JSNative which produces an // interpreted JSFunction where !hasScript. Interpreted call paths then // call InitializeLazyFunctionScript if !hasScript. if (fs->selfHostedName) { @@ -4305,17 +4305,17 @@ JS_PUBLIC_API JSString* JS_AtomizeAndPin JS_PUBLIC_API JSString* JS_AtomizeAndPinUCString(JSContext* cx, const char16_t* s) { return JS_AtomizeAndPinUCStringN(cx, s, js_strlen(s)); } JS_PUBLIC_API size_t JS_GetStringLength(JSString* str) { return str->length(); } -JS_PUBLIC_API bool JS_StringIsFlat(JSString* str) { return str->isFlat(); } +JS_PUBLIC_API bool JS_StringIsLinear(JSString* str) { return str->isLinear(); } JS_PUBLIC_API bool JS_StringHasLatin1Chars(JSString* str) { return str->hasLatin1Chars(); } JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1StringCharsAndLength( JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str, size_t* plength) { @@ -4360,17 +4360,18 @@ JS_PUBLIC_API bool JS_GetStringCharAt(JS if (!linear) { return false; } *res = linear->latin1OrTwoByteChar(index); return true; } -JS_PUBLIC_API char16_t JS_GetFlatStringCharAt(JSFlatString* str, size_t index) { +JS_PUBLIC_API char16_t JS_GetLinearStringCharAt(JSLinearString* str, + size_t index) { return str->latin1OrTwoByteChar(index); } JS_PUBLIC_API bool JS_CopyStringChars(JSContext* cx, mozilla::Range<char16_t> dest, JSString* str) { AssertHeapIsIdleOrStringIsFlat(str); CHECK_THREAD(cx); @@ -4381,55 +4382,58 @@ JS_PUBLIC_API bool JS_CopyStringChars(JS return false; } MOZ_ASSERT(linear->length() <= dest.length()); CopyChars(dest.begin().get(), *linear); return true; } -JS_PUBLIC_API const Latin1Char* JS_GetLatin1InternedStringChars( - const JS::AutoRequireNoGC& nogc, JSString* str) { - MOZ_ASSERT(str->isAtom()); - JSFlatString* flat = str->ensureFlat(nullptr); - if (!flat) { - return nullptr; - } - return flat->latin1Chars(nogc); -} - -JS_PUBLIC_API const char16_t* JS_GetTwoByteInternedStringChars( - const JS::AutoRequireNoGC& nogc, JSString* str) { - MOZ_ASSERT(str->isAtom()); - JSFlatString* flat = str->ensureFlat(nullptr); - if (!flat) { - return nullptr; - } - return flat->twoByteChars(nogc); -} - -extern JS_PUBLIC_API JSFlatString* JS_FlattenString(JSContext* cx, - JSString* str) { +extern JS_PUBLIC_API JS::UniqueTwoByteChars JS_CopyStringCharsZ(JSContext* cx, + JSString* str) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(str); - JSFlatString* flat = str->ensureFlat(cx); - if (!flat) { + + JSLinearString* linear = str->ensureLinear(cx); + if (!linear) { + return nullptr; + } + + size_t len = linear->length(); + + static_assert(js::MaxStringLength < UINT32_MAX, + "len + 1 must not overflow on 32-bit platforms"); + + UniqueTwoByteChars chars(cx->pod_malloc<char16_t>(len + 1)); + if (!chars) { return nullptr; } - return flat; -} - -extern JS_PUBLIC_API const Latin1Char* JS_GetLatin1FlatStringChars( - const JS::AutoRequireNoGC& nogc, JSFlatString* str) { + + CopyChars(chars.get(), *linear); + chars[len] = '\0'; + + return chars; +} + +extern JS_PUBLIC_API JSLinearString* JS_EnsureLinearString(JSContext* cx, + JSString* str) { + AssertHeapIsIdle(); + CHECK_THREAD(cx); + cx->check(str); + return str->ensureLinear(cx); +} + +extern JS_PUBLIC_API const Latin1Char* JS_GetLatin1LinearStringChars( + const JS::AutoRequireNoGC& nogc, JSLinearString* str) { return str->latin1Chars(nogc); } -extern JS_PUBLIC_API const char16_t* JS_GetTwoByteFlatStringChars( - const JS::AutoRequireNoGC& nogc, JSFlatString* str) { +extern JS_PUBLIC_API const char16_t* JS_GetTwoByteLinearStringChars( + const JS::AutoRequireNoGC& nogc, JSLinearString* str) { return str->twoByteChars(nogc); } JS_PUBLIC_API bool JS_CompareStrings(JSContext* cx, JSString* str1, JSString* str2, int32_t* result) { AssertHeapIsIdle(); CHECK_THREAD(cx); @@ -4458,29 +4462,30 @@ JS_PUBLIC_API bool JS_StringEqualsAscii( JSLinearString* linearStr = str->ensureLinear(cx); if (!linearStr) { return false; } *match = StringEqualsAscii(linearStr, asciiBytes, length); return true; } -JS_PUBLIC_API bool JS_FlatStringEqualsAscii(JSFlatString* str, - const char* asciiBytes) { +JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str, + const char* asciiBytes) { return StringEqualsAscii(str, asciiBytes); } -JS_PUBLIC_API bool JS_FlatStringEqualsAscii(JSFlatString* str, - const char* asciiBytes, - size_t length) { +JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str, + const char* asciiBytes, + size_t length) { return StringEqualsAscii(str, asciiBytes, length); } -JS_PUBLIC_API size_t JS_PutEscapedFlatString(char* buffer, size_t size, - JSFlatString* str, char quote) { +JS_PUBLIC_API size_t JS_PutEscapedLinearString(char* buffer, size_t size, + JSLinearString* str, + char quote) { return PutEscapedString(buffer, size, str, quote); } JS_PUBLIC_API size_t JS_PutEscapedString(JSContext* cx, char* buffer, size_t size, JSString* str, char quote) { AssertHeapIsIdle(); JSLinearString* linearStr = str->ensureLinear(cx); @@ -4654,17 +4659,17 @@ JS_PUBLIC_API bool JS::PropertySpecNameE return false; } Symbol* sym = JSID_TO_SYMBOL(id); return sym->isWellKnownSymbol() && sym->code() == name.symbol(); } MOZ_ASSERT(!PropertySpecNameIsDigits(name)); return JSID_IS_ATOM(id) && - JS_FlatStringEqualsAscii(JSID_TO_ATOM(id), name.string()); + JS_LinearStringEqualsAscii(JSID_TO_ATOM(id), name.string()); } JS_PUBLIC_API bool JS_Stringify(JSContext* cx, MutableHandleValue vp, HandleObject replacer, HandleValue space, JSONWriteCallback callback, void* data) { AssertHeapIsIdle(); CHECK_THREAD(cx); cx->check(replacer, space);
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2310,118 +2310,127 @@ extern JS_PUBLIC_API size_t JS_PutEscape * * While getting the length of a string is infallible, getting the chars can * fail. As indicated by the lack of a JSContext parameter, there are two * special cases where getting the chars is infallible: * * The first case is for strings that have been atomized, e.g. directly by * JS_AtomizeAndPinString or implicitly because it is stored in a jsid. * - * The second case is "flat" strings that have been explicitly prepared in a - * fallible context by JS_FlattenString. To catch errors, a separate opaque - * JSFlatString type is returned by JS_FlattenString and expected by - * JS_GetFlatStringChars. Note, though, that this is purely a syntactic - * distinction: the input and output of JS_FlattenString are the same actual - * GC-thing. If a JSString is known to be flat, JS_ASSERT_STRING_IS_FLAT can be - * used to make a debug-checked cast. Example: + * The second case is "linear" strings that have been explicitly prepared in a + * fallible context by JS_EnsureLinearString. To catch errors, a separate opaque + * JSLinearString type is returned by JS_EnsureLinearString and expected by + * JS_Get{Latin1,TwoByte}StringCharsAndLength. Note, though, that this is purely + * a syntactic distinction: the input and output of JS_EnsureLinearString are + * the same actual GC-thing. If a JSString is known to be linear, + * JS_ASSERT_STRING_IS_LINEAR can be used to make a debug-checked cast. Example: * - * // in a fallible context - * JSFlatString* fstr = JS_FlattenString(cx, str); - * if (!fstr) { + * // In a fallible context. + * JSLinearString* lstr = JS_EnsureLinearString(cx, str); + * if (!lstr) { * return false; * } - * MOZ_ASSERT(fstr == JS_ASSERT_STRING_IS_FLAT(str)); + * MOZ_ASSERT(lstr == JS_ASSERT_STRING_IS_LINEAR(str)); * - * // in an infallible context, for the same 'str' + * // In an infallible context, for the same 'str'. * AutoCheckCannotGC nogc; - * const char16_t* chars = JS_GetTwoByteFlatStringChars(nogc, fstr) + * const char16_t* chars = JS_GetTwoByteLinearStringChars(nogc, lstr) * MOZ_ASSERT(chars); * - * Flat strings and interned strings are always null-terminated, so - * JS_FlattenString can be used to get a null-terminated string. + * Note: JS strings (including linear strings and atoms) are not + * null-terminated! * * Additionally, string characters are stored as either Latin1Char (8-bit) * or char16_t (16-bit). Clients can use JS_StringHasLatin1Chars and can then * call either the Latin1* or TwoByte* functions. Some functions like * JS_CopyStringChars and JS_GetStringCharAt accept both Latin1 and TwoByte * strings. */ extern JS_PUBLIC_API size_t JS_GetStringLength(JSString* str); -extern JS_PUBLIC_API bool JS_StringIsFlat(JSString* str); +extern JS_PUBLIC_API bool JS_StringIsLinear(JSString* str); /** Returns true iff the string's characters are stored as Latin1. */ extern JS_PUBLIC_API bool JS_StringHasLatin1Chars(JSString* str); extern JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1StringCharsAndLength( JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str, size_t* length); extern JS_PUBLIC_API const char16_t* JS_GetTwoByteStringCharsAndLength( JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str, size_t* length); extern JS_PUBLIC_API bool JS_GetStringCharAt(JSContext* cx, JSString* str, size_t index, char16_t* res); -extern JS_PUBLIC_API char16_t JS_GetFlatStringCharAt(JSFlatString* str, - size_t index); +extern JS_PUBLIC_API char16_t JS_GetLinearStringCharAt(JSLinearString* str, + size_t index); extern JS_PUBLIC_API const char16_t* JS_GetTwoByteExternalStringChars( JSString* str); extern JS_PUBLIC_API bool JS_CopyStringChars(JSContext* cx, mozilla::Range<char16_t> dest, JSString* str); -extern JS_PUBLIC_API JSFlatString* JS_FlattenString(JSContext* cx, - JSString* str); - -extern JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1FlatStringChars( - const JS::AutoRequireNoGC& nogc, JSFlatString* str); - -extern JS_PUBLIC_API const char16_t* JS_GetTwoByteFlatStringChars( - const JS::AutoRequireNoGC& nogc, JSFlatString* str); - -static MOZ_ALWAYS_INLINE JSFlatString* JSID_TO_FLAT_STRING(jsid id) { +/** + * Copies the string's characters to a null-terminated char16_t buffer. + * + * Returns nullptr on OOM. + */ +extern JS_PUBLIC_API JS::UniqueTwoByteChars JS_CopyStringCharsZ(JSContext* cx, + JSString* str); + +extern JS_PUBLIC_API JSLinearString* JS_EnsureLinearString(JSContext* cx, + JSString* str); + +extern JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1LinearStringChars( + const JS::AutoRequireNoGC& nogc, JSLinearString* str); + +extern JS_PUBLIC_API const char16_t* JS_GetTwoByteLinearStringChars( + const JS::AutoRequireNoGC& nogc, JSLinearString* str); + +static MOZ_ALWAYS_INLINE JSLinearString* JSID_TO_LINEAR_STRING(jsid id) { MOZ_ASSERT(JSID_IS_STRING(id)); - return (JSFlatString*)JSID_TO_STRING(id); + return reinterpret_cast<JSLinearString*>(JSID_TO_STRING(id)); } -static MOZ_ALWAYS_INLINE JSFlatString* JS_ASSERT_STRING_IS_FLAT(JSString* str) { - MOZ_ASSERT(JS_StringIsFlat(str)); - return (JSFlatString*)str; +static MOZ_ALWAYS_INLINE JSLinearString* JS_ASSERT_STRING_IS_LINEAR( + JSString* str) { + MOZ_ASSERT(JS_StringIsLinear(str)); + return reinterpret_cast<JSLinearString*>(str); } -static MOZ_ALWAYS_INLINE JSString* JS_FORGET_STRING_FLATNESS( - JSFlatString* fstr) { - return (JSString*)fstr; +static MOZ_ALWAYS_INLINE JSString* JS_FORGET_STRING_LINEARNESS( + JSLinearString* str) { + return reinterpret_cast<JSString*>(str); } /* - * Additional APIs that avoid fallibility when given a flat string. + * Additional APIs that avoid fallibility when given a linear string. */ -extern JS_PUBLIC_API bool JS_FlatStringEqualsAscii(JSFlatString* str, - const char* asciiBytes); -extern JS_PUBLIC_API bool JS_FlatStringEqualsAscii(JSFlatString* str, - const char* asciiBytes, - size_t length); +extern JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str, + const char* asciiBytes); +extern JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str, + const char* asciiBytes, + size_t length); template <size_t N> -bool JS_FlatStringEqualsLiteral(JSFlatString* str, - const char (&asciiBytes)[N]) { +bool JS_LinearStringEqualsLiteral(JSLinearString* str, + const char (&asciiBytes)[N]) { MOZ_ASSERT(asciiBytes[N - 1] == '\0'); - return JS_FlatStringEqualsAscii(str, asciiBytes, N - 1); + return JS_LinearStringEqualsAscii(str, asciiBytes, N - 1); } -extern JS_PUBLIC_API size_t JS_PutEscapedFlatString(char* buffer, size_t size, - JSFlatString* str, - char quote); +extern JS_PUBLIC_API size_t JS_PutEscapedLinearString(char* buffer, size_t size, + JSLinearString* str, + char quote); /** * Create a dependent string, i.e., a string that owns no character storage, * but that refers to a slice of another string's chars. Dependent strings * are mutable by definition, so the thread safety comments above apply. */ extern JS_PUBLIC_API JSString* JS_NewDependentString(JSContext* cx, JS::HandleString str,
--- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -589,18 +589,18 @@ JSObject* ErrorObject::createConstructor if (!ctor) { return nullptr; } ctor->as<JSFunction>().setExtendedSlot(0, Int32Value(type)); return ctor; } -JS_FRIEND_API JSFlatString* js::GetErrorTypeName(JSContext* cx, - int16_t exnType) { +JS_FRIEND_API JSLinearString* js::GetErrorTypeName(JSContext* cx, + int16_t exnType) { /* * JSEXN_INTERNALERR returns null to prevent that "InternalError: " * is prepended before "uncaught exception: " */ if (exnType < 0 || exnType >= JSEXN_LIMIT || exnType == JSEXN_INTERNALERR || exnType == JSEXN_WARN || exnType == JSEXN_NOTE) { return nullptr; }
--- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -12,17 +12,17 @@ #include "mozilla/TimeStamp.h" #include <stdint.h> #include "builtin/BigInt.h" #include "builtin/MapObject.h" #include "builtin/Promise.h" #include "builtin/TestingFunctions.h" -#include "gc/GCInternals.h" +#include "gc/GC.h" #include "gc/PublicIterators.h" #include "gc/WeakMap.h" #include "js/CharacterEncoding.h" #include "js/Printf.h" #include "js/Proxy.h" #include "js/Wrapper.h" #include "proxy/DeadObjectProxy.h" #include "vm/ArgumentsObject.h" @@ -1109,22 +1109,17 @@ void js::DumpHeap(JSContext* cx, FILE* f mozilla::MallocSizeOf mallocSizeOf) { if (nurseryBehaviour == js::CollectNurseryBeforeDump) { cx->runtime()->gc.evictNursery(JS::GCReason::API); } DumpHeapTracer dtrc(fp, cx, mallocSizeOf); fprintf(dtrc.output, "# Roots.\n"); - { - JSRuntime* rt = cx->runtime(); - js::gc::AutoTraceSession session(rt); - gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP); - rt->gc.traceRuntime(&dtrc, session); - } + TraceRuntimeWithoutEviction(&dtrc); fprintf(dtrc.output, "# Weak maps.\n"); WeakMapBase::traceAllMappings(&dtrc); fprintf(dtrc.output, "==========\n"); dtrc.prefix = "> "; IterateHeapUnbarriered(cx, &dtrc, DumpHeapVisitZone, DumpHeapVisitRealm,
--- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -751,20 +751,16 @@ MOZ_ALWAYS_INLINE size_t GetAtomLength(J // Maximum length of a JS string. This is chosen so that the number of bytes // allocated for a null-terminated TwoByte string still fits in int32_t. static const uint32_t MaxStringLength = (1 << 30) - 2; static_assert((uint64_t(MaxStringLength) + 1) * sizeof(char16_t) <= INT32_MAX, "size of null-terminated JSString char buffer must fit in " "INT32_MAX"); -MOZ_ALWAYS_INLINE size_t GetFlatStringLength(JSFlatString* s) { - return reinterpret_cast<JS::shadow::String*>(s)->length(); -} - MOZ_ALWAYS_INLINE size_t GetLinearStringLength(JSLinearString* s) { return reinterpret_cast<JS::shadow::String*>(s)->length(); } MOZ_ALWAYS_INLINE bool LinearStringHasLatin1Chars(JSLinearString* s) { return reinterpret_cast<JS::shadow::String*>(s)->flags() & JS::shadow::String::LATIN1_CHARS_BIT; } @@ -802,24 +798,16 @@ MOZ_ALWAYS_INLINE const char16_t* GetTwo } return s->nonInlineCharsTwoByte; } MOZ_ALWAYS_INLINE JSLinearString* AtomToLinearString(JSAtom* atom) { return reinterpret_cast<JSLinearString*>(atom); } -MOZ_ALWAYS_INLINE JSFlatString* AtomToFlatString(JSAtom* atom) { - return reinterpret_cast<JSFlatString*>(atom); -} - -MOZ_ALWAYS_INLINE JSLinearString* FlatStringToLinearString(JSFlatString* s) { - return reinterpret_cast<JSLinearString*>(s); -} - MOZ_ALWAYS_INLINE const JS::Latin1Char* GetLatin1AtomChars( const JS::AutoRequireNoGC& nogc, JSAtom* atom) { return GetLatin1LinearStringChars(nogc, AtomToLinearString(atom)); } MOZ_ALWAYS_INLINE const char16_t* GetTwoByteAtomChars( const JS::AutoRequireNoGC& nogc, JSAtom* atom) { return GetTwoByteLinearStringChars(nogc, AtomToLinearString(atom)); @@ -897,20 +885,16 @@ inline bool CopyStringChars(JSContext* c if (!linear) { return false; } CopyLinearStringChars(dest, linear, len, start); return true; } -inline void CopyFlatStringChars(char16_t* dest, JSFlatString* s, size_t len) { - CopyLinearStringChars(dest, FlatStringToLinearString(s), len); -} - /** * Add some or all property keys of obj to the id vector *props. * * The flags parameter controls which property keys are added. Pass a * combination of the following bits: * * JSITER_OWNONLY - Don't also search the prototype chain; only consider * obj's own properties. @@ -1131,18 +1115,18 @@ extern JS_FRIEND_API const DOMCallbacks* extern JS_FRIEND_API JSObject* GetTestingFunctions(JSContext* cx); /* Implemented in jsexn.cpp. */ /** * Get an error type name from a JSExnType constant. * Returns nullptr for invalid arguments and JSEXN_INTERNALERR */ -extern JS_FRIEND_API JSFlatString* GetErrorTypeName(JSContext* cx, - int16_t exnType); +extern JS_FRIEND_API JSLinearString* GetErrorTypeName(JSContext* cx, + int16_t exnType); extern JS_FRIEND_API RegExpShared* RegExpToSharedNonInline( JSContext* cx, JS::HandleObject regexp); /* Implemented in CrossCompartmentWrapper.cpp. */ typedef enum NukeReferencesToWindow { NukeWindowReferences, DontNukeWindowReferences
--- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -60,17 +60,17 @@ struct JSFunctionSpec; struct JSPrincipals; struct JSPropertySpec; struct JSSecurityCallbacks; struct JSStructuredCloneCallbacks; struct JSStructuredCloneReader; struct JSStructuredCloneWriter; class JS_PUBLIC_API JSTracer; -class JSFlatString; +class JSLinearString; template <typename T> struct JSConstScalarSpec; typedef JSConstScalarSpec<double> JSConstDoubleSpec; typedef JSConstScalarSpec<int32_t> JSConstIntegerSpec; namespace js {
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3353,25 +3353,25 @@ struct DisassembleOptionParser { lines(false), recursive(false), sourceNotes(true) {} bool parse(JSContext* cx) { /* Read options off early arguments */ while (argc > 0 && argv[0].isString()) { JSString* str = argv[0].toString(); - JSFlatString* flatStr = JS_FlattenString(cx, str); - if (!flatStr) { - return false; - } - if (JS_FlatStringEqualsLiteral(flatStr, "-l")) { + JSLinearString* linearStr = JS_EnsureLinearString(cx, str); + if (!linearStr) { + return false; + } + if (JS_LinearStringEqualsLiteral(linearStr, "-l")) { lines = true; - } else if (JS_FlatStringEqualsLiteral(flatStr, "-r")) { + } else if (JS_LinearStringEqualsLiteral(linearStr, "-r")) { recursive = true; - } else if (JS_FlatStringEqualsLiteral(flatStr, "-S")) { + } else if (JS_LinearStringEqualsLiteral(linearStr, "-S")) { sourceNotes = false; } else { break; } argv++; argc--; } return true; @@ -4537,23 +4537,23 @@ static bool SetJitCompilerOption(JSConte // Disallow setting JIT options when there are worker threads, to avoid // races. if (workerThreadsLock) { ReportUsageErrorASCII( cx, callee, "Can't set JIT options when there are worker threads."); return false; } - JSFlatString* strArg = JS_FlattenString(cx, args[0].toString()); + JSLinearString* strArg = JS_EnsureLinearString(cx, args[0].toString()); if (!strArg) { return false; } -#define JIT_COMPILER_MATCH(key, string) \ - else if (JS_FlatStringEqualsLiteral(strArg, string)) opt = \ +#define JIT_COMPILER_MATCH(key, string) \ + else if (JS_LinearStringEqualsLiteral(strArg, string)) opt = \ JSJITCOMPILER_##key; JSJitCompilerOption opt = JSJITCOMPILER_NOT_AN_OPTION; if (false) { } JIT_COMPILER_OPTIONS(JIT_COMPILER_MATCH); #undef JIT_COMPILER_MATCH
--- a/js/src/shell/jsshell.cpp +++ b/js/src/shell/jsshell.cpp @@ -67,18 +67,17 @@ bool GenerateInterfaceHelp(JSContext* cx return false; } numEntries++; if (!buf.append(" ", 2)) { return false; } - if (!buf.append(usage.isString() ? usage.toString() - : JSID_TO_FLAT_STRING(id))) { + if (!buf.append(usage.isString() ? usage.toString() : JSID_TO_STRING(id))) { return false; } } RootedString s(cx, buf.finishString()); if (!s || !JS_DefineProperty(cx, obj, "help", s, 0)) { return false; }
--- a/js/src/vm/BytecodeUtil.cpp +++ b/js/src/vm/BytecodeUtil.cpp @@ -24,18 +24,16 @@ #include "jsapi.h" #include "jsnum.h" #include "jstypes.h" #include "jsutil.h" #include "frontend/BytecodeCompiler.h" #include "frontend/SourceNotes.h" -#include "gc/FreeOp.h" -#include "gc/GCInternals.h" #include "js/CharacterEncoding.h" #include "js/Printf.h" #include "js/Symbol.h" #include "util/StringBuffer.h" #include "util/Text.h" #include "vm/BytecodeLocation.h" #include "vm/CodeCoverage.h" #include "vm/EnvironmentObject.h" @@ -2857,41 +2855,53 @@ JS_FRIEND_API JSString* js::GetPCCountSc if (sp.hadOutOfMemory()) { return nullptr; } return NewStringCopyZ<CanGC>(cx, sp.string()); } +struct CollectedScripts { + MutableHandle<ScriptVector> scripts; + bool ok = true; + + explicit CollectedScripts(MutableHandle<ScriptVector> scripts) + : scripts(scripts) {} + + static void consider(JSRuntime* rt, void* data, JSScript* script, + const JS::AutoRequireNoGC& nogc) { + auto self = static_cast<CollectedScripts*>(data); + if (!script->filename()) { + return; + } + if (!self->scripts.append(script)) { + self->ok = false; + } + } +}; + static bool GenerateLcovInfo(JSContext* cx, JS::Realm* realm, GenericPrinter& out) { - JSRuntime* rt = cx->runtime(); - AutoRealmUnchecked ar(cx, realm); // Collect the list of scripts which are part of the current realm. - { js::gc::AutoPrepareForTracing apft(cx); } // Hold the scripts that we have already flushed, to avoid flushing them // twice. using JSScriptSet = GCHashSet<JSScript*>; Rooted<JSScriptSet> scriptsDone(cx, JSScriptSet(cx)); Rooted<ScriptVector> queue(cx, ScriptVector(cx)); - for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) { - for (auto script = zone->cellIter<JSScript>(); !script.done(); - script.next()) { - if (script->realm() != realm || !script->filename()) { - continue; - } - - if (!queue.append(script)) { - return false; - } + + { + CollectedScripts result(&queue); + IterateScripts(cx, realm, &result, &CollectedScripts::consider); + if (!result.ok) { + return false; } } if (queue.length() == 0) { return true; } // Ensure the LCovRealm exists to collect info into.
--- a/js/src/vm/CharacterEncoding.cpp +++ b/js/src/vm/CharacterEncoding.cpp @@ -82,25 +82,25 @@ static size_t GetDeflatedUTF8StringLengt while (v) { v >>= 5; nbytes++; } } return nbytes; } -JS_PUBLIC_API size_t JS::GetDeflatedUTF8StringLength(JSFlatString* s) { +JS_PUBLIC_API size_t JS::GetDeflatedUTF8StringLength(JSLinearString* s) { JS::AutoCheckCannotGC nogc; return s->hasLatin1Chars() ? ::GetDeflatedUTF8StringLength(s->latin1Chars(nogc), s->length()) : ::GetDeflatedUTF8StringLength(s->twoByteChars(nogc), s->length()); } -JS_PUBLIC_API size_t JS::DeflateStringToUTF8Buffer(JSFlatString* src, +JS_PUBLIC_API size_t JS::DeflateStringToUTF8Buffer(JSLinearString* src, mozilla::Span<char> dst) { JS::AutoCheckCannotGC nogc; if (src->hasLatin1Chars()) { auto source = AsChars(MakeSpan(src->latin1Chars(nogc), src->length())); size_t read; size_t written; Tie(read, written) = ConvertLatin1toUtf8Partial(source, dst); Unused << read;
--- a/js/src/vm/ErrorObject.cpp +++ b/js/src/vm/ErrorObject.cpp @@ -176,19 +176,16 @@ JSErrorReport* js::ErrorObject::getOrCre report.column = columnNumber(); // Message. Note that |new Error()| will result in an undefined |message| // slot, so we need to explicitly substitute the empty string in that case. RootedString message(cx, getMessage()); if (!message) { message = cx->runtime()->emptyString; } - if (!message->ensureFlat(cx)) { - return nullptr; - } UniqueChars utf8 = StringToNewUTF8CharsZ(cx, *message); if (!utf8) { return nullptr; } report.initOwnedMessage(utf8.release()); // Cache and return.
--- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -8,17 +8,16 @@ #include "mozilla/Maybe.h" #include "mozilla/ScopeExit.h" #include "mozilla/Unused.h" #include "mozilla/Utf8.h" // mozilla::Utf8Unit #include "builtin/Promise.h" #include "frontend/BytecodeCompilation.h" -#include "gc/GCInternals.h" #include "jit/IonBuilder.h" #include "js/ContextOptions.h" // JS::ContextOptions #include "js/SourceText.h" #include "js/UniquePtr.h" #include "js/Utility.h" #include "threading/CpuCount.h" #include "util/NativeStack.h" #include "vm/ErrorReporting.h"
--- a/js/src/vm/JSContext.h +++ b/js/src/vm/JSContext.h @@ -1331,16 +1331,28 @@ struct MOZ_RAII AutoSetThreadIsSweeping private: JSContext* cx; bool prevState; JS::Zone* prevZone; #endif }; +// Note that this class does not suppress buffer allocation/reallocation in the +// nursery, only Cells themselves. +class MOZ_RAII AutoSuppressNurseryCellAlloc { + JSContext* cx_; + + public: + explicit AutoSuppressNurseryCellAlloc(JSContext* cx) : cx_(cx) { + cx_->nurserySuppressions_++; + } + ~AutoSuppressNurseryCellAlloc() { cx_->nurserySuppressions_--; } +}; + } // namespace gc } /* namespace js */ #define CHECK_THREAD(cx) \ MOZ_ASSERT_IF(cx && !cx->isHelperThreadContext(), \ js::CurrentThreadCanAccessRuntime(cx->runtime()))
--- a/js/src/vm/JSScript.cpp +++ b/js/src/vm/JSScript.cpp @@ -1909,17 +1909,17 @@ class ScriptSource::LoadSourceMatcher { }; /* static */ bool ScriptSource::loadSource(JSContext* cx, ScriptSource* ss, bool* loaded) { return ss->data.match(LoadSourceMatcher(cx, ss, loaded)); } /* static */ -JSFlatString* JSScript::sourceData(JSContext* cx, HandleScript script) { +JSLinearString* JSScript::sourceData(JSContext* cx, HandleScript script) { MOZ_ASSERT(script->scriptSource()->hasSourceText()); return script->scriptSource()->substring(cx, script->sourceStart(), script->sourceEnd()); } bool JSScript::appendSourceDataForToString(JSContext* cx, StringBuffer& buf) { MOZ_ASSERT(scriptSource()->hasSourceText()); return scriptSource()->appendSubstring(cx, buf, toStringStart(), @@ -2204,18 +2204,18 @@ ScriptSource::PinnedUnits<Unit>::PinnedU prev_ = *stack_; *stack_ = this; } } template class ScriptSource::PinnedUnits<Utf8Unit>; template class ScriptSource::PinnedUnits<char16_t>; -JSFlatString* ScriptSource::substring(JSContext* cx, size_t start, - size_t stop) { +JSLinearString* ScriptSource::substring(JSContext* cx, size_t start, + size_t stop) { MOZ_ASSERT(start <= stop); size_t len = stop - start; if (!len) { return cx->emptyString(); } UncompressedSourceCache::AutoHoldEntry holder; @@ -2234,18 +2234,18 @@ JSFlatString* ScriptSource::substring(JS PinnedUnits<char16_t> units(cx, this, holder, start, len); if (!units.asChars()) { return nullptr; } return NewStringCopyN<CanGC>(cx, units.asChars(), len); } -JSFlatString* ScriptSource::substringDontDeflate(JSContext* cx, size_t start, - size_t stop) { +JSLinearString* ScriptSource::substringDontDeflate(JSContext* cx, size_t start, + size_t stop) { MOZ_ASSERT(start <= stop); size_t len = stop - start; if (!len) { return cx->emptyString(); } UncompressedSourceCache::AutoHoldEntry holder; @@ -2300,17 +2300,17 @@ bool ScriptSource::appendSubstring(JSCon return false; } const char16_t* units = pinned.get(); return buf.append(units, len); } } -JSFlatString* ScriptSource::functionBodyString(JSContext* cx) { +JSLinearString* ScriptSource::functionBodyString(JSContext* cx) { MOZ_ASSERT(isFunctionBody()); size_t start = parameterListEnd_ + (sizeof(FunctionConstructorMedialSigils) - 1); size_t stop = length() - (sizeof(FunctionConstructorFinalBrace) - 1); return substring(cx, start, stop); }
--- a/js/src/vm/JSScript.h +++ b/js/src/vm/JSScript.h @@ -1001,24 +1001,25 @@ class ScriptSource { }; public: size_t length() const { MOZ_ASSERT(hasSourceText() || hasBinASTSource()); return data.match(UncompressedLengthMatcher()); } - JSFlatString* substring(JSContext* cx, size_t start, size_t stop); - JSFlatString* substringDontDeflate(JSContext* cx, size_t start, size_t stop); + JSLinearString* substring(JSContext* cx, size_t start, size_t stop); + JSLinearString* substringDontDeflate(JSContext* cx, size_t start, + size_t stop); MOZ_MUST_USE bool appendSubstring(JSContext* cx, js::StringBuffer& buf, size_t start, size_t stop); bool isFunctionBody() { return parameterListEnd_ != 0; } - JSFlatString* functionBodyString(JSContext* cx); + JSLinearString* functionBodyString(JSContext* cx); void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ScriptSourceInfo* info) const; private: // Overwrites |data| with the uncompressed data from |source|. // // This function asserts nothing about |data|. Users should use assertions to @@ -2766,17 +2767,17 @@ class JSScript : public js::BaseScript { bodyScope()->is<js::EvalScope>(); } bool isGlobalCode() const { return bodyScope()->is<js::GlobalScope>(); } // Returns true if the script may read formal arguments on the stack // directly, via lazy arguments or a rest parameter. bool mayReadFrameArgsDirectly(); - static JSFlatString* sourceData(JSContext* cx, JS::HandleScript script); + static JSLinearString* sourceData(JSContext* cx, JS::HandleScript script); MOZ_MUST_USE bool appendSourceDataForToString(JSContext* cx, js::StringBuffer& buf); void setDefaultClassConstructorSpan(js::ScriptSourceObject* sourceObject, uint32_t start, uint32_t end, unsigned line, unsigned column);
--- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -22,17 +22,16 @@ # include <sys/mman.h> #endif #include "jsfriendapi.h" #include "jsmath.h" #include "builtin/Promise.h" #include "gc/FreeOp.h" -#include "gc/GCInternals.h" #include "gc/PublicIterators.h" #include "jit/arm/Simulator-arm.h" #include "jit/arm64/vixl/Simulator-vixl.h" #include "jit/IonBuilder.h" #include "jit/JitRealm.h" #include "jit/mips32/Simulator-mips32.h" #include "jit/mips64/Simulator-mips64.h" #include "js/Date.h"
--- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -2870,17 +2870,17 @@ static bool CloneProperties(JSContext* c !JS_DefinePropertyById(cx, clone, id, val, attrs[i])) { return false; } } return true; } -static JSString* CloneString(JSContext* cx, JSFlatString* selfHostedString) { +static JSString* CloneString(JSContext* cx, JSLinearString* selfHostedString) { size_t len = selfHostedString->length(); { JS::AutoCheckCannotGC nogc; JSString* clone; if (selfHostedString->hasLatin1Chars()) { clone = NewStringCopyN<NoGC>(cx, selfHostedString->latin1Chars(nogc), len); } else { @@ -2994,20 +2994,20 @@ static JSObject* CloneObject(JSContext* } else if (selfHostedObject->is<BooleanObject>()) { clone = BooleanObject::create( cx, selfHostedObject->as<BooleanObject>().unbox()); } else if (selfHostedObject->is<NumberObject>()) { clone = NumberObject::create(cx, selfHostedObject->as<NumberObject>().unbox()); } else if (selfHostedObject->is<StringObject>()) { JSString* selfHostedString = selfHostedObject->as<StringObject>().unbox(); - if (!selfHostedString->isFlat()) { + if (!selfHostedString->isLinear()) { MOZ_CRASH(); } - RootedString str(cx, CloneString(cx, &selfHostedString->asFlat())); + RootedString str(cx, CloneString(cx, &selfHostedString->asLinear())); if (!str) { return nullptr; } clone = StringObject::create(cx, str); } else if (selfHostedObject->is<ArrayObject>()) { clone = NewDenseEmptyArray(cx, nullptr, TenuredObject); } else { MOZ_ASSERT(selfHostedObject->isNative()); @@ -3035,20 +3035,20 @@ static bool CloneValue(JSContext* cx, Ha return false; } vp.setObject(*clone); } else if (selfHostedValue.isBoolean() || selfHostedValue.isNumber() || selfHostedValue.isNullOrUndefined()) { // Nothing to do here: these are represented inline in the value. vp.set(selfHostedValue); } else if (selfHostedValue.isString()) { - if (!selfHostedValue.toString()->isFlat()) { + if (!selfHostedValue.toString()->isLinear()) { MOZ_CRASH(); } - JSFlatString* selfHostedString = &selfHostedValue.toString()->asFlat(); + JSLinearString* selfHostedString = &selfHostedValue.toString()->asLinear(); JSString* clone = CloneString(cx, selfHostedString); if (!clone) { return false; } vp.setString(clone); } else if (selfHostedValue.isSymbol()) { // Well-known symbols are shared. mozilla::DebugOnly<JS::Symbol*> sym = selfHostedValue.toSymbol();
--- a/js/src/vm/StringType.cpp +++ b/js/src/vm/StringType.cpp @@ -23,17 +23,16 @@ #include "mozilla/Vector.h" #include <algorithm> // std::{all_of,copy_n,enable_if,is_const,move} #include <type_traits> // std::is_unsigned #include "jsfriendapi.h" #include "frontend/BytecodeCompiler.h" -#include "gc/GCInternals.h" #include "gc/Marking.h" #include "gc/Nursery.h" #include "js/CharacterEncoding.h" #include "js/StableStringChars.h" #include "js/Symbol.h" #include "js/UbiNode.h" #include "util/StringBuffer.h" #include "util/Unicode.h"
--- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -75,17 +75,17 @@ const char* js::TypeIdStringImpl(jsid id return "(new)"; } if (JSID_IS_SYMBOL(id)) { return "(symbol)"; } static char bufs[4][100]; static unsigned which = 0; which = (which + 1) & 3; - PutEscapedString(bufs[which], 100, JSID_TO_FLAT_STRING(id), 0); + PutEscapedString(bufs[which], 100, JSID_TO_LINEAR_STRING(id), 0); return bufs[which]; } #endif ///////////////////////////////////////////////////////////////////// // Logging /////////////////////////////////////////////////////////////////////
--- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -6899,17 +6899,17 @@ static bool HandleInstantiationFailure(J if (!haveSource) { JS_ReportErrorASCII(cx, "asm.js link failure with source discarding enabled"); return false; } uint32_t begin = metadata.toStringStart; uint32_t end = metadata.srcEndAfterCurly(); - Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end)); + Rooted<JSLinearString*> src(cx, source->substringDontDeflate(cx, begin, end)); if (!src) { return false; } RootedFunction fun( cx, NewScriptedFunction(cx, 0, FunctionFlags::INTERPRETED_NORMAL, name, /* proto = */ nullptr, gc::AllocKind::FUNCTION, TenuredObject)); @@ -7244,17 +7244,17 @@ JSString* js::AsmJSModuleToString(JSCont } if (fun->explicitName() && !out.append(fun->explicitName())) { return nullptr; } if (!out.append("() {\n [native code]\n}")) { return nullptr; } } else { - Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end)); + Rooted<JSLinearString*> src(cx, source->substring(cx, begin, end)); if (!src) { return nullptr; } if (!out.append(src)) { return nullptr; } } @@ -7294,17 +7294,17 @@ JSString* js::AsmJSFunctionToString(JSCo MOZ_ASSERT(fun->explicitName()); if (!out.append(fun->explicitName())) { return nullptr; } if (!out.append("() {\n [native code]\n}")) { return nullptr; } } else { - Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end)); + Rooted<JSLinearString*> src(cx, source->substring(cx, begin, end)); if (!src) { return nullptr; } if (!out.append(src)) { return nullptr; } }
--- a/js/src/wasm/WasmJS.cpp +++ b/js/src/wasm/WasmJS.cpp @@ -1013,27 +1013,28 @@ bool WasmModuleObject::customSections(JS Vector<char, 8> name(cx); { RootedString str(cx, ToString(cx, args.get(1))); if (!str) { return false; } - Rooted<JSFlatString*> flat(cx, str->ensureFlat(cx)); - if (!flat) { + Rooted<JSLinearString*> linear(cx, str->ensureLinear(cx)); + if (!linear) { return false; } - if (!name.initLengthUninitialized(JS::GetDeflatedUTF8StringLength(flat))) { + if (!name.initLengthUninitialized( + JS::GetDeflatedUTF8StringLength(linear))) { return false; } mozilla::Unused << JS::DeflateStringToUTF8Buffer( - flat, MakeSpan(name.begin(), name.length())); + linear, MakeSpan(name.begin(), name.length())); } RootedValueVector elems(cx); RootedArrayBufferObject buf(cx); for (const CustomSection& cs : module->customSections()) { if (name.length() != cs.name.length()) { continue; }
--- a/js/src/wasm/WasmTextToBinary.cpp +++ b/js/src/wasm/WasmTextToBinary.cpp @@ -616,19 +616,19 @@ class WasmTokenStream { WasmToken fail(const char16_t* begin) const { return WasmToken(begin); } WasmToken nan(const char16_t* begin); WasmToken literal(const char16_t* begin); WasmToken next(); void skipSpaces(); public: - explicit WasmTokenStream(const char16_t* text) + explicit WasmTokenStream(const char16_t* text, size_t textLen) : cur_(text), - end_(text + js_strlen(text)), + end_(text + textLen), lineStart_(text), line_(1), lookaheadIndex_(0), lookaheadDepth_(0) {} void generateError(WasmToken token, UniqueChars* error) { unsigned column = token.begin() - lineStart_ + 1; *error = JS_smprintf("parsing wasm text at %u:%u", line_, column); } @@ -2298,19 +2298,19 @@ struct WasmParseContext { WasmTokenStream ts; LifoAlloc& lifo; UniqueChars* error; DtoaState* dtoaState; uintptr_t stackLimit; uint32_t nextSym; bool requiresDataCount; - WasmParseContext(const char16_t* text, uintptr_t stackLimit, LifoAlloc& lifo, - UniqueChars* error) - : ts(text), + WasmParseContext(const char16_t* text, size_t textLen, uintptr_t stackLimit, + LifoAlloc& lifo, UniqueChars* error) + : ts(text, textLen), lifo(lifo), error(error), dtoaState(NewDtoaState()), stackLimit(stackLimit), nextSym(0), requiresDataCount(false) {} ~WasmParseContext() { DestroyDtoaState(dtoaState); } @@ -5266,20 +5266,20 @@ static AstModule* ParseBinaryModule(Wasm auto* data = new (c.lifo) AstDataSegment(nullptr, std::move(fragments)); if (!data || !module->append(data)) { return nullptr; } return module; } -static AstModule* ParseModule(const char16_t* text, uintptr_t stackLimit, - LifoAlloc& lifo, UniqueChars* error, - bool* binary) { - WasmParseContext c(text, stackLimit, lifo, error); +static AstModule* ParseModule(const char16_t* text, size_t textLen, + uintptr_t stackLimit, LifoAlloc& lifo, + UniqueChars* error, bool* binary) { + WasmParseContext c(text, textLen, stackLimit, lifo, error); *binary = false; if (!c.ts.match(WasmToken::OpenParen, c.error)) { return nullptr; } if (!c.ts.match(WasmToken::Module, c.error)) { return nullptr; @@ -7625,23 +7625,24 @@ static bool EncodeBinaryModule(const Ast } } return true; } /*****************************************************************************/ -bool wasm::TextToBinary(const char16_t* text, uintptr_t stackLimit, - Bytes* bytes, Uint32Vector* offsets, - UniqueChars* error) { +bool wasm::TextToBinary(const char16_t* text, size_t textLen, + uintptr_t stackLimit, Bytes* bytes, + Uint32Vector* offsets, UniqueChars* error) { LifoAlloc lifo(AST_LIFO_DEFAULT_CHUNK_SIZE); bool binary = false; - AstModule* module = ParseModule(text, stackLimit, lifo, error, &binary); + AstModule* module = + ParseModule(text, textLen, stackLimit, lifo, error, &binary); if (!module) { return false; } if (binary) { return EncodeBinaryModule(*module, bytes); }
--- a/js/src/wasm/WasmTextToBinary.h +++ b/js/src/wasm/WasmTextToBinary.h @@ -20,20 +20,20 @@ #define wasm_text_to_binary_h #include "wasm/WasmTypes.h" namespace js { namespace wasm { // Translate the textual representation of a wasm module (given by a -// null-terminated char16_t array) into serialized bytes. If there is an error +// char16_t array + length) into serialized bytes. If there is an error // other than out-of-memory an error message string will be stored in 'error'. -extern MOZ_MUST_USE bool TextToBinary(const char16_t* text, +extern MOZ_MUST_USE bool TextToBinary(const char16_t* text, size_t textLen, uintptr_t stackLimit, Bytes* bytes, Uint32Vector* offsets, UniqueChars* error); } // namespace wasm } // namespace js #endif // wasm_text_to_binary_h
--- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -811,78 +811,78 @@ bool xpc::GlobalProperties::Parse(JSCont for (uint32_t i = 0; i < length; i++) { RootedValue nameValue(cx); ok = JS_GetElement(cx, obj, i, &nameValue); NS_ENSURE_TRUE(ok, false); if (!nameValue.isString()) { JS_ReportErrorASCII(cx, "Property names must be strings"); return false; } - JSFlatString* nameStr = JS_FlattenString(cx, nameValue.toString()); + JSLinearString* nameStr = JS_EnsureLinearString(cx, nameValue.toString()); if (!nameStr) { return false; } - if (JS_FlatStringEqualsLiteral(nameStr, "Blob")) { + if (JS_LinearStringEqualsLiteral(nameStr, "Blob")) { Blob = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "ChromeUtils")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "ChromeUtils")) { ChromeUtils = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "CSS")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "CSS")) { CSS = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "CSSRule")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "CSSRule")) { CSSRule = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "Directory")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "Directory")) { Directory = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "DOMParser")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "DOMParser")) { DOMParser = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "Element")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "Element")) { Element = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "Event")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "Event")) { Event = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "File")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "File")) { File = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "FileReader")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "FileReader")) { FileReader = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "FormData")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "FormData")) { FormData = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "InspectorUtils")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "InspectorUtils")) { InspectorUtils = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "MessageChannel")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "MessageChannel")) { MessageChannel = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "Node")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "Node")) { Node = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "NodeFilter")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "NodeFilter")) { NodeFilter = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "PromiseDebugging")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "PromiseDebugging")) { PromiseDebugging = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "TextDecoder")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "TextDecoder")) { TextDecoder = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "TextEncoder")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "TextEncoder")) { TextEncoder = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "URL")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "URL")) { URL = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "URLSearchParams")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "URLSearchParams")) { URLSearchParams = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "XMLHttpRequest")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "XMLHttpRequest")) { XMLHttpRequest = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "XMLSerializer")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "XMLSerializer")) { XMLSerializer = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "atob")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "atob")) { atob = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "btoa")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "btoa")) { btoa = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "caches")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "caches")) { caches = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "crypto")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "crypto")) { crypto = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "fetch")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "fetch")) { fetch = true; - } else if (JS_FlatStringEqualsLiteral(nameStr, "indexedDB")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "indexedDB")) { indexedDB = true; #ifdef MOZ_WEBRTC - } else if (JS_FlatStringEqualsLiteral(nameStr, "rtcIdentityProvider")) { + } else if (JS_LinearStringEqualsLiteral(nameStr, "rtcIdentityProvider")) { rtcIdentityProvider = true; #endif } else { RootedString nameStr(cx, nameValue.toString()); JS::UniqueChars name = JS_EncodeStringToUTF8(cx, nameStr); if (!name) { return false; }
--- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -704,26 +704,26 @@ bool XPCConvert::JSData2Native(JSContext } size_t length = JS_GetStringLength(str); if (!length) { rs->Truncate(); return true; } - JSFlatString* flat = JS_FlattenString(cx, str); - if (!flat) { + JSLinearString* linear = JS_EnsureLinearString(cx, str); + if (!linear) { return false; } - size_t utf8Length = JS::GetDeflatedUTF8StringLength(flat); + size_t utf8Length = JS::GetDeflatedUTF8StringLength(linear); rs->SetLength(utf8Length); mozilla::DebugOnly<size_t> written = JS::DeflateStringToUTF8Buffer( - flat, mozilla::MakeSpan(rs->BeginWriting(), utf8Length)); + linear, mozilla::MakeSpan(rs->BeginWriting(), utf8Length)); MOZ_ASSERT(written == utf8Length); return true; } case nsXPTType::T_CSTRING: { nsACString* rs = (nsACString*)d; if (s.isNull() || s.isUndefined()) {
--- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -375,20 +375,20 @@ void xpc::ErrorNote::ErrorNoteToMessageS } } /* static */ void xpc::ErrorReport::ErrorReportToMessageString(JSErrorReport* aReport, nsAString& aString) { aString.Truncate(); if (aReport->message()) { - JSFlatString* name = js::GetErrorTypeName( + JSLinearString* name = js::GetErrorTypeName( CycleCollectedJSContext::Get()->Context(), aReport->exnType); if (name) { - AssignJSFlatString(aString, name); + AssignJSLinearString(aString, name); aString.AppendLiteral(": "); } aString.Append(NS_ConvertUTF8toUTF16(aReport->message().c_str())); } } /***************************************************************************/ @@ -465,20 +465,21 @@ JSObject* CreateGlobalObject(JSContext* TraceChildren(&trc, GCCellPtr(global.get())); MOZ_ASSERT(trc.ok, "Trace hook on global needs to call TraceXPCGlobal for " "XPConnect compartments."); } #endif const char* className = clasp->name; - AllocateProtoAndIfaceCache(global, (strcmp(className, "Window") == 0 || - strcmp(className, "ChromeWindow") == 0) - ? ProtoAndIfaceCache::WindowLike - : ProtoAndIfaceCache::NonWindowLike); + AllocateProtoAndIfaceCache(global, + (strcmp(className, "Window") == 0 || + strcmp(className, "ChromeWindow") == 0) + ? ProtoAndIfaceCache::WindowLike + : ProtoAndIfaceCache::NonWindowLike); } } return global; } void InitGlobalObjectOptions(JS::RealmOptions& aOptions, nsIPrincipal* aPrincipal) {
--- a/js/xpconnect/tests/chrome/test_wrappers.xul +++ b/js/xpconnect/tests/chrome/test_wrappers.xul @@ -67,24 +67,16 @@ https://bugzilla.mozilla.org/show_bug.cg "stringifying a native function." + " " + eventTargetToString + " " + nativeToString); is(win.XPathResult.NUMBER_TYPE, 1, "can access constants on constructors"); is(typeof win.IDBKeyRange.bound, "function", "can access crazy IDBKeyRange static functions"); // Test getter/setter lookup on Xray wrappers. ok(Object.prototype.__lookupGetter__.call(win.document, 'title'), 'found getter on document'); ok(Object.prototype.__lookupGetter__.call(win.document, 'title'), 'found getter on document'); - - // Test QI on new dom bindings. - try { - var QIed = win.document.documentElement.QueryInterface(Ci.nsIClassInfo); - ok(false, "Should throw for new binding objects not having classinfo"); - } catch(e) { - is(e.name, "NS_NOINTERFACE", "Threw while QI-ing on wrapper"); - } } SimpleTest.waitForExplicitFinish(); ]]></script> <iframe type="content" src="http://example.org/tests/js/xpconnect/tests/mochitest/chrome_wrappers_helper.html" onload="go()"
--- a/media/audioipc/README_MOZILLA +++ b/media/audioipc/README_MOZILLA @@ -1,8 +1,8 @@ The source from this directory was copied from the audioipc-2 git repository using the update.sh script. The only changes made were those applied by update.sh and the addition of Makefile.in build files for the Mozilla build system. The audioipc-2 git repository is: https://github.com/djg/audioipc-2.git -The git commit ID used was f6f56c4352ee4c1b5e483e4594c4c3f309246ceb (2019-07-30 10:52:45 +1200) +The git commit ID used was b82970f6106ceec4a8f599eda631775eb5d5afaf (2019-10-11 08:25:07 +1300)
--- a/media/audioipc/audioipc/Cargo.toml +++ b/media/audioipc/audioipc/Cargo.toml @@ -6,36 +6,37 @@ authors = [ "Dan Glastonbury <dan.glastonbury@gmail.com>" ] description = "Remote Cubeb IPC" edition = "2018" [dependencies] bincode = "1.0" bytes = "0.4" -cubeb = "0.5.5" +cubeb = "0.6.0" futures = "0.1.18" log = "0.4" memmap = "0.7" -scoped-tls = "0.1" serde = "1.*.*" serde_derive = "1.*.*" tokio = "0.1" tokio-io = "0.1" +audio_thread_priority = "0.20.2" [target.'cfg(unix)'.dependencies] iovec = "0.1" libc = "0.2" mio = "0.6.19" mio-uds = "0.6.7" tokio-reactor = "0.1" [target.'cfg(windows)'.dependencies] +miow = "0.3.3" mio-named-pipes = { git = "https://github.com/alexcrichton/mio-named-pipes" } tokio-named-pipes = { git = "https://github.com/NikVolf/tokio-named-pipes", branch = "stable" } -winapi = "0.3.6" +winapi = { version = "0.3.6", features = ["combaseapi", "objbase"] } [dependencies.error-chain] version = "0.11.0" default-features = false [build-dependencies] cc = "1.0"
--- a/media/audioipc/audioipc/src/frame.rs +++ b/media/audioipc/audioipc/src/frame.rs @@ -90,16 +90,19 @@ where return Ok(Some(frame).into()); } self.is_readable = false; } assert!(!self.eof); + // XXX(kinetik): work around tokio_named_pipes assuming at least 1kB available. + self.read_buf.reserve(INITIAL_CAPACITY); + // Otherwise, try to read more data and try again. Make sure we've // got room for at least one byte to read to ensure that we don't // get a spurious 0 that looks like EOF if try_ready!(self.io.read_buf(&mut self.read_buf)) == 0 { self.eof = true; } self.is_readable = true;
--- a/media/audioipc/audioipc/src/handle_passing.rs +++ b/media/audioipc/audioipc/src/handle_passing.rs @@ -128,16 +128,19 @@ where return Ok(Some(item).into()); } self.is_readable = false; } assert!(!self.eof); + // XXX(kinetik): work around tokio_named_pipes assuming at least 1kB available. + self.read_buf.reserve(INITIAL_CAPACITY); + // Otherwise, try to read more data and try again. Make sure we've // got room for at least one byte to read to ensure that we don't // get a spurious 0 that looks like EOF let n = try_ready!(self.io.read_buf(&mut self.read_buf)); if n == 0 { self.eof = true; }
--- a/media/audioipc/audioipc/src/lib.rs +++ b/media/audioipc/audioipc/src/lib.rs @@ -179,8 +179,25 @@ pub fn get_shm_path(dir: &str) -> PathBu pub mod messagestream_unix; #[cfg(unix)] pub use crate::messagestream_unix::*; #[cfg(windows)] pub mod messagestream_win; #[cfg(windows)] pub use messagestream_win::*; + +#[cfg(windows)] +pub fn server_platform_init() { + use winapi::um::combaseapi; + use winapi::um::objbase; + use winapi::shared::winerror; + + unsafe { + let r = combaseapi::CoInitializeEx(std::ptr::null_mut(), + objbase::COINIT_MULTITHREADED); + assert!(winerror::SUCCEEDED(r)); + } +} + +#[cfg(unix)] +pub fn server_platform_init() { +}
--- a/media/audioipc/audioipc/src/messages.rs +++ b/media/audioipc/audioipc/src/messages.rs @@ -4,16 +4,18 @@ // accompanying file LICENSE for details use crate::PlatformHandle; use crate::PlatformHandleType; use cubeb::{self, ffi}; use std::ffi::{CStr, CString}; use std::os::raw::{c_char, c_int, c_uint}; use std::ptr; +#[cfg(target_os = "linux")] +use audio_thread_priority::RtPriorityThreadInfo; #[derive(Debug, Serialize, Deserialize)] pub struct Device { pub output_name: Option<Vec<u8>>, pub input_name: Option<Vec<u8>>, } impl<'a> From<&'a cubeb::DeviceRef> for Device { @@ -200,19 +202,21 @@ pub enum ServerMessage { StreamDestroy(usize), StreamStart(usize), StreamStop(usize), StreamResetDefaultDevice(usize), StreamGetPosition(usize), StreamGetLatency(usize), StreamSetVolume(usize, f32), - StreamSetPanning(usize, f32), StreamGetCurrentDevice(usize), StreamRegisterDeviceChangeCallback(usize, bool), + + #[cfg(target_os = "linux")] + PromoteThreadToRealTime([u8; std::mem::size_of::<RtPriorityThreadInfo>()]), } // Server -> Client messages. // TODO: Streams need id. #[derive(Debug, Serialize, Deserialize)] pub enum ClientMessage { ClientConnected, ClientDisconnected, @@ -229,20 +233,22 @@ pub enum ClientMessage { StreamDestroyed, StreamStarted, StreamStopped, StreamDefaultDeviceReset, StreamPosition(u64), StreamLatency(u32), StreamVolumeSet, - StreamPanningSet, StreamCurrentDevice(Device), StreamRegisterDeviceChangeCallback, + #[cfg(target_os = "linux")] + ThreadPromoted, + Error(c_int), } #[derive(Debug, Deserialize, Serialize)] pub enum CallbackReq { Data { nframes: isize, input_frame_size: usize,
--- a/media/audioipc/audioipc/src/messagestream_win.rs +++ b/media/audioipc/audioipc/src/messagestream_win.rs @@ -3,43 +3,58 @@ // This program is made available under an ISC-style license. See the // accompanying file LICENSE for details use mio_named_pipes; use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; use std::sync::atomic::{AtomicUsize, Ordering}; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_named_pipes; +use winapi::um::winbase::FILE_FLAG_OVERLAPPED; +use std::os::windows::fs::*; #[derive(Debug)] -pub struct MessageStream(mio_named_pipes::NamedPipe); +pub struct MessageStream(miow::pipe::NamedPipe); pub struct AsyncMessageStream(tokio_named_pipes::NamedPipe); impl MessageStream { - fn new(stream: mio_named_pipes::NamedPipe) -> MessageStream { + fn new(stream: miow::pipe::NamedPipe) -> MessageStream { MessageStream(stream) } pub fn anonymous_ipc_pair( ) -> std::result::Result<(MessageStream, MessageStream), std::io::Error> { - let pipe1 = mio_named_pipes::NamedPipe::new(get_pipe_name())?; - let pipe2 = unsafe { mio_named_pipes::NamedPipe::from_raw_handle(pipe1.as_raw_handle()) }; + let pipe_name = get_pipe_name(); + let pipe1 = miow::pipe::NamedPipe::new(&pipe_name)?; + let pipe2 = { + let mut opts = std::fs::OpenOptions::new(); + opts.read(true) + .write(true) + .custom_flags(FILE_FLAG_OVERLAPPED); + let file = opts.open(&pipe_name)?; + unsafe { + miow::pipe::NamedPipe::from_raw_handle(file.into_raw_handle()) + } + }; Ok((MessageStream::new(pipe1), MessageStream::new(pipe2))) } pub unsafe fn from_raw_fd(raw: super::PlatformHandleType) -> MessageStream { - MessageStream::new(mio_named_pipes::NamedPipe::from_raw_handle(raw)) + MessageStream::new(miow::pipe::NamedPipe::from_raw_handle(raw)) } pub fn into_tokio_ipc( self, handle: &tokio::reactor::Handle, ) -> std::result::Result<AsyncMessageStream, std::io::Error> { + let pipe = unsafe { + mio_named_pipes::NamedPipe::from_raw_handle(self.into_raw_handle()) + }; Ok(AsyncMessageStream::new( - tokio_named_pipes::NamedPipe::from_pipe(self.0, handle)?, + tokio_named_pipes::NamedPipe::from_pipe(pipe, handle)?, )) } } impl AsyncMessageStream { fn new(stream: tokio_named_pipes::NamedPipe) -> AsyncMessageStream { AsyncMessageStream(stream) } @@ -79,18 +94,17 @@ impl AsyncWrite for AsyncMessageStream { impl AsRawHandle for AsyncMessageStream { fn as_raw_handle(&self) -> RawHandle { self.0.as_raw_handle() } } impl IntoRawHandle for MessageStream { fn into_raw_handle(self) -> RawHandle { - // XXX: Ideally this would call into_raw_handle. - self.0.as_raw_handle() + self.0.into_raw_handle() } } static PIPE_ID: AtomicUsize = AtomicUsize::new(0); fn get_pipe_name() -> String { let pid = std::process::id(); let pipe_id = PIPE_ID.fetch_add(1, Ordering::SeqCst);
--- a/media/audioipc/client/Cargo.toml +++ b/media/audioipc/client/Cargo.toml @@ -4,16 +4,15 @@ version = "0.4.0" authors = [ "Matthew Gregan <kinetik@flim.org>", "Dan Glastonbury <dan.glastonbury@gmail.com>" ] description = "Cubeb Backend for talking to remote cubeb server." edition = "2018" [dependencies] -audio_thread_priority = "0.19.1" +audio_thread_priority = "0.20.2" audioipc = { path="../audioipc" } -cubeb-backend = "0.5.5" +cubeb-backend = "0.6.0" futures = { version="0.1.18", default-features=false, features=["use_std"] } futures-cpupool = { version="0.1.8", default-features=false } -lazy_static = "1.2.0" log = "0.4" tokio = "0.1"
--- a/media/audioipc/client/src/context.rs +++ b/media/audioipc/client/src/context.rs @@ -1,18 +1,20 @@ // Copyright © 2017 Mozilla Foundation // // This program is made available under an ISC-style license. See the // accompanying file LICENSE for details -use crate::assert_not_in_callback; +use crate::{assert_not_in_callback, run_in_callback}; use crate::stream; +use crate::{ClientStream, G_SERVER_FD, CPUPOOL_INIT_PARAMS}; +#[cfg(not(target_os = "linux"))] +use audio_thread_priority::promote_current_thread_to_real_time; #[cfg(target_os = "linux")] -use crate::G_THREAD_POOL; -use crate::{ClientStream, CpuPoolInitParams, CPUPOOL_INIT_PARAMS, G_SERVER_FD}; +use audio_thread_priority::get_current_thread_info; use audioipc::codec::LengthDelimitedCodec; use audioipc::frame::{framed, Framed}; use audioipc::platformhandle_passing::{framed_with_platformhandles, FramedWithPlatformHandles}; use audioipc::{core, rpc}; use audioipc::{ messages, messages::DeviceCollectionReq, messages::DeviceCollectionResp, ClientMessage, ServerMessage, }; @@ -84,48 +86,56 @@ fn open_server_stream() -> io::Result<au Err(io::Error::new( io::ErrorKind::Other, "Failed to get server connection.", )) } } +#[cfg(target_os = "linux")] +fn promote_thread(rpc: &rpc::ClientProxy<ServerMessage, ClientMessage>) +{ + match get_current_thread_info() { + Ok(info) => { + let bytes = info.serialize(); + // Don't wait for the response, this is on the callback thread, which must not block. + rpc.call(ServerMessage::PromoteThreadToRealTime(bytes)); + } + Err(_) => { + warn!("Could not remotely promote thread to RT."); + } + } +} + +#[cfg(not(target_os = "linux"))] +fn promote_thread(_rpc: &rpc::ClientProxy<ServerMessage, ClientMessage>) +{ + match promote_current_thread_to_real_time(0, 48000) { + Ok(_) => { + info!("Audio thread promoted to real-time."); + } + Err(_) => { + warn!("Could not promote thread to real-time."); + } + } +} + fn register_thread(callback: Option<extern "C" fn(*const ::std::os::raw::c_char)>) { if let Some(func) = callback { let thr = thread::current(); let name = CString::new(thr.name().unwrap()).unwrap(); func(name.as_ptr()); } } -fn create_thread_pool(init_params: CpuPoolInitParams) -> CpuPool { - futures_cpupool::Builder::new() - .name_prefix("AudioIPC") - .after_start(move || register_thread(init_params.thread_create_callback)) - .pool_size(init_params.pool_size) - .stack_size(init_params.stack_size) - .create() -} - -#[cfg(target_os = "linux")] -fn get_thread_pool(init_params: CpuPoolInitParams) -> CpuPool { - let mut guard = G_THREAD_POOL.lock().unwrap(); - if guard.is_some() { - // Sandbox is on, and the thread pool was created earlier, before the lockdown. - guard.take().unwrap() - } else { - // Sandbox is off, let's create the pool now, promoting the threads will work. - create_thread_pool(init_params) - } -} - -#[cfg(not(target_os = "linux"))] -fn get_thread_pool(init_params: CpuPoolInitParams) -> CpuPool { - create_thread_pool(init_params) +fn promote_and_register_thread(rpc: &rpc::ClientProxy<ServerMessage, ClientMessage>, + callback: Option<extern "C" fn(*const ::std::os::raw::c_char)>) { + promote_thread(rpc); + register_thread(callback); } #[derive(Default)] struct DeviceCollectionCallback { cb: ffi::cubeb_device_collection_changed_callback, user_ptr: usize, } @@ -157,24 +167,27 @@ impl rpc::Server for DeviceCollectionSer (dcb.cb, dcb.user_ptr) }; let (output_cb, output_user_ptr) = { let dcb = self.output_device_callback.lock().unwrap(); (dcb.cb, dcb.user_ptr) }; self.cpu_pool.spawn_fn(move || { - if devtype.contains(cubeb_backend::DeviceType::INPUT) { - unsafe { input_cb.unwrap()(ptr::null_mut(), input_user_ptr as *mut c_void) } - } - if devtype.contains(cubeb_backend::DeviceType::OUTPUT) { - unsafe { - output_cb.unwrap()(ptr::null_mut(), output_user_ptr as *mut c_void) + run_in_callback(|| { + + if devtype.contains(cubeb_backend::DeviceType::INPUT) { + unsafe { input_cb.unwrap()(ptr::null_mut(), input_user_ptr as *mut c_void) } } - } + if devtype.contains(cubeb_backend::DeviceType::OUTPUT) { + unsafe { + output_cb.unwrap()(ptr::null_mut(), output_user_ptr as *mut c_void) + } + } + }); Ok(DeviceCollectionResp::DeviceChange) }) } } } } @@ -205,26 +218,32 @@ impl ContextOps for ClientContext { open_server_stream() .and_then(|stream| stream.into_tokio_ipc(&handle)) .and_then(|stream| bind_and_send_client(stream, &tx_rpc)) }) .map_err(|_| Error::default())?; let rpc = rx_rpc.recv().map_err(|_| Error::default())?; + let rpc2 = rpc.clone(); // Don't let errors bubble from here. Later calls against this context // will return errors the caller expects to handle. let _ = send_recv!(rpc, ClientConnect(std::process::id()) => ClientConnected); let backend_id = send_recv!(rpc, ContextGetBackendId => ContextBackendId()) .unwrap_or_else(|_| "(remote error)".to_string()); let backend_id = CString::new(backend_id).expect("backend_id query failed"); - let cpu_pool = get_thread_pool(params); + let cpu_pool = futures_cpupool::Builder::new() + .name_prefix("AudioIPC") + .after_start(move || promote_and_register_thread(&rpc2, params.thread_create_callback)) + .pool_size(params.pool_size) + .stack_size(params.stack_size) + .create(); let ctx = Box::new(ClientContext { _ops: &CLIENT_OPS as *const _, rpc, core, cpu_pool, backend_id, device_collection_rpc: false,
--- a/media/audioipc/client/src/lib.rs +++ b/media/audioipc/client/src/lib.rs @@ -3,48 +3,32 @@ // This program is made available under an ISC-style license. See the // accompanying file LICENSE for details. #![warn(unused_extern_crates)] #[macro_use] extern crate cubeb_backend; #[macro_use] extern crate log; -#[macro_use] -extern crate lazy_static; #[macro_use] mod send_recv; mod context; mod stream; use crate::context::ClientContext; use crate::stream::ClientStream; -use audio_thread_priority::RtPriorityHandle; use audioipc::{PlatformHandle, PlatformHandleType}; use cubeb_backend::{capi, ffi}; -use futures_cpupool::CpuPool; -#[cfg(target_os = "linux")] -use std::ffi::CString; use std::os::raw::{c_char, c_int}; -use std::sync::Mutex; -#[cfg(target_os = "linux")] -use std::sync::{Arc, Condvar}; -#[cfg(target_os = "linux")] -use std::thread; type InitParamsTls = std::cell::RefCell<Option<CpuPoolInitParams>>; thread_local!(static IN_CALLBACK: std::cell::RefCell<bool> = std::cell::RefCell::new(false)); thread_local!(static CPUPOOL_INIT_PARAMS: InitParamsTls = std::cell::RefCell::new(None)); -thread_local!(static G_PRIORITY_HANDLES: std::cell::RefCell<Vec<RtPriorityHandle>> = std::cell::RefCell::new(vec![])); - -lazy_static! { - static ref G_THREAD_POOL: Mutex<Option<CpuPool>> = Mutex::new(None); -} // This must match the definition of AudioIpcInitParams in // dom/media/CubebUtils.cpp in Gecko. #[repr(C)] #[derive(Clone, Copy, Debug)] pub struct AudioIpcInitParams { // Fields only need to be public for ipctest. pub server_connection: PlatformHandleType, @@ -72,16 +56,29 @@ impl CpuPoolInitParams { fn set_in_callback(in_callback: bool) { IN_CALLBACK.with(|b| { assert_eq!(*b.borrow(), !in_callback); *b.borrow_mut() = in_callback; }); } +fn run_in_callback<F, R>(f: F) -> R +where + F: FnOnce() -> R +{ + set_in_callback(true); + + let r = f(); + + set_in_callback(false); + + r +} + fn assert_not_in_callback() { IN_CALLBACK.with(|b| { assert_eq!(*b.borrow(), false); }); } fn set_cpupool_init_params<P>(params: P) where @@ -89,63 +86,16 @@ where { CPUPOOL_INIT_PARAMS.with(|p| { *p.borrow_mut() = params.into(); }); } static mut G_SERVER_FD: Option<PlatformHandle> = None; -#[cfg(target_os = "linux")] -#[no_mangle] -pub unsafe extern "C" fn audioipc_init_threads(init_params: *const AudioIpcInitParams) { - let thread_create_callback = (*init_params).thread_create_callback; - - // It is critical that this function waits until the various threads are created, promoted to - // real-time, and _then_ return, because the sandbox lockdown happens right after returning - // from here. - let pair = Arc::new((Mutex::new((*init_params).pool_size), Condvar::new())); - let pair2 = pair.clone(); - - let register_thread = move || { - if let Some(func) = thread_create_callback { - let thr = thread::current(); - let name = CString::new(thr.name().unwrap()).unwrap(); - func(name.as_ptr()); - let &(ref lock, ref cvar) = &*pair2; - let mut count = lock.lock().unwrap(); - *count -= 1; - cvar.notify_one(); - } - }; - - let mut pool = G_THREAD_POOL.lock().unwrap(); - - *pool = Some( - futures_cpupool::Builder::new() - .name_prefix("AudioIPC") - .after_start(register_thread) - .pool_size((*init_params).pool_size) - .stack_size((*init_params).stack_size) - .create(), - ); - - let &(ref lock, ref cvar) = &*pair; - let mut count = lock.lock().unwrap(); - while *count != 0 { - count = cvar.wait(count).unwrap(); - } -} - -#[cfg(not(target_os = "linux"))] -#[no_mangle] -pub unsafe extern "C" fn audioipc_init_threads(_: *const AudioIpcInitParams) { - unimplemented!(); -} - #[no_mangle] /// Entry point from C code. pub unsafe extern "C" fn audioipc_client_init( c: *mut *mut ffi::cubeb, context_name: *const c_char, init_params: *const AudioIpcInitParams, ) -> c_int { if init_params.is_null() {
--- a/media/audioipc/client/src/stream.rs +++ b/media/audioipc/client/src/stream.rs @@ -1,15 +1,15 @@ // Copyright © 2017 Mozilla Foundation // // This program is made available under an ISC-style license. See the // accompanying file LICENSE for details use crate::ClientContext; -use crate::{assert_not_in_callback, set_in_callback}; +use crate::{assert_not_in_callback, run_in_callback}; use audioipc::codec::LengthDelimitedCodec; use audioipc::frame::{framed, Framed}; use audioipc::messages::{self, CallbackReq, CallbackResp, ClientMessage, ServerMessage}; use audioipc::rpc; use audioipc::shm::{SharedMemMutSlice, SharedMemSlice}; use cubeb_backend::{ffi, DeviceRef, Error, Result, Stream, StreamOps}; use futures::Future; use futures_cpupool::{CpuFuture, CpuPool}; @@ -103,59 +103,59 @@ impl rpc::Server for CallbackServer { let output_ptr: *mut u8 = match output_shm { Some(ref mut shm) => shm .get_mut_slice(nframes as usize * output_frame_size) .unwrap() .as_mut_ptr(), None => ptr::null_mut(), }; - set_in_callback(true); - let nframes = unsafe { - cb( - ptr::null_mut(), - user_ptr as *mut c_void, - input_ptr as *const _, - output_ptr as *mut _, - nframes as _, - ) - }; - set_in_callback(false); + run_in_callback(|| { + let nframes = unsafe { + cb( + ptr::null_mut(), + user_ptr as *mut c_void, + input_ptr as *const _, + output_ptr as *mut _, + nframes as _, + ) + }; - Ok(CallbackResp::Data(nframes as isize)) + Ok(CallbackResp::Data(nframes as isize)) + }) }) } CallbackReq::State(state) => { trace!("stream_thread: State Callback: {:?}", state); let user_ptr = self.user_ptr; let cb = self.state_cb.unwrap(); self.cpu_pool.spawn_fn(move || { - set_in_callback(true); - unsafe { - cb(ptr::null_mut(), user_ptr as *mut _, state); - } - set_in_callback(false); + run_in_callback(|| { + unsafe { + cb(ptr::null_mut(), user_ptr as *mut _, state); + } + }); Ok(CallbackResp::State) }) } CallbackReq::DeviceChange => { let cb = self.device_change_cb.clone(); let user_ptr = self.user_ptr; self.cpu_pool.spawn_fn(move || { - set_in_callback(true); - let cb = cb.lock().unwrap(); - if let Some(cb) = *cb { - unsafe { - cb(user_ptr as *mut _); + run_in_callback(|| { + let cb = cb.lock().unwrap(); + if let Some(cb) = *cb { + unsafe { + cb(user_ptr as *mut _); + } + } else { + warn!("DeviceChange received with null callback"); } - } else { - warn!("DeviceChange received with null callback"); - } - set_in_callback(false); + }); Ok(CallbackResp::DeviceChange) }) } } } } @@ -279,22 +279,16 @@ impl<'ctx> StreamOps for ClientStream<'c } fn set_volume(&mut self, volume: f32) -> Result<()> { assert_not_in_callback(); let rpc = self.context.rpc(); send_recv!(rpc, StreamSetVolume(self.token, volume) => StreamVolumeSet) } - fn set_panning(&mut self, panning: f32) -> Result<()> { - assert_not_in_callback(); - let rpc = self.context.rpc(); - send_recv!(rpc, StreamSetPanning(self.token, panning) => StreamPanningSet) - } - fn current_device(&mut self) -> Result<&DeviceRef> { assert_not_in_callback(); let rpc = self.context.rpc(); match send_recv!(rpc, StreamGetCurrentDevice(self.token) => StreamCurrentDevice()) { Ok(d) => Ok(unsafe { DeviceRef::from_ptr(Box::into_raw(Box::new(d.into()))) }), Err(e) => Err(e), } }
deleted file mode 100644 --- a/media/audioipc/disable-rt.patch +++ /dev/null @@ -1,139 +0,0 @@ -diff --git a/media/audioipc/client/src/context.rs b/media/audioipc/client/src/context.rs ---- a/media/audioipc/client/src/context.rs -+++ b/media/audioipc/client/src/context.rs -@@ -3,17 +3,16 @@ - // This program is made available under an ISC-style license. See the - // accompanying file LICENSE for details - - use crate::assert_not_in_callback; - use crate::stream; - #[cfg(target_os = "linux")] - use crate::G_THREAD_POOL; - use crate::{ClientStream, CpuPoolInitParams, CPUPOOL_INIT_PARAMS, G_SERVER_FD}; --use audio_thread_priority::promote_current_thread_to_real_time; - use audioipc::codec::LengthDelimitedCodec; - use audioipc::frame::{framed, Framed}; - use audioipc::platformhandle_passing::{framed_with_platformhandles, FramedWithPlatformHandles}; - use audioipc::{core, rpc}; - use audioipc::{ - messages, messages::DeviceCollectionReq, messages::DeviceCollectionResp, ClientMessage, - ServerMessage, - }; -@@ -86,24 +85,16 @@ fn open_server_stream() -> io::Result<au - Err(io::Error::new( - io::ErrorKind::Other, - "Failed to get server connection.", - )) - } - } - - fn register_thread(callback: Option<extern "C" fn(*const ::std::os::raw::c_char)>) { -- match promote_current_thread_to_real_time(0, 48000) { -- Ok(_) => { -- info!("Audio thread promoted to real-time."); -- } -- Err(_) => { -- warn!("Could not promote thread to real-time."); -- } -- } - if let Some(func) = callback { - let thr = thread::current(); - let name = CString::new(thr.name().unwrap()).unwrap(); - func(name.as_ptr()); - } - } - - fn create_thread_pool(init_params: CpuPoolInitParams) -> CpuPool { -diff --git a/media/audioipc/client/src/lib.rs b/media/audioipc/client/src/lib.rs ---- a/media/audioipc/client/src/lib.rs -+++ b/media/audioipc/client/src/lib.rs -@@ -13,18 +13,16 @@ extern crate lazy_static; - - #[macro_use] - mod send_recv; - mod context; - mod stream; - - use crate::context::ClientContext; - use crate::stream::ClientStream; --#[cfg(target_os = "linux")] --use audio_thread_priority::promote_current_thread_to_real_time; - use audio_thread_priority::RtPriorityHandle; - use audioipc::{PlatformHandle, PlatformHandleType}; - use cubeb_backend::{capi, ffi}; - use futures_cpupool::CpuPool; - #[cfg(target_os = "linux")] - use std::ffi::CString; - use std::os::raw::{c_char, c_int}; - use std::sync::Mutex; -@@ -104,26 +102,16 @@ pub unsafe extern "C" fn audioipc_init_t - // It is critical that this function waits until the various threads are created, promoted to - // real-time, and _then_ return, because the sandbox lockdown happens right after returning - // from here. - let pair = Arc::new((Mutex::new((*init_params).pool_size), Condvar::new())); - let pair2 = pair.clone(); - - let register_thread = move || { - if let Some(func) = thread_create_callback { -- match promote_current_thread_to_real_time(0, 48000) { -- Ok(handle) => { -- G_PRIORITY_HANDLES.with(|handles| { -- (handles.borrow_mut()).push(handle); -- }); -- } -- Err(_) => { -- warn!("Could not promote audio threads to real-time during initialization."); -- } -- } - let thr = thread::current(); - let name = CString::new(thr.name().unwrap()).unwrap(); - func(name.as_ptr()); - let &(ref lock, ref cvar) = &*pair2; - let mut count = lock.lock().unwrap(); - *count -= 1; - cvar.notify_one(); - } -diff --git a/media/audioipc/server/src/lib.rs b/media/audioipc/server/src/lib.rs ---- a/media/audioipc/server/src/lib.rs -+++ b/media/audioipc/server/src/lib.rs -@@ -6,17 +6,16 @@ - - #[macro_use] - extern crate error_chain; - #[macro_use] - extern crate log; - #[macro_use] - extern crate lazy_static; - --use audio_thread_priority::promote_current_thread_to_real_time; - use audioipc::core; - use audioipc::platformhandle_passing::framed_with_platformhandles; - use audioipc::rpc; - use audioipc::{MessageStream, PlatformHandle, PlatformHandleType}; - use futures::sync::oneshot; - use futures::Future; - use std::error::Error; - use std::ffi::{CStr, CString}; -@@ -59,22 +58,16 @@ struct ServerWrapper { - core_thread: core::CoreThread, - callback_thread: core::CoreThread, - } - - fn run() -> Result<ServerWrapper> { - trace!("Starting up cubeb audio server event loop thread..."); - - let callback_thread = core::spawn_thread("AudioIPC Callback RPC", || { -- match promote_current_thread_to_real_time(0, 48000) { -- Ok(_) => {} -- Err(_) => { -- debug!("Failed to promote audio callback thread to real-time."); -- } -- } - trace!("Starting up cubeb audio callback event loop thread..."); - Ok(()) - }) - .or_else(|e| { - debug!( - "Failed to start cubeb audio callback event loop thread: {:?}", - e.description() - );
--- a/media/audioipc/server/Cargo.toml +++ b/media/audioipc/server/Cargo.toml @@ -4,20 +4,20 @@ version = "0.2.3" authors = [ "Matthew Gregan <kinetik@flim.org>", "Dan Glastonbury <dan.glastonbury@gmail.com>" ] description = "Remote cubeb server" edition = "2018" [dependencies] -audio_thread_priority = "0.19.1" +audio_thread_priority = "0.20.2" audioipc = { path = "../audioipc" } -cubeb-core = "0.5.5" +cubeb-core = "0.6.0" futures = "0.1.18" lazy_static = "1.2.0" log = "0.4" -slab = "0.3.0" +slab = "0.4" tokio = "0.1" [dependencies.error-chain] version = "0.11.0" default-features = false
--- a/media/audioipc/server/src/lib.rs +++ b/media/audioipc/server/src/lib.rs @@ -6,16 +6,17 @@ #[macro_use] extern crate error_chain; #[macro_use] extern crate log; #[macro_use] extern crate lazy_static; +use audio_thread_priority::promote_current_thread_to_real_time; use audioipc::core; use audioipc::platformhandle_passing::framed_with_platformhandles; use audioipc::rpc; use audioipc::{MessageStream, PlatformHandle, PlatformHandleType}; use futures::sync::oneshot; use futures::Future; use std::error::Error; use std::ffi::{CStr, CString}; @@ -58,16 +59,22 @@ struct ServerWrapper { core_thread: core::CoreThread, callback_thread: core::CoreThread, } fn run() -> Result<ServerWrapper> { trace!("Starting up cubeb audio server event loop thread..."); let callback_thread = core::spawn_thread("AudioIPC Callback RPC", || { + match promote_current_thread_to_real_time(0, 48000) { + Ok(_) => {} + Err(_) => { + debug!("Failed to promote audio callback thread to real-time."); + } + } trace!("Starting up cubeb audio callback event loop thread..."); Ok(()) }) .or_else(|e| { debug!( "Failed to start cubeb audio callback event loop thread: {:?}", e.description() );
--- a/media/audioipc/server/src/server.rs +++ b/media/audioipc/server/src/server.rs @@ -25,16 +25,18 @@ use std::cell::RefCell; use std::convert::From; use std::ffi::CStr; use std::mem::{size_of, ManuallyDrop}; use std::os::raw::{c_long, c_void}; use std::rc::Rc; use std::{panic, slice}; use tokio::reactor; use tokio::runtime::current_thread; +#[cfg(target_os = "linux")] +use audio_thread_priority::{RtPriorityThreadInfo, promote_thread_to_real_time}; use crate::errors::*; fn error(error: cubeb::Error) -> ClientMessage { ClientMessage::Error(error.raw_code()) } struct CubebDeviceCollectionManager { @@ -162,16 +164,17 @@ where if state.is_none() { let params = super::G_CUBEB_CONTEXT_PARAMS.lock().unwrap(); let context_name = Some(params.context_name.as_c_str()); let backend_name = if let Some(ref name) = params.backend_name { Some(name.as_c_str()) } else { None }; + audioipc::server_platform_init(); let context = cubeb::Context::init(context_name, backend_name); let manager = CubebDeviceCollectionManager::new(); *state = Some(CubebContextState { context, manager }); } let state = state.as_mut().unwrap(); f(&state.context, &mut state.manager) }) } @@ -278,17 +281,17 @@ im