mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 11:55:49 +00:00
Merge autoland to mozilla-central. a=merge
This commit is contained in:
commit
36a784a4c4
@ -47,9 +47,8 @@ git = "https://github.com/mozilla-spidermonkey/jsparagus"
|
||||
replace-with = "vendored-sources"
|
||||
rev = "2e56bb9bae5d8211137980a717ee991cc4a5eb98"
|
||||
|
||||
[source."https://github.com/kvark/spirv_cross"]
|
||||
branch = "wgpu5"
|
||||
git = "https://github.com/kvark/spirv_cross"
|
||||
[source."https://github.com/kvark/dummy-web"]
|
||||
git = "https://github.com/kvark/dummy-web"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."https://github.com/kinetiknz/mio-named-pipes"]
|
||||
@ -82,6 +81,16 @@ git = "https://github.com/hsivonen/chardetng"
|
||||
replace-with = "vendored-sources"
|
||||
rev = "302c995f91f44cf26e77dc4758ad56c3ff0153ad"
|
||||
|
||||
[source."https://github.com/gfx-rs/wgpu"]
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
replace-with = "vendored-sources"
|
||||
rev = "d23288e"
|
||||
|
||||
[source."https://github.com/gfx-rs/naga"]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
replace-with = "vendored-sources"
|
||||
rev = "93db57c"
|
||||
|
||||
[source."https://github.com/bytecodealliance/wasmtime"]
|
||||
git = "https://github.com/bytecodealliance/wasmtime"
|
||||
replace-with = "vendored-sources"
|
||||
|
@ -119,7 +119,6 @@ gfx/vr/service/openvr/src/strtools_public.cpp
|
||||
gfx/vr/service/openvr/src/strtools_public.h
|
||||
gfx/vr/service/openvr/src/vrpathregistry_public.cpp
|
||||
gfx/vr/service/openvr/src/vrpathregistry_public.h
|
||||
gfx/wgpu/.*
|
||||
gfx/ycbcr/.*
|
||||
intl/hyphenation/hyphen/.*
|
||||
intl/icu/.*
|
||||
|
365
Cargo.lock
generated
365
Cargo.lock
generated
@ -87,15 +87,21 @@ name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ash"
|
||||
version = "0.32.1"
|
||||
version = "0.33.0+1.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06063a002a77d2734631db74e8f4ce7148b77fe522e6bca46f2ae7774fd48112"
|
||||
checksum = "a2142f1fa77cc4d24ffd2f24dc84f88ce5b1e588d524f10fb473a04b93aef14f"
|
||||
dependencies = [
|
||||
"libloading 0.7.0",
|
||||
]
|
||||
@ -393,7 +399,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b83b7baab1e671718d78204225800d6b170e648188ac7dc992e9d6bddf87d0c0"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"arrayvec 0.5.2",
|
||||
"constant_time_eq",
|
||||
]
|
||||
|
||||
@ -510,9 +516,6 @@ name = "cc"
|
||||
version = "1.0.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cert_storage"
|
||||
@ -638,21 +641,6 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa-foundation"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"block",
|
||||
"core-foundation",
|
||||
"core-graphics-types",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
@ -1052,9 +1040,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "d3d12"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "091ed1b25fe47c7ff129fc440c23650b6114f36aa00bc7212cc8041879294428"
|
||||
checksum = "2daefd788d1e96e0a9d66dee4b828b883509bc3ea9ce30665f04c3246372690c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libloading 0.7.0",
|
||||
@ -1219,15 +1207,6 @@ dependencies = [
|
||||
"smallbitvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "drm-fourcc"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebbf3a5ed4671aabffefce172ff43d69c1f27dd2c6aea28e5212a70f32ada0cf"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.8"
|
||||
@ -1349,16 +1328,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "external-memory"
|
||||
version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4dfe8d292b014422776a8c516862d2bff8a81b223a4461dfdc45f3862dc9d39"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"drm-fourcc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
@ -1844,148 +1813,6 @@ dependencies = [
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-auxil"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1694991b11d642680e82075a75c7c2bd75556b805efa7660b705689f05b1ab1c"
|
||||
dependencies = [
|
||||
"fxhash",
|
||||
"gfx-hal",
|
||||
"spirv_cross",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-backend-dx11"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f9e453baf3aaef2b0c354ce0b3d63d76402e406a59b64b7182d123cfa6635ae"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"gfx-auxil",
|
||||
"gfx-hal",
|
||||
"gfx-renderdoc",
|
||||
"libloading 0.7.0",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"range-alloc",
|
||||
"raw-window-handle",
|
||||
"smallvec",
|
||||
"spirv_cross",
|
||||
"thunderdome",
|
||||
"winapi",
|
||||
"wio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-backend-dx12"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21506399f64a3c4d389182a89a30073856ae33eb712315456b4fd8f39ee7682a"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-set",
|
||||
"bitflags",
|
||||
"d3d12",
|
||||
"gfx-auxil",
|
||||
"gfx-hal",
|
||||
"gfx-renderdoc",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"range-alloc",
|
||||
"raw-window-handle",
|
||||
"smallvec",
|
||||
"spirv_cross",
|
||||
"thunderdome",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-backend-empty"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29c8f813c47791918aa00dc9c9ddf961d23fa8c2a5d869e6cb8ea84f944820f4"
|
||||
dependencies = [
|
||||
"gfx-hal",
|
||||
"log",
|
||||
"raw-window-handle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-backend-metal"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0de85808e2a98994c6af925253f8a9593bc57180ef1ea137deab6d35cc949517"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"block",
|
||||
"cocoa-foundation",
|
||||
"copyless",
|
||||
"core-graphics-types",
|
||||
"foreign-types",
|
||||
"fxhash",
|
||||
"gfx-auxil",
|
||||
"gfx-hal",
|
||||
"log",
|
||||
"metal",
|
||||
"naga",
|
||||
"objc",
|
||||
"parking_lot",
|
||||
"profiling",
|
||||
"range-alloc",
|
||||
"raw-window-handle",
|
||||
"spirv_cross",
|
||||
"storage-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-backend-vulkan"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9861ec855acbbc65c0e4f966d761224886e811dc2c6d413a4776e9293d0e5c0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"ash",
|
||||
"byteorder",
|
||||
"core-graphics-types",
|
||||
"gfx-hal",
|
||||
"gfx-renderdoc",
|
||||
"inplace_it",
|
||||
"log",
|
||||
"naga",
|
||||
"objc",
|
||||
"parking_lot",
|
||||
"raw-window-handle",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-hal"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fbb575ea793dd0507b3082f4f2cde62dc9f3cebd98f5cd49ba2a4da97a976fd"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"external-memory",
|
||||
"naga",
|
||||
"raw-window-handle",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gfx-renderdoc"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8027995e247e2426d3a00d13f5191dd56c314bff02dc4b54cbf727f1ba9c40a"
|
||||
dependencies = [
|
||||
"libloading 0.7.0",
|
||||
"log",
|
||||
"renderdoc-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gkrust"
|
||||
version = "0.1.0"
|
||||
@ -2172,6 +1999,18 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "glow"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f04649123493bc2483cbef4daddb45d40bbdae5adb221a63a23efdb0cc99520"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"slotmap",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glsl"
|
||||
version = "4.0.3"
|
||||
@ -2228,9 +2067,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gpu-alloc"
|
||||
version = "0.4.7"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbc1b6ca374e81862526786d9cb42357ce03706ed1b8761730caafd02ab91f3a"
|
||||
checksum = "c481459c44304a1dfed23bd650bb3912e12c9f77d7871f86d7ed7c9730a52e79"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"gpu-alloc-types",
|
||||
@ -2247,9 +2086,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gpu-descriptor"
|
||||
version = "0.1.1"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8a70f1e87a3840ed6a3e99e02c2b861e4dbdf26f0d07e38f42ea5aff46cfce2"
|
||||
checksum = "d7a237f0419ab10d17006d55c62ac4f689a6bf52c75d3f38b8361d249e8d4b0b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"gpu-descriptor-types",
|
||||
@ -2569,6 +2408,11 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.100"
|
||||
source = "git+https://github.com/kvark/dummy-web#5731e569d865a1ebaf116f48dad781f355a99243"
|
||||
|
||||
[[package]]
|
||||
name = "jsparagus"
|
||||
version = "0.1.0"
|
||||
@ -2625,7 +2469,7 @@ name = "jsparagus-parser"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=2e56bb9bae5d8211137980a717ee991cc4a5eb98#2e56bb9bae5d8211137980a717ee991cc4a5eb98"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"arrayvec 0.5.2",
|
||||
"bumpalo",
|
||||
"jsparagus-ast",
|
||||
"jsparagus-generated-parser",
|
||||
@ -2672,6 +2516,16 @@ dependencies = [
|
||||
"smoosh",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "khronos-egl"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libloading 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "khronos_api"
|
||||
version = "3.1.0"
|
||||
@ -3035,9 +2889,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "metal"
|
||||
version = "0.23.0"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79d7d769f1c104b8388294d6594d491d2e21240636f5f94d37f8a0f3d7904450"
|
||||
checksum = "e0514f491f4cc03632ab399ee01e2c1c1b12d3e1cf2d667c1ff5f87d6dcd2084"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"block",
|
||||
@ -3191,7 +3045,7 @@ dependencies = [
|
||||
name = "mozglue-static"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"arrayvec 0.5.2",
|
||||
"cc",
|
||||
"rustc_version",
|
||||
]
|
||||
@ -3309,9 +3163,8 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
|
||||
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef670817eef03d356d5a509ea275e7dd3a78ea9e24261ea3cb2dfed1abb08f64"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/gfx-rs/naga?rev=93db57c#93db57c12b4a5eff48bdd00c494efa5ec89567ad"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"bitflags",
|
||||
@ -3320,8 +3173,8 @@ dependencies = [
|
||||
"log",
|
||||
"num-traits",
|
||||
"petgraph",
|
||||
"rose_tree",
|
||||
"spirv_headers",
|
||||
"serde",
|
||||
"spirv",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@ -4281,15 +4134,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rose_tree"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "284de9dae38774e2813aaabd7e947b4a6fe9b8c58c2309f754a487cdd50de1c2"
|
||||
dependencies = [
|
||||
"petgraph",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsclientcerts"
|
||||
version = "0.1.0"
|
||||
@ -4365,7 +4209,7 @@ version = "1.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9787e62372fc0c5a0f3af64c392652db72d3ec1cc0cff1becc175d2c11e6fbcc"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"arrayvec 0.5.2",
|
||||
"num-traits",
|
||||
"serde",
|
||||
]
|
||||
@ -4649,6 +4493,11 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
|
||||
|
||||
[[package]]
|
||||
name = "slotmap"
|
||||
version = "1.100.0"
|
||||
source = "git+https://github.com/kvark/dummy-web#5731e569d865a1ebaf116f48dad781f355a99243"
|
||||
|
||||
[[package]]
|
||||
name = "smallbitvec"
|
||||
version = "2.5.0"
|
||||
@ -4686,26 +4535,10 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spirv-cross-internal"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/kvark/spirv_cross?branch=wgpu5#a5a90d38ab1f82ad8327b48e161dbfe556ef6c6e"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spirv_cross"
|
||||
version = "0.23.0"
|
||||
source = "git+https://github.com/kvark/spirv_cross?branch=wgpu5#a5a90d38ab1f82ad8327b48e161dbfe556ef6c6e"
|
||||
dependencies = [
|
||||
"spirv-cross-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spirv_headers"
|
||||
version = "1.5.0"
|
||||
name = "spirv"
|
||||
version = "0.2.0+1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f5b132530b1ac069df335577e3581765995cba5a13995cdbbdbc8fb057c532c"
|
||||
checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"num-traits",
|
||||
@ -4750,15 +4583,6 @@ dependencies = [
|
||||
"xpcom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "storage-map"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418bb14643aa55a7841d5303f72cf512cfb323b8cc221d51580500a1ca75206c"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "storage_variant"
|
||||
version = "0.1.0"
|
||||
@ -4780,7 +4604,7 @@ name = "style"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"app_units",
|
||||
"arrayvec",
|
||||
"arrayvec 0.5.2",
|
||||
"atomic_refcell",
|
||||
"bindgen",
|
||||
"bitflags",
|
||||
@ -5040,12 +4864,6 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b5b2bd897775cb425729882f0710639eb69f3d784db834ee85941ae9c35bb83"
|
||||
|
||||
[[package]]
|
||||
name = "thunderdome"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87b4947742c93ece24a0032141d9caa3d853752e694a57e35029dd2bd08673e0"
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.43"
|
||||
@ -5338,7 +5156,7 @@ version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6ee6f45294ecb6e220e76b8afddb50a8b69d433f31ad9eb2d16fb44029ef5db"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"arrayvec 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5540,6 +5358,11 @@ version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
source = "git+https://github.com/kvark/dummy-web#5731e569d865a1ebaf116f48dad781f355a99243"
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.78.2"
|
||||
@ -5564,6 +5387,11 @@ dependencies = [
|
||||
"wast",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.100"
|
||||
source = "git+https://github.com/kvark/dummy-web#5731e569d865a1ebaf116f48dad781f355a99243"
|
||||
|
||||
[[package]]
|
||||
name = "webdriver"
|
||||
version = "0.43.1"
|
||||
@ -5738,21 +5566,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wgpu-core"
|
||||
version = "0.9.2"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=d23288e#d23288e455eec657c5632d7c24410d0d2ef2057e"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"arrayvec 0.7.1",
|
||||
"bitflags",
|
||||
"cfg_aliases",
|
||||
"copyless",
|
||||
"fxhash",
|
||||
"gfx-backend-dx11",
|
||||
"gfx-backend-dx12",
|
||||
"gfx-backend-empty",
|
||||
"gfx-backend-metal",
|
||||
"gfx-backend-vulkan",
|
||||
"gfx-hal",
|
||||
"gpu-alloc",
|
||||
"gpu-descriptor",
|
||||
"log",
|
||||
"naga",
|
||||
"parking_lot",
|
||||
@ -5761,12 +5582,47 @@ dependencies = [
|
||||
"serde",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"wgpu-hal",
|
||||
"wgpu-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wgpu-hal"
|
||||
version = "0.10.1"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=d23288e#d23288e455eec657c5632d7c24410d0d2ef2057e"
|
||||
dependencies = [
|
||||
"arrayvec 0.7.1",
|
||||
"ash",
|
||||
"bit-set",
|
||||
"bitflags",
|
||||
"block",
|
||||
"core-graphics-types",
|
||||
"d3d12",
|
||||
"foreign-types",
|
||||
"fxhash",
|
||||
"glow",
|
||||
"gpu-alloc",
|
||||
"gpu-descriptor",
|
||||
"inplace_it",
|
||||
"khronos-egl",
|
||||
"libloading 0.7.0",
|
||||
"log",
|
||||
"metal",
|
||||
"naga",
|
||||
"objc",
|
||||
"parking_lot",
|
||||
"range-alloc",
|
||||
"raw-window-handle",
|
||||
"renderdoc-sys",
|
||||
"thiserror",
|
||||
"wgpu-types",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wgpu-types"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=d23288e#d23288e455eec657c5632d7c24410d0d2ef2057e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"serde",
|
||||
@ -5781,6 +5637,7 @@ dependencies = [
|
||||
"parking_lot",
|
||||
"serde",
|
||||
"wgpu-core",
|
||||
"wgpu-hal",
|
||||
"wgpu-types",
|
||||
]
|
||||
|
||||
|
@ -30,7 +30,6 @@ exclude = [
|
||||
|
||||
# Excluded because these crates have their own Cargo workspaces so they can't
|
||||
# be included in the top-level one.
|
||||
"gfx/wgpu",
|
||||
"gfx/wr",
|
||||
|
||||
# Excluded because they are used only as dependencies, not top-level targets,
|
||||
@ -44,6 +43,7 @@ exclude = [
|
||||
]
|
||||
|
||||
# Use the new dependency resolver to reduce some of the platform-specific dependencies.
|
||||
# This is required for 'third_party/rust/wgpu-hal'
|
||||
resolver = "2"
|
||||
|
||||
# Explicitly specify what our profiles use. The opt-level setting here is
|
||||
@ -82,8 +82,13 @@ chardetng = { git = "https://github.com/hsivonen/chardetng", rev="302c995f91f44c
|
||||
chardetng_c = { git = "https://github.com/hsivonen/chardetng_c", rev="ed8a4c6f900a90d4dbc1d64b856e61490a1c3570" }
|
||||
libudev-sys = { path = "dom/webauthn/libudev-sys" }
|
||||
packed_simd = { git = "https://github.com/hsivonen/packed_simd", rev="6a16f954950401b92b4e220fbf2dfaf6f00e1fb2" }
|
||||
spirv_cross = { git = "https://github.com/kvark/spirv_cross", branch = "wgpu5" }
|
||||
minidump_writer_linux = { git = "https://github.com/msirringhaus/minidump_writer_linux.git", rev = "029ac0d54b237f27dc7d8d4e51bc0fb076e5e852" }
|
||||
# The following overrides point to dummy projects, as a temporary measure until this is resolved:
|
||||
# https://github.com/rust-lang/cargo/issues/6179
|
||||
js-sys = { git = "https://github.com/kvark/dummy-web" }
|
||||
slotmap = { git = "https://github.com/kvark/dummy-web" }
|
||||
wasm-bindgen = { git = "https://github.com/kvark/dummy-web" }
|
||||
web-sys = { git = "https://github.com/kvark/dummy-web" }
|
||||
|
||||
[patch.crates-io.cranelift-codegen]
|
||||
git = "https://github.com/bytecodealliance/wasmtime"
|
||||
|
@ -19,7 +19,7 @@ extern "C" {
|
||||
|
||||
static void getCurrentValueCB(AtkValue* obj, GValue* value) {
|
||||
Accessible* acc = GetInternalObj(ATK_OBJECT(obj));
|
||||
if (acc) {
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ static void getCurrentValueCB(AtkValue* obj, GValue* value) {
|
||||
|
||||
static void getMaximumValueCB(AtkValue* obj, GValue* value) {
|
||||
Accessible* acc = GetInternalObj(ATK_OBJECT(obj));
|
||||
if (acc) {
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ static void getMaximumValueCB(AtkValue* obj, GValue* value) {
|
||||
|
||||
static void getMinimumValueCB(AtkValue* obj, GValue* value) {
|
||||
Accessible* acc = GetInternalObj(ATK_OBJECT(obj));
|
||||
if (acc) {
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ static void getMinimumValueCB(AtkValue* obj, GValue* value) {
|
||||
|
||||
static void getMinimumIncrementCB(AtkValue* obj, GValue* minimumIncrement) {
|
||||
Accessible* acc = GetInternalObj(ATK_OBJECT(obj));
|
||||
if (acc) {
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -195,9 +195,16 @@ class RemoteAccessibleBase : public Accessible {
|
||||
DocAccessibleParent* AsDoc() const { return IsDoc() ? mDoc : nullptr; }
|
||||
|
||||
void ApplyCache(CacheUpdateType aUpdateType, AccAttributes* aFields) {
|
||||
if (aUpdateType == CacheUpdateType::Initial || !mCachedFields) {
|
||||
if (aUpdateType == CacheUpdateType::Initial) {
|
||||
mCachedFields = aFields;
|
||||
} else {
|
||||
if (!mCachedFields) {
|
||||
// The fields cache can be uninitialized if there were no cache-worthy
|
||||
// fields in the initial cache push.
|
||||
// We don't do a simple assign because we don't want to store the
|
||||
// DeleteEntry entries.
|
||||
mCachedFields = new AccAttributes();
|
||||
}
|
||||
mCachedFields->Update(aFields);
|
||||
}
|
||||
}
|
||||
|
@ -47,9 +47,8 @@ class AboutPrivateBrowsingChild extends RemotePageChild {
|
||||
}
|
||||
|
||||
PrivateBrowsingFeatureConfig() {
|
||||
const config = NimbusFeatures.privatebrowsing.getAllVariables({
|
||||
sendExposureEvent: true,
|
||||
});
|
||||
const config = NimbusFeatures.privatebrowsing.getAllVariables();
|
||||
NimbusFeatures.privatebrowsing.recordExposureEvent();
|
||||
|
||||
// Format urls if any are defined
|
||||
["infoLinkUrl", "promoLinkUrl"].forEach(key => {
|
||||
|
@ -1466,7 +1466,7 @@ pref("browser.newtabpage.activity-stream.asrouter.providers.message-groups", "{\
|
||||
// this page over http opens us up to a man-in-the-middle attack that we'd rather not face. If you are a downstream
|
||||
// repackager of this code using an alternate snippet url, please keep your users safe
|
||||
pref("browser.newtabpage.activity-stream.asrouter.providers.snippets", "{\"id\":\"snippets\",\"enabled\":false,\"type\":\"remote\",\"url\":\"https://snippets.cdn.mozilla.net/%STARTPAGE_VERSION%/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/\",\"updateCycleInMs\":14400000}");
|
||||
pref("browser.newtabpage.activity-stream.asrouter.providers.messaging-experiments", "{\"id\":\"messaging-experiments\",\"enabled\":true,\"type\":\"remote-experiments\",\"messageGroups\":[\"cfr\",\"whats-new-panel\",\"moments-page\",\"aboutwelcome\",\"infobar\"],\"updateCycleInMs\":3600000}");
|
||||
pref("browser.newtabpage.activity-stream.asrouter.providers.messaging-experiments", "{\"id\":\"messaging-experiments\",\"enabled\":true,\"type\":\"remote-experiments\",\"messageGroups\":[\"cfr\",\"whats-new-panel\",\"moments-page\",\"aboutwelcome\",\"infobar\",\"spotlight\"],\"updateCycleInMs\":3600000}");
|
||||
|
||||
// ASRouter user prefs
|
||||
pref("browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons", true);
|
||||
|
4
browser/base/content/logos/vpn-promo-logo.svg
Normal file
4
browser/base/content/logos/vpn-promo-logo.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 18 KiB |
29
browser/base/content/spotlight.html
Normal file
29
browser/base/content/spotlight.html
Normal file
@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src chrome:; object-src 'none'">
|
||||
<meta name="referrer" content="no-referrer">
|
||||
<link rel="stylesheet" type="text/css" href="chrome://global/skin/in-content/common.css">
|
||||
<link rel="stylesheet" type="text/css" href="chrome://browser/skin/spotlight.css">
|
||||
<link rel="localization" href="branding/brand.ftl">
|
||||
<link rel="localization" href="browser/branding/brandings.ftl">
|
||||
<link rel="localization" href="browser/newtab/asrouter.ftl">
|
||||
</head>
|
||||
<body role="dialog" aria-labelledby="title" aria-describedby="content">
|
||||
<template id="logo-and-content">
|
||||
<div id="dialog-content">
|
||||
<img class="logo" alt="" src=""/>
|
||||
<h1 id="title" class="title"></h1>
|
||||
<p id="content" class="text"></p>
|
||||
<button id="primary" class="primary"></button>
|
||||
<button id="secondary" class="secondary text-link"></button>
|
||||
</div>
|
||||
</template>
|
||||
<script src="chrome://browser/content/spotlight.js"></script>
|
||||
</body>
|
||||
</html>
|
54
browser/base/content/spotlight.js
Normal file
54
browser/base/content/spotlight.js
Normal file
@ -0,0 +1,54 @@
|
||||
/* 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/. */
|
||||
|
||||
const { document: gDoc } = window.docShell.chromeEventHandler.ownerGlobal;
|
||||
|
||||
function renderSpotlight() {
|
||||
const [content, params] = window.arguments[0];
|
||||
const template = document.querySelector(`#${content?.template}`);
|
||||
const clone = template.content.cloneNode(true);
|
||||
|
||||
document.body.classList.add(content.template);
|
||||
|
||||
let imageEl = clone.querySelector(".logo");
|
||||
imageEl.src = content.logoImageURL;
|
||||
|
||||
for (let textProp in content.body) {
|
||||
let el = clone.querySelector(`.${textProp}`);
|
||||
if (!content.body[textProp]?.label) {
|
||||
el.remove();
|
||||
continue;
|
||||
}
|
||||
if (content.body[textProp].label.string_id) {
|
||||
document.l10n.setAttributes(el, content.body[textProp].label.string_id);
|
||||
} else {
|
||||
el.textContent = content.body[textProp].label;
|
||||
}
|
||||
}
|
||||
|
||||
document.body.appendChild(clone);
|
||||
|
||||
let primaryBtn = document.getElementById("primary");
|
||||
let secondaryBtn = document.getElementById("secondary");
|
||||
if (primaryBtn) {
|
||||
primaryBtn.addEventListener("click", () => {
|
||||
params.primaryBtn = true;
|
||||
window.close();
|
||||
});
|
||||
|
||||
// If we just call focus() at some random time, it'll cause a flush,
|
||||
// which slows things down unnecessarily, so instead we use rAF...
|
||||
requestAnimationFrame(() => {
|
||||
primaryBtn.focus({ preventFocusRing: true });
|
||||
});
|
||||
}
|
||||
if (secondaryBtn) {
|
||||
secondaryBtn.addEventListener("click", () => {
|
||||
params.secondaryBtn = true;
|
||||
window.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
renderSpotlight();
|
@ -16,6 +16,7 @@ browser.jar:
|
||||
content/browser/logos/etp-mobile.svg (content/logos/etp-mobile.svg)
|
||||
content/browser/logos/lockwise.svg (content/logos/lockwise.svg)
|
||||
content/browser/logos/monitor.svg (content/logos/monitor.svg)
|
||||
content/browser/logos/vpn-promo-logo.svg (content/logos/vpn-promo-logo.svg)
|
||||
content/browser/logos/proxy-light.svg (content/logos/proxy-light.svg)
|
||||
content/browser/logos/proxy-dark.svg (content/logos/proxy-dark.svg)
|
||||
content/browser/logos/send.svg (content/logos/send.svg)
|
||||
@ -104,6 +105,8 @@ browser.jar:
|
||||
content/browser/blockedSite.js (content/blockedSite.js)
|
||||
content/browser/upgradeDialog.html (content/upgradeDialog.html)
|
||||
content/browser/upgradeDialog.js (content/upgradeDialog.js)
|
||||
content/browser/spotlight.html (content/spotlight.html)
|
||||
content/browser/spotlight.js (content/spotlight.js)
|
||||
|
||||
% override chrome://global/content/netError.xhtml chrome://browser/content/certerror/aboutNetError.xhtml
|
||||
|
||||
|
@ -91,7 +91,7 @@
|
||||
#downloadsPanel-blockedSubview,
|
||||
#downloadsPanel-mainView {
|
||||
font: caption;
|
||||
width: 35em;
|
||||
min-width: 37em;
|
||||
padding: 0.62em;
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@
|
||||
<panelview id="downloadsPanel-mainView">
|
||||
<vbox class="panel-view-body-unscrollable">
|
||||
<richlistbox id="downloadsListBox"
|
||||
data-l10n-id="downloads-panel-list"
|
||||
data-l10n-id="downloads-panel-items"
|
||||
data-l10n-attrs="style"
|
||||
context="downloadsContextMenu"
|
||||
onmouseover="DownloadsView.onDownloadMouseOver(event);"
|
||||
|
@ -443,12 +443,8 @@ class BaseAboutNewTabService {
|
||||
* This is calculated in the same way the default URL is.
|
||||
*/
|
||||
|
||||
if (
|
||||
NimbusFeatures.aboutwelcome.isEnabled({
|
||||
defaultValue: true,
|
||||
sendExposureEvent: true,
|
||||
})
|
||||
) {
|
||||
NimbusFeatures.aboutwelcome.recordExposureEvent();
|
||||
if (NimbusFeatures.aboutwelcome.isEnabled({ defaultValue: true })) {
|
||||
return ABOUT_WELCOME_URL;
|
||||
}
|
||||
return this.defaultURL;
|
||||
|
@ -15,6 +15,7 @@ const MESSAGE_TYPE_LIST = [
|
||||
"TOOLBAR_PANEL_TELEMETRY",
|
||||
"MOMENTS_PAGE_TELEMETRY",
|
||||
"INFOBAR_TELEMETRY",
|
||||
"SPOTLIGHT_TELEMETRY",
|
||||
"AS_ROUTER_TELEMETRY_USER_EVENT",
|
||||
|
||||
// Admin types
|
||||
|
@ -0,0 +1,140 @@
|
||||
{
|
||||
"title": "Spotlight",
|
||||
"description": "A template with an image, title, content and two buttons.",
|
||||
"version": "1.0.0",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"template": {
|
||||
"type": "string",
|
||||
"description": "Specify the layout template for the Spotlight",
|
||||
"enum": ["logo-and-content"]
|
||||
},
|
||||
"logoImageURL": {
|
||||
"type": "string",
|
||||
"description": "URL for image to use with the content"
|
||||
},
|
||||
"body": {
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"description": "The title shown in the Spotlight message",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Message shown in the header element"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"string_id": {
|
||||
"type": "string",
|
||||
"description": "Id of localized string for the header element"
|
||||
}
|
||||
},
|
||||
"required": ["string_id"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": ["label"]
|
||||
}
|
||||
},
|
||||
"text": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"description": "The content shown in the Spotlight message",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Message shown in the paragraph element"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"string_id": {
|
||||
"type": "string",
|
||||
"description": "Id of localized string for the paragraph element"
|
||||
}
|
||||
},
|
||||
"required": ["string_id"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": ["label"]
|
||||
}
|
||||
},
|
||||
"primary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"description": "The label for the primary button",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Message shown in the button element"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"string_id": {
|
||||
"type": "string",
|
||||
"description": "Id of localized string for the button element"
|
||||
}
|
||||
},
|
||||
"required": ["string_id"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"action": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Action dispatched by the button."
|
||||
},
|
||||
"data": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"required": ["label", "action"]
|
||||
}
|
||||
},
|
||||
"secondary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"description": "The label for the secondary button",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Message shown in the button element"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"string_id": {
|
||||
"type": "string",
|
||||
"description": "Id of localized string for the button element"
|
||||
}
|
||||
},
|
||||
"required": ["string_id"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"required": ["label", "action"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["title", "text", "primary", "secondary"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["body"]
|
||||
}
|
||||
|
@ -2375,7 +2375,7 @@ __webpack_require__.r(__webpack_exports__);
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
const MESSAGE_TYPE_LIST = ["BLOCK_MESSAGE_BY_ID", "USER_ACTION", "IMPRESSION", "TRIGGER", "NEWTAB_MESSAGE_REQUEST", "DOORHANGER_TELEMETRY", "TOOLBAR_BADGE_TELEMETRY", "TOOLBAR_PANEL_TELEMETRY", "MOMENTS_PAGE_TELEMETRY", "INFOBAR_TELEMETRY", "AS_ROUTER_TELEMETRY_USER_EVENT", // Admin types
|
||||
const MESSAGE_TYPE_LIST = ["BLOCK_MESSAGE_BY_ID", "USER_ACTION", "IMPRESSION", "TRIGGER", "NEWTAB_MESSAGE_REQUEST", "DOORHANGER_TELEMETRY", "TOOLBAR_BADGE_TELEMETRY", "TOOLBAR_PANEL_TELEMETRY", "MOMENTS_PAGE_TELEMETRY", "INFOBAR_TELEMETRY", "SPOTLIGHT_TELEMETRY", "AS_ROUTER_TELEMETRY_USER_EVENT", // Admin types
|
||||
"ADMIN_CONNECT_STATE", "UNBLOCK_MESSAGE_BY_ID", "UNBLOCK_ALL", "BLOCK_BUNDLE", "UNBLOCK_BUNDLE", "DISABLE_PROVIDER", "ENABLE_PROVIDER", "EVALUATE_JEXL_EXPRESSION", "EXPIRE_QUERY_CACHE", "FORCE_ATTRIBUTION", "FORCE_WHATSNEW_PANEL", "CLOSE_WHATSNEW_PANEL", "OVERRIDE_MESSAGE", "MODIFY_MESSAGE_JSON", "RESET_PROVIDER_PREF", "SET_PROVIDER_USER_PREF", "RESET_GROUPS_STATE"];
|
||||
const MESSAGE_TYPE_HASH = MESSAGE_TYPE_LIST.reduce((hash, value) => {
|
||||
hash[value] = value;
|
||||
|
@ -994,6 +994,30 @@ What's New panel client_id is reported in all the channels.
|
||||
}
|
||||
```
|
||||
|
||||
## Spotlight pings
|
||||
|
||||
This reports when the user interacts with the Messaging System Spotlight component
|
||||
Similar policy applied as for the Infobar messages: client_id is reported in all
|
||||
the channels. Currently this is only used in experiments.
|
||||
|
||||
```
|
||||
{
|
||||
"experiments" : {
|
||||
"exp1" : {
|
||||
"branch" : "treatment-a"
|
||||
}
|
||||
},
|
||||
"addon_version" : "20210115035053",
|
||||
"release_channel" : "release",
|
||||
"locale" : "en-US",
|
||||
"event" : ["IMPRESSION", "CLICK", "DISMISS"],
|
||||
"client_id" : "c4beb4bf-4feb-9c4e-9587-9323b28c2e50",
|
||||
"version" : "93",
|
||||
"message_id" : "SPOTLIGHT_MESSAGE_93",
|
||||
"browser_session_id" : "93714e76-9919-ca49-b697-5e7c09a1394f"
|
||||
}
|
||||
```
|
||||
|
||||
## Messaging-experiments pings
|
||||
|
||||
As the new experiment platform, the Messaging experiment manager is now managing & operating all the experiments of Firefox Messaging System, including the first-run experience (about:welcome), CFR, Whats-new-panel, Moments Page, and Snippets.
|
||||
|
@ -14,6 +14,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
SnippetsTestMessageProvider:
|
||||
"resource://activity-stream/lib/SnippetsTestMessageProvider.jsm",
|
||||
PanelTestProvider: "resource://activity-stream/lib/PanelTestProvider.jsm",
|
||||
Spotlight: "resource://activity-stream/lib/Spotlight.jsm",
|
||||
ToolbarBadgeHub: "resource://activity-stream/lib/ToolbarBadgeHub.jsm",
|
||||
ToolbarPanelHub: "resource://activity-stream/lib/ToolbarPanelHub.jsm",
|
||||
MomentsPageHub: "resource://activity-stream/lib/MomentsPageHub.jsm",
|
||||
@ -1182,6 +1183,9 @@ class _ASRouter {
|
||||
case "infobar":
|
||||
InfoBar.showInfoBarMessage(browser, message, this.dispatchCFRAction);
|
||||
break;
|
||||
case "spotlight":
|
||||
Spotlight.showSpotlightDialog(browser, message, this.dispatchCFRAction);
|
||||
break;
|
||||
}
|
||||
|
||||
return { message };
|
||||
|
@ -34,7 +34,8 @@ class ASRouterParentProcessMessageHandler {
|
||||
case msg.TOOLBAR_BADGE_TELEMETRY:
|
||||
case msg.TOOLBAR_PANEL_TELEMETRY:
|
||||
case msg.MOMENTS_PAGE_TELEMETRY:
|
||||
case msg.DOORHANGER_TELEMETRY: {
|
||||
case msg.DOORHANGER_TELEMETRY:
|
||||
case msg.SPOTLIGHT_TELEMETRY: {
|
||||
return this.handleTelemetry({ type, data });
|
||||
}
|
||||
default: {
|
||||
|
@ -210,6 +210,44 @@ const MESSAGES = () => [
|
||||
patterns: ["*://*/*.pdf"],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "SPOTLIGHT_MESSAGE_93",
|
||||
template: "spotlight",
|
||||
content: {
|
||||
template: "logo-and-content",
|
||||
logoImageURL: "chrome://browser/content/logos/vpn-promo-logo.svg",
|
||||
body: {
|
||||
title: {
|
||||
label: {
|
||||
string_id: "spotlight-public-wifi-vpn-header",
|
||||
},
|
||||
},
|
||||
text: {
|
||||
label: {
|
||||
string_id: "spotlight-public-wifi-vpn-body",
|
||||
},
|
||||
},
|
||||
primary: {
|
||||
label: {
|
||||
string_id: "spotlight-public-wifi-vpn-primary-button",
|
||||
},
|
||||
action: {
|
||||
type: "OPEN_URL",
|
||||
data: {
|
||||
args: "https://www.mozilla.org/en-US/products/vpn/",
|
||||
where: "tabshifted",
|
||||
},
|
||||
},
|
||||
},
|
||||
secondary: {
|
||||
label: {
|
||||
string_id: "spotlight-public-wifi-vpn-link",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
frequency: { lifetime: 3 },
|
||||
},
|
||||
];
|
||||
|
||||
const PanelTestProvider = {
|
||||
|
65
browser/components/newtab/lib/Spotlight.jsm
Normal file
65
browser/components/newtab/lib/Spotlight.jsm
Normal file
@ -0,0 +1,65 @@
|
||||
/* 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 { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
SpecialMessageActions:
|
||||
"resource://messaging-system/lib/SpecialMessageActions.jsm",
|
||||
});
|
||||
|
||||
const Spotlight = {
|
||||
sendUserEventTelemetry(event, message, dispatch) {
|
||||
const ping = {
|
||||
message_id: message.id,
|
||||
event,
|
||||
};
|
||||
dispatch({
|
||||
type: "SPOTLIGHT_TELEMETRY",
|
||||
data: { action: "spotlight_user_event", ...ping },
|
||||
});
|
||||
},
|
||||
|
||||
async showSpotlightDialog(browser, message, dispatchCFRAction) {
|
||||
const win = browser.ownerGlobal;
|
||||
if (win.gDialogBox.isOpen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let params = { primaryBtn: false, secondaryBtn: false };
|
||||
|
||||
// There are two events named `IMPRESSION` the first one refers to telemetry
|
||||
// while the other refers to ASRouter impressions used for the frequency cap
|
||||
this.sendUserEventTelemetry("IMPRESSION", message, dispatchCFRAction);
|
||||
dispatchCFRAction({ type: "IMPRESSION", data: message });
|
||||
|
||||
await win.gDialogBox.open("chrome://browser/content/spotlight.html", [
|
||||
message.content,
|
||||
params,
|
||||
]);
|
||||
|
||||
// If dismissed or no button is pressed then report telemetry and exit
|
||||
if (params.secondaryBtn || !params.primaryBtn) {
|
||||
this.sendUserEventTelemetry("DISMISS", message, dispatchCFRAction);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (params.primaryBtn) {
|
||||
this.sendUserEventTelemetry("CLICK", message, dispatchCFRAction);
|
||||
SpecialMessageActions.handleAction(
|
||||
message.content.body.primary.action,
|
||||
browser
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
this.Spotlight = Spotlight;
|
||||
|
||||
const EXPORTED_SYMBOLS = ["Spotlight"];
|
@ -620,6 +620,9 @@ this.TelemetryFeed = class TelemetryFeed {
|
||||
case "infobar_user_event":
|
||||
event = await this.applyInfoBarPolicy(event);
|
||||
break;
|
||||
case "spotlight_user_event":
|
||||
event = await this.applySpotlightPolicy(event);
|
||||
break;
|
||||
case "moments_user_event":
|
||||
event = await this.applyMomentsPolicy(event);
|
||||
break;
|
||||
@ -675,6 +678,13 @@ this.TelemetryFeed = class TelemetryFeed {
|
||||
return { ping, pingType: "infobar" };
|
||||
}
|
||||
|
||||
async applySpotlightPolicy(ping) {
|
||||
ping.client_id = await this.telemetryClientId;
|
||||
ping.browser_session_id = browserSessionId;
|
||||
delete ping.action;
|
||||
return { ping, pingType: "spotlight" };
|
||||
}
|
||||
|
||||
/**
|
||||
* Per Bug 1484035, Moments metrics comply with following policies:
|
||||
* 1). In release, it collects impression_id, and treats bucket_id as message_id
|
||||
@ -1004,6 +1014,8 @@ this.TelemetryFeed = class TelemetryFeed {
|
||||
// Intentional fall-through
|
||||
case msg.INFOBAR_TELEMETRY:
|
||||
// Intentional fall-through
|
||||
case msg.SPOTLIGHT_TELEMETRY:
|
||||
// Intentional fall-through
|
||||
case at.AS_ROUTER_TELEMETRY_USER_EVENT:
|
||||
this.handleASRouterUserEvent(action);
|
||||
break;
|
||||
|
@ -32,6 +32,7 @@ https_first_disabled = true
|
||||
[browser_asrouter_snippets.js]
|
||||
https_first_disabled = true
|
||||
[browser_asrouter_snippets_dismiss.js]
|
||||
[browser_asrouter_spotlight.js]
|
||||
[browser_asrouter_targeting.js]
|
||||
[browser_context_menu_item.js]
|
||||
[browser_discovery_render.js]
|
||||
|
@ -1,3 +1,8 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { InfoBar } = ChromeUtils.import(
|
||||
"resource://activity-stream/lib/InfoBar.jsm"
|
||||
);
|
||||
|
@ -0,0 +1,123 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Spotlight } = ChromeUtils.import(
|
||||
"resource://activity-stream/lib/Spotlight.jsm"
|
||||
);
|
||||
const { PanelTestProvider } = ChromeUtils.import(
|
||||
"resource://activity-stream/lib/PanelTestProvider.jsm"
|
||||
);
|
||||
const { BrowserWindowTracker } = ChromeUtils.import(
|
||||
"resource:///modules/BrowserWindowTracker.jsm"
|
||||
);
|
||||
const { SpecialMessageActions } = ChromeUtils.import(
|
||||
"resource://messaging-system/lib/SpecialMessageActions.jsm"
|
||||
);
|
||||
|
||||
function waitForDialog(callback = win => win.close()) {
|
||||
return BrowserTestUtils.promiseAlertDialog(
|
||||
null,
|
||||
"chrome://browser/content/spotlight.html",
|
||||
{ callback, isSubDialog: true }
|
||||
);
|
||||
}
|
||||
|
||||
function showAndWaitForDialog(dialogOptions, callback) {
|
||||
const promise = waitForDialog(callback);
|
||||
Spotlight.showSpotlightDialog(
|
||||
dialogOptions.browser,
|
||||
dialogOptions.message,
|
||||
dialogOptions.dispatchStub
|
||||
);
|
||||
return promise;
|
||||
}
|
||||
|
||||
add_task(async function test_show_spotlight() {
|
||||
let message = (await PanelTestProvider.getMessages()).find(
|
||||
m => m.id === "SPOTLIGHT_MESSAGE_93"
|
||||
);
|
||||
|
||||
Assert.ok(message?.id, "Should find the Spotlight message");
|
||||
|
||||
let dispatchStub = sinon.stub();
|
||||
let browser = BrowserWindowTracker.getTopWindow().gBrowser.selectedBrowser;
|
||||
|
||||
await showAndWaitForDialog({ message, browser, dispatchStub }, async win => {
|
||||
win.document.getElementById("secondary").click();
|
||||
});
|
||||
|
||||
Assert.ok(!gBrowser.ownerGlobal.gDialogBox.isOpen, "Should close Spotlight");
|
||||
});
|
||||
|
||||
add_task(async function test_telemetry() {
|
||||
let message = (await PanelTestProvider.getMessages()).find(
|
||||
m => m.id === "SPOTLIGHT_MESSAGE_93"
|
||||
);
|
||||
|
||||
let dispatchStub = sinon.stub();
|
||||
let browser = BrowserWindowTracker.getTopWindow().gBrowser.selectedBrowser;
|
||||
|
||||
await showAndWaitForDialog({ message, browser, dispatchStub }, async win => {
|
||||
win.document.getElementById("secondary").click();
|
||||
});
|
||||
|
||||
Assert.equal(
|
||||
dispatchStub.callCount,
|
||||
3,
|
||||
"1 IMPRESSION and 2 SPOTLIGHT_TELEMETRY"
|
||||
);
|
||||
Assert.equal(
|
||||
dispatchStub.firstCall.args[0].type,
|
||||
"SPOTLIGHT_TELEMETRY",
|
||||
"Should match"
|
||||
);
|
||||
Assert.equal(
|
||||
dispatchStub.firstCall.args[0].data.event,
|
||||
"IMPRESSION",
|
||||
"Should match"
|
||||
);
|
||||
Assert.equal(
|
||||
dispatchStub.secondCall.args[0].type,
|
||||
"IMPRESSION",
|
||||
"Should match"
|
||||
);
|
||||
Assert.equal(
|
||||
dispatchStub.thirdCall.args[0].type,
|
||||
"SPOTLIGHT_TELEMETRY",
|
||||
"Should match"
|
||||
);
|
||||
Assert.equal(
|
||||
dispatchStub.thirdCall.args[0].data.event,
|
||||
"DISMISS",
|
||||
"Should match"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_primaryButton() {
|
||||
let message = (await PanelTestProvider.getMessages()).find(
|
||||
m => m.id === "SPOTLIGHT_MESSAGE_93"
|
||||
);
|
||||
|
||||
let dispatchStub = sinon.stub();
|
||||
let browser = BrowserWindowTracker.getTopWindow().gBrowser.selectedBrowser;
|
||||
let specialActionStub = sinon.stub(SpecialMessageActions, "handleAction");
|
||||
|
||||
await showAndWaitForDialog({ message, browser, dispatchStub }, async win => {
|
||||
win.document.getElementById("primary").click();
|
||||
});
|
||||
|
||||
Assert.equal(
|
||||
specialActionStub.callCount,
|
||||
1,
|
||||
"Should be called by primary action"
|
||||
);
|
||||
Assert.deepEqual(
|
||||
specialActionStub.firstCall.args[0],
|
||||
message.content.body.primary.action,
|
||||
"Should be called with button action"
|
||||
);
|
||||
|
||||
specialActionStub.restore();
|
||||
});
|
@ -1,6 +1,7 @@
|
||||
import { PanelTestProvider } from "lib/PanelTestProvider.jsm";
|
||||
import update_schema from "content-src/asrouter/templates/OnboardingMessage/UpdateAction.schema.json";
|
||||
import whats_new_schema from "content-src/asrouter/templates/OnboardingMessage/WhatsNewMessage.schema.json";
|
||||
import spotlight_schema from "content-src/asrouter/templates/OnboardingMessage/Spotlight.schema.json";
|
||||
|
||||
describe("PanelTestProvider", () => {
|
||||
let messages;
|
||||
@ -10,7 +11,7 @@ describe("PanelTestProvider", () => {
|
||||
it("should have a message", () => {
|
||||
// Careful: when changing this number make sure that new messages also go
|
||||
// through schema verifications.
|
||||
assert.lengthOf(messages, 9);
|
||||
assert.lengthOf(messages, 10);
|
||||
});
|
||||
it("should be a valid message", () => {
|
||||
const updateMessages = messages.filter(
|
||||
@ -30,4 +31,12 @@ describe("PanelTestProvider", () => {
|
||||
assert.property(message, "order");
|
||||
}
|
||||
});
|
||||
it("should be a valid message", () => {
|
||||
const spotlightMessages = messages.filter(
|
||||
({ template }) => template === "spotlight"
|
||||
);
|
||||
for (let message of spotlightMessages) {
|
||||
assert.jsonSchema(message.content, spotlight_schema);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -20,6 +20,7 @@ const FAKE_UUID = "{foo-123-foo}";
|
||||
const FAKE_ROUTER_MESSAGE_PROVIDER = [{ id: "cfr", enabled: true }];
|
||||
const FAKE_TELEMETRY_ID = "foo123";
|
||||
|
||||
// eslint-disable-next-line max-statements
|
||||
describe("TelemetryFeed", () => {
|
||||
let globals;
|
||||
let sandbox;
|
||||
@ -774,6 +775,16 @@ describe("TelemetryFeed", () => {
|
||||
assert.equal(pingType, "infobar");
|
||||
});
|
||||
});
|
||||
describe("#applySpotlightPolicy", () => {
|
||||
it("should set client_id and set pingType", async () => {
|
||||
let pingData = { action: "foo" };
|
||||
const { ping, pingType } = await instance.applySpotlightPolicy(pingData);
|
||||
|
||||
assert.propertyVal(ping, "client_id", FAKE_TELEMETRY_ID);
|
||||
assert.equal(pingType, "spotlight");
|
||||
assert.notProperty(ping, "action");
|
||||
});
|
||||
});
|
||||
describe("#applyMomentsPolicy", () => {
|
||||
it("should use client_id and message_id in prerelease", async () => {
|
||||
globals.set("UpdateUtils", {
|
||||
@ -1045,6 +1056,18 @@ describe("TelemetryFeed", () => {
|
||||
|
||||
assert.calledOnce(instance.applyMomentsPolicy);
|
||||
});
|
||||
it("should call applySpotlightPolicy if action equals to spotlight_user_event", async () => {
|
||||
const data = {
|
||||
action: "spotlight_user_event",
|
||||
event: "CLICK",
|
||||
message_id: "SPOTLIGHT_MESSAGE_93",
|
||||
};
|
||||
sandbox.stub(instance, "applySpotlightPolicy");
|
||||
const action = ac.ASRouterUserEvent(data);
|
||||
await instance.createASRouterEvent(action);
|
||||
|
||||
assert.calledOnce(instance.applySpotlightPolicy);
|
||||
});
|
||||
it("should call applyUndesiredEventPolicy if action equals to asrouter_undesired_event", async () => {
|
||||
const data = {
|
||||
action: "asrouter_undesired_event",
|
||||
|
@ -260,20 +260,17 @@ class ProviderQuickSuggest extends UrlbarProvider {
|
||||
let isQuickSuggestLinkClicked =
|
||||
details.selIndex == resultIndex && details.selType !== "help";
|
||||
let {
|
||||
qsSuggestion, // The full keyword
|
||||
sponsoredAdvertiser,
|
||||
sponsoredImpressionUrl,
|
||||
sponsoredClickUrl,
|
||||
sponsoredBlockId,
|
||||
} = result.payload;
|
||||
// impression
|
||||
//
|
||||
// Set `search_query` and `matched_keywords` to empty string, both of
|
||||
// them are required fields for the impression, so we need to keep them
|
||||
// in the payload. See bug 1725492 for more details.
|
||||
PartnerLinkAttribution.sendContextualServicesPing(
|
||||
{
|
||||
search_query: "",
|
||||
matched_keywords: "",
|
||||
search_query: details.searchString,
|
||||
matched_keywords: qsSuggestion || details.searchString,
|
||||
advertiser: sponsoredAdvertiser,
|
||||
block_id: sponsoredBlockId,
|
||||
position: telemetryResultIndex,
|
||||
|
@ -505,12 +505,12 @@ function assertCustomImpression(index) {
|
||||
Assert.equal(payload.position, index + 1, "Should set the position");
|
||||
Assert.equal(
|
||||
payload.search_query,
|
||||
"",
|
||||
TEST_SEARCH_STRING,
|
||||
"Should set the search_query to an empty string"
|
||||
);
|
||||
Assert.equal(
|
||||
payload.matched_keywords,
|
||||
"",
|
||||
TEST_SEARCH_STRING,
|
||||
"Should set the matched_keywords to an empty string"
|
||||
);
|
||||
}
|
||||
|
@ -15,8 +15,8 @@ downloads-panel =
|
||||
# The style attribute has the width of the Downloads Panel expressed using
|
||||
# a CSS unit. The longest labels that should fit are usually those of
|
||||
# in-progress and blocked downloads.
|
||||
downloads-panel-list =
|
||||
.style = width: 70ch
|
||||
downloads-panel-items =
|
||||
.style = width: 35em
|
||||
|
||||
downloads-cmd-pause =
|
||||
.label = Pause
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
:root {
|
||||
--downloads-item-height: 6em;
|
||||
--downloads-item-font-size-factor: 0.95;
|
||||
--downloads-item-font-size-factor: 0.80;
|
||||
--downloads-item-details-opacity: 0.7;
|
||||
}
|
||||
|
||||
|
@ -97,6 +97,7 @@
|
||||
* skin/classic/browser/preferences/containers.css (../shared/preferences/containers.css)
|
||||
* skin/classic/browser/preferences/containers-dialog.css (../shared/preferences/containers-dialog.css)
|
||||
skin/classic/browser/upgradeDialog.css (../shared/upgradeDialog.css)
|
||||
skin/classic/browser/spotlight.css (../shared/spotlight.css)
|
||||
skin/classic/browser/upgradeDialog/highlights-24.svg (../shared/upgradeDialog/highlights-24.svg)
|
||||
skin/classic/browser/upgradeDialog/menu-24.svg (../shared/upgradeDialog/menu-24.svg)
|
||||
skin/classic/browser/upgradeDialog/tabs-24.svg (../shared/upgradeDialog/tabs-24.svg)
|
||||
|
71
browser/themes/shared/spotlight.css
Normal file
71
browser/themes/shared/spotlight.css
Normal file
@ -0,0 +1,71 @@
|
||||
/* 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/. */
|
||||
|
||||
/* Cribbed from upgradeDialog.js; whether this is actually still required
|
||||
* is not totally clear, but better to be safe than sorry:
|
||||
*
|
||||
* For some reason SubDialog browser sizing can result in scrollbars, so just
|
||||
* hide the horizontal scrollbar that would have then required vertical
|
||||
* scrollbar. This should be okay as we wrap content for this fixed width
|
||||
* dialog unless the window is actually narrow and really does need
|
||||
* horizontal scrollbars. */
|
||||
@media (min-width: 604px) {
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
width: 604px;
|
||||
padding: 12px 30px;
|
||||
}
|
||||
|
||||
#dialog-content {
|
||||
min-height: 330px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
object-fit: contain;
|
||||
margin-bottom: 13px;
|
||||
}
|
||||
|
||||
#title {
|
||||
font-weight: 500;
|
||||
font-size: 26px;
|
||||
line-height: 36px;
|
||||
text-align: center;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#content {
|
||||
font-weight: 400;
|
||||
font-size: 13px;
|
||||
line-height: 16px;
|
||||
max-width: 372px;
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
#primary {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#secondary {
|
||||
/* make this look like a link rather than a button */
|
||||
background: none;
|
||||
|
||||
/* without this; we fall back to black on mouseover */
|
||||
color: var(--in-content-link-color);
|
||||
|
||||
/* make the font look like the mock */
|
||||
font-size: 13px;
|
||||
line-height: 16px;
|
||||
font-weight: normal;
|
||||
}
|
@ -86,6 +86,7 @@ pth:third_party/python/more_itertools
|
||||
pth:third_party/python/mozilla_version
|
||||
pth:third_party/python/pathspec
|
||||
pth:third_party/python/pep487/lib
|
||||
pth:third_party/python/pip_tools
|
||||
pth:third_party/python/pluggy
|
||||
pth:third_party/python/ply
|
||||
pth:third_party/python/py
|
||||
|
@ -83,7 +83,7 @@ the build system.
|
||||
|
||||
* mach reinvents the virtualenv.
|
||||
|
||||
There is code in ``build/mach_bootstrap.py`` that configures ``sys.path``
|
||||
There is code in ``build/mach_initialize.py`` that configures ``sys.path``
|
||||
much the same way the virtualenv does. There are various bugs tracking
|
||||
this. However, no clear solution has yet been devised. It's not a huge
|
||||
problem and thus not a huge priority.
|
||||
|
@ -26,18 +26,17 @@ from types import ModuleType
|
||||
|
||||
|
||||
STATE_DIR_FIRST_RUN = """
|
||||
mach and the build system store shared state in a common directory on the
|
||||
filesystem. The following directory will be created:
|
||||
Mach and the build system store shared state in a common directory
|
||||
on the filesystem. The following directory will be created:
|
||||
|
||||
{userdir}
|
||||
{}
|
||||
|
||||
If you would like to use a different directory, hit CTRL+c and set the
|
||||
MOZBUILD_STATE_PATH environment variable to the directory you would like to
|
||||
use and re-run mach. For this change to take effect forever, you'll likely
|
||||
want to export this environment variable from your shell's init scripts.
|
||||
If you would like to use a different directory, hit CTRL+c, set the
|
||||
MOZBUILD_STATE_PATH environment variable to the directory you'd like to
|
||||
use, and run Mach again.
|
||||
|
||||
Press ENTER/RETURN to continue or CTRL+c to abort.
|
||||
""".lstrip()
|
||||
""".strip()
|
||||
|
||||
|
||||
# Individual files providing mach commands.
|
||||
@ -79,6 +78,7 @@ MACH_MODULES = [
|
||||
"testing/web-platform/mach_commands.py",
|
||||
"testing/xpcshell/mach_commands.py",
|
||||
"toolkit/components/telemetry/tests/marionette/mach_commands.py",
|
||||
"toolkit/components/glean/build_scripts/mach_commands.py",
|
||||
"tools/browsertime/mach_commands.py",
|
||||
"tools/compare-locales/mach_commands.py",
|
||||
"tools/lint/mach_commands.py",
|
||||
@ -196,7 +196,7 @@ install a recent enough Python 3.
|
||||
""".strip()
|
||||
|
||||
|
||||
def bootstrap(topsrcdir):
|
||||
def initialize(topsrcdir):
|
||||
# Ensure we are running Python 3.6+. We run this check as soon as
|
||||
# possible to avoid a cryptic import/usage error.
|
||||
if sys.version_info < (3, 6):
|
||||
@ -225,6 +225,8 @@ def bootstrap(topsrcdir):
|
||||
site_paths = set(site.getsitepackages() + [site.getusersitepackages()])
|
||||
sys.path = [path for path in sys.path if path not in site_paths]
|
||||
|
||||
state_dir = _create_state_dir()
|
||||
|
||||
sys.path[0:0] = mach_sys_path(topsrcdir)
|
||||
import mach.base
|
||||
import mach.main
|
||||
@ -331,26 +333,6 @@ def bootstrap(topsrcdir):
|
||||
if key is None:
|
||||
return
|
||||
if key == "state_dir":
|
||||
state_dir = get_state_dir()
|
||||
if state_dir == os.environ.get("MOZBUILD_STATE_PATH"):
|
||||
if not os.path.exists(state_dir):
|
||||
print(
|
||||
"Creating global state directory from environment variable: %s"
|
||||
% state_dir
|
||||
)
|
||||
os.makedirs(state_dir, mode=0o770)
|
||||
else:
|
||||
if not os.path.exists(state_dir):
|
||||
if not os.environ.get("MOZ_AUTOMATION"):
|
||||
print(STATE_DIR_FIRST_RUN.format(userdir=state_dir))
|
||||
try:
|
||||
sys.stdin.readline()
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(1)
|
||||
|
||||
print("\nCreating default state directory: %s" % state_dir)
|
||||
os.makedirs(state_dir, mode=0o770)
|
||||
|
||||
return state_dir
|
||||
|
||||
if key == "local_state_dir":
|
||||
@ -380,7 +362,7 @@ def bootstrap(topsrcdir):
|
||||
|
||||
if not driver.settings_paths:
|
||||
# default global machrc location
|
||||
driver.settings_paths.append(get_state_dir())
|
||||
driver.settings_paths.append(state_dir)
|
||||
# always load local repository configuration
|
||||
driver.settings_paths.append(topsrcdir)
|
||||
|
||||
@ -449,6 +431,39 @@ def _finalize_telemetry_glean(telemetry, is_bootstrap, success):
|
||||
telemetry.submit(is_bootstrap)
|
||||
|
||||
|
||||
def _create_state_dir():
|
||||
# Global build system and mach state is stored in a central directory. By
|
||||
# default, this is ~/.mozbuild. However, it can be defined via an
|
||||
# environment variable. We detect first run (by lack of this directory
|
||||
# existing) and notify the user that it will be created. The logic for
|
||||
# creation is much simpler for the "advanced" environment variable use
|
||||
# case. For default behavior, we educate users and give them an opportunity
|
||||
# to react.
|
||||
state_dir = os.environ.get("MOZBUILD_STATE_PATH")
|
||||
if state_dir:
|
||||
if not os.path.exists(state_dir):
|
||||
print(
|
||||
"Creating global state directory from environment variable: {}".format(
|
||||
state_dir
|
||||
)
|
||||
)
|
||||
else:
|
||||
state_dir = os.path.expanduser("~/.mozbuild")
|
||||
if not os.path.exists(state_dir):
|
||||
if not os.environ.get("MOZ_AUTOMATION"):
|
||||
print(STATE_DIR_FIRST_RUN.format(state_dir))
|
||||
try:
|
||||
sys.stdin.readline()
|
||||
print("\n")
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(1)
|
||||
|
||||
print("Creating default state directory: {}".format(state_dir))
|
||||
|
||||
os.makedirs(state_dir, mode=0o770, exist_ok=True)
|
||||
return state_dir
|
||||
|
||||
|
||||
# Hook import such that .pyc/.pyo files without a corresponding .py file in
|
||||
# the source directory are essentially ignored. See further below for details
|
||||
# and caveats.
|
@ -1,7 +1,7 @@
|
||||
packages.txt:build/common_virtualenv_packages.txt
|
||||
# glean-sdk may not be installable if a wheel isn't available
|
||||
# and it has to be built from source.
|
||||
pypi-optional:glean-sdk==36.0.0:telemetry will not be collected
|
||||
pypi-optional:glean-sdk==40.0.0:telemetry will not be collected
|
||||
# Mach gracefully handles the case where `psutil` is unavailable.
|
||||
pypi-optional:psutil==5.8.0:telemetry will be missing some data
|
||||
pypi:zstandard==0.15.2
|
||||
|
@ -115,7 +115,6 @@ gfx/tests/
|
||||
gfx/thebes/
|
||||
gfx/vr/
|
||||
gfx/webrender_bindings/
|
||||
gfx/wgpu/
|
||||
gfx/wgpu_bindings/
|
||||
gfx/wr/
|
||||
gfx/ycbcr/
|
||||
|
@ -2,7 +2,6 @@
|
||||
%include build/sparse-profiles/taskgraph
|
||||
|
||||
[include]
|
||||
path:gfx/wgpu/
|
||||
path:gfx/wr/
|
||||
path:taskcluster/scripts/misc/
|
||||
path:tools/github-sync/
|
||||
|
@ -6,7 +6,7 @@ path:build/moz.configure/checks.configure
|
||||
path:build/moz.configure/init.configure
|
||||
path:build/moz.configure/util.configure
|
||||
# Used for bootstrapping the mach driver.
|
||||
path:build/mach_bootstrap.py
|
||||
path:build/mach_initialize.py
|
||||
path:build/build_virtualenv_packages.txt
|
||||
path:build/common_virtualenv_packages.txt
|
||||
path:build/mach_virtualenv_packages.txt
|
||||
|
@ -67,9 +67,6 @@ path:.cron.yml
|
||||
path:gfx/wr/Cargo.lock
|
||||
path:gfx/wr/ci-scripts/
|
||||
|
||||
# for the wgpu-deps toolchain task
|
||||
path:gfx/wgpu/Cargo.lock
|
||||
|
||||
# for the mar-tools toolchain task
|
||||
path:mfbt/
|
||||
path:modules/libmar/
|
||||
|
@ -1,4 +0,0 @@
|
||||
%include build/sparse-profiles/mach
|
||||
|
||||
[include]
|
||||
path:gfx/wgpu/
|
@ -128,6 +128,8 @@ skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still di
|
||||
[browser_layout_getGrids.js]
|
||||
[browser_layout_simple.js]
|
||||
[browser_markers-cycle-collection.js]
|
||||
skip-if =
|
||||
os == ("linux" && webrender && debug) # Bug 1698179
|
||||
[browser_markers-gc.js]
|
||||
[browser_markers-minor-gc.js]
|
||||
[browser_markers-parse-html.js]
|
||||
|
@ -209,7 +209,7 @@ int32_t BrowsingContext::IndexOf(BrowsingContext* aChild) {
|
||||
return index;
|
||||
}
|
||||
|
||||
WindowContext* BrowsingContext::GetTopWindowContext() {
|
||||
WindowContext* BrowsingContext::GetTopWindowContext() const {
|
||||
if (mParentWindow) {
|
||||
return mParentWindow->TopWindowContext();
|
||||
}
|
||||
@ -859,7 +859,10 @@ void BrowsingContext::Detach(bool aFromIPC) {
|
||||
}
|
||||
});
|
||||
} else if (!aFromIPC) {
|
||||
auto callback = [](auto) {};
|
||||
// Hold a strong reference to ourself until the responses come back to
|
||||
// ensure the BrowsingContext isn't cleaned up before the parent process
|
||||
// acknowledges the discard request.
|
||||
auto callback = [self = RefPtr{this}](auto) {};
|
||||
ContentChild::GetSingleton()->SendDiscardBrowsingContext(this, callback,
|
||||
callback);
|
||||
}
|
||||
@ -963,6 +966,14 @@ bool BrowsingContext::AncestorsAreCurrent() const {
|
||||
}
|
||||
}
|
||||
|
||||
bool BrowsingContext::IsInBFCache() const {
|
||||
if (mozilla::SessionHistoryInParent()) {
|
||||
return mIsInBFCache;
|
||||
}
|
||||
return mParentWindow &&
|
||||
mParentWindow->TopWindowContext()->GetWindowStateSaved();
|
||||
}
|
||||
|
||||
Span<RefPtr<BrowsingContext>> BrowsingContext::Children() const {
|
||||
if (WindowContext* current = mCurrentWindowContext) {
|
||||
return current->Children();
|
||||
|
@ -412,7 +412,7 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
||||
// NOTE: Unlike `GetEmbedderWindowGlobal`, `GetParentWindowContext` does not
|
||||
// cross toplevel content browser boundaries.
|
||||
WindowContext* GetParentWindowContext() const { return mParentWindow; }
|
||||
WindowContext* GetTopWindowContext();
|
||||
WindowContext* GetTopWindowContext() const;
|
||||
|
||||
already_AddRefed<BrowsingContext> GetOpener() const {
|
||||
RefPtr<BrowsingContext> opener(Get(GetOpenerId()));
|
||||
@ -857,7 +857,7 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
||||
|
||||
void FlushSessionStore();
|
||||
|
||||
bool IsInBFCache() const { return mIsInBFCache; }
|
||||
bool IsInBFCache() const;
|
||||
|
||||
bool AllowJavascript() const { return GetAllowJavascript(); }
|
||||
bool CanExecuteScripts() const { return mCanExecuteScripts; }
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "nsGlobalWindowInner.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
@ -67,6 +68,13 @@ bool WindowContext::IsCurrent() const {
|
||||
return mBrowsingContext->mCurrentWindowContext == this;
|
||||
}
|
||||
|
||||
bool WindowContext::IsInBFCache() {
|
||||
if (mozilla::SessionHistoryInParent()) {
|
||||
return mBrowsingContext->IsInBFCache();
|
||||
}
|
||||
return TopWindowContext()->GetWindowStateSaved();
|
||||
}
|
||||
|
||||
nsGlobalWindowInner* WindowContext::GetInnerWindow() const {
|
||||
return mWindowGlobalChild ? mWindowGlobalChild->GetWindowGlobal() : nullptr;
|
||||
}
|
||||
@ -354,6 +362,12 @@ void WindowContext::DidSet(FieldIndex<IDX_HasReportedShadowDOMUsage>,
|
||||
}
|
||||
}
|
||||
|
||||
bool WindowContext::CanSet(FieldIndex<IDX_WindowStateSaved>, bool aValue,
|
||||
ContentParent* aSource) {
|
||||
return !mozilla::SessionHistoryInParent() && IsTop() &&
|
||||
CheckOnlyOwningProcessCanSet(aSource);
|
||||
}
|
||||
|
||||
void WindowContext::CreateFromIPC(IPCInitializer&& aInit) {
|
||||
MOZ_RELEASE_ASSERT(XRE_IsContentProcess(),
|
||||
"Should be a WindowGlobalParent in the parent");
|
||||
|
@ -89,7 +89,11 @@ class BrowsingContextGroup;
|
||||
FIELD(HadLazyLoadImage, bool) \
|
||||
/* Whether we can execute scripts in this WindowContext. Has no effect \
|
||||
* unless scripts are also allowed in the BrowsingContext. */ \
|
||||
FIELD(AllowJavascript, bool)
|
||||
FIELD(AllowJavascript, bool) \
|
||||
/* If this field is `true`, it means that this WindowContext's \
|
||||
* WindowState was saved to be stored in the legacy (non-SHIP) BFCache \
|
||||
* implementation. Always false for SHIP */ \
|
||||
FIELD(WindowStateSaved, bool)
|
||||
|
||||
class WindowContext : public nsISupports, public nsWrapperCache {
|
||||
MOZ_DECL_SYNCED_CONTEXT(WindowContext, MOZ_EACH_WC_FIELD)
|
||||
@ -113,6 +117,9 @@ class WindowContext : public nsISupports, public nsWrapperCache {
|
||||
// BrowsingContext.
|
||||
bool IsCurrent() const;
|
||||
|
||||
// Returns `true` if this WindowContext is currently in the BFCache.
|
||||
bool IsInBFCache();
|
||||
|
||||
bool IsInProcess() const { return mIsInProcess; }
|
||||
|
||||
bool HasBeforeUnload() const { return GetHasBeforeUnload(); }
|
||||
@ -287,6 +294,9 @@ class WindowContext : public nsISupports, public nsWrapperCache {
|
||||
|
||||
void DidSet(FieldIndex<IDX_SHEntryHasUserInteraction>, bool aOldValue);
|
||||
|
||||
bool CanSet(FieldIndex<IDX_WindowStateSaved>, bool aValue,
|
||||
ContentParent* aSource);
|
||||
|
||||
// Overload `DidSet` to get notifications for a particular field being set.
|
||||
//
|
||||
// You can also overload the variant that gets the old value if you need it.
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "mozilla/StaticPrefs_javascript.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -115,11 +116,20 @@ bool CCGCScheduler::GCRunnerFiredDoGC(TimeStamp aDeadline,
|
||||
// Run a GC slice, possibly the first one of a major GC.
|
||||
nsJSContext::IsShrinking is_shrinking = nsJSContext::NonShrinkingGC;
|
||||
if (!InIncrementalGC() && aStep.mReason == JS::GCReason::USER_INACTIVE) {
|
||||
bool do_gc = mWantAtLeastRegularGC;
|
||||
|
||||
if (!mUserIsActive) {
|
||||
mIsCompactingOnUserInactive = true;
|
||||
is_shrinking = nsJSContext::ShrinkingGC;
|
||||
} else if (!mWantAtLeastRegularGC) {
|
||||
// Don't GC now.
|
||||
if (!nsRefreshDriver::IsRegularRateTimerTicking()) {
|
||||
mIsCompactingOnUserInactive = true;
|
||||
is_shrinking = nsJSContext::ShrinkingGC;
|
||||
do_gc = true;
|
||||
} else {
|
||||
// Poke again to restart the timer.
|
||||
PokeShrinkingGC();
|
||||
}
|
||||
}
|
||||
|
||||
if (!do_gc) {
|
||||
using mozilla::ipc::IdleSchedulerChild;
|
||||
IdleSchedulerChild* child =
|
||||
IdleSchedulerChild::GetMainThreadIdleScheduler();
|
||||
@ -233,8 +243,14 @@ void CCGCScheduler::PokeShrinkingGC() {
|
||||
[](nsITimer* aTimer, void* aClosure) {
|
||||
CCGCScheduler* s = static_cast<CCGCScheduler*>(aClosure);
|
||||
s->KillShrinkingGCTimer();
|
||||
s->SetWantMajorGC(JS::GCReason::USER_INACTIVE);
|
||||
s->EnsureGCRunner(0);
|
||||
if (!s->mUserIsActive) {
|
||||
if (!nsRefreshDriver::IsRegularRateTimerTicking()) {
|
||||
s->SetWantMajorGC(JS::GCReason::USER_INACTIVE);
|
||||
s->EnsureGCRunner(0);
|
||||
} else {
|
||||
s->PokeShrinkingGC();
|
||||
}
|
||||
}
|
||||
},
|
||||
this, StaticPrefs::javascript_options_compact_on_user_inactive_delay(),
|
||||
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY, "ShrinkingGCTimerFired");
|
||||
|
@ -6932,7 +6932,7 @@ bool Document::RemoveFromBFCacheSync() {
|
||||
removed = true;
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
if (mozilla::SessionHistoryInParent() && XRE_IsContentProcess()) {
|
||||
if (BrowsingContext* bc = GetBrowsingContext()) {
|
||||
if (bc->IsInBFCache()) {
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
|
@ -959,17 +959,14 @@ nsRect Element::GetClientAreaRect() {
|
||||
presContext && presContext->IsRootContentDocument();
|
||||
if (overlayScrollbars && rootContentDocument &&
|
||||
doc->IsScrollingElement(this)) {
|
||||
// We will always have a pres shell if we have a pres context, and we will
|
||||
// only get here if we have a pres context from the root content document
|
||||
// check
|
||||
PresShell* presShell = doc->GetPresShell();
|
||||
|
||||
// Ensure up to date dimensions, but don't reflow
|
||||
RefPtr<nsViewManager> viewManager = presShell->GetViewManager();
|
||||
if (viewManager) {
|
||||
viewManager->FlushDelayedResize(false);
|
||||
if (PresShell* presShell = doc->GetPresShell()) {
|
||||
// Ensure up to date dimensions, but don't reflow
|
||||
RefPtr<nsViewManager> viewManager = presShell->GetViewManager();
|
||||
if (viewManager) {
|
||||
viewManager->FlushDelayedResize(false);
|
||||
}
|
||||
return nsRect(nsPoint(), presContext->GetVisibleArea().Size());
|
||||
}
|
||||
return nsRect(nsPoint(), presContext->GetVisibleArea().Size());
|
||||
}
|
||||
|
||||
nsIFrame* frame;
|
||||
|
12
dom/base/crashtests/1728670-1-child.html
Normal file
12
dom/base/crashtests/1728670-1-child.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<script>
|
||||
document.documentElement.clientHeight;
|
||||
document.body.clientHeight;
|
||||
</script>
|
||||
<body>
|
||||
<script>
|
||||
document.documentElement.clientHeight;
|
||||
document.body.clientHeight;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
3
dom/base/crashtests/1728670-1.html
Normal file
3
dom/base/crashtests/1728670-1.html
Normal file
@ -0,0 +1,3 @@
|
||||
<html>
|
||||
<iframe src="http://example.org/1728670-1-child.html" style="display: none;">
|
||||
</html>
|
@ -263,3 +263,4 @@ skip-if(ThreadSanitizer) load 1681729.html
|
||||
skip-if(ThreadSanitizer) load 1693049.html
|
||||
skip-if(ThreadSanitizer||Android) load 1697525.html
|
||||
skip-if(ThreadSanitizer||Android) load 1712198.html # Mysterious failure that should be investigated (bug 1712866).
|
||||
skip-if(Android) HTTP load 1728670-1.html
|
||||
|
@ -272,6 +272,7 @@
|
||||
#include "nsIWebProgressListener.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIWidgetListener.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "nsJSPrincipals.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsLayoutStatics.h"
|
||||
@ -2739,7 +2740,8 @@ bool nsPIDOMWindowInner::HasOpenWebSockets() const {
|
||||
}
|
||||
|
||||
bool nsPIDOMWindowInner::IsCurrentInnerWindow() const {
|
||||
if (mBrowsingContext && mBrowsingContext->IsInBFCache()) {
|
||||
if (mozilla::SessionHistoryInParent() && mBrowsingContext &&
|
||||
mBrowsingContext->IsInBFCache()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -7322,6 +7322,11 @@ already_AddRefed<nsISupports> nsGlobalWindowOuter::SaveWindowState() {
|
||||
nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal();
|
||||
NS_ASSERTION(inner, "No inner window to save");
|
||||
|
||||
if (WindowContext* wc = inner->GetWindowContext()) {
|
||||
MOZ_ASSERT(!wc->GetWindowStateSaved());
|
||||
Unused << wc->SetWindowStateSaved(true);
|
||||
}
|
||||
|
||||
// Don't do anything else to this inner window! After this point, all
|
||||
// calls to SetTimeoutOrInterval will create entries in the timeout
|
||||
// list that will only run after this window has come out of the bfcache.
|
||||
@ -7364,6 +7369,11 @@ nsresult nsGlobalWindowOuter::RestoreWindowState(nsISupports* aState) {
|
||||
}
|
||||
}
|
||||
|
||||
if (WindowContext* wc = inner->GetWindowContext()) {
|
||||
MOZ_ASSERT(wc->GetWindowStateSaved());
|
||||
Unused << wc->SetWindowStateSaved(false);
|
||||
}
|
||||
|
||||
inner->Thaw();
|
||||
|
||||
holder->DidRestoreWindow();
|
||||
|
@ -207,7 +207,7 @@ bool GetCanvasContextType(const nsAString& str,
|
||||
}
|
||||
|
||||
if (StaticPrefs::dom_webgpu_enabled()) {
|
||||
if (str.EqualsLiteral("gpupresent")) {
|
||||
if (str.EqualsLiteral("webgpu")) {
|
||||
*out_type = dom::CanvasContextType::WebGPU;
|
||||
return true;
|
||||
}
|
||||
|
@ -2699,12 +2699,13 @@ void ClientWebGLContext::ClearDepth(GLclampf v) { Run<RPROC(ClearDepth)>(v); }
|
||||
|
||||
void ClientWebGLContext::ClearStencil(GLint v) { Run<RPROC(ClearStencil)>(v); }
|
||||
|
||||
void ClientWebGLContext::ColorMaskI(Maybe<GLuint> i, bool r, bool g,
|
||||
bool b, bool a) const {
|
||||
void ClientWebGLContext::ColorMaskI(Maybe<GLuint> i, bool r, bool g, bool b,
|
||||
bool a) const {
|
||||
const FuncScope funcScope(*this, "colorMask");
|
||||
if (IsContextLost()) return;
|
||||
|
||||
const uint8_t mask = uint8_t(r << 0) | uint8_t(g << 1) | uint8_t(b << 2) | uint8_t(a << 3);
|
||||
const uint8_t mask =
|
||||
uint8_t(r << 0) | uint8_t(g << 1) | uint8_t(b << 2) | uint8_t(a << 3);
|
||||
Run<RPROC(ColorMask)>(i, mask);
|
||||
}
|
||||
|
||||
|
@ -110,6 +110,9 @@ interface BrowsingContext {
|
||||
readonly attribute DOMString embedderElementType;
|
||||
|
||||
readonly attribute boolean createdDynamically;
|
||||
|
||||
readonly attribute boolean isInBFCache;
|
||||
|
||||
/**
|
||||
* The sandbox flags on the browsing context. These reflect the value of the
|
||||
* sandbox attribute of the associated IFRAME or CSP-protectable content, if
|
||||
|
@ -27,6 +27,14 @@ interface JSWindowActorParent {
|
||||
*/
|
||||
readonly attribute WindowGlobalParent? manager;
|
||||
|
||||
/**
|
||||
* The WindowContext associated with this JSWindowActorParent. For
|
||||
* JSWindowActorParent this is identical to `manager`, but is also exposed as
|
||||
* `windowContext` for consistency with `JSWindowActorChild`. Until the actor
|
||||
* is initialized, accesses to windowContext will fail.
|
||||
*/
|
||||
readonly attribute WindowContext? windowContext;
|
||||
|
||||
[Throws]
|
||||
readonly attribute CanonicalBrowsingContext? browsingContext;
|
||||
};
|
||||
@ -44,6 +52,12 @@ interface JSWindowActorChild {
|
||||
*/
|
||||
readonly attribute WindowGlobalChild? manager;
|
||||
|
||||
/**
|
||||
* The WindowContext associated with this JSWindowActorChild. Until the actor
|
||||
* is initialized, accesses to windowContext will fail.
|
||||
*/
|
||||
readonly attribute WindowContext? windowContext;
|
||||
|
||||
[Throws]
|
||||
readonly attribute Document? document;
|
||||
|
||||
|
@ -20,6 +20,9 @@ interface WindowContext {
|
||||
|
||||
readonly attribute WindowContext topWindowContext;
|
||||
|
||||
// True if this WindowContext is currently frozen in the BFCache.
|
||||
readonly attribute boolean isInBFCache;
|
||||
|
||||
// True if this window has registered a "beforeunload" event handler.
|
||||
readonly attribute boolean hasBeforeUnload;
|
||||
|
||||
|
@ -1053,13 +1053,13 @@ nsresult EventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
}
|
||||
static MarkerSchema MarkerTypeDisplay() {
|
||||
using MS = MarkerSchema;
|
||||
MS schema{MS::Location::markerChart, MS::Location::markerTable,
|
||||
MS::Location::timelineOverview};
|
||||
MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable,
|
||||
MS::Location::TimelineOverview};
|
||||
schema.SetChartLabel("{marker.data.eventType}");
|
||||
schema.SetTooltipLabel("{marker.data.eventType} - DOMEvent");
|
||||
schema.SetTableLabel("{marker.data.eventType}");
|
||||
schema.AddKeyLabelFormat("latency", "Latency",
|
||||
MS::Format::duration);
|
||||
MS::Format::Duration);
|
||||
return schema;
|
||||
}
|
||||
};
|
||||
|
@ -1310,8 +1310,9 @@ static void GetActionHint(const IMEState& aState, const nsIContent& aContent,
|
||||
|
||||
// Get the input content corresponding to the focused node,
|
||||
// which may be an anonymous child of the input content.
|
||||
nsIContent* inputContent = aContent.FindFirstNonChromeOnlyAccessContent();
|
||||
if (!inputContent->IsHTMLElement(nsGkAtoms::input)) {
|
||||
HTMLInputElement* inputElement = HTMLInputElement::FromNode(
|
||||
aContent.FindFirstNonChromeOnlyAccessContent());
|
||||
if (!inputElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1319,45 +1320,42 @@ static void GetActionHint(const IMEState& aState, const nsIContent& aContent,
|
||||
// return won't submit the form, use "maybenext".
|
||||
bool willSubmit = false;
|
||||
bool isLastElement = false;
|
||||
nsCOMPtr<nsIFormControl> control(do_QueryInterface(inputContent));
|
||||
if (control) {
|
||||
HTMLFormElement* formElement = control->GetForm();
|
||||
// is this a form and does it have a default submit element?
|
||||
if (formElement) {
|
||||
if (formElement->IsLastActiveElement(control)) {
|
||||
isLastElement = true;
|
||||
}
|
||||
|
||||
if (formElement->GetDefaultSubmitElement()) {
|
||||
willSubmit = true;
|
||||
// is this an html form...
|
||||
} else {
|
||||
// ... and does it only have a single text input element ?
|
||||
if (!formElement->ImplicitSubmissionIsDisabled() ||
|
||||
// ... or is this the last non-disabled element?
|
||||
isLastElement) {
|
||||
willSubmit = true;
|
||||
}
|
||||
}
|
||||
HTMLFormElement* formElement = inputElement->GetForm();
|
||||
// is this a form and does it have a default submit element?
|
||||
if (formElement) {
|
||||
if (formElement->IsLastActiveElement(inputElement)) {
|
||||
isLastElement = true;
|
||||
}
|
||||
|
||||
if (!isLastElement && formElement) {
|
||||
// If next tabbable content in form is text control, hint should be "next"
|
||||
// even there is submit in form.
|
||||
if (IsNextFocusableElementTextControl(inputContent->AsElement())) {
|
||||
// This is focusable text control
|
||||
// XXX What good hint for read only field?
|
||||
aActionHint.AssignLiteral("maybenext");
|
||||
return;
|
||||
if (formElement->GetDefaultSubmitElement()) {
|
||||
willSubmit = true;
|
||||
// is this an html form...
|
||||
} else {
|
||||
// ... and does it only have a single text input element ?
|
||||
if (!formElement->ImplicitSubmissionIsDisabled() ||
|
||||
// ... or is this the last non-disabled element?
|
||||
isLastElement) {
|
||||
willSubmit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isLastElement && formElement) {
|
||||
// If next tabbable content in form is text control, hint should be "next"
|
||||
// even there is submit in form.
|
||||
if (IsNextFocusableElementTextControl(inputElement)) {
|
||||
// This is focusable text control
|
||||
// XXX What good hint for read only field?
|
||||
aActionHint.AssignLiteral("maybenext");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!willSubmit) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (control->ControlType() == FormControlType::InputSearch) {
|
||||
if (inputElement->ControlType() == FormControlType::InputSearch) {
|
||||
aActionHint.AssignLiteral("search");
|
||||
return;
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ already_AddRefed<PointerEvent> PointerEvent::Constructor(
|
||||
aParam.mClientX, aParam.mClientY, false, false, false,
|
||||
false, aParam.mButton, aParam.mRelatedTarget);
|
||||
e->InitializeExtraMouseEventDictionaryMembers(aParam);
|
||||
e->mPointerType = Some(aParam.mPointerType);
|
||||
|
||||
WidgetPointerEvent* widgetEvent = e->mEvent->AsPointerEvent();
|
||||
widgetEvent->pointerId = aParam.mPointerId;
|
||||
@ -140,6 +141,11 @@ NS_IMPL_RELEASE_INHERITED(PointerEvent, MouseEvent)
|
||||
|
||||
void PointerEvent::GetPointerType(nsAString& aPointerType,
|
||||
CallerType aCallerType) {
|
||||
if (mPointerType.isSome()) {
|
||||
aPointerType = mPointerType.value();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShouldResistFingerprinting(aCallerType)) {
|
||||
aPointerType.AssignLiteral("mouse");
|
||||
return;
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "mozilla/dom/MouseEvent.h"
|
||||
#include "mozilla/dom/PointerEventBinding.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
class nsPresContext;
|
||||
|
||||
@ -61,6 +62,9 @@ class PointerEvent : public MouseEvent {
|
||||
|
||||
nsTArray<RefPtr<PointerEvent>> mCoalescedEvents;
|
||||
nsTArray<RefPtr<PointerEvent>> mPredictedEvents;
|
||||
|
||||
// This is used to store the pointerType assigned from constructor.
|
||||
Maybe<nsString> mPointerType;
|
||||
};
|
||||
|
||||
void ConvertPointerTypeToString(uint16_t aPointerTypeSrc,
|
||||
|
@ -1756,37 +1756,37 @@ nsGenericHTMLFormElement* HTMLFormElement::GetDefaultSubmitElement() const {
|
||||
}
|
||||
|
||||
bool HTMLFormElement::IsDefaultSubmitElement(
|
||||
const nsIFormControl* aControl) const {
|
||||
MOZ_ASSERT(aControl, "Unexpected call");
|
||||
const nsGenericHTMLFormElement* aElement) const {
|
||||
MOZ_ASSERT(aElement, "Unexpected call");
|
||||
|
||||
if (aControl == mDefaultSubmitElement) {
|
||||
if (aElement == mDefaultSubmitElement) {
|
||||
// Yes, it is
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mDefaultSubmitElement || (aControl != mFirstSubmitInElements &&
|
||||
aControl != mFirstSubmitNotInElements)) {
|
||||
if (mDefaultSubmitElement || (aElement != mFirstSubmitInElements &&
|
||||
aElement != mFirstSubmitNotInElements)) {
|
||||
// It isn't
|
||||
return false;
|
||||
}
|
||||
|
||||
// mDefaultSubmitElement is null, but we have a non-null submit around
|
||||
// (aControl, in fact). figure out whether it's in fact the default submit
|
||||
// (aElement, in fact). figure out whether it's in fact the default submit
|
||||
// and just hasn't been set that way yet. Note that we can't just call
|
||||
// HandleDefaultSubmitRemoval because we might need to notify to handle that
|
||||
// correctly and we don't know whether that's safe right here.
|
||||
if (!mFirstSubmitInElements || !mFirstSubmitNotInElements) {
|
||||
// We only have one first submit; aControl has to be it
|
||||
// We only have one first submit; aElement has to be it
|
||||
return true;
|
||||
}
|
||||
|
||||
// We have both kinds of submits. Check which comes first.
|
||||
nsIFormControl* defaultSubmit =
|
||||
nsGenericHTMLFormElement* defaultSubmit =
|
||||
CompareFormControlPosition(mFirstSubmitInElements,
|
||||
mFirstSubmitNotInElements, this) < 0
|
||||
? mFirstSubmitInElements
|
||||
: mFirstSubmitNotInElements;
|
||||
return aControl == defaultSubmit;
|
||||
return aElement == defaultSubmit;
|
||||
}
|
||||
|
||||
bool HTMLFormElement::ImplicitSubmissionIsDisabled() const {
|
||||
@ -1802,13 +1802,13 @@ bool HTMLFormElement::ImplicitSubmissionIsDisabled() const {
|
||||
}
|
||||
|
||||
bool HTMLFormElement::IsLastActiveElement(
|
||||
const nsIFormControl* aControl) const {
|
||||
MOZ_ASSERT(aControl, "Unexpected call");
|
||||
const nsGenericHTMLFormElement* aElement) const {
|
||||
MOZ_ASSERT(aElement, "Unexpected call");
|
||||
|
||||
for (auto* element : Reversed(mControls->mElements)) {
|
||||
// XXX How about date/time control?
|
||||
if (element->IsTextControl(false) && !element->IsDisabled()) {
|
||||
return element == aControl;
|
||||
return element == aElement;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -201,19 +201,19 @@ class HTMLFormElement final : public nsGenericHTMLElement,
|
||||
bool ImplicitSubmissionIsDisabled() const;
|
||||
|
||||
/**
|
||||
* Check whether a given nsIFormControl is the last single line input control
|
||||
* that is not disabled. aControl is expected to not be null.
|
||||
* Check whether a given nsGenericHTMLFormElement is the last single line
|
||||
* input control that is not disabled. aElement is expected to not be null.
|
||||
*/
|
||||
bool IsLastActiveElement(const nsIFormControl* aControl) const;
|
||||
bool IsLastActiveElement(const nsGenericHTMLFormElement* aElement) const;
|
||||
|
||||
/**
|
||||
* Check whether a given nsIFormControl is the default submit
|
||||
* Check whether a given nsGenericHTMLFormElement is the default submit
|
||||
* element. This is different from just comparing to
|
||||
* GetDefaultSubmitElement() in certain situations inside an update
|
||||
* when GetDefaultSubmitElement() might not be up to date. aControl
|
||||
* when GetDefaultSubmitElement() might not be up to date. aElement
|
||||
* is expected to not be null.
|
||||
*/
|
||||
bool IsDefaultSubmitElement(const nsIFormControl* aControl) const;
|
||||
bool IsDefaultSubmitElement(const nsGenericHTMLFormElement* aElement) const;
|
||||
|
||||
/**
|
||||
* Flag the form to know that a button or image triggered scripted form
|
||||
|
@ -326,9 +326,9 @@ struct ProcessPriorityChange {
|
||||
}
|
||||
static MarkerSchema MarkerTypeDisplay() {
|
||||
using MS = MarkerSchema;
|
||||
MS schema{MS::Location::markerChart, MS::Location::markerTable};
|
||||
schema.AddKeyFormat("Before", MS::Format::string);
|
||||
schema.AddKeyFormat("After", MS::Format::string);
|
||||
MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
|
||||
schema.AddKeyFormat("Before", MS::Format::String);
|
||||
schema.AddKeyFormat("After", MS::Format::String);
|
||||
schema.AddStaticLabelValue("Note",
|
||||
"This is a notification of the priority change "
|
||||
"that was done by the parent process");
|
||||
@ -352,9 +352,9 @@ struct ProcessPriority {
|
||||
}
|
||||
static MarkerSchema MarkerTypeDisplay() {
|
||||
using MS = MarkerSchema;
|
||||
MS schema{MS::Location::markerChart, MS::Location::markerTable};
|
||||
schema.AddKeyFormat("Priority", MS::Format::string);
|
||||
schema.AddKeyFormat("Marker cause", MS::Format::string);
|
||||
MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
|
||||
schema.AddKeyFormat("Priority", MS::Format::String);
|
||||
schema.AddKeyFormat("Marker cause", MS::Format::String);
|
||||
schema.SetAllLabels("priority: {marker.data.Priority}");
|
||||
return schema;
|
||||
}
|
||||
|
@ -108,10 +108,10 @@ struct SubProcessPriorityChange {
|
||||
}
|
||||
static MarkerSchema MarkerTypeDisplay() {
|
||||
using MS = MarkerSchema;
|
||||
MS schema{MS::Location::markerChart, MS::Location::markerTable};
|
||||
schema.AddKeyFormat("pid", MS::Format::integer);
|
||||
schema.AddKeyFormat("Before", MS::Format::string);
|
||||
schema.AddKeyFormat("After", MS::Format::string);
|
||||
MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
|
||||
schema.AddKeyFormat("pid", MS::Format::Integer);
|
||||
schema.AddKeyFormat("Before", MS::Format::String);
|
||||
schema.AddKeyFormat("After", MS::Format::String);
|
||||
schema.SetAllLabels(
|
||||
"priority of child {marker.data.pid}:"
|
||||
" {marker.data.Before} -> {marker.data.After}");
|
||||
@ -135,10 +135,10 @@ struct SubProcessPriority {
|
||||
}
|
||||
static MarkerSchema MarkerTypeDisplay() {
|
||||
using MS = MarkerSchema;
|
||||
MS schema{MS::Location::markerChart, MS::Location::markerTable};
|
||||
schema.AddKeyFormat("pid", MS::Format::integer);
|
||||
schema.AddKeyFormat("Priority", MS::Format::string);
|
||||
schema.AddKeyFormat("Marker cause", MS::Format::string);
|
||||
MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
|
||||
schema.AddKeyFormat("pid", MS::Format::Integer);
|
||||
schema.AddKeyFormat("Priority", MS::Format::String);
|
||||
schema.AddKeyFormat("Marker cause", MS::Format::String);
|
||||
schema.SetAllLabels(
|
||||
"priority of child {marker.data.pid}: {marker.data.Priority}");
|
||||
return schema;
|
||||
|
@ -25,6 +25,10 @@ JSObject* JSWindowActorChild::WrapObject(JSContext* aCx,
|
||||
|
||||
WindowGlobalChild* JSWindowActorChild::GetManager() const { return mManager; }
|
||||
|
||||
WindowContext* JSWindowActorChild::GetWindowContext() const {
|
||||
return mManager ? mManager->WindowContext() : nullptr;
|
||||
}
|
||||
|
||||
void JSWindowActorChild::Init(const nsACString& aName,
|
||||
WindowGlobalChild* aManager) {
|
||||
MOZ_ASSERT(!mManager, "Cannot Init() a JSWindowActorChild twice!");
|
||||
|
@ -57,6 +57,7 @@ class JSWindowActorChild final : public JSActor {
|
||||
}
|
||||
|
||||
WindowGlobalChild* GetManager() const;
|
||||
WindowContext* GetWindowContext() const;
|
||||
void Init(const nsACString& aName, WindowGlobalChild* aManager);
|
||||
void ClearManager() override;
|
||||
Document* GetDocument(ErrorResult& aRv);
|
||||
|
@ -23,6 +23,10 @@ JSObject* JSWindowActorParent::WrapObject(JSContext* aCx,
|
||||
|
||||
WindowGlobalParent* JSWindowActorParent::GetManager() const { return mManager; }
|
||||
|
||||
WindowContext* JSWindowActorParent::GetWindowContext() const {
|
||||
return mManager;
|
||||
}
|
||||
|
||||
void JSWindowActorParent::Init(const nsACString& aName,
|
||||
WindowGlobalParent* aManager) {
|
||||
MOZ_ASSERT(!mManager, "Cannot Init() a JSWindowActorParent twice!");
|
||||
|
@ -46,6 +46,7 @@ class JSWindowActorParent final : public JSActor {
|
||||
}
|
||||
|
||||
WindowGlobalParent* GetManager() const;
|
||||
WindowContext* GetWindowContext() const;
|
||||
void Init(const nsACString& aName, WindowGlobalParent* aManager);
|
||||
void ClearManager() override;
|
||||
CanonicalBrowsingContext* GetBrowsingContext(ErrorResult& aRv);
|
||||
|
@ -214,11 +214,10 @@ class AsyncLogger {
|
||||
}
|
||||
static MarkerSchema MarkerTypeDisplay() {
|
||||
using MS = MarkerSchema;
|
||||
MS schema{MS::Location::markerChart, MS::Location::markerTable};
|
||||
MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
|
||||
schema.SetChartLabel("{marker.data.name}");
|
||||
schema.SetTableLabel("{marker.name} - {marker.data.name}");
|
||||
schema.AddKeyLabelFormat("name", "Comment",
|
||||
MarkerSchema::Format::string);
|
||||
schema.AddKeyLabelFormat("name", "Comment", MS::Format::String);
|
||||
return schema;
|
||||
}
|
||||
};
|
||||
@ -231,7 +230,7 @@ class AsyncLogger {
|
||||
baseprofiler::SpliceableJSONWriter& aWriter) {}
|
||||
static MarkerSchema MarkerTypeDisplay() {
|
||||
using MS = MarkerSchema;
|
||||
MS schema{MS::Location::markerChart, MS::Location::markerTable};
|
||||
MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
|
||||
// Nothing outside the defaults.
|
||||
return schema;
|
||||
}
|
||||
|
@ -62,28 +62,54 @@ LazyLogModule gMediaTrackGraphLog("MediaTrackGraph");
|
||||
*/
|
||||
static nsTHashMap<nsUint32HashKey, MediaTrackGraphImpl*> gGraphs;
|
||||
|
||||
void NativeInputTrack::AudioDataBuffers::SetOutputData(AudioDataValue* aBuffer,
|
||||
size_t aFrames,
|
||||
uint32_t aChannels,
|
||||
TrackRate aRate) {
|
||||
mOutputData = Some(BufferInfo{aBuffer, aFrames, aChannels, aRate});
|
||||
const AudioDataValue* AudioInputSamples::Data() const {
|
||||
return mData.Elements();
|
||||
}
|
||||
|
||||
void NativeInputTrack::AudioDataBuffers::SetInputData(AudioDataValue* aBuffer,
|
||||
size_t aFrames,
|
||||
uint32_t aChannels,
|
||||
TrackRate aRate) {
|
||||
mInputData = Some(BufferInfo{aBuffer, aFrames, aChannels, aRate});
|
||||
size_t AudioInputSamples::FrameCount() const {
|
||||
MOZ_ASSERT(mChannels > 0);
|
||||
return mData.Length() / mChannels;
|
||||
}
|
||||
|
||||
void NativeInputTrack::AudioDataBuffers::Clear(Scope aScope) {
|
||||
if (aScope & Scope::Input) {
|
||||
mInputData.take();
|
||||
TrackRate AudioInputSamples::Rate() const { return mRate; }
|
||||
|
||||
uint32_t AudioInputSamples::Channels() const { return mChannels; }
|
||||
|
||||
bool AudioInputSamples::IsEmpty() const { return mData.IsEmpty(); }
|
||||
|
||||
void AudioInputSamples::Push(const AudioDataValue* aBuffer, size_t aFrames,
|
||||
TrackRate aRate, uint32_t aChannels) {
|
||||
MOZ_ASSERT(aRate > 0);
|
||||
MOZ_ASSERT(aChannels > 0);
|
||||
|
||||
if (mRate == 0) {
|
||||
mRate = aRate;
|
||||
}
|
||||
if (mChannels == 0) {
|
||||
mChannels = aChannels;
|
||||
}
|
||||
|
||||
if (aScope & Scope::Output) {
|
||||
mOutputData.take();
|
||||
MOZ_ASSERT(aRate == mRate);
|
||||
MOZ_ASSERT(aChannels == mChannels);
|
||||
|
||||
CheckedInt<size_t> samples(aFrames);
|
||||
samples *= static_cast<size_t>(aChannels);
|
||||
MOZ_ASSERT(samples.isValid());
|
||||
|
||||
size_t oldLen = mData.Length();
|
||||
size_t newLen = oldLen + samples.value();
|
||||
if (newLen > mData.Capacity()) {
|
||||
mData.SetCapacity(newLen);
|
||||
}
|
||||
mData.SetLengthAndRetainStorage(newLen);
|
||||
AudioDataValue* dest = mData.Elements() + oldLen;
|
||||
PodCopy(dest, aBuffer, samples.value());
|
||||
}
|
||||
|
||||
void AudioInputSamples::Clear() {
|
||||
mRate = 0;
|
||||
mChannels = 0;
|
||||
mData.ClearAndRetainStorage();
|
||||
}
|
||||
|
||||
NativeInputTrack* NativeInputTrack::Create(MediaTrackGraphImpl* aGraph) {
|
||||
@ -109,10 +135,7 @@ size_t NativeInputTrack::RemoveUser() {
|
||||
|
||||
void NativeInputTrack::DestroyImpl() {
|
||||
MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
|
||||
if (mDataHolder) {
|
||||
mDataHolder->Clear(static_cast<AudioDataBuffers::Scope>(
|
||||
AudioDataBuffers::Scope::Input | AudioDataBuffers::Scope::Output));
|
||||
}
|
||||
mInputData.Clear();
|
||||
ProcessedMediaTrack::DestroyImpl();
|
||||
}
|
||||
|
||||
@ -121,27 +144,23 @@ void NativeInputTrack::ProcessInput(GraphTime aFrom, GraphTime aTo,
|
||||
MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
|
||||
TRACE_COMMENT("NativeInputTrack::ProcessInput", "%p", this);
|
||||
|
||||
if (!mDataHolder || !mDataHolder->mInputData) {
|
||||
if (mInputData.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// One NotifyInputData might have multiple following ProcessInput calls, but
|
||||
// we only process one input per NotifyInputData call.
|
||||
NativeInputTrack::AudioDataBuffers::BufferInfo inputInfo =
|
||||
mDataHolder->mInputData.extract();
|
||||
// The number of NotifyInputData and ProcessInput calls could be different. We
|
||||
// always process the input data from NotifyInputData in the first
|
||||
// ProcessInput after the NotifyInputData
|
||||
|
||||
MOZ_ASSERT(mInputChannels == inputInfo.mChannels);
|
||||
MOZ_ASSERT(inputInfo.mChannels >= 1 && inputInfo.mChannels <= 8,
|
||||
"Support up to 8 channels");
|
||||
// The mSegment will be the de-interleaved audio data converted from
|
||||
// mInputData
|
||||
|
||||
GetData<AudioSegment>()->Clear();
|
||||
GetData<AudioSegment>()->AppendFromInterleavedBuffer(
|
||||
inputInfo.mBuffer, inputInfo.mFrames, inputInfo.mChannels,
|
||||
mInputData.Data(), mInputData.FrameCount(), mInputData.Channels(),
|
||||
PRINCIPAL_HANDLE_NONE);
|
||||
|
||||
LOG(LogLevel::Verbose,
|
||||
("NativeInputTrack %p Appending %zu frames of raw audio", this,
|
||||
inputInfo.mFrames));
|
||||
mInputData.Clear();
|
||||
}
|
||||
|
||||
uint32_t NativeInputTrack::NumberOfChannels() const {
|
||||
@ -149,22 +168,13 @@ uint32_t NativeInputTrack::NumberOfChannels() const {
|
||||
return mInputChannels;
|
||||
}
|
||||
|
||||
void NativeInputTrack::InitDataHolderIfNeeded() {
|
||||
MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());
|
||||
if (!mDataHolder) {
|
||||
mDataHolder.emplace();
|
||||
}
|
||||
}
|
||||
|
||||
void NativeInputTrack::NotifyOutputData(MediaTrackGraphImpl* aGraph,
|
||||
AudioDataValue* aBuffer, size_t aFrames,
|
||||
TrackRate aRate, uint32_t aChannels) {
|
||||
MOZ_ASSERT(aGraph->OnGraphThreadOrNotRunning());
|
||||
MOZ_ASSERT(aGraph == mGraph, "Receive output data from another graph");
|
||||
MOZ_ASSERT(mDataHolder);
|
||||
mDataHolder->SetOutputData(aBuffer, aFrames, aChannels, aRate);
|
||||
for (auto& listener : mDataUsers) {
|
||||
listener->NotifyOutputData(aGraph, mDataHolder->mOutputData.value());
|
||||
listener->NotifyOutputData(aGraph, aBuffer, aFrames, aRate, aChannels);
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,9 +182,8 @@ void NativeInputTrack::NotifyInputStopped(MediaTrackGraphImpl* aGraph) {
|
||||
MOZ_ASSERT(aGraph->OnGraphThreadOrNotRunning());
|
||||
MOZ_ASSERT(aGraph == mGraph,
|
||||
"Receive input stopped signal from another graph");
|
||||
MOZ_ASSERT(mDataHolder);
|
||||
mInputChannels = 0;
|
||||
mDataHolder->Clear(AudioDataBuffers::Scope::Input);
|
||||
mInputData.Clear();
|
||||
for (auto& listener : mDataUsers) {
|
||||
listener->NotifyInputStopped(aGraph);
|
||||
}
|
||||
@ -188,15 +197,13 @@ void NativeInputTrack::NotifyInputData(MediaTrackGraphImpl* aGraph,
|
||||
MOZ_ASSERT(aGraph->OnGraphThreadOrNotRunning());
|
||||
MOZ_ASSERT(aGraph == mGraph, "Receive input data from another graph");
|
||||
|
||||
MOZ_ASSERT(mDataHolder);
|
||||
MOZ_ASSERT(aChannels);
|
||||
if (!mInputChannels) {
|
||||
mInputChannels = aChannels;
|
||||
}
|
||||
mDataHolder->SetInputData(const_cast<AudioDataValue*>(aBuffer), aFrames,
|
||||
aChannels, aRate);
|
||||
mInputData.Push(aBuffer, aFrames, aRate, aChannels);
|
||||
for (auto& listener : mDataUsers) {
|
||||
listener->NotifyInputData(aGraph, mDataHolder->mInputData.value(),
|
||||
listener->NotifyInputData(aGraph, aBuffer, aFrames, aRate, aChannels,
|
||||
aAlreadyBuffered);
|
||||
}
|
||||
}
|
||||
@ -205,9 +212,7 @@ void NativeInputTrack::DeviceChanged(MediaTrackGraphImpl* aGraph) {
|
||||
MOZ_ASSERT(aGraph->OnGraphThreadOrNotRunning());
|
||||
MOZ_ASSERT(aGraph == mGraph,
|
||||
"Receive device changed signal from another graph");
|
||||
MOZ_ASSERT(mDataHolder);
|
||||
mDataHolder->Clear(static_cast<AudioDataBuffers::Scope>(
|
||||
AudioDataBuffers::Scope::Input | AudioDataBuffers::Scope::Output));
|
||||
mInputData.Clear();
|
||||
for (auto& listener : mDataUsers) {
|
||||
listener->DeviceChanged(aGraph);
|
||||
}
|
||||
@ -819,7 +824,6 @@ void MediaTrackGraphImpl::OpenAudioInputImpl(CubebUtils::AudioDeviceID aID,
|
||||
return inputTrack.get();
|
||||
});
|
||||
MOZ_ASSERT(track);
|
||||
track->InitDataHolderIfNeeded();
|
||||
|
||||
nsTArray<RefPtr<AudioDataListener>>& listeners = track->mDataUsers;
|
||||
MOZ_ASSERT(!listeners.Contains(aListener), "Don't add a listener twice.");
|
||||
|
@ -101,20 +101,34 @@ class NativeInputTrack;
|
||||
class ProcessedMediaTrack;
|
||||
class SourceMediaTrack;
|
||||
|
||||
// The interleaved audio input data from audio input callbacks
|
||||
class AudioInputSamples {
|
||||
public:
|
||||
AudioInputSamples() = default;
|
||||
~AudioInputSamples() = default;
|
||||
|
||||
const AudioDataValue* Data() const;
|
||||
size_t FrameCount() const;
|
||||
TrackRate Rate() const;
|
||||
uint32_t Channels() const;
|
||||
|
||||
bool IsEmpty() const;
|
||||
void Push(const AudioDataValue* aBuffer, size_t aFrames, TrackRate aRate,
|
||||
uint32_t aChannels);
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
nsTArray<AudioDataValue> mData;
|
||||
TrackRate mRate = 0;
|
||||
uint32_t mChannels = 0;
|
||||
};
|
||||
|
||||
class AudioDataListenerInterface {
|
||||
protected:
|
||||
// Protected destructor, to discourage deletion outside of Release():
|
||||
virtual ~AudioDataListenerInterface() = default;
|
||||
|
||||
public:
|
||||
// Information for the interleaved buffer coming from the audio callbacks
|
||||
struct BufferInfo {
|
||||
AudioDataValue* mBuffer = nullptr;
|
||||
size_t mFrames = 0;
|
||||
uint32_t mChannels = 0;
|
||||
TrackRate mRate = 0;
|
||||
};
|
||||
|
||||
/* These are for cubeb audio input & output streams: */
|
||||
/**
|
||||
* Output data to speakers, for use as the "far-end" data for echo
|
||||
@ -122,19 +136,22 @@ class AudioDataListenerInterface {
|
||||
* chunks.
|
||||
*/
|
||||
virtual void NotifyOutputData(MediaTrackGraphImpl* aGraph,
|
||||
BufferInfo aInfo) = 0;
|
||||
AudioDataValue* aBuffer, size_t aFrames,
|
||||
TrackRate aRate, uint32_t aChannels) = 0;
|
||||
/**
|
||||
* An AudioCallbackDriver with an input stream signaling that it has stopped
|
||||
* for any reason and the AudioDataListener will not be notified of input data
|
||||
* until the driver is restarted or another driver has started.
|
||||
*/
|
||||
virtual void NotifyInputStopped(MediaTrackGraphImpl* aGraph) = 0;
|
||||
|
||||
/**
|
||||
* Input data from a microphone (or other audio source. This is not
|
||||
* guaranteed to be in any particular size chunks.
|
||||
*/
|
||||
virtual void NotifyInputData(MediaTrackGraphImpl* aGraph,
|
||||
const BufferInfo aInfo,
|
||||
const AudioDataValue* aBuffer, size_t aFrames,
|
||||
TrackRate aRate, uint32_t aChannels,
|
||||
uint32_t aAlreadyBuffered) = 0;
|
||||
|
||||
/**
|
||||
|
@ -64,9 +64,6 @@ class NativeInputTrack : public ProcessedMediaTrack {
|
||||
uint32_t aAlreadyBuffered);
|
||||
void DeviceChanged(MediaTrackGraphImpl* aGraph);
|
||||
|
||||
// Other Graph Thread APIs
|
||||
void InitDataHolderIfNeeded();
|
||||
|
||||
// Any thread
|
||||
NativeInputTrack* AsNativeInputTrack() override { return this; }
|
||||
|
||||
@ -75,30 +72,9 @@ class NativeInputTrack : public ProcessedMediaTrack {
|
||||
nsTArray<RefPtr<AudioDataListener>> mDataUsers;
|
||||
|
||||
private:
|
||||
class AudioDataBuffers {
|
||||
public:
|
||||
AudioDataBuffers() = default;
|
||||
void SetOutputData(AudioDataValue* aBuffer, size_t aFrames,
|
||||
uint32_t aChannels, TrackRate aRate);
|
||||
void SetInputData(AudioDataValue* aBuffer, size_t aFrames,
|
||||
uint32_t aChannels, TrackRate aRate);
|
||||
|
||||
enum Scope : unsigned char {
|
||||
Input = 0x01,
|
||||
Output = 0x02,
|
||||
};
|
||||
void Clear(Scope aScope);
|
||||
|
||||
typedef AudioDataListenerInterface::BufferInfo BufferInfo;
|
||||
// Storing the audio output data coming from NotifyOutputData
|
||||
Maybe<BufferInfo> mOutputData;
|
||||
// Storing the audio input data coming from NotifyInputData
|
||||
Maybe<BufferInfo> mInputData;
|
||||
};
|
||||
|
||||
// Only accessed on the graph thread.
|
||||
// Storing the audio data coming from GraphDriver directly.
|
||||
Maybe<AudioDataBuffers> mDataHolder;
|
||||
// Queue the audio input data coming from NotifyInputData. Used in graph
|
||||
// thread only.
|
||||
AudioInputSamples mInputData;
|
||||
|
||||
// Only accessed on the graph thread.
|
||||
uint32_t mInputChannels = 0;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "MediaTrackGraphImpl.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -70,9 +71,7 @@ TEST(TestAudioInputProcessing, UnaccountedPacketizerBuffering)
|
||||
processedTime = 0;
|
||||
nextTime = MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(nrFrames);
|
||||
generator.GenerateInterleaved(buffer.Elements(), nrFrames);
|
||||
aip->NotifyInputData(graph,
|
||||
AudioInputProcessing::BufferInfo{
|
||||
buffer.Elements(), nrFrames, channels, rate},
|
||||
aip->NotifyInputData(graph, buffer.Elements(), nrFrames, rate, channels,
|
||||
nextTime - nrFrames);
|
||||
aip->ProcessInput(graph, nullptr);
|
||||
aip->Pull(graph, processedTime, nextTime, segment.GetDuration(), &segment,
|
||||
@ -90,9 +89,7 @@ TEST(TestAudioInputProcessing, UnaccountedPacketizerBuffering)
|
||||
processedTime = nextTime;
|
||||
nextTime = MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(2 * nrFrames);
|
||||
generator.GenerateInterleaved(buffer.Elements(), nrFrames);
|
||||
aip->NotifyInputData(graph,
|
||||
AudioInputProcessing::BufferInfo{
|
||||
buffer.Elements(), nrFrames, channels, rate},
|
||||
aip->NotifyInputData(graph, buffer.Elements(), nrFrames, rate, channels,
|
||||
nextTime - (2 * nrFrames));
|
||||
aip->ProcessInput(graph, nullptr);
|
||||
aip->Pull(graph, processedTime, nextTime, segment.GetDuration(), &segment,
|
||||
@ -102,3 +99,226 @@ TEST(TestAudioInputProcessing, UnaccountedPacketizerBuffering)
|
||||
|
||||
graph->Destroy();
|
||||
}
|
||||
|
||||
TEST(TestAudioInputProcessing, InputDataCapture)
|
||||
{
|
||||
// This test simulates an audio cut issue happens when using Redmi AirDots.
|
||||
// Similar issues could happen when using other Bluetooth devices like Bose QC
|
||||
// 35 II or Sony WH-XB900N.
|
||||
|
||||
const TrackRate rate = 8000; // So the packetizer takes 80 frames
|
||||
const uint32_t channels = 1;
|
||||
auto graph = MakeRefPtr<NiceMock<MockGraph>>(rate, channels);
|
||||
auto aip = MakeRefPtr<AudioInputProcessing>(channels, PRINCIPAL_HANDLE_NONE);
|
||||
AudioGenerator<AudioDataValue> generator(channels, rate);
|
||||
|
||||
const size_t frames = 72;
|
||||
const size_t bufferSize = frames * channels;
|
||||
nsTArray<AudioDataValue> buffer(bufferSize);
|
||||
buffer.AppendElements(bufferSize);
|
||||
|
||||
GraphTime processedTime;
|
||||
GraphTime nextTime;
|
||||
AudioSegment segment;
|
||||
bool ended;
|
||||
|
||||
aip->Start();
|
||||
|
||||
{
|
||||
// First iteration.
|
||||
// aip will fill (WEBAUDIO_BLOCK_SIZE + packetizer-size) = 128 + 80 = 208
|
||||
// silence frames in begining of its data storage. The iteration will take
|
||||
// (nextTime - segment-duration) = (128 - 0) = 128 frames to segment,
|
||||
// leaving 208 - 128 = 80 silence frames.
|
||||
const TrackTime bufferedFrames = 80U;
|
||||
processedTime = 0;
|
||||
nextTime = MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(frames);
|
||||
|
||||
generator.GenerateInterleaved(buffer.Elements(), frames);
|
||||
aip->NotifyInputData(graph, buffer.Elements(), frames, rate, channels, 0);
|
||||
buffer.ClearAndRetainStorage();
|
||||
aip->ProcessInput(graph, nullptr);
|
||||
aip->Pull(graph, processedTime, nextTime, segment.GetDuration(), &segment,
|
||||
true, &ended);
|
||||
EXPECT_EQ(aip->NumBufferedFrames(graph), bufferedFrames);
|
||||
}
|
||||
|
||||
{
|
||||
// Second iteration.
|
||||
// We will packetize 80 frames to aip's data storage. The last round left 80
|
||||
// frames so we have 80 + 80 = 160 frames. The iteration will take (nextTime
|
||||
// - segment-duration) = (256 - 128) = 128 frames to segment, leaving 160 -
|
||||
// 128 = 32 frames.
|
||||
const TrackTime bufferedFrames = 32U;
|
||||
processedTime = nextTime;
|
||||
nextTime = MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(2 * frames);
|
||||
|
||||
generator.GenerateInterleaved(buffer.Elements(), frames);
|
||||
aip->NotifyInputData(graph, buffer.Elements(), frames, rate, channels,
|
||||
0 /* ignored */);
|
||||
buffer.ClearAndRetainStorage();
|
||||
aip->ProcessInput(graph, nullptr);
|
||||
aip->Pull(graph, processedTime, nextTime, segment.GetDuration(), &segment,
|
||||
true, &ended);
|
||||
EXPECT_EQ(aip->NumBufferedFrames(graph), bufferedFrames);
|
||||
}
|
||||
|
||||
{
|
||||
// Third iteration.
|
||||
// Sometimes AudioCallbackDriver's buffer, whose type is
|
||||
// AudioCallbackBufferWrapper, could be unavailable, and therefore
|
||||
// ProcessInput won't be called. In this case, we should queue the audio
|
||||
// data and process them when ProcessInput can be called again.
|
||||
processedTime = nextTime;
|
||||
nextTime = MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(3 * frames);
|
||||
// Note that processedTime is *equal* to nextTime (processedTime ==
|
||||
// nextTime) now but it's ok since we don't call ProcessInput here.
|
||||
|
||||
generator.GenerateInterleaved(buffer.Elements(), frames);
|
||||
aip->NotifyInputData(graph, buffer.Elements(), frames, rate, channels,
|
||||
0 /* ignored */);
|
||||
Unused << processedTime;
|
||||
buffer.ClearAndRetainStorage();
|
||||
}
|
||||
|
||||
{
|
||||
// Fourth iteration.
|
||||
// We will packetize 80 (previous round) + 80 (this round) = 160 frames to
|
||||
// aip's data storage. 32 frames are left after the second iteration, so we
|
||||
// have 160 + 32 = 192 frames. The iteration will take (nextTime
|
||||
// - segment-duration) = (384 - 256) = 128 frames to segment, leaving 192 -
|
||||
// 128 = 64 frames.
|
||||
const TrackTime bufferedFrames = 64U;
|
||||
processedTime = nextTime;
|
||||
nextTime = MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(4 * frames);
|
||||
generator.GenerateInterleaved(buffer.Elements(), frames);
|
||||
aip->NotifyInputData(graph, buffer.Elements(), frames, rate, channels,
|
||||
0 /* ignored */);
|
||||
buffer.ClearAndRetainStorage();
|
||||
aip->ProcessInput(graph, nullptr);
|
||||
aip->Pull(graph, processedTime, nextTime, segment.GetDuration(), &segment,
|
||||
true, &ended);
|
||||
EXPECT_EQ(aip->NumBufferedFrames(graph), bufferedFrames);
|
||||
}
|
||||
|
||||
// TODO: Add a similar test for aip->SetPassThrough(true)
|
||||
|
||||
graph->Destroy();
|
||||
}
|
||||
|
||||
TEST(TestAudioInputProcessing, InputDataCapturePassThrough)
|
||||
{
|
||||
// This test simulates an audio cut issue happens when using Redmi AirDots.
|
||||
// Similar issues could happen when using other Bluetooth devices like Bose QC
|
||||
// 35 II or Sony WH-XB900N.
|
||||
|
||||
const TrackRate rate = 8000; // So the packetizer takes 80 frames
|
||||
const uint32_t channels = 1;
|
||||
auto graph = MakeRefPtr<NiceMock<MockGraph>>(rate, channels);
|
||||
auto aip = MakeRefPtr<AudioInputProcessing>(channels, PRINCIPAL_HANDLE_NONE);
|
||||
AudioGenerator<AudioDataValue> generator(channels, rate);
|
||||
|
||||
const size_t frames = 72;
|
||||
const size_t bufferSize = frames * channels;
|
||||
nsTArray<AudioDataValue> buffer(bufferSize);
|
||||
buffer.AppendElements(bufferSize);
|
||||
|
||||
GraphTime processedTime;
|
||||
GraphTime nextTime;
|
||||
AudioSegment segment;
|
||||
AudioSegment source;
|
||||
bool ended;
|
||||
|
||||
aip->SetPassThrough(graph, true);
|
||||
aip->Start();
|
||||
|
||||
{
|
||||
// First iteration.
|
||||
// aip will fill (WEBAUDIO_BLOCK_SIZE + ) = 128 + 72 = 200 silence frames in
|
||||
// begining of its data storage. The iteration will take (nextTime -
|
||||
// segment-duration) = (128 - 0) = 128 frames to segment, leaving 200 - 128
|
||||
// = 72 silence frames.
|
||||
const TrackTime bufferedFrames = 72U;
|
||||
processedTime = 0;
|
||||
nextTime = MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(frames);
|
||||
|
||||
generator.GenerateInterleaved(buffer.Elements(), frames);
|
||||
source.AppendFromInterleavedBuffer(buffer.Elements(), frames, channels,
|
||||
PRINCIPAL_HANDLE_NONE);
|
||||
aip->NotifyInputData(graph, buffer.Elements(), frames, rate, channels, 0);
|
||||
buffer.ClearAndRetainStorage();
|
||||
aip->ProcessInput(graph, &source);
|
||||
aip->Pull(graph, processedTime, nextTime, segment.GetDuration(), &segment,
|
||||
true, &ended);
|
||||
EXPECT_EQ(aip->NumBufferedFrames(graph), bufferedFrames);
|
||||
source.Clear();
|
||||
}
|
||||
|
||||
{
|
||||
// Second iteration.
|
||||
// We will feed 72 frames to aip's data storage. The last round left 72
|
||||
// frames so we have 72 + 72 = 144 frames. The iteration will take (nextTime
|
||||
// - segment-duration) = (256 - 128) = 128 frames to segment, leaving 144 -
|
||||
// 128 = 16 frames.
|
||||
const TrackTime bufferedFrames = 16U;
|
||||
processedTime = nextTime;
|
||||
nextTime = MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(2 * frames);
|
||||
|
||||
generator.GenerateInterleaved(buffer.Elements(), frames);
|
||||
source.AppendFromInterleavedBuffer(buffer.Elements(), frames, channels,
|
||||
PRINCIPAL_HANDLE_NONE);
|
||||
aip->NotifyInputData(graph, buffer.Elements(), frames, rate, channels,
|
||||
0 /* ignored */);
|
||||
buffer.ClearAndRetainStorage();
|
||||
aip->ProcessInput(graph, &source);
|
||||
aip->Pull(graph, processedTime, nextTime, segment.GetDuration(), &segment,
|
||||
true, &ended);
|
||||
EXPECT_EQ(aip->NumBufferedFrames(graph), bufferedFrames);
|
||||
source.Clear();
|
||||
}
|
||||
|
||||
{
|
||||
// Third iteration.
|
||||
// Sometimes AudioCallbackDriver's buffer, whose type is
|
||||
// AudioCallbackBufferWrapper, could be unavailable, and therefore
|
||||
// ProcessInput won't be called. In this case, we should queue the audio
|
||||
// data and process them when ProcessInput can be called again.
|
||||
processedTime = nextTime;
|
||||
nextTime = MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(3 * frames);
|
||||
// Note that processedTime is *equal* to nextTime (processedTime ==
|
||||
// nextTime) now but it's ok since we don't call ProcessInput here.
|
||||
|
||||
generator.GenerateInterleaved(buffer.Elements(), frames);
|
||||
source.AppendFromInterleavedBuffer(buffer.Elements(), frames, channels,
|
||||
PRINCIPAL_HANDLE_NONE);
|
||||
aip->NotifyInputData(graph, buffer.Elements(), frames, rate, channels,
|
||||
0 /* ignored */);
|
||||
Unused << processedTime;
|
||||
buffer.ClearAndRetainStorage();
|
||||
}
|
||||
|
||||
{
|
||||
// Fourth iteration.
|
||||
// We will feed 72 (previous round) + 72 (this round) = 144 frames to aip's
|
||||
// data storage. 16 frames are left after the second iteration, so we have
|
||||
// 144 + 16 = 160 frames. The iteration will take (nextTime -
|
||||
// segment-duration) = (384 - 256) = 128 frames to segment, leaving 160 -
|
||||
// 128 = 32 frames.
|
||||
const TrackTime bufferedFrames = 32U;
|
||||
processedTime = nextTime;
|
||||
nextTime = MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(4 * frames);
|
||||
generator.GenerateInterleaved(buffer.Elements(), frames);
|
||||
source.AppendFromInterleavedBuffer(buffer.Elements(), frames, channels,
|
||||
PRINCIPAL_HANDLE_NONE);
|
||||
aip->NotifyInputData(graph, buffer.Elements(), frames, rate, channels,
|
||||
0 /* ignored */);
|
||||
buffer.ClearAndRetainStorage();
|
||||
aip->ProcessInput(graph, &source);
|
||||
aip->Pull(graph, processedTime, nextTime, segment.GetDuration(), &segment,
|
||||
true, &ended);
|
||||
EXPECT_EQ(aip->NumBufferedFrames(graph), bufferedFrames);
|
||||
source.Clear();
|
||||
}
|
||||
|
||||
graph->Destroy();
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
window.addEventListener('load', () => {
|
||||
SpecialPowers.Components.classes["@mozilla.org/peerconnection;1"].createInstance(SpecialPowers.Components.interfaces.nsIArray);
|
||||
})
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
|
@ -35,4 +35,3 @@ load 1576938.html
|
||||
skip-if(Android) pref(media.getusermedia.audiocapture.enabled,true) load 1573536.html
|
||||
skip-if(!Android) pref(media.getusermedia.audiocapture.enabled,true) pref(media.navigator.permission.device,false) load 1573536.html # media.navigator.permission.device is mobile-only, so other platforms fail to set it (Bug 1350948)
|
||||
load 1594136.html
|
||||
load 1717318.html
|
||||
|
@ -886,20 +886,21 @@ void AudioInputProcessing::Pull(MediaTrackGraphImpl* aGraph, GraphTime aFrom,
|
||||
}
|
||||
|
||||
void AudioInputProcessing::NotifyOutputData(MediaTrackGraphImpl* aGraph,
|
||||
BufferInfo aInfo) {
|
||||
AudioDataValue* aBuffer,
|
||||
size_t aFrames, TrackRate aRate,
|
||||
uint32_t aChannels) {
|
||||
MOZ_ASSERT(aGraph->OnGraphThread());
|
||||
MOZ_ASSERT(mEnabled);
|
||||
|
||||
if (!mPacketizerOutput ||
|
||||
mPacketizerOutput->mPacketSize != aInfo.mRate / 100u ||
|
||||
mPacketizerOutput->mChannels != aInfo.mChannels) {
|
||||
if (!mPacketizerOutput || mPacketizerOutput->mPacketSize != aRate / 100u ||
|
||||
mPacketizerOutput->mChannels != aChannels) {
|
||||
// It's ok to drop the audio still in the packetizer here: if this changes,
|
||||
// we changed devices or something.
|
||||
mPacketizerOutput = MakeUnique<AudioPacketizer<AudioDataValue, float>>(
|
||||
aInfo.mRate / 100, aInfo.mChannels);
|
||||
aRate / 100, aChannels);
|
||||
}
|
||||
|
||||
mPacketizerOutput->Input(aInfo.mBuffer, aInfo.mFrames);
|
||||
mPacketizerOutput->Input(aBuffer, aFrames);
|
||||
|
||||
while (mPacketizerOutput->PacketsAvailable()) {
|
||||
uint32_t samplesPerPacket =
|
||||
@ -918,11 +919,11 @@ void AudioInputProcessing::NotifyOutputData(MediaTrackGraphImpl* aGraph,
|
||||
uint32_t channelCountFarend = 0;
|
||||
uint32_t framesPerPacketFarend = 0;
|
||||
|
||||
// Downmix from aInfo.mChannels to MAX_CHANNELS if needed. We always have
|
||||
// Downmix from aChannels to MAX_CHANNELS if needed. We always have
|
||||
// floats here, the packetized performed the conversion.
|
||||
if (aInfo.mChannels > MAX_CHANNELS) {
|
||||
if (aChannels > MAX_CHANNELS) {
|
||||
AudioConverter converter(
|
||||
AudioConfig(aInfo.mChannels, 0, AudioConfig::FORMAT_FLT),
|
||||
AudioConfig(aChannels, 0, AudioConfig::FORMAT_FLT),
|
||||
AudioConfig(MAX_CHANNELS, 0, AudioConfig::FORMAT_FLT));
|
||||
framesPerPacketFarend = mPacketizerOutput->mPacketSize;
|
||||
framesPerPacketFarend =
|
||||
@ -932,9 +933,9 @@ void AudioInputProcessing::NotifyOutputData(MediaTrackGraphImpl* aGraph,
|
||||
deinterleavedPacketDataChannelPointers.SetLength(MAX_CHANNELS);
|
||||
} else {
|
||||
interleavedFarend = packet;
|
||||
channelCountFarend = aInfo.mChannels;
|
||||
channelCountFarend = aChannels;
|
||||
framesPerPacketFarend = mPacketizerOutput->mPacketSize;
|
||||
deinterleavedPacketDataChannelPointers.SetLength(aInfo.mChannels);
|
||||
deinterleavedPacketDataChannelPointers.SetLength(aChannels);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(interleavedFarend &&
|
||||
@ -960,7 +961,7 @@ void AudioInputProcessing::NotifyOutputData(MediaTrackGraphImpl* aGraph,
|
||||
|
||||
// Having the same config for input and output means we potentially save
|
||||
// some CPU.
|
||||
StreamConfig inputConfig(aInfo.mRate, channelCountFarend, false);
|
||||
StreamConfig inputConfig(aRate, channelCountFarend, false);
|
||||
StreamConfig outputConfig = inputConfig;
|
||||
|
||||
// Passing the same pointers here saves a copy inside this function.
|
||||
@ -1102,29 +1103,35 @@ void AudioInputProcessing::ProcessInput(MediaTrackGraphImpl* aGraph,
|
||||
MOZ_ASSERT(aGraph);
|
||||
MOZ_ASSERT(aGraph->OnGraphThread());
|
||||
|
||||
if (mEnded || !mEnabled || !mLiveBufferingAppended || !mInputData) {
|
||||
if (mEnded || !mEnabled || !mLiveBufferingAppended ||
|
||||
mPendingData.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// One NotifyInputData might have multiple following ProcessInput calls, but
|
||||
// we only process one input per NotifyInputData call.
|
||||
BufferInfo inputInfo = mInputData.extract();
|
||||
// The number of NotifyInputData and ProcessInput calls could be different. We
|
||||
// always process the input data from NotifyInputData in the first
|
||||
// ProcessInput after the NotifyInputData
|
||||
|
||||
// If some processing is necessary, packetize and insert in the WebRTC.org
|
||||
// code. Otherwise, directly insert the mic data in the MTG, bypassing all
|
||||
// processing.
|
||||
if (PassThrough(aGraph)) {
|
||||
if (aSegment) {
|
||||
if (aSegment && !aSegment->IsEmpty()) {
|
||||
mSegment.AppendSegment(aSegment, mPrincipal);
|
||||
} else {
|
||||
mSegment.AppendFromInterleavedBuffer(inputInfo.mBuffer, inputInfo.mFrames,
|
||||
inputInfo.mChannels, mPrincipal);
|
||||
mSegment.AppendFromInterleavedBuffer(mPendingData.Data(),
|
||||
mPendingData.FrameCount(),
|
||||
mPendingData.Channels(), mPrincipal);
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(aGraph->GraphRate() == inputInfo.mRate);
|
||||
PacketizeAndProcess(aGraph, inputInfo.mBuffer, inputInfo.mFrames,
|
||||
inputInfo.mRate, inputInfo.mChannels);
|
||||
MOZ_ASSERT(aGraph->GraphRate() == mPendingData.Rate());
|
||||
// Bug 1729041: Feed aSegment to PacketizeAndProcess so mPendingData can be
|
||||
// removed, and save a copy.
|
||||
PacketizeAndProcess(aGraph, mPendingData.Data(), mPendingData.FrameCount(),
|
||||
mPendingData.Rate(), mPendingData.Channels());
|
||||
}
|
||||
|
||||
mPendingData.Clear();
|
||||
}
|
||||
|
||||
void AudioInputProcessing::NotifyInputStopped(MediaTrackGraphImpl* aGraph) {
|
||||
@ -1138,13 +1145,15 @@ void AudioInputProcessing::NotifyInputStopped(MediaTrackGraphImpl* aGraph) {
|
||||
if (mPacketizerInput) {
|
||||
mPacketizerInput->Clear();
|
||||
}
|
||||
mInputData.take();
|
||||
mPendingData.Clear();
|
||||
}
|
||||
|
||||
// Called back on GraphDriver thread!
|
||||
// Note this can be called back after ::Stop()
|
||||
void AudioInputProcessing::NotifyInputData(MediaTrackGraphImpl* aGraph,
|
||||
const BufferInfo aInfo,
|
||||
const AudioDataValue* aBuffer,
|
||||
size_t aFrames, TrackRate aRate,
|
||||
uint32_t aChannels,
|
||||
uint32_t aAlreadyBuffered) {
|
||||
MOZ_ASSERT(aGraph->OnGraphThread());
|
||||
TRACE("AudioInputProcessing::NotifyInputData");
|
||||
@ -1157,7 +1166,7 @@ void AudioInputProcessing::NotifyInputData(MediaTrackGraphImpl* aGraph,
|
||||
mLiveBufferingAppended = Some(aAlreadyBuffered);
|
||||
}
|
||||
|
||||
mInputData = Some(aInfo);
|
||||
mPendingData.Push(aBuffer, aFrames, aRate, aChannels);
|
||||
}
|
||||
|
||||
#define ResetProcessingIfNeeded(_processing) \
|
||||
@ -1191,7 +1200,7 @@ void AudioInputProcessing::DeviceChanged(MediaTrackGraphImpl* aGraph) {
|
||||
void AudioInputProcessing::End() {
|
||||
mEnded = true;
|
||||
mSegment.Clear();
|
||||
mInputData.take();
|
||||
mPendingData.Clear();
|
||||
}
|
||||
|
||||
TrackTime AudioInputProcessing::NumBufferedFrames(
|
||||
|
@ -141,9 +141,13 @@ class AudioInputProcessing : public AudioDataListener {
|
||||
GraphTime aTrackEnd, AudioSegment* aSegment,
|
||||
bool aLastPullThisIteration, bool* aEnded);
|
||||
|
||||
void NotifyOutputData(MediaTrackGraphImpl* aGraph, BufferInfo aInfo) override;
|
||||
void NotifyOutputData(MediaTrackGraphImpl* aGraph, AudioDataValue* aBuffer,
|
||||
size_t aFrames, TrackRate aRate,
|
||||
uint32_t aChannels) override;
|
||||
void NotifyInputStopped(MediaTrackGraphImpl* aGraph) override;
|
||||
void NotifyInputData(MediaTrackGraphImpl* aGraph, const BufferInfo aInfo,
|
||||
void NotifyInputData(MediaTrackGraphImpl* aGraph,
|
||||
const AudioDataValue* aBuffer, size_t aFrames,
|
||||
TrackRate aRate, uint32_t aChannels,
|
||||
uint32_t aAlreadyBuffered) override;
|
||||
bool IsVoiceInput(MediaTrackGraphImpl* aGraph) const override {
|
||||
// If we're passing data directly without AEC or any other process, this
|
||||
@ -241,7 +245,7 @@ class AudioInputProcessing : public AudioDataListener {
|
||||
// Whether or not we've ended and removed the AudioInputTrack.
|
||||
bool mEnded;
|
||||
// Store the unprocessed interleaved audio input data
|
||||
Maybe<BufferInfo> mInputData;
|
||||
AudioInputSamples mPendingData;
|
||||
};
|
||||
|
||||
// MediaTrack subclass tailored for MediaEngineWebRTCMicrophoneSource.
|
||||
|
@ -100,10 +100,14 @@ bool WebrtcAudioConduit::SetLocalSSRCs(const std::vector<uint32_t>& aSSRCs,
|
||||
if (mSendStreamConfig.rtp.ssrc == aSSRCs[0]) {
|
||||
return true;
|
||||
}
|
||||
// Update the value of the ssrcs in the config structure.
|
||||
mRecvStreamConfig.rtp.local_ssrc = aSSRCs[0];
|
||||
mSendStreamConfig.rtp.ssrc = aSSRCs[0];
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex); // Avoid racing against GetLocalSSRCs
|
||||
// Update the value of the ssrcs in the config structure.
|
||||
mRecvStreamConfig.rtp.local_ssrc = aSSRCs[0];
|
||||
}
|
||||
|
||||
mSendStreamConfig.rtp.ssrc = aSSRCs[0];
|
||||
mRecvChannelProxy->SetLocalSSRC(aSSRCs[0]);
|
||||
|
||||
return RecreateSendStreamIfExists();
|
||||
|
@ -35,6 +35,7 @@ prefs =
|
||||
network.proxy.allow_hijacking_localhost=true
|
||||
|
||||
[test_1488832.html]
|
||||
[test_1717318.html]
|
||||
[test_a_noOp.html]
|
||||
scheme=http
|
||||
[test_dataChannel_basicAudio.html]
|
||||
|
26
dom/media/webrtc/tests/mochitests/test_1717318.html
Normal file
26
dom/media/webrtc/tests/mochitests/test_1717318.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>PC construct with no global object (bug 1717318)</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script class="testbody" type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
// nsIArray is not special here, it could be pretty much any interface.
|
||||
// We do this outside the try block just in case someday the interface is
|
||||
// removed.
|
||||
const dummyInterface = SpecialPowers.Components.interfaces.nsIArray;
|
||||
ok(dummyInterface, "nsIArray should exist");
|
||||
try {
|
||||
// Just don't crash.
|
||||
SpecialPowers.Components.classes["@mozilla.org/peerconnection;1"]
|
||||
.createInstance(dummyInterface);
|
||||
} catch (e) {}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -335,7 +335,7 @@ void NrSocketBase::fire_callback(int how) {
|
||||
}
|
||||
|
||||
// NrSocket implementation
|
||||
NS_IMPL_ISUPPORTS0(NrSocket)
|
||||
NS_IMPL_QUERY_INTERFACE0(NrSocket)
|
||||
|
||||
// The nsASocket callbacks
|
||||
void NrSocket::OnSocketReady(PRFileDesc* fd, int16_t outflags) {
|
||||
@ -1087,16 +1087,15 @@ NrUdpSocketIpc::NrUdpSocketIpc()
|
||||
err_(false),
|
||||
state_(NR_INIT) {}
|
||||
|
||||
NrUdpSocketIpc::~NrUdpSocketIpc() {
|
||||
NrUdpSocketIpc::~NrUdpSocketIpc() = default;
|
||||
|
||||
void NrUdpSocketIpc::Destroy() {
|
||||
#if defined(MOZILLA_INTERNAL_API)
|
||||
// close(), but transfer the socket_child_ reference to die as well
|
||||
// destroy_i also dispatches back to STS to call ReleaseUse, to avoid shutting
|
||||
// down the IO thread before close() runs.
|
||||
RUN_ON_THREAD(
|
||||
io_thread_,
|
||||
mozilla::WrapRunnableNM(&NrUdpSocketIpc::destroy_i,
|
||||
socket_child_.forget().take(), sts_thread_),
|
||||
NS_DISPATCH_NORMAL);
|
||||
// We use a NonOwning runnable because our refcount has already gone to 0.
|
||||
io_thread_->Dispatch(
|
||||
NewNonOwningRunnableMethod(__func__, this, &NrUdpSocketIpc::destroy_i));
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1560,17 +1559,10 @@ void NrUdpSocketIpc::close_i() {
|
||||
|
||||
static void ReleaseIOThread_s() { sThread->ReleaseUse(); }
|
||||
|
||||
// close(), but transfer the socket_child_ reference to die as well
|
||||
// static
|
||||
void NrUdpSocketIpc::destroy_i(dom::UDPSocketChild* aChild,
|
||||
const nsCOMPtr<nsIEventTarget>& aStsThread) {
|
||||
RefPtr<dom::UDPSocketChild> socket_child_ref =
|
||||
already_AddRefed<dom::UDPSocketChild>(aChild);
|
||||
if (socket_child_ref) {
|
||||
socket_child_ref->Close();
|
||||
}
|
||||
void NrUdpSocketIpc::destroy_i() {
|
||||
close_i();
|
||||
|
||||
RUN_ON_THREAD(aStsThread, WrapRunnableNM(&ReleaseIOThread_s),
|
||||
RUN_ON_THREAD(sts_thread_, WrapRunnableNM(&ReleaseIOThread_s),
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
#endif
|
||||
|
@ -161,7 +161,10 @@ class NrSocket : public NrSocketBase, public nsASocketHandler {
|
||||
virtual uint64_t ByteCountReceived() override { return 0; }
|
||||
|
||||
// nsISupports methods
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(NrSocket, Destroy(),
|
||||
override);
|
||||
virtual void Destroy() { delete this; }
|
||||
|
||||
// Implementations of the async_event APIs
|
||||
virtual int async_wait(int how, NR_async_cb cb, void* cb_arg, char* function,
|
||||
@ -263,6 +266,7 @@ class NrUdpSocketIpc : public NrSocketIpc {
|
||||
|
||||
private:
|
||||
virtual ~NrUdpSocketIpc();
|
||||
virtual void Destroy();
|
||||
|
||||
DISALLOW_COPY_ASSIGN(NrUdpSocketIpc);
|
||||
|
||||
@ -274,8 +278,7 @@ class NrUdpSocketIpc : public NrSocketIpc {
|
||||
void sendto_i(const net::NetAddr& addr, UniquePtr<MediaPacket> buf);
|
||||
void close_i();
|
||||
#if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API)
|
||||
static void destroy_i(dom::UDPSocketChild* aChild,
|
||||
const nsCOMPtr<nsIEventTarget>& aStsThread);
|
||||
void destroy_i();
|
||||
#endif
|
||||
// STS thread executor
|
||||
void recv_callback_s(RefPtr<nr_udp_message> msg);
|
||||
|
@ -255,13 +255,13 @@ struct UserTimingMarker {
|
||||
}
|
||||
static MarkerSchema MarkerTypeDisplay() {
|
||||
using MS = MarkerSchema;
|
||||
MS schema{MS::Location::markerChart, MS::Location::markerTable};
|
||||
MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
|
||||
schema.SetAllLabels("{marker.data.name}");
|
||||
schema.AddStaticLabelValue("Marker", "UserTiming");
|
||||
schema.AddKeyLabelFormat("entryType", "Entry Type", MS::Format::string);
|
||||
schema.AddKeyLabelFormat("name", "Name", MS::Format::string);
|
||||
schema.AddKeyLabelFormat("startMark", "Start Mark", MS::Format::string);
|
||||
schema.AddKeyLabelFormat("endMark", "End Mark", MS::Format::string);
|
||||
schema.AddKeyLabelFormat("entryType", "Entry Type", MS::Format::String);
|
||||
schema.AddKeyLabelFormat("name", "Name", MS::Format::String);
|
||||
schema.AddKeyLabelFormat("startMark", "Start Mark", MS::Format::String);
|
||||
schema.AddKeyLabelFormat("endMark", "End Mark", MS::Format::String);
|
||||
schema.AddStaticLabelValue("Description",
|
||||
"UserTimingMeasure is created using the DOM API "
|
||||
"performance.measure().");
|
||||
|
@ -41,7 +41,7 @@ ffi::WGPUStoreOp ConvertStoreOp(const dom::GPUStoreOp& aOp) {
|
||||
case dom::GPUStoreOp::Store:
|
||||
return ffi::WGPUStoreOp_Store;
|
||||
case dom::GPUStoreOp::Discard:
|
||||
return ffi::WGPUStoreOp_Clear;
|
||||
return ffi::WGPUStoreOp_Discard;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected load op");
|
||||
}
|
||||
|
@ -735,7 +735,7 @@ RawId WebGPUChild::DeviceCreateRenderPipeline(
|
||||
if (!vertex_desc.IsNull()) {
|
||||
const auto& vd = vertex_desc.Value();
|
||||
vb_desc.array_stride = vd.mArrayStride;
|
||||
vb_desc.step_mode = ffi::WGPUInputStepMode(vd.mStepMode);
|
||||
vb_desc.step_mode = ffi::WGPUVertexStepMode(vd.mStepMode);
|
||||
// Note: we are setting the length but not the pointer
|
||||
vb_desc.attributes_length = vd.mAttributes.Length();
|
||||
for (const auto& vat : vd.mAttributes) {
|
||||
|
@ -81,10 +81,6 @@ static void FreeDevice(RawId id, void* param) {
|
||||
NS_ERROR("Unable FreeDevice");
|
||||
}
|
||||
}
|
||||
static void FreeSwapChain(RawId id, void* param) {
|
||||
Unused << id;
|
||||
Unused << param;
|
||||
}
|
||||
static void FreeShaderModule(RawId id, void* param) {
|
||||
ipc::ByteBuf byteBuf;
|
||||
wgpu_server_shader_module_free(id, ToFFI(&byteBuf));
|
||||
@ -178,7 +174,6 @@ static ffi::WGPUIdentityRecyclerFactory MakeFactory(void* param) {
|
||||
ffi::WGPUIdentityRecyclerFactory factory = {param};
|
||||
factory.free_adapter = FreeAdapter;
|
||||
factory.free_device = FreeDevice;
|
||||
factory.free_swap_chain = FreeSwapChain;
|
||||
factory.free_pipeline_layout = FreePipelineLayout;
|
||||
factory.free_shader_module = FreeShaderModule;
|
||||
factory.free_bind_group_layout = FreeBindGroupLayout;
|
||||
@ -606,8 +601,8 @@ ipc::IPCResult WebGPUParent::RecvSwapChainPresent(
|
||||
bufferId = data->mUnassignedBufferIds.back();
|
||||
data->mUnassignedBufferIds.pop_back();
|
||||
|
||||
ffi::WGPUBufferUsage usage =
|
||||
WGPUBufferUsage_COPY_DST | WGPUBufferUsage_MAP_READ;
|
||||
ffi::WGPUBufferUsages usage =
|
||||
WGPUBufferUsages_COPY_DST | WGPUBufferUsages_MAP_READ;
|
||||
ffi::WGPUBufferDescriptor desc = {};
|
||||
desc.size = bufferSize;
|
||||
desc.usage = usage;
|
||||
|
@ -299,10 +299,8 @@ void LoadContextOptions(const char* aPrefName, void* /* aClosure */) {
|
||||
GetWorkerPref<bool>("asyncstack_capture_debuggee_only"_ns))
|
||||
.setPrivateClassFields(
|
||||
GetWorkerPref<bool>("experimental.private_fields"_ns))
|
||||
#ifdef NIGHTLY_BUILD
|
||||
.setClassStaticBlocks(
|
||||
GetWorkerPref<bool>("experimental.class_static_blocks"_ns))
|
||||
#endif
|
||||
.setPrivateClassMethods(
|
||||
GetWorkerPref<bool>("experimental.private_methods"_ns))
|
||||
.setErgnomicBrandChecks(
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "nsRegion.h"
|
||||
#include <memory>
|
||||
|
||||
class gfxASurface;
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
class SurfaceTextureImage;
|
||||
@ -92,10 +91,6 @@ class GLContextEGL final : public GLContext {
|
||||
|
||||
virtual void GetWSIInfo(nsCString* const out) const override;
|
||||
|
||||
// hold a reference to the given surface
|
||||
// for the lifetime of this context.
|
||||
void HoldSurface(gfxASurface* aSurf);
|
||||
|
||||
EGLSurface GetEGLSurface() const { return mSurface; }
|
||||
|
||||
bool HasExtBufferAge() const;
|
||||
@ -138,7 +133,6 @@ class GLContextEGL final : public GLContext {
|
||||
const EGLSurface mFallbackSurface;
|
||||
|
||||
EGLSurface mSurfaceOverride = EGL_NO_SURFACE;
|
||||
RefPtr<gfxASurface> mThebesSurface;
|
||||
bool mBound = false;
|
||||
|
||||
bool mIsPBuffer = false;
|
||||
|
@ -51,7 +51,6 @@
|
||||
# error "Platform not recognized"
|
||||
#endif
|
||||
|
||||
#include "gfxASurface.h"
|
||||
#include "gfxCrashReporterUtils.h"
|
||||
#include "gfxFailure.h"
|
||||
#include "gfxPlatform.h"
|
||||
@ -583,10 +582,6 @@ void GLContextEGL::GetWSIInfo(nsCString* const out) const {
|
||||
#endif
|
||||
}
|
||||
|
||||
// hold a reference to the given surface
|
||||
// for the lifetime of this context.
|
||||
void GLContextEGL::HoldSurface(gfxASurface* aSurf) { mThebesSurface = aSurf; }
|
||||
|
||||
bool GLContextEGL::HasExtBufferAge() const {
|
||||
return mEgl->IsExtensionSupported(EGLExtension::EXT_buffer_age);
|
||||
}
|
||||
|
@ -46,10 +46,10 @@
|
||||
#include "mozilla/layers/LayersMessages.h" // for SpecificLayerAttributes, CompositorAnimations (ptr only), ContainerLayerAt...
|
||||
#include "mozilla/layers/LayersTypes.h" // for EventRegions, operator<<, CompositionPayload, CSSTransformMatrix, MOZ_LAYE...
|
||||
#include "nsBaseHashtable.h" // for nsBaseHashtable<>::Iterator, nsBaseHashtable<>::LookupResult
|
||||
#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
|
||||
#include "nsPrintfCString.h" // for nsPrintfCString
|
||||
#include "nsRegionFwd.h" // for IntRegion
|
||||
#include "nsString.h" // for nsTSubstring
|
||||
#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
|
||||
#include "nsPrintfCString.h" // for nsPrintfCString
|
||||
#include "nsRegionFwd.h" // for IntRegion
|
||||
#include "nsString.h" // for nsTSubstring
|
||||
|
||||
// Undo the damage done by mozzconf.h
|
||||
#undef compress
|
||||
@ -1412,7 +1412,6 @@ void ReadbackLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) {
|
||||
//--------------------------------------------------
|
||||
// LayerManager
|
||||
|
||||
|
||||
void LayerManager::Log(const char* aPrefix) {
|
||||
if (!IsLogEnabled()) return;
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common-vs.hlsl"
|
||||
|
||||
struct VS_BLEND_OUTPUT
|
||||
{
|
||||
float4 vPosition : SV_Position;
|
||||
float2 vTexCoords : TEXCOORD0;
|
||||
float2 vBackdropCoords : TEXCOORD1;
|
||||
float2 vLocalPos : TEXCOORD2;
|
||||
float3 vMaskCoords : TEXCOORD3;
|
||||
nointerpolation float4 vClipRect : TEXCOORD4;
|
||||
};
|
@ -1,540 +0,0 @@
|
||||
float4 BlendMultiplyPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendMultiply(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendScreenPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendScreen(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendOverlayPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendOverlay(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendDarkenPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendDarken(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendLightenPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendLighten(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendColorDodgePS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendColorDodge(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendColorBurnPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendColorBurn(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendHardLightPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= sOpacity;
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendHardLight(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendSoftLightPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendSoftLight(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendDifferencePS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendDifference(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendExclusionPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendExclusion(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendHuePS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendHue(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendSaturationPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendSaturation(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendColorPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendColor(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendLuminosityPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendLuminosity(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
float4 Blend{BLEND_FUNC}PS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
// Apply masks to the source texture, not the result.
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = Blend{BLEND_FUNC}(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common.hlsl"
|
||||
#include "common-ps.hlsl"
|
||||
#include "blend-common.hlsl"
|
||||
#include "../BlendingHelpers.hlslh"
|
||||
|
||||
Texture2D simpleTex : register(ps, t0);
|
||||
Texture2D tBackdrop : register(ps, t1);
|
||||
|
||||
#include "blend-ps-generated.hlslh"
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user