Merge autoland to mozilla-central. a=merge

This commit is contained in:
Marian-Vasile Laza 2021-09-04 12:38:27 +03:00
commit 36a784a4c4
1071 changed files with 148792 additions and 191246 deletions

View File

@ -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"

View File

@ -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
View File

@ -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",
]

View File

@ -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"

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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 => {

View File

@ -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);

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

View 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>

View 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();

View File

@ -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

View File

@ -91,7 +91,7 @@
#downloadsPanel-blockedSubview,
#downloadsPanel-mainView {
font: caption;
width: 35em;
min-width: 37em;
padding: 0.62em;
}

View File

@ -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);"

View File

@ -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;

View File

@ -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

View File

@ -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"]
}

View File

@ -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;

View File

@ -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.

View File

@ -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 };

View File

@ -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: {

View File

@ -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 = {

View 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"];

View File

@ -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;

View File

@ -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]

View File

@ -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"
);

View File

@ -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();
});

View File

@ -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);
}
});
});

View File

@ -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",

View File

@ -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,

View File

@ -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"
);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View 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;
}

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -115,7 +115,6 @@ gfx/tests/
gfx/thebes/
gfx/vr/
gfx/webrender_bindings/
gfx/wgpu/
gfx/wgpu_bindings/
gfx/wr/
gfx/ycbcr/

View File

@ -2,7 +2,6 @@
%include build/sparse-profiles/taskgraph
[include]
path:gfx/wgpu/
path:gfx/wr/
path:taskcluster/scripts/misc/
path:tools/github-sync/

View File

@ -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

View File

@ -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/

View File

@ -1,4 +0,0 @@
%include build/sparse-profiles/mach
[include]
path:gfx/wgpu/

View File

@ -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]

View File

@ -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();

View File

@ -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; }

View File

@ -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");

View File

@ -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.

View File

@ -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");

View File

@ -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();

View File

@ -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;

View 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>

View File

@ -0,0 +1,3 @@
<html>
<iframe src="http://example.org/1728670-1-child.html" style="display: none;">
</html>

View File

@ -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

View File

@ -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;
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
};

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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!");

View File

@ -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);

View File

@ -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!");

View File

@ -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);

View File

@ -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;
}

View File

@ -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.");

View File

@ -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;
/**

View File

@ -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;

View File

@ -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();
}

View File

@ -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>

View File

@ -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

View File

@ -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(

View File

@ -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.

View File

@ -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();

View File

@ -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]

View 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>

View File

@ -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

View File

@ -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);

View File

@ -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().");

View File

@ -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");
}

View File

@ -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) {

View File

@ -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;

View File

@ -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(

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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