diff --git a/.flake8 b/.flake8 deleted file mode 100644 index d4fb3a318ee..00000000000 --- a/.flake8 +++ /dev/null @@ -1,18 +0,0 @@ -[flake8] -ignore = - # trailing whitespace; the standard tidy process will enforce no trailing whitespace - W291, - # linebreak before binary operator; replaced by W504 - linebreak after binary operator - W503, - # 80 character line length; the standard tidy process will enforce line length - E501 -exclude = - # temporary local files - target - __pycache__ - python/_venv* - # upstream - third_party - python/mach - components - tests diff --git a/.github/workflows/ohos.yml b/.github/workflows/ohos.yml index 0fe92dcf5c7..2cda0acbfc9 100644 --- a/.github/workflows/ohos.yml +++ b/.github/workflows/ohos.yml @@ -169,11 +169,17 @@ jobs: - name: Build for aarch64 HarmonyOS run: | ./mach build --locked --target aarch64-unknown-linux-ohos --profile=${{ inputs.profile }} --flavor=harmonyos --no-default-features --features tracing,tracing-hitrace + - name: Upload supprt/hitrace-bencher/runs.json + uses: actions/upload-artifact@v4 + with: + name: runs.json + path: support/hitrace-bencher/runs.json + overwrite: true - uses: actions/upload-artifact@v4 with: # Upload the **unsigned** artifact - We don't have the signing materials in pull request workflows - path: target/openharmony/aarch64-unknown-linux-ohos/${{ inputs.profile }}/entry/build/harmonyos/outputs/default/servoshell-default-unsigned.hap name: servoshell-hos-${{ inputs.profile }}.hap + path: target/openharmony/aarch64-unknown-linux-ohos/${{ inputs.profile }}/entry/build/harmonyos/outputs/default/servoshell-default-unsigned.hap test-harmonyos-aarch64: @@ -239,10 +245,19 @@ jobs: [[ $servo_pid =~ ^[0-9]+$ ]] || { echo "It looks like servo crashed!" ; exit 1; } # If the grep fails, then the trace output for the "page loaded" prompt is missing grep 'org\.servo\.servo-.* tracing_mark_write.*PageLoadEndedPrompt' test_output/servo.ftrace + - name: Getting runs file + uses: actions/download-artifact@v4 + with: + # Name of the artifact to download. + # If unspecified, all artifacts for the run are downloaded. + name: runs.json - name: "Run benchmark" - run: hitrace-bench --bencher -b "org.servo.servo" -p "https://www.servo.org" -n 5 + run: hitrace-bench -r runs.json - name: Getting bencher uses: bencherdev/bencher@main + - name: Getting model name + run: | + echo "MODEL_NAME=$(hdc bugreport | head -n 20 | grep MarketName | awk '{for (i=2; i> $GITHUB_ENV - name: Uploading to bencher.dev run: | - bencher run --adapter json --file bench.json --project '${{ env.BENCHER_PROJECT }}' --token '${{ secrets.BENCHER_API_TOKEN }}' --github-actions '${{ secrets.GITHUB_TOKEN }}' + bencher run --adapter json --file bench.json --project '${{ env.BENCHER_PROJECT }}' --token '${{ secrets.BENCHER_API_TOKEN }}' --github-actions '${{ secrets.GITHUB_TOKEN }}' --testbed="$MODEL_NAME" diff --git a/.vscode/extensions.json b/.vscode/extensions.json index d776261927d..7bf53b27bf2 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -16,6 +16,8 @@ // IDL language support "mythmon.idl", // TOML files - "tamasfe.even-better-toml" + "tamasfe.even-better-toml", + // Python files + "charliermarsh.ruff" ] } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 36e579d2921..5918a8cf23a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,9 +20,9 @@ checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] name = "accountable-refcell" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e2bba6f21fcf0ae382750eb6d9387c42807761fa7329d3a05fcd1334e8c3f2" +checksum = "6afea9052e0b2d90e38572691d87194b2e5d8d6899b9b850b22aaab17e486252" dependencies = [ "backtrace", ] @@ -139,7 +139,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.9.0", + "bitflags 2.9.1", "cc", "cesu8", "jni", @@ -238,12 +238,12 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" dependencies = [ "anstyle", - "once_cell", + "once_cell_polyfill", "windows-sys 0.59.0", ] @@ -500,7 +500,7 @@ version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cexpr", "clang-sys", "itertools 0.10.5", @@ -523,7 +523,7 @@ version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cexpr", "clang-sys", "itertools 0.10.5", @@ -564,9 +564,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" dependencies = [ "serde", ] @@ -609,7 +609,7 @@ name = "bluetooth" version = "0.0.1" dependencies = [ "base", - "bitflags 2.9.0", + "bitflags 2.9.1", "bluetooth_traits", "blurdroid", "blurmac", @@ -737,6 +737,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.10.1" @@ -759,7 +765,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "log", "polling", "rustix", @@ -795,7 +801,6 @@ dependencies = [ "log", "lyon_geom", "net_traits", - "num-traits", "pixels", "range", "raqote", @@ -844,9 +849,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.22" +version = "1.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" +checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" dependencies = [ "jobserver", "libc", @@ -870,9 +875,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.17.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d4ba6e40bd1184518716a6e1a781bf9160e286d219ccdb8ab2612e74cfe4789" +checksum = "e34e221e91c7eb5e8315b5c9cf1a61670938c0626451f954a51693ed44b37f45" dependencies = [ "smallvec", "target-lexicon", @@ -964,18 +969,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" dependencies = [ "anstyle", "clap_lex", @@ -1084,7 +1089,7 @@ version = "0.0.1" dependencies = [ "base", "bincode", - "bitflags 2.9.0", + "bitflags 2.9.1", "compositing_traits", "constellation_traits", "crossbeam-channel", @@ -1099,12 +1104,12 @@ dependencies = [ "net", "pixels", "profile_traits", - "script_traits", "servo_allocator", "servo_config", "servo_geometry", "stylo_traits", "surfman", + "timers", "tracing", "webrender", "webrender_api", @@ -1197,7 +1202,6 @@ name = "constellation_traits" version = "0.0.1" dependencies = [ "base", - "bitflags 2.9.0", "canvas_traits", "devtools_traits", "embedder_traits", @@ -1212,6 +1216,7 @@ dependencies = [ "serde", "servo_malloc_size_of", "servo_url", + "snapshot", "strum", "strum_macros", "uuid", @@ -1223,10 +1228,10 @@ dependencies = [ [[package]] name = "content-security-policy" version = "0.5.4" -source = "git+https://github.com/servo/rust-content-security-policy/?branch=servo-csp#334bfcbf0a3f503b21c90aee6aee30d4b8c9558a" +source = "git+https://github.com/servo/rust-content-security-policy/?branch=servo-csp#58a09ee320fd6fbb828748ae04255e4c8d3f9c9e" dependencies = [ "base64 0.22.1", - "bitflags 2.9.0", + "bitflags 2.9.1", "once_cell", "percent-encoding", "regex", @@ -1485,9 +1490,9 @@ dependencies = [ [[package]] name = "cursor-icon" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" [[package]] name = "darling" @@ -1608,7 +1613,7 @@ name = "devtools_traits" version = "0.0.1" dependencies = [ "base", - "bitflags 2.9.0", + "bitflags 2.9.1", "embedder_traits", "http 1.3.1", "ipc-channel", @@ -1672,28 +1677,16 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" dependencies = [ - "dirs-sys 0.5.0", + "dirs-sys", ] [[package]] name = "dirs" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ - "dirs-sys 0.4.1", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users 0.4.6", - "windows-sys 0.48.0", + "dirs-sys", ] [[package]] @@ -1704,7 +1697,7 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users 0.5.0", + "redox_users", "windows-sys 0.59.0", ] @@ -1720,7 +1713,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "objc2 0.6.1", ] @@ -1834,7 +1827,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25dd34cec49ab55d85ebf70139cb1ccd29c977ef6b6ba4fe85489d6877ee9ef3" dependencies = [ "ahash", - "bitflags 2.9.0", + "bitflags 2.9.1", "emath", "epaint", "log", @@ -1912,7 +1905,6 @@ name = "embedder_traits" version = "0.0.1" dependencies = [ "base", - "cfg-if", "cookie 0.18.1", "crossbeam-channel", "euclid", @@ -1929,6 +1921,7 @@ dependencies = [ "servo_malloc_size_of", "servo_url", "strum_macros", + "stylo", "stylo_traits", "url", "webdriver", @@ -2027,9 +2020,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys 0.59.0", @@ -2132,6 +2125,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + [[package]] name = "float-ord" version = "0.3.2" @@ -2152,11 +2151,11 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "font-kit" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64b34f4efd515f905952d91bc185039863705592c0c53ae6d979805dd154520" +checksum = "2c7e611d49285d4c4b2e1727b72cf05353558885cc5252f93707b845dfcaf3d3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "byteorder", "core-foundation 0.9.4", "core-graphics", @@ -2175,6 +2174,29 @@ dependencies = [ "yeslogic-fontconfig-sys", ] +[[package]] +name = "fontconfig-parser" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646" +dependencies = [ + "roxmltree", +] + +[[package]] +name = "fontdb" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser", +] + [[package]] name = "fonts" version = "0.0.1" @@ -2182,7 +2204,7 @@ dependencies = [ "app_units", "atomic_refcell", "base", - "bitflags 2.9.0", + "bitflags 2.9.1", "byteorder", "compositing_traits", "core-foundation 0.9.4", @@ -2324,6 +2346,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "fst" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" + [[package]] name = "futf" version = "0.1.5" @@ -2588,7 +2616,7 @@ version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c501c495842c2b23cdacead803a5a343ca2a5d7a7ddaff14cc5f6cf22cfb92c2" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "futures-channel", "futures-core", "futures-executor", @@ -2679,7 +2707,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "gpu-alloc-types", ] @@ -2689,7 +2717,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -2706,11 +2734,11 @@ dependencies = [ [[package]] name = "gpu-descriptor" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "gpu-descriptor-types", "hashbrown", ] @@ -2721,7 +2749,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -3220,9 +3248,9 @@ dependencies = [ [[package]] name = "hitrace" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92c0ae6f30b32eaeb811143fba3b56864f477b2e69458b13779a07b3aaf2f6e" +checksum = "4e3037245d690359ac992d8e3bb96e15ace6ad0a00305b680f4b1fd4ede684d9" dependencies = [ "hitrace-sys", ] @@ -3388,12 +3416,13 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" +checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" dependencies = [ "bytes", "futures-channel", + "futures-core", "futures-util", "http 1.3.1", "http-body 1.0.1", @@ -3906,6 +3935,22 @@ dependencies = [ "tiff", ] +[[package]] +name = "image-webp" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imagesize" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" + [[package]] name = "imsz" version = "0.2.2" @@ -3928,7 +3973,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "inotify-sys", "libc", ] @@ -4036,9 +4081,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806" +checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" dependencies = [ "jiff-static", "log", @@ -4049,9 +4094,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48" +checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" dependencies = [ "proc-macro2", "quote", @@ -4123,7 +4168,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "serde", "unicode-segmentation", ] @@ -4145,6 +4190,16 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" +[[package]] +name = "kurbo" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1077d333efea6170d9ccb96d3c3026f300ca0773da4938cc4c811daa6df68b0c" +dependencies = [ + "arrayvec", + "smallvec", +] + [[package]] name = "layout" version = "0.0.1" @@ -4152,8 +4207,7 @@ dependencies = [ "app_units", "atomic_refcell", "base", - "bitflags 2.9.0", - "canvas_traits", + "bitflags 2.9.1", "compositing_traits", "constellation_traits", "data-url", @@ -4249,12 +4303,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -4269,7 +4323,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "libc", "redox_syscall 0.5.7", ] @@ -4287,7 +4341,6 @@ dependencies = [ "bluetooth_traits", "canvas", "canvas_traits", - "cfg-if", "compositing", "compositing_traits", "constellation", @@ -4387,9 +4440,9 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -4551,7 +4604,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block", "core-graphics-types", "foreign-types 0.5.0", @@ -4565,7 +4618,6 @@ name = "metrics" version = "0.0.1" dependencies = [ "base", - "constellation_traits", "ipc-channel", "log", "malloc_size_of_derive", @@ -4620,14 +4672,14 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4686,7 +4738,7 @@ checksum = "2b977c445f26e49757f9aca3631c3b8b836942cb278d69a92e7b80d3b24da632" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.9.0", + "bitflags 2.9.1", "cfg_aliases", "codespan-reporting", "half", @@ -4736,7 +4788,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32036ede4ef064610304337831e9d49dac23e7edc4e9efd076c8259eab6d19a9" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "ctor", "napi-sys-ohos", ] @@ -4756,7 +4808,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "jni-sys", "log", "ndk-sys 0.6.0+11769913", @@ -4808,6 +4860,7 @@ dependencies = [ "devtools_traits", "embedder_traits", "flate2", + "fst", "futures 0.3.31", "futures-core", "futures-util", @@ -4830,12 +4883,12 @@ dependencies = [ "pixels", "profile_traits", "rayon", + "resvg", "rustls", "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", - "servo_allocator", "servo_arc", "servo_config", "servo_malloc_size_of", @@ -4863,6 +4916,7 @@ dependencies = [ "content-security-policy", "cookie 0.18.1", "crossbeam-channel", + "data-url", "embedder_traits", "headers 0.4.0", "http 1.3.1", @@ -4884,6 +4938,7 @@ dependencies = [ "servo_url", "url", "uuid", + "webrender_api", ] [[package]] @@ -4898,7 +4953,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cfg-if", "cfg_aliases", "libc", @@ -5089,7 +5144,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "libc", "objc2 0.5.2", @@ -5105,7 +5160,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "objc2 0.6.1", "objc2-foundation 0.3.1", ] @@ -5116,7 +5171,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "objc2 0.5.2", "objc2-core-location", @@ -5140,7 +5195,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -5152,7 +5207,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "dispatch2", "objc2 0.6.1", ] @@ -5193,7 +5248,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "dispatch", "libc", @@ -5206,7 +5261,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "objc2 0.6.1", "objc2-core-foundation", ] @@ -5229,7 +5284,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -5241,7 +5296,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -5264,7 +5319,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "objc2 0.5.2", "objc2-cloud-kit", @@ -5296,7 +5351,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "objc2 0.5.2", "objc2-core-location", @@ -5341,9 +5396,9 @@ dependencies = [ [[package]] name = "ohos-ime" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48107e68ed8451c17c2ff95938e1ba86003fb290a04f7a0213ce2d16ce4b3ee6" +checksum = "ee3ea454e31a3372cd9c4ed903db4fae861e92f57cf51852a3cd80f9d3945dcd" dependencies = [ "log", "ohos-ime-sys", @@ -5382,6 +5437,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "oorandom" version = "11.1.5" @@ -5471,9 +5532,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -5481,9 +5542,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -5510,9 +5571,9 @@ dependencies = [ [[package]] name = "pathfinder_simd" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cf07ef4804cfa9aea3b04a7bbdd5a40031dbb6b4f2cbaf2b011666c80c5b4f2" +checksum = "bf9027960355bf3afff9841918474a81a5f972ac6d226d518060bba758b5ad57" dependencies = [ "rustc_version", ] @@ -5605,6 +5666,12 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + [[package]] name = "pin-project" version = "1.1.10" @@ -5815,7 +5882,6 @@ dependencies = [ "ipc-channel", "libc", "log", - "parking_lot", "profile_traits", "regex", "serde", @@ -5851,7 +5917,6 @@ dependencies = [ "servo_config", "servo_malloc_size_of", "signpost", - "strum_macros", "time", "tracing", ] @@ -5894,6 +5959,12 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quick-xml" version = "0.37.5" @@ -6034,18 +6105,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 2.9.0", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom", - "libredox", - "thiserror 1.0.69", + "bitflags 2.9.1", ] [[package]] @@ -6059,12 +6119,6 @@ dependencies = [ "thiserror 2.0.9", ] -[[package]] -name = "ref_filter_map" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b5ceb840e4009da4841ed22a15eb49f64fdd00a2138945c5beacf506b2fb5ed" - [[package]] name = "regex" version = "1.11.1" @@ -6118,6 +6172,32 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "resvg" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8928798c0a55e03c9ca6c4c6846f76377427d2c1e1f7e6de3c06ae57942df43" +dependencies = [ + "gif", + "image-webp", + "log", + "pico-args", + "rgb", + "svgtypes", + "tiny-skia", + "usvg", + "zune-jpeg", +] + +[[package]] +name = "rgb" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +dependencies = [ + "bytemuck", +] + [[package]] name = "ring" version = "0.17.14" @@ -6139,12 +6219,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "beceb6f7bf81c73e73aeef6dd1356d9a1b2b4909e1f0fc3e59b034f9572d7b7f" dependencies = [ "base64 0.22.1", - "bitflags 2.9.0", + "bitflags 2.9.1", "serde", "serde_derive", "unicode-ident", ] +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -6178,7 +6264,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "errno", "libc", "linux-raw-sys", @@ -6232,9 +6318,27 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "rustybuzz" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" +dependencies = [ + "bitflags 2.9.1", + "bytemuck", + "core_maths", + "log", + "smallvec", + "ttf-parser", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] [[package]] name = "ryu" @@ -6280,7 +6384,7 @@ dependencies = [ "base", "base64 0.22.1", "bincode", - "bitflags 2.9.0", + "bitflags 2.9.1", "bluetooth_traits", "canvas_traits", "cbc", @@ -6330,13 +6434,11 @@ dependencies = [ "nom", "num-traits", "num_cpus", - "parking_lot", "percent-encoding", "phf", "pixels", "profile_traits", "range", - "ref_filter_map", "regex", "script_bindings", "script_layout_interface", @@ -6386,7 +6488,7 @@ dependencies = [ name = "script_bindings" version = "0.0.1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "crossbeam-channel", "cssparser", "deny_public_fields", @@ -6426,7 +6528,6 @@ dependencies = [ "app_units", "atomic_refcell", "base", - "canvas_traits", "compositing_traits", "constellation_traits", "embedder_traits", @@ -6439,7 +6540,6 @@ dependencies = [ "ipc-channel", "libc", "malloc_size_of_derive", - "metrics", "net_traits", "pixels", "profile_traits", @@ -6451,7 +6551,6 @@ dependencies = [ "servo_malloc_size_of", "servo_url", "stylo", - "stylo_traits", "webrender_api", ] @@ -6479,7 +6578,6 @@ dependencies = [ "devtools_traits", "embedder_traits", "euclid", - "http 1.3.1", "ipc-channel", "keyboard-types", "malloc_size_of_derive", @@ -6515,9 +6613,9 @@ dependencies = [ [[package]] name = "selectors" version = "0.28.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea" +source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cssparser", "derive_more", "fxhash", @@ -6625,7 +6723,7 @@ dependencies = [ [[package]] name = "servo-media" version = "0.1.0" -source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" +source = "git+https://github.com/servo/media#4931a4b380acd9c95b8787cbcfa812823864e2d0" dependencies = [ "once_cell", "servo-media-audio", @@ -6638,7 +6736,7 @@ dependencies = [ [[package]] name = "servo-media-audio" version = "0.2.0" -source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" +source = "git+https://github.com/servo/media#4931a4b380acd9c95b8787cbcfa812823864e2d0" dependencies = [ "byte-slice-cast", "euclid", @@ -6659,7 +6757,7 @@ dependencies = [ [[package]] name = "servo-media-derive" version = "0.1.0" -source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" +source = "git+https://github.com/servo/media#4931a4b380acd9c95b8787cbcfa812823864e2d0" dependencies = [ "proc-macro2", "quote", @@ -6669,7 +6767,7 @@ dependencies = [ [[package]] name = "servo-media-dummy" version = "0.1.0" -source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" +source = "git+https://github.com/servo/media#4931a4b380acd9c95b8787cbcfa812823864e2d0" dependencies = [ "ipc-channel", "servo-media", @@ -6683,7 +6781,7 @@ dependencies = [ [[package]] name = "servo-media-gstreamer" version = "0.1.0" -source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" +source = "git+https://github.com/servo/media#4931a4b380acd9c95b8787cbcfa812823864e2d0" dependencies = [ "byte-slice-cast", "glib", @@ -6716,7 +6814,7 @@ dependencies = [ [[package]] name = "servo-media-gstreamer-render" version = "0.1.0" -source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" +source = "git+https://github.com/servo/media#4931a4b380acd9c95b8787cbcfa812823864e2d0" dependencies = [ "gstreamer", "gstreamer-video", @@ -6726,7 +6824,7 @@ dependencies = [ [[package]] name = "servo-media-gstreamer-render-android" version = "0.1.0" -source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" +source = "git+https://github.com/servo/media#4931a4b380acd9c95b8787cbcfa812823864e2d0" dependencies = [ "glib", "gstreamer", @@ -6740,7 +6838,7 @@ dependencies = [ [[package]] name = "servo-media-gstreamer-render-unix" version = "0.1.0" -source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" +source = "git+https://github.com/servo/media#4931a4b380acd9c95b8787cbcfa812823864e2d0" dependencies = [ "glib", "gstreamer", @@ -6755,7 +6853,7 @@ dependencies = [ [[package]] name = "servo-media-player" version = "0.1.0" -source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" +source = "git+https://github.com/servo/media#4931a4b380acd9c95b8787cbcfa812823864e2d0" dependencies = [ "ipc-channel", "serde", @@ -6767,7 +6865,7 @@ dependencies = [ [[package]] name = "servo-media-streams" version = "0.1.0" -source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" +source = "git+https://github.com/servo/media#4931a4b380acd9c95b8787cbcfa812823864e2d0" dependencies = [ "uuid", ] @@ -6775,12 +6873,12 @@ dependencies = [ [[package]] name = "servo-media-traits" version = "0.1.0" -source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" +source = "git+https://github.com/servo/media#4931a4b380acd9c95b8787cbcfa812823864e2d0" [[package]] name = "servo-media-webrtc" version = "0.1.0" -source = "git+https://github.com/servo/media#eb96030cdd153ebcbbe3836dc6471303187740e9" +source = "git+https://github.com/servo/media#4931a4b380acd9c95b8787cbcfa812823864e2d0" dependencies = [ "log", "servo-media-streams", @@ -6810,7 +6908,7 @@ dependencies = [ [[package]] name = "servo_arc" version = "0.4.1" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea" +source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620" dependencies = [ "serde", "stable_deref_trait", @@ -6863,6 +6961,8 @@ dependencies = [ "ipc-channel", "keyboard-types", "markup5ever", + "mime", + "resvg", "servo_allocator", "servo_arc", "smallvec", @@ -6926,19 +7026,15 @@ dependencies = [ "euclid", "getopts", "gilrs", - "gleam", "glow", "headers 0.4.0", "hilog", "hitrace", - "http 1.3.1", - "icu_locid", "image", "ipc-channel", "jni", "keyboard-types", "libc", - "libloading", "libservo", "log", "mime_guess", @@ -6955,9 +7051,7 @@ dependencies = [ "raw-window-handle", "rustls", "serde_json", - "servo-tracing", "servo_allocator", - "shellwords", "sig", "surfman", "tokio", @@ -7002,16 +7096,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shellwords" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e515aa4699a88148ed5ef96413ceef0048ce95b43fbc955a33bde0a70fcae6" -dependencies = [ - "lazy_static", - "regex", -] - [[package]] name = "shlex" version = "1.3.0" @@ -7050,6 +7134,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "simplecss" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" +dependencies = [ + "log", +] + [[package]] name = "siphasher" version = "1.0.1" @@ -7095,7 +7188,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "calloop", "calloop-wayland-source", "cursor-icon", @@ -7140,15 +7233,17 @@ version = "0.0.1" dependencies = [ "euclid", "ipc-channel", + "malloc_size_of_derive", "pixels", "serde", + "servo_malloc_size_of", ] [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -7166,7 +7261,7 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -7202,6 +7297,9 @@ name = "strict-num" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] [[package]] name = "string_cache" @@ -7271,12 +7369,12 @@ dependencies = [ [[package]] name = "stylo" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea" +source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620" dependencies = [ "app_units", "arrayvec", "atomic_refcell", - "bitflags 2.9.0", + "bitflags 2.9.1", "byteorder", "cssparser", "derive_more", @@ -7329,7 +7427,7 @@ dependencies = [ [[package]] name = "stylo_atoms" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea" +source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620" dependencies = [ "string_cache", "string_cache_codegen", @@ -7338,12 +7436,12 @@ dependencies = [ [[package]] name = "stylo_config" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea" +source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620" [[package]] name = "stylo_derive" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea" +source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620" dependencies = [ "darling", "proc-macro2", @@ -7355,16 +7453,16 @@ dependencies = [ [[package]] name = "stylo_dom" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea" +source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "stylo_malloc_size_of", ] [[package]] name = "stylo_malloc_size_of" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea" +source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620" dependencies = [ "app_units", "cssparser", @@ -7381,15 +7479,15 @@ dependencies = [ [[package]] name = "stylo_static_prefs" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea" +source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620" [[package]] name = "stylo_traits" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea" +source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620" dependencies = [ "app_units", - "bitflags 2.9.0", + "bitflags 2.9.1", "cssparser", "euclid", "malloc_size_of_derive", @@ -7415,7 +7513,7 @@ name = "surfman" version = "0.9.8" source = "git+https://github.com/servo/surfman?rev=f7688b4585f9e0b5d4bf8ee8e4a91e82349610b1#f7688b4585f9e0b5d4bf8ee8e4a91e82349610b1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cfg_aliases", "cgl", "cocoa", @@ -7445,6 +7543,16 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb" +[[package]] +name = "svgtypes" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc" +dependencies = [ + "kurbo", + "siphasher", +] + [[package]] name = "sw-composite" version = "0.7.16" @@ -7492,9 +7600,9 @@ dependencies = [ [[package]] name = "system-deps" -version = "7.0.3" +version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005" +checksum = "e4be53aa0cba896d2dc615bd42bbc130acdcffa239e0a2d965ea5b3b2a86ffdb" dependencies = [ "cfg-expr", "heck", @@ -7528,9 +7636,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.16" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "task_info" @@ -7732,6 +7840,7 @@ dependencies = [ "bytemuck", "cfg-if", "log", + "png", "tiny-skia-path", ] @@ -7766,10 +7875,25 @@ dependencies = [ "serde_json", ] +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "to_shmem" version = "0.2.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea" +source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620" dependencies = [ "cssparser", "servo_arc", @@ -7782,7 +7906,7 @@ dependencies = [ [[package]] name = "to_shmem_derive" version = "0.1.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#bc815af4b5ae01768eaef64d21cebe6d66be06ea" +source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620" dependencies = [ "darling", "proc-macro2", @@ -7793,9 +7917,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", @@ -8011,6 +8135,9 @@ name = "ttf-parser" version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +dependencies = [ + "core_maths", +] [[package]] name = "tungstenite" @@ -8112,6 +8239,18 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" +[[package]] +name = "unicode-bidi-mirroring" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe" + +[[package]] +name = "unicode-ccc" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -8136,6 +8275,12 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + [[package]] name = "unicode-width" version = "0.1.14" @@ -8192,6 +8337,33 @@ dependencies = [ "url", ] +[[package]] +name = "usvg" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80be9b06fbae3b8b303400ab20778c80bbaf338f563afe567cf3c9eea17b47ef" +dependencies = [ + "base64 0.22.1", + "data-url", + "flate2", + "fontdb", + "imagesize", + "kurbo", + "log", + "pico-args", + "roxmltree", + "rustybuzz", + "simplecss", + "siphasher", + "strict-num", + "svgtypes", + "tiny-skia-path", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "xmlwriter", +] + [[package]] name = "utf-8" version = "0.7.6" @@ -8402,7 +8574,7 @@ version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "rustix", "wayland-backend", "wayland-scanner", @@ -8414,7 +8586,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cursor-icon", "wayland-backend", ] @@ -8436,7 +8608,7 @@ version = "0.32.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-scanner", @@ -8448,7 +8620,7 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fd38cdad69b56ace413c6bcc1fbf5acc5e2ef4af9d5f8f1f9570c0c83eae175" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -8461,7 +8633,7 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cb6cdc73399c0e06504c437fe3cf886f25568dd5454473d565085b36d6a8bbf" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -8574,9 +8746,7 @@ dependencies = [ "ipc-channel", "keyboard-types", "log", - "net_traits", "pixels", - "script_traits", "serde", "serde_json", "servo_config", @@ -8590,7 +8760,7 @@ dependencies = [ name = "webgl" version = "0.0.1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "byteorder", "canvas_traits", "compositing_traits", @@ -8623,7 +8793,6 @@ dependencies = [ "log", "serde", "servo_config", - "servo_malloc_size_of", "snapshot", "webgpu_traits", "webrender", @@ -8663,7 +8832,7 @@ source = "git+https://github.com/servo/webrender?branch=0.67#ae2477d9a6da403e5b5 dependencies = [ "allocator-api2", "bincode", - "bitflags 2.9.0", + "bitflags 2.9.1", "build-parallel", "byteorder", "derive_more", @@ -8697,7 +8866,7 @@ version = "0.66.0" source = "git+https://github.com/servo/webrender?branch=0.67#ae2477d9a6da403e5b5dce8a17415a2cd1563074" dependencies = [ "app_units", - "bitflags 2.9.0", + "bitflags 2.9.1", "byteorder", "crossbeam-channel", "euclid", @@ -8717,7 +8886,7 @@ name = "webrender_build" version = "0.0.2" source = "git+https://github.com/servo/webrender?branch=0.67#ae2477d9a6da403e5b5dce8a17415a2cd1563074" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "lazy_static", ] @@ -8726,7 +8895,6 @@ name = "webxr" version = "0.0.1" dependencies = [ "crossbeam-channel", - "embedder_traits", "euclid", "glow", "log", @@ -8752,9 +8920,9 @@ dependencies = [ [[package]] name = "weezl" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" [[package]] name = "wgpu-core" @@ -8765,7 +8933,7 @@ dependencies = [ "arrayvec", "bit-set", "bit-vec", - "bitflags 2.9.0", + "bitflags 2.9.1", "cfg_aliases", "document-features", "hashbrown", @@ -8823,7 +8991,7 @@ dependencies = [ "arrayvec", "ash", "bit-set", - "bitflags 2.9.0", + "bitflags 2.9.1", "block", "bytemuck", "cfg-if", @@ -8864,7 +9032,7 @@ version = "25.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2aa49460c2a8ee8edba3fca54325540d904dd85b2e086ada762767e17d06e8bc" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "bytemuck", "js-sys", "log", @@ -9255,14 +9423,14 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.30.10" +version = "0.30.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d05bd8908e14618c9609471db04007e644fd9cce6529756046cfc577f9155e" +checksum = "a4409c10174df8779dc29a4788cac85ed84024ccbc1743b776b21a520ee1aaf4" dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "bytemuck", "calloop", @@ -9463,7 +9631,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "dlib", "log", "once_cell", @@ -9493,6 +9661,12 @@ dependencies = [ "markup5ever", ] +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + [[package]] name = "yeslogic-fontconfig-sys" version = "6.0.0" @@ -9609,6 +9783,12 @@ dependencies = [ "syn", ] +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + [[package]] name = "zune-inflate" version = "0.2.54" @@ -9617,3 +9797,12 @@ checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" dependencies = [ "simd-adler32", ] + +[[package]] +name = "zune-jpeg" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index 4045a0ffcb9..c290a21f1fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ publish = false rust-version = "1.85.0" [workspace.dependencies] -accountable-refcell = "0.2.0" +accountable-refcell = "0.2.2" aes = "0.8.4" aes-gcm = "0.10.3" aes-kw = { version = "0.2.1", features = ["alloc"] } @@ -70,7 +70,7 @@ gstreamer-sys = "0.23" gstreamer-video = "0.23" harfbuzz-sys = "0.6.1" headers = "0.4" -hitrace = "0.1.4" +hitrace = "0.1.5" html5ever = "0.31" http = "1.3" http-body-util = "0.1" @@ -113,6 +113,7 @@ rand_isaac = "0.3" raw-window-handle = "0.6" rayon = "1" regex = "1.11" +resvg = "0.45.0" rustls = { version = "0.23", default-features = false, features = ["logging", "std", "tls12"] } rustls-pemfile = "2.0" rustls-pki-types = "1.12" diff --git a/README.md b/README.md index 8147702f92d..8d51be16439 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,15 @@ Servo is a prototype web browser engine written in the [Rust](https://github.com/rust-lang/rust) language. It is currently developed on 64-bit macOS, 64-bit Linux, 64-bit Windows, 64-bit OpenHarmony, and Android. -Servo welcomes contribution from everyone. Check out [The Servo Book](https://book.servo.org) to get started, or go to [servo.org](https://servo.org/) for news and guides. +Servo welcomes contribution from everyone. Check out: + +- The [Servo Book](https://book.servo.org) for documentation +- [servo.org](https://servo.org/) for news and guides + +Coordination of Servo development happens: +- Here in the Github Issues +- On the [Servo Zulip](https://servo.zulipchat.com/) +- In video calls advertised in the [Servo Project](https://github.com/servo/project/issues) repo. ## Getting started diff --git a/SECURITY.md b/SECURITY.md index 0c5dd453447..c4e75025880 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,4 +1,4 @@ # Security Policy -Given that Servo does not yet have customers or products, we are comfortable accepting the security related vulnerabilities as a [new GitHub issue](https://github.com/servo/servo/security/advisories/new) for now. +Given that Servo does not yet have customers or products, we are comfortable accepting the security related issues as [GitHub security reports](https://github.com/servo/servo/security/advisories/new) for now. diff --git a/components/canvas/Cargo.toml b/components/canvas/Cargo.toml index 6084fc6e434..7aadc8a9bb5 100644 --- a/components/canvas/Cargo.toml +++ b/components/canvas/Cargo.toml @@ -24,7 +24,6 @@ ipc-channel = { workspace = true } log = { workspace = true } lyon_geom = "1.0.4" net_traits = { workspace = true } -num-traits = { workspace = true } pixels = { path = "../pixels" } range = { path = "../range" } raqote = "0.8.5" diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index 82a221d560d..efadbf8d577 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -97,7 +97,10 @@ impl<'a> CanvasPaintThread<'a> { let canvas_data = canvas_paint_thread.create_canvas(size); creator.send(canvas_data).unwrap(); }, - Ok(ConstellationCanvasMsg::Exit) => break, + Ok(ConstellationCanvasMsg::Exit(exit_sender)) => { + let _ = exit_sender.send(()); + break; + }, Err(e) => { warn!("Error on CanvasPaintThread receive ({})", e); break; diff --git a/components/compositing/Cargo.toml b/components/compositing/Cargo.toml index 8a670a4b4a7..084bb54a5fc 100644 --- a/components/compositing/Cargo.toml +++ b/components/compositing/Cargo.toml @@ -34,11 +34,11 @@ log = { workspace = true } net = { path = "../net" } pixels = { path = "../pixels" } profile_traits = { workspace = true } -script_traits = { workspace = true } servo_allocator = { path = "../allocator" } servo_config = { path = "../config" } servo_geometry = { path = "../geometry" } stylo_traits = { workspace = true } +timers = { path = "../timers" } tracing = { workspace = true, optional = true } webrender = { workspace = true } webrender_api = { workspace = true } diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index b1669277ba1..a76b0022122 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -7,10 +7,9 @@ use std::collections::HashMap; use std::env; use std::fs::create_dir_all; use std::iter::once; -use std::mem::take; use std::rc::Rc; use std::sync::Arc; -use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; +use std::time::{SystemTime, UNIX_EPOCH}; use base::cross_process_instant::CrossProcessInstant; use base::id::{PipelineId, WebViewId}; @@ -33,7 +32,7 @@ use fnv::FnvHashMap; use ipc_channel::ipc::{self, IpcSharedMemory}; use libc::c_void; use log::{debug, info, trace, warn}; -use pixels::{CorsStatus, Image, ImageFrame, PixelFormat}; +use pixels::{CorsStatus, ImageFrame, ImageMetadata, PixelFormat, RasterImage}; use profile_traits::mem::{ProcessReports, ProfilerRegistration, Report, ReportKind}; use profile_traits::time::{self as profile_time, ProfilerCategory}; use profile_traits::{path, time_profile}; @@ -54,8 +53,9 @@ use webrender_api::{ }; use crate::InitialCompositorState; +use crate::refresh_driver::RefreshDriver; use crate::webview_manager::WebViewManager; -use crate::webview_renderer::{UnknownWebView, WebViewRenderer}; +use crate::webview_renderer::{PinchZoomResult, UnknownWebView, WebViewRenderer}; #[derive(Debug, PartialEq)] enum UnableToComposite { @@ -87,6 +87,9 @@ pub enum WebRenderDebugOption { } /// Data that is shared by all WebView renderers. pub struct ServoRenderer { + /// The [`RefreshDriver`] which manages the rythym of painting. + refresh_driver: RefreshDriver, + /// This is a temporary map between [`PipelineId`]s and their associated [`WebViewId`]. Once /// all renderer operations become per-`WebView` this map can be removed, but we still sometimes /// need to work backwards to figure out what `WebView` is associated with a `Pipeline`. @@ -152,18 +155,14 @@ pub struct IOCompositor { /// The number of frames pending to receive from WebRender. pending_frames: usize, - /// The [`Instant`] of the last animation tick, used to avoid flooding the Constellation and - /// ScriptThread with a deluge of animation ticks. - last_animation_tick: Instant, - /// A handle to the memory profiler which will automatically unregister /// when it's dropped. _mem_profiler_registration: ProfilerRegistration, } /// Why we need to be repainted. This is used for debugging. -#[derive(Clone, Copy, Default)] -struct RepaintReason(u8); +#[derive(Clone, Copy, Default, PartialEq)] +pub(crate) struct RepaintReason(u8); bitflags! { impl RepaintReason: u8 { @@ -387,6 +386,10 @@ impl IOCompositor { ); let compositor = IOCompositor { global: Rc::new(RefCell::new(ServoRenderer { + refresh_driver: RefreshDriver::new( + state.constellation_chan.clone(), + state.event_loop_waker, + ), shutdown_state: state.shutdown_state, pipeline_to_webview_map: Default::default(), compositor_receiver: state.receiver, @@ -407,7 +410,6 @@ impl IOCompositor { webrender: Some(state.webrender), rendering_context: state.rendering_context, pending_frames: 0, - last_animation_tick: Instant::now(), _mem_profiler_registration: registration, }; @@ -451,7 +453,16 @@ impl IOCompositor { } pub fn needs_repaint(&self) -> bool { - !self.needs_repaint.get().is_empty() + let repaint_reason = self.needs_repaint.get(); + if repaint_reason.is_empty() { + return false; + } + + !self + .global + .borrow() + .refresh_driver + .wait_to_paint(repaint_reason) } pub fn finish_shutting_down(&mut self) { @@ -520,15 +531,17 @@ impl IOCompositor { pipeline_id, animation_state, ) => { - if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) { - if webview_renderer - .change_pipeline_running_animations_state(pipeline_id, animation_state) && - webview_renderer.animating() - { - // These operations should eventually happen per-WebView, but they are - // global now as rendering is still global to all WebViews. - self.process_animations(true); - } + let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else { + return; + }; + + if webview_renderer + .change_pipeline_running_animations_state(pipeline_id, animation_state) + { + self.global + .borrow() + .refresh_driver + .notify_animation_state_changed(webview_renderer); } }, @@ -573,14 +586,15 @@ impl IOCompositor { }, CompositorMsg::SetThrottled(webview_id, pipeline_id, throttled) => { - if let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) { - if webview_renderer.set_throttled(pipeline_id, throttled) && - webview_renderer.animating() - { - // These operations should eventually happen per-WebView, but they are - // global now as rendering is still global to all WebViews. - self.process_animations(true); - } + let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else { + return; + }; + + if webview_renderer.set_throttled(pipeline_id, throttled) { + self.global + .borrow() + .refresh_driver + .notify_animation_state_changed(webview_renderer); } }, @@ -621,29 +635,37 @@ impl IOCompositor { } }, - CompositorMsg::WebDriverMouseButtonEvent(webview_id, action, button, x, y) => { + CompositorMsg::WebDriverMouseButtonEvent( + webview_id, + action, + button, + x, + y, + message_id, + ) => { let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else { warn!("Handling input event for unknown webview: {webview_id}"); return; }; let dppx = webview_renderer.device_pixels_per_page_pixel(); let point = dppx.transform_point(Point2D::new(x, y)); - webview_renderer.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent { - point, - action, - button, - })); + webview_renderer.dispatch_input_event( + InputEvent::MouseButton(MouseButtonEvent::new(action, button, point)) + .with_webdriver_message_id(Some(message_id)), + ); }, - CompositorMsg::WebDriverMouseMoveEvent(webview_id, x, y) => { + CompositorMsg::WebDriverMouseMoveEvent(webview_id, x, y, message_id) => { let Some(webview_renderer) = self.webview_renderers.get_mut(webview_id) else { warn!("Handling input event for unknown webview: {webview_id}"); return; }; let dppx = webview_renderer.device_pixels_per_page_pixel(); let point = dppx.transform_point(Point2D::new(x, y)); - webview_renderer - .dispatch_input_event(InputEvent::MouseMove(MouseMoveEvent { point })); + webview_renderer.dispatch_input_event( + InputEvent::MouseMove(MouseMoveEvent::new(point)) + .with_webdriver_message_id(Some(message_id)), + ); }, CompositorMsg::WebDriverWheelScrollEvent(webview_id, x, y, delta_x, delta_y) => { @@ -1264,39 +1286,6 @@ impl IOCompositor { self.set_needs_repaint(RepaintReason::Resize); } - /// If there are any animations running, dispatches appropriate messages to the constellation. - fn process_animations(&mut self, force: bool) { - // When running animations in order to dump a screenshot (not after a full composite), don't send - // animation ticks faster than about 60Hz. - // - // TODO: This should be based on the refresh rate of the screen and also apply to all - // animation ticks, not just ones sent while waiting to dump screenshots. This requires - // something like a refresh driver concept though. - if !force && (Instant::now() - self.last_animation_tick) < Duration::from_millis(16) { - return; - } - self.last_animation_tick = Instant::now(); - - let animating_webviews: Vec<_> = self - .webview_renderers - .iter() - .filter_map(|webview_renderer| { - if webview_renderer.animating() { - Some(webview_renderer.id) - } else { - None - } - }) - .collect(); - if !animating_webviews.is_empty() { - if let Err(error) = self.global.borrow().constellation_sender.send( - EmbedderToConstellationMessage::TickAnimation(animating_webviews), - ) { - warn!("Sending tick to constellation failed ({error:?})."); - } - } - } - pub fn on_zoom_reset_window_event(&mut self, webview_id: WebViewId) { if self.global.borrow().shutdown_state() != ShutdownState::NotShuttingDown { return; @@ -1403,6 +1392,11 @@ impl IOCompositor { /// Render the WebRender scene to the active `RenderingContext`. If successful, trigger /// the next round of animations. pub fn render(&mut self) -> bool { + self.global + .borrow() + .refresh_driver + .notify_will_paint(self.webview_renderers.iter()); + if let Err(error) = self.render_inner() { warn!("Unable to render: {error:?}"); return false; @@ -1412,9 +1406,6 @@ impl IOCompositor { // the scene no longer needs to be repainted. self.needs_repaint.set(RepaintReason::empty()); - // Queue up any subsequent paints for animations. - self.process_animations(true); - true } @@ -1424,7 +1415,7 @@ impl IOCompositor { &mut self, webview_id: WebViewId, page_rect: Option>, - ) -> Result, UnableToComposite> { + ) -> Result, UnableToComposite> { self.render_inner()?; let size = self.rendering_context.size2d().to_i32(); @@ -1451,16 +1442,19 @@ impl IOCompositor { Ok(self .rendering_context .read_to_image(rect) - .map(|image| Image { - width: image.width(), - height: image.height(), + .map(|image| RasterImage { + metadata: ImageMetadata { + width: image.width(), + height: image.height(), + }, format: PixelFormat::RGBA8, frames: vec![ImageFrame { delay: None, - bytes: ipc::IpcSharedMemory::from_bytes(&image), + byte_range: 0..image.len(), width: image.width(), height: image.height(), }], + bytes: ipc::IpcSharedMemory::from_bytes(&image), id: None, cors_status: CorsStatus::Safe, })) @@ -1482,10 +1476,8 @@ impl IOCompositor { if opts::get().wait_for_stable_image { // The current image may be ready to output. However, if there are animations active, - // tick those instead and continue waiting for the image output to be stable AND - // all active animations to complete. + // continue waiting for the image output to be stable AND all active animations to complete. if self.animations_or_animation_callbacks_running() { - self.process_animations(false); return Err(UnableToComposite::NotReadyToPaintImage( NotReadyToPaint::AnimationsActive, )); @@ -1668,11 +1660,39 @@ impl IOCompositor { if let Err(err) = self.rendering_context.make_current() { warn!("Failed to make the rendering context current: {:?}", err); } - let mut webview_renderers = take(&mut self.webview_renderers); - for webview_renderer in webview_renderers.iter_mut() { - webview_renderer.process_pending_scroll_events(self); + + let mut need_zoom = false; + let scroll_offset_updates: Vec<_> = self + .webview_renderers + .iter_mut() + .filter_map(|webview_renderer| { + let (zoom, scroll_result) = + webview_renderer.process_pending_scroll_and_pinch_zoom_events(); + need_zoom = need_zoom || (zoom == PinchZoomResult::DidPinchZoom); + scroll_result + }) + .collect(); + + if need_zoom || !scroll_offset_updates.is_empty() { + let mut transaction = Transaction::new(); + if need_zoom { + self.send_root_pipeline_display_list_in_transaction(&mut transaction); + } + for update in scroll_offset_updates { + let offset = LayoutVector2D::new(-update.offset.x, -update.offset.y); + transaction.set_scroll_offsets( + update.external_scroll_id, + vec![SampledScrollOffset { + offset, + generation: 0, + }], + ); + } + + self.generate_frame(&mut transaction, RenderReasons::APZ); + self.global.borrow_mut().send_transaction(transaction); } - self.webview_renderers = webview_renderers; + self.global.borrow().shutdown_state() != ShutdownState::FinishedShuttingDown } diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index a66c61499e5..4faeadf5ba6 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -11,7 +11,7 @@ use compositing_traits::rendering_context::RenderingContext; use compositing_traits::{CompositorMsg, CompositorProxy}; use constellation_traits::EmbedderToConstellationMessage; use crossbeam_channel::{Receiver, Sender}; -use embedder_traits::ShutdownState; +use embedder_traits::{EventLoopWaker, ShutdownState}; use profile_traits::{mem, time}; use webrender::RenderApi; use webrender_api::DocumentId; @@ -22,9 +22,10 @@ pub use crate::compositor::{IOCompositor, WebRenderDebugOption}; mod tracing; mod compositor; +mod refresh_driver; mod touch; -pub mod webview_manager; -pub mod webview_renderer; +mod webview_manager; +mod webview_renderer; /// Data used to construct a compositor. pub struct InitialCompositorState { @@ -49,4 +50,7 @@ pub struct InitialCompositorState { pub webrender_gl: Rc, #[cfg(feature = "webxr")] pub webxr_main_thread: webxr::MainThreadRegistry, + /// An [`EventLoopWaker`] used in order to wake up the embedder when it is + /// time to paint. + pub event_loop_waker: Box, } diff --git a/components/compositing/refresh_driver.rs b/components/compositing/refresh_driver.rs new file mode 100644 index 00000000000..5531a7257c8 --- /dev/null +++ b/components/compositing/refresh_driver.rs @@ -0,0 +1,234 @@ +/* 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 https://mozilla.org/MPL/2.0/. */ + +use std::cell::Cell; +use std::collections::hash_map::Values; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread::{self, JoinHandle}; +use std::time::Duration; + +use base::id::WebViewId; +use constellation_traits::EmbedderToConstellationMessage; +use crossbeam_channel::{Sender, select}; +use embedder_traits::EventLoopWaker; +use log::warn; +use timers::{BoxedTimerCallback, TimerEventId, TimerEventRequest, TimerScheduler, TimerSource}; + +use crate::compositor::RepaintReason; +use crate::webview_renderer::WebViewRenderer; + +const FRAME_DURATION: Duration = Duration::from_millis(1000 / 120); + +/// The [`RefreshDriver`] is responsible for controlling updates to aall `WebView`s +/// onscreen presentation. Currently, it only manages controlling animation update +/// requests. +/// +/// The implementation is very basic at the moment, only requesting new animation +/// frames at a constant time after a repaint. +pub(crate) struct RefreshDriver { + /// The channel on which messages can be sent to the Constellation. + pub(crate) constellation_sender: Sender, + + /// Whether or not we are currently animating via a timer. + pub(crate) animating: Cell, + + /// Whether or not we are waiting for our frame timeout to trigger + pub(crate) waiting_for_frame_timeout: Arc, + + /// A [`TimerThread`] which is used to schedule frame timeouts in the future. + timer_thread: TimerThread, + + /// An [`EventLoopWaker`] to be used to wake up the embedder when it is + /// time to paint a frame. + event_loop_waker: Box, +} + +impl RefreshDriver { + pub(crate) fn new( + constellation_sender: Sender, + event_loop_waker: Box, + ) -> Self { + Self { + constellation_sender, + animating: Default::default(), + waiting_for_frame_timeout: Default::default(), + timer_thread: Default::default(), + event_loop_waker, + } + } + + fn timer_callback(&self) -> BoxedTimerCallback { + let waiting_for_frame_timeout = self.waiting_for_frame_timeout.clone(); + let event_loop_waker = self.event_loop_waker.clone_box(); + Box::new(move |_| { + waiting_for_frame_timeout.store(false, Ordering::Relaxed); + event_loop_waker.wake(); + }) + } + + /// Notify the [`RefreshDriver`] that a paint is about to happen. This will trigger + /// new animation frames for all active `WebView`s and schedule a new frame deadline. + pub(crate) fn notify_will_paint( + &self, + webview_renderers: Values<'_, WebViewId, WebViewRenderer>, + ) { + // If we are still waiting for the frame to timeout this paint was caused for some + // non-animation related reason and we should wait until the frame timeout to trigger + // the next one. + if self.waiting_for_frame_timeout.load(Ordering::Relaxed) { + return; + } + + // If any WebViews are animating ask them to paint again for another animation tick. + let animating_webviews: Vec<_> = webview_renderers + .filter_map(|webview_renderer| { + if webview_renderer.animating() { + Some(webview_renderer.id) + } else { + None + } + }) + .collect(); + + // If nothing is animating any longer, update our state and exit early without requesting + // any noew frames nor triggering a new animation deadline. + if animating_webviews.is_empty() { + self.animating.set(false); + return; + } + + if let Err(error) = + self.constellation_sender + .send(EmbedderToConstellationMessage::TickAnimation( + animating_webviews, + )) + { + warn!("Sending tick to constellation failed ({error:?})."); + } + + // Queue the next frame deadline. + self.animating.set(true); + self.waiting_for_frame_timeout + .store(true, Ordering::Relaxed); + self.timer_thread + .queue_timer(FRAME_DURATION, self.timer_callback()); + } + + /// Notify the [`RefreshDriver`] that the animation state of a particular `WebView` + /// via its associated [`WebViewRenderer`] has changed. In the case that a `WebView` + /// has started animating, the [`RefreshDriver`] will request a new frame from it + /// immediately, but only render that frame at the next frame deadline. + pub(crate) fn notify_animation_state_changed(&self, webview_renderer: &WebViewRenderer) { + if !webview_renderer.animating() { + // If no other WebView is animating we will officially stop animated once the + // next frame has been painted. + return; + } + + if let Err(error) = + self.constellation_sender + .send(EmbedderToConstellationMessage::TickAnimation(vec![ + webview_renderer.id, + ])) + { + warn!("Sending tick to constellation failed ({error:?})."); + } + + if self.animating.get() { + return; + } + + self.animating.set(true); + self.waiting_for_frame_timeout + .store(true, Ordering::Relaxed); + self.timer_thread + .queue_timer(FRAME_DURATION, self.timer_callback()); + } + + /// Whether or not the renderer should trigger a message to the embedder to request a + /// repaint. This might be false if: we are animating and the repaint reason is just + /// for a new frame. In that case, the renderer should wait until the frame timeout to + /// ask the embedder to repaint. + pub(crate) fn wait_to_paint(&self, repaint_reason: RepaintReason) -> bool { + if !self.animating.get() || repaint_reason != RepaintReason::NewWebRenderFrame { + return false; + } + + self.waiting_for_frame_timeout.load(Ordering::Relaxed) + } +} + +enum TimerThreadMessage { + Request(TimerEventRequest), + Quit, +} + +/// A thread that manages a [`TimerScheduler`] running in the background of the +/// [`RefreshDriver`]. This is necessary because we need a reliable way of waking up the +/// embedder's main thread, which may just be sleeping until the `EventLoopWaker` asks it +/// to wake up. +/// +/// It would be nice to integrate this somehow into the embedder thread, but it would +/// require both some communication with the embedder and for all embedders to be well +/// behave respecting wakeup timeouts -- a bit too much to ask at the moment. +struct TimerThread { + sender: Sender, + join_handle: Option>, +} + +impl Drop for TimerThread { + fn drop(&mut self) { + let _ = self.sender.send(TimerThreadMessage::Quit); + if let Some(join_handle) = self.join_handle.take() { + let _ = join_handle.join(); + } + } +} + +impl Default for TimerThread { + fn default() -> Self { + let (sender, receiver) = crossbeam_channel::unbounded::(); + let join_handle = thread::Builder::new() + .name(String::from("CompositorTimerThread")) + .spawn(move || { + let mut scheduler = TimerScheduler::default(); + + loop { + select! { + recv(receiver) -> message => { + match message { + Ok(TimerThreadMessage::Request(request)) => { + scheduler.schedule_timer(request); + }, + _ => return, + } + }, + recv(scheduler.wait_channel()) -> _message => { + scheduler.dispatch_completed_timers(); + }, + }; + } + }) + .expect("Could not create RefreshDriver timer thread."); + + Self { + sender, + join_handle: Some(join_handle), + } + } +} + +impl TimerThread { + fn queue_timer(&self, duration: Duration, callback: BoxedTimerCallback) { + let _ = self + .sender + .send(TimerThreadMessage::Request(TimerEventRequest { + callback, + source: TimerSource::FromWorker, + id: TimerEventId(0), + duration, + })); + } +} diff --git a/components/compositing/webview_renderer.rs b/components/compositing/webview_renderer.rs index a51dd5f8cda..b0e91ccb02e 100644 --- a/components/compositing/webview_renderer.rs +++ b/components/compositing/webview_renderer.rs @@ -20,15 +20,11 @@ use fnv::FnvHashSet; use log::{debug, warn}; use servo_geometry::DeviceIndependentPixel; use style_traits::{CSSPixel, PinchZoomFactor}; -use webrender::Transaction; use webrender_api::units::{ DeviceIntPoint, DeviceIntRect, DevicePixel, DevicePoint, DeviceRect, LayoutVector2D, }; -use webrender_api::{ - ExternalScrollId, HitTestFlags, RenderReasons, SampledScrollOffset, ScrollLocation, -}; +use webrender_api::{ExternalScrollId, HitTestFlags, ScrollLocation}; -use crate::IOCompositor; use crate::compositor::{PipelineDetails, ServoRenderer}; use crate::touch::{TouchHandler, TouchMoveAction, TouchMoveAllowed, TouchSequenceState}; @@ -55,6 +51,19 @@ enum ScrollZoomEvent { Scroll(ScrollEvent), } +#[derive(Clone, Copy, Debug, PartialEq)] +pub(crate) struct ScrollResult { + pub pipeline_id: PipelineId, + pub external_scroll_id: ExternalScrollId, + pub offset: LayoutVector2D, +} + +#[derive(PartialEq)] +pub(crate) enum PinchZoomResult { + DidPinchZoom, + DidNotPinchZoom, +} + /// A renderer for a libservo `WebView`. This is essentially the [`ServoRenderer`]'s interface to a /// libservo `WebView`, but the code here cannot depend on libservo in order to prevent circular /// dependencies, which is why we store a `dyn WebViewTrait` here instead of the `WebView` itself. @@ -678,17 +687,17 @@ impl WebViewRenderer { /// fn simulate_mouse_click(&mut self, point: DevicePoint) { let button = MouseButton::Left; - self.dispatch_input_event(InputEvent::MouseMove(MouseMoveEvent { point })); - self.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent { + self.dispatch_input_event(InputEvent::MouseMove(MouseMoveEvent::new(point))); + self.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent::new( + MouseButtonAction::Down, button, - action: MouseButtonAction::Down, point, - })); - self.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent { + ))); + self.dispatch_input_event(InputEvent::MouseButton(MouseButtonEvent::new( + MouseButtonAction::Up, button, - action: MouseButtonAction::Up, point, - })); + ))); } pub(crate) fn notify_scroll_event( @@ -737,9 +746,17 @@ impl WebViewRenderer { self.on_scroll_window_event(scroll_location, cursor) } - pub(crate) fn process_pending_scroll_events(&mut self, compositor: &mut IOCompositor) { + /// Process pending scroll events for this [`WebViewRenderer`]. Returns a tuple containing: + /// + /// - A boolean that is true if a zoom occurred. + /// - An optional [`ScrollResult`] if a scroll occurred. + /// + /// It is up to the caller to ensure that these events update the rendering appropriately. + pub(crate) fn process_pending_scroll_and_pinch_zoom_events( + &mut self, + ) -> (PinchZoomResult, Option) { if self.pending_scroll_zoom_events.is_empty() { - return; + return (PinchZoomResult::DidNotPinchZoom, None); } // Batch up all scroll events into one, or else we'll do way too much painting. @@ -790,37 +807,24 @@ impl WebViewRenderer { } } - let zoom_changed = - self.set_pinch_zoom_level(self.pinch_zoom_level().get() * combined_magnification); let scroll_result = combined_scroll_event.and_then(|combined_event| { self.scroll_node_at_device_point( combined_event.cursor.to_f32(), combined_event.scroll_location, ) }); - if !zoom_changed && scroll_result.is_none() { - return; + if let Some(scroll_result) = scroll_result { + self.send_scroll_positions_to_layout_for_pipeline(scroll_result.pipeline_id); } - let mut transaction = Transaction::new(); - if zoom_changed { - compositor.send_root_pipeline_display_list_in_transaction(&mut transaction); - } + let pinch_zoom_result = match self + .set_pinch_zoom_level(self.pinch_zoom_level().get() * combined_magnification) + { + true => PinchZoomResult::DidPinchZoom, + false => PinchZoomResult::DidNotPinchZoom, + }; - if let Some((pipeline_id, external_id, offset)) = scroll_result { - let offset = LayoutVector2D::new(-offset.x, -offset.y); - transaction.set_scroll_offsets( - external_id, - vec![SampledScrollOffset { - offset, - generation: 0, - }], - ); - self.send_scroll_positions_to_layout_for_pipeline(pipeline_id); - } - - compositor.generate_frame(&mut transaction, RenderReasons::APZ); - self.global.borrow_mut().send_transaction(transaction); + (pinch_zoom_result, scroll_result) } /// Perform a hit test at the given [`DevicePoint`] and apply the [`ScrollLocation`] @@ -831,7 +835,7 @@ impl WebViewRenderer { &mut self, cursor: DevicePoint, scroll_location: ScrollLocation, - ) -> Option<(PipelineId, ExternalScrollId, LayoutVector2D)> { + ) -> Option { let scroll_location = match scroll_location { ScrollLocation::Delta(delta) => { let device_pixels_per_page = self.device_pixels_per_page_pixel(); @@ -871,8 +875,12 @@ impl WebViewRenderer { let scroll_result = pipeline_details .scroll_tree .scroll_node_or_ancestor(scroll_tree_node, scroll_location); - if let Some((external_id, offset)) = scroll_result { - return Some((*pipeline_id, external_id, offset)); + if let Some((external_scroll_id, offset)) = scroll_result { + return Some(ScrollResult { + pipeline_id: *pipeline_id, + external_scroll_id, + offset, + }); } } } diff --git a/components/config/prefs.rs b/components/config/prefs.rs index a9ec112e3eb..896a4fe0bc4 100644 --- a/components/config/prefs.rs +++ b/components/config/prefs.rs @@ -99,7 +99,6 @@ pub struct Preferences { pub dom_serviceworker_timeout_seconds: i64, pub dom_servo_helpers_enabled: bool, pub dom_servoparser_async_html_tokenizer_enabled: bool, - pub dom_shadowdom_enabled: bool, pub dom_svg_enabled: bool, pub dom_testable_crash_enabled: bool, pub dom_testbinding_enabled: bool, @@ -117,10 +116,6 @@ pub struct Preferences { // https://testutils.spec.whatwg.org#availability pub dom_testutils_enabled: bool, pub dom_trusted_types_enabled: bool, - /// Enable the [URLPattern] API. - /// - /// [URLPattern]: https://developer.mozilla.org/en-US/docs/Web/API/URLPattern - pub dom_urlpattern_enabled: bool, pub dom_xpath_enabled: bool, /// Enable WebGL2 APIs. pub dom_webgl2_enabled: bool, @@ -277,7 +272,6 @@ impl Preferences { dom_serviceworker_timeout_seconds: 60, dom_servo_helpers_enabled: false, dom_servoparser_async_html_tokenizer_enabled: false, - dom_shadowdom_enabled: true, dom_svg_enabled: false, dom_testable_crash_enabled: false, dom_testbinding_enabled: false, @@ -294,7 +288,6 @@ impl Preferences { dom_testperf_enabled: false, dom_testutils_enabled: false, dom_trusted_types_enabled: false, - dom_urlpattern_enabled: false, dom_webgl2_enabled: false, dom_webgpu_enabled: false, dom_webgpu_wgpu_backend: String::new(), diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 5db37800c42..5b4d244e746 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -132,7 +132,7 @@ use embedder_traits::{ FocusSequenceNumber, ImeEvent, InputEvent, JSValue, JavaScriptEvaluationError, JavaScriptEvaluationId, MediaSessionActionType, MediaSessionEvent, MediaSessionPlaybackState, MouseButton, MouseButtonAction, MouseButtonEvent, Theme, ViewportDetails, WebDriverCommandMsg, - WebDriverLoadStatus, + WebDriverCommandResponse, WebDriverLoadStatus, }; use euclid::Size2D; use euclid::default::Size2D as UntypedSize2D; @@ -148,6 +148,7 @@ use net_traits::pub_domains::reg_host; use net_traits::request::Referrer; use net_traits::storage_thread::{StorageThreadMsg, StorageType}; use net_traits::{self, IpcSend, ReferrerPolicy, ResourceThreads}; +use profile_traits::mem::ProfilerMsg; use profile_traits::{mem, time}; use script_layout_interface::{LayoutFactory, ScriptThreadFactory}; use script_traits::{ @@ -172,6 +173,7 @@ use crate::browsingcontext::{ AllBrowsingContextsIterator, BrowsingContext, FullyActiveBrowsingContextsIterator, NewBrowsingContextInfo, }; +use crate::constellation_webview::ConstellationWebView; use crate::event_loop::EventLoop; use crate::pipeline::{InitialPipelineState, Pipeline}; use crate::process_manager::ProcessManager; @@ -229,18 +231,6 @@ struct WebrenderWGPU { wgpu_image_map: WGPUImageMap, } -/// Servo supports multiple top-level browsing contexts or “webviewsâ€, so `Constellation` needs to -/// store webview-specific data for bookkeeping. -struct WebView { - /// The currently focused browsing context in this webview for key events. - /// The focused pipeline is the current entry of the focused browsing - /// context. - focused_browsing_context_id: BrowsingContextId, - - /// The joint session history for this webview. - session_history: JointSessionHistory, -} - /// A browsing context group. /// /// @@ -324,7 +314,7 @@ pub struct Constellation { compositor_proxy: CompositorProxy, /// Bookkeeping data for all webviews in the constellation. - webviews: WebViewManager, + webviews: WebViewManager, /// Channels for the constellation to send messages to the public /// resource-related threads. There are two groups of resource threads: one @@ -532,6 +522,8 @@ pub struct InitialConstellationState { struct WebDriverData { load_channel: Option<(PipelineId, IpcSender)>, resize_channel: Option>>, + // Forward responses from the script thread to the webdriver server. + input_command_response_sender: Option>, } impl WebDriverData { @@ -539,6 +531,7 @@ impl WebDriverData { WebDriverData { load_channel: None, resize_channel: None, + input_command_response_sender: None, } } } @@ -892,6 +885,16 @@ where if self.shutting_down { return; } + + let Some(theme) = self + .webviews + .get(webview_id) + .map(ConstellationWebView::theme) + else { + warn!("Tried to create Pipeline for uknown WebViewId: {webview_id:?}"); + return; + }; + debug!( "{}: Creating new pipeline in {}", pipeline_id, browsing_context_id @@ -970,6 +973,7 @@ where time_profiler_chan: self.time_profiler_chan.clone(), mem_profiler_chan: self.mem_profiler_chan.clone(), viewport_details: initial_viewport_details, + theme, event_loop, load_data, prev_throttled: throttled, @@ -1433,8 +1437,8 @@ where size_type, ); }, - EmbedderToConstellationMessage::ThemeChange(theme) => { - self.handle_theme_change(theme); + EmbedderToConstellationMessage::ThemeChange(webview_id, theme) => { + self.handle_theme_change(webview_id, theme); }, EmbedderToConstellationMessage::TickAnimation(webview_ids) => { self.handle_tick_animation(webview_ids) @@ -1485,6 +1489,9 @@ where ) => { self.handle_evaluate_javascript(webview_id, evaluation_id, script); }, + EmbedderToConstellationMessage::CreateMemoryReport(sender) => { + self.mem_profiler_chan.send(ProfilerMsg::Report(sender)); + }, } } @@ -1867,6 +1874,18 @@ where ScriptToConstellationMessage::FinishJavaScriptEvaluation(evaluation_id, result) => { self.handle_finish_javascript_evaluation(evaluation_id, result) }, + ScriptToConstellationMessage::WebDriverInputComplete(msg_id) => { + if let Some(ref reply_sender) = self.webdriver.input_command_response_sender { + reply_sender + .send(WebDriverCommandResponse { id: msg_id }) + .unwrap_or_else(|_| { + warn!("Failed to send WebDriverInputComplete {:?}", msg_id); + self.webdriver.input_command_response_sender = None; + }); + } else { + warn!("No WebDriver input_command_response_sender"); + } + }, } } @@ -2743,7 +2762,11 @@ where } debug!("Exiting Canvas Paint thread."); - if let Err(e) = self.canvas_sender.send(ConstellationCanvasMsg::Exit) { + let (canvas_exit_sender, canvas_exit_receiver) = unbounded(); + if let Err(e) = self + .canvas_sender + .send(ConstellationCanvasMsg::Exit(canvas_exit_sender)) + { warn!("Exit Canvas Paint thread failed ({})", e); } @@ -2785,6 +2808,10 @@ where debug!("Exiting GLPlayer thread."); WindowGLContext::get().exit(); + // Wait for the canvas thread to exit before shutting down the font service, as + // canvas might still be using the system font service before shutting down. + let _ = canvas_exit_receiver.recv(); + debug!("Exiting the system font service thread."); self.system_font_service.exit(); @@ -3127,13 +3154,8 @@ where // Register this new top-level browsing context id as a webview and set // its focused browsing context to be itself. - self.webviews.add( - webview_id, - WebView { - focused_browsing_context_id: browsing_context_id, - session_history: JointSessionHistory::new(), - }, - ); + self.webviews + .add(webview_id, ConstellationWebView::new(browsing_context_id)); // https://html.spec.whatwg.org/multipage/#creating-a-new-browsing-context-group let mut new_bc_group: BrowsingContextGroup = Default::default(); @@ -3539,10 +3561,7 @@ where self.pipelines.insert(new_pipeline_id, pipeline); self.webviews.add( new_webview_id, - WebView { - focused_browsing_context_id: new_browsing_context_id, - session_history: JointSessionHistory::new(), - }, + ConstellationWebView::new(new_browsing_context_id), ); // https://html.spec.whatwg.org/multipage/#bcg-append @@ -4836,7 +4855,11 @@ where mouse_button, x, y, + msg_id, + response_sender, ) => { + self.webdriver.input_command_response_sender = Some(response_sender); + self.compositor_proxy .send(CompositorMsg::WebDriverMouseButtonEvent( webview_id, @@ -4844,11 +4867,16 @@ where mouse_button, x, y, + msg_id, )); }, - WebDriverCommandMsg::MouseMoveAction(webview_id, x, y) => { + WebDriverCommandMsg::MouseMoveAction(webview_id, x, y, msg_id, response_sender) => { + self.webdriver.input_command_response_sender = Some(response_sender); + self.compositor_proxy - .send(CompositorMsg::WebDriverMouseMoveEvent(webview_id, x, y)); + .send(CompositorMsg::WebDriverMouseMoveEvent( + webview_id, x, y, msg_id, + )); }, WebDriverCommandMsg::WheelScrollAction(webview, x, y, delta_x, delta_y) => { self.compositor_proxy @@ -5599,18 +5627,31 @@ where } } - /// Handle theme change events from the embedder and forward them to the script thread + /// Handle theme change events from the embedder and forward them to all appropriate `ScriptThread`s. #[cfg_attr( feature = "tracing", tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") )] - fn handle_theme_change(&mut self, theme: Theme) { + fn handle_theme_change(&mut self, webview_id: WebViewId, theme: Theme) { + let Some(webview) = self.webviews.get_mut(webview_id) else { + warn!("Received theme change request for uknown WebViewId: {webview_id:?}"); + return; + }; + if !webview.set_theme(theme) { + return; + } + for pipeline in self.pipelines.values() { - let msg = ScriptThreadMessage::ThemeChange(pipeline.id, theme); - if let Err(err) = pipeline.event_loop.send(msg) { + if pipeline.webview_id != webview_id { + continue; + } + if let Err(error) = pipeline + .event_loop + .send(ScriptThreadMessage::ThemeChange(pipeline.id, theme)) + { warn!( - "{}: Failed to send theme change event to pipeline ({:?}).", - pipeline.id, err + "{}: Failed to send theme change event to pipeline ({error:?}).", + pipeline.id, ); } } diff --git a/components/constellation/constellation_webview.rs b/components/constellation/constellation_webview.rs new file mode 100644 index 00000000000..16c19e629fb --- /dev/null +++ b/components/constellation/constellation_webview.rs @@ -0,0 +1,45 @@ +/* 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 https://mozilla.org/MPL/2.0/. */ + +use base::id::BrowsingContextId; +use embedder_traits::Theme; + +use crate::session_history::JointSessionHistory; + +/// The `Constellation`'s view of a `WebView` in the embedding layer. This tracks all of the +/// `Constellation` state for this `WebView`. +pub(crate) struct ConstellationWebView { + /// The currently focused browsing context in this webview for key events. + /// The focused pipeline is the current entry of the focused browsing + /// context. + pub focused_browsing_context_id: BrowsingContextId, + + /// The joint session history for this webview. + pub session_history: JointSessionHistory, + + /// The [`Theme`] that this [`ConstellationWebView`] uses. This is communicated to all + /// `ScriptThread`s so that they know how to render the contents of a particular `WebView. + theme: Theme, +} + +impl ConstellationWebView { + pub(crate) fn new(focused_browsing_context_id: BrowsingContextId) -> Self { + Self { + focused_browsing_context_id, + session_history: JointSessionHistory::new(), + theme: Theme::Light, + } + } + + /// Set the [`Theme`] on this [`ConstellationWebView`] returning true if the theme changed. + pub(crate) fn set_theme(&mut self, new_theme: Theme) -> bool { + let old_theme = std::mem::replace(&mut self.theme, new_theme); + old_theme != self.theme + } + + /// Get the [`Theme`] of this [`ConstellationWebView`]. + pub(crate) fn theme(&self) -> Theme { + self.theme + } +} diff --git a/components/constellation/lib.rs b/components/constellation/lib.rs index c24543743b7..8927888aa93 100644 --- a/components/constellation/lib.rs +++ b/components/constellation/lib.rs @@ -9,6 +9,7 @@ mod tracing; mod browsingcontext; mod constellation; +mod constellation_webview; mod event_loop; mod logging; mod pipeline; diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index 556ef9bd60f..a0bf106ea06 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -25,7 +25,7 @@ use constellation_traits::{LoadData, SWManagerMsg, ScriptToConstellationChan}; use crossbeam_channel::{Sender, unbounded}; use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg}; use embedder_traits::user_content_manager::UserContentManager; -use embedder_traits::{AnimationState, FocusSequenceNumber, ViewportDetails}; +use embedder_traits::{AnimationState, FocusSequenceNumber, Theme, ViewportDetails}; use fonts::{SystemFontServiceProxy, SystemFontServiceProxySender}; use ipc_channel::Error; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; @@ -61,7 +61,7 @@ pub struct Pipeline { /// The ID of the browsing context that contains this Pipeline. pub browsing_context_id: BrowsingContextId, - /// The ID of the top-level browsing context that contains this Pipeline. + /// The [`WebViewId`] of the `WebView` that contains this Pipeline. pub webview_id: WebViewId, pub opener: Option, @@ -170,6 +170,9 @@ pub struct InitialPipelineState { /// The initial [`ViewportDetails`] to use when starting this new [`Pipeline`]. pub viewport_details: ViewportDetails, + /// The initial [`Theme`] to use when starting this new [`Pipeline`]. + pub theme: Theme, + /// The ID of the pipeline namespace for this script thread. pub pipeline_namespace_id: PipelineNamespaceId, @@ -224,6 +227,7 @@ impl Pipeline { opener: state.opener, load_data: state.load_data.clone(), viewport_details: state.viewport_details, + theme: state.theme, }; if let Err(e) = script_chan.send(ScriptThreadMessage::AttachLayout(new_layout_info)) @@ -280,6 +284,7 @@ impl Pipeline { time_profiler_chan: state.time_profiler_chan, mem_profiler_chan: state.mem_profiler_chan, viewport_details: state.viewport_details, + theme: state.theme, script_chan: script_chan.clone(), load_data: state.load_data.clone(), script_port, @@ -494,6 +499,7 @@ pub struct UnprivilegedPipelineContent { time_profiler_chan: time::ProfilerChan, mem_profiler_chan: profile_mem::ProfilerChan, viewport_details: ViewportDetails, + theme: Theme, script_chan: IpcSender, load_data: LoadData, script_port: IpcReceiver, @@ -544,6 +550,7 @@ impl UnprivilegedPipelineContent { memory_profiler_sender: self.mem_profiler_chan.clone(), devtools_server_sender: self.devtools_ipc_sender, viewport_details: self.viewport_details, + theme: self.theme, pipeline_namespace_id: self.pipeline_namespace_id, content_process_shutdown_sender: content_process_shutdown_chan, webgl_chan: self.webgl_chan, diff --git a/components/constellation/tracing.rs b/components/constellation/tracing.rs index fd7fe7dd251..99551bd58fc 100644 --- a/components/constellation/tracing.rs +++ b/components/constellation/tracing.rs @@ -78,6 +78,7 @@ mod from_compositor { Self::SetScrollStates(..) => target!("SetScrollStates"), Self::PaintMetric(..) => target!("PaintMetric"), Self::EvaluateJavaScript(..) => target!("EvaluateJavaScript"), + Self::CreateMemoryReport(..) => target!("CreateMemoryReport"), } } } @@ -177,6 +178,7 @@ mod from_script { Self::TitleChanged(..) => target!("TitleChanged"), Self::IFrameSizes(..) => target!("IFrameSizes"), Self::ReportMemory(..) => target!("ReportMemory"), + Self::WebDriverInputComplete(..) => target!("WebDriverInputComplete"), Self::FinishJavaScriptEvaluation(..) => target!("FinishJavaScriptEvaluation"), } } @@ -239,7 +241,7 @@ mod from_script { Self::StopGamepadHapticEffect(..) => target_variant!("StopGamepadHapticEffect"), Self::ShutdownComplete => target_variant!("ShutdownComplete"), Self::ShowNotification(..) => target_variant!("ShowNotification"), - Self::ShowSelectElementMenu(..) => target_variant!("ShowSelectElementMenu"), + Self::ShowFormControl(..) => target_variant!("ShowFormControl"), Self::FinishJavaScriptEvaluation(..) => { target_variant!("FinishJavaScriptEvaluation") }, diff --git a/components/devtools/actors/breakpoint.rs b/components/devtools/actors/breakpoint.rs new file mode 100644 index 00000000000..04f2de140b4 --- /dev/null +++ b/components/devtools/actors/breakpoint.rs @@ -0,0 +1,55 @@ +/* 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 https://mozilla.org/MPL/2.0/. */ + +use serde::Serialize; + +use crate::EmptyReplyMsg; +use crate::actor::{Actor, ActorMessageStatus}; +use crate::protocol::JsonPacketStream; + +#[derive(Serialize)] +pub struct BreakpointListActorMsg { + actor: String, +} + +pub struct BreakpointListActor { + name: String, +} + +impl Actor for BreakpointListActor { + fn name(&self) -> String { + self.name.clone() + } + + fn handle_message( + &self, + _registry: &crate::actor::ActorRegistry, + msg_type: &str, + _msg: &serde_json::Map, + stream: &mut std::net::TcpStream, + _stream_id: crate::StreamId, + ) -> Result { + Ok(match msg_type { + "setBreakpoint" => { + let msg = EmptyReplyMsg { from: self.name() }; + let _ = stream.write_json_packet(&msg); + + ActorMessageStatus::Processed + }, + "setActiveEventBreakpoints" => { + let msg = EmptyReplyMsg { from: self.name() }; + let _ = stream.write_json_packet(&msg); + + ActorMessageStatus::Processed + }, + _ => ActorMessageStatus::Ignored, + }) + } +} + +impl BreakpointListActor { + pub fn new(name: String) -> Self { + Self { name } + } +} diff --git a/components/devtools/actors/watcher.rs b/components/devtools/actors/watcher.rs index 061ffc92336..7720daf070d 100644 --- a/components/devtools/actors/watcher.rs +++ b/components/devtools/actors/watcher.rs @@ -19,6 +19,7 @@ use serde::Serialize; use serde_json::{Map, Value}; use self::network_parent::{NetworkParentActor, NetworkParentActorMsg}; +use super::breakpoint::BreakpointListActor; use super::thread::ThreadActor; use super::worker::WorkerMsg; use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; @@ -362,10 +363,14 @@ impl Actor for WatcherActor { ActorMessageStatus::Processed }, "getBreakpointListActor" => { + let breakpoint_list_name = registry.new_name("breakpoint-list"); + let breakpoint_list = BreakpointListActor::new(breakpoint_list_name.clone()); + registry.register_later(Box::new(breakpoint_list)); + let _ = stream.write_json_packet(&GetBreakpointListActorReply { from: self.name(), breakpoint_list: GetBreakpointListActorReplyInner { - actor: registry.new_name("breakpoint-list"), + actor: breakpoint_list_name, }, }); ActorMessageStatus::Processed diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs index d097cb25e9d..74a45eaf866 100644 --- a/components/devtools/lib.rs +++ b/components/devtools/lib.rs @@ -53,6 +53,7 @@ use crate::protocol::JsonPacketStream; mod actor; /// mod actors { + pub mod breakpoint; pub mod browsing_context; pub mod console; pub mod device; diff --git a/components/fonts/platform/macos/font.rs b/components/fonts/platform/macos/font.rs index 56eb8f4dd2c..5249621be81 100644 --- a/components/fonts/platform/macos/font.rs +++ b/components/fonts/platform/macos/font.rs @@ -287,7 +287,7 @@ impl PlatformFontMethods for PlatformFont { .unwrap_or(average_advance); let metrics = FontMetrics { - underline_size: Au::from_f64_au(underline_thickness), + underline_size: Au::from_f64_px(underline_thickness), // TODO(Issue #201): underline metrics are not reliable. Have to pull out of font table // directly. // diff --git a/components/fonts/platform/windows/font.rs b/components/fonts/platform/windows/font.rs index e33b2ad9d3e..74f592e63b9 100644 --- a/components/fonts/platform/windows/font.rs +++ b/components/fonts/platform/windows/font.rs @@ -132,7 +132,9 @@ impl PlatformFontMethods for PlatformFont { pt_size: Option, ) -> Result { let font_face = FontCollection::system() - .get_font_from_descriptor(&font_identifier.font_descriptor) + .font_from_descriptor(&font_identifier.font_descriptor) + .ok() + .flatten() .ok_or("Could not create Font from descriptor")? .create_font_face(); Self::new(font_face, pt_size) diff --git a/components/fonts/platform/windows/font_list.rs b/components/fonts/platform/windows/font_list.rs index d1aa19e178a..e9cdaac8562 100644 --- a/components/fonts/platform/windows/font_list.rs +++ b/components/fonts/platform/windows/font_list.rs @@ -25,7 +25,9 @@ where { let system_fc = FontCollection::system(); for family in system_fc.families_iter() { - callback(family.name()); + if let Ok(family_name) = family.family_name() { + callback(family_name); + } } } @@ -40,13 +42,17 @@ pub struct LocalFontIdentifier { impl LocalFontIdentifier { pub fn index(&self) -> u32 { FontCollection::system() - .get_font_from_descriptor(&self.font_descriptor) + .font_from_descriptor(&self.font_descriptor) + .ok() + .flatten() .map_or(0, |font| font.create_font_face().get_index()) } pub(crate) fn native_font_handle(&self) -> NativeFontHandle { let face = FontCollection::system() - .get_font_from_descriptor(&self.font_descriptor) + .font_from_descriptor(&self.font_descriptor) + .ok() + .flatten() .expect("Could not create Font from FontDescriptor") .create_font_face(); let path = face @@ -62,7 +68,9 @@ impl LocalFontIdentifier { } pub(crate) fn read_data_from_file(&self) -> Option> { - let font = FontCollection::system().get_font_from_descriptor(&self.font_descriptor)?; + let font = FontCollection::system() + .font_from_descriptor(&self.font_descriptor) + .ok()??; let face = font.create_font_face(); let files = face.get_files(); assert!(!files.is_empty()); @@ -86,10 +94,12 @@ where F: FnMut(FontTemplate), { let system_fc = FontCollection::system(); - if let Some(family) = system_fc.get_font_family_by_name(family_name) { + if let Ok(Some(family)) = system_fc.font_family_by_name(family_name) { let count = family.get_font_count(); for i in 0..count { - let font = family.get_font(i); + let Ok(font) = family.font(i) else { + continue; + }; let template_descriptor = (&font).into(); let local_font_identifier = LocalFontIdentifier { font_descriptor: Arc::new(font.to_descriptor()), diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml index 0505581fba7..0e4cd0b79fd 100644 --- a/components/layout/Cargo.toml +++ b/components/layout/Cargo.toml @@ -21,7 +21,6 @@ app_units = { workspace = true } atomic_refcell = { workspace = true } base = { workspace = true } bitflags = { workspace = true } -canvas_traits = { workspace = true } compositing_traits = { workspace = true } constellation_traits = { workspace = true } data-url = { workspace = true } diff --git a/components/layout/construct_modern.rs b/components/layout/construct_modern.rs index 8f1282ec9f6..d09744b2031 100644 --- a/components/layout/construct_modern.rs +++ b/components/layout/construct_modern.rs @@ -150,7 +150,6 @@ impl<'a, 'dom> ModernContainerBuilder<'a, 'dom> { let inline_formatting_context = inline_formatting_context_builder.finish( self.context, - self.propagated_data, true, /* has_first_formatted_line */ false, /* is_single_line_text_box */ self.info.style.writing_mode.to_bidi_level(), diff --git a/components/layout/context.rs b/components/layout/context.rs index 3411eed486c..1ee76606b0b 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -10,17 +10,21 @@ use fnv::FnvHashMap; use fonts::FontContext; use fxhash::FxHashMap; use net_traits::image_cache::{ - ImageCache, ImageCacheResult, ImageOrMetadataAvailable, UsePlaceholder, + Image as CachedImage, ImageCache, ImageCacheResult, ImageOrMetadataAvailable, PendingImageId, + UsePlaceholder, }; use parking_lot::{Mutex, RwLock}; -use pixels::Image as PixelImage; -use script_layout_interface::{IFrameSizes, ImageAnimationState, PendingImage, PendingImageState}; +use pixels::RasterImage; +use script_layout_interface::{ + IFrameSizes, ImageAnimationState, PendingImage, PendingImageState, PendingRasterizationImage, +}; use servo_url::{ImmutableOrigin, ServoUrl}; use style::context::SharedStyleContext; use style::dom::OpaqueNode; use style::values::computed::image::{Gradient, Image}; +use webrender_api::units::{DeviceIntSize, DeviceSize}; -use crate::display_list::WebRenderImageInfo; +pub(crate) type CachedImageOrError = Result; pub struct LayoutContext<'a> { pub id: PipelineId, @@ -39,11 +43,17 @@ pub struct LayoutContext<'a> { /// A list of in-progress image loads to be shared with the script thread. pub pending_images: Mutex>, + /// A list of fully loaded vector images that need to be rasterized to a specific + /// size determined by layout. This will be shared with the script thread. + pub pending_rasterization_images: Mutex>, + /// A collection of ` + + + + + + + + + + \ No newline at end of file diff --git a/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-write-domstring.https.html b/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-write-domstring.https.html new file mode 100644 index 00000000000..a16f358f46d --- /dev/null +++ b/tests/wpt/tests/clipboard-apis/async-navigator-clipboard-write-domstring.https.html @@ -0,0 +1,112 @@ + + +Async Clipboard input type validation tests - DOMString input in write API + + +Body needed for test_driver.click() + + + + + + \ No newline at end of file diff --git a/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-nn.html b/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-nn.html new file mode 100644 index 00000000000..b2da2d415a8 --- /dev/null +++ b/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-nn.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + diff --git a/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynn.html b/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynn.html new file mode 100644 index 00000000000..3ab5b758684 --- /dev/null +++ b/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynn.html @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + diff --git a/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynyn.html b/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynyn.html new file mode 100644 index 00000000000..e486fcb3682 --- /dev/null +++ b/tests/wpt/tests/close-watcher/iframes/dialog-same-origin-ynyn.html @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + diff --git a/tests/wpt/tests/close-watcher/iframes/resources/dialog-prevents-close.html b/tests/wpt/tests/close-watcher/iframes/resources/dialog-prevents-close.html new file mode 100644 index 00000000000..580e5220dae --- /dev/null +++ b/tests/wpt/tests/close-watcher/iframes/resources/dialog-prevents-close.html @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/tests/wpt/tests/compute-pressure/compute_pressure_basic.https.window.js b/tests/wpt/tests/compute-pressure/compute_pressure_basic.https.window.js index a120f97a403..a13d1766c53 100644 --- a/tests/wpt/tests/compute-pressure/compute_pressure_basic.https.window.js +++ b/tests/wpt/tests/compute-pressure/compute_pressure_basic.https.window.js @@ -21,6 +21,26 @@ pressure_test(async (t) => { return promise_rejects_dom(t, 'NotSupportedError', observer.observe('cpu')); }, 'Return NotSupportedError when calling observer()'); +pressure_test(async (t) => { + await create_virtual_pressure_source('cpu'); + t.add_cleanup(async () => { + await remove_virtual_pressure_source('cpu'); + }); + + const changes = await new Promise((resolve, reject) => { + const observer = new PressureObserver(resolve); + t.add_cleanup(() => observer.disconnect()); + observer.observe('cpu').catch(reject); + update_virtual_pressure_source('cpu', 'critical', 0.5).catch(reject); + }); + assert_equals(1, changes.length); + assert_equals(changes[0].state, 'critical'); + assert_equals(changes[0].source, 'cpu'); + assert_equals(typeof changes[0].time, 'number'); + assert_equals(typeof changes[0].ownContributionEstimate, 'number'); + assert_equals(changes[0].ownContributionEstimate, 0.5); +}, 'Basic functionality test'); + pressure_test(async (t) => { await create_virtual_pressure_source('cpu'); t.add_cleanup(async () => { @@ -37,7 +57,8 @@ pressure_test(async (t) => { assert_equals(changes[0].state, 'critical'); assert_equals(changes[0].source, 'cpu'); assert_equals(typeof changes[0].time, 'number'); -}, 'Basic functionality test'); + assert_equals(changes[0].ownContributionEstimate, null); +}, 'Basic functionality test with no ownContributionEstimate'); pressure_test(async (t) => { await create_virtual_pressure_source('cpu'); diff --git a/tests/wpt/tests/compute-pressure/compute_pressure_duplicate_updates.https.window.js b/tests/wpt/tests/compute-pressure/compute_pressure_duplicate_updates.https.window.js index 231d4afc345..abf53854b40 100644 --- a/tests/wpt/tests/compute-pressure/compute_pressure_duplicate_updates.https.window.js +++ b/tests/wpt/tests/compute-pressure/compute_pressure_duplicate_updates.https.window.js @@ -19,15 +19,15 @@ pressure_test(async (t) => { const syncObserver = new SyncPressureObserver(t); await syncObserver.observer().observe('cpu'); - await update_virtual_pressure_source('cpu', 'critical'); + await update_virtual_pressure_source('cpu', 'critical', 0.2); await syncObserver.waitForUpdate(); assert_equals(syncObserver.changes()[0][0].state, 'critical'); - await update_virtual_pressure_source('cpu', 'critical'); + await update_virtual_pressure_source('cpu', 'critical', 0.2); await new Promise(resolve => {t.step_timeout(resolve, 3000)}); assert_equals(syncObserver.changes().length, 1); - await update_virtual_pressure_source('cpu', 'nominal'); + await update_virtual_pressure_source('cpu', 'nominal'), 0.2; await syncObserver.waitForUpdate(); assert_equals(syncObserver.changes()[1][0].state, 'nominal'); diff --git a/tests/wpt/tests/compute-pressure/resources/worker-support.js b/tests/wpt/tests/compute-pressure/resources/worker-support.js index 39caeb6192f..72e1fbfb204 100644 --- a/tests/wpt/tests/compute-pressure/resources/worker-support.js +++ b/tests/wpt/tests/compute-pressure/resources/worker-support.js @@ -43,8 +43,8 @@ function remove_virtual_pressure_source(source) { return send_message({command: 'remove', params: [source]}); } -function update_virtual_pressure_source(source, state) { - return send_message({command: 'update', params: [source, state]}); +function update_virtual_pressure_source(source, state, estimate) { + return send_message({command: 'update', params: [source, state, estimate]}); } const uuid = new URLSearchParams(location.search).get('uuid'); diff --git a/tests/wpt/tests/content-security-policy/frame-src/frame-src-blocked.sub.html b/tests/wpt/tests/content-security-policy/frame-src/frame-src-blocked.sub.html index a4957f8715c..76fcc2cbb53 100644 --- a/tests/wpt/tests/content-security-policy/frame-src/frame-src-blocked.sub.html +++ b/tests/wpt/tests/content-security-policy/frame-src/frame-src-blocked.sub.html @@ -18,17 +18,17 @@ }, false); function alert_assert(msg) { - t_alert.step(function() { + t_log.step(function() { if (msg.match(/^FAIL/i)) { assert_unreached(msg); - t_alert.done(); + t_log.done(); } for (var i = 0; i < expected_alerts.length; i++) { if (expected_alerts[i] == msg) { assert_equals(expected_alerts[i], msg); expected_alerts.splice(i, 1); if (expected_alerts.length == 0) { - t_alert.done(); + t_log.done(); } return; } diff --git a/tests/wpt/tests/cookie-store/cookieListItem_attributes.https.any.js b/tests/wpt/tests/cookie-store/cookieListItem_attributes.https.any.js index 542bd6c5387..b42a745d3e4 100644 --- a/tests/wpt/tests/cookie-store/cookieListItem_attributes.https.any.js +++ b/tests/wpt/tests/cookie-store/cookieListItem_attributes.https.any.js @@ -161,7 +161,7 @@ promise_test(async testCase => { assert_equals(cookie.name, 'cookie-name'); assert_equals(cookie.value, 'cookie-value'); assert_equals(cookie.domain, null); - assert_equals(cookie.path, currentDirectory + '/'); + assert_equals(cookie.path, currentDirectory); assert_equals(cookie.expires, null); assert_equals(cookie.secure, true); assert_equals(cookie.sameSite, 'strict'); @@ -169,7 +169,7 @@ promise_test(async testCase => { for (const key of kCookieListItemKeys) { assert_in_array(key, itemKeys); } -}, 'CookieListItem - cookieStore.set adds / to path if it does not end with /'); +}, 'CookieListItem - cookieStore.set does not add / to path if it does not end with /'); ['strict', 'lax', 'none'].forEach(sameSiteValue => { promise_test(async testCase => { @@ -208,19 +208,22 @@ promise_test(async testCase => { assert_equals(cookie.secure, true); }, 'CookieListItem - secure defaults to true'); -promise_test(async testCase => { - await cookieStore.delete('cookie-name'); - testCase.add_cleanup(async () => { + +if (self.GLOBAL.isWindow()) { + promise_test(async testCase => { await cookieStore.delete('cookie-name'); - }); + testCase.add_cleanup(async () => { + await cookieStore.delete('cookie-name'); + }); - let encodedCookie = encodeURIComponent(JSON.stringify("cookie-name=1; max-age=99999999999999999999999999999; path=/")); - await fetch(`/cookies/resources/cookie.py?set=${encodedCookie}`); + let encodedCookie = encodeURIComponent(JSON.stringify("cookie-name=1; max-age=99999999999999999999999999999; path=/")); + await fetch(`/cookies/resources/cookie.py?set=${encodedCookie}`); - assert_equals(document.cookie, "cookie-name=1", 'The cookie was set as expected.'); + assert_equals(document.cookie, "cookie-name=1", 'The cookie was set as expected.'); - const cookie = await cookieStore.get('cookie-name'); - assert_equals(cookie.name, 'cookie-name'); - assert_equals(cookie.value, '1'); - assert_approx_equals(cookie.expires, kFourHundredDaysFromNow, kOneDay); -}, "Test max-age attribute over the 400 days"); + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie.name, 'cookie-name'); + assert_equals(cookie.value, '1'); + assert_approx_equals(cookie.expires, kFourHundredDaysFromNow, kOneDay); + }, "Test max-age attribute over the 400 days"); +} diff --git a/tests/wpt/tests/cookie-store/cookieStore_delete_arguments.https.any.js b/tests/wpt/tests/cookie-store/cookieStore_delete_arguments.https.any.js index 37a551b3a9f..2503de0abb0 100644 --- a/tests/wpt/tests/cookie-store/cookieStore_delete_arguments.https.any.js +++ b/tests/wpt/tests/cookie-store/cookieStore_delete_arguments.https.any.js @@ -1,11 +1,14 @@ // META: title=Cookie Store API: cookieStore.delete() arguments +// META: script=resources/cookie-test-helpers.js // META: global=window,serviceworker 'use strict'; promise_test(async testCase => { await cookieStore.set('cookie-name', 'cookie-value'); - + testCase.add_cleanup(async () => { + await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`); + }); await cookieStore.delete('cookie-name'); const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie, null); @@ -14,7 +17,7 @@ promise_test(async testCase => { promise_test(async testCase => { await cookieStore.set('cookie-name', 'cookie-value'); testCase.add_cleanup(async () => { - await cookieStore.delete('cookie-name'); + await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`); }); await cookieStore.delete({ name: 'cookie-name' }); @@ -42,7 +45,7 @@ promise_test(async testCase => { await cookieStore.set( { name: 'cookie-name', value: 'cookie-value', domain: currentDomain }); testCase.add_cleanup(async () => { - await cookieStore.delete({ name: 'cookie-name', domain: currentDomain }); + await setCookieStringHttp(`cookie-name=deleted; Domain=${currentDomain}; Max-Age=0`); }); await cookieStore.delete({ name: 'cookie-name', domain: currentDomain }); @@ -79,7 +82,8 @@ promise_test(async testCase => { await cookieStore.set( { name: 'cookie-name', value: 'cookie-value', path: currentDirectory }); testCase.add_cleanup(async () => { - await cookieStore.delete({ name: 'cookie-name', path: currentDirectory }); + await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`); + await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}/; Max-Age=0`); }); await cookieStore.delete({ name: 'cookie-name', path: currentDirectory }); @@ -96,7 +100,8 @@ promise_test(async testCase => { await cookieStore.set( { name: 'cookie-name', value: 'cookie-value', path: currentDirectory }); testCase.add_cleanup(async () => { - await cookieStore.delete({ name: 'cookie-name', path: currentDirectory }); + await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`); + await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}/; Max-Age=0`); }); await cookieStore.delete({ name: 'cookie-name', path: subDirectory }); @@ -109,18 +114,36 @@ promise_test(async testCase => { const currentUrl = new URL(self.location.href); const currentPath = currentUrl.pathname; const currentDirectory = currentPath.substr(0, currentPath.lastIndexOf('/')); - await cookieStore.set( - { name: 'cookie-name', - value: 'cookie-value', - path: currentDirectory + '/' }); + await setCookieStringHttp(`cookie-name=cookie-value; Path=${currentDirectory};`); + testCase.add_cleanup(async () => { - await cookieStore.delete({ name: 'cookie-name', path: currentDirectory }); + await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`); + await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}/; Max-Age=0`); }); await cookieStore.delete({ name: 'cookie-name', path: currentDirectory }); const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie, null); -}, 'cookieStore.delete with missing / at the end of path'); +}, 'cookieStore.delete does not append / at the end of path'); + +promise_test(async testCase => { + if (typeof self.document === 'undefined') { + // The test is being run from a service worker context where document is undefined + testCase.done(); + return; + } + const currentUrl = new URL(self.location.href); + const currentPath = currentUrl.pathname; + const currentDirectory = currentPath.substr(0, currentPath.lastIndexOf('/')); + await setCookieStringDocument('cookie-name=cookie-value; path=' + currentDirectory); + testCase.add_cleanup(async () => { + await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`); + await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}/; Max-Age=0`); + }); + await cookieStore.delete({ name: 'cookie-name', path: currentDirectory }); + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie, null); +}, 'cookieStore.delete can delete a cookie set by document.cookie if document is defined'); promise_test(async testCase => { const currentUrl = new URL(self.location.href); @@ -136,7 +159,7 @@ promise_test(async testCase => { promise_test(async testCase => { await cookieStore.set('cookie-name', 'cookie-value'); testCase.add_cleanup(async () => { - await cookieStore.delete('cookie-name'); + await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`); }); const cookie_attributes = await cookieStore.get('cookie-name'); @@ -151,7 +174,7 @@ promise_test(async testCase => { promise_test(async testCase => { await cookieStore.set('', 'cookie-value'); testCase.add_cleanup(async () => { - await cookieStore.delete(''); + await setCookieStringHttp(`=deleted; Max-Age=0`); }); await cookieStore.delete(''); @@ -162,10 +185,25 @@ promise_test(async testCase => { promise_test(async testCase => { await cookieStore.set('', 'cookie-value'); testCase.add_cleanup(async () => { - await cookieStore.delete(''); + await setCookieStringHttp(`=deleted; Max-Age=0`); }); await cookieStore.delete({ name: '' }); const cookie = await cookieStore.get(''); assert_equals(cookie, null); }, 'cookieStore.delete with empty name in options'); + +promise_test(async testCase => { + // Cookies having a __Host- prefix are not allowed to specify a domain + await cookieStore.delete('cookie-name'); + + const currentUrl = new URL(self.location.href); + const currentDomain = currentUrl.hostname; + + await promise_rejects_js(testCase, TypeError, cookieStore.delete( + { name: '__Host-cookie-name', + value: 'cookie-value', + domain: currentDomain })); + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie, null); +}, 'cookieStore.delete with a __Host- prefix should not have a domain'); diff --git a/tests/wpt/tests/cookie-store/cookieStore_get_set_across_origins.sub.https.html b/tests/wpt/tests/cookie-store/cookieStore_get_set_across_origins.sub.https.html index c67ef98bcc9..004e37630ac 100644 --- a/tests/wpt/tests/cookie-store/cookieStore_get_set_across_origins.sub.https.html +++ b/tests/wpt/tests/cookie-store/cookieStore_get_set_across_origins.sub.https.html @@ -63,4 +63,87 @@ promise_test(async t => { assert_equals(frameCookie.name, 'cookie-name'); assert_equals(frameCookie.value, 'cookie-value'); }, 'cookieStore.get() in cross-origin frame sees cookieStore.set()'); + +promise_test(async t => { + const iframe = await createIframe(kCorsUrl, t); + assert_true(iframe != null); + + document.cookie = "__Host-test=a; Path=/; Secure"; + iframe.contentWindow.postMessage({ + opname: 'set-host-cookie', + name: '__Host-test', + value: 'b', + }, kCorsBase); + + const message = await waitForMessage(); + t.add_cleanup(async () => { + await cookieStore.delete({ name: '__Host-test'}); + }); + + assert_equals(document.cookie, '__Host-test=a'); + + // Cleanup iframe cookie + iframe.contentWindow.postMessage({ + opname: 'delete-host-cookie', + name: '__Host-test', + }, kCorsBase); + await waitForMessage(); +}, 'cookieStore.set() in cross-origin does not overwrite the __Host- cookie'); + +promise_test(async t => { + const iframe = await createIframe(kCorsUrl, t); + assert_true(iframe != null); + + document.cookie = "__Host-test=a; Path=/; Secure"; + await cookieStore.set({name: "__Host-test", value: "a", path: "/"}); + t.add_cleanup(async () => { + await cookieStore.delete({ name: '__Host-test'}); + }); + + iframe.contentWindow.postMessage({ + opname: 'set-host-cookie', + name: '__Host-test', + value: 'b', + }, kCorsBase); + + let message = await waitForMessage(); + + let cookies = await cookieStore.getAll(); + assert_equals(cookies.length, 1); + assert_equals(cookies[0].name, '__Host-test'); + assert_equals(cookies[0].value, 'a'); + + iframe.contentWindow.postMessage({ + opname: 'get-cookie', + name: '__Host-test', + }, kCorsBase); + message = await waitForMessage(); + let { frameCookie } = message; + assert_not_equals(frameCookie, null); + assert_equals(frameCookie.name, '__Host-test'); + assert_equals(frameCookie.value, 'b'); + + // Make sure deleting the cookie doesn't affect the other domain's cookie + await cookieStore.delete({ name: '__Host-test'}); + cookies = await cookieStore.getAll(); + assert_equals(cookies.length, 0); + + iframe.contentWindow.postMessage({ + opname: 'get-cookie', + name: '__Host-test', + }, kCorsBase); + message = await waitForMessage(); + ({ frameCookie } = message); + assert_not_equals(frameCookie, null); + assert_equals(frameCookie.name, '__Host-test'); + assert_equals(frameCookie.value, 'b'); + + // Cleanup iframe cookie + iframe.contentWindow.postMessage({ + opname: 'delete-host-cookie', + name: '__Host-test', + }, kCorsBase); + await waitForMessage(); +}, "__Host- cookies set via cookieStore.set() in same-site domains don't overwrite each other"); + diff --git a/tests/wpt/tests/cookie-store/cookieStore_set_arguments.https.any.js b/tests/wpt/tests/cookie-store/cookieStore_set_arguments.https.any.js index 064fcc5de52..3e9ac5f3e98 100644 --- a/tests/wpt/tests/cookie-store/cookieStore_set_arguments.https.any.js +++ b/tests/wpt/tests/cookie-store/cookieStore_set_arguments.https.any.js @@ -1,4 +1,5 @@ // META: title=Cookie Store API: cookieStore.set() arguments +// META: script=resources/cookie-test-helpers.js // META: global=window,serviceworker 'use strict'; @@ -8,7 +9,7 @@ promise_test(async testCase => { await cookieStore.set('cookie-name', 'cookie-value'); testCase.add_cleanup(async () => { - await cookieStore.delete('cookie-name'); + await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`); }); const cookie = await cookieStore.get('cookie-name'); @@ -21,7 +22,7 @@ promise_test(async testCase => { await cookieStore.set({ name: 'cookie-name', value: 'cookie-value' }); testCase.add_cleanup(async () => { - await cookieStore.delete('cookie-name'); + await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`); }); const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie.name, 'cookie-name'); @@ -42,7 +43,7 @@ promise_test(async testCase => { await cookieStore.delete('cookie-name'); cookieStore.set('cookie-name', 'suspicious-value=resembles-name-and-value'); testCase.add_cleanup(async () => { - await cookieStore.delete('cookie-name'); + await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`); }); const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie.name, 'cookie-name'); @@ -81,7 +82,7 @@ promise_test(async testCase => { value: 'cookie-value', expires: new Date(tenYearsFromNow) }); testCase.add_cleanup(async () => { - await cookieStore.delete('cookie-name'); + await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`); }); const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie.name, 'cookie-name'); @@ -98,7 +99,7 @@ promise_test(async testCase => { value: 'cookie-value', expires: new Date(tenYearsAgo) }); testCase.add_cleanup(async () => { - await cookieStore.delete('cookie-name'); + await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`); }); const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie, null); @@ -112,7 +113,7 @@ promise_test(async testCase => { await cookieStore.set( { name: 'cookie-name', value: 'cookie-value', expires: tenYearsFromNow }); testCase.add_cleanup(async () => { - await cookieStore.delete('cookie-name'); + await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`); }); const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie.name, 'cookie-name'); @@ -127,7 +128,7 @@ promise_test(async testCase => { await cookieStore.set( { name: 'cookie-name', value: 'cookie-value', expires: tenYearsAgo }); testCase.add_cleanup(async () => { - await cookieStore.delete('cookie-name'); + await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`); }); const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie, null); @@ -156,7 +157,7 @@ promise_test(async testCase => { await cookieStore.set( { name: 'cookie-name', value: 'cookie-value', domain: currentDomain }); testCase.add_cleanup(async () => { - await cookieStore.delete({ name: 'cookie-name', domain: currentDomain }); + await setCookieStringHttp(`cookie-name=deleted; Domain=${currentDomain}; Path=/; Max-Age=0`); }); const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie.name, 'cookie-name'); @@ -195,12 +196,12 @@ promise_test(async testCase => { await cookieStore.set('cookie-name', 'cookie-value1'); testCase.add_cleanup(async () => { - await cookieStore.delete('cookie-name'); + await setCookieStringHttp(`cookie-name=deleted; Path=/; Max-Age=0`); }); await cookieStore.set( { name: 'cookie-name', value: 'cookie-value2', domain: currentDomain }); testCase.add_cleanup(async () => { - await cookieStore.delete({ name: 'cookie-name', domain: currentDomain }); + await setCookieStringHttp(`cookie-name=deleted; Domain=${currentDomain}; Path=/; Max-Age=0`); }); const cookies = await cookieStore.getAll('cookie-name'); @@ -224,7 +225,7 @@ promise_test(async testCase => { await cookieStore.set( { name: 'cookie-name', value: 'cookie-value', path: currentDirectory }); testCase.add_cleanup(async () => { - await cookieStore.delete({ name: 'cookie-name', path: currentDirectory }); + await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`); }); const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie.name, 'cookie-name'); @@ -243,7 +244,7 @@ promise_test(async testCase => { await cookieStore.set( { name: 'cookie-name', value: 'cookie-value', path: subDirectory }); testCase.add_cleanup(async () => { - await cookieStore.delete({ name: 'cookie-name', path: subDirectory }); + await setCookieStringHttp(`cookie-name=deleted; Path=${subDirectory}; Max-Age=0`); }); const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie, null); @@ -254,12 +255,13 @@ promise_test(async testCase => { await cookieStore.set('cookie-name', 'cookie-old-value'); testCase.add_cleanup(async () => { - await cookieStore.delete('cookie-name'); + await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`); }); + await cookieStore.set( { name: 'cookie-name', value: 'cookie-new-value', path: '/' }); testCase.add_cleanup(async () => { - await cookieStore.delete({ name: 'cookie-name', path: '/' }); + await setCookieStringHttp(`cookie-name=deleted; Path=/; Max-Age=0`); }); const cookies = await cookieStore.getAll('cookie-name'); @@ -277,13 +279,34 @@ promise_test(async testCase => { await cookieStore.set( { name: 'cookie-name', value: 'cookie-value', path: currentDirectory }); testCase.add_cleanup(async () => { - await cookieStore.delete({ name: 'cookie-name', path: currentDirectory }); + await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}/; Max-Age=0`); }); + await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`); const cookie = await cookieStore.get('cookie-name'); - assert_equals(cookie.name, 'cookie-name'); - assert_equals(cookie.value, 'cookie-value'); - assert_equals(cookie.path, currentDirectory + '/'); -}, 'cookieStore.set adds / to path that does not end with /'); + assert_equals(cookie, null); +}, 'cookieStore.set does not add / to path that does not end with /'); + +promise_test(async testCase => { + if (typeof self.document === 'undefined') { + // The test is being run from a service worker context where document is undefined + testCase.done(); + return; + } + const currentUrl = new URL(self.location.href); + const currentPath = currentUrl.pathname; + const currentDirectory = currentPath.substr(0, currentPath.lastIndexOf('/')); + await setCookieStringDocument('cookie-name=cookie-value; path=' + currentDirectory); + await cookieStore.set( + { name: 'cookie-name', value: 'new-cookie-value', path: currentDirectory }); + testCase.add_cleanup(async () => { + await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}; Max-Age=0`); + await setCookieStringHttp(`cookie-name=deleted; Path=${currentDirectory}/; Max-Age=0`); + }); + const cookies = await cookieStore.getAll('cookie-name'); + assert_equals(cookies.length, 1); + assert_equals(cookies[0].name, 'cookie-name'); + assert_equals(cookies[0].value, 'cookie-new-value'); +}, 'cookieStore.set can modify a cookie set by document.cookie if document is defined'); promise_test(async testCase => { const currentUrl = new URL(self.location.href); @@ -299,7 +322,7 @@ promise_test(async testCase => { promise_test(async testCase => { await cookieStore.set('cookie-name', 'old-cookie-value'); testCase.add_cleanup(async () => { - await cookieStore.delete('cookie-name'); + await setCookieStringHttp(`cookie-name=deleted; Max-Age=0`); }); const cookie_attributes = await cookieStore.get('cookie-name'); @@ -336,3 +359,57 @@ promise_test(async testCase => { const cookie = await cookieStore.get('cookie-name'); assert_equals(cookie, null); }, 'cookieStore.set checks if the domain is too long'); + +promise_test(async testCase => { + // Cookies having a __Host- prefix are not allowed to specify a domain + await cookieStore.delete('cookie-name'); + + const currentUrl = new URL(self.location.href); + const currentDomain = currentUrl.hostname; + + await promise_rejects_js(testCase, TypeError, cookieStore.set( + { name: '__Host-cookie-name', + value: 'cookie-value', + domain: currentDomain })); + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie, null); +}, 'cookieStore.set with a __Host- prefix should not have a domain'); + +promise_test(async testCase => { + await promise_rejects_js(testCase, TypeError, cookieStore.set( + { name: '', + value: ' ' })); + + await promise_rejects_js(testCase, TypeError, cookieStore.set( + { name: ' ', + value: '' })); + + await promise_rejects_js(testCase, TypeError, cookieStore.set( + { name: ' ', + value: ' ' })); +}, 'cookieStore.set with whitespace only name and value'); + +promise_test(async testCase => { + testCase.add_cleanup(async () => { + await cookieStore.delete('a b'); + }); + await cookieStore.set('a b', 'x y'); + const cookie = await cookieStore.get('a b'); + assert_equals(cookie.value, "x y"); + + await promise_rejects_js(testCase, TypeError, cookieStore.set( + { name: 'a ', + value: 'x' })); + + await promise_rejects_js(testCase, TypeError, cookieStore.set( + { name: ' a', + value: 'x' })); + + await promise_rejects_js(testCase, TypeError, cookieStore.set( + { name: 'a', + value: 'x ' })); + + await promise_rejects_js(testCase, TypeError, cookieStore.set( + { name: 'a', + value: 'x ' })); +}, 'cookieStore.set with whitespace at begining or end'); diff --git a/tests/wpt/tests/cookie-store/resources/cookie-test-helpers.js b/tests/wpt/tests/cookie-store/resources/cookie-test-helpers.js index 178947ad6ec..8e23ff2c422 100644 --- a/tests/wpt/tests/cookie-store/resources/cookie-test-helpers.js +++ b/tests/wpt/tests/cookie-store/resources/cookie-test-helpers.js @@ -210,9 +210,10 @@ async function cookie_test(func, description) { // Wipe cookies used by tests before and after the test. async function deleteAllCookies() { - (await cookieStore.getAll()).forEach(({name, value}) => { - cookieStore.delete(name); - }); + await Promise.all((await cookieStore.getAll()).map(async ({name, value}) => { + await cookieStore.delete(name); + await cookieStore.delete({name: name, partitioned: true}); + })); } return promise_test(async t => { diff --git a/tests/wpt/tests/cookie-store/resources/helper_iframe.sub.html b/tests/wpt/tests/cookie-store/resources/helper_iframe.sub.html index 3bd1843d574..d5cae23d160 100644 --- a/tests/wpt/tests/cookie-store/resources/helper_iframe.sub.html +++ b/tests/wpt/tests/cookie-store/resources/helper_iframe.sub.html @@ -40,6 +40,17 @@ } else if (opname === 'push-state') { history.pushState("foo", null, "some/path"); event.source.postMessage('pushState called'); + } else if (opname === "set-host-cookie") { + const { name, value } = event.data + await cookieStore.set({ + name, + value, + }); + event.source.postMessage('Cookie has been set', event.origin); + } else if (opname === "delete-host-cookie") { + const { name} = event.data + await cookieStore.delete({ name: name}); + event.source.postMessage('Cookie has been deleted', event.origin); } }); diff --git a/tests/wpt/tests/css/CSS2/zindex/z-index-020.html b/tests/wpt/tests/css/CSS2/zindex/z-index-020.html new file mode 100644 index 00000000000..34a7272a254 --- /dev/null +++ b/tests/wpt/tests/css/CSS2/zindex/z-index-020.html @@ -0,0 +1,39 @@ + + +CSS Test: z-index - dynamic changes + + + + + + +

Test passes if there is a filled green square and no red.

+ +
+
+ + + + + diff --git a/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins-aspect-ratio.html b/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins-aspect-ratio.html index 4eaa9d2f3a6..347005204e3 100644 --- a/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins-aspect-ratio.html +++ b/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins-aspect-ratio.html @@ -11,14 +11,14 @@ } .abspos { position: absolute; - inset: 10px auto 10px 50px; + inset: 50px auto 50px 50px; margin: auto 0 auto 0; align-self: stretch; background: green; } .abspos::before { content: ''; - min-width: 100px; + min-width: 50px; height: 100%; aspect-ratio: 1; display: block; diff --git a/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins.html b/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins.html index 9d1b6454c84..9d6eb230653 100644 --- a/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins.html +++ b/tests/wpt/tests/css/css-align/abspos/align-self-stretch-auto-margins.html @@ -11,15 +11,15 @@ } .abspos { position: absolute; - inset: 10px 50px 10px 50px; + inset: 50px; margin: auto 0 auto 0; align-self: stretch; background: green; } .abspos::before { content: ''; - width: 100px; - height: 100px; + width: 50px; + height: 50px; display: block; } diff --git a/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins-aspect-ratio.html b/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins-aspect-ratio.html index c50b32f089b..bc6120584c2 100644 --- a/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins-aspect-ratio.html +++ b/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins-aspect-ratio.html @@ -11,7 +11,7 @@ } .abspos { position: absolute; - inset: 50px 10px auto 10px; + inset: 50px 50px auto 50px; margin: 0 auto 0 auto; justify-self: stretch; background: green; @@ -19,7 +19,7 @@ .abspos::before { content: ''; width: 100%; - min-height: 100px; + min-height: 50px; aspect-ratio: 1; display: block; } diff --git a/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins.html b/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins.html index 7d7b4bfc857..675321fc2b1 100644 --- a/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins.html +++ b/tests/wpt/tests/css/css-align/abspos/justify-self-stretch-auto-margins.html @@ -11,15 +11,15 @@ } .abspos { position: absolute; - inset: 50px 10px 50px 10px; + inset: 50px; margin: 0 auto 0 auto; justify-self: stretch; background: green; } .abspos::before { content: ''; - width: 100px; - height: 100px; + width: 50px; + height: 50px; display: block; } diff --git a/tests/wpt/tests/css/css-align/blocks/justify-items-anonymous.tentative.html b/tests/wpt/tests/css/css-align/blocks/justify-items-anonymous.html similarity index 100% rename from tests/wpt/tests/css/css-align/blocks/justify-items-anonymous.tentative.html rename to tests/wpt/tests/css/css-align/blocks/justify-items-anonymous.html diff --git a/tests/wpt/tests/css/css-align/blocks/justify-self-auto-margins-2.html b/tests/wpt/tests/css/css-align/blocks/justify-self-auto-margins-2.html index 33c98d6c1df..e81c4bba6f4 100644 --- a/tests/wpt/tests/css/css-align/blocks/justify-self-auto-margins-2.html +++ b/tests/wpt/tests/css/css-align/blocks/justify-self-auto-margins-2.html @@ -1,8 +1,7 @@ - +
-
-
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change.html b/tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change.html index 0f7d805844f..e5559433206 100644 --- a/tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change.html +++ b/tests/wpt/tests/css/css-anchor-position/anchor-center-visibility-change.html @@ -1,8 +1,9 @@ -Tests 'anchor-center' value when target visibility changes +Tests 'anchor-center' value when target visibility changes (by changing 'display', 'visibility', or popover trigger) + @@ -27,27 +28,61 @@ .target { position-anchor: --anchor; - position: fixed; - background: cyan; + position: absolute; +} + +.target-inner { + width: 30px; + height: 20px; +} + +#target-1 { justify-self: anchor-center; + background: cyan; display: none; } + +#target-2 { + align-self: anchor-center; + background: blue; + visibility: hidden; +} + +#target-3 { + align-self: anchor-center; + justify-self: anchor-center; + background: magenta; + + /* Override default popover style */ + margin: 0; + padding: 0; + border: none; +}
-
-
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+ + diff --git a/tests/wpt/tests/css/css-anchor-position/anchor-in-multicol-crash.html b/tests/wpt/tests/css/css-anchor-position/anchor-in-multicol-crash.html new file mode 100644 index 00000000000..8a4206630a1 --- /dev/null +++ b/tests/wpt/tests/css/css-anchor-position/anchor-in-multicol-crash.html @@ -0,0 +1,46 @@ + +CSS Anchor Positioning: Crash with anchor in multicol + + + + PASS if no crash +
+
+
+
+
+
+ diff --git a/tests/wpt/tests/css/css-anchor-position/anchor-in-multicol-inherit-crash.html b/tests/wpt/tests/css/css-anchor-position/anchor-in-multicol-inherit-crash.html new file mode 100644 index 00000000000..233f8382e8a --- /dev/null +++ b/tests/wpt/tests/css/css-anchor-position/anchor-in-multicol-inherit-crash.html @@ -0,0 +1,53 @@ + +CSS Anchor Positioning: Crash with anchor in multicol (inheritance) + + + + PASS if no crash +
+
+
+
+
+
+
+
+ diff --git a/tests/wpt/tests/css/css-anchor-position/chrome-419501749-crash.html b/tests/wpt/tests/css/css-anchor-position/chrome-419501749-crash.html new file mode 100644 index 00000000000..2ab29fc87f5 --- /dev/null +++ b/tests/wpt/tests/css/css-anchor-position/chrome-419501749-crash.html @@ -0,0 +1,12 @@ + + + +

Pass if no crash

+
diff --git a/tests/wpt/tests/css/css-anchor-position/position-area-visibility-change.html b/tests/wpt/tests/css/css-anchor-position/position-area-visibility-change.html new file mode 100644 index 00000000000..61d8ab50284 --- /dev/null +++ b/tests/wpt/tests/css/css-anchor-position/position-area-visibility-change.html @@ -0,0 +1,113 @@ + + + + + + Tests that an element positioned using position-area renders when it's initially hidden, then shown + + + + + + + + + + + + +
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/tests/wpt/tests/css/css-anchor-position/position-try-ident-function.html b/tests/wpt/tests/css/css-anchor-position/position-try-ident-function.html new file mode 100644 index 00000000000..4457c4f14f8 --- /dev/null +++ b/tests/wpt/tests/css/css-anchor-position/position-try-ident-function.html @@ -0,0 +1,23 @@ + +CSS Anchor Positioning: The ident() function in @position-try/position-try + + + + + + +
+ diff --git a/tests/wpt/tests/css/css-anchor-position/position-visibility-no-overflow-without-anchor.html b/tests/wpt/tests/css/css-anchor-position/position-visibility-no-overflow-without-anchor.html new file mode 100644 index 00000000000..01f4d97947b --- /dev/null +++ b/tests/wpt/tests/css/css-anchor-position/position-visibility-no-overflow-without-anchor.html @@ -0,0 +1,36 @@ + + +CSS Anchor Positioning Test: position-visibility: no-overflow without an anchor + + + + +
+
anchor1
+ +
target1
+
diff --git a/tests/wpt/tests/css/css-anchor-position/reference/position-area-visibility-change-ref.html b/tests/wpt/tests/css/css-anchor-position/reference/position-area-visibility-change-ref.html new file mode 100644 index 00000000000..87e18049409 --- /dev/null +++ b/tests/wpt/tests/css/css-anchor-position/reference/position-area-visibility-change-ref.html @@ -0,0 +1,72 @@ + + + + + +
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ \ No newline at end of file diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-left.html b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-left.html new file mode 100644 index 00000000000..b38b7f3f278 --- /dev/null +++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-left.html @@ -0,0 +1,71 @@ + +shape-outside with corner-shape: notch + + + + + + +
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-right.html b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-right.html new file mode 100644 index 00000000000..96a297230bb --- /dev/null +++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-outside-right.html @@ -0,0 +1,71 @@ + +shape-outside with corner-shape: notch + + + + + + +
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin-ref.html b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin-ref.html new file mode 100644 index 00000000000..2c1ccf86cc6 --- /dev/null +++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin-ref.html @@ -0,0 +1,16 @@ + + +overflow-clip-margin with border-radius & corner-shape + +
+
diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin.html b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin.html new file mode 100644 index 00000000000..97371aa6c3f --- /dev/null +++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-overflow-clip-margin.html @@ -0,0 +1,29 @@ + + +overflow-clip-margin with border-radius & corner-shape + + + + + + + +
+
+
diff --git a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html index 590e960830f..12cd2546bf4 100644 --- a/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html +++ b/tests/wpt/tests/css/css-borders/tentative/corner-shape/corner-shape-render-fuzzy.html @@ -4,9 +4,7 @@ - - diff --git a/tests/wpt/tests/css/css-break/table/table-parts-offsetheight.html b/tests/wpt/tests/css/css-break/table/table-parts-offsetheight.html index 5bdc33b521a..cc49f339de7 100644 --- a/tests/wpt/tests/css/css-break/table/table-parts-offsetheight.html +++ b/tests/wpt/tests/css/css-break/table/table-parts-offsetheight.html @@ -19,11 +19,11 @@ diff --git a/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-lr.tentative.html b/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-lr.tentative.html index bdac1f40607..77516a6146f 100644 --- a/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-lr.tentative.html +++ b/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-lr.tentative.html @@ -39,103 +39,103 @@ test(() => { assert_equals(table.offsetTop, 8, "offsetTop"); assert_equals(table.offsetLeft, 8, "offsetLeft"); - assert_equals(table.offsetWidth, 177, "offsetWidth"); - assert_equals(table.offsetHeight, 184, "offsetHeight"); + assert_equals(table.offsetWidth, 70, "offsetWidth"); + assert_equals(table.offsetHeight, 584, "offsetHeight"); }, "table"); test(() => { assert_equals(colgroup.offsetTop, 18, "offsetTop"); assert_equals(colgroup.offsetLeft, 18, "offsetLeft"); - assert_equals(colgroup.offsetWidth, 157, "offsetWidth"); - assert_equals(colgroup.offsetHeight, 107, "offsetHeight"); + assert_equals(colgroup.offsetWidth, 70, "offsetWidth"); + assert_equals(colgroup.offsetHeight, 507, "offsetHeight"); }, "colgroup"); test(() => { assert_equals(col.offsetTop, 18, "offsetTop"); assert_equals(col.offsetLeft, 18, "offsetLeft"); - assert_equals(col.offsetWidth, 157, "offsetWidth"); - assert_equals(col.offsetHeight, 50, "offsetHeight"); + assert_equals(col.offsetWidth, 70, "offsetWidth"); + assert_equals(col.offsetHeight, 450, "offsetHeight"); }, "col"); test(() => { assert_equals(col2.offsetTop, 75, "offsetTop"); assert_equals(col2.offsetLeft, 18, "offsetLeft"); - assert_equals(col2.offsetWidth, 157, "offsetWidth"); - assert_equals(col2.offsetHeight, 50, "offsetHeight"); + assert_equals(col2.offsetWidth, 70, "offsetWidth"); + assert_equals(col2.offsetHeight, 450, "offsetHeight"); }, "col2"); test(() => { assert_equals(colgroup2.offsetTop, 132, "offsetTop"); assert_equals(colgroup2.offsetLeft, 18, "offsetLeft"); - assert_equals(colgroup2.offsetWidth, 157, "offsetWidth"); - assert_equals(colgroup2.offsetHeight, 50, "offsetHeight"); + assert_equals(colgroup2.offsetWidth, 70, "offsetWidth"); + assert_equals(colgroup2.offsetHeight, 450, "offsetHeight"); }, "colgroup2"); test(() => { assert_equals(col3.offsetTop, 132, "offsetTop"); assert_equals(col3.offsetLeft, 18, "offsetLeft"); - assert_equals(col3.offsetWidth, 157, "offsetWidth"); - assert_equals(col3.offsetHeight, 50, "offsetHeight"); + assert_equals(col3.offsetWidth, 70, "offsetWidth"); + assert_equals(col3.offsetHeight, 450, "offsetHeight"); }, "col3"); test(() => { assert_equals(rowgroup.offsetTop, 18, "offsetTop"); assert_equals(rowgroup.offsetLeft, 18, "offsetLeft"); - assert_equals(rowgroup.offsetWidth, 157, "offsetWidth"); - assert_equals(rowgroup.offsetHeight, 164, "offsetHeight"); + assert_equals(rowgroup.offsetWidth, 70, "offsetWidth"); + assert_equals(rowgroup.offsetHeight, 564, "offsetHeight"); }, "rowgroup"); test(() => { assert_equals(row.offsetTop, 18, "offsetTop"); assert_equals(row.offsetLeft, 18, "offsetLeft"); - assert_equals(row.offsetWidth, 100, "offsetWidth"); - assert_equals(row.offsetHeight, 164, "offsetHeight"); + assert_equals(row.offsetWidth, 70, "offsetWidth"); + assert_equals(row.offsetHeight, 364, "offsetHeight"); }, "row"); test(() => { assert_equals(cell.offsetTop, 18, "offsetTop"); assert_equals(cell.offsetLeft, 18, "offsetLeft"); - assert_equals(cell.offsetWidth, 100, "offsetWidth"); - assert_equals(cell.offsetHeight, 50, "offsetHeight"); + assert_equals(cell.offsetWidth, 70, "offsetWidth"); + assert_equals(cell.offsetHeight, 250, "offsetHeight"); }, "cell"); test(() => { assert_equals(content.offsetTop, 18, "offsetTop"); assert_equals(content.offsetLeft, 18, "offsetLeft"); - assert_equals(content.offsetWidth, 100, "offsetWidth"); - assert_equals(content.offsetHeight, 50, "offsetHeight"); + assert_equals(content.offsetWidth, 70, "offsetWidth"); + assert_equals(content.offsetHeight, 250, "offsetHeight"); }, "content"); test(() => { assert_equals(cell2.offsetTop, 75, "offsetTop"); assert_equals(cell2.offsetLeft, 18, "offsetLeft"); - assert_equals(cell2.offsetWidth, 100, "offsetWidth"); - assert_equals(cell2.offsetHeight, 50, "offsetHeight"); + assert_equals(cell2.offsetWidth, 70, "offsetWidth"); + assert_equals(cell2.offsetHeight, 250, "offsetHeight"); }, "cell2"); test(() => { assert_equals(content2.offsetTop, 75, "offsetTop"); assert_equals(content2.offsetLeft, 18, "offsetLeft"); - assert_equals(content2.offsetWidth, 100, "offsetWidth"); - assert_equals(content2.offsetHeight, 50, "offsetHeight"); + assert_equals(content2.offsetWidth, 70, "offsetWidth"); + assert_equals(content2.offsetHeight, 250, "offsetHeight"); }, "content2"); test(() => { assert_equals(cell3.offsetTop, 132, "offsetTop"); assert_equals(cell3.offsetLeft, 18, "offsetLeft"); - assert_equals(cell3.offsetWidth, 100, "offsetWidth"); - assert_equals(cell3.offsetHeight, 50, "offsetHeight"); + assert_equals(cell3.offsetWidth, 70, "offsetWidth"); + assert_equals(cell3.offsetHeight, 250, "offsetHeight"); }, "cell3"); test(() => { assert_equals(content3.offsetTop, 132, "offsetTop"); assert_equals(content3.offsetLeft, 18, "offsetLeft"); - assert_equals(content3.offsetWidth, 100, "offsetWidth"); - assert_equals(content3.offsetHeight, 50, "offsetHeight"); + assert_equals(content3.offsetWidth, 70, "offsetWidth"); + assert_equals(content3.offsetHeight, 250, "offsetHeight"); }, "content3"); test(() => { assert_equals(row2.offsetTop, 218, "offsetTop"); assert_equals(row2.offsetLeft, 55, "offsetLeft"); - assert_equals(row2.offsetWidth, 50, "offsetWidth"); - assert_equals(row2.offsetHeight, 164, "offsetHeight"); + assert_equals(row2.offsetWidth, 70, "offsetWidth"); + assert_equals(row2.offsetHeight, 364, "offsetHeight"); }, "row2"); test(() => { assert_equals(cell4.offsetTop, 218, "offsetTop"); assert_equals(cell4.offsetLeft, 55, "offsetLeft"); - assert_equals(cell4.offsetWidth, 50, "offsetWidth"); - assert_equals(cell4.offsetHeight, 50, "offsetHeight"); + assert_equals(cell4.offsetWidth, 70, "offsetWidth"); + assert_equals(cell4.offsetHeight, 250, "offsetHeight"); }, "cell4"); test(() => { assert_equals(content4.offsetTop, 218, "offsetTop"); assert_equals(content4.offsetLeft, 55, "offsetLeft"); - assert_equals(content4.offsetWidth, 50, "offsetWidth"); - assert_equals(content4.offsetHeight, 50, "offsetHeight"); + assert_equals(content4.offsetWidth, 70, "offsetWidth"); + assert_equals(content4.offsetHeight, 250, "offsetHeight"); }, "content4"); diff --git a/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-rl.tentative.html b/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-rl.tentative.html index 1eb751032ca..ea58b145738 100644 --- a/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-rl.tentative.html +++ b/tests/wpt/tests/css/css-break/table/table-parts-offsets-vertical-rl.tentative.html @@ -39,103 +39,103 @@ test(() => { assert_equals(table.offsetTop, 8, "offsetTop"); assert_equals(table.offsetLeft, 8, "offsetLeft"); - assert_equals(table.offsetWidth, 177, "offsetWidth"); - assert_equals(table.offsetHeight, 184, "offsetHeight"); + assert_equals(table.offsetWidth, 70, "offsetWidth"); + assert_equals(table.offsetHeight, 584, "offsetHeight"); }, "table"); test(() => { assert_equals(colgroup.offsetTop, 18, "offsetTop"); assert_equals(colgroup.offsetLeft, 8, "offsetLeft"); - assert_equals(colgroup.offsetWidth, 157, "offsetWidth"); - assert_equals(colgroup.offsetHeight, 107, "offsetHeight"); + assert_equals(colgroup.offsetWidth, 70, "offsetWidth"); + assert_equals(colgroup.offsetHeight, 507, "offsetHeight"); }, "colgroup"); test(() => { assert_equals(col.offsetTop, 18, "offsetTop"); assert_equals(col.offsetLeft, 8, "offsetLeft"); - assert_equals(col.offsetWidth, 157, "offsetWidth"); - assert_equals(col.offsetHeight, 50, "offsetHeight"); + assert_equals(col.offsetWidth, 70, "offsetWidth"); + assert_equals(col.offsetHeight, 450, "offsetHeight"); }, "col"); test(() => { assert_equals(col2.offsetTop, 75, "offsetTop"); assert_equals(col2.offsetLeft, 8, "offsetLeft"); - assert_equals(col2.offsetWidth, 157, "offsetWidth"); - assert_equals(col2.offsetHeight, 50, "offsetHeight"); + assert_equals(col2.offsetWidth, 70, "offsetWidth"); + assert_equals(col2.offsetHeight, 450, "offsetHeight"); }, "col2"); test(() => { assert_equals(colgroup2.offsetTop, 132, "offsetTop"); assert_equals(colgroup2.offsetLeft, 8, "offsetLeft"); - assert_equals(colgroup2.offsetWidth, 157, "offsetWidth"); - assert_equals(colgroup2.offsetHeight, 50, "offsetHeight"); + assert_equals(colgroup2.offsetWidth, 70, "offsetWidth"); + assert_equals(colgroup2.offsetHeight, 450, "offsetHeight"); }, "colgroup2"); test(() => { assert_equals(col3.offsetTop, 132, "offsetTop"); assert_equals(col3.offsetLeft, 8, "offsetLeft"); - assert_equals(col3.offsetWidth, 157, "offsetWidth"); - assert_equals(col3.offsetHeight, 50, "offsetHeight"); + assert_equals(col3.offsetWidth, 70, "offsetWidth"); + assert_equals(col3.offsetHeight, 450, "offsetHeight"); }, "col3"); test(() => { assert_equals(rowgroup.offsetTop, 18, "offsetTop"); assert_equals(rowgroup.offsetLeft, 8, "offsetLeft"); - assert_equals(rowgroup.offsetWidth, 157, "offsetWidth"); - assert_equals(rowgroup.offsetHeight, 164, "offsetHeight"); + assert_equals(rowgroup.offsetWidth, 70, "offsetWidth"); + assert_equals(rowgroup.offsetHeight, 564, "offsetHeight"); }, "rowgroup"); test(() => { assert_equals(row.offsetTop, 18, "offsetTop"); assert_equals(row.offsetLeft, 8, "offsetLeft"); - assert_equals(row.offsetWidth, 100, "offsetWidth"); - assert_equals(row.offsetHeight, 164, "offsetHeight"); + assert_equals(row.offsetWidth, 70, "offsetWidth"); + assert_equals(row.offsetHeight, 364, "offsetHeight"); }, "row"); test(() => { assert_equals(cell.offsetTop, 18, "offsetTop"); assert_equals(cell.offsetLeft, 8, "offsetLeft"); - assert_equals(cell.offsetWidth, 100, "offsetWidth"); - assert_equals(cell.offsetHeight, 50, "offsetHeight"); + assert_equals(cell.offsetWidth, 70, "offsetWidth"); + assert_equals(cell.offsetHeight, 250, "offsetHeight"); }, "cell"); test(() => { assert_equals(content.offsetTop, 18, "offsetTop"); assert_equals(content.offsetLeft, 8, "offsetLeft"); - assert_equals(content.offsetWidth, 100, "offsetWidth"); - assert_equals(content.offsetHeight, 50, "offsetHeight"); + assert_equals(content.offsetWidth, 70, "offsetWidth"); + assert_equals(content.offsetHeight, 250, "offsetHeight"); }, "content"); test(() => { assert_equals(cell2.offsetTop, 75, "offsetTop"); assert_equals(cell2.offsetLeft, 8, "offsetLeft"); - assert_equals(cell2.offsetWidth, 100, "offsetWidth"); - assert_equals(cell2.offsetHeight, 50, "offsetHeight"); + assert_equals(cell2.offsetWidth, 70, "offsetWidth"); + assert_equals(cell2.offsetHeight, 250, "offsetHeight"); }, "cell2"); test(() => { assert_equals(content2.offsetTop, 75, "offsetTop"); assert_equals(content2.offsetLeft, 8, "offsetLeft"); - assert_equals(content2.offsetWidth, 100, "offsetWidth"); - assert_equals(content2.offsetHeight, 50, "offsetHeight"); + assert_equals(content2.offsetWidth, 70, "offsetWidth"); + assert_equals(content2.offsetHeight, 250, "offsetHeight"); }, "content2"); test(() => { assert_equals(cell3.offsetTop, 132, "offsetTop"); assert_equals(cell3.offsetLeft, 8, "offsetLeft"); - assert_equals(cell3.offsetWidth, 100, "offsetWidth"); - assert_equals(cell3.offsetHeight, 50, "offsetHeight"); + assert_equals(cell3.offsetWidth, 70, "offsetWidth"); + assert_equals(cell3.offsetHeight, 250, "offsetHeight"); }, "cell3"); test(() => { assert_equals(content3.offsetTop, 132, "offsetTop"); assert_equals(content3.offsetLeft, 8, "offsetLeft"); - assert_equals(content3.offsetWidth, 100, "offsetWidth"); - assert_equals(content3.offsetHeight, 50, "offsetHeight"); + assert_equals(content3.offsetWidth, 70, "offsetWidth"); + assert_equals(content3.offsetHeight, 250, "offsetHeight"); }, "content3"); test(() => { assert_equals(row2.offsetTop, 218, "offsetTop"); assert_equals(row2.offsetLeft, 8, "offsetLeft"); - assert_equals(row2.offsetWidth, 50, "offsetWidth"); - assert_equals(row2.offsetHeight, 164, "offsetHeight"); + assert_equals(row2.offsetWidth, 70, "offsetWidth"); + assert_equals(row2.offsetHeight, 364, "offsetHeight"); }, "row2"); test(() => { assert_equals(cell4.offsetTop, 218, "offsetTop"); assert_equals(cell4.offsetLeft, 8, "offsetLeft"); - assert_equals(cell4.offsetWidth, 50, "offsetWidth"); - assert_equals(cell4.offsetHeight, 50, "offsetHeight"); + assert_equals(cell4.offsetWidth, 70, "offsetWidth"); + assert_equals(cell4.offsetHeight, 250, "offsetHeight"); }, "cell4"); test(() => { assert_equals(content4.offsetTop, 218, "offsetTop"); assert_equals(content4.offsetLeft, 8, "offsetLeft"); - assert_equals(content4.offsetWidth, 50, "offsetWidth"); - assert_equals(content4.offsetHeight, 50, "offsetHeight"); + assert_equals(content4.offsetWidth, 70, "offsetWidth"); + assert_equals(content4.offsetHeight, 250, "offsetHeight"); }, "content4"); diff --git a/tests/wpt/tests/css/css-break/table/table-parts-offsets.tentative.html b/tests/wpt/tests/css/css-break/table/table-parts-offsets.tentative.html index 265d761ffb3..4bed47b6a4d 100644 --- a/tests/wpt/tests/css/css-break/table/table-parts-offsets.tentative.html +++ b/tests/wpt/tests/css/css-break/table/table-parts-offsets.tentative.html @@ -38,103 +38,103 @@ test(() => { assert_equals(table.offsetTop, 8, "offsetTop"); assert_equals(table.offsetLeft, 8, "offsetLeft"); - assert_equals(table.offsetWidth, 184, "offsetWidth"); - assert_equals(table.offsetHeight, 177, "offsetHeight"); + assert_equals(table.offsetWidth, 584, "offsetWidth"); + assert_equals(table.offsetHeight, 70, "offsetHeight"); }, "table"); test(() => { assert_equals(colgroup.offsetTop, 18, "offsetTop"); assert_equals(colgroup.offsetLeft, 18, "offsetLeft"); - assert_equals(colgroup.offsetWidth, 107, "offsetWidth"); - assert_equals(colgroup.offsetHeight, 157, "offsetHeight"); + assert_equals(colgroup.offsetWidth, 507, "offsetWidth"); + assert_equals(colgroup.offsetHeight, 70, "offsetHeight"); }, "colgroup"); test(() => { assert_equals(col.offsetTop, 18, "offsetTop"); assert_equals(col.offsetLeft, 18, "offsetLeft"); - assert_equals(col.offsetWidth, 50, "offsetWidth"); - assert_equals(col.offsetHeight, 157, "offsetHeight"); + assert_equals(col.offsetWidth, 450, "offsetWidth"); + assert_equals(col.offsetHeight, 70, "offsetHeight"); }, "col"); test(() => { assert_equals(col2.offsetTop, 18, "offsetTop"); assert_equals(col2.offsetLeft, 75, "offsetLeft"); - assert_equals(col2.offsetWidth, 50, "offsetWidth"); - assert_equals(col2.offsetHeight, 157, "offsetHeight"); + assert_equals(col2.offsetWidth, 450, "offsetWidth"); + assert_equals(col2.offsetHeight, 70, "offsetHeight"); }, "col2"); test(() => { assert_equals(colgroup2.offsetTop, 18, "offsetTop"); assert_equals(colgroup2.offsetLeft, 132, "offsetLeft"); - assert_equals(colgroup2.offsetWidth, 50, "offsetWidth"); - assert_equals(colgroup2.offsetHeight, 157, "offsetHeight"); + assert_equals(colgroup2.offsetWidth, 450, "offsetWidth"); + assert_equals(colgroup2.offsetHeight, 70, "offsetHeight"); }, "colgroup2"); test(() => { assert_equals(col3.offsetTop, 18, "offsetTop"); assert_equals(col3.offsetLeft, 132, "offsetLeft"); - assert_equals(col3.offsetWidth, 50, "offsetWidth"); - assert_equals(col3.offsetHeight, 157, "offsetHeight"); + assert_equals(col3.offsetWidth, 450, "offsetWidth"); + assert_equals(col3.offsetHeight, 70, "offsetHeight"); }, "col3"); test(() => { assert_equals(rowgroup.offsetTop, 18, "offsetTop"); assert_equals(rowgroup.offsetLeft, 18, "offsetLeft"); - assert_equals(rowgroup.offsetWidth, 164, "offsetWidth"); - assert_equals(rowgroup.offsetHeight, 157, "offsetHeight"); + assert_equals(rowgroup.offsetWidth, 564, "offsetWidth"); + assert_equals(rowgroup.offsetHeight, 70, "offsetHeight"); }, "rowgroup"); test(() => { assert_equals(row.offsetTop, 18, "offsetTop"); assert_equals(row.offsetLeft, 18, "offsetLeft"); - assert_equals(row.offsetWidth, 164, "offsetWidth"); - assert_equals(row.offsetHeight, 100, "offsetHeight"); + assert_equals(row.offsetWidth, 364, "offsetWidth"); + assert_equals(row.offsetHeight, 70, "offsetHeight"); }, "row"); test(() => { assert_equals(cell.offsetTop, 18, "offsetTop"); assert_equals(cell.offsetLeft, 18, "offsetLeft"); - assert_equals(cell.offsetWidth, 50, "offsetWidth"); - assert_equals(cell.offsetHeight, 100, "offsetHeight"); + assert_equals(cell.offsetWidth, 250, "offsetWidth"); + assert_equals(cell.offsetHeight, 70, "offsetHeight"); }, "cell"); test(() => { assert_equals(content.offsetTop, 18, "offsetTop"); assert_equals(content.offsetLeft, 18, "offsetLeft"); - assert_equals(content.offsetWidth, 50, "offsetWidth"); - assert_equals(content.offsetHeight, 100, "offsetHeight"); + assert_equals(content.offsetWidth, 250, "offsetWidth"); + assert_equals(content.offsetHeight, 70, "offsetHeight"); }, "content"); test(() => { assert_equals(cell2.offsetTop, 18, "offsetTop"); assert_equals(cell2.offsetLeft, 75, "offsetLeft"); - assert_equals(cell2.offsetWidth, 50, "offsetWidth"); - assert_equals(cell2.offsetHeight, 100, "offsetHeight"); + assert_equals(cell2.offsetWidth, 250, "offsetWidth"); + assert_equals(cell2.offsetHeight, 70, "offsetHeight"); }, "cell2"); test(() => { assert_equals(content2.offsetTop, 18, "offsetTop"); assert_equals(content2.offsetLeft, 75, "offsetLeft"); - assert_equals(content2.offsetWidth, 50, "offsetWidth"); - assert_equals(content2.offsetHeight, 100, "offsetHeight"); + assert_equals(content2.offsetWidth, 250, "offsetWidth"); + assert_equals(content2.offsetHeight, 70, "offsetHeight"); }, "content2"); test(() => { assert_equals(cell3.offsetTop, 18, "offsetTop"); assert_equals(cell3.offsetLeft, 132, "offsetLeft"); - assert_equals(cell3.offsetWidth, 50, "offsetWidth"); - assert_equals(cell3.offsetHeight, 100, "offsetHeight"); + assert_equals(cell3.offsetWidth, 250, "offsetWidth"); + assert_equals(cell3.offsetHeight, 70, "offsetHeight"); }, "cell3"); test(() => { assert_equals(content3.offsetTop, 18, "offsetTop"); assert_equals(content3.offsetLeft, 132, "offsetLeft"); - assert_equals(content3.offsetWidth, 50, "offsetWidth"); - assert_equals(content3.offsetHeight, 100, "offsetHeight"); + assert_equals(content3.offsetWidth, 250, "offsetWidth"); + assert_equals(content3.offsetHeight, 70, "offsetHeight"); }, "content3"); test(() => { assert_equals(row2.offsetTop, 55, "offsetTop"); assert_equals(row2.offsetLeft, 218, "offsetLeft"); - assert_equals(row2.offsetWidth, 164, "offsetWidth"); - assert_equals(row2.offsetHeight, 50, "offsetHeight"); + assert_equals(row2.offsetWidth, 364, "offsetWidth"); + assert_equals(row2.offsetHeight, 70, "offsetHeight"); }, "row2"); test(() => { assert_equals(cell4.offsetTop, 55, "offsetTop"); assert_equals(cell4.offsetLeft, 218, "offsetLeft"); - assert_equals(cell4.offsetWidth, 50, "offsetWidth"); - assert_equals(cell4.offsetHeight, 50, "offsetHeight"); + assert_equals(cell4.offsetWidth, 250, "offsetWidth"); + assert_equals(cell4.offsetHeight, 70, "offsetHeight"); }, "cell4"); test(() => { assert_equals(content4.offsetTop, 55, "offsetTop"); assert_equals(content4.offsetLeft, 218, "offsetLeft"); - assert_equals(content4.offsetWidth, 50, "offsetWidth"); - assert_equals(content4.offsetHeight, 50, "offsetHeight"); + assert_equals(content4.offsetWidth, 250, "offsetWidth"); + assert_equals(content4.offsetHeight, 70, "offsetHeight"); }, "content4"); diff --git a/tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html b/tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html index 9bb87459623..a5c489e40a6 100644 --- a/tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html +++ b/tests/wpt/tests/css/css-color/parsing/color-computed-relative-color.html @@ -871,6 +871,7 @@ fuzzy_test_computed_color(`lch(from var(--mycolor) l 0 h)`, `lch(62.75 0 326.96)`, 0.02); fuzzy_test_computed_color(`var(--mygray)`, `lch(62.75 0 326.96)`, 0.02); fuzzy_test_computed_color(`lch(from var(--mygray) l 30 h)`, `lch(62.75 30 326.96)`, 0.02); + fuzzy_test_computed_color(`LCH(from var(--accent) l c calc(h + 180 * sibling-index()))`, `lch(65.49 39.45 10.11)`, 0.02); diff --git a/tests/wpt/tests/css/css-conditional/container-queries/at-container-style-parsing.html b/tests/wpt/tests/css/css-conditional/container-queries/at-container-style-parsing.html index 2e6722335c2..2890727ad4c 100644 --- a/tests/wpt/tests/css/css-conditional/container-queries/at-container-style-parsing.html +++ b/tests/wpt/tests/css/css-conditional/container-queries/at-container-style-parsing.html @@ -18,7 +18,34 @@ test_cq_condition_known('style(--my-prop: )'); test_cq_condition_known('style(--foo: bar !important)'); test_cq_condition_known('style(--foo)'); + test_cq_condition_known('style(--my-prop: attr(data-foo))'); + test_cq_condition_known('style(--foo >= --bar)'); + test_cq_condition_known('style(--foo = --bar)'); + test_cq_condition_known('style(--foo <= --bar)'); + test_cq_condition_known('style(10px > 10em)'); + test_cq_condition_known('style(--foo >= 10em)'); + test_cq_condition_known('style(10px > --bar)'); + test_cq_condition_known('style(10px = --bar)'); + test_cq_condition_known('style(--foo < --bar)'); + test_cq_condition_known('style(10px <= 10em)'); + test_cq_condition_known('style(10px = 10em)'); + test_cq_condition_known('style(10px <= calc(10em + 20em))'); + test_cq_condition_known('style(calc(10em + 20em) < 10px)'); + test_cq_condition_known('style(--foo < 10em)'); + test_cq_condition_known('style(10px <= --bar)'); + test_cq_condition_known('style(--foo < --bar <= --baz)'); + test_cq_condition_known('style(--foo >= --bar > --baz)'); + test_cq_condition_known('style(--foo > 10px > 10em)'); + test_cq_condition_known('style(10px < --foo < 10em)'); + test_cq_condition_known('style(10px < --foo <= 10em)'); + test_cq_condition_known('style(10px <= --foo < 10em)'); + test_cq_condition_known('style(10px > 10em > --foo)'); + test_cq_condition_known('style(10px < 10em < 10)'); + test_cq_condition_known('style(var(--p) < calc(100 + 200))'); + test_cq_condition_known('style(attr(data-foo type()) < var(--p) < var(--q))'); test_cq_condition_unknown('style(--foo: bar;)'); test_cq_condition_unknown('style(style(--foo: bar))'); + test_cq_condition_unknown('style(10px < 10em > 10)'); + test_cq_condition_unknown('style( < 10em)'); diff --git a/tests/wpt/tests/css/css-conditional/container-queries/container-ident-function.html b/tests/wpt/tests/css/css-conditional/container-queries/container-ident-function.html new file mode 100644 index 00000000000..692efa757b3 --- /dev/null +++ b/tests/wpt/tests/css/css-conditional/container-queries/container-ident-function.html @@ -0,0 +1,24 @@ + +CSS Conditional: The ident() function in @container/container-name + + + + + + +
+ diff --git a/tests/wpt/tests/css/css-conditional/container-queries/font-relative-units.html b/tests/wpt/tests/css/css-conditional/container-queries/font-relative-units.html index 3d676402e1e..97f43ac466f 100644 --- a/tests/wpt/tests/css/css-conditional/container-queries/font-relative-units.html +++ b/tests/wpt/tests/css/css-conditional/container-queries/font-relative-units.html @@ -7,6 +7,7 @@ + + +

Test passes if there is a filled green square.

+
+
+
+
+
+
+ + diff --git a/tests/wpt/tests/css/css-contain/contain-layout-stacking-context-001.html b/tests/wpt/tests/css/css-contain/contain-layout-stacking-context-001.html index 4ec3bcee6fd..5724fa1feac 100644 --- a/tests/wpt/tests/css/css-contain/contain-layout-stacking-context-001.html +++ b/tests/wpt/tests/css/css-contain/contain-layout-stacking-context-001.html @@ -1,66 +1,32 @@ - - - - CSS Test: 'contain: layout' with stacking contents. Z-index is defined only for siblings and children. - - - - - - - - -
-

-
- -
-
-

-
- -
-
-
- -
-

-
- - +'contain: layout' establishes stacking context. + + + + + +
+
+
+
+Test succeeds if there is no red. diff --git a/tests/wpt/tests/css/css-content/parsing/content-counter-valid.html b/tests/wpt/tests/css/css-content/parsing/content-counter-valid.html new file mode 100644 index 00000000000..6de60c9f1d8 --- /dev/null +++ b/tests/wpt/tests/css/css-content/parsing/content-counter-valid.html @@ -0,0 +1,13 @@ + + +CSS Content Test: counter() in alt text parsing + + + + +
+ diff --git a/tests/wpt/tests/css/css-exclusions/wrap-flow-001.html b/tests/wpt/tests/css/css-exclusions/wrap-flow-001.html index f87c5baf8b2..5750d8b73c2 100644 --- a/tests/wpt/tests/css/css-exclusions/wrap-flow-001.html +++ b/tests/wpt/tests/css/css-exclusions/wrap-flow-001.html @@ -41,8 +41,9 @@
diff --git a/tests/wpt/tests/css/css-flexbox/flex-container-min-content-002.tentative.html b/tests/wpt/tests/css/css-flexbox/flex-container-min-content-002.tentative.html index 92d37e3b9d8..f7e5016b59e 100644 --- a/tests/wpt/tests/css/css-flexbox/flex-container-min-content-002.tentative.html +++ b/tests/wpt/tests/css/css-flexbox/flex-container-min-content-002.tentative.html @@ -165,5 +165,5 @@ diff --git a/tests/wpt/tests/css/css-flexbox/stretched-child-in-nested-flexbox.html b/tests/wpt/tests/css/css-flexbox/stretched-child-in-nested-flexbox-001.html similarity index 100% rename from tests/wpt/tests/css/css-flexbox/stretched-child-in-nested-flexbox.html rename to tests/wpt/tests/css/css-flexbox/stretched-child-in-nested-flexbox-001.html diff --git a/tests/wpt/tests/css/css-flexbox/stretched-child-in-nested-flexbox-002.html b/tests/wpt/tests/css/css-flexbox/stretched-child-in-nested-flexbox-002.html new file mode 100644 index 00000000000..9a00b3c40a3 --- /dev/null +++ b/tests/wpt/tests/css/css-flexbox/stretched-child-in-nested-flexbox-002.html @@ -0,0 +1,19 @@ + + + +css-flexbox: Tests nested flex item with `align-items: stretch` + + + + + + +

Test passes if there is a filled green square and no red.

+
+
+
+
+
+
+ + diff --git a/tests/wpt/tests/css/css-fonts/font-face-range-order.html b/tests/wpt/tests/css/css-fonts/font-face-range-order.html index b198a9fb572..feae4803e7d 100644 --- a/tests/wpt/tests/css/css-fonts/font-face-range-order.html +++ b/tests/wpt/tests/css/css-fonts/font-face-range-order.html @@ -16,7 +16,7 @@ font-family: reversed-range-test; font-stretch: 200% 50%; font-style: oblique 90deg -90deg; font-weight: 900 100; -src: local(Ahem); +src: url(/fonts/Ahem.ttf); } + diff --git a/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-004-ref.html b/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-004-ref.html new file mode 100644 index 00000000000..52e45c4f65f --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-004-ref.html @@ -0,0 +1,32 @@ + + + +
+
+
+
+
+
+
+
+ + diff --git a/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-004.html b/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-004.html new file mode 100644 index 00000000000..c5d1e3f99cc --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-004.html @@ -0,0 +1,51 @@ + + + + column-rule-color declared with repeaters doesn't crash when recomputing + + + + + + +
+
+
+
+
+
+
+
+ + + diff --git a/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-006-ref.html b/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-006-ref.html new file mode 100644 index 00000000000..09bef415d40 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/agnostic/gap-decorations-006-ref.html @@ -0,0 +1,52 @@ + + + + +
+
+
+
+
+
+ + +
+
diff --git a/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020-ref.html b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020-ref.html new file mode 100644 index 00000000000..b708a78a347 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020-ref.html @@ -0,0 +1,55 @@ + + + + +
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020.html b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020.html new file mode 100644 index 00000000000..6c07493d14d --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-020.html @@ -0,0 +1,49 @@ + + + CSS Gap Decorations: flex gaps are painted when container scrolls. + + + + + +
+
+
+
+
+
+
+
diff --git a/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021-ref.html b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021-ref.html new file mode 100644 index 00000000000..1e28d73b4e2 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021-ref.html @@ -0,0 +1,55 @@ + + + + +
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021.html b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021.html new file mode 100644 index 00000000000..c59db4f635b --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-021.html @@ -0,0 +1,49 @@ + + + CSS Gap Decorations: flex gaps are painted with overflow hidden. + + + + + +
+
+
+
+
+
+
+
diff --git a/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-023.html b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-023.html new file mode 100644 index 00000000000..9a7c429a1a1 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-023.html @@ -0,0 +1,57 @@ + + + CSS Gap Decorations: flex gaps are painted when going from no gap rule to a gap rule that would be visible. + + + + + + + + +
+
+
+
+
+
+ + diff --git a/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-024.html b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-024.html new file mode 100644 index 00000000000..66cb0e86062 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/flex/flex-gap-decorations-024.html @@ -0,0 +1,38 @@ + + + + CSS Gap Decorations: shorthands column rules with !important are painted and overriden correctly. + + + + + +
+
+
+
+
+
diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034-ref.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034-ref.html new file mode 100644 index 00000000000..4e964879e79 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034-ref.html @@ -0,0 +1,71 @@ + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034.html new file mode 100644 index 00000000000..afe20ef5117 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-034.html @@ -0,0 +1,48 @@ + + + CSS Gap Decorations: Gaps are painted with container with overflow hidden, with JS scroll + + + + + + +
+
+
+
+
+
+
+
+
+
+
+ + + diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035-ref.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035-ref.html new file mode 100644 index 00000000000..851360a99a4 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035-ref.html @@ -0,0 +1,71 @@ + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035.html new file mode 100644 index 00000000000..d2fa76094a9 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-035.html @@ -0,0 +1,44 @@ + + + CSS Gap Decorations: Gaps are painted when container scrolls. + + + + + + +
+
+
+
+
+
+
+
+
+
+
+ diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036-ref.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036-ref.html new file mode 100644 index 00000000000..29ed684d85f --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036-ref.html @@ -0,0 +1,71 @@ + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036.html new file mode 100644 index 00000000000..8b1e1e2e1c2 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-036.html @@ -0,0 +1,44 @@ + + + CSS Gap Decorations: Gaps are painted with container with overflow hidden. + + + + + + +
+
+
+
+
+
+
+
+
+
+
+ diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037-ref.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037-ref.html new file mode 100644 index 00000000000..4a2ee5bd5c6 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037-ref.html @@ -0,0 +1,70 @@ + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037.html new file mode 100644 index 00000000000..656bfee7dfc --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-037.html @@ -0,0 +1,48 @@ + + + CSS Gap Decorations: Gaps are painted with container with overflow scroll and no background. + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+ diff --git a/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-039.html b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-039.html new file mode 100644 index 00000000000..c03d482ac49 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/grid/grid-gap-decorations-039.html @@ -0,0 +1,63 @@ + + + CSS Gap Decorations: grid column gaps are painted with solid styling. + + + + + + + + +
+
+
+
+
+
+ + diff --git a/tests/wpt/tests/css/css-gaps/multicol/multicol-gap-decorations-018-ref.html b/tests/wpt/tests/css/css-gaps/multicol/multicol-gap-decorations-018-ref.html new file mode 100644 index 00000000000..521d3925062 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/multicol/multicol-gap-decorations-018-ref.html @@ -0,0 +1,50 @@ + + + + + +
+
+
+
+
+ +
+
+
diff --git a/tests/wpt/tests/css/css-gaps/multicol/multicol-gap-decorations-019.html b/tests/wpt/tests/css/css-gaps/multicol/multicol-gap-decorations-019.html new file mode 100644 index 00000000000..c4f81bb95ea --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/multicol/multicol-gap-decorations-019.html @@ -0,0 +1,55 @@ + + + + column-rule-color declared with repeaters that depend on currentcolor should be recomputed when currentcolor changes + + + + + + + +
+
+
+
+
+
+
+
+ + + diff --git a/tests/wpt/tests/css/css-gaps/multicol/multicol-gap-intersections-018.html b/tests/wpt/tests/css/css-gaps/multicol/multicol-gap-intersections-018.html new file mode 100644 index 00000000000..b8f8e1619a0 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/multicol/multicol-gap-intersections-018.html @@ -0,0 +1,60 @@ + + + CSS Gap Decorations: Multicolumn gap decorations that are added later are painted. + + + + + + + + +
+

+

+

+

+

+

+
+ + diff --git a/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-bidirectional-shorthands.html b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-bidirectional-shorthands.html index 9ff3815c21f..2ace9f255fb 100644 --- a/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-bidirectional-shorthands.html +++ b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-bidirectional-shorthands.html @@ -44,6 +44,11 @@ test(function() { assert_equals(window.getComputedStyle(document.getElementById('target1')).getPropertyValue('rule-style'), 'solid'); }, "rule-style shorthand computed from longhand values"); + test(function() { + assert_equals(window.getComputedStyle(document.getElementById('target1')).getPropertyValue('rule'), '10px solid rgb(0, 255, 0)'); + }, "rule shorthand computed from longhand values"); + + test(function() { assert_equals(window.getComputedStyle(document.getElementById('target2')).getPropertyValue('rule-color'), ''); @@ -54,6 +59,9 @@ test(function() { assert_equals(window.getComputedStyle(document.getElementById('target2')).getPropertyValue('rule-style'), ''); }, "rule-style shorthand cannot be computed from longhand values so expect an empty string"); + test(function() { + assert_equals(window.getComputedStyle(document.getElementById('target2')).getPropertyValue('rule'), ''); + }, "rule shorthand cannot be computed from longhand values so expect an empty string"); diff --git a/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-important.html b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-important.html new file mode 100644 index 00000000000..76f3862533c --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-important.html @@ -0,0 +1,20 @@ + + + + CSS GapDecorations: !important flag parsing + + + + + + +
+ + + diff --git a/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html new file mode 100644 index 00000000000..63e108d2886 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-computed.html @@ -0,0 +1,61 @@ + + + + +CSS Gap Decoration: *rule getComputedStyle() + + + + + + + + +
+
+ + + + diff --git a/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-from-longhands.tentative.html b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-from-longhands.tentative.html new file mode 100644 index 00000000000..ed7c9a317e6 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-from-longhands.tentative.html @@ -0,0 +1,89 @@ + + + + CSS Gap Decorations: individual separate longhands form shorthand + + + + + + +
+ diff --git a/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-invalid.html b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-invalid.html new file mode 100644 index 00000000000..bbc347cc79e --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-invalid.html @@ -0,0 +1,30 @@ + + + + +CSS Gap Decorations: *-rule parsing + + + + + + + + + + + diff --git a/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-roundtrip.tentative.html b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-roundtrip.tentative.html new file mode 100644 index 00000000000..5955af8923c --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-roundtrip.tentative.html @@ -0,0 +1,21 @@ + + + + CSS Gap Decorations: *rule properties round trips properly + + + + +
+ diff --git a/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-valid.html b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-valid.html new file mode 100644 index 00000000000..cc05cf3b9e6 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand-valid.html @@ -0,0 +1,59 @@ + + + + +CSS Gap Decorations: parsing column-rule with valid values + + + + + + + + + + + diff --git a/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand.html b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand.html new file mode 100644 index 00000000000..c6c2a375167 --- /dev/null +++ b/tests/wpt/tests/css/css-gaps/parsing/gap-decorations-rule-shorthand.html @@ -0,0 +1,195 @@ + + + + +CSS Gap Decorations: *-rule sets longhands + + + + + + + + + + diff --git a/tests/wpt/tests/css/css-gaps/serialization/gap-decorations-properties.html b/tests/wpt/tests/css/css-gaps/serialization/gap-decorations-properties.html deleted file mode 100644 index 4985b5550f2..00000000000 --- a/tests/wpt/tests/css/css-gaps/serialization/gap-decorations-properties.html +++ /dev/null @@ -1,300 +0,0 @@ - - - - - - CSS Test: Gap Decorations - Properties exist - - - - - - - - - - - -
-
-
-
I T
-
IT
-
I
-
-
- - - - - diff --git a/tests/wpt/tests/css/css-grid/grid-extrinsically-sized-mutations.html b/tests/wpt/tests/css/css-grid/grid-extrinsically-sized-mutations.html index 75600046e82..ea9eb7ca242 100644 --- a/tests/wpt/tests/css/css-grid/grid-extrinsically-sized-mutations.html +++ b/tests/wpt/tests/css/css-grid/grid-extrinsically-sized-mutations.html @@ -105,17 +105,21 @@ function mutateContent() {
diff --git a/tests/wpt/tests/css/css-images/gradient/conic-gradient-001.html b/tests/wpt/tests/css/css-images/gradient/conic-gradient-001.html index 37e41094fb2..949f955e552 100644 --- a/tests/wpt/tests/css/css-images/gradient/conic-gradient-001.html +++ b/tests/wpt/tests/css/css-images/gradient/conic-gradient-001.html @@ -1,10 +1,10 @@ - - + + Tests the maximum value of color stops in conic-gradient(). - - -
-
-
-
-
- - + .test1 { + background: linear-gradient(90deg in srgb, hsl(60deg 0 50%), yellow); + } + + .test2 { + background: linear-gradient(90deg in srgb, hsl(20deg 0 50%), yellow); + } + + .test3 { + background: linear-gradient(90deg in srgb, hsl(60deg none 50%), yellow); + } + + .test4 { + background: linear-gradient(90deg in srgb, hsl(none 0 50%), yellow); + } + + .test5 { + background: linear-gradient(90deg in srgb, hsl(none none 50%), yellow); + } + + +
+
+
+
+
diff --git a/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-002.html b/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-002.html index 96038650136..881ba723f91 100644 --- a/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-002.html +++ b/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-002.html @@ -1,40 +1,39 @@ - - - - - Gradient analogous missing components carry forward logic tests - - - - - - - - -

They should be equivalent to `background: color-mix(in srgb, color(srgb none 1 none), lime)`

-
This should be a lime background.
-
This should be a lime background.
-
This should be a lime background.
-
This should be a lime background.
- - + + +Gradient analogous missing components carry forward logic tests + + + + + + +

They should be equivalent to `background: color-mix(in srgb, color(srgb none 1 none), lime)`

+
This should be a lime background.
+
This should be a lime background.
+
This should be a lime background.
+
This should be a lime background.
diff --git a/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-003.html b/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-003.html index c4c8995c1ef..c97571f54b9 100644 --- a/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-003.html +++ b/tests/wpt/tests/css/css-images/gradient/gradient-analogous-missing-components-003.html @@ -1,35 +1,33 @@ - - - - - Gradient analogous missing components carry forward logic tests - - - - - - - - -
This should be a lime background.
-
This should be a lime background.
-
This should be a lime background.
- - + + +Gradient analogous missing components carry forward logic tests + + + + + + + +
This should be a lime background.
+
This should be a lime background.
+
This should be a lime background.
diff --git a/tests/wpt/tests/css/css-images/gradient/gradient-single-stop-none-interpolation.html b/tests/wpt/tests/css/css-images/gradient/gradient-single-stop-none-interpolation.html index 14cd9d76302..449bde6e25a 100644 --- a/tests/wpt/tests/css/css-images/gradient/gradient-single-stop-none-interpolation.html +++ b/tests/wpt/tests/css/css-images/gradient/gradient-single-stop-none-interpolation.html @@ -1,40 +1,40 @@ - - - Gradient interpolation with single stop that has missing components - - - - - - - -
-
-
-
-
- - + +Gradient interpolation with single stop that has missing components + + + + + +
+
+
+
+
diff --git a/tests/wpt/tests/css/css-images/infinite-radial-gradient-refcrash.html b/tests/wpt/tests/css/css-images/infinite-radial-gradient-refcrash.html index a3a1e7fb069..a150b619116 100644 --- a/tests/wpt/tests/css/css-images/infinite-radial-gradient-refcrash.html +++ b/tests/wpt/tests/css/css-images/infinite-radial-gradient-refcrash.html @@ -2,6 +2,7 @@ CSS Images Test: repeating-radial-gradient with huge size crashes Chrome + -